文章目录
一、发布者和订阅者的编程实现
1. 环境准备
- 转移到工作空间目录下:
cd ~/catkin_ws/src
- 创建新的测试功能包:
catkin_create_pkg learning_topic roscpp rospy std_msgs geometry_msgs turtlesim
- 通讯模型图示如下:
2. 发布者publisher代码
- 由于此部分主要以代码为主,故在代码中写注释来分析:
/**
* 该例程讲发布turtle/cmd_vel话题,消息类型geometry_msgs::Twist
*/
#include <ros/ros.h>
// 导入ROS系统包含核心公共头文件
#include <geometry_msgs/Twist.h>
// 导入geometry_msgs/Twist消息头文件
int main(int argc, char **argv)
{
// ROS节点初始化,指定节点名称为velocity_publisher,注意名称要保持唯一性,
ros::init(argc, argv, "velocity_publisher");
// 创建节点句柄
ros::NodeHandle n;
// 创建一个publisher,发布名为/turtle1/cmd_vel的topic,
//消息类型为geometry_msgs::Twist,队列长度
//定义消息队列大小为10,即超过10条消息后,旧消息丢弃
ros::Publisher turtle_vel_pub = n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel", 10);
// 设置循环的频率
ros::Rate loop_rate(10);
int count = 0;
while (ros::ok())
{
/*
默认roscpp会植入一个SIGINT处理机制,当按下Ctrl‐C,就会让ros::ok()返回false, 那循环就会结束。
ros::ok() 返回false的几种情况:
SIGINT收到(Ctrl‐C)信号
另一个同名节点启动,会先中止之前的同名节点
ros::shutdown()被调用
所有的ros::NodeHandles被销毁
*/
// 初始化geometry_msgs::Twist类型的消息
geometry_msgs::Twist vel_msg;
vel_msg.linear.x = 0.5;
vel_msg.angular.z = 0.2;
// 发布消息
turtle_vel_pub.publish(vel_msg);
ROS_INFO("Publish turtle velocity command[%0.2f m/s, %0.2f rad/s]", vel_msg.linear.x, vel_msg.angular.z);
// 按照循环频率延时
loop_rate.sleep();
}
return 0;
}
3. 订阅者subsrciber代码
/**
* 该例程讲发布turtle1/pose话题,消息类型turtlesim::pose
*/
#include <ros/ros.h>
#include "turtlesim/Pose.h"
// 接收到订阅的消息后,会进入消息回调函数
void poseCallback(const turtlesim::Pose::ConstPtr& msg)
{
// 将接收到的消息打印出来
ROS_INFO("Turtle pose: x:%0.6f, y:%0.6f", msg->x, msg->y);
}
int main(int argc, char **argv)
{
// ROS节点初始化
ros::init(argc, argv, "pose_subscriber");
// 创建节点句柄
ros::NodeHandle n;
// 创建一个Subscriber, 订阅名为turtle1/pose的topic,注册回调函数poseCallback
ros::Subscriber pose_sub = n.subscribe("/turtle1/pose", 10, poseCallback);
// 循环等待回调函数
ros::spin();
return 0;
}
4. 编译并运行
CMakelist文件修改
- 发布者代码编译规则:
在install部分之前添加如下指令:
add_executable(velocity_publisher src/velocity_publisher.cpp) #设置需要编译的代码和生成的可执行文件 target_link_libraries(velocity_publisher ${catkin_LIBRARIES}) #设置链接库
- 订阅者代码编译规则:
在install部分之前添加如下指令:
add_executable(pose_subscriber src/pose_subscriber.cpp) #设置需要编译的代码和生成的可执行文件 target_link_libraries(pose_subscriber ${catkin_LIBRARIES}) #设置链接库
编译并运行
- 在工作空间目录下编译:
cd ~/catkin_ws
catkin_make
- ROS命令:
roscore
rosrun turtlesim turtlesim_node
rosrun learning_topic velocity_publisher
rosrun learning_topic pose_subscriber
二、自定义消息
1. 自定义话题消息
- 创建msg文件夹:
- 内部创建Person.msg文件:
string name
uint8 sex
uint8 age
uint8 unknown = 0
uint8 male = 1
uint8 female = 2
2. 添加功能包依赖和编译规则
- 修改XML文件:
添加如下指令
<build_depend>message_generation</build_depend> <exec_depend>message_runtime</exec_depend>
- 修改CMakelist文件:
在最初添加:
find_package(...... message_generation)
在Declare ROS之前添加:add_message_files(FILES Person.msg) generate_messages(DEPENDENCIES std_msgs)
在build之前添加
catkin_package(...... message_runtime)
- 编译:在编译后可以在devel下的include中找到learning_topic的person头文件
3. 创建编译代码
发布者
- 头文件:
#include <learning_topic/Person.h>
- 发布话题:
ros::Publisher person_info_pub = n.advertise<learning_topic::Person>("/person_info", 10);
- 循环内消息传递:
// 初始化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);
订阅者
- 头文件:
#include <learning_topic/Person.h>
- 消息回调打印:
// 将接收到的消息打印出来
ROS_INFO("Subscribe Person Info: name:%s age:%d sex:%d",
msg->name.c_str(), msg->age, msg->sex);
- 订阅话题:
// 创建一个Subscriber, 订阅名为/person_info的topic,注册回调函数poseCallback
ros::Subscriber person_info_sub = n.subscribe("/person_info", 10, poseCallback);
4. 编译并运行
- 修改CMake文件
在install之前添加:
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)
- 编译并运行
cd ~/catkin_ws
catkin_make
roscore
rosrun learning_topic person_subscriber
rosrun learning_topic person_publisher
三、Python编程
- 对于Python编程而言,与C++的区别存在三点
- 自行建立sripts文件夹,并且需要修改属性,保证py文件可以作为程序执行文件
- 代码风格不同,具体代码由于篇幅原因不进行展示
- CMake文件修改方法不同,Python的修改方法如下:
在指定位置找到并修改成如下:catkin_install_python(PROGRAMS scripts/velocity_publisher.py DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} )
- 在实际的编译过程中我们能够发现,Python的开发相比C++简单很多,无需添加一大堆依赖项和链接,更加简洁
总结
本文借鉴了古月居的ROS入门21讲的部分内容,主要目的在于从编程代码出发深入认识ROS的话题通讯机制,并掌握基本的ROS编程技巧,下一篇博客将会对服务器/客户端通讯进行研究,敬请期待。