相信許多愛好者止步於昂貴的機器人價格。雖然有了Arduino,但一個載重能力很弱的機器人小車成本也得一兩百塊錢。搭建自己的機器人更是費時費力。
所以如果你只是普通機器人愛好者,或者還沒想好要拿機器人做什麼,那我們還是從模擬器開始吧……
URDF
為了製作我們的模擬器,首先我們得瞭解下什麼是URDF
什麼是URDF。 Unified Robot Description Format——統一機器人描述格式。總覺得這和Sensor支援才是ROS的精華所在,通訊frameworks的並不見得出彩。
可能大部分讀者都像我這樣窮<bi~背景聲>沒錢買ROS支援的機器人,不過ROS還是很Nice的考慮到了這一群體,提供了模擬器支援。(明明是為了更快速的軟體開發,喂。)
本想從ROS網站的培訓教程開始http://wiki.ros.org/urdf/Tutorials開始的,不過本著實踐為本的目的,我們還是以《Learning ROS for Robostic Programming》為基礎吧。
參考文獻
1. ROS urdf教程:http://wiki.ros.org/urdf/Tutorials
2. 《Learning ROS for Robostic Programming》
準備工作
安裝urdf_tutorial包
sudo apt-get install ros-hydro-urdf-tutorial
執行
rosrun rviz rviz
當然,沒有運行roscore你的rviz也無法啟動。不過如果錯誤顯示你的rviz找不到執行檔案的話,請參照http://wiki.ros.org/rviz
URDF基本文法
統一機器人描述格式URDF,其實就是為了能夠抽象描述一個機器人的硬體。而且URDF是基於XML的,所以閱讀起來應該非常容易。
筆者以為要理解URDF用自頂向下的方式更快。即從為瞭解決一個怎樣的問題開始。在這裡我們先用一個簡單情境熟悉一下會用到的工具。
不得不說小車是最簡單實用的機器人, 一個車身加四個輪子就組成了最基本的小車結構,而且具備一定載重能力的小車也不會太貴。
見如下圖片。
(圖一)
第一版
在URDF語言中,機器人都會由各個組件(Link)通過關節(Joint)串連而成。而這裡的關鍵就是描述組件和關節之間的關係。
在這個簡單的小車模型中,一共有5個組件: 車身 + 4個輪子。 4個關節: 每個輪子一個。
於是,我們得到了最初了URDF版本 01_car_skeleton.urdf
<robot name="test_robot"> <link name="base_link" /> <link name="wheel_1" /> <link name="wheel_2" /> <link name="wheel_3" /> <link name="wheel_4" /> <joint name="joint_base_wheel1" type="fixed"> <parent link="base_link"/> <child link="wheel_1"/> </joint> <joint name="joint_base_wheel2" type="fixed"> <parent link="base_link"/> <child link="wheel_2"/> </joint> <joint name="joint_base_wheel3" type="fixed"> <parent link="base_link"/> <child link="wheel_3"/> </joint> <joint name="joint_base_wheel4" type="fixed"> <parent link="base_link"/> <child link="wheel_4"/> </joint></robot>
很簡單對吧。
用<link> tag描述各個組件,<joint> tag描述各個關節。用<parent>和<child>描述關節串連的組件。
只要描述了Link和Joint之間的關係,我們很容易就能構建機器人的架構。
我們可以用如下命令來檢查urdf檔案是否有文法問題。
check_urdf 01_skeleton.urdf
只要得到如下結果就表明文法沒問題。
robot name is: test_robot---------- Successfully Parsed XML ---------------root Link: base_link has 4 child(ren) child(1): wheel_1 child(2): wheel_2 child(3): wheel_3 child(4): wheel_4
但請注意這雖然描述了各個組件之間的關係,但仍是一個不完整的URDF,無法在模擬器中顯示。
第二版
<visual>tag用來描述模組的視覺效果。
<geometry>tag 用來描述模組的形狀和大小。
<origin>tag用來描述模組的位置。
加上模組大小之後的小車檔案如下所示。02_visual.urdf
<robot name="test_robot"> <link name="base_link"> <visual> <geometry> <box size="0.2 .3 .1"/> </geometry> <origin rpy="0 0 0" xyz="0 0 0.05"/> </visual> </link> <link name="wheel_1"> <visual> <geometry> <cylinder length="0.05" radius="0.05"/> </geometry> <origin rpy="0 1.5 0" xyz="0.1 0.1 0"/> </visual> </link> <link name="wheel_2"> <visual> <geometry> <cylinder length="0.05" radius="0.05"/> </geometry> <origin rpy="0 1.5 0" xyz="-0.1 0.1 0"/> </visual> </link> <link name="wheel_3"> <visual> <geometry> <cylinder length="0.05" radius="0.05"/> </geometry> <origin rpy="0 1.5 0" xyz="0.1 -0.1 0"/> </visual> </link> <link name="wheel_4"> <visual> <geometry> <cylinder length="0.05" radius="0.05"/> </geometry> <origin rpy="0 1.5 0" xyz="-0.1 -0.1 0"/> </visual> </link> <joint name="joint_base_wheel1" type="fixed"> <parent link="base_link"/> <child link="wheel_1"/> </joint> <joint name="joint_base_wheel2" type="fixed"> <parent link="base_link"/> <child link="wheel_2"/> </joint> <joint name="joint_base_wheel3" type="fixed"> <parent link="base_link"/> <child link="wheel_3"/> </joint> <joint name="joint_base_wheel4" type="fixed"> <parent link="base_link"/> <child link="wheel_4"/> </joint></robot>
現在通過如下命令,你就通過rviz查看你的小車模型啦。
roslaunch urdf_tutorial display.launch model:=02_visual.urdf
第三步: 上色
Mmm,我們的小車就快完成了,但全是紅色總覺得怪怪的而且很難辨認。
不過上色同樣很簡單。使用<material> tag並且設定<color> tag
我們得到第三個版本:03_color.urdf
<robot name="test_robot"> <link name="base_link"> <visual> <geometry> <box size="0.2 .3 .1"/> </geometry> <origin rpy="0 0 0" xyz="0 0 0.05"/> <material name="white"> <color rgba="1 1 1 1"/> </material> </visual> </link> <link name="wheel_1"> <visual> <geometry> <cylinder length="0.05" radius="0.05"/> </geometry> <origin rpy="0 1.5 0" xyz="0.1 0.1 0"/> <material name="black"> <color rgba="0 0 0 1"/> </material> </visual> </link> <link name="wheel_2"> <visual> <geometry> <cylinder length="0.05" radius="0.05"/> </geometry> <origin rpy="0 1.5 0" xyz="-0.1 0.1 0"/> <material name="black"/> </visual> </link> <link name="wheel_3"> <visual> <geometry> <cylinder length="0.05" radius="0.05"/> </geometry> <origin rpy="0 1.5 0" xyz="0.1 -0.1 0"/> <material name="black"/> </visual> </link> <link name="wheel_4"> <visual> <geometry> <cylinder length="0.05" radius="0.05"/> </geometry> <origin rpy="0 1.5 0" xyz="-0.1 -0.1 0"/> <material name="black"/> </visual> </link> <joint name="joint_base_wheel1" type="fixed"> <parent link="base_link"/> <child link="wheel_1"/> </joint> <joint name="joint_base_wheel2" type="fixed"> <parent link="base_link"/> <child link="wheel_2"/> </joint> <joint name="joint_base_wheel3" type="fixed"> <parent link="base_link"/> <child link="wheel_3"/> </joint> <joint name="joint_base_wheel4" type="fixed"> <parent link="base_link"/> <child link="wheel_4"/> </joint></robot>
我們可以看到rviz的結果,如圖一所示。
這下我們差不多完成了。我們馬上就可以移動我們的小車啦。
但是等等,在我們的URDF檔案中,內嵌了關於各個組件的大小參數以及位置。這些當然是我們根據草圖用計算機算出來的。
但是這樣的擴充性也太差了吧。難道對每個模型我們都得這麼計算嗎。對於相同模型的不同尺寸我們還得重新計算一次。
第四步: Xacro
什麼是Xacro? 我們可以把它理解成為針對URDF的擴充性和配置性而設計的宏語言(macro language)。
有了Xacro,我們就可以像編程一樣來寫URDF檔案了。
首先我們來看Xacro檔案的變數定義:
<xacro:property name="body_width" value=".2" />
只要定義了body_width,我們就可以通過${body_width}來引用其值了。有了這個,至少我們可以把需要配置的變數進行統一管理。
其次,我們來看一下Xacro如何進行宏定義。
這裡的宏和C語言的宏很像,在轉換成URDF檔案時編譯器會將其展開。其基本文法為:
<xacro:macro name="wheel" params="param1 param2"> </xacro:macro>
我們來看下URDF檔案中關於車身和車輪的大小描述。
<box size="0.2 .3 .1"/>
<origin rpy="0 0 0" xyz="0 0 0.05"/>
<cylinder length="0.05" radius="0.05"/>
<origin rpy="0 1.5 0" xyz="-0.1 0.1 0"/>
這裡涉及到的參數有:
車身的大小(body_size),車身中心的位置(body_pos)。
車輪半徑(wheel_radius)和輪胎寬度(wheel_width),車輪圓心的位置(wheel1_pos, wheel2_pos, wheel3_pos, wheel4_pos)。
相應的在Xacro中定義參數的文法為:
<xacro:property name="body_size" value=".2 .3 .1" /> <xacro:property name="body_pos" value="0 0 0.05" /> <xacro:property name="wheel_radius" value="0.05" /> <xacro:property name="wheel_length" value="0.05" /> <xacro:property name="wheel1_pos" value="0.1 0.1 0" /> <xacro:property name="wheel2_pos" value="-0.1 0.1 0" /> <xacro:property name="wheel3_pos" value="0.1 -0.1 0" /> <xacro:property name="wheel4_pos" value="-0.1 -0.1 0" />
並且每個輪子和串連的代碼也基本相同。
基於上述亮點,我們可以得到以下xacro檔案。04_xacro.xacro
<?xml version="1.0"?><robot xmlns:sensor="http://playerstage.sourceforge.net/gazebo/xmlschema/#sensor" xmlns:controller="http://playerstage.sourceforge.net/gazebo/xmlschema/#controller" xmlns:interface="http://playerstage.sourceforge.net/gazebo/xmlschema/#interface" xmlns:xacro="http://playerstage.sourceforge.net/gazebo/xmlschema/#interface" name="test_robot"> <xacro:property name="body_size" value=".2 .3 .1" /> <xacro:property name="body_pos" value="0 0 0.05" /> <xacro:property name="wheel_radius" value="0.05" /> <xacro:property name="wheel_length" value="0.05" /> <xacro:property name="wheel1_pos" value="0.1 0.1 0" /> <xacro:property name="wheel2_pos" value="-0.1 0.1 0" /> <xacro:property name="wheel3_pos" value="0.1 -0.1 0" /> <xacro:property name="wheel4_pos" value="-0.1 -0.1 0" /> <xacro:macro name="wheel" params="wheelname position"> <link name="${wheelname}"> <visual> <geometry> <cylinder length="${wheel_length}" radius="${wheel_radius}"/> </geometry> <origin rpy="0 1.5 0" xyz="${position}"/> <material name="black"> <color rgba="0 0 0 1"/> </material> </visual> </link> <joint name="joint_base_${wheelname}" type="fixed"> <parent link="base_link"/> <child link="${wheelname}"/> </joint> </xacro:macro> <xacro:wheel wheelname="wheel1" position="${wheel1_pos}"/> <xacro:wheel wheelname="wheel2" position="${wheel2_pos}"/> <xacro:wheel wheelname="wheel3" position="${wheel3_pos}"/> <xacro:wheel wheelname="wheel4" position="${wheel4_pos}"/> <link name="base_link"> <visual> <geometry> <box size="${body_size}"/> </geometry> <origin rpy="0 0 0" xyz="${body_pos}"/> <material name="white"> <color rgba="1 1 1 1"/> </material> </visual> </link></robot>
驗證該檔案的正確性可以有兩種方法。
1. 轉換成URDF檔案,使用check_urdf
rosrun xacro xacro.py 04_xacro.xacro > 04_xacro.urdf
2. 使用xacrodisplay.launch
roslaunch urdf_tutorial xacrodisplay.launch model:=04_xacro.xacro
我們都會得到和圖1一樣的小車模型。這下我們就可以用Xacro來構建機器人模型了。