ROS學習筆記(八): ROS通信架構


ROS學習筆記(八): ROS通信架構

本章主要介紹了通信架構的基礎通信方式和相關概念。其中首先介紹了最小的進程單元節點Node,和節點管理器Node master。了解了ROS中的進程都是由很多的Node組成,並且由Node master來管理這些節點。

介紹ROS的“發動機”——launch文件,學習它的格式和內容,更深入的理解ROS在啟動運行時它的工作都是由什么進程支配的,從而理解啟動運行的原理。

ROS中的通信方式有四種,主題、服務、參數服務器、動作庫。每個通信方式都有自己的特點,本章首先介紹話題通信方式--topic。

01 Node & Master

1.1 Node

在ROS中,最小的進程單元就是節點(node)。一個軟件包里可以有多個可執行文件,可執行文件在運行之后就成了一個進程(process),這個進程在ROS中就叫做節點。 從程序角度來說,node就是一個可執行文件(通常為C++編譯生成的可執行文件、Python腳本)被執行,加載到了內存之中;從功能角度來說,通常一個node負責者機器人的某一個單獨的功能。由於機器人的功能模塊非常復雜,我們往往不會把所有功能都集中到一個node上,而會采用分布式的方式,把雞蛋放到不同的籃子里。

1.2 Master

由於機器人的元器件很多,功能龐大,因此實際運行時往往會運行眾多的node,負責感知世界、控制運動、決策和計算等功能。那么如何合理的進行調配、管理這些node?這就要利用ROS提供給我們的節點管理器master, master在整個網絡通信架構里相當於管理中心,管理着各個node。node首先在master處進行注冊,之后master會將該node納入整個ROS程序中。node之間的通信也是先由master進行“牽線”,才能兩兩的進行點對點通信。當ROS程序啟動時,第一步首先啟動master,由節點管理器處理依次啟動node。

1.3 啟動master和node

當我們要啟動ROS時,首先輸入命令:

$ roscore

此時ROS master啟動,同時啟動的還有rosoutparameter server,其中rosout是負責日志輸出的一個節點,其作用是告知用戶當前系統的狀態,包括輸出系統的error、warning等等,並且將log記錄於日志文件中,parameter server即是參數服務器,它並不是一個node,而是存儲參數配置的一個服務器。每一次我們運行ROS的節點前,都需要把master啟動起來,這樣才能夠讓節點啟動和注冊。

master之后,節點管理器就開始按照系統的安排協調進行啟動具體的節點。節點就是一個進程,只不過在ROS中它被賦予了專用的名字—node。我們知道一個package中存放着可執行文件,可執行文件是靜態的,當系統執行這些可執行文件,將這些文件加載到內存中,它就成為了動態的node。

具體啟動node的語句是:

$ rosrun pkg_name node_name

通常我們運行ROS,就是按照這樣的順序啟動,有時候節點太多,我們會選擇用launch文件來啟動。 Master、Node之間以及Node之間的關系如下圖所示:

1.4 rosrun和rosnode命令

rosrun命令的詳細用法如下

$ rosrun [--prefix cmd] [--debug] pkg_name node_name [ARGS]

rosrun將會尋找PACKAGE下的名為EXECUTABLE的可執行程序,將可選參數ARGS傳入。

例如在GDB下運行ros程序:

$ rosrun --prefix 'gdb -ex run --args' pkg_name node_name

rosnode命令的詳細作用列表如下

rosnode命令 作用
rosnode list 列出當前運行的node信息
rosnode info node_name 顯示出node的詳細信息
rosnode kill node_name 結束某個node
rosnode ping 測試連接節點
rosnode machine 列出在特定機器或列表機器上運行的節點
rosnode cleanup 清除不可到達節點的注冊信息

以上命令中常用的為前三個,在開發調試時經常會需要查看當前node以及node信息,所以請記住這些常用命令。如果想不起來,也可以通過rosnode help來查看rosnode命令的用法。

02 launch文件

2.1 簡介

機器人是一個系統工程,通常一個機器人運行操作時要開啟多個node,對於一個復雜的機器人的啟動操作應該怎么做呢?當然,我們並不需要每個節點依次進行rosrun,ROS為我們提供了一個命令能一次性啟動master和多個node。該命令是:

