ROS应用开发入门 话题消息的定义和使用

ROS是机器人操作系统的简称,本文介绍ROS应用开发入门,话题消息的定义和使用。发布者Publisher 和订阅者Subscribler 之间通讯都使用话题消息(topic message)。本文先定义一个话题消息,然后一个发布者发送,另一个订阅者接收。先是c++代码,然后是python 代码,你也可选择只看一种你熟悉的。

在前面2文(ROS 应用开发入门 发布者Publisher的编程 和 ROS 应用开发入门 订阅者Subscribler的编程)中,为了减少复杂性,我们使用了和仿真小乌龟通讯,话题消息也是现成的,但本文就要介绍自定义话题消息,这是符合我的实际应用需求。希望你看过前面2文,至少定义好了功能包。

自定义话题消息

在工程包目录下新建一个目录msg

cd ~/catkin_ws/src/learning_topic

mkdir msg

cd msg

然后新建一个Person.msg 文件

nano Person.msg

文件内容为:

string name
uint8  age
uint8  sex

uint8 unknown = 0
uint8 male    = 1
uint8 female  = 2

回到工程包目录下,打开并编辑package.xml:

 cd ~/catkin_ws/src/learning_topic

nano package.xml

  <build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend>

添加的位置是参考下面位置,就是<export> 前面注释上面:

 <exec_depend>roscpp</exec_depend>
  <exec_depend>rospy</exec_depend>
  <exec_depend>std_msgs</exec_depend>
  <exec_depend>turtlesim</exec_depend>

  <build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend>

  <!-- The export tag contains other, unspecified, tags -->
  <export>

然后打开并编辑CMakeLists.txt,总共3处

nano CMakeLists.txt

先在find_package 里添加 message_generation
添加后如下所示:

find_package(catkin REQUIRED COMPONENTS
  geometry_msgs
  roscpp
  rospy
  std_msgs
  turtlesim
  message_generation
)

 添加如下代码,也可以作为2行,

add_message_files(
  FILES
  Person.msg
)

generate_messages(
  DEPENDENCIES
  std_msgs
)

添加位置参看如下: 

## Generate added messages and services with any dependencies listed here
# generate_messages(
#   DEPENDENCIES
#   geometry_msgs#   std_msgs
# )


add_message_files(
  FILES
  Person.msg
)

generate_messages(
  DEPENDENCIES
  std_msgs
)

################################################
## Declare ROS dynamic reconfigure parameters ##
################################################

在catkin_package里,取消   CATKIN_DEPENDS geometry_msgs roscpp rospy std_msgs turtlesim行的注释,并添加 message_runtime
效果如下:

catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES learning_topic
   CATKIN_DEPENDS geometry_msgs roscpp rospy std_msgs turtlesim message_runtime
#  DEPENDS system_lib
)

修改完这2个文件后,就在工作空间编译。

编译必须回到 ~/catkin_ws 目录下

cd ~/catkin_ws

catkin_make

这样话题信息就定义准备好了。

看看编译最后阶段信息

Scanning dependencies of target learning_topic_generate_messages_py
[ 36%] Generating Python from MSG learning_topic/Person
[ 45%] Linking CXX executable /home/leon/catkin_ws/devel/lib/learning_topic/pose_subscriber
[ 54%] Generating Python msg __init__.py for learning_topic
[ 54%] Built target pose_subscriber
Scanning dependencies of target learning_topic_generate_messages_cpp
[ 63%] Generating C++ code from learning_topic/Person.msg
[ 63%] Built target learning_topic_generate_messages_py
Scanning dependencies of target learning_topic_generate_messages_eus
[ 72%] Generating EusLisp code from learning_topic/Person.msg
[ 72%] Built target learning_topic_generate_messages_cpp
Scanning dependencies of target learning_topic_generate_messages_lisp
[ 81%] Generating Lisp code from learning_topic/Person.msg
[ 90%] Generating EusLisp manifest code for learning_topic
[ 90%] Built target learning_topic_generate_messages_lisp
Scanning dependencies of target learning_topic_generate_messages_nodejs
[100%] Generating Javascript code from learning_topic/Person.msg
[100%] Built target learning_topic_generate_messages_nodejs
[100%] Built target learning_topic_generate_messages_eus
Scanning dependencies of target learning_topic_generate_messages
[100%] Built target learning_topic_generate_messages
leon@ubuntu:~/catkin_ws$ 

