文章只是个人学习过程中学习笔记,主要参考ROS教程1 2 3。
msg(消息)文件就是文本文件,用于描述ROS消息的字段。它们用于为不同编程语言编写的消息生成源代码。
msg文件存放在软件包的msg目录下。
msg4文件就是简单的文本文件,每行都有一个字段类型和字段名称。它的结构为:
fieldtype + fieldname
可以使用的类型为:
# 特殊的Header类型,它含有时间戳和ROS中广泛使用的坐标帧信息
# 在msg文件的第一行经常可以看到Header header。
std_msgs/Header header
uint8 is_true
uint32 height
uint32 width
string child_frame_id
time stamp
geometry_msgs/PoseWithCovariance pose
geometry_msgs/TwistWithCovariance twist
uint8[] data
rosmsg显示有关ROS消息类型的信息。
| 命令 | 功能 |
|---|---|
rosmsg show | 显示消息的描述(详细信息) |
rosmsg info | rosmsg show的别名,功能一样 |
rosmsg list | 列出所有消息 |
rosmsg md5 | 显示md5加密的消息 |
rosmsg package | 列出某个软件包(package)的消息 |
rosmsg packages | 列出包含消息的软件包(packages) |
还是在原来创建的软件包 beginner_tutorials 中定义一个新的消息。
# 切换到软件包的目录路径
roscd beginner_tutorials
# 创建msg文件夹目录
mkdir msg
# 创建名为Num.msg的文件,并添加一个消息字段
echo "int64 num" > msg/Num.msg
1. 为已经存在里面的find_package调用添加message_generation依赖项(),这样就能生成消息了。(添加 message_generation 依赖项,必须有 std_msgs 。)
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
2. 添加自定义的消息文件。将你msg文件夹中自定义的*.msg文件添加在这里。
add_message_files(
FILES
Num.msg
)
3. 用于生成所有定义的message文件,需要添加本文件需要依赖的packages。其实就是告诉编译器,编译 *.msg 文件时,需要依赖的库或package。
generate_messages(
DEPENDENCIES
std_msgs
)
4. 导出消息的运行时依赖关系。
catkin_package(
...
CATKIN_DEPENDS message_runtime ...
...)
添加编译依赖与执行依赖。
<build_depend>message_generationbuild_depend>
<exec_depend>message_runtimeexec_depend>
Node:在构建时,其实只需要message_generation,而在运行时,我们只需要message_runtime。
已经创建了一些新消息,所以需要重新make一下软件包:
cd
cd catkin_ws
catkin_make

msg目录中的任何.msg文件都将生成所有支持语言的代码。
~/catkin_ws/devel/include/beginner_tutorials/
~/catkin_ws/devel/lib/python2.7/dist-packages/beginner_tutorials/msg
rosmsg list 列出ROS中的所有消息(msg)。
rosmsg packages [options] 列出包含消息的软件包。
# 列出包含消息的软件包,每行显示一个软件包名
rosmsg packages
# 在一行中列出包含消息的软件包
rosmsg packages -s
rosmsg package [package-name] 列出某个软件包(package)的消息。

rosmsg show [message type] 显示消息的详细信息。