$ roslaunch pkg_name file_name.launch

roslaunch命令首先會自動進行檢測系統的roscore有沒有運行,也即是確認節點管理器是否在運行狀態中,如果master沒有啟動,那么roslaunch就會首先啟動master,然后再按照launch的規則執行。launch文件里已經配置好了啟動的規則。 所以roslaunch就像是一個啟動工具,能夠一次性把多個節點按照我們預先的配置啟動起來,減少我們在終端中一條條輸入指令的麻煩。

2.2 寫法與格式

launch文件同樣也遵循着xml格式規范,是一種標簽文本,它的格式包括以下標簽:

<launch>    <!--根標簽-->
<node>    <!--需要啟動的node及其參數-->
<include>    <!--包含其他launch-->
<machine>    <!--指定運行的機器-->
<env-loader>    <!--設置環境變量-->
<param>    <!--定義參數到參數服務器-->
<rosparam>    <!--啟動yaml文件參數到參數服務器-->
<arg>    <!--定義變量-->
<remap>    <!--設定參數映射-->
<group>    <!--設定命名空間-->
</launch>    <!--根標簽-->

參考鏈接:http://wiki.ros.org/roslaunch/XML

2.3 示例

launch文件的寫法和格式看起來內容比較復雜,我們先來介紹一個最簡單的例子如下:

<launch>
<node name="talker" pkg="rospy_tutorials" type="talker" />
</launch>

這是官網給出的一個最小的例子,文本中的信息是,它啟動了一個單獨的節點talker,該節點是包rospy_tutorials軟件包中的節點。

然而實際中的launch文件要復雜很多,我們以Ros-Academy-for-Beginners中的robot_sim_demo為例:

<launch>
<!--arg是launch標簽中的變量聲明,arg的name為變量名,default或者value為值-->
<arg name="robot" default="xbot2"/>
<arg name="debug" default="false"/>
<arg name="gui" default="true"/>
<arg name="headless" default="false"/>

<!-- Start Gazebo with a blank world -->
<include file="$(find gazebo_ros)/launch/empty_world.launch"> <!--include用來嵌套仿真場景的launch文件-->
<arg name="world_name" value="$(find robot_sim_demo)/worlds/ROS-Academy.world"/>
<arg name="debug" value="$(arg debug)" />
<arg name="gui" value="$(arg gui)" />
<arg name="paused" value="false"/>
<arg name="use_sim_time" value="true"/>
<arg name="headless" value="$(arg headless)"/>
</include>

<!-- Oh, you wanted a robot? --> <!--嵌套了機器人的launch文件-->
<include file="$(find robot_sim_demo)/launch/include/$(arg robot).launch.xml" />

<!--如果你想連同RViz一起啟動,可以按照以下方式加入RViz這個node-->
<!--node name="rviz" pkg="rviz" type="rviz" args="-d $(find robot_sim_demo)/urdf_gazebo.rviz" /-->
</launch>

這個launch文件相比上一個簡單的例子來說,內容稍微有些復雜,它的作用是:啟動gazebo模擬器,導入參數內容,加入機器人模型。

小結

對於初學者,我們不要求掌握每一個標簽是什么作用,但至少應該有一個印象。如果我們要進行自己寫launch文件,可以先從改launch文件的模板入手,基本可以滿足普通項目的要求。

03 Topic(話題)

3.1 簡介

ROS的通信方式是ROS最為核心的概念,ROS系統的精髓就在於它提供的通信架構。ROS的通信方式有以下四種:

  • Topic 主題
  • Service 服務
  • Parameter Service 參數服務器
  • Actionlib 動作庫

3.2 Topic(發布/訂閱)

ROS中的通信方式中,topic是常用的一種。對於實時性、周期性的消息,使用topic來傳輸是最佳的選擇。topic是一種點對點的單向通信方式,這里的“點”指的是node,也就是說node之間可以通過topic方式來傳遞信息。topic要經歷下面幾步的初始化過程:首先,publisher節點和subscriber節點都要到節點管理器進行注冊,然后publisher會發布topic,subscriber在master的指揮下會訂閱該topic,從而建立起sub-pub之間的通信。注意整個過程是單向的。其結構示意圖如下:

Subscriber接收消息會進行處理,一般這個過程叫做回調(Callback)。所謂回調就是提前定義好了一個處理函數(寫在代碼中),當有消息來就會觸發這個處理函數,函數會對消息進行處理。

注意整個過程是單向的。

  • Talker向ROS Master注冊
  • Listener向ROS Master注冊
  • ROS Master通過RPC向Listener發送Talker的地址信息
  • Listener接收到地址信息,通過RPC向Talker發送連接請求
  • Talker確認連接請求,通過RPC向Listener確認連接
  • Listener與Talker建立網絡連接
  • Talker向Listener發布數據

總結:前五步的通信協議都是RPC,最后兩步傳輸數據才用TCP

3.3 通信示例

怎么樣來理解“異步”這個概念呢?在node1每發布一次消息之后,就會繼續執行下一個動作,至於消息是什么狀態、被怎樣處理,它不需要了解;而對於node2圖像處理程序,它只管接收和處理/camera_rgb上的消息,至於是誰發來的,它不會關心。所以node1、node2兩者都是各司其責,不存在協同工作,我們稱這樣的通信方式是異步的。

ROS是一種分布式的架構,一個topic可以被多個節點同時發布,也可以同時被多個節點接收。比如在這個場景中用戶可以再加入一個圖像顯示的節點,我們在想看看攝像頭節點的畫面,則可以用自己的筆記本連接到機器人上的節點管理器,然后在自己的電腦上啟動圖像顯示節點。

這就體現了分布式系統通信的好處:擴展性好、軟件復用率高。

總結三點

  1. topic通信方式是異步的,發送時調用publish()方法,發送完成立即返回,不用等待反饋。
  2. subscriber通過回調函數的方式來處理消息。
  3. topic可以同時有多個subscribers,也可以同時有多個publishers。ROS中這樣的例子有:/rosout、/tf等等。

3.4 操作命令

在實際應用中,我們應該熟悉topic的幾種使用命令,下表詳細的列出了各自的命令及其作用。

命令 作用
rostopic list 列出當前所有的topic
rostopic info topic_name 顯示某個topic的屬性信息
rostopic echo topic_name 顯示某個topic的內容
rostopic pub topic_name ... 向某個topic發布內容
rostopic bw topic_name 查看某個topic的帶寬
rostopic hz topic_name 查看某個topic的頻率
rostopic find topic_type 查找某個類型的topic
rostopic type topic_name 查看某個topic的類型(msg)

如果你一時忘記了命令的寫法,可以通過rostopic helprostopic command -h查看具體用法。

小結

topic的通信方式是ROS中比較常見的單向異步通信方式,它在很多時候的通信是比較易用且高效的。但是有些需要交互的通信時該方式就顯露出自己的不足之處了,后續我們會介紹雙向同步的通信方式service

04 Message

4.1 簡介

topic有很嚴格的格式要求,比如上節的攝像頭進程中的rgb圖像topic,它就必然要遵循ROS中定義好的rgb圖像格式。這種數據格式就是Message。Message按照定義解釋就是topic內容的數據類型,也稱之為topic的格式標准。這里和我們平常用到的Massage直觀概念有所不同,這里的Message不單單指一條發布或者訂閱的消息,也指定為topic的格式標准。

4.2 結構與類型

基本的msg包括bool、int8、int16、int32、int64(以及uint)、float、float64、string、time、duration、header、可變長數組array[]、固定長度數組array[C]。那么具體的一個msg是怎么組成的呢?我們用一個具體的msg來了解,例如上例中的msg sensor_msg/image,位置存放在sensor_msgs/msg/image.msg里,它的結構如下:

std_msg/Header header
    uint32    seq
    time    stamp
    string    frame_id
uint32    height
uint32    width
string    encoding
uint8    is_bigendian
uint32    step
uint8[]    data