看来是为多种语言都准备好了。

c++ 验证源代码

要使用话题信息来验证,需要发布者和订阅者2个程序,我们都放在 工程目录的src目录下

转到src 目录下,分别建立文件person_publisher.cpp和 person_subscriber.cpp

~/catkin_ws/src/learning_topic/src

nano person_publisher.cpp

文件内容是:

/**
 * 该例程将发布/person_info话题,自定义消息类型learning_topic::Person
 */
 
#include <ros/ros.h>
#include "learning_topic/Person.h"

int main(int argc, char **argv)
{
    // ROS节点初始化
    ros::init(argc, argv, "person_publisher");

    // 创建节点句柄
    ros::NodeHandle n;

    // 创建一个Publisher,发布名为/person_info的topic,消息类型为learning_topic::Person,队列长度10
    ros::Publisher person_info_pub = n.advertise<learning_topic::Person>("/person_info", 10);

    // 设置循环的频率
    ros::Rate loop_rate(1);

    int count = 0;
    while (ros::ok())
    {
        // 初始化learning_topic::Person类型的消息
    	learning_topic::Person person_msg;
		person_msg.name = "Tom";
		person_msg.age  = 18;
		person_msg.sex  = learning_topic::Person::male;

        // 发布消息
		person_info_pub.publish(person_msg);

       	ROS_INFO("Publish Person Info: name:%s  age:%d  sex:%d", 
				  person_msg.name.c_str(), person_msg.age, person_msg.sex);

        // 按照循环频率延时
        loop_rate.sleep();
    }

    return 0;
}

nano person_subscriber.cpp

文件内容是:

/**
 * 该例程将订阅/person_info话题,自定义消息类型learning_topic::Person
 */
 
#include <ros/ros.h>
#include "learning_topic/Person.h"

// 接收到订阅的消息后,会进入消息回调函数
void personInfoCallback(const learning_topic::Person::ConstPtr& msg)
{
    // 将接收到的消息打印出来
    ROS_INFO("Subcribe Person Info: name:%s  age:%d  sex:%d", 
			 msg->name.c_str(), msg->age, msg->sex);
}

int main(int argc, char **argv)
{
    // 初始化ROS节点
    ros::init(argc, argv, "person_subscriber");

    // 创建节点句柄
    ros::NodeHandle n;

    // 创建一个Subscriber,订阅名为/person_info的topic,注册回调函数personInfoCallback
    ros::Subscriber person_info_sub = n.subscribe("/person_info", 10, personInfoCallback);

    // 循环等待回调函数
    ros::spin();

    return 0;
}

2个文件准备好了,下面

配置cmake文件

在 ~/catkin_ws/src/learning_topic/ 目录下,有个CMakeLists.txt 文件,我们需要修改这个文件

cd  ~/catkin_ws/src/learning_topic/

nano CMakeLists.txt 

在这个文件中添加下面几行,

add_executable(person_publisher src/person_publisher.cpp)
target_link_libraries(person_publisher ${catkin_LIBRARIES})
add_dependencies(person_publisher ${PROJECT_NAME}_generate_messages_cpp)

add_executable(person_subscriber src/person_subscriber.cpp)
target_link_libraries(person_subscriber ${catkin_LIBRARIES})
add_dependencies(person_subscriber ${PROJECT_NAME}_generate_messages_cpp)

添加的位置是参考下面位置,就是 ## install ## 前面,然后上一个发布者,订阅者添加各2行的后面:

## Specify libraries to link a library or executable target against
# target_link_libraries(${PROJECT_NAME}_node
#   ${catkin_LIBRARIES}
# )

add_executable(velocity_publisher src/velocity_publisher.cpp)
target_link_libraries(velocity_publisher ${catkin_LIBRARIES})

