构建机器人


预计完成时间:15 分钟

2.4   连杆与关节

你已经创建了第一个只有单一元素的机器人模型,也就是一个连杆。那么,一个连杆由哪些部分组成呢?

每个连杆都必须包含以下属性:

惯性属性

它包含 质量(kg)原点(m)惯性矩阵(kg·m²)

<inertial>
    <mass value="10" />
    <origin
        xyz="0 0 0.3"
        rpy="0 0 0" />
    <inertia
         ixx="1.5417"
         ixy="0"
         ixz="0"
         iyy="3.467"
         iyz="0"
         izz="4.742" />
</inertial>

碰撞与可视属性

在这个例子中,collisionvisual 看起来是相同的,但它们的用途不同。模拟器使用 collision 来计算连杆之间的物理交互;visual 仅用于渲染显示,不会影响连杆与其他对象的交互方式。

如果你的可视网格非常复杂,但又不希望在物理交互上做不必要的高强度计算,或者想节省算力,就可以让 collisionvisual 使用不同的几何定义。

<collision>
    <geometry>
        <box size="2 1.3 0.4" />
    </geometry>
</collision>

<visual>
    <geometry>
        <box size="2 1.3 0.4" />
    </geometry>
</visual>

关节

关节用于连接各个连杆,并在它们之间建立运动关系。在本单元中,你要构建的是移动机器人,因此接下来要给你创建的底盘加上一只车轮。

继续在 robot.urdf 文件中,在 </link> 结束标签之后添加以下代码:

  复制并粘贴

In [ ]:
<!-- Joint - chassis / left wheel -->
<joint name="joint_chassis_left_wheel" type="continuous">
    <origin rpy="0 0 0" xyz="-0.5 0.65 0" />
    <child link="link_left_wheel" />
    <parent link="link_chassis" />
    <axis rpy="0 0 0" xyz="0 1 0" />
    <limit effort="10000" velocity="1000" />
    <joint_properties damping="1.0" friction="1.0" />
</joint>

<!-- Link - left wheel -->
<link name="link_left_wheel">
    <inertial>
        <mass value="1" />
        <origin xyz="0 0 0" rpy="0 0 0" />
        <inertia ixx="0.002526666666667" ixy="0" ixz="0" iyy="0.002526666666667" iyz="0" izz="0.005"/>
    </inertial>

    <collision>
        <origin rpy="0 0 1.5707" xyz="0 0.18 0" />
        <geometry>
            <cylinder length="0.12" radius="0.4"/>
        </geometry>
    </collision>
    <visual>
        <origin rpy="0 0 1.5707" xyz="0 0.18 0" />
        <geometry>
            <cylinder length="0.12" radius="0.4"/>
        </geometry>
    </visual>

    <collision>
        <origin rpy="0 0 1.5707" xyz="0 0.06 0" />
        <geometry>
            <cylinder length="0.12" radius="0.08"/>
        </geometry>
    </collision>
    <visual>
        <origin rpy="0 0 1.5707" xyz="0 0.06 0" />
        <geometry>
            <cylinder length="0.12" radius="0.08"/>
        </geometry>
    </visual>
</link>

这里你有两组 collisionvisual 标签,它们各自对应不同的部分。一个连杆中可以包含多组这样的标签,数量并不受限。它们都会按照关节的位置关系显示出来。

在这个例子里,你分别为车轮本体和它的轮轴创建了一组可视与碰撞定义。

重新启动 rviz.launch.py 文件。

  在 Web Shell 1 中执行

In [ ]:
cd /workspace; colcon build --packages-select robot_description; source install/setup.bash
In [ ]:
ros2 launch robot_description rviz.launch.py

你应该得到如下结果:

"RViz URDF Links Launch"

但是等等……车轮去哪了?这里发生了什么?

这是因为你当前只运行了 Robot State Publisher 和 RViz。这个节点只会发布机器人固定关节的状态(这里是底盘),不会发布可动关节的状态(例如车轮)。如果想把这些可动关节显示出来,你还需要一个能够提供关节状态的节点,这就是 Joint State Publisher GUI 的作用。

要启动 Joint State Publisher GUI,请在一个新的 web shell 中运行以下命令:

提示: 如果系统提示找不到 joint_state_publisher_gui,请先执行:

sudo apt install ros-humble-joint-state-publisher-gui

  在 Web Shell 2 中执行

In [ ]:
ros2 run joint_state_publisher_gui joint_state_publisher_gui

现在你会看到类似下面的界面:

"RViz URDF Links Launch"

注意,现在你已经可以通过滑块来控制车轮旋转了。

