Learning URDF Step by Step

1 从一无所有创建一个可视化的使用URDF的机器人模型
学习如何创建一个能够在rviz中看到的机器人模型。在这部分教程中,我们将创建一个乍一看很像R2D2的机器人模型。在后面的教程中,你会学到如何用关节连接模型,添加一些物理属性,用xacro生成更加整洁的代码,并使之能够在gazebo中移动。但是到目前为止,我们将集中在正确的得等到一个几何可视化模型上。
在这些教程中,我们将以来一些来自urdf_tools包中的工具和launch文件。尤其是,joint_state_publisher需要从华盛顿大学的源下载,连接到joint_state_publisher维基页面上。这些教程中提到的所有的机器人模型都能够在urdf_tutorial包中找到。
1.1一个形状
首先,我们来探索一个简单的形状。


<robot name="myfirst">
  <link name="base_link">
    <visual>
      <geometry>
        <cylinder length="0.6" radius="0.2"/>
      geometry>
    visual>
  link>
robot>

把这些xml语言翻译过来就是,这是一个名为myfirst的机器人,包括一个link,可视化部件仅仅是一个圆柱体,0.6米长,半径是0.2米。
可以检查一下这个模型:

roslaunch urdf_tutorial display.launch model:=urdf/01-myfirst.urdf

这里完成了三件事情:
 加载特定的模型到参数服务器
 运行节点来发布关节状态和转换
 运行rviz及其配置文件
这个launch文件假设01-myfirst.urdf在你所运行命令的文件夹的urdf子文件夹中,否则,你可以用:model:=’$(find pkg-name)/urdf/01-myfirst.urdf’。这里pkg-name是这个文件所在包的名称。这里所有的例程都在urdf_tutorial包中。
我们可以看到下面的画面:
Learning URDF Step by Step_第1张图片
需要注意的是:
 固定坐标系是网格中心所在的转换坐标系,这里,它是你定义的base_link坐标
 可视元素有自己的原点,在几何形状的形心位置。所以,圆柱的一半在网格的下面。
1.2 多个形状
现在让我们来看看如何添加多个形状。如果我们仅仅添加更多的link元素到urdf中的话,解析器不知道该如何放置它们,所以,我们必须添加关节。关节元素可以是柔性关节,也可以是刚性关节。我们将从刚性关节或固定关节开始。


<robot name="multipleshapes">
  <link name="base_link">
    <visual>
      <geometry>
        <cylinder length="0.6" radius="0.2"/>
      geometry>
    visual>
  link>

  <link name="right_leg">
    <visual>
      <geometry>
        <box size="0.6 .2 .1"/>
      geometry>
    visual>
  link>

  <joint name="base_to_right_leg" type="fixed">
    <parent link="base_link"/>
    <child link="right_leg"/>
  joint>

robot>

注意我们如何定义一个0.6m×0.2m×0.1m的盒子
关节定义要依据父子关系。URDF最终是一个树结构,有一个root link。这就意味着腿的位置依赖于base_link的位置。

roslaunch urdf_tutorial display.launch model:=urdf/02-multipleshape.urdf

Learning URDF Step by Step_第2张图片

所有形状相互重叠,因为他们有相同的原点,如果我们不想让他们重叠的话,我们必须定义更多的原点。
1.3 原点
R2D2的腿连接到它半边躯干的顶部。所以,我们要确定关节的原点。同时,它不连接到腿的中间位置,而是连接到上面的部分。我们也就必须确定腿的原点的偏移量。同时我们需要旋转腿让他直立起来。


<robot name="origins">
  <link name="base_link">
    <visual>
      <geometry>
        <cylinder length="0.6" radius="0.2"/>
      geometry>
    visual>
  link>

  <link name="right_leg">
    <visual>
      <geometry>
        <box size="0.6 .2 .1"/>
      geometry>
      <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
    visual>
  link>

  <joint name="base_to_right_leg" type="fixed">
    <parent link="base_link"/>
    <child link="right_leg"/>
    <origin xyz="0.22 0 .25"/>
  joint>

robot>

让我们开始检查关节的原点。它根据父节点的参考系来定义。所以我们有在X方向上(左)0.22米和Z方向(上)0.25米。这就是说忽略掉子连接的可视化原点标签,子连接将会是在左上。因为我们不确定一个rpy(横滚、俯仰、偏转)属性,子参考系将会默认有一个与父参考系相同的方向。
现在看一下腿的可视原点,它由xyz和rpy偏移量。这定义了可视元素的中心会在哪个位置,与它的原点相关。因为我们想要腿连接到顶部,我们通过设置Z偏移量为-0.3米来将原点向下移动。因为我们想要腿与Z轴平行,我们需要绕Y轴旋转PI/2.

