機器人描述--URDF和XACRO

1. 關於URDF的一些雜談

URDF(Unified Robot Description Format), 是一種特殊的xml文件格式, 作爲機器人的一種描述文件, 在ROS裏面大量使用. 接觸ROS比較久的同學, 應該會經常見到一種類似命名的包(package) – xxx_description. 這個包裏面就是包含某個機器人的描述文件. 比如pr2_decription, baxter_descrition, 以及ur_description等. 上述舉例的機器人描述包都是可以通過apt-get的方式進行安裝. 使用命令格式如斯: sudo apt-get install ros-indigo-pr2-descrition, 其中indigo是你所安裝的ROS版本名, 後面就是所需要安裝的包名, 下劃線用中畫線代替.

對機器人使用gazebo進行仿真時, 需要加載的機器人模型就是urdf模型, 當然, 單純的urdf是不能精確描述機器人以及所需要仿真的世界的. gazebo對其進行了擴展, 感興趣的朋友可以查看gazebo官網的一些教程. 其中會提供一些標籤, 對系統動態, 重心等的設定.

如果想使用開源庫moveit對機器人進行路徑規劃, 在moveit setup assistant教程中, 第一步就是關於如何將機器人模型導入進來, 導入的機器人模型就是urdf(導入xacro格式時也是先將其解析爲urdf).

諸如這些應用, 當然還不限於這些應用, 可以看到, 瞭解URDF以及會使用URDF是一件很重要的事情. 而xacro文件, 是提供了一些更爲高級編輯方式的宏文件. 這種格式的文件, 在使用時, 均先會調用rosrun xacro xacro.py xxx.urdf.xacro > xxx.urdf, 將其解析成對應的urdf文件. 然後再使用.

下述內容, 僅僅是對urdf文件編輯和查看由最基礎的瞭解, 以方便能夠看得懂機器人描述文件, 以及該怎麼利用別人已經寫好的描述文件進行組合, 重構得到自己的機器人描述文件. 如果是需要更詳細, 精確的描述, 則還需要自己再去對urdf文件進行學習.

2. URDF文件

URDF教程中, 第一個出現的就是下圖, 很形象的將URDF要定義的主要內容給展現了出來. 一般, 機器人都是由link和joint進行描述. 都會呈現爲樹狀(想象數據結構裏面的樹), 如圖1, 由一個根link(link1)向上, 分別出現了兩個分支–link2和link3, 分別由joint連接link. link4就可以類似的理解.


這裏寫圖片描述

瞭解機器人的一般描述方式之後, 我們來看一下下圖中這個形狀的機器人該怎麼來描述它.

<robot name="test_robot">
  <link name="link1" />
  <link name="link2" />
  <link name="link3" />
  <link name="link4" />

  <joint name="joint1" type="continuous">
    <parent link="link1"/>
    <child link="link2"/>
  </joint>

  <joint name="joint2" type="continuous">
    <parent link="link1"/>
    <child link="link3"/>
  </joint>

  <joint name="joint3" type="continuous">
    <parent link="link3"/>
    <child link="link4"/>
  </joint>
</robot>

從上述內容可以看到, 機器人最重要的兩個內容 – link和joint, 是如何進行定義. 文件都定義了哪些標籤, 以及該怎麼使用. 其中內容很簡單, 我就不浪費篇幅了.

細心的朋友肯定能夠感受到, 雖然能夠想象的出來大概是一個什麼樣子, 但是上面的內容是不能夠唯一確定一個機器人或者一個…東西…, 因爲每個link長什麼樣子?他們又是一個什麼樣子的位置關係? 這些在上面的內容中都是沒有定義的. 如圖中所示, 可能現在每一個不同的同學, 所聯想到的樣子都是不一樣的, 一個仙人掌? 一個兩指的夾持器? anythin..當然, 上面所示內容的urdf文件是不能夠被正確解析的, 也是不能夠可視化出來的. 但上面內容就類似於整個機器人的骨架, 機器人就由這些東西組成. 一共擁有4個link, 和3個joint, 像圖中所示的樣子連接起來.

2.2 位置

