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來構建機器人模型了。