当然,这还不是车轮期望的安装位置或旋转方式。那么问题出在哪里呢?

关节定义

来看一下关节定义:

<joint name="joint_chassis_left_wheel" type="continuous">
    <origin rpy="0 0 0" xyz="-0.5 0.88 0" />
    <child link="link_left_wheel" />
    <parent link="link_chassis" />
    <axis rpy="0 0 0" xyz="0 1 0" />
    <limit effort="10000" velocity="1000" />
    <joint_properties damping="1.0" friction="1.0" />
</joint>

第一个属性 type 用来定义该连杆能够进行哪一种运动。常见类型包括 continuousrevoluteprismaticfixed。除此之外还有其他类型,你可以在这里查看完整参考:http://wiki.ros.org/urdf/XML/joint

origin 属性用于定义关节相对于底盘的位置。底盘连杆起始于 0 0 0,长度为 2 米,宽度为 1.3 米。底盘会向两侧延伸,因此它的侧边界位于 1.3/2,也就是 0.65 米 的位置。

接着,需要定义 childparent 连杆。再比如 axis,它用来指定转动轴。你还可以通过 limit 设置最大力矩和速度,不过现在这部分并不是重点。当前阶段你主要是在设计机器人的几何结构,而与运动动力学相关的 joint properties 会在后续再讨论。

最后来看 axis 定义。这里决定该连杆绕哪一个坐标轴旋转。在这个例子中,你希望它绕 Y 轴旋转,这个设置是正确的。

问题在于,你的这个 link 圆柱几何体(长度和半径)是按照 Z 轴方向定义的,因此需要绕 X 轴旋转一下才能修正。

回到左轮的连杆定义,把 collisionvisual 标签中的 origin 属性改成绕 X 轴旋转 90 度:

<link name="link_left_wheel">
    ...
    <collision>
        <origin rpy="1.5707 0 0" xyz="0 0.18 0" />
        <geometry>
            <cylinder length="0.12" radius="0.4"/>
        </geometry>
    </collision>
    <visual>
        <origin rpy="1.5707 0 0" xyz="0 0.18 0" />
        <geometry>
            <cylinder length="0.12" radius="0.4"/>
        </geometry>
    </visual>

    <collision>
        <origin rpy="1.5707 0 0" xyz="0 0.06 0" />
        <geometry>
            <cylinder length="0.12" radius="0.08"/>
        </geometry>
    </collision>
    <visual>
        <origin rpy="1.5707 0 0" xyz="0 0.06 0" />
        <geometry>
            <cylinder length="0.12" radius="0.08"/>
        </geometry>
    </visual>
    ...

重新启动 rviz.launch,并同时运行 Joint State Publisher GUI

  在 Web Shell 1 中执行

In [ ]:
cd /workspace; colcon build --packages-select robot_description; source install/setup.bash
In [ ]:
ros2 launch robot_description rviz.launch.py

  在 Web Shell 2 中执行

In [ ]:
ros2 run joint_state_publisher_gui joint_state_publisher_gui

"RViz URDF Links Joints Launch"

查看下图中的机器人尺寸,你会更容易理解为什么 XML 定义里使用的是这些数值:

"Robot Dimensions"

- 练习 2.2.1 -

完善当前模型并把它补全!

在这个练习中,再补充以下几个部分,让机器人更完整:

  • 添加右侧车轮
  • 给两个车轮都添加新的 visual 元素,让旋转效果更明显(例如轮毂盖)
  • 在机器人前方添加一个通过 fixed 关节连接的脚轮
  • 修改并补充底盘和车轮的材质颜色,让它看起来尽量接近下图

"RViz URDF Ex22 Launch"

请参考下图来创建脚轮的固定关节以及可视部件。

"Robot Dimensions Extended"

注意: 当前 ROS2 RVIZ2 中存在一个 Bug:URDF 中父连杆的颜色会传递到子连杆上,因此 RVIZ 中显示的颜色可能与 URDF 文件中的定义并不完全一致。更多信息请参考 RVIZ2 的颜色 Bug

- 练习 2.2.1 结束 -
- 练习 2.2.1 参考答案 -

在你自己尝试完成练习之前,不要先看答案。完成之后再回头对照参考答案,会更有助于比较和检查自己的实现。

如果你在完成练习时遇到问题,可以到论坛寻求支持。

robot.urdf

- 练习 2.2.1 参考答案结束 -

参考资料

你可以在下面查看连杆和关节的完整规范(链接指向 ROS1 文档):

在使用 XML 为 ROS2 定义机器人模型时,这些说明依然适用。