觀察上面msg的定義,是不是很類似C語言中的結構體呢?通過具體的定義圖像的寬度,高度等等來規范圖像的格式。所以這就解釋了Message不僅僅是我們平時理解的一條一條的消息,而且更是ROS中topic的格式規范。或者可以理解msg是一個“類”,那么我們每次發布的內容可以理解為“對象”,這么對比來理解可能更加容易。 我們實際通常不會把Message概念分的那么清,通常說Message既指的是類,也是指它的對象。而msg文件則相當於類的定義了。

4.3 操作命令

rosmsg的命令相比topic就比較少了,只有兩個如下:

rosmsg命令 作用
rosmsg list 列出系統上所有的msg
rosmsg show msg_name 顯示某個msg的內容

05 常見message

本小節主要介紹常見的message類型,包括std_msgs, sensor_msgs, nav_msgs, geometry_msgs等

Vector3.msg

#文件位置:geometry_msgs/Vector3.msg

float64 x
float64 y
float64 z

Accel.msg

#定義加速度項,包括線性加速度和角加速度
#文件位置:geometry_msgs/Accel.msg
Vector3 linear
Vector3 angular

Header.msg

#定義數據的參考時間和參考坐標
#文件位置:std_msgs/Header.msg
uint32 seq      #數據ID
time stamp      #數據時間戳
string frame_id #數據的參考坐標系

Echos.msg

#定義超聲傳感器
#文件位置:自定義msg文件
Header header
uint16 front_left
uint16 front_center
uint16 front_right
uint16 rear_left
uint16 rear_center
uint16 rear_right

Quaternion.msg

#消息代表空間中旋轉的四元數
#文件位置:geometry_msgs/Quaternion.msg

float64 x
float64 y
float64 z
float64 w

Imu.msg

#消息包含了從慣性原件中得到的數據,加速度為m/^2,角速度為rad/s
#如果所有的測量協方差已知,則需要全部填充進來如果只知道方差,則
#只填充協方差矩陣的對角數據即可
#位置:sensor_msgs/Imu.msg

Header header
Quaternion orientation
float64[9] orientation_covariance
Vector3 angular_velocity
float64[9] angular_velocity_covariance
Vector3 linear_acceleration
float64[] linear_acceleration_covariance

LaserScan.msg

#平面內的激光測距掃描數據,注意此消息類型僅僅適配激光測距設備
#如果有其他類型的測距設備(如聲吶),需要另外創建不同類型的消息
#位置:sensor_msgs/LaserScan.msg

Header header            #時間戳為接收到第一束激光的時間
float32 angle_min        #掃描開始時的角度(單位為rad)
float32 angle_max        #掃描結束時的角度(單位為rad)
float32 angle_increment    #兩次測量之間的角度增量(單位為rad)
float32 time_increment    #兩次測量之間的時間增量(單位為s)
float32 scan_time        #兩次掃描之間的時間間隔(單位為s)
float32 range_min        #距離最小值(m)
float32 range_max        #距離最大值(m)
float32[] ranges        #測距數據(m,如果數據不在最小數據和最大數據之間,則拋棄)
float32[] intensities    #強度,具體單位由測量設備確定,如果儀器沒有強度測量,則數組為空即可

Point.msg

#空間中的點的位置
#文件位置:geometry_msgs/Point.msg

float64 x
float64 y
float64 z

Pose.msg

#消息定義自由空間中的位姿信息,包括位置和指向信息
#文件位置:geometry_msgs/Pose.msg

Point position
Quaternion orientation

PoseStamped.msg

#定義有時空基准的位姿
#文件位置:geometry_msgs/PoseStamped.msg

Header header
Pose pose

PoseWithCovariance.msg

#表示空間中含有不確定性的位姿信息
#文件位置:geometry_msgs/PoseWithCovariance.msg

Pose pose
float64[36] covariance

Power.msg

#表示電源狀態,是否開啟
#文件位置:自定義msg文件
Header header
bool power
######################
bool ON  = 1
bool OFF = 0

Twist.msg

#定義空間中物體運動的線速度和角速度
#文件位置:geometry_msgs/Twist.msg

Vector3 linear
Vector3 angular

TwistWithCovariance.msg