在定義好了機器人的骨架後, 進一步我們可以使用origin子標籤進行定義link所應該在的位置. 但是有一點應該注意到, link和link之間是使用joint進行連接, 那麼link的位置, 就由連接他的joint確定. 所以, 該子標籤是定義在joint內. 在三維空間中, 要精確描述一個剛性體的姿態, 僅僅使用他的xyz座標是不夠的, 還需要使用rpy. rpy角是描述船舶在海中航行時姿態的一種方法. 將船的行駛方向取爲z軸, 繞z軸旋轉稱爲滾動(Roll), 繞y軸旋轉稱爲俯仰(Pitch), 繞x軸旋轉稱爲偏轉(Yaw). 這種描述方式大量運用於各個領域. 依稀記得, kinect2關於臉部模型匹配的DEMO程序裏面, 對臉部的描述就用到了這種描述方式來描述姿態. 在機器人中, 當然運用就更多了. 現在對之前的內容進行擴充. 其中rpy代表的是角度, 用弧度表示.

<robot name="test_robot">
  <link name="link1" />
  <link name="link2" />
  <link name="link3" />
  <link name="link4" />


  <joint name="joint1" type="continuous">
    <parent link="link1"/>
    <child link="link2"/>
    <origin xyz=".5 .3 0.7" rpy="0 0 0" />
  </joint>

  <joint name="joint2" type="continuous">
    <parent link="link1"/>
    <child link="link3"/>
    <origin xyz="-.2 .5 -0.3" rpy="0 0 1.57" />
  </joint>

  <joint name="joint3" type="continuous">
    <parent link="link3"/>
    <child link="link4"/>
    <origin xyz=".5 0 0.2" rpy="0 0 -1.57" />
  </joint>
</robot>

上述位置關係定義如下圖所示. xyz就如同一個平移向量, 將下一個link的原點座標移動到下一個位置(起點是父link的原點). 同時, 你也可以多嘗試幾次rpy, 體會下一個座標系是如何進行變換的. 雖然現在還沒有任何東西出來, 但每個link的空間位置以及姿態已經被我們所指定了.


link_graph

2.3 形狀

在解決了每個link的相對位置之後, 還有一個很關鍵的問題, 就是每個link長什麼樣子呢? 圓的? 扁的? 還是奇形怪狀的? 下面示例了一些常用的形狀, 以及可能會導入的一些奇形怪狀的東西. 不但可以導入stl格式的文件, 還可以導入dae格式.下述示例中導入了一個小刀.

<?xml version="1.0"?>
<robot name="test_robot">
  <link name="link1">
    <visual>
      <geometry>
        <cylinder length="0.6" radius="0.2" />
      </geometry>
    </visual>
  </link>

  <link name="link2">
    <visual>
      <geometry>
        <box size="0.6 0.2 .1" />
      </geometry>
    </visual>
  </link>

  <link name="link3" >
    <visual>
      <geometry>
        <sphere radius="0.2"/>
      </geometry>
    </visual>
  </link>

  <link name="link4" >
    <visual>
      <origin rpy="0 -1.57 0" xyz="0 0 0"/>
      <geometry>
        <mesh filename="package://urdf_csdn/urdf/mesh/knife.stl"/>
      </geometry>
    </visual>
  </link>


  <joint name="joint1" type="fixed">
    <parent link="link1"/>
    <child link="link2"/>
    <origin xyz="0.22 0 0.6" rpy="0 1.57 0" />
  </joint>

  <joint name="joint2" type="continuous">
    <parent link="link1"/>
    <child link="link3"/>
    <origin xyz="-0.1 0.5 0" />
  </joint>

  <joint name="joint3" type="fixed">
    <parent link="link3"/>
    <child link="link4"/>
    <origin xyz=".5 0 0" rpy="0 0 -1.57" />
  </joint>
</robot>

2.4 Collision 和 joint限制

當然, 每個link一般是不會產生重合的, 在運動規劃的時候, 也會去避免碰撞到自己, 所以針對於每一個link, 還有一個collision標籤, 和visual標籤內容完全一樣.

前面內容可以看到, 每個link可以看作是一個剛體, 剛體和剛體之間是通過joint進行連接, 那麼, 問題就來了. 這個joint是固定的? 還是可以任意的動? 如果可以動, 那麼, 問題又來了, 極限位置是多少? 等等等等…

比如, 我們限定joint2只能沿着y軸旋轉, 則需要添加<axis xyz="0 1 0"/>, 類似的, 可以指定其他關節的轉動軸, 例如<axis xyz="-0.2 0.1 1"/>.

比如, 我們要限定joint2的移動範圍, 則需要添加<limit lower="-3.14" upper="3.14" effort="150.0" velocity="3.15"/>, 從標籤中可以看到, 上下限以及速度, 力矩等都是可以指定的.

