ROS 學習系列,ros學習系列
前面已經介紹了如何使用URDF建造機器人小車並顯示在Rviz的模擬環境裡面,但是小車是靜止的。下面介紹如何讓它在Rviz裡面動起來,並理清URDF,TF 和 odom 的關係。
1. ROS中base_link, odom, fixed_frame, target_frame和虛擬大地圖map的關係
一般在urdf檔案中都要定義base_link,它代表了機器人的主幹,其它所有的frame都是相對於base_link定義並粘在一起的。它們一起相對於大地圖map移動,讓機器人移動就是向tf發布 geometry_msgs::TransformStamped 訊息通知ros base_linke相對於map的tf轉換關係。先看一下這幾個概念在ros中的定義:
map
map是虛擬世界中的固定frame, 它的Z軸指向正上方,也就是天空。一個時間點上移動機器人的姿態相對於map不應該出現明顯的漂移。如果一個map是不連續穩定的那就意味著機器人的位置在任何一個時間點上都會是變化的。
一般雷射地位儀等裝置會連續的計算map的位置因而造成它的不穩定性,這也使它不能成為一個好的參照體frame.
odom
odom是一個很好的固定世界參照frame.機器人的姿態相對odom而言是隨時間是經常可變,所以在長遠中它不是一個好的全域參照系。但在某一時間點而言它相對機器人的位置是不變的。
典型的 odom frame 是通過運動源來計算出來的, 例如輪子運動,視覺位移等.
odom frame 的準確性使它在局部參照系中是很有用的。但是不適合作全域參照frame.
base_link
base_link參照繫緊緊粘在移動機器人基座上的任何一個位置和角度。
各個Frames的關係
frame之間是按樹狀結構組織的。所以每個frame只有一個父節點和任意多個子節點。 上述幾個frame的關係:
map --> odom --> base_link
Frame Authorities
odom到base_link的座標轉換是從運動源計算出來廣播的。
map到base_link的座標轉換是被定位模組計算出來的. 但定位模組並不發布map到base_link的轉換. 相反它先接受從odom到base_link的轉換, 再計算並廣播map到odom的位置轉換關係。
fixed_frameRViz中認定的大世界就是fixed_frame
target_frame
Rviz中視覺跟蹤的frame是 target_frame
2. RViz如何動態確定各個frame之間的座標轉換
先看一下啟動RViz的launch檔案,裡面定要了服務於RViz的參數和node
<launch> <arg name="model" /> <arg name="gui" default="False" /> <param name="robot_description" textfile="$(arg model)" /> <param name="use_gui" value="$(arg gui)"/> <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" /> <node name="robot_state_publisher" pkg="robot_state_publisher" type="state_publisher" /> <node name="rviz" pkg="rviz" type="rviz" args="-d $(find sp1s)/urdf.rviz" required="true" /></launch>
"robot_description" 參數定義了urdf檔案的路徑,它被 robot_state_publisher節點使用。該節點解析urdf檔案後將各個frame的狀態發布給tf. 因此在rviz裡面就看到各個frame(link)之間的tf轉換顯示OK.否則會顯示warning.
"joint_state_publisher"節點擷取urdf裡面定義的rotate link並發布座標轉換給tf.否則會顯示warning. 注意: "joint_state_publisher" 是python寫的,只支援ascii編碼,不支援Unicode,如果發現RViz報告下面錯誤:
"No transform from [front_left] to [base_link]"
那就是因為urdf檔案是Unicode編碼的。
3. geometry_msgs/TransformStamped 訊息的作用和機構geometry_msgs/TransformStamped 就是通知ROS 兩個frame之間的tf轉換關係。當兩個frame之間關係經常變化,如輪子移動,手臂關節移動等,則需要編寫node來即時發布。查看該訊息結構:
<span style="font-size:18px;">rosmsg show -r geometry_msgs/TransformStamped# This expresses a transform from coordinate frame header.frame_id# to the coordinate frame child_frame_id## This message is mostly used by the # <a href="http://www.ros.org/wiki/tf">tf</a> package. # See its documentation for more information.Header headerstring child_frame_id # the frame id of the child frameTransform <strong><span style="color:#FF0000;">transform</span></strong></span>
Transform其中transform就是我們關心的 tf 轉換關係,child_frame_id是"base_link", header.frame_id 則是'odom'. 查看geometry_msgs/transform:
rosmsg show -r geometry_msgs/Transform# This represents the transform between two coordinate frames in free space.Vector3 <strong><span style="color:#FF0000;">translation</span></strong>Quaternion rotationrosmsg show -r Vector3[geometry_msgs/Vector3]:# This represents a vector in free space. float64 xfloat64 yfloat64 z
這裡的x, y, z 就定義了兩個frame的tf轉換關係。
4. RViz中如何定義 base_link 和 odom 之間的 tf 座標轉換要移動機器人,就需要向tf發布geometry_msgs/TransformStamped 訊息通知ros base_linke相對於map的tf轉換關係,也就是說告訴ROS運動的base_link相對於不動的odom位置位移。這裡的odom frame並不能定義在urdf檔案裡面,它是一個虛擬。我們只需要RViz知道fixed_frame就是odom就可以了。所以在urdf.rviz檔案中這樣定義虛擬odom:
<span style="font-size:18px;">Global Options: Background Color: 48; 48; 48 Fixed Frame: <strong><span style="color:#FF0000;">/odom</span></strong> Target Frame: <Fixed Frame> Frame Rate: 30</span>
如果現在啟動 RViz來觀察機器人:
<span style="font-size:18px;">roslaunch sp1s display.launch model:=urdf/sp1s.urdf </span>
肯定會得到錯誤警告,而且RViz中無法顯示完整的機器人:
"No transform from [odom] to [base_link]"
這個錯誤很容易理解,沒有任何地方定義odom和base_link之間的tf關係,他們之間是連續變化的,我們當然不能在任何地方寫固定位移量定義tf transform.
但是我們可以寫一個node來不斷的發送geometry_msgs/TransformStamped訊息。被發送對象就是tf。 ROS官方有個執行個體完整代碼如何發布odom到base_link的變換,代碼執行個體直接拷貝並在本地編譯。這個例子不斷向odom主題發送訊息更改odom與base_link之間的位移,位移的軌跡就是一個圓周。這個node名字叫 odom_publisher. 它其實做了兩件事情:
1. 向 tf 發送geometry_msgs/TransformStamped 訊息, 就是讓機器人運動起來。
2. 向odom主題發送nav_msgs/Odometry導航訊息,報告角速度,線速度和巡航角度。這部分代碼相對本文來講不是必須的。
同"joint_state_publisher" node一樣,“ odom_publisher”需要在RViz啟動之前啟動,添加它的啟動項。修改後的dispaly.launch檔案:
<launch><arg name="model" /><arg name="gui" default="False" /><param name="robot_description" textfile="$(arg model)" /><param name="use_gui" value="$(arg gui)"/> <strong><span style="color:#FF0000;"><node name="odom_publisher" pkg="sp1s" type="odom_publisher" /></span></strong> <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" /><node name="robot_state_publisher" pkg="robot_state_publisher" type="state_publisher" /><node name="rviz" pkg="rviz" type="rviz" args="-d $(find sp1s)/urdf.rviz" required="true"/></launch></span>
再次開啟RViz:
roslaunch sp1s display.launch model:=urdf/sp1s.urdf
這次就看到機器人在地圖空間中做規則的圓周運動了! 因為RViz收到了odom_publisher向tf發送的座標轉換內容。
4. RViz中觀察移動軌跡
“ odom_publisher”中還向 odom主題發布了nav_msgs/Odometry導航訊息,這樣就可以在RViz中顯示運動軌跡了。在RViz中點擊 'add',選中Odometry,配置該dispaly的topic為 "odom" 就可以看到不斷變化的運動軌跡了。這是因為nav_msgs/Odometry中包含了線速度,角速度和巡航角度,所以RViz可以顯示出來。
5.odom frame和 odom topic
這兩個完全是不同的東西,很容易混淆。一個是地圖上的一個參照系,一個是topic用來接收導航輸入的。名字一樣,純屬巧合!