#消息定義了包含不確定性的速度量,協方差矩陣按行分別表示:
#沿x方向速度的不確定性,沿y方向速度的不確定性,沿z方向速度的不確定性
#繞x轉動角速度的不確定性,繞y軸轉動的角速度的不確定性,繞z軸轉動的
#角速度的不確定性
#文件位置:geometry_msgs/TwistWithCovariance.msg

Twist twist
float64[36] covariance  #分別表示[x; y; z; Rx; Ry; Rz]

Odometry.msg

#消息描述了自由空間中位置和速度的估計值
#文件位置:nav_msgs/Odometry.msg

Header header
string child_frame_id
PoseWithCovariance pose
TwistWithCovariance twist

06 Service(服務)

  • Talker向ROS Master注冊
  • Listener向ROS Master注冊
  • ROS Master進行信息匹配
  • Listener與Talker建立網絡連接,發送服務的請求數據
  • Talker接收請求參數,執行服務功能,執行完后,發送應答數據

總結:前三步的通信協議都是RPC,最后兩步傳輸數據才用TCP

6.1 Service

topic(主題)是ROS中的一種單向的異步通信方式。然而有些時候單向的通信滿足不了通信要求,比如當一些節點只是臨時而非周期性的需要某些數據,如果用topic通信方式時就會消耗大量不必要的系統資源,造成系統的低效率高功耗。
這種情況下,就需要有另外一種請求-查詢式的通信模型。這節我們來介紹ROS通信中的另一種通信方式——service。

6.2 工作原理

簡介

為了解決以上問題,service方式在通信模型上與topic做了區別。Service通信是雙向的,它不僅可以發送消息,同時還會有反饋。所以service包括兩部分,一部分是請求方(Clinet),另一部分是應答方/服務提供方(Server)。這時請求方(Client)就會發送一個request,要等待server處理,反饋回一個reply,這樣通過類似“請求-應答”的機制完成整個服務通信。

這種通信方式的示意圖如下:
Node B是server(應答方),提供了一個服務的接口,叫做/Service,我們一般都會用string類型來指定service的名稱,類似於topic。Node A向Node B發起了請求,經過處理后得到了反饋。

過程

Service是同步通信方式,所謂同步就是說,此時Node A發布請求后會在原地等待reply,直到Node B處理完了請求並且完成了reply,Node A才會繼續執行。Node A等待過程中,是處於阻塞狀態的成通信。這樣的通信模型沒有頻繁的消息傳遞,沒有沖突與高系統資源的占用,只有接受請求才執行服務,簡單而且高效。

6.3 topic VS service

名稱 Topic (主題) Service(服務)
通信方式 單向異步通信 雙向同步通信
實現原理 TCP/IP TCP/IP
通信模型 Publish-Subscribe Request-Reply
反饋機制
緩沖區
實時性
映射關系 Publish-Subscribe(多對多) Request-Reply( 多對一)
特點 接受者收到數據會回調( Callback) 遠程過程調用( RPC)服務器端的服務
應用場景 連續、 高頻的數據發布 (數據傳輸) 偶爾使用的功能/具體的任務(邏輯處理)
舉例 激光雷達、 里程計發布數據 開關傳感器、 拍照、 逆解計算

注意: 遠程過程調用(Remote Procedure Call, RPC),可以簡單的理解為在一個進程里調用另一個進程的函數。

6.4 操作命令

在實際應用中,service通信方式的命令時rosservice,具體的命令參數如下表:

rosservice 命令 作用
rosservice list 顯示服務列表
rosservice info 打印服務信息
rosservice type 打印服務類型
rosservice uri 打印服務ROSRPC uri
rosservice find 按服務類型查找服務
rosservice call 使用所提供的args調用服務
rosservice args 打印服務參數

小結

本節我們詳細介紹了service通信方式,建議與topic通信方式進行對比記憶,這樣我們能更深的理解這兩種通信方式,也能在以后的學習工作中更加合理使用每個通信方式,獲得更高的效率。

07 Srv

7.1 簡介

