ROS 快速入门教程02
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 运行节点
打开两个终端分别输入
roscorerosrun 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 小结