機器人是一種高度復雜的系統性實現,在機器人上可能集成各種傳感器(雷達、攝像頭、GPS…)以及運動控制實現,為了解耦合,在 ROS
中每一個功能點都是一個單獨的進程,每一個進程都是獨立運行的。
更確切的講,ROS
是進程(也稱為Nodes)的分布式框架。 因為這些進程甚至還可分布於不同主機,不同主機協同工作,從而分散計算壓力。不過隨之也有一個問題: 不同的進程是如何通信的?也即不同進程間如何實現數據交換的?在此我們就需要介紹一下 ROS
中的通信機制了。
ROS
中的基本通信機制主要有如下三種實現策略:
話題通信是 ROS
中使用頻率最高的一種通信模式,話題通信是基於發布訂閱模式的,也即:一個節點發布消息,另一個節點訂閱該消息。話題通信的應用場景也極其廣泛,比如下面一個常見場景:
機器人在執行導航功能,使用的傳感器是激光雷達,機器人會采集激光雷達感知到的信息並計算,然後生成運動控制信息驅動機器人底盤運動。
在上述場景中,就不止一次使用到了話題通信。
ROS
中有一個節點需要時時的發布當前雷達采集到的數據,導航模塊中也有節點會訂閱並解析雷達數據。以此類推,像雷達、攝像頭、GPS… 等等一些傳感器數據的采集,也都是使用了話題通信,換言之,話題通信適用於不斷更新的數據傳輸相關的應用場景。
首先我們要實現下圖所示的話題模型,該模型如下圖所示,該模型中涉及到三個角色:
ROS Master
(管理者)Talker
(發布者)Listener
(訂閱者)ROS Master
負責保管 Talker
和 Listener
注冊的信息,並匹配話題相同的 Talker
與 Listener
,幫助 Talker
與 Listener
建立連接,連接建立後,Talker
可以發布消息,且發布的消息會被 Listener
訂閱。
其中,主題名稱節點為 /turtle1/cmd_vel
,發布者和訂閱者的消息類型為 geometry_msgs::Twist
。
在 src
目錄下創建功能包,包名為 topic_demo
,依賴分別為 rospy
、 std_msgs
、 geometry_msgs
。
[email protected]:~/project/ros/ros_demo/src$ catkin_create_pkg topic_demo rospy std_msgs geometry_msgs
輸出如下:
turtlesim Created file topic_demo/package.xml
Created file topic_demo/CMakeLists.txt
Created folder topic_demo/src
Successfully created files in /home/wohu/project/ros/ros_demo/src/topic_demo. Please adjust the values in package.xml.
在功能包下面建立一個 scripts
文件夾,在 scripts
文件裡面建立一個 .py
文件。
publisher.py
代碼內容:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 該例程將發布turtle1/cmd_vel話題,消息類型geometry_msgs::Twist
import rospy
from geometry_msgs.msg import Twist
def velocity_publisher():
# ROS節點初始化
rospy.init_node('velocity_publisher', anonymous=True)
# 創建一個Publisher,發布名為/turtle1/cmd_vel的topic,消息類型為geometry_msgs::Twist,隊列長度10
turtle_vel_pub = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size=10)
#設置循環的頻率
rate = rospy.Rate(10)
while not rospy.is_shutdown():
# 初始化geometry_msgs::Twist類型的消息
vel_msg = Twist()
vel_msg.linear.x = 0.5
vel_msg.angular.z = 0.2
# 發布消息
turtle_vel_pub.publish(vel_msg)
rospy.loginfo("Publsh turtle velocity command[%0.2f m/s, %0.2f rad/s]",
vel_msg.linear.x, vel_msg.angular.z)
# 按照循環頻率延時
rate.sleep()
if __name__ == '__main__':
try:
velocity_publisher()
except rospy.ROSInterruptException:
pass
$ chmod +x publisher.py
roscore
啟動 ROS
服務$ roscore
$ rosrun turtlesim turtlesim_node
$ rosrun topic_demo publisher.py
rosrun
後面跟著創建的包名 topic_demo
和發布者的文件 publisher.py
演示結果如下:
如果運行後報錯:
$ rosrun topic_demo publisher.py
[rosrun] Couldn't find executable named publisher.py below /home/wohu/project/ros/ros_demo/src/topic_demo [rosrun] Found the following, but they're either not files,
[rosrun] or not executable:
[rosrun] /home/wohu/project/ros/ros_demo/src/topic_demo/scripts/publisher.py
[email protected]:~/project/ros/ros_demo/src$
說明 publisher.py
文件權限沒有修改。
和前面一樣,在功能包 topic_demo
目錄的 src
目錄下存放訂閱者文件
訂閱者代碼實現
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 該例程將訂閱/turtle1/pose話題,消息類型turtlesim::Pose
import rospy
from turtlesim.msg import Pose
def poseCallback(msg):
rospy.loginfo("Turtle pose: x:%0.6f, y:%0.6f", msg.x, msg.y)
def pose_subscriber():
# ROS節點初始化
rospy.init_node('pose_subscriber', anonymous=True)
# 創建一個Subscriber,訂閱名為/turtle1/pose的topic,注冊回調函數poseCallback
rospy.Subscriber("/turtle1/pose", Pose, poseCallback)
# 循環等待回調函數
rospy.spin()
if __name__ == '__main__':
pose_subscriber()
依次分別打開 3 個終端執行下面命令:
$ roscore
$ rosrun turtlesim turtlesim_node
$ rosrun turtlesim turtle_teleop_key
通過下面命令啟動訂閱者
$ rosrun topic_demo pose_subscriber.py
通過上、下、左、右 控制海龜移動,然後就可以看到 pose_subscriber.py
腳本輸出海龜的位置信息了。
經過測試驗證,publisher.py
代碼也可以放在 src
目錄下
更改腳本名稱後運行下面命令,也是可以運行起來的。
$ rosrun topic_demo publisher_demo.py