目录
简要介绍
在ROS中,话题(topics)是最常用的通信机制之一,它允许节点之间以异步的方式进行消息的发布和订阅。一个节点可以发布某个话题的消息,而其他节点则可以订阅该话题以接收相应的消息。
话题通信机制是一种:一(发布者)对多(订阅者)、异步的通信机制
ROS话题通信机制的一些核心概念和流程:
1.消息类型(Message type):在ROS中,每个话题都有一个特定的消息类型,该消息类型定义了该话题所传递的数据结构和内容。例如,一个表示激光雷达扫描数据的消息类型可能包括激光雷达的位置、角度、距离等信息。
2.发布者(Publisher):发布者是一个ROS节点,它可以将特定消息类型的数据发布到某个话题中,其他节点可以通过订阅该话题来接收该消息。一个节点可以同时作为多个话题的发布者。
3.订阅者(Subscriber):订阅者是一个ROS节点,它可以从某个话题中接收特定消息类型的数据,从而实现对该话题的订阅。一个节点可以同时订阅多个话题。
4.话题名称(Topic name):话题名称是一个字符串,用来标识某个话题在ROS系统中的唯一性。在进行订阅或发布操作时,节点需要指定要订阅或发布的话题名称。
5.消息队列(Message queue):消息队列是一个缓存区,用来存储已发布但未被订阅者接收的消息。当节点订阅某个话题时,如果该话题之前已经有消息发布,那么这些消息会首先被放入消息队列中,等待订阅者进行接收。
话题通信的流程如下
1.发布者创建一个话题,并将特定消息类型的数据发布到该话题中。
2.订阅者订阅特定话题,等待接收该话题中的消息。
3.如果在订阅者订阅之前已经有消息发布到该话题中,那么这些消息会被放入消息队列中,等待订阅者进行接收。
4.当发布者发布新的消息时,订阅者会收到该消息并进行处理。
ROS常见的topic命令行指令
rostopic echo
:该命令可以用于打印某个话题的消息内容,从而实时监测该话题的状态和数据。例如,使用rostopic echo /scan
可以实时显示激光雷达数据。
rostopic hz
:该命令可以用于查看某个话题的发布频率,从而评估系统的性能和稳定性。例如,使用rostopic hz /scan
可以显示激光雷达数据的发布频率。
rostopic info
:该命令可以用于查看某个话题的详细信息,包括其名称、数据类型、发布者和订阅者等内容。例如,使用rostopic info /scan
可以显示激光雷达数据的相关信息。
rostopic list
:该命令可以列举出当前ROS系统中所有可用的话题名称,从而方便用户查看和选择特定话题。例如,使用rostopic list
可以显示所有可用的话题名称。
rostopic pub
:该命令可以用于往某个话题中输入特定的消息内容,从而模拟某些场景下的数据输入。例如,使用rostopic pub /cmd_vel geometry_msgs/Twist "{linear: {x: 0.1}, angular: {z: 0.5}}"
可以向/cmd_vel话题发送一个Twist消息。
rostopic bw
:该命令可以用于查看某个话题的带宽使用情况,从而评估系统网络和性能瓶颈。例如,使用rostopic bw /scan
可以显示激光雷达数据的带宽使用情况。
rostopic find
:该命令可以根据数据类型查找符合条件的话题名称,从而方便用户快速定位到特定话题。例如,使用rostopic find std_msgs/String
可以查找所有数据类型为std_msgs/String的话题名称。
rostopic type
:该命令可以用于查看某个话题的数据类型,从而帮助用户了解该话题所传递的数据结构和内容。例如,使用rostopic type /scan
可以显示激光雷达数据的数据类型。
发布话题
发布话题是指将消息发送到特定的话题,以便其他节点可以接收和处理这些消息。话题是一种基于发布-订阅模式的通信机制,它允许不同的节点之间进行异步的消息传递。
1.创建ROS节点并初始化
在开始发布消息之前,需要先创建一个ROS节点,并进行初始化。这个节点将负责发布消息到指定的话题。
cpp
#include "ros/ros.h"
int main(int argc, char **argv)
{
// 初始化ROS节点
ros::init(argc, argv, "publisher_node");
// 创建NodeHandle对象
ros::NodeHandle nh;
// 在这里编写发布者的代码
return 0;
}
2.创建话题发布者
在ROS节点中,你需要创建一个话题发布者对象。话题发布者用于将消息发送到特定的话题。你需要指定话题的名称和消息类型作为发布者的参数。
ros::Publisher pub = nh.advertise<消息类型>("话题名称", 队列大小);
e.g如果要发布字符串消息到名为/chatter
的话题上
cpp
ros::Publisher pub = nh.advertise<std_msgs::String>("/chatter", 10);
3.创建消息实例并设置内容
在发布消息之前,需要创建一个对应消息类型的实例,并设置其内容。
消息类型 message;
message.字段 = 值;
e.g.对于
std_msgs::String
消息类型,可以这样创建一个消息实例,并将其内容设置为"Hello, World!":std_msgs::String message;
message.data = "Hello, World!";
4.将消息发布出去
使用话题发布者的publish()
方法将消息发布到指定的话题上。
pub.publish(message);
5.保持节点运行
在发布消息后,一般需要调用ros::spin()
或者ros::spinOnce()
来保持节点处于运行状态,以便能够发送消息并接收其他节点发送的消息。
ros::spin();
// 或者
ros::spinOnce();
订阅话题
订阅者(Subscriber)用于接收和处理其他节点发布的消息。订阅者通过订阅特定的话题来接收消息,并在接收到消息后执行相应的回调函数进行处理。下面是订阅话题的详细步骤:
初始化ROS节点和创建NodeHandle
在开始订阅消息之前,首先需要初始化ROS节点并创建一个NodeHandle对象。
cpp
#include "ros/ros.h"
int main(int argc, char **argv)
{
ros::init(argc, argv, "subscriber_node");
ros::NodeHandle nh;
// 在这里编写订阅者的代码
ros::spin(); // 保持节点运行
return 0;
}
创建订阅者并指定回调函数
使用NodeHandle对象的subscribe<消息类型>("话题名称", 队列大小, 回调函数)
方法创建一个订阅者,指定要订阅的消息类型、话题名称、队列大小以及接收到消息时要调用的回调函数。
ros::Subscriber sub = nh.subscribe("话题名称", 队列大小, 回调函数);
e.g如果要订阅名为/chatter
的字符串消息,可以这样创建订阅者:
cpp
void messageCallback(const std_msgs::String::ConstPtr& msg)
{
ROS_INFO("Received message: %s", msg->data.c_str());
}
ros::Subscriber sub = nh.subscribe("/chatter", 10, messageCallback);
编写消息回调函数
消息回调函数是在接收到消息时被调用的函数,用于处理接收到的消息数据。
cpp
void messageCallback(const 消息类型::ConstPtr& msg)
{
// 处理接收到的消息
}
保持节点运行:
最后,在订阅消息后,通常需要调用ros::spin()
或者ros::spinOnce()
来保持节点处于运行状态,以便接收和处理消息。
完整的订阅者代码:
cpp
#include "ros/ros.h"
#include "std_msgs/String.h"
void messageCallback(const std_msgs::String::ConstPtr& msg)
{
ROS_INFO("Received message: %s", msg->data.c_str());
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "subscriber_node");
ros::NodeHandle nh;
ros::Subscriber sub = nh.subscribe("/chatter", 10, messageCallback);
ros::spin();
return 0;
}
自定义消息类型数据
创建消息文件
使用ROS消息描述语言(Message Description Language,简称msg)创建一个消息文件,该文件定义了自定义消息的结构和字段。通常,消息文件位于msg
文件夹中。
e.g创建一个名为CustomMessage.msg
的消息文件,其中包含一个字符串字段data
cpp
string data
在CMakeLists.txt
中添加消息依赖
在ROS软件包的CMakeLists.txt
文件中添加对自定义消息的依赖项。
cpp
find_package(catkin REQUIRED COMPONENTS
roscpp
std_msgs
message_generation # 添加这行
)
add_message_files(
FILES
CustomMessage.msg # 添加你创建的消息文件
)
generate_messages(
DEPENDENCIES
std_msgs
)
确保在CMakeLists.txt
的catkin_package()
函数之前添加了message_generation
依赖。
编译和构建
运行catkin_make
命令编译和构建ROS软件包。
cpp
cd catkin_ws
catkin_make
使用自定义消息类型
在代码中使用自定义消息类型,包括订阅者和发布者。
cpp
#include "ros/ros.h"
#include "package_name/CustomMessage.h" // 替换成你的自定义消息类型
void messageCallback(const package_name::CustomMessage::ConstPtr& msg)
{
ROS_INFO("Received message: %s", msg->data.c_str());
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "subscriber_node");
ros::NodeHandle nh;
ros::Subscriber sub = nh.subscribe("/chatter", 10, messageCallback);
ros::spin();
return 0;
}
上述将
package_name
替换为你的自定义消息所在的软件包名。CustomMessage
是自定义消息类型的名称,需要根据实际情况进行替换。确保在使用自定义消息之前,已经运行了
catkin_make
命令来编译和构建ROS软件包,以便让ROS能够正确识别和使用自定义消息类型。
注意点
在使用自定义消息之前,要确保订阅者和发布者都使用了相同的自定义消息类型,并且正确地引用了消息类型的头文件。