<?xml version="1.0"?>
<robot name="test_robot">
  <link name="link1">
    <visual>
      <geometry>
        <cylinder length="0.6" radius="0.2" />
      </geometry>
    </visual>

    <collision>
      <origin xyz="0.0 0 0.0" rpy="0 0 0" />
      <geometry>
        <cylinder length="0.6" radius="0.2" />
      </geometry>
    </collision>
  </link>

  <link name="link2">
    <visual>
      <geometry>
        <box size="0.6 0.2 .1" />
      </geometry>
    </visual>
  </link>

  <link name="link3" >
    <visual>
      <geometry>
        <sphere radius="0.2"/>
      </geometry>
    </visual>
  </link>

  <link name="link4" >
    <visual>
      <origin rpy="0 -1.57 0" xyz="0 0 0"/>
      <geometry>
        <mesh filename="package://urdf_csdn/urdf/mesh/knife.stl"/>
      </geometry>
    </visual>
  </link>


  <joint name="joint1" type="fixed">
    <parent link="link1"/>
    <child link="link2"/>
    <origin xyz="0.22 0 0.6" rpy="0 1.57 0" />
  </joint>

  <joint name="joint2" type="continuous">
    <parent link="link1"/>
    <child link="link3"/>
    <origin xyz="-0.1 0.5 0" />
    <axis xyz="0 1 0"/>
    <limit lower="-3.14" upper="3.14" effort="150.0" velocity="3.15"/>
  </joint>

  <joint name="joint3" type="fixed">
    <parent link="link3"/>
    <child link="link4"/>
    <origin xyz=".5 0 0" rpy="0 0 -1.57" />
  </joint>
</robot>

2.5 可視化

查看urdf文件, 可以使用urdf_tutorial包, 命令格式roslaunch urdf_tutorial display.launch model:=path/to/your/xxx.urdf, 會使用Rviz進行顯示, 如上述內容, 進行顯示之後, 可以得到下圖所示內容. 座標系圖示, 需要添加TF條目進行顯示. 值得注意的地方, 將Global Options中的fixed frame設定爲link1. 如果你設定了可移動的關節, 想查看以下關節移動的效果以及設定等, 使用roslaunch urdf_tutorial display.launch model:=path/to/your/xxx.urdf gui:=true, 你會看到彈出一個控制面板(如果沒找到, 再好好找一找, 或許真的很小).


這裏寫圖片描述

通過上述方式, 在rviz中正確顯示模型之後, 新打開一個命令行, 輸入rostopic list命令, 可以查看到類似如下的輸出. 可以看到, 開啓了/joint_states話題(Topic), 使用rostopic echo /joint_states可以看到話題數據.


這裏寫圖片描述

3. XACRO文件

前面也提到了, XACRO文件和URDF實質上是等價的. XACRO格式提供了一些更高級的方式來組織編輯機器人描述. 主要提供了三種方式來使得整個描述文件變得簡單. 借用在教程中一句話來形容xacro的優勢: “Fortunately, you can use the xacro package to make your life simpler”.

3.1 Constants

Usage: <xacro:property name="WIDTH" value="2.0"/>

類似於C語言中的宏定義, 在頭部定義, 如<xacro:property name="WIDTH" value="2.0"/>, 以${WIDTH}的方式進行使用. 經常會看到的一個常量定義, <property name="PI" value="3.14159265" />. 還有定義一個前綴, 這樣後面關節名都可以方便的進行修改. 比如<property name="prefix" value="my_"/>, 後面關節名字就可以類似的進行更新. <joint name="${prefix}joint1" type="revolute"/>.

在有了上面的常量定義之後, 類似於宏定義, 完成字符串替換, 同時還可以進行一些簡單的數學運算.

Usage: ${1/2}, ${PI*(WIDTH*0.5)}

3.2 Macros

這個纔是xacro文件中最重要的部分. 就像宏函數一樣, 完成一些最小模塊的定義, 方便重用, 以及可以使用參數來標識不同的部分.

3.2.1 Simple Macro

Usage:

<xacro:macro name="default_origin">
    <origin xyz="0 0 0" rpy="0 0 0"/>
</xacro:macro>
<xacro:default_origin />

前面三行對宏進行定義, 第四行是使用.

3.2.2 Parameterized Macro

Usage:

<xacro:macro name="default_link" params="prefix">
    <link name="${prefix}_link1" />
