最近由于项目所需刚开始学习ros,学习自b站的古月 ROS入门21讲,做一个总结,仅为自己学习使用,可供参考。
《ROS机器人开发实践》一书中讲的十分清楚,这里只是我自己的一个通俗的理解。
实现一个publisher发送消息topic,subscriber从topic中接收消息。其中包含了四个部分:
1 . 发布者(publisher)。
2. 订阅者(subscriber)。
3. 话题(topic): 发布者发布消息给话题,订阅者从指定话题订阅消息。
4. 消息(message):发送或接收的消息类型可以使用已有的消息类型,也可以自己定义消息类型。
以小乌龟程序为例,利用键盘对乌龟进行操作的指令如下
rosrun turtlesim turtle_teleop_key
节点关系如下:
这里有两个节点/teleop_turtle和 /turtlesim,和一个话题/turtle1/cmd_vel组成。/teleop_turtle创建了一个发布者,用于发布键盘控制的指令;/turtlesim创建了一个订阅者,用于订阅速度指令,实现乌龟的运动;/turtle1/cmd_vel是话题。
topic一共由发布者、订阅者、话题、消息组成。其中的发布者和订阅者是节点,需要通过C++或python来分别进行定义,话题和消息则是在这两个代码文件中进行调用,步骤如下:
1、创建功能包。一切的程序调用都需要在功能包中完成。
2、自定义话题消息。若使用已有的消息类型则不需要定义。
3、publisher源文件的创建。(C++或python)
4、subscriber源文件的创建。(C++或python)
5、编译生成可执行文件(python可省略该步骤)。
(6、测试执行)
下面以一个发布和订阅人员信息的例子详细介绍每一个步骤:
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src
catkin_init_workspace
cd ~/catkin_ws
catkin_make
source devel/setup.bash
cd ~/catkin_ws/src
在src文件夹路径下建立功能包catkin_create_pkg learning_topic roscpp rospy std_msgs
创建功能包,其中learning_topic是功能包名称,roscpp、rospy、std_msgs是相关依赖。1、learning_topic功能包中建立名为“msg”文件夹,用以保存Person.msg文件。
2、在msg文件夹中用touch或gedit指令建立一个名为“Person.msg”文件,其文件内容如下:
string name
uint8 age
uint8 sex
uint8 unknown = 0
uint8 male = 1
uint8 female = 2
1、添加编译依赖:
2、添加执行依赖:
1、在“find_package”中添加
message_generation
2、将定义的Person.msg文件作为定义的消息接口,针对定义编译。
在“Declare ROS message, service and actions”中添加
add_message_files(FILES Person.msg)
3、说明编译Person.msg时所依赖的包。
在“Declare ROS message, service and actions”中添加
generate_messages(DEPENDENCIES std_msgs)
4、添加message运行的依赖。
在“catkin_package”中添加
CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
进入工作空间根目录进行编译
cd ~/catkin_ws
catkin_make
在路径~/catkin_ws/devel/include
中会产生Person.h文件,里面就是定义的消息类型
在~/catkin_ws/src/learning_topic/src
路径下创建publisher源文件:person_publisher.cpp
其源代码如下:
//添加所依赖的头文件
#include
#include
//主函数
int main(int argc,char **argv)
{
//初始化节点,"person_publisher"为发布者节点
ros::init(argc,argv,"person_publisher");
//设置句柄
ros::NodeHandle n;
//创建发布者,发布者名字为person_info_pub;消息类型为learning_topic::Person;话题节点为/person_info;10代表缓冲队列大小
ros::Publisher person_info_pub = n.advertise<learning_topic::Person>("/person_info",10);
//设置循环频率,单位是HZ
ros::Rate loop_rate(1);
//进入循环
int count = 0;
while(ros::ok())
{
//初始化learning_topic::Person类型消息
learning_topic::Person person_msg; //声明Person类的一个对象person_msg
person_msg.name = "Tom";
person_msg.age = 18;
person_msg.sex = learning_topic::Person::male; //调用预定义的宏
//发布消息
person_info_pub.publish(person_msg); //发布者person_info_pub发布消息
//显示发布信息
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();
}
}
在~/catkin_ws/src/learning_topic/src
路径下创建subscriber源文件:person_sbscriber.cpp
其源代码如下:
//添加所依赖的头文件
#include
#include
//回调函数
void PersonInfoCallback(const learning_topic::Person::ConstPtr& msg)
{
//显示接收到的信息
ROS_INFO("subscribe Person Info:name:%s,age:%d,sex:%d",msg->name.c_str(),msg->age,msg->sex);
}
//主函数
int main(int argc,char **argv)
{
//初始化节点,"person_subscriber"为订阅节点
ros::init(argc,argv,"person_subscriber");
//设置句柄
ros::NodeHandle n;
//创建订阅者,person_info_sub是订阅者,从话题“/person_info”订阅
ros::Subscriber person_info_sub = n.subscribe("/person_info",10,PersonInfoCallback);
//循环等待
ros::spin();
return 0;
}
1、生成可执行文件
add_executable (person_publisher src/person_publisher.cpp)
add_executable (person_subscriber src/person_subscriber.cpp)
2、设置链接
target_link_libraries(person_publisher ${catkin_LIBRARIES})
target_link_libraries(person_subscriber ${catkin_LIBRARIES})
3、添加依赖
add_dependencies(person_publisher ${PROJECT_NAME}_generate_message_cpp)
add_dependencies(person_subscriber ${PROJECT_NAME}_generate_message_cpp)
在~/catkin_ws
路径下执行
catkin_make
测试之前记得先要source devel/setup.bash
,创建环境变量。
打开三个终端分别输入以下命令:
roscore
rosrun learning_topic person_publisher
rosrun learning_topic person_subscriber
执行成功后打开新的终端执行rqt_graph
查看节点关系如下:
其中/person_publisher是发布者节点,发送消息给/person_info话题,/person_subscriber是订阅者节点,从person_info话题订阅消息。消息类型为learning_topic::Person。