5. Node 节点
以智能手机为例,当我们使用智能手机的某个功能时,大多时候在使用手机的某个APP。同样当我们使用ROS的某个功能时,使用的是ROS的某一个或者某一些节点。

虽然每次我们只使用ROS的某一个或者某一些节点,但我们无法下载单一节点,这些节点是以包的形式存储的,上一篇内容以讲解如何安装apt包,这里不再演示。

5.1 工作空间设置
这里以建立一个超声波工作包为例。
打开终端输入
cd catkin_ws/src #进入代码目录
catkin_create_pkg ssr_pkg rospy roscpp std_msgs
catkin_create_pkg +包名+依赖项列表
catkin_create_pkg是 ROS 中用来创建包的命令。ssr_pkg是你要创建的包的名字。rospy,roscpp,std_msgs是你在创建包时所依赖的 ROS 包。- 简单来说,这条命令会创建一个名为
ssr_pkg的 ROS 包,并自动将rospy(Python客户端库)、roscpp(C++客户端库)和std_msgs(标准消息类型)作为依赖项包含进去。
5.1.1 学习roscpp依赖项
打开终端输入
roscd roscpp
ls
code package.xml


name:包名
version:版本
description:包的内容描述
maintainer:维护者信息
有以上四条内容的xml文件基本能确定该目录里存放ros的一个功能包,以后可以根据这种方式判断目录是否为ros功能包。
5.2 自创软件包和下载软件包的区别
我们注意到roscpp这个软件包在/opt/ros/noetic/share文件夹下,该文件夹下还有许多软件包。
这些软件包都是我们使用sudo apt install指令或安装ROS自带下载下来的。
这些软件包与我们建立的catkin_ws工作目录下的软件包不同点在于,这些包是现成的可执行文件可以直接使用执行,而catkin_ws目录下的都是源码文件,需要编译后才能运行。
这时我们可以回想在.bashrc文件里编辑的两条指令:

第一条便是加载apt下载的软件包地址,第二个加载catkin_ws目录下的软件包地址。
5.3 创建超声波包的节点
打开vscode,创建chao_node.cpp文件。

#include<ros/ros.h>
int main(int argc, char **argv)
{
printf("Hello, ROS!\n");
return 0;
}
如有爆红,请删除json文件并重启vscode,打开setting.json,调整至 "C_Cpp.errorSquiggles": "disabled"

5.4 编译文件
打开CMakeList文件找到Build章节。

找到
add_executable(${PROJECT_NAME}_node src/ssr_pkg_node.cpp)
复制后放到最下面,取消注释并改为:
add_executable(chao_node src/chao_node.cpp)
然后运行编译:

5.5 运行节点
打开两个终端分别输入
roscore
rosrun ssr_pkg chao_node

用vscode打开chao_node文件。
#include<ros/ros.h>
int main(int argc, char **argv)
{
ros::init(argc, argv, "chao_node");
printf("当你能编译这条指令时,你已经基本学会ROS节点的编译了。\n");
return 0;
}
打开CMakeList找到
target_link_libraries(${PROJECT_NAME}_node
${catkin_LIBRARIES}
)
复制到最下面取消注释,改为:
target_link_libraries(chao_node
${catkin_LIBRARIES}
)
保存并编译。

5.6 ROS中的while循环
与cpp中的while循环不同,ROS中的while循环括号内并不是存放true or false而是ros::ok()。
5.7 小结