rosmsg md5[message type] 显示md5加密的消息。如果编译的版本不匹配,这也会发出警告。
Node:md5 命令仅供专家用户使用。(??)
功能:基于话题通信,发布者以一定频率发布自定义消息并打印输出消息,订阅者订阅自定义消息并打印输出消息。
实现:
1. 创建发布者(talker)节点,该节点不断广播自定义消息。
2. 创建订阅者(listener)节点,该节点持续接收自定义消息。
3. 创建自定义消息(Num.msg),(见4.1小节 创建msg)
4. 发布订阅话题chatter
在beginner_tutorials软件包的src目录下创建发布者和订阅者源文件:
roscd beginner_tutorials
cd src
touch talker.cpp listener.cpp
#include "ros/ros.h"
#include "beginner_tutorials/Num.h" // 在 /devel/include 目录下
int main(int argc, char **argv)
{
/* 防止中文乱码 */
setlocale(LC_ALL,"");
/* 初始化ROS节点 */
ros::init(argc, argv, "talker");
/* 为这个进程节点创建句柄 */
ros::NodeHandle nh;
/* 创建发布者对象 */
ros::Publisher pub = nh.advertise<beginner_tutorials::Num>("chatter", 1000);
/* 设定循环发布的频率为1Hz */
ros::Rate loop_rate(1);
/* 要发布的消息 */
beginner_tutorials::Num msg;
msg.num = 0;
while(ros::ok())
{
ROS_INFO("当前num值为: %d",msg.num);
/* 发布消息 */
pub.publish(msg);
ros::spinOnce();
loop_rate.sleep();
msg.num += 1;
}
return 0;
}
对上边的内容进行一下总结:
- 初始化ROS系统
- 向主节点宣告我们将要在
chatter话题上发布beginner_tutorials/Num类型的消息- 以每秒1次的速率向
chatter话题循环发布消息
#include "ros/ros.h"
#include "beginner_tutorials/Num.h" // 在 /devel/include 目录下
/* 回调函数,当有新消息到达chatter话题时就会调用 */
void chatterCallback(const beginner_tutorials::Num::ConstPtr& msg)
{
ROS_INFO("已收到的Num的值: %d",msg->num);
}
int main(int argc, char **argv)
{
/* 防止中文乱码 */
setlocale(LC_ALL,"");
/* 初始化ROS节点 */
ros::init(argc, argv, "listener");
/* 为这个进程节点创建句柄 */
ros::NodeHandle nh;
/* 创建订阅者对象
* 通过节点管理器订阅chatter话题。收到消息,调用回调函数chatterCallback。
* 第2个参数是队列大小,>1000时,丢弃旧消息。
*/
ros::Subscriber sub = nh.subscribe("chatter",1000, chatterCallback);
/* 启动自循环 回调函数处理, 不占用太多CPU */
ros::spin();
return 0;
}
同样地,我们来总结一下:
- 初始化ROS系统
- 订阅
chatter话题- 开始spin自循环,等待消息的到达
- 当消息到达后,调用
chatterCallback()函数
只需将这几行添加到CMakeLists.txt文件的底部:
add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_dependencies(talker ${PROJECT_NAME}_generate_messages_cpp)
add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
add_dependencies(listener ${PROJECT_NAME}_generate_messages_cpp)
编译后,在终端中执行过程如下所示。

在beginner_tutorials软件包的scripts目录下创建发布者和订阅者源文件:
roscd beginner_tutorials
cd scripts
touch talker.py listener.py
chmod +x talker.py listener.py
#!/usr/bin/env python
# encoding: utf-8
import rospy
from beginner_tutorials.msg import Num
def talker():
# 初始化ROS节点
rospy.init_node("talker",anonymous=True)
# 创建发布者对象
pub = rospy.Publisher('chatter', Num, queue_size=1000)
# 创建一个Rate对象rate,1Hz
rate = rospy.Rate(1)
# 要发布的消息
msg = Num()
msg.num = 0
# 循环
while not rospy.is_shutdown():
rospy.loginfo("当前num值为: %d",msg.num)
pub.publish(msg)
rate.sleep()
msg.num += 1
if __name__ == '__main__':
try:
talker()
except rospy.ROSInterruptException:
pass
#!/usr/bin/env python
# encoding: utf-8
import rospy
from beginner_tutorials.msg import Num
def callback(msg):
rospy.loginfo("已收到的Num的值: %d",msg.num)
def listener():
# 初始化ROS节点
rospy.init_node("listener",anonymous=True)
# 创建发布者对象
pub = rospy.Subscriber('chatter', Num, callback, queue_size=1000)
rospy.spin()
if __name__ == '__main__':
listener()
# 安装python可执行脚本
catkin_install_python(PROGRAMS
scripts/turtle_publisher.py
scripts/talker.py
scripts/listener.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
编译后,在终端中执行过程如下所示。

ROS.otg. ROS教程[EB/OL]. 2020-12-22[2022-7-5].
http://wiki.ros.org/cn/ROS/Tutorials. ↩︎
.ROS.org. 编写简单的发布者和订阅者(C++)[EB/OL]. 2020-12-25[2022-07-30]. https://wiki.ros.org/cn/ROS/Tutorials/WritingPublisherSubscriber%28c%2B%2B%29. ↩︎
.ROS.org. 编写简单的发布者和订阅者(Python)[EB/OL]. 2020-12-25[2022-07-30]. https://wiki.ros.org/cn/ROS/Tutorials/WritingPublisherSubscriber%28python%29. ↩︎
ROS.org. msg[EB/OL]. https://wiki.ros.org/msg[2022-07-30]. https://wiki.ros.org/msg. ↩︎