roslaunch urdf_tutorial display.launch model:=urdf/03-origins.urdf

Learning URDF Step by Step_第3张图片
这个launch文件运行的包将会为基于你的URDF模型的每一个link创建TF坐标系。Rviz用这个信息指出在什么位置显示每一个形状。
如果一个给定的URDF link的TF坐标系不存在,它将会被放置在白色的原点。
1.4 材料
“Aright”,我听见你说,“这很有趣,但是不是每个人都有一个B21。我的机器人和R2D2不是红色的!”说得很好,让我们来看一下材料标签。


<robot name="materials">
  <link name="base_link">
    <visual>
      <geometry>
        <cylinder length="0.6" radius="0.2"/>
      geometry>
      <material name="blue">
        <color rgba="0 0 .8 1"/>
      material>
    visual>
  link>

  <link name="right_leg">
    <visual>
      <geometry>
        <box size="0.6 .2 .1"/>
      geometry>
      <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
      <material name="white">
        <color rgba="1 1 1 1"/>
      material>
    visual>
  link>

  <joint name="base_to_right_leg" type="fixed">
    <parent link="base_link"/>
    <child link="right_leg"/>
    <origin xyz="0.22 0 .25"/>
  joint>

  <link name="left_leg">
    <visual>
      <geometry>
        <box size="0.6 .2 .1"/>
      geometry>
      <origin rpy="0 1.57075 0" xyz="0 0 -0.3"/>
      <material name="white"/>
    visual>
  link>

  <joint name="base_to_left_leg" type="fixed">
    <parent link="base_link"/>
    <child link="left_leg"/>
    <origin xyz="-0.22 0 .25"/>
  joint>

robot>

机器人身体现在是蓝色的。通过添加材料标签,我们用定义一个新的称之为蓝色的材料,将RGBA分别定义为0,0,0.8,1。取值范围都在[0,1]
白色材料定义很简单。
对于第二条腿,我们只需要通过材料名称来指定就可以了。因为我们之前已经定义过了。
你也可以使用纹理来定义一个图像文件作为颜色的对象。

roslaunch urdf_tutorial display.launch nodel:urdf/04-materials.urdf

Learning URDF Step by Step_第4张图片