類似msg文件,srv文件是用來描述服務(service數據類型的,service通信的數據格式定義在*.srv中。它聲明了一個服務,包括請求(request)和響應(reply)兩部分。其格式聲明如下:

舉例:

msgs_demo/srv/DetectHuman.srv

bool start_detect
---
my_pkg/HumanPose[] pose_data

msgs_demo/msg/HumanPose.msg

std_msgs/Header header
string uuid
int32 number_of_joints
my_pkg/JointPose[]joint_data

msgs_demo/msg/JointPose.msg

string joint_name
geometry_msgs/Pose pose
floar32 confidence

DetectHUman.srv文件為例,該服務例子取自OpenNI的人體檢測ROS軟件包。它是用來查詢當前深度攝像頭中的人體姿態和關節數的。

srv文件格式很固定,第一行是請求的格式,中間用---隔開,第三行是應答的格式。

在本例中,請求為是否開始檢測,應答為一個數組,數組的每個元素為某個人的姿態(HumanPose)。而對於人的姿態,其實是一個msg,所以srv可以嵌套msg在其中,但它不能嵌套srv。

7.2 操作命令

具體的操作指令如下表:

rossrv 命令 作用
rossrv show 顯示服務描述
rossrv list 列出所有服務
rossrv md5 顯示服務md5sum
rossrv package 列出包中的服務
rossrv packages 列出包含服務的包

7.3 修改部分文件

定義完了msg、srv文件,還有重要的一個步驟就是修改package.xml和修改CMakeList.txt。這些文件需要添加一些必要的依賴等,例如:

<build_depend>** message_generation **</build_depend>
<run_depend>** message_runtime **</run_depend>

上述文本中“**”所引就是新添加的依賴。又例如:

find_package(...roscpp rospy std_msgs ** message_generation **)
catkin_package(
...
CATJIN_DEPENDS ** message_runtime ** ...
...)

add_message_file(
FILES
** DetectHuman.srv **
** HumanPose.msg **
** JointPos.msg **)

** generate_messages(DEPENDENCIES std_msgs) **

添加的這些內容指定了srv或者msg在編譯或者運行中需要的依賴。具體的作用我們初學者可不深究,我們需要了解的是,無論我們自定義了srv,還是msg,修改上述部分添加依賴都是必不可少的一步。

08 常見srv類型

本小節介紹常見的srv類型及其定義 srv類型相當於兩個message通道,一個發送,一個接收

AddTwoInts.srv

#對兩個整數求和,虛線前是輸入量,后是返回量
#文件位置:自定義srv文件
int32 a
int32 b
---
int32 sum

Empty.srv

#文件位置:std_srvs/Empty.srv
#代表一個空的srv類型

---

GetMap.srv

#文件位置:nav_msgs/GetMap.srv
#獲取地圖,注意請求部分為空

---
nav_msgs/OccupancyGrid map

GetPlan.srv

#文件位置:nav_msgs/GetPlan.srv
#得到一條從當前位置到目標點的路徑
geometry_msgs/PoseStamped start        #起始點
geometry_msgs/PoseStamped goal        #目標點
float32 tolerance    #到達目標點的x,y方向的容錯距離
---
nav_msgs/Path plan

SetBool.srv

#文件位置:std_srvs/SetBools.srv
bool data # 啟動或者關閉硬件
---
bool success   # 標示硬件是否成功運行
string message # 運行信息

SetCameraInfo.srv

#文件位置:sensor_msgs/SetCameraInfo.srv
#通過給定的CameraInfo相機信息,來對相機進行標定
sensor_msgs/CameraInfo camera_info        #相機信息
---
bool success            #如果調用成功,則返回true
string status_message    #給出調用成功的細節

SetMap.srv

#文件位置:nav_msgs/SetMap.srv
#以初始位置為基准,設定新的地圖
nav_msgs/OccupancyGrid map
geometry_msgs/PoseWithCovarianceStamped initial_pose
---
bool success

TalkerListener.srv

#文件位置: 自定義srv文件
---
bool success   # 標示srv是否成功運行
string message # 信息,如錯誤信息等

Trigger.srv

#文件位置:std_srvs/Trigger.srv
---
bool success   # 標示srv是否成功運行
string message # 信息,如錯誤信息等

09 Parameter server

基於RPC的參數服務器

  • Talker向ROS Master設置變量參數
  • Listener向ROS Master查詢參數值
  • ROS Master向Listener發送參數值

總結:通信協議都是RPC

9.1 簡介

參數服務器(parameter server)。與前兩種通信方式不同,參數服務器也可以說是特殊的“通信方式”。特殊點在於參數服務器是節點存儲參數的地方、用於配置參數,全局共享參數。參數服務器使用互聯網傳輸,在節點管理器中運行,實現整個通信過程。

參數服務器,作為ROS中另外一種數據傳輸方式,有別於topic和service,它更加的靜態。參數服務器維護着一個數據字典,字典里存儲着各種參數和配置。

字典簡介

何為字典,其實就是一個個的鍵值對,我們小時候學習語文的時候,常常都會有一本字典,當遇到不認識的字了我們可以查部首查到這個字,獲取這個字的讀音、意義等等,而這里的字典可以對比理解記憶。鍵值kay可以理解為語文里的“部首”這個概念,每一個key都是唯一的,參照下圖:

每一個key不重復,且每一個key對應着一個value。也可以說字典就是一種映射關系,在實際的項目應用中,因為字典的這種靜態的映射特點,我們往往將一些不常用到的參數和配置放入參數服務器里的字典里,這樣對這些數據進行讀寫都將方便高效。

維護方式

參數服務器的維護方式非常的簡單靈活,總的來講有三種方式:

  • 命令行維護
  • launch文件內讀寫
  • node源碼

下面我們來一一介紹這三種維護方式。

9.2 命令行維護

使用命令行來維護參數服務器,主要使用rosparam語句來進行操作的各種命令,如下表:

rosparam 命令 作用
rosparam set param_key param_value 設置參數
rosparam get param_key 顯示參數
rosparam load file_name 從文件加載參數
rosparam dump file_name 保存參數到文件
rosparam delete 刪除參數
rosparam list 列出參數名稱

load&&dump文件

load和dump文件需要遵守YAML格式,YAML格式具體示例如下:

name:'Zhangsan'
age:20
gender:'M'
score{Chinese:80,Math:90}
score_history:[85,82,88,90]

簡明解釋。就是“名稱+:+值”這樣一種常用的解釋方式。一般格式如下:

key : value

遵循格式進行定義參數。其實就可以把YAML文件的內容理解為字典,因為它也是鍵值對的形式。

9.3 launch文件內讀寫

launch文件中有很多標簽,而與參數服務器相關的標簽只有兩個,一個是<param>,另一個是<rosparam>。這兩個標簽功能比較相近,但<param>一般只設置一個參數,請看下例:

(1) (2) (3)

觀察上例比如序號3的param就定義了一個key和一個value,交給了參數服務器維護。而序號1的param只給出了key,沒有直接給出value,這里的value是由后沒的腳本運行結果作為value進行定義的。序號(2)就是rosparam的典型用法,先指定一個YAML文件,然后施加command,其效果等於rosparam load file_name

9.4 node源碼

除了上述最常用的兩種讀寫參數服務器的方法,還有一種就是修改ROS的源碼,也就是利用API來對參數服務器進行操作。

參數類型

ROS參數服務器為參數值使用XMLRPC數據類型,其中包括:strings, integers, floats, booleans, lists, dictionaries, iso8601 dates, and base64-encoded data。

10 Action

10.1 簡介

Actionlib是ROS中一個很重要的庫,類似service通信機制,actionlib也是一種請求響應機制的通信方式,actionlib主要彌補了service通信的一個不足,就是當機器人執行一個長時間的任務時,假如利用service通信方式,那么publisher會很長時間接受不到反饋的reply,致使通信受阻。當service通信不能很好的完成任務時候,actionlib則可以比較適合實現長時間的通信過程,actionlib通信過程可以隨時被查看過程進度,也可以終止請求,這樣的一個特性,使得它在一些特別的機制中擁有很高的效率。

10.2 通信原理

Action的工作原理是client-server模式,也是一個雙向的通信模式。通信雙方在ROS Action Protocol下通過消息進行數據的交流通信。client和server為用戶提供一個簡單的API來請求目標(在客戶端)或通過函數調用和回調來執行目標(在服務器端)。

工作模式的結構示意圖如下:

什么是動作(action)

  • 一種問答通信機制;
  • 帶有連續反饋;
  • 可以在任務過程中止運行;
  • 基於ROS的消息機制實現。

    通信雙方在ROS Action Protocal下進行交流通信是通過接口來實現,如下圖:

Action的接口

  • goal:發布任務目標;
  • cancel:請求取消任務;
  • status:通知客戶端當前的狀態;
  • feedback:周期反饋任務運行的監控數據;
  • result:向客戶端發送任務的執行結果,只發布一次。

    我們可以看到,客戶端會向服務器發送目標指令和取消動作指令,而服務器則可以給客戶端發送實時的狀態信息,結果信息,反饋信息等等,從而完成了service(服務)沒法做到的部分.

10.3 Action 規范

利用動作庫進行請求響應,動作的內容格式應包含三個部分,目標、反饋、結果。

  • 目標

機器人執行一個動作,應該有明確的移動目標信息,包括一些參數的設定,方向、角度、速度等等。從而使機器人完成動作任務。

  • 反饋

在動作進行的過程中,應該有實時的狀態信息反饋給服務器的實施者,告訴實施者動作完成的狀態,可以使實施者作出准確的判斷去修正命令。

  • 結果

當運動完成時,動作服務器把本次運動的結果數據發送給客戶端,使客戶端得到本次動作的全部信息,例如可能包含機器人的運動時長,最終姿勢等等。

10.4 Action規范文件格式

Action規范文件的后綴名是.action,它的內容格式如下:

# Define the goal
uint32 dishwasher_id  # Specify which dishwasher we want to use
---
# Define the result
uint32 total_dishes_cleaned
---
# Define a feedback message
float32 percent_complete

10.5 Action實例詳解

Actionlib是一個用來實現action的一個功能包集。我們在demo中設置一個場景,執行一個搬運的action,搬運過程中客戶端會不斷的發回反饋信息,最終完成整個搬運過程.

本小節的演示源碼在課程的演示代碼包里,此處為鏈接.

首先寫handling.action文件,類比如上的格式.包括三個部分,目標,結果,反饋.如下:

# Define the goal
uint32 handling_id 
---
# Define the result
uint32 Handling_completed
---
# Define a feedback message
float32 percent_complete

寫完之后修改文件夾里CmakeLists.txt如下內容:

  1. find_package(catkin REQUIRED genmsg actionlib_msgs actionlib)
  2. add_action_files(DIRECTORY action FILES DoDishes.action) generate_messages(DEPENDENCIES actionlib_msgs)
  3. add_action_files(DIRECTORY action FILES Handling.action)
  4. generate_messages( DEPENDENCIES actionlib_msgs)

修改package.xml,添加所需要的依賴如下:

  1. actionlib
  2. actionlib_msgs
  3. actionlib
  4. actionlib_msgs

然后回到工作空間 catkin_ws進行編譯.

本例中設置的action,定義了一個搬運的例子,首先寫客戶端,實現功能發送action請求,進行目標活動.之后寫服務器,實驗返回客戶端活動當前狀態信息,結果信息,和反饋信息.從而實現action.本例測試結果截圖如下:

小結

至此,ROS通信架構的四種通信方式就介紹結束,我們可以對比學習這四種通信方式,去思考每一種通信的優缺點和適用條件,在正確的地方用正確的通信方式,這樣整個ROS的通信會更加高效,機器人也將更加的靈活和智能。機器人學會了通信,也就相當於有了“靈魂”。

11 常見action類型

本小節介紹常見的action類型以及其定義

AddTwoInts.action

#文件位置:自定義action文件
#表示將兩個整數求和
int64 a
int64 b
---
int64 sum
---

AutoDocking.action

#文件位置:自定義action文件
#goal
---
#result
string text
---
#feedback
string state
string text

GetMap.action

#文件位置:nav_msgs/GetMap.action
#獲取地圖信息,響應部分為空

---
nav_msgs/OccupancyGrid map
---
#無返回部分

MoveBase.action

#文件位置:geometry_msgs/MoveBase.action
geometry_msgs/PoseStamped target_pose
---
---
geometry_msgs/PoseStamped base_position


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM