本文参考了ROS_Kinetic_05 ROS基础内容,在本人的计算机环境ubuntu16.04 64bit+kinetic基础上进行实践。
1. ROS节点node的基本概念和操作
官网教程:http://wiki.ros.org/cn/ROS/Tutorials/UnderstandingNodes
涉及到的基本概念:
Nodes:节点,一个节点即为一个可执行文件,节点之间通过ROS这个系统进行通信。
Messages:消息,消息是一种ROS数据类型,用于主题的订阅或发布。
Topics:主题,节点可以发布消息到主题,也可以订阅某些主题以接收这些主题的消息。
Master:节点管理器,ROS名称服务。(在ROS2中取消了Master节点)
rosout: ROS中相当于stdout/stderr。
roscore: 主机+ rosout + 参数服务器。
rospy = python 客户端库
roscpp = c++ 客户端库
节点是ROS中最重要的概念之一。每个ROS运行实例被称为节点。换句话说,每个ROS程序运行的进程,就是一个节点。每个机器人程序,可以有非常多个节点。我们也可以运行同一个程序的多个副本(但要确保每个副本使用不同节点名),则每个副本都被当作一个独立节点。
节点(Node)可以用来提供某种数据或能力,比如读取某Sensor数据。也可以是一个获取这些数据并处理的节点(Node),例如从别的节点那拿到Sensor并处理。但他们之间如何知道对方存在与否呢?哪些node需要哪种数据呢?这就需要有个管理者,它就是NodeMaster/ Node Core。每个Node启动时,需要向它注册,申明自己提供什么服务或需要什么数据。
Node是ROS package中一个可执行文件。ROS node利用ROS用户库去和其他node进行通信。nodes也可以向topic发起发布或者订阅,nodes也可以提供或者使用一个service.
为何说Node是ROS核心,看看它通常被用来做什么:
控制电机速度,获取激光雷达数据,获取Camera数据,利用以上数据定位,路径规划。
启动一个Node:
#rosrun package-name executable-name
两个参数,参数1:功能包名。 参数2:可执行文件名。(见后面的例子)
查看当前有哪些Node:
#rosnode list
停止一个Node:
#rosnode kill node-name
虽然也可以ctrl-c停止,但此时Node master 可能会没有及时注销此node.造成误会。(当然这种情况可以:rosnode cleanup)
查看当前运行的node的信息:
#rosnode info Node_Name
--------------------------------------------------------------------------------------------------------------------------------------
1.1 实例
下面是一个运行node的例子
首先在一个terminal上启动ros
~$ roscore
在另一个terminal上启动一个turtlesim模拟器并启动一个turtlesim_node节点
~$ rosrun turtlesim turtlesim_node
在另一个terminal上查看节点列表
~$ rosnode list
如下图所示:
此时只有rosout和turtlesim节点这两个,其中turtlesim就是通过turtlesim启动的那个节点,默认名字与模拟器相同。下面我们再启动一个terminal并启动一个turtlesim节点,并给它起个名字:
~$ rosrun turtlesim turtlesim_node __name:=kinetic_turtle
然后我们再用rosnode list命令查看,发现多了一个叫kinetic_turtle节点。
如果启动两个同名的node,如下图的test1,则也会只保留一个,第一个创建的会被强制关闭:
使用rosnode ping nodename可以测试能否ping通某个节点,
删除节点:~$ rosnode kill nodename
~$ rosnode cleanup
关闭turtlesim_node,请按下“Ctrl-C” 。
查看节点信息:
这里可以看到节点订阅和发布的消息的类型。
-------------------------------------------------------------------------------------------------------------------------------------------
2. ROS中的主题topic
在开始topic相关讨论之前,我们先看通过turtlesim中的那个turtlesim(小海龟)的例子来了解一下ros中的topic是怎么一回事。
2.1 实例
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
(1)启动小乌龟turtle
ROS的资料中提到一只虚拟小乌龟:turtle,关于它的例子也十分简单,比如启动它
~$ roscore
在另一个terminal中启动一个turtle节点
~$ rosrun turtlesim turtlesim_node
另打开一个ternimal标签
~$ rosrun turtlesim turtle_teleop_key
将会得到蓝色背景下随机的一直小乌龟,并且可以使用方向键控制移动,但是turtle_teleop_key的节点系统里是没有源代码的,只有一个能够直接运行的文件.
另起一个terminal,打开节点图可以更直观地看到这两个节点间传递消息的主题
~$ rqt_graph
显然,/teleop_turtle这个节点单向传递速度的控制信息给turtlesim节点, 那么完全可以按照程序的意愿使小乌龟的运行处于脱机运行状态.
Node之间,是通过Message来传递消息的,每个Message就是一个数据结构,如geonetry_msgs/Twist.msg.
- 换句话说自己写一个可发布/turtle1/cmd_vel的程序.
我们必须知道/turtle1/cmd_vel里发布的msg是什么样的,执行如下命令,查看传递的消息:
~$ rostopic type /turtle1/cmd_vel | rosmsg show
geometry_msgs/Vector3 linear
float64 x
float64 y
float64 z
geometry_msgs/Vector3 angular
float64 x
float64 y
float64 z
可以看到msg为geometry_msgs/Vector3,这个消息的原型在ROS中,/opt/ros/kinetic/share/geometry_msgs/Vector3 ,内容为
float64 x
float64 y
float64 z
(2)简单的自转
那么接下来自己写一个node,发布它们就可以了.
在catkin中建立一个package,如toldturtle,并创建一个node.(下面标注的红色的toldturtle和talk,也可以改成其他名称,只要保证一致即可)
~$ cd ~/catkin_ws/src/
~$ catkin_create_pkg toldturtle roscpp std_msgs geometry_msgs
在该package的src下创建一个名为talk.cpp的node.
#include <ros/ros.h>#include <geometry_msgs/Twist.h>ros::Publisher cmdVelPub;int main(int argc, char **argv){ ros::init(argc, argv, "talk"); //"talk"必须是nodename std::string topic = "/turtle1/cmd_vel"; //topic name ros::NodeHandle n; cmdVelPub = n.advertise<geometry_msgs::Twist>(topic, 1); //第一个参数也可以写成"/turtle1/cmd_vel"这样的topic name //第二个参数是发布的缓冲区大小,<geometry_msgs::Twist>是消息类型 ros::Rate loopRate(2); //与Rate::sleep();配合指定自循环频率 ROS_INFO("talk cpp start...");//输出显示信息 geometry_msgs::Twist speed; // 控制信号载体 Twist message while (ros::ok()){ speed.linear.x = 1; // 设置线速度为1m/s,正为前进,负为后退 speed.angular.z = 1; // 设置角速度为1rad/s,正为左转,负为右转 cmdVelPub.publish(speed); // 将刚才设置的指令发送给机器人 ros::spinOnce(); loopRate.sleep();//按loopRate(2)设置的2HZ将程序挂起 } return 0;}
并且修改cmake代码,让编译系统明白如何编译,这里我的package为toldturtle,node为talk.cpp:
cmake_minimum_required(VERSION 2.8.3)project(toldturtle)find_package(catkin REQUIRED COMPONENTS geometry_msgs roscpp rospy std_msgs)catkin_package( CATKIN_DEPENDS geometry_msgs roscpp rospy std_msgs)include_directories( ${catkin_INCLUDE_DIRS})## Declare a C++ executable add_executable(talk src/talk.cpp)## Specify libraries to link a library or executable target against target_link_libraries(talk ${catkin_LIBRARIES} )
这样在terminal里编译下整个catkin的package
~$ cd ~/catkin_ws/
~$ catkin_make
如果编译成功,就可以看到提示了.
(3)效果
在终端运行写的node
~$ rosrun toldturtle talk
此时,我们查看ros中的节点,
这样就通过编写一个talk,来实现在ros中对turtle的控制.
此时,turtle也受前面的teleop_turtle控制,我们仍然可以通过键盘上的箭头控制小乌龟,只不过它目前受两个控制,在键盘箭头控制的同时,仍然受talk的控制进行画圆,即可以用方向键控制自旋转的turtle.
此时查看节点之间的关系,我们发现talk和teleop_turtle都可以传递消息给turtlesim。
通过这个例子,结合订阅/发布消息机制,我们可以认为turtlesim节点订阅了turtle1/cmd_vel这个主题,而只要某个节点发布了这个主题的消息,turtlesim节点都能接受并根据传过来的消息内容(即geometry_msgs/Vector3)更新乌龟的位置。
关于乌龟控制的例子,我们参考了:http://blog.****.net/under_maple/article/details/49430765
(4)通过rostopic命令发布topic消息来控制小乌龟
除了上面的方式,写一个package来实现对小乌龟的控制外,还有更方面的一种方式来实现对小乌龟的控制,就是在命令行里,借助rostopic命令,发布一条小乌龟控制所需要的消息
rostopic pub [topic] [msg_type] [args
~$ rostopic pub -1 /turtle1/cmd_vel geometry_msgs/Twist -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]'
publishing and latching message for 3.0 seconds
上面的命令告诉小海龟按照线速度2角速度1.8进行移动,时间为3s,如下图所示(忘记截图了,此图来源于http://blog.****.net/bobsweetie/article/details/43638797):
小乌龟移动3s后停止了,我们可以用rostopic pub -r命令发布一个稳定的命令流。
~$ rostopic pub /turtle1/cmd_vel geometry_msgs/Twist -r 1 -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]
~$ rostopic hz /turtle1/pose
subscribed to [/turtle1/pose]
average rate: 124.817
min: 0.006s max: 0.010s std dev: 0.00141s window: 118
average rate: 125.015
min: 0.006s max: 0.010s std dev: 0.00142s window: 243
average rate: 124.968
min: 0.006s max: 0.010s std dev: 0.00142s window: 368
average rate: 125.009
min: 0.006s max: 0.010s std dev: 0.00141s window: 493
~$ rostopic type /turtle1/cmd_vel | rosmsg show
~$ rosrun rqt_plot rqt_plot
rostopic命令相关的内容,可以参考:http://blog.****.net/bobsweetie/article/details/43638797
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2.2 ROS中的topic的理解(三种主要通信方式中的一种)
下面我们正式开始ros中的topic主题部分的理解。
ROS Node之间通讯方式主要依靠的就是主题(Topic)和服务(Service), 参数(parameter) 三种。Message就是放在Topic中。这里需要注意,Topic只是ROS中的一种通信方式,而不是唯一的通信方式。
Message传递的的理念:
当一个节点想要分享信息时,它就会发布(publish)消息到对应的一个或多个Topic(主题);当一个节点想要接收消息时,它就会订阅(Subscribe)它所需要的一个或多个Topic。
ROS Topic:
主题是由ROS网络对消息进行路由,对消息进行管理的数据总线。每一条消息都要发布到相应的主题上。当一个节点发送数据时,我们就说这个节点向某个主题发布了消息。
节点可以通过订阅某个主题,接受别的节点发布的消息。
ROS Master负责确保发布主题的Node和订阅主题的Node能找到对方。而Message是直接从发布Node传递到订阅Node.并不需要经过Node Master。
A:消息以一种publish/subscribe的方式传递。
B:节点可以在给定的主题中发布/订阅消息。
C:一个节点可以订阅/发布多个不同主题。
D:允许多个Node订阅/发布同一个主题。
E:订阅节点和发布节点并不知道相互之间的存在。
Message注册和订阅过程:
Talker这个Node,启动后注册了一个Topic,名为bar, 并告知Node Master,接收端口为:1234。
Listener这个Node启动后订阅了一个Topic,名为bar.
Node Master告知Listener,主题的端口为1234。
Listener去连接1234端口,Talker监听到有人连接。就告知对方,数据接口是2345。
于是两个Node就连通起来了。
同一个时刻,只有一个Node Master。所以可以共享数据。
我们继续用上面的程序来查看Topic.
#roscore
#rosrun turtlesim turtlesim_node
#rosrun turtlesim turtlesim_node __name:=turtle2
#rosrun turtlesim turtle_teleop_key
1. 运行了roscore,
2. 运行了turtlesim包内的turtlesim_node这node两次,使用不同的node_Name.
3. 运行了turtlesim包内的turtle_teleop_key.
turtlesim_node和turtle_teleop_keynode之间用topic交流通信.
turtle_teleop_key在这个topic上发布按键敲击,而turtlesim订阅同样的topic接受按键敲击.
可以使用可视化工具查看Topic的数据传输。
#rosrun rqt_graph rqt_graph
图示:
这个和我们原来研究的zeromq差不错,都是基于订阅/发布模式的消息传递机制。
3. 总结
要理解ROS topics、ROS nodes、ROS Messages之间的关系。目前个人的理解是:ROS topics是ROS nodes之间进行通信的枢纽,ROS messages是ROS nodes订阅和发布数据的载体。两个ROS nodes欲实现通信,则其中一个节点向ROS topic发布ROS messages,另一节点则通过订阅此topic来接收messages,两者的message类型一定要相同,而message的类型由主题确定,通过rostopic type命令可以查看topic的数据类型。
然后就是辅助查看ROS中节点关系和数据的工具:rqt_graph和rqt_plot,两者都是针对ROS类型的,其中rqt_graph工具会自动搜寻系统中正在运行的节点和主题,并动态绘制出关系图,rqt_plot则是绘制发布到topic上的数据的图形,因此两者使用的前提是有ROS的进程在运行。
运行节点:roscore
rosrun turtlesim turtlesim_node
rosrun turtlesim turtle_teleop_key
查看节点关系图:rosrun rqt_graph rqt_graph
显示topic1上所发布的数据:rostopic echo topic1
列出当前处于**状态的topic列表:rostopic list -v
显示topic1的数据类型:rostopic type topic1
显示类型更加详细的信息:rosmsg show type1
直接向主题topic1发布数据:rostopic pub [topic1] [msg_type] [args]
显示主题topic1上数据的发布速率:rostopic hz [topic1]