add_executable(pose_subscriber src/pose_subscriber.cpp)
target_link_libraries(pose_subscriber ${catkin_LIBRARIES})


add_executable(person_publisher src/person_publisher.cpp)
target_link_libraries(person_publisher ${catkin_LIBRARIES})
add_dependencies(person_publisher ${PROJECT_NAME}_generate_messages_cpp)

add_executable(person_subscriber src/person_subscriber.cpp)
target_link_libraries(person_subscriber ${catkin_LIBRARIES})
add_dependencies(person_subscriber ${PROJECT_NAME}_generate_messages_cpp)

#############
## Install ##
#############

保存,退出

这样编译配置就完成了。

编译和运行测试

编译必须回到 ~/catkin_ws 目录下

cd ~/catkin_ws

catkin_make

编译后应该source 一次:

source devel/setup.bash

如果编译有错,就要排除错误,然后就运行测试。

打开一个终端,启动ros,执行

roscore

再打开一个终端,启动订阅者,执行

rosrun learning_topic person_subscriber

再打开一个终端,启动发布者:

rosrun learning_topic person_publisher

程序运行结果如下:

c++ 验证成功。

python 验证源代码

要使用话题信息来验证,需要发布者和订阅者2个程序,我们都放在 工程目录的scripts 目录下

转到scripts 目录下,分别建立文件person_publisher.py 和 person_subscriber.py

~/catkin_ws/src/learning_topic/scripts

nano person_publisher.py

文件内容是:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 该例程将发布/person_info话题,自定义消息类型learning_topic::Person

import rospy
from learning_topic.msg import Person

def velocity_publisher():
	# ROS节点初始化
    rospy.init_node('person_publisher', anonymous=True)

	# 创建一个Publisher,发布名为/person_info的topic,消息类型为learning_topic::Person,队列长度10
    person_info_pub = rospy.Publisher('/person_info', Person, queue_size=10)

	#设置循环的频率
    rate = rospy.Rate(10) 

    while not rospy.is_shutdown():
		# 初始化learning_topic::Person类型的消息
    	person_msg = Person()
    	person_msg.name = "Tom";
    	person_msg.age  = 18;
    	person_msg.sex  = Person.male;

		# 发布消息
        person_info_pub.publish(person_msg)
    	rospy.loginfo("Publsh person message[%s, %d, %d]", 
				person_msg.name, person_msg.age, person_msg.sex)

		# 按照循环频率延时
        rate.sleep()

if __name__ == '__main__':
    try:
        velocity_publisher()
    except rospy.ROSInterruptException:
        pass

nano person_subscriber.py

文件内容是:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 该例程将订阅/person_info话题,自定义消息类型learning_topic::Person

import rospy
from learning_topic.msg import Person

def personInfoCallback(msg):
    rospy.loginfo("Subcribe Person Info: name:%s  age:%d  sex:%d", 
			 msg.name, msg.age, msg.sex)

def person_subscriber():
	# ROS节点初始化
    rospy.init_node('person_subscriber', anonymous=True)

	# 创建一个Subscriber,订阅名为/person_info的topic,注册回调函数personInfoCallback
    rospy.Subscriber("/person_info", Person, personInfoCallback)

	# 循环等待回调函数
    rospy.spin()

if __name__ == '__main__':
    person_subscriber()

运行测试

因为python 不需要编译,但需要设置为可执行文件

chmod +x *.py

打开一个终端,启动ros,执行

roscore

先source 一下:

source ~/catkin_ws/devel/setup.bash

再打开一个终端,启动订阅者,执行

rosrun learning_topic person_subscriber.py 

再打开一个终端,启动发布者:

rosrun learning_topic person_publisher.py

程序运行结果如下:

python 验证成功。

显示信息流关系

再打开一个新的终端,并输入命令:

rqt_graph

可以看到如下信息关系图:

源代码也可以在 https://github.com/huchunxu/ros_21_tutorials 下载

全文介绍到此。

猜你喜欢

转载自blog.csdn.net/leon_zeng0/article/details/114873060