6.Topic话题与Message消息
6.1 Topic(话题)
话题 是一种消息通信的机制,在 ROS 中用于实现 发布-订阅 模式。发布者(Publisher)将数据发布到一个话题上,而订阅者(Subscriber)订阅该话题来接收数据。话题是无连接的,即它不要求发布者和订阅者之间建立直接的联系。
- 发布者(Publisher):一个节点可以作为话题的发布者,定期将数据发送到指定的话题。
- 订阅者(Subscriber):另一个节点可以订阅该话题,从中接收数据。
在 ROS 中,话题通常是用于传输实时数据,例如传感器数据、机器人状态信息等。
特点:
- 无连接性:发布者和订阅者之间没有直接连接,它们通过话题传递消息。
- 异步通信:数据发送和接收是异步的,发布者可以继续发布数据,订阅者接收到数据后进行处理。
- 多对多通信:一个话题可以同时有多个发布者和多个订阅者。
6.2 Message(消息)
消息 是 ROS 中传输的数据格式。它定义了数据的类型和结构,类似于一个数据包。消息的结构由字段组成,这些字段的类型可以是简单的基础类型(如 int、float)或复杂的自定义类型(如数组、结构体等)。
ROS 提供了许多标准消息类型,如 std_msgs/String、sensor_msgs/Image、geometry_msgs/Twist 等,用户也可以定义自定义的消息类型。
消息的类型:
- 标准消息类型:ROS 定义了很多标准消息类型,可以直接使用。例如,
std_msgs/String用于传递字符串数据,sensor_msgs/Image用于传递图像数据,geometry_msgs/Twist用于表示机器人运动的线速度和角速度等。 - 自定义消息类型:用户可以根据需要定义自己的消息类型。自定义消息通常通过
.msg文件来描述,它们存储在 ROS 包中并在编译时生成相应的代码。 -
消息的定义格式:
ROS 中的消息通过 .msg 文件定义,文件中的每一行都描述了一个字段及其数据类型。例如,一个自定义的消息文件 Person.msg 可能会像这样定义:
string name
int32 age
float32 height
该文件描述了一个 Person 消息类型,包含了 name(字符串)、age(32位整数)和 height(32位浮点数)三个字段。
消息的发布与订阅:
- 发布者发送消息:发布者通过
advertise()函数来创建一个话题并开始发布消息。 - 订阅者接收消息:订阅者通过
subscribe()函数来订阅一个话题,并在回调函数中处理接收到的消息。
话题与消息的关系
- 话题 是一个数据流的通道,是消息的发布和订阅的载体。节点通过发布和订阅话题来进行数据交换。
- 消息 是话题上传输的具体数据内容。消息通过话题从发布者传递到订阅者,订阅者可以通过回调函数处理接收到的消息。
消息类型和自定义消息
ROS 提供了很多常见的消息类型,便于开发者使用,如:
std_msgs/String:字符串消息。geometry_msgs/Twist:用于表示机器人速度的消息,包含线速度和角速度。sensor_msgs/Image:用于传输图像数据的消息。
如果预定义的消息类型不能满足需求,开发者可以创建自定义消息类型。自定义消息类型是通过 .msg 文件定义的,ROS 会根据这些文件自动生成 C++ 和 Python 代码,使得这些消息可以被传递和处理。
6.3 小结


7.使用C++编写Publisher发布者节点
打开之前的chao_node.cpp,改为:
#include<ros/ros.h>
#include<std_msgs/String.h>
int main(int argc, char *argv[])
{
ros::init(argc, argv, "chao_node");
printf("你已经成功编译了一个ROS节点\n");
ros::NodeHandle nh;
ros::Publisher pub = nh.advertise<std_msgs::String>("ssr_node_topic", 10);
while(ros::ok())
{
printf("你已经成功编译了一个ROS节点!\n");
std_msgs::String msg;
msg.data = "Hello, ROS!";
pub.publish(msg);
}
return 0;
}
NodeHandle是 ROS 中用于与 ROS 系统交互的接口。它为节点提供了一些基本的功能,包括与 ROS 参数服务器的交互、发布/订阅话题、服务调用等。创建NodeHandle实例时,它会自动连接到 ROS Master,并初始化该节点的相关通信设施。nh是一个ros::NodeHandle类型的对象,用于在当前节点中执行与 ROS 系统的通信任务。nh.advertise<std_msgs::String>("ssr_node_topic", 10):这是NodeHandle对象nh调用的advertise函数,作用是告诉 ROS 系统:当前节点将向名为"ssr_node_topic"的话题发布消息,消息类型为std_msgs::String,并且该话题的队列大小为10。即,当消息还未被消费时,最多有 10 个消息会被保存在队列中,超过这个数目时,新的消息将会丢弃(或覆盖掉旧的消息,取决于配置)。ros::Publisher pub:创建一个ros::Publisher类型的对象pub,它是用来管理消息发布操作的。通过它,你可以发布消息到话题中。std_msgs::String的消息对象msg。std_msgs::String是 ROS 中的一种消息类型,用于传输字符串数据。msg是一个std_msgs::String类型的变量,表示一个消息实例,你可以将要发布的数据(即字符串)赋给msg的data字段。pub.publish(msg)是调用ros::Publisher对象pub的publish方法,该方法负责将消息发送到指定的话题。msg是要发布的消息对象,这里它包含了一个字符串"Hello, ROS!"。当调用publish(msg)时,ROS 会将消息msg发布到在创建pub时指定的"ssr_node_topic"话题上,其他节点如果订阅了该话题,就会收到这个消息。
7.2 运行新节点
启动roscore,再打开新的终端输入rosrun ssr_pkg chao_node

在打开新的终端输入命令,查看当前运行的话题
rostopic list

再输入
rostopic echo /ssr_node_topic
查看话题内容

创建新窗口输入,查看话题每秒钟发送频率。
rostopic hz /ssr_node_topic

7.2 控制话题频率
#include<ros/ros.h>
#include<std_msgs/String.h>
int main(int argc, char *argv[])
{
ros::init(argc, argv, "chao_node");
printf("你已经成功编译了一个ROS节点\n");
ros::NodeHandle nh;
ros::Publisher pub = nh.advertise<std_msgs::String>("ssr_node_topic", 10);
ros::Rate loop_rate(10);
while(ros::ok())
{
printf("你已经成功编译了一个ROS节点!\n");
std_msgs::String msg;
msg.data = "Hello, ROS!";
pub.publish(msg);
loop_rate.sleep();
}
return 0;
}
重复上述步骤就能获得每秒刷新频率为10的话题。

7.3 小结




















