《MuJoCo不简明教程》Chapter1 概述(二)
本文使用 Zhihu On VSCode 创作并发布
本文介绍MuJoCo的相关模块和入门内容。
1.1 Mujoco环境建模
MuJoCo模型可以为XML形式的MJCF或者URDF文件,通过物理引擎编译成以下的数据结构(文件类型):
将模型分成high/low level的原因是:
- 高层模型用于用户定义模型的便利,mjCModel数据结构基本上跟MJCF里面的定义一一对应,用户也可以直接编程来构建mjCModel。
- mjCModel进一步编译成mjModel底层模型,底层模型直接用于计算和保存,不能被反编译恢复。
例1
下图是一个MJCF格式文件的简单实例。定义了一个固接在惯性坐标系中的平面、光照阴影和一个六自由度悬浮的方块。
<mujoco>
<worldbody>
<light diffuse=".5 .5 .5" pos="0 0 3" dir="0 0 -1"/>
<geom type="plane" size="1 1 0.1" rgba=".9 0 0 1"/>
<body pos="0 0 1">
<joint type="free"/>
<geom type="box" size=".1 .2 .3" rgba="0 .9 0 1"/>
</body>
</worldbody>
</mujoco>
可视化的结果:
用如下代码可以实现前向动力学仿真:
#include "mujoco.h"
#include "stdio.h"
char error[1000];
mjModel* m;
mjData* d;
int main(void)
{
// activate MuJoCo
mj_activate("mjkey.txt");
// load model from file and check for errors
m = mj_loadXML("hello.xml", NULL, error, 1000);
if( !m )
{
printf("%s\n", error);
return 1;
}
// make data corresponding to model
d = mj_makeData(m);
// run simulation for 10 seconds
while( d->time<10 )
mj_step(m, d);
// free model and data, deactivate
mj_deleteData(d);
mj_deleteModel(m);
mj_deactivate();
return 0;
}
事实上OpenAI的mujoco_py即是对c语言数据结构的python封装。上段代码只是被动物理现象的仿真。在机器人控制任务中,我们还需要输入驱动器控制量,来实现跟环境的交互。
1.2 更复杂的MJCF格式模型定义
下面展示了更加复杂的物理模型:
<mujoco model="example">
<compiler coordinate="global"/>
<default>
<geom rgba=".8 .6 .4 1"/>
</default>
<asset>
<texture type="skybox" builtin="gradient" rgb1="1 1 1" rgb2=".6 .8 1"
width="256" height="256"/>
</asset>
<worldbody>
<light pos="0 1 1" dir="0 -1 -1" diffuse="1 1 1"/>
<body>
<geom type="capsule" fromto="0 0 1 0 0 0.6" size="0.06"/>
<joint type="ball" pos="0 0 1"/>
<body>
<geom type="capsule" fromto="0 0 0.6 0.3 0 0.6" size="0.04"/>
<joint type="hinge" pos="0 0 0.6" axis="0 1 0"/>
<joint type="hinge" pos="0 0 0.6" axis="1 0 0"/>
<body>
<geom type="ellipsoid" pos="0.4 0 0.6" size="0.1 0.08 0.02"/>
<site name="end1" pos="0.5 0 0.6" type="sphere" size="0.01"/>
<joint type="hinge" pos="0.3 0 0.6" axis="0 1 0"/>
<joint type="hinge" pos="0.3 0 0.6" axis="0 0 1"/>
</body>
</body>
</body>
<body>
<geom type="cylinder" fromto="0.5 0 0.2 0.5 0 0" size="0.07"/>
<site name="end2" pos="0.5 0 0.2" type="sphere" size="0.01"/>
<joint type="free"/>
</body>
</worldbody>
<tendon>
<spatial limited="true" range="0 0.6" width="0.005">
<site site="end1"/>
<site site="end2"/>
</spatial>asset
</tendon>
</mujoco>
这个模型定义了一个七自由度的机械臂和长度受限的被动弹簧结构。最外层的必须是worldbody。worldbody内部定义了机械臂末端通过一根柔性绳连接一个圆柱体。肩关节上是球关节,肘部和腕部各有两个正交的铰接关节。
用于动力学计算的刚体坐标系位姿、惯量从geoms几何形状中推算得到。site用于虚拟的定位点,这里被用来连接绳子的两端。default、asset分别定义了默认属性和背景属性等。可以看到MJCF格式相对URDF格式的建模文件可读性有了很大的提升。
2 模型元素
这里简单介绍MuJoCo建模的基础元素,之后我们会更深入地介绍建模和仿真计算之间的关联,以及在mjModel中的数据结构表示。
2.1 Options
每个MuJoCo模型有下列三种options。如果没有显式定义的话会采用它们的默认值。它们的值在每一步step的仿真前可以动态修改(如用于sim2real的domain randomization)。
- mOption: 定义了所有跟物理仿真相关的options,比如选择动力学算法、更改仿真流程(屏蔽一些不需要的步骤)、调节环境的system-level参数如中立加速度等。
- mjVisual: 包含所有可视化相关的选项。
- mjStatic: 包含了编译器编译后模型的数据统计量,如机体重量、所占空间范围等。
2.2 Assets
Assets用于增加或者改变元素默认信息。每个assets可以被多个模型元素引用(通过名字来引用)。
- Mesh: 从STL文件中导入的三角面片网格,有缩放选项用于缩放网格大小。编译器可以自动推断网格的惯量特性。注意MuJoC定义的STL文件不支持颜色,网格的颜色特性通过下文中材质决定。
- Skin: skinned meshes(或skins)是表面柔性可变性的网格。网格中顶点被固定在刚体上(称为bones),并且每个顶点可以属于多个bones,从而实现skin的光滑形变。skins只是用于可视化而不影响物理仿真。
- Height field: 高度场可以从PNG文件(内部会转化成灰度图)中读取。在碰撞检测和可视化中被自动三角化。因此在碰撞检测中极可能在单个geom中出现大量接触点,此时只取前16个接触点。高度场适合用于建模大型的(相对控制的机器人)地表面。
- Texture: 表面纹理信息一般从PNG或者用户定义颜色中读取。可视化界面支持两种纹理映射:2D 和方块cube。2D映射用于平面和高度场,cube映射用于收缩包装(shrink-wrapping)的3D物体。cube的六面可以从单独的文件读取或者复合图像文件,并且只能通过material来引用。
- Material: 材质用于控制几何形状geoms,sites和绳tendons的外观。材料外观的纹理映射跟OpenGL中的RGBA、高光、反射、散射等特性交互。
2.3 运动链
MuJoCo一般用于约束刚体的仿真。系统状态定义在关节广义坐标系中,刚体被组织成运动链。除了worldbody外其他刚体都只有一个父节点,并且运动环结构的定义不被允许。如果想要定义闭环结构话,需要通过equality属性来定义环关节。
因此MuJoCo模型的骨架由一到多个运动链组成(自由浮动刚体也可以定义成一个运动链),下面列出的元素依附于具体某个刚体(下一节中的元素则不依附任何刚体)。
- Body: 刚体body有质量和惯量特性,但是不包含任何几何信息(几何信息包含在geoms中)。每个刚体有两个坐标系:用于定义刚体和其他元素位姿关系的坐标系,和一个位于刚体质心并且对其主惯量轴的惯量坐标系(此坐标系中惯量矩阵是对角形式)。在每一步仿真中MuJoCo递推计算前向动力学,得到刚体在全局坐标系中的位姿。
- Joint: 关节定义在刚体中,来创建刚体和其父节点刚体的自由度(当关节缺失时两个刚体固接)。有四种类型的关节:球关节ball,滑动关节slide,旋转关节hinge,自由关节free。其中球关节和自由关节通过单位四元数表示。
- DOF: 自由度跟关节数相关,但不是一一对应,这是由于球关节和自由关节有多个自由度。自由度有速度相关的性质如摩擦损失、阻尼、电机惯量等。广义力在自由度空间内表达;关节具有位置相关的性质如范围限制、弹簧刚度等。自由度不直接由用户定义,而是通过编译器仿真指定关节时创建。
- Geom: geom是固接到刚体上的3D形状。一个刚体可以有多个geoms。geom可以用于碰撞检测、渲染、自动推断刚体质量惯量。MuJoCo支持多种基元几何形状:plane, sphere, capsule, ellipsoid, cylinder, box。geom有大量的材质相关特性用于仿真和可视化。
- Site: Site可以认为是零质量的geom。其定义了刚体坐标系中感兴趣的位置点,通常用于定义一些对象(如传感器、肌腱路径点、滑块终点)的位置。不参与碰撞检测。
- Camera: MuJoCo的默认存在一个相机,用户可以在可视化界面中自由移动鼠标来切换视角。另外用户也可以自己定义一些相机视角用于立体渲染等。
- Light: 光源可以固接在世界坐标系下或者移动的刚体上。MuJoCo实现的可视化界面可以访问OpenGL中所有的光源模型如环境光、漫反射、镜面反射、衰减截止、方向光、雾、阴影等等。默认的主光源跟相机一起移动,其特性可以通过mjVisual选项来改变。
2.4 单独元素
这里单独元素不属于任何刚体,可以在运动链外被定义。
- Reference pose: 关节位置的参考值存于mjModel.qpos0。表示模型初始时关节角度。当仿真重置时,mjData.qpos中的数据可以重置为mjModel.qpos0。
- Spring reference pose: 关节和线缆弹簧平衡状态下的位置。当远离平衡点时会产生正比位置变化量的弹簧力。弹簧的初始值存在mjModel.qpos_spring中。对于滑动关节和旋转关节,初始参考值通过属性springref指定。对于球关节和自由关节,参考值由初始模型配置确定。
- Tendon: 标量的线缆(tendon)元素可以用于驱动、施加限制、等值约束、或者创建弹簧-阻尼器、摩擦损失等等。有固定(fixed)和空间(spatial)两种类型的线缆。固定线缆是关节位置的线性组合,用于建模机械耦合(如回差)。空间线缆用于定义通过固定site点的最短路径、或者包含特殊形状外轮廓(球体或者圆柱)的路径。空间线缆还可以通过滑轮拆成多束。
- Actuator: MuJoCo提供了灵活的驱动器模型,可以通过三个属性来配置:传动机构(transmission)、驱动动力学(activation dynamics)、力生成机制(force generation)。传动系统指定了驱动器如何连接到(可通过关节、线缆、滑块)系统上。驱动动力学用于建模驱动器的内部激励状态转移(如非线性的气缸、液压缸、人工肌肉),最高支持三阶系统。力生成机制定义了如何将输入的控制信号映射到标量的驱动力上,再转换到广义力(乘以传动机构的力臂)。
- Sensor: 传感器数据存在mjData.sensordata全局数组中。传感器数据不用于任何内部计算,而是提供给用户做控制或者数据分析。目前实现的传感器类型包括触觉传感器、IMU、力/力矩传感器、关节/线缆位置速度传感器、驱动器广义位置/速度/力传感器、运动捕捉系统标记点位置姿态、磁力计。另外还有一些用户自定义传感器,允许用户代码将自定义传感量插入到sensordata中。MuJoCo的离线渲染功能则可以直接用于模拟彩色/深度相机。
- Equality: 等值约束可以在运动链中添加额外的约束,如创建闭环关节或者机械耦合。仿真时模型内部力将等值约束跟其他约束一起处理。实现的等值约束有:通过一个球关节点连接两个刚体、刚体固接、两平面滑动约束、固定线缆/关节的空间位置、通过三次多项式耦合两个关节/线缆的位置。
- Contact pair: 合理的接触选择有助于提高仿真效率。MuJoCo提供了十分精细的接触生成过程。geom的接触检测过滤来自两个方面:两物体足够近时触发、dynamic过滤器;通过MJCF文件显式定义。接触涉及到两个geoms,MJCF显式定义方式有助于用户定义一些dynamic机制无法实现的功能,可用于微调接触模型。
- Contact exclude: 接触筛除定义了哪些geoms接触需要被排除在外,从而避免一些不想要的接触。
- Custom numeric: 在仿真时读取内部数据方法:1. 定义MJCF文件中全局数值变量。2. 定义特定元素的扩展数组,通过size中的nuser_XXX属性来定义。3.使用mjData.userdata,用户可以在这个数据结构中存储自定义计算结果。
- Custom text: 自定义文字域。一般用于自定义计算,如指定命令关键字、提供一些调试的文本信息。
- Custom tuple: Custom tuple是MuJoCo元素的列表,用于指定特定元素的集合来进行自定义计算。比如用户可以使用包含特定刚体配对的tuple来进行自己实现的碰撞检测过程。
- Keyframe: Keyframe是对仿真中状态变量的快照,包含关节位置、速度、驱动器驱动量、仿真时间。一般用于重置仿真到某个状态。注意keyframe不用于记录轨迹,轨迹需要记录到用户实现额外的外部文件中(避免占用太多内存)。