</xacro:macro>
<xacro:default_link prefix="my" />

類似, 前三行定義, 第四行是進行使用. 當然, 不單由這樣簡單的參數, 還可以使用塊參數.
Usage:

<xacro:macro name="default_link" params="prefix *origin">
    <link name="${prefix}_link1" >
        <xacro:insert_block name="prigin" />
    </link>
</xacro:macro>
<xacro:default_link prefix="my">
    <origin xyz="0 0 0" rpy="0 0 0" />
</xacro:default_link>

一般情況下, 很多已有的機器人模型, 都是以xacro格式提供描述, 而在xacro文件中, 整個機器人定義爲一個很大的宏. 例如, barrett hand, 想進一步瞭解的朋友可以點擊前面的鏈接, 查看以下barrett hand是如何進行描述的.

3.2.3 Include

很多模型都是已宏的形式進行定義, 並以最小集團分成很多個文件. 而最終的機器人描述就變得非常簡單了. 下面摘錄一個ur5的描述文件. 從中可以看出來xacro的強大優勢. 在最後的示例中我們還能夠看到, urdf文件也是能夠直接導入進來的.

<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="ur5" >

  <!-- common stuff -->
  <xacro:include filename="$(find ur_description)/urdf/ur5/common.gazebo.xacro" />

  <!-- ur5 -->
  <xacro:include filename="$(find ur_description)/urdf/ur5/ur5.urdf.xacro" />

  <!-- arm -->
  <xacro:ur5_robot prefix="" joint_limited="false"/>

  <link name="world" />

  <joint name="world_joint" type="fixed">
    <parent link="world" />
    <child link = "base_link" />
    <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
  </joint>

</robot>

當然, 此時的簡單是建立在之前的複雜的基礎上的. 從上述內容中可以看到, 首先是在ur_description包中找到另外幾個xacro文件, 將其包含進來. 當然應該注意到, include類似於C語言中的include, 先將該文件擴展到包含的位置. 但包含進來的文件很有可能只是一個參數宏的定義. 並沒有被調用. 所以, 示例中調用了一個宏(<xacro:ur5_robot prefix="" joint_limited="false"/>), 產生一個ur5機器人.

3.3 可視化

urdf_tutorial包也是可以查看xacro文件的. 使用roslaunch urdf_tutorial xacrodisplay.launch model:=path/to/your/xxx.urdf.xacro.

4. 關於urdf_tutorial

前面提到的可視化都是使用urdf_tutorial包進行的. 分別調用了兩個launch文件. 在上面的示例中我們還看到了不但會使用rviz進行可視化, 還會發起一些話題等. 其實這些我們能夠從他的launch文件中一窺究竟.

打開命令行, 輸入: rosed urdf_tutorial dispaly.launch. 會使用vim打開該文件. 可以看到下述內容.

<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 urdf_tutorial)/urdf.rviz" required="true" />
</launch>

由上可以看到, 參數model是沒有默認值的, 所以調用該launch文件必須指定model參數. 其他都比較易懂, 主要解釋以下robot_description, 可以看到, 其前面是param. 這個是指定ros 參數服務器中的參數值. 而打開rviz之後, rviz就是直接從參數服務器中讀取機器人描述文件, 也就是這個參數. 然後進行顯示. use_gui也是如此對顯示產生的影響. 另外, 還發起了兩個發佈者節點, 分別發佈joint_states和robot_state. 這也就是會由joint_states話題的原因. xacrodispaly.launch文件和上面類似, 但在處理文件時, 使用的是: <param name="robot_description" command="$(find xacro)/xacro.py $(arg model)" />. 在launch中將xacro文件解析爲urdf.

至於其中啓動的兩個節點, joint_state_publisher 和 robot_state_publisher, 可以查看ROS Answer上相關的解釋. 另外, 在robot_state_publisher概述中提到, robot_state_publisher從/joint_states話題中獲取機器人joint角度作爲輸入, 使用機器人的運動學樹模型計算出機器人link的3D姿態, 然後將其發佈到話題/tf/tf_static. joint_state_publisher從ROS參數服務器中讀取robot_description參數, 找到所有non-fixed joint, 發佈他們的JointState消息到/joint_states話題.

5. 排列組合

5.1 UR + Barrett

有了前面的基礎之後, 我們就可以進行一些屬於我們自己的私人定製了. 比如說, 使用ur5作爲手臂, 接上barrett hand或者shadow hand. 這樣就可以得到一個完整的操作模型了. 先看一下效果.


