ROS:机器人描述--URDF和XACRO

1 URDF 文件

1.1 link和joint

图中机器人的描述方式

复制代码

<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的位置关系和具体形状。

1.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的空间位置以及姿态已经被我们所指定了.

1.3 形状

复制代码

<?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>

复制代码

1.4 Collision和joint limit

当然, 每个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>

复制代码

1.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可以看到话题数据

2 XACRO文件

前面也提到了, XACRO文件和URDF实质上是等价的. XACRO格式提供了一些更高级的方式来组织编辑机器人描述. 主要提供了三种方式来使得整个描述文件变得简单. 借用在教程中一句话来形容xacro的优势: “Fortunately, you can use the xacro package to make your life simpler”.

2.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)} 

2.2 Macros

这个才是xacro文件中最重要的部分. 就像宏函数一样, 完成一些最小模块的定义, 方便重用, 以及可以使用参数来标识不同的部分.

2.2.1 Simple Macro

Usage

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

前面三行对宏进行定义, 第四行是使用.

2.2.2 Paramiterized 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是如何进行描述的

2.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机器人

2.3 可视化

urdf_tutorial包也是可以查看xacro文件的. 使用

roslaunch urdf_tutorial xacrodisplay.launch model:=path/to/your/xxx.urdf.xacro.

3 关于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="(findxacro)/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 话题

猜你喜欢

转载自blog.csdn.net/qq_25241325/article/details/88392068