4. 关节与执行器

各位同学,欢迎来到第四章。前几章我们把四足机器人的躯干和腿的几何模型搭好了,但你会发现——它现在还是一堆「死」的几何体,动不了。

想让机器人动起来,核心就两个东西:关节(Joint)和执行器(Actuator)。关节决定了运动自由度,执行器提供动力。今天我们就来彻底搞懂它们。

4.1 关节(Joint)的本质

在 MuJoCo 里,关节就是连接两个 body 的「运动副」。它定义了子 body 相对于父 body 的运动方式。说白了,没有关节,所有 body 都是焊死的。

MuJoCo 支持三种基础关节类型,我整理了一张表,方便你对比:

关节类型 自由度 运动方式 典型用途
hinge 1 绕固定轴旋转 四足机器人髋关节、膝关节
slide 1 沿固定轴平移 直线导轨、活塞
free 6 空间自由运动(3平移+3旋转) 机器人躯干与世界的连接

关键点:四足机器人的躯干必须使用 free 关节与世界连接,否则它会被钉死在原地,无法移动和旋转。

我个人习惯把 free 关节想象成「把机器人扔进虚拟世界」的那个关节。没有它,你的机器人就像被胶水粘在桌上,四条腿再怎么动也跑不起来。

4.2 关节的 XML 语法

关节定义在 <body> 内部,通过 <joint> 元素声明。来看一个最简单的例子:

<body name="torso">
    <joint name="root" type="free"/>
    <geom type="box" size="0.3 0.15 0.1" rgba="0.8 0.2 0.2 1"/>
</body>

这里我给躯干加了一个 free 关节,命名为 root。这样躯干就能在仿真世界里自由移动了。

但今天我们的重点是旋转关节。假设我想在躯干上额外加一个旋转部件,比如一个雷达或者机械臂基座,那就需要 hinge 关节:

<body name="torso">
    <joint name="root" type="free"/>
    <geom type="box" size="0.3 0.15 0.1" rgba="0.8 0.2 0.2 1"/>

    <body name="rotator" pos="0 0 0.15">
        <joint name="turntable" type="hinge" axis="0 0 1"/>
        <geom type="cylinder" size="0.1 0.05" rgba="0.2 0.6 0.8 1"/>
    </body>
</body>

注意看 axis="0 0 1",这表示旋转轴是 Z 轴(朝上)。如果你想让关节绕 X 轴或 Y 轴转,改成 1 0 0 或 0 1 0 就行。

小技巧:定义 hinge 关节时,axis 向量会被自动归一化,所以你不需要担心长度问题。但方向一定要写对,否则关节会朝奇怪的方向转。

4.3 执行器(Actuator)——给关节注入灵魂

关节定义了「能怎么动」,执行器定义了「用什么力动」。MuJoCo 支持多种执行器类型,最常用的是 motor(电机)和 position(位置伺服)。

执行器定义在 <worldbody> 之外,通常在 <actuator> 块里:

<actuator>
    <motor name="turntable_motor" joint="turntable" ctrlrange="-1 1" ctrllimited="true"/>
</actuator>

这里我绑定了 turntable 关节,给它一个电机执行器。ctrlrange="-1 1" 表示控制输入范围是 -1 到 1,对应电机的最大反向和正向扭矩。

我曾经在项目里犯过一个低级错误:给关节绑定了执行器,但忘了设置 ctrllimited="true"。结果仿真一跑,电机直接输出无穷大的扭矩,机器人瞬间飞到了天上去……嗯,从那以后我再也不敢漏掉这个参数了。

4.4 完整示例:带旋转关节的躯干

把上面的代码拼起来,就是一个完整的、带旋转关节的躯干模型:

<mujoco model="torso_with_rotator">
    <compiler angle="radian"/>

    <worldbody>
        <body name="torso">
            <joint name="root" type="free"/>
            <geom type="box" size="0.3 0.15 0.1" rgba="0.8 0.2 0.2 1"/>

            <body name="rotator" pos="0 0 0.15">
                <joint name="turntable" type="hinge" axis="0 0 1"/>
                <geom type="cylinder" size="0.1 0.05" rgba="0.2 0.6 0.8 1"/>
            </body>
        </body>
    </worldbody>

    <actuator>
        <motor name="turntable_motor" joint="turntable" ctrlrange="-1 1" ctrllimited="true"/>
    </actuator>
</mujoco>

把这个文件保存为 torso_with_joint.xml,用 MuJoCo 的 simulate 工具打开。你会看到躯干自由悬浮在空中,上面有一个蓝色圆柱。在仿真窗口里找到控制面板,把 turntable_motor 的滑块拖到 0.5,圆柱就会开始旋转。

注意:如果你看不到控制滑块,检查一下 ctrlrange 是否设置正确,以及执行器的 joint 名称是否与关节名称完全匹配。MuJoCo 对名称大小写敏感。

4.5 关节参数进阶

除了基本的 type 和 axis,关节还有一些常用参数,我列出来供你参考:

参数 作用 示例
pos 关节在父 body 中的位置 pos="0 0 0.1"
axis 旋转轴或平移方向 axis="0 1 0"
range 关节运动范围(弧度或米) range="-1.57 1.57"
limited 是否启用范围限制 limited="true"
damping 关节阻尼系数 damping="0.1"
stiffness 关节刚度(用于弹簧关节) stiffness="10"

你想想看,如果给四足机器人的膝关节加上 range="-2.0 0.0" 和 limited="true",就能防止腿向后弯折成反关节。这在真实机器人上可是致命的机械损伤。

4.6 知识结构图

下面这张 SVG 图梳理了本章的核心概念和它们之间的关系:

关节与执行器知识结构图 关节与执行器核心概念 关节类型 hinge(旋转) slide(平移) free(自由) 执行器类型 motor(电机) position(位置) velocity(速度) 绑定 关键参数 axis / range / limited ctrlrange / ctrllimited damping / stiffness pos(关节位置) 核心:关节定义运动能力,执行器提供驱动力,参数控制行为边界

4.7 避坑指南

最后,分享几个我踩过的坑,希望能帮你省点时间:

  • 关节名称冲突:同一个模型里,关节名称不能重复。我习惯用 body名称_joint 的命名方式,比如 hip_left_joint,这样一目了然。
  • 执行器绑定错误:执行器的 joint 属性必须与关节的 name 完全一致。少写一个字母,MuJoCo 就会报错。
  • 忘记设置 limited:如果不设 limited="true",range 参数会被忽略,关节可以无限旋转。这在仿真里可能不会报错,但会让你的机器人做出各种反物理动作。
  • 轴方向搞反:定义 hinge 关节时,axis 的正方向决定了旋转的正方向。如果你发现关节朝反方向转,把 axis 取反就行。