這裏寫圖片描述

UR Description

首先需要下載所需要的UR機械臂的包, 打開命令行, 輸入: git clone https://github.com/ros-industrial/universal_robot.git, 下載下來之後, 在universal_robot文件夾內有一個叫ur_description文件夾, 這裏面就是我們需要的機器人描述文件.

* Barrett Hand Description*

https://github.com/RobotnikAutomation/barrett_hand/tree/hydro-devel中, 下載得到bhand_description, 就是我們所需要的barrett hand描述文件.

* 組合 *

將前面得到的ur_description和bhand_description拷貝到catkin_ws目錄下(確保能夠找到這兩個包), 到catkin_ws目錄下, 運行catkin_make. 注意查看提示信息, 是否發現ur_description和bhand_description這兩個包.

以下述內容新建一個文件, 以xxx.urdf.xacro格式命名. 運行roslaunch urdf_tutorial xacrodisplay.launch model:=path/to/your/xxx.urdf.xacro來進行顯示. 最終結果就如上圖所示. 從下面的描述來看, 是不是很簡潔?

<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="ur5bh" >

  <!-- common stuff -->
  <xacro:include filename="$(find ur_description)/urdf/common.gazebo.xacro" />

  <!-- ur5 -->
  <xacro:include filename="$(find ur_description)/urdf/ur5.urdf.xacro" />

  <!-- barrett hand -->
  <xacro:include filename="$(find bhand_description)/urdf/bh282.urdf.xacro" />

  <!-- arm -->
  <xacro:ur5_robot prefix="" joint_limited="true"/>

  <link name="world" />

  <joint name="world_joint" type="fixed">
    <parent link="world" />
    <child link = "base_link" />
    <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
  </joint>

  <!-- end effector -->
  <xacro:bhand_macro parent="ee_link" name="bh">
    <origin xyz="0.012 0.0 0.0" rpy="${pi/2.0} ${pi/2.0} ${pi/2.0}"/>
  </xacro:bhand_macro>

</robot>

5.2 Baxter + YCB

有些時候, 我們不但需要機器人, 同時還需要一些場景, 比如機器人面前的一個桌子, 桌子上面放一些物品等, 或者一些稀奇古怪的東西, 放在機器人旁邊, 和機器人一起導入來運行. 就比如下圖所示的樣子.


這裏寫圖片描述

* Baxter *

可以使用另外一種方式來獲取Baxter的描述文件. 打開命令行, 以此輸入:

$ sudo apt-get install ros-indigo-baxter-description
$ cd ~/catkin_ws/src/
$ cp -r /opt/ros/indigo/baxter_description ./
$ rosrun xacro xacro.py --inorder baxter_description/urdf/baxter.urdf.xacro\
> baxter_description/urdf/baxter_new.urdf

如上所述, 一定得注意最後一條指令, 可以參考Github上xacro的一條Issues, 其中一定需要添加--inorder, 參數. 否則生成模型會失敗. 所以我們提前將baxter的xacro文件轉換成urdf格式.

* The YCB Object and Model Set *

http://rll.eecs.berkeley.edu/ycb/上, 可以下載到一些物體的三維模型以及urdf文件. 進入網站之後, 點擊下載ROS packages for setup descriptions of ‘Pitcher-Mug Protocol’ and ‘Table Setting Protocol’ in Gazebo simulation environment. 將下載下來的文件解壓到和前述文件中的同級目錄中. 其中有一些launch文件, 可以運行起來, 看一看效果. 挺好玩的.

* 排列 *

所有東西都準備好之後, 將下述內容拷貝到一個新的xacro文件中. 和之前一樣, 運行並顯示. 可以得到前述圖像中的樣子. 和之前的類似, viz打開之後, 需要將Fixed Frame設定成world, 模型才能正常顯示.

<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="baxter_and_world" >

  <link name="world"/>

  <joint name="world_to_baxter" type="fixed">
    <parent link="world"/>
    <child link="base"/>
  </joint>

  <!-- baxter -->
  <xacro:include filename="$(find baxter_description)/urdf/baxter_new.urdf" />

  <!-- table -->
  <xacro:include filename="$(find ycb_object_models)/models/urdf/table.urdf" />

  <joint name="base_table" type="fixed" >
    <parent link="world"/>
    <child link="table_top_link"/>
    <origin xyz="1 0 -0.7" />
  </joint>

</robot>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章