1.5 完成这个模型
现在我们 用更多的形状来完成这个模型。最明显的,我们要添加一个球和一些网格,我们也需要添加一些我们后面要用到的碎片。(整个源文件的链接https://github.com/ros/urdf_tutorial/blob/master/urdf/05-visual.urdf)
Learning URDF Step by Step_第5张图片
添加球体

  <link name="head">
    <visual>
      <geometry>
        <sphere radius="0.2"/>
      geometry>
      <material name="white"/>
    visual>
  link>

网格是从pr2借用的,意味着你需要pr2_description包且其可见。

  <link name="left_gripper">
    <visual>
      <geometry>
        <mesh filename="package://pr2_description/meshes/gripper_v0/l_finger.dae"/>
      geometry>
    visual>
  link>

网格可以从一些不同的格式来导入。STL是一种通用的格式,但是这个引擎也支持DAE格式,它有自己的颜色数据,意味着你不需要来确定颜色。
网格也可以通过相关的缩放参数或者边界尺寸来定义大小尺寸。
2 使用URDF创建一个可动的机器人模型
在这部分教程中我们将修正我们在上一部分教程中建立的R2D2模型,使它有一个可动的关节。在之前的模型中,所有的关节都是固定的。现在我们来探索关节非常重要的三种类型:continuous, revolute和prismatic。
这部分教程依赖于一些来自urdf_tools包中的工具和launch文件。最为明显的,joint_state_publisher需要从华盛顿大学的源下载,链接到joint_state_publisher的维基页面。
https://github.com/ros/urdf_tutorial/blob/master/urdf/06-flexible.urdf这是新的具有灵活关节的urdf。你可以与之前的版本作比较来看看每一个改动过的地方,这里我们只集中精力看三个例子关节。
为了可视化控制这个模型,运行roslaunch urdf_tutorial display.launch model:=urdf/06-flexible.urdf gui:=True.这时也会跳出一个GUI界面,允许你来控制非固定部分的关节运动。可以先玩一玩体验一下,然后我们来看看怎么来完成这个效果。
Learning URDF Step by Step_第6张图片
2.1 头

  <joint name="head_swivel" type="continuous">
    <parent link="base_link"/>
    <child link="head"/>
    <axis xyz="0 0 1"/>
    <origin xyz="0 0 0.3"/>
  joint>

身体和头之间的连接是一个连续关节,就是说它可以到从负无穷到正无穷的每一个角度。轮子也是这样的一个模型,所以它也可以在两个方向想永远旋转。
我们需要添加的额外信息是旋转轴,这里要通过xyz三元组来确定,这里确定一个头可以绕之转动的向量。因为我们想要绕z轴转动,所以给定的向量是:”0,0,1“
2.2 夹子

  <joint name="left_gripper_joint" type="revolute">
    <axis xyz="0 0 1"/>
    <limit effort="1000.0" lower="0.0" upper="0.548" velocity="0.5"/>
    <origin rpy="0 0 0" xyz="0.2 0.01 0"/>
    <parent link="gripper_pole"/>
    <child link="left_gripper"/>
  joint>

左右夹子的关机都被定义为一个旋转关节。就是说它们可以像连续型关节一样旋转,但是它们有严格的限制。因此,我们必须包含limit标签来定义上限和下限(弧度)我们也必须确定这个关机的最大速度和力。
2.3 夹臂

  <joint name="gripper_extension" type="prismatic">
    <parent link="base_link"/>
    <child link="gripper_pole"/>
    <limit effort="1000.0" lower="-0.38" upper="0" velocity="0.5"/>
    <origin rpy="0 0 1.57075" xyz="0 0.19 .2"/>
  joint>

这个夹臂是一个不太一样的关节,称之为棱状关节。这就是说它沿着一个轴运动,而不是绕着它运动。这样的变换运动允许我们的机器人模型伸展和收缩它的手臂。
棱状手臂的限制用与旋转手臂同样的方法来定义,只不过它的计量单位是米而不是弧度。
2.4 其他类型的关节
在空间运动的关节还有两种类型,像棱状关节一样,还有平面关节,它可以在一个平面内运动。更多地,浮动关节式不受约束的。可以在三维空间中任意运动。这些关节不能只被一个数字定义,所以在这个教程中就不在讲述了。
2.5 定义姿态
在你移动GUI的滑块的时候,模型在Rviz中运动,这是怎么做到的呢,首先GUI解析了URDF,找到所有非固定关节和他们的限制。然后,它用滑块的值发布sensor_msgs/JointState消息。那些后来用robot_state_publisher计算不同部件之间的转换。转换树的结果用来显示所有的形状。
3 添加Physical和Collision属性到一个URDF模型中
3.1 Collision
到目前为止,我们仅仅用单个的子元素确定了我们的links,visual定义了机器人看起来的样子。然而,为了使碰撞探测能够工作来像Gazebo一样模拟机器人,我们需要定义碰撞元素。
https://raw.githubusercontent.com/ros/urdf_tutorial/master/urdf/07-physics.urdf这里是带有碰撞元素和物理属性的模型文件。
下面是我们新的base_link的代码

<link name="base_link">
    <visual>
      <geometry>
        <cylinder length="0.6" radius="0.2"/>
      geometry>
      <material name="blue">
        <color rgba="0 0 .8 1"/>
      material>
    visual>
    <collision>
      <geometry>
        <cylinder length="0.6" radius="0.2"/>
      geometry>
    collision>
  link>

 碰撞元素是link对象的一个子元素,与visual标签处于同样的地位。
 碰撞元素定义的方式和形状定义时一样的,用一个geometry标签。geometry标签的格式和visual中的是一样的。
 你也可以定义一个圆点作为碰撞标签的子元素。
在很多情况下,你想要碰撞geometry和origin跟visual中的geometry和origin是完全一样的,然而,有两种情况是你不想看到的。
更快的执行——为两个网格做碰撞检测要比为简单的几何形状做碰撞检测做更复杂的运算,所以,你在碰撞检测中向用简单的几何形状来取代网格。
安全区域——你有时候想要靠近敏感设备做严格的运动,比如,我们不想要r2d2的头做任何的碰撞,我们或许定义碰撞形状为一个圆柱来包住它的头,从而不让任何东西靠近。
3.2物理属性
为了能够使得模型正确的仿真,你需要为你的机器人定义一些物理属性。比如像Gazebo中的物理引擎。
3.2.1 惯性
每一个连接元素都需要一个惯性标签,下面是一个简单的例子。

  <link name="base_link">
    <visual>
      <geometry>
        <cylinder length="0.6" radius="0.2"/>
      geometry>
      <material name="blue">
        <color rgba="0 0 .8 1"/>
      material>
    visual>
    <collision>
      <geometry>
        <cylinder length="0.6" radius="0.2"/>
      geometry>
    collision>
    <inertial>
      <mass value="10"/>
      <inertia ixx="0.4" ixy="0.0" ixz="0.0" iyy="0.4" iyz="0.0" izz="0.2"/>
    inertial>
  link>

 这个元素也是link对象的一个子元素
 质量的定义单位是千克
 这个3×3的转动惯量矩阵由惯性元素定义。因为这时对称的,它可以只用6个元素来表示
ixx ixy ixz
ixy iyy iyz
ixz iyz izz
 这个信息可以由像MeshLab这样的模型程序来提供给你。原始几何体的转动惯量是可以计算的(比如圆柱、长方体、球体)
 惯性张量取决于质量和对象质量的分布,一个好的第一近似值是假设等于质量再体积中的分布,计算惯性张量基于对象的形状。
 如果不确定该怎么定,矩阵ixx/iyy/izz=1e-3或者更小的值通常被用于一个中等尺寸默认值(它适合一个0.1米边长的盒子质量是0.6kg)。尽管通常被选用,这个定义矩阵是一个相当糟糕的值,因为通常情况下它太高了。
 你也可以定义一个origin标签来确定重心和惯性参考系。
 当使用实时控制器时,惯性元素设为0可能造成机器人模型在无警告的情况下崩溃,所有link的原点都会变得与世界坐标系的原点重合。
3.2.2 接触系数
当各个连接相互接触时,你也可以定义他们的行为。这可以用collision标签的子元素contact_coefficients来定义,有下面三个属性需要指定:
 mu——摩擦系数
 kp——刚度系数
 kd——阻尼系数
3.2.3 关节动力学
关节如何运动由关节的dynamics标签定义。有两个属性需要指定
friction——物理静摩擦力。对于棱状关节来说,它的单位是牛顿,对于旋转关节来说,它的单位是牛米。
damping——物理阻尼值。对于棱状关节来说,单位是牛/米,对于旋转关节来说,单位是N▪m/rad
如果不定义,这些系数默认取值为0.
3.3 其他标签
在单纯的URDF领域内,还有两个保留标签来定义关节:calibration和safety controller
4 使用Xacro来清理URDF文件。
到现在为止,如果你按照所有这些步骤设计你的机器人,你或许会纠结于各种各样的数学计算来做非常简单的机器人描述和正确解析。幸运的是,你可以用xacro包来是你的生活更加简单,它做了以下三件非常有用的事情。
 Constants 常数
 Simple Math 简单数学
 Macros 宏计算
在这个教程中,我们来看看这些捷径是如何减少URDF文件的大小和使它仍然易读的。
4.1 使用Xacro
就像它的名字所指的那样,xacro是一种宏语言。xacro语言运行所有的宏命令并输出其结果。典型应用就像下面这样:
rosrun xacro xacro.py model.xacro > model.urdf
你也可以在一个launch文件中自动生成urdf。这是很方便的,因为它可以保持更新而不使用硬件驱动空间。然而,它需要花费时间来生成。所以要注意你的launch文件可能需要更长的启动时间(以pr2_description为例)。

<param name="robot_description" 
  command="$(find xacro)/xacro.py '$(find pr2_description)/robots/pr2.urdf.xacro'" />

在URDF文件的顶部,你必须指定一个命名空间,来让文件正确解析。比如,这些就是一个可用的xacro文件的最开始两行:


<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="firefighter">

4.2 常量
我们来快速看一眼R2D2中的base_link

 <link name="base_link">
    <visual>
      <geometry>
        <cylinder length="0.6" radius="0.2"/>
      geometry>
      <material name="blue">
        <color rgba="0 0 .8 1"/>
      material>
    visual>
    <collision>
      <geometry>
        <cylinder length="0.6" radius="0.2"/>
      geometry>
    collision>
  link>

这里的信息有一点冗余,我们制定了圆柱的半径两次。更糟糕的是,如果我们想要改变它,我们需要更改两个地方。
幸运的是,xacro允许你指定作为常数的属性。上面的代码,我们可以写成这样:

<xacro:property name="width" value=".2" />
<xacro:property name="bodylen" value=".6" />
<link name="base_link">
    <visual>
        <geometry>
            <cylinder radius="${width}" length="${bodylen}"/>
        geometry>
        <material name="blue">
            <color rgba="0 0 .8 1"/>
        material>
    visual>
    <collision>
        <geometry>
            <cylinder radius="${width}" length="${bodylen}"/>
        geometry>
    collision>
link>

 这两个值在刚开始的两行中指定了。他们其实可以在任何地方指定,我们一般放在首行的位置。
 跟指定实际半径值不一样,我们用一个美元符号和花括号修饰了这两个量
 这段代码跟上面的代码实际上是一样的。
${}结构里面的内容的值通常被用来替代这个结构,意味着你可以把它与文本结合起来使用

<xacro:property name=”robotname” value=”marvin” />
<link name=”${robotname}s_leg” />

就会生成

<link name=”marvins_leg” />

4.3 数学
你可以在${}中通过使用操作符(+,-,*,/)反复构建复杂的表达式,一元减法和括号。不支持幂运算和取模运算。例如:

"${wheeldiam/2}" length=".1"/>
"${reflect*(width+.02)} 0 .25" />

所有的运算用的都是float类型,因此

<link name="${5/6}"/>

求值结果为:

<link name="0.833333333333"/>

4.4 宏
这对于xacro包来说是最大最有用的部件。
4.4.1 简单宏
让我们来看一下简单的没有用的宏

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

(这样做是没有用的,因为如果原点没有指定,其默认值跟这里指定的是一样的),这个代码将生成:

<origin rpy="0 0 0" xyz="0 0 0"/>

 技术上讲这不是一个必备的元素,但是你需要指定它来使用它
 每一个

    <xacro:macro name="default_inertial" params="mass">
        <inertial>
                <mass value="${mass}" />
                <inertia ixx="1.0" ixy="0.0" ixz="0.0"
                     iyy="1.0" iyz="0.0"
                     izz="1.0" />
        inertial>
xacro:macro>

可以像下面这样使用:

<xacro:default_inertial mass="10"/>

参数就像是一个属性,你可以在表达式中使用它们
你也可以将整个块作为参数:

<xacro:macro name="blue_shape" params="name *shape">
    <link name="${name}">
        <visual>
            <geometry>
                <xacro:insert_block name="shape" />
            geometry>
            <material name="blue">
                <color rgba="0 0 .8 1"/>
            material>
        visual>
        <collision>
            <geometry>
                <xacro:insert_block name="shape" />
            geometry>
        collision>
    link>
xacro:macro>

<xacro:blue_shape name="base_link">
    <cylinder radius=".42" length=".01" />
xacro:blue_shape>

 要指定一个块参数,要在它的参数名称之前加一个*
 一个块可以用insert_block命令来插入
 插入块可以插入多次
4.5 实际应用
宏语言允许你做的事情更加的灵活。在R2D2模型中有一些非常有用的方法来使用xacro。
来看看宏文件生成的模型,运行下面的命令:

roslaunch urdf_tutorial xacrodisplay.launch model:=urdf/08-macroed.urdf.xacro

4.5.1 Leg macro
通常你会想在不同的位置上生成很多相似的对象。通常都会是一些对称的位置。你可以使用一个宏和一些简单的数学来减少你要写的代码量,就像我们在R2的腿中做的那样

<xacro:macro name="leg" params="prefix reflect">
    <link name="${prefix}_leg">
        <visual>
            <geometry>
                <box size="${leglen} .2 .1"/>
            geometry>
            <origin xyz="0 0 -${leglen/2}" rpy="0 ${pi/2} 0"/>
            <material name="white">
                <color rgba="1 1 1 1"/>
            material>
        visual>
        <collision>
            <geometry>
                <box size="${leglen} .2 .1"/>
            geometry>
            <origin xyz="0 0 -${leglen/2}" rpy="0 ${pi/2} 0"/>
        collision>
        <xacro:default_inertial mass="10"/>
    link>

    <joint name="base_to_${prefix}_leg" type="fixed">
        <parent link="base_link"/>
        <child link="${prefix}_leg"/>
        <origin xyz="${reflect*(width+.02)} 0 .25" />
    joint>
    
xacro:macro>
<xacro:leg prefix="right" reflect="1" />
<xacro:leg prefix="left" reflect="-1" />

命令窍门1:使用一个名称前缀来得等到两个相似的对象名称
命令窍门2:使用数学计算关节原点,以防你改变你的机器人尺寸,用一些数学计算改变一个属性来计算关节偏移量会减少很多麻烦
命令窍门3:使用一个反射参数,设置其为1或者-1。看看我们如何使用反射参数来把腿放在处在base_to_${prefix}_leg原点的身体的两侧

你可能感兴趣的:(ROS学习日志)