当前位置:   article > 正文

MuJoCo 入门教程(四)建模

mujoco

系列文章目录

 


前言

 


 

一、简介

        MuJoCo 可以加载本地 MJCF 格式的 XML 模型文件,也可以加载流行但较为有限的 URDF 格式的 XML 模型文件。本章是 MJCF 建模指南。参考手册可在 XML 参考一章中找到。URDF 文档可以在其他地方找到;这里我们只描述 MuJoCo 特有的 URDF 扩展。

        MJCF 模型可以表示具有多种特征和模型元素的复杂动力系统。访问所有这些特征需要丰富的建模格式,如果在设计时没有考虑到可用性,这种格式就会变得繁琐。因此,我们努力将 MJCF 设计成一种可扩展的格式,允许用户从小规模开始,以后再建立更详细的模型。在这方面特别有用的是广泛的默认设置机制,其灵感来自 HTML 中的层叠样式表(CSS)。它使用户能够快速创建新模型并进行实验。大量选项可用于重新配置仿真流水线,而快速重新加载则使模型编辑成为一个交互式过程,从而为实验提供了进一步帮助。

        我们可以将 MJCF 视为建模格式和编程语言的混合体。它有一个内置编译器,这是一个通常与编程语言相关的概念。虽然 MJCF 不具备通用编程语言的功能,但会根据模型的设计自动调用许多复杂的编译时计算。

1.1 加载模型

        正如 "概述 "一章的 "模型实例 "中所解释的,MuJoCo 模型可以从 MJCF 或 URDF 格式的纯文本 XML 文件加载,然后编译成底层 mjModel。另外,也可以直接从二进制 MJB 文件加载先前保存的 mjModel,该文件的格式没有记录,但基本上是 mjModel 内存缓冲区的副本。MJCF 和 URDF 文件通过 mj_loadXML 加载,而 MJB 文件则通过 mj_loadModel 加载。

        加载 XML 文件时,首先使用 TinyXML 内部解析器将其解析为文档对象模型(DOM)。然后对 DOM 进行处理,并将其转换为高级 mjCModel 对象。转换取决于模型格式--它是根据 XML 文件中的顶级元素而不是文件扩展名推断出来的。回想一下,一个有效的 XML 文件有一个唯一的顶层元素。对于 MJCF,该元素必须是 mujoco;对于 URDF,该元素必须是 robot。

 1.2 编译模型

        一旦创建了高级 mjCModel(通过加载 MJCF 文件或 URDF 文件,或在此类功能可用时通过编程创建),它就会被编译到 mjModel 中。尽管加载和编译目前合并为一个步骤,但编译独立于加载,这意味着无论 mjCModel 是如何创建的,编译器都以相同的方式工作。解析器和编译器都会执行大量的错误检查,并在遇到第一个错误时终止。产生的错误消息包含 XML 文件中的行和列编号,不言自明,因此我们不在此记录。解析器使用自定义模式确保文件结构、元素和属性有效。然后,编译器会进行许多额外的语义检查。最后,对编译后的模型进行一次仿真,并拦截任何运行时错误。后者是通过(临时)设置 mju_user_error,使其指向一个抛出 C++ 异常的函数来实现的;如果需要,用户可以在运行时实现类似的错误拦截功能。

        整个解析和编译过程非常快,如果模型不包含需要通过仿真计算的大型网格或执行器长度范围,则整个过程不到一秒。这使得通过经常重新加载和可视化变化来交互式设计模型成为可能。请注意,simulate.cc 代码示例有一个重新加载当前模型的快捷键(Ctrl+L)。

1.3 保存模型

        一个 MJCF 模型可以由多个(包含的)XML 文件以及从 XML 引用的网格、高度域和纹理组成。编译后,所有这些文件的内容都会合并到 mjModel 中,然后可以使用 mj_saveModel 将其保存为二进制 MJB 文件。MJB 是一个独立文件,不会引用任何其他文件。它的加载速度也更快。因此我们建议将常用模型保存为 MJB 文件,并在需要仿真时加载。

        也可以使用 mj_saveLastXML 将编译后的 mjCModel 保存为 MJCF。如果相应 mjModel 中的任何实值字段在编译后被修改(这种情况并不常见,但在系统识别应用中可能会发生),则会在保存前自动将修改复制回 mjCModel。请注意,不能在编译后的模型中进行结构更改。XML 编写器会尝试生成最小的 MJCF 文件,以保证编译成相同的模型,其中不包括因纯文本表示实值而造成的可忽略的数字差异。生成的文件可能与原始文件结构不同,因为 MJCF 有许多方便用户的功能,允许以不同方式指定同一模型。XML 写入器使用的是 MJCF 的 "规范 "子集,其中所有坐标都是本地坐标,所有身体位置、方向和惯性属性都是明确指定的。在计算一章中,我们展示了一个 MJCF 文件示例和相应的保存示例。

二、MJCF 机制

        MJCF 使用多种机制来创建模型,这些机制跨越多个模型元素。为了避免重复,我们在本节中只详细描述一次。除了在 "计算 "一章中介绍的概念外,这些机制并不对应新的仿真概念。它们的作用是简化 MJCF 模型的创建,并使不同数据格式的使用无需手动转换为统一格式。

2.1 运动树

        MJCF 文件的主要部分是由嵌套的主体元素创建的 XML 树。顶层的主体是特殊的,称为 worldbody。这种树状结构与 URDF 形成鲜明对比,后者先创建链接集合,然后用指定子链接和父链接的连接点将它们连接起来。在 MJCF 中,从 XML 的意义上讲,子体就是父体的子体。

        当一个关节被定义在一个体内部时,它的功能不是连接父体和子体,而是在它们之间创建运动自由度如果给定的体内部没有定义关节,则该体将被焊接到其父体上。在 MJCF 中,一个体可以包含多个关节,因此无需引入虚拟体来创建复合关节。相反,只需在同一主体中定义构成所需复合关节的所有原始关节即可。例如,可以使用两个滑块和一个铰链来模拟在平面内运动的肢体。

        其他 MJCF 元素可以在嵌套的主体元素所创建的树中定义,特别是关节、几何体、场地、摄像机、灯光。当一个元素被定义在一个肢体内时,它就固定在该肢体的局部坐标系上,并始终随其移动。涉及多个机构或根本不涉及机构的元素,将在运动树之外的单独部分中定义。

2.2 默认设置

        MJCF 有一个精心设计的机制来设置默认属性值。这使我们能够拥有大量的元素和属性,以展示软件的丰富功能,同时编写简短易读的模型文件。这种机制还能让用户在一个地方引入变化,并将其传播到整个模型中。我们从一个例子开始。

  1. <mujoco>
  2. <default class="main">
  3. <geom rgba="1 0 0 1"/>
  4. <default class="sub">
  5. <geom rgba="0 1 0 1"/>
  6. </default>
  7. </default>
  8. <worldbody>
  9. <geom type="box"/>
  10. <body childclass="sub">
  11. <geom type="ellipsoid"/>
  12. <geom type="sphere" rgba="0 0 1 1"/>
  13. <geom type="cylinder" class="main"/>
  14. </body>
  15. </worldbody>
  16. </mujoco>

        由于缺少某些必要信息,本示例实际上无法编译,但在此我们只对 geom rgba 值的设置感兴趣。由于采用了默认设置机制,上述创建的四个 geom 最终将具有以下 rgba 值:

geom type

geom rgba

box

1 0 0 1

ellipsoid

0 1 0 1

sphere

0 0 1 1

cylinder

1 0 0 1

         由于没有指定其他类,方框使用顶层默认类 "main "来设置其未定义属性的值。正文指定了子类 "sub",除非另有说明,否则该正文的所有子类(及其所有子类等)都将使用子类 "sub"。因此,椭圆体使用 "sub "类。球体明确定义了 rgba,可以覆盖默认设置。圆柱体指定的默认类是 "main",因此它使用的是 "main "而不是 "sub",尽管后者是在包含 geom 的 body 的 childclass 属性中指定的。

        现在我们来描述一下一般规则。MuJoCo 支持数量不限的默认类,这些默认类由 XML 中可能嵌套的默认元素创建。每个类都有一个唯一的名称  —— 这是一个必备属性,但顶层类除外,其名称如果未定义,则为 "main"。每个类还有一个完整的虚拟模型元素集合,其属性设置如下。当一个默认类被定义在另一个默认类中时,子类会自动继承父类的所有属性值。然后,子类可以通过定义相应的属性来覆盖部分或全部属性。顶层默认值类没有父类,因此其属性被初始化为内部默认值,参见参考章节。

        默认类中包含的虚拟元素并不是模型的一部分;它们只是用来初始化实际模型元素的属性值。当首次创建实际元素时,它的所有属性都会从默认类中当前处于活动状态的相应哑元素中复制。默认类总是处于活动状态,可以通过以下三种方式之一来确定。如果当前元素或其任何父体中没有指定类,则使用顶层类(无论其名称是 "main "还是其他)。如果当前元素中没有指定类,但它的一个或多个祖先体指定了一个子类,则使用离它最近的祖先体的子类。如果当前元素指定了一个类,那么无论其祖先主体中是否有任何子类属性,都会使用该类。

        某些属性,如主体惯性,可以处于特殊的未定义状态。这将指示编译器从其他信息中推断出相应的值,在这种情况下,编译器会推断出附着在主体上的 geoms 的惯性。未定义状态不能在 XML 文件中输入。因此,一旦给定类中定义了属性,该类或其任何子类中都不能对其进行未定义。因此,如果我们的目标是在给定的模型元素中不定义某个属性,那么它就必须在活动默认类中不被定义。

        最后一个转折点是执行器。它们之所以不同,是因为一些与执行器相关的元素实际上是快捷方式,而快捷方式与默认设置机制的交互方式并不明显。下文的执行器快捷方式部分将对此进行解释。

2.3 坐标系

        运动学树中定义的所有元素的位置和方向都用局部坐标表示,对于体来说是相对于父体的坐标,而对于geoms、关节、场地、摄像机和灯光来说,是相对于包含该元素的体的坐标

        编译器/角度是一个相关属性。它指定 MJCF 文件中的角度是用度还是弧度表示(编译后,角度始终用弧度表示)。

        位置用

pos: real(3), "0 0 0"
相对于父体的位置。

2.3.1 坐标系方向

        有几个模型元素具有与之相关的右手空间坐标系。除了关节之外,这些都是运动学树中定义的元素。空间坐标系由其位置和方向定义。指定三维位置非常简单,但指定三维方向则具有挑战性。因此,MJCF 提供了几种可供选择的机制。无论用户选择哪种机制,坐标系的方向总是在内部转换为单位四元数。回想一下,围绕单位向量 eq?%28x%2Cy%2Cz%29 给出的轴旋转一个角度的三维旋转对应于四元数 2%29%5Ccdot%28x%2Cy%2Cz%29%29 。还请注意,每个三维方位都可以通过绕某个轴旋转某个角度来唯一指定。

        所有具有空间坐标系的 MJCF 元素都允许使用下面列出的五个属性。坐标系的方向最多使用其中一个属性指定。quat 属性有一个与空旋转相对应的默认值,而其他属性则在特殊的未定义状态下初始化。因此,如果用户没有指定这些属性,坐标系就不会旋转。

quat: real(4), “1 0 0 0”

        如果已知四元数,这是指定坐标系方向的首选方法,因为它不涉及转换。相反,它被归一化为单位长度,并在编译时复制到 mjModel 中。当模型保存为 MJCF 时,所有坐标系的方向都将使用此属性以四元数表示。

axisangle: real(4), optional

        这些数字就是上文提到的 eq?%28x%2Cy%2Cz%2Ca%29。最后一个数字是旋转角度,单位为度或弧度,由编译器的角度属性指定。前三个数字决定了一个三维向量,即旋转轴。在编译过程中,该向量被归一化为单位长度,因此用户可以指定任何非零长度的向量。请记住,旋转是右旋的;如果向量(x,y,z)的方向相反,则旋转结果也会相反。改变 a 的符号也可以用来指定相反的旋转。

euler: real(3), optional

        围绕三个坐标轴的旋转角度。围绕这些坐标轴旋转的顺序由编译器的 eulerseq 属性决定,并且对整个模型都是一样的。

xyaxes: real(6), optional

        前 3 个数字是坐标系的 X 轴。接下来的 3 个数字是坐标系的 Y 轴,它会自动与 X 轴正交。然后将 Z 轴定义为 X 轴和 Y 轴的交叉积。

zaxis: real(3), optional

        坐标系的 Z 轴。编译器会找到最小的旋转,将向量 (0,0,1) 映射到此处指定的向量。这样就隐式地确定了坐标系的 X 轴和 Y 轴。这对于以 Z 轴为旋转对称轴的几何体以及沿其坐标系 Z 轴定向的灯光都很有用。

2.4 求解器参数

        计算一章中的求解器参数部分解释了 eq?d%2Cb%2Ck 这些决定 MuJoCo 中约束行为的量的数学和算法含义。这里我们将解释如何设置它们。设置是通过属性 solref 和 solimp 间接完成的,所有涉及约束的 MJCF 元素都有这两个属性。这些参数可以根据每个约束或每个缺省值类进行调整,也可以保持未定义 —— 在这种情况下,MuJoCo 使用下图所示的内部缺省值。还请注意选项中提供的覆盖机制;它可用于在运行时更改所有与接触相关的求解器参数,以便对参数设置进行交互式试验或实施数值优化的延续方法。

        在这里,我们只关注一个标量约束。使用与 "计算 "一章略有不同的符号,让 eq?a_%7B1%7D 表示加速度,eq?v 表示速度,eq?r 表示位置或残差(在摩擦维度中定义为 0),eq?keq?b 表示虚拟弹簧的刚度和阻尼,用于定义参考加速度 eq?a_%7B%5Cmathrm%7Bref%7D%7D%3D-bv-kr 。eq?d是约束阻抗,eq?a_0 表示没有约束力时的加速度。我们之前的分析表明,约束空间中的动力学近似于

eq?a_1&plus;d%5Ccdot%28bv&plus;kr%29%3D%281-d%29%5Ccdot%20a_0

        同样,用户可控制的参数有 eq?d%2Cb%2Ck。其余量是系统状态的函数,在每个时间步长自动计算。

2.4.1 阻抗

        我们首先解释一下约束阻抗 eq?d.

阻抗的直观描述

        阻抗 d∈(0,1) 与约束产生力的能力相对应。d 值越小,约束越弱;d 值越大,约束越强。阻抗在任何时候都会对约束产生影响,尤其是当系统处于静止状态时。阻抗使用 solimp 属性设置。

        回想一下,eq?d 必须介于 0 和 1 之间;MuJoCo 内部将其限制在 [mjMINIMP mjMAXIMP] 范围内,目前设置为 [0.0001 0.9999]。它使求解器在非强制加速度 eq?a_0 和参考加速度 eq?a_%7Bref%7D 之间进行内插。用户可以将 eq?d 设为常量,也可以利用其插值特性,使其与位置相关,即与约束违反 eq?r 相关的函数。与位置相关的阻抗可用于对物体周围的柔性接触层进行建模,或定义随着违反程度的增大而变得更强的相等约束(例如用于近似反向间隙)。函数 eq?d%28r%29 的形状由元素特定参数向量 solimp 决定。

solimp : real(5), "0.9 0.95 0.001 0.5 2"
这五个数字(eq?d_0%2Cd_%5Ctext%7Bwidth%2C%20width%2C%20midpoint%2C%20power%7D)是 eq?d%28r%29  的参数,即阻抗 eq?d 与违反约束条件 eq?r 的函数关系。

前 3 个数值表明,当 eq?r 从 0 到  eq?width 变化时,阻抗将平滑变化:

eq?d%280%29%3Dd_0%2C%5Cquad%20d%28%5Cmathrm%7Bwidth%7D%29%3Dd_%7B%5Cmathrm%7Bwidth%7D%7D

如下图所示,第 4 和第 5 个值,即中点和功率,控制着在 d 0 和 widthd 宽度之间插值的正余弦函数的形状。由于阻抗 d(r) 取决于 r 的绝对值,因此图中显示的是两个反射的四边形。
用于生成函数的多项式样条曲线的幂必须大于等于 1。中点(指定拐点)必须介于 0 和 1 之间,并以宽度单位表示。请注意,当幂次为 1 时,无论中点在哪里,函数都是线性的。

5d3ac4f9c6b5466e9637d4b30c341d11.png

这些图显示了纵轴上的阻抗 d(r)与横轴上的违反约束条件 r 的函数关系。

对于相等约束,r 即为违反约束。对于极限、椭圆锥体的法线方向和金字塔锥体的所有方向,r 是(极限或接触)距离减去约束生效的边距;对于接触,这个边距就是边距。当 r<0(穿透)时,极限约束和接触约束生效。

对于椭圆锥体的摩擦损耗或摩擦尺寸,违规 r 同等于零,因此只有 d(0) 会影响这些约束,所有其他 solimp 值都会被忽略。

提示

对于完全平滑的动力学,极限和接触应为 =0。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2.5 接触参数

        计算章节的 "接触 "部分介绍了每个接触的参数。下面我们将解释如何设置这些参数。如果使用 XML 元素对明确定义了几何体对,则其属性可直接指定所有触点参数。在这种情况下,单个 geom 的参数将被忽略。另一方面,如果触点是由动态机制生成的,则其参数需要从触点对中的两个 geoms 中推断出来。如果两个几何体的参数完全相同,则无需做任何处理,但如果它们的参数不同呢?在这种情况下,我们将使用几何体属性 solmix 和优先级来决定如何组合它们。每个接触参数的组合规则如下:

2.5.1 condim

        如果两个 geom 中的一个优先级更高,则使用其 condim。如果两个 geom 的优先级相同,则使用两个 condim 中的最大值。通过这种方式,除非无摩擦geom的优先级更高,否则无摩擦geom和有摩擦geom会形成摩擦接触。例如,在粒子系统中,我们可能不希望粒子粘在任何物体上,而后者则是理想的选择。

2.5.2 friction

        请注意,接触点最多可以有 5 个摩擦系数:两个切向摩擦系数、一个扭转摩擦系数和两个滚动摩擦系数。实际上,mjData.contact 中的每个触点都有全部 5 个摩擦系数,即使 condim 小于 6 并且没有使用所有系数。相比之下,geoms 只有 3 个摩擦系数:切向(两轴相同)、扭转、滚动(两轴相同)。通过复制切向分量和滚动分量,每个摩擦系数的三维矢量都会扩展成一个摩擦系数的五维矢量。然后根据以下规则计算接触摩擦系数:如果两个几何体中的一个具有更高的优先级,则使用其摩擦系数。否则,将使用两个地基上每个摩擦系数的元素最大值。其原理类似于在 condim 上取最大值:我们希望摩擦力更大的地基获胜。每个接触点有 5 个摩擦系数,而每个几何点只有 3 个摩擦系数的原因如下。对于一对接触件,我们希望求解器能够处理最灵活的模型。如前所述,各向异性摩擦可以用来模拟滑行等效果。不过,这需要知道接触切平面的两个轴线是如何定向的。对于一对预定义的接触,我们事先知道两个几何体的类型,相应的碰撞函数总是以相同的方式生成接触坐标系--我们在此不做描述,但可以在可视化工具中看到。但是,对于单个几何体来说,我们不知道它们可能会与哪些其他几何体碰撞,也不知道它们的几何体类型是什么,因此在指定单个几何体时无法知道接触切平面的方向。这就是 MuJoCo 不允许在单个 geom 规范中使用各向异性摩擦力,而只允许在显式接触对规范中使用的原因。

2.5.3 边距,间隙 margin, gap

        使用两个几何边距(或间隙)的最大值。这里忽略了几何优先级,因为边距和间隙都是距离属性,单边规范意义不大。

2.5.4 solref, solimp

        如果两个 geom 中的一个优先级更高,则使用其 solref 和 solimp 参数。如果两个地理坐标的优先级相同,则使用加权平均值。权重与 solmix 属性成正比,即 weight1 = solmix1 / (solmix1 + solmix2),类似地 weight2 也是如此。这一加权平均规则有一个重要的例外。如果任一地理坐标的 solref 为非正值,即依赖于直接格式,那么无论 solmix 如何,都将使用元素最小值。这是因为对不同格式的 solref 参数进行平均是毫无意义的。

2.6 接触覆盖

        MuJoCo 使用了一个精心设计的新颖约束模型,该模型在 "计算 "一章中有所描述。要直观了解该模型的工作原理,需要进行一些实验。为了方便这一过程,我们提供了一种机制,可以在不更改实际模型的情况下覆盖部分求解器参数。一旦覆盖被禁用,仿真就会恢复到模型中指定的参数。这种机制还可用于在数值优化(如最优控制或状态估计)的背景下实施延续方法。具体做法是,在优化的早期阶段,允许接触从远处起作用,以帮助优化器找到梯度并接近好的解 决方案,并在后期减少这种影响,使最终解决方案符合物理实际。

        这里的相关设置包括:flag 的覆盖属性,用于启用或禁用这一机制;option 的 o_margin、o_solref、o_solimp 属性,用于指定新的求解器参数。请注意,覆盖仅适用于接触,而不适用于其他类型的约束。原则上,MuJoCo 模型中有许多实值参数可以从类似的覆盖机制中受益。然而,我们必须在某个地方划出一条界线,而接触是自然的选择,因为它们会产生最丰富但最难调整的行为。此外,接触动力学通常会给数值优化带来挑战,而经验表明,接触参数的持续性有助于避免局部最小值。

 2.7 用户参数

        一些 MJCF 元素具有可选属性 user,它定义了一个自定义元素特定参数数组。它与 size 元素的相应 "nuser_XXX "属性交互。例如,如果我们将 nuser_geom 设置为 5,那么 mjModel 中的每个 geom 都会有一个由 5 个实值参数组成的自定义数组。在 MJCF 文件中,可以通过 geom 的用户属性定义这些特定于 geom 的参数,如果省略该属性,则编译器会将这些参数设置为 0。所有 "nuser_XXX "属性的默认值都是-1,它指示编译器自动将该值设置为模型中定义的最大相关用户属性的长度。MuJoCo 不会在任何内部计算中使用这些参数;相反,它们可用于自定义计算。解析器允许在 XML 中使用任意长度的数组,编译器随后会将这些数组的长度调整为 nuser_XXX。

        一些通常用于内部计算的特定元素参数也可用于自定义计算。这可以通过安装用户回调来实现,用户回调可以覆盖仿真管道的部分功能。例如,一般执行器元素具有 dyntype 和 dynprm 属性。如果 dyntype 被设置为 "用户",那么 MuJoCo 将调用 mjcb_act_dyn 来计算执行器的动力学,而不是调用其内部函数。mjcb_act_dyn 指向的用户函数可以任意解释 dynprm 中定义的参数。不过,这个参数数组的长度不能改变(与前面描述的自定义数组不同,后者的长度是在 MJCF 文件中定义的)。这一点同样适用于其他回调。

        除了上述特定于元素的用户参数外,我们还可以通过自定义元素在模型中包含全局数据。对于在仿真过程中发生变化的数据,还有数组 mjData.userdata,其大小由 size 元素的 nuserdata 属性决定。

 2.8 求解器设置

        计算约束力和约束加速度需要数值求解一个优化问题。MuJoCo 有三种求解优化问题的算法:CG、牛顿和 PGS。每种算法都可以应用于摩擦锥的金字塔模型或椭圆模型,以及密集或稀疏的约束雅各布。此外,用户还可以指定最大迭代次数和控制提前终止的容差水平。此外,还有第二个 Noslip 求解器,这是一个后处理步骤,通过指定正数的 Noslip 迭代次数即可启用。所有这些算法设置都可以在选项元素中指定。

        默认设置适用于大多数模型,但在某些情况下有必要调整算法。最好的方法是试验相关设置,并使用 simulate.cc 中的可视化剖析器,它可以显示不同计算的时间以及每次迭代的求解器统计数据。我们可以提供以下一般指导和意见:

  • 对于小型模型,约束雅各比应该是密集的,而对于大型模型,约束雅各比应该是稀疏的。默认设置为 "自动";当自由度数不超过 60 时,它解析为密集,超过 60 时则解析为稀疏。但请注意,阈值最好根据活动约束的数量来定义,这与模型和行为有关。
  • 在金字塔形摩擦锥和椭圆形摩擦锥之间进行选择是一种建模选择,而不是算法选择,也就是说,它导致了用相同算法求解的不同优化问题。椭圆锥更贴近物理现实。不过,金字塔锥可以提高算法的性能,但不一定。虽然默认值为金字塔形,但我们建议尝试椭圆锥形。当接触滑移成为一个问题时,抑制它的最佳方法是使用椭圆锥、大的印迹率和公差极小的牛顿算法。如果这还不够,可以启用 Noslip 求解器。
  • 牛顿算法是大多数模型的最佳选择。它在全局最小值附近具有二次收敛性,迭代次数少得惊人--通常在 5 次左右,很少超过 20 次。在使用时,应尽量使用公差值,如 1e-10,因为它能够在不增加延迟的情况下实现高精度(由于最后的二次收敛)。我们只在具有椭圆锥和许多滑动接触的大型模型中见过它减速的情况。在这种情况下,Hessian 因式分解需要大量更新。在某些大型模型中,由于模型元素的排序不理想,导致高填充(计算最优消除顺序是 NP 难的,因此我们依靠启发式),计算速度也会减慢。请注意,可以在剖析器中监测因式分解赫塞斯中的非零点数。
  • CG 算法在上述牛顿减慢的情况下运行良好。一般来说,CG 算法具有良好的线性收敛性,但在迭代次数上无法与牛顿算法相提并论,尤其是在需要高精度的情况下。不过,CG 的迭代速度要快得多,而且不会受到填充或椭圆锥复杂性增加的影响。如果牛顿太慢,可以尝试 CG。
  • 当自由度数大于约束数时,PGS 求解器效果最佳。PGS 求解的是一个约束优化问题,根据我们的经验,它的收敛性是亚线性的,但通常在最初的几次迭代中进展迅速。因此,在可以容忍不精确解的情况下,它是一个不错的选择。对于具有大质量比或其他导致调节能力差的模型特性的系统,PGS 的收敛速度往往相当缓慢。请记住,PGS 执行的是顺序更新,因此会破坏物理本应对称的系统的对称性。相比之下,CG 和牛顿则执行并行更新并保持对称性。
  • Noslip 求解器是一种改进的 PGS 求解器。它在主求解器(可以是牛顿、CG 或 PGS)之后作为后处理步骤执行。主求解器更新所有未知数。相比之下,Noslip 求解器只更新摩擦维的约束力,而忽略约束正则化。这样做的效果是抑制由柔性约束模型引起的漂移或滑移。然而,这一连串的优化步骤不再是解决一个定义明确的优化问题(或任何其他问题),而只是一种临时机制。虽然它通常都能完成任务,但我们发现,在具有更复杂的多触点相互作用的模型中,它也会出现一些不稳定的情况。
  • PGS 在计算约束空间中的反惯性时需要设置成本(CPU 时间)。类似地,牛顿计算 Hessian 的初始因式分解也需要设置成本,而且根据以后需要更新多少因式分解,还会产生额外的因式分解成本。CG 没有任何设置成本。由于 Noslip 求解器也是一个 PGS 求解器,因此只要启用 Noslip,即使主求解器是 CG 或牛顿,也要支付 PGS 设置成本。主 PGS 和 Noslip PGS 的设置操作是相同的,因此当两者都启用时,只需支付一次设置费用。

 2.9 执行器

        本节介绍在 MuJoCo 中使用执行器的各个方面。有关计算模型,请参阅执行模型。

2.9.1 组禁用

        执行器组禁用属性(可在运行时通过设置 mjOption.disableactuator 整数位域进行更改)允许用户根据执行器组禁用执行器组。当用户希望在同一运动学树中使用多种类型的执行器时,这一功能非常方便。例如,考虑到机器人的固件支持多种控制模式,如扭矩控制和位置控制。在这种情况下,可以在同一个 MJCF 模型中定义这两种类型的执行器,将其中一种类型的执行器分配到组 0,另一种类型的执行器分配到组 1。

        执行器组禁用 MJCF 属性选择了默认禁用的执行器组,可在运行时设置 mjOption.disableactuator 以切换活动执行器组。请注意,执行器总数 mjModel.nu 和执行器指数都保持不变,因此用户需要知道禁用执行器的 mjData.ctrl 值将被忽略,并且不会产生力。本示例模型有三个执行器组,可以在运行时在仿真交互式查看器中进行切换。请参见右侧的示例模型和相关屏幕截图。

 2.9.2 快捷方式

        如计算一章的执行模型部分所述,MuJoCo 提供了一个灵活的执行器模型,其中的传动、激活 动力学和力生成组件可以独立指定。用户可通过 XML 通用元素访问全部功能,从而创建各种自定义致动器。此外,MJCF 还提供了配置常用执行器的快捷方式。这可通过 XML 元素电机、位置、速度、速度内、阻尼器、气缸、肌肉和附着力来实现。这些都不是单独的模型元素。在内部,MuJoCo 只支持一种执行器类型 —— 这就是为什么在保存 MJCF 模型时,所有执行器都被写为通用执行器的原因。快捷方式隐式地创建通用执行器,将其属性设置为合适的值,并以可能不同的名称公开属性子集。例如,位置创建了一个位置伺服,其属性 kp 是伺服增益。然而,general 没有 kp 属性。相反,解析器会以协调的方式调整通用执行器的增益和偏置参数,以模仿位置伺服。如果直接使用 general 执行器,并将其属性设置为下文所述的特定值,也可以达到同样的效果。

        执行器快捷方式还与默认设置相互影响。记得默认设置机制涉及到类,每个类都有一个完整的虚拟元素集合(每种元素类型一个),用于初始化实际模型元素的属性。特别是,每个默认类只有一个通用执行器元素。如果我们在同一个默认设置类中先指定位置,然后再指定速度,会发生什么情况?XML 元素是按顺序处理的,每次遇到与执行器相关的元素时,都会设置单个通用执行器的属性。因此速度优先。然而,如果我们在缺省值类中指定 general,那么它只会设置明确给出的属性,而其他属性则保持不变。在创建实际模型元素时也会出现类似的复杂情况。假设活动缺省值类指定了 position,而现在我们使用 general 创建了一个执行器,并省略了它的某些属性。缺失的属性将被设置为用于位置伺服建模的任何值,尽管这个执行器可能并不打算用作位置伺服。

        鉴于这些潜在的复杂性,我们建议采用一种简单的方法:在默认类和实际模型元素的创建 中使用相同的执行器快捷方式。如果给定模型需要不同的致动器,要么创建多个默认类,要么避免使用致动器默认类,而是明确指定其所有属性。

2.9.3 力限制

        执行器的力通常受下限和上限的限制。这些限制可通过三种方式实现:

使用 ctrlrange 控制箝位:
        如果设置了该执行器属性,输入控制值将被箝位。对于简单的电机,控制输入的箝位等同于力输出的箝位。

通过 forcerange 在执行机构输出端进行力箝位:
        如果设置了该执行机构属性,执行机构的输出力将被箝位。该属性对位置执行器等非常有用,可以将力控制在一定范围内。需要注意的是,位置执行器通常也需要控制范围夹紧,以避免触及关节限制。

使用 joint/actuatorfrcrange 在关节输入处夹紧力:
        该关节属性可在通过传动装置后,夹紧作用在关节上的所有执行器的输入力。如果传动是微不足道的(传动装置和关节之间是一对一的关系),那么在关节处夹紧作动器的力就等同于在作动器处夹紧力。然而,在多个执行器作用于一个关节或一个执行器作用于多个关节,但实际扭矩是由关节处的单个物理执行器施加的情况下,最好将力夹紧在关节本身。下面举三个例子,说明在关节而不是作动器上夹紧作动器的力是可取的:

  • 在这个示例模型中,两个执行器(一个电机和一个阻尼器)作用在一个关节上。
  • 在本示例模型(类似于 "杜宾车")中,两个致动器通过一个固定的腱传动装置作用于两个车轮,以施加对称(向前/向后滚动)和非对称(向右/向左转弯)扭矩。
  • 在这个示例模型中,一个场地传动装置实现了手臂末端执行器的笛卡尔控制器。为了使计算出的扭矩能够通过单个扭矩受限的关节电机实现,需要在关节处夹紧扭矩。

        需要注意的是,在这种情况下,如果力/力矩由传动装置合成,则应使用 jointactuatorfrc 传感器来报告作用在关节上的总致动器力。标准致动器 frc 传感器将继续报告预夹紧的致动器力。

        上述三种夹紧方式并不完全相同,可以根据需要进行组合。

2.9.4 长度范围

        字段 mjModel.actuator_lengthrange 包含可行的致动器长度范围(或更准确地说,致动器传动装置的长度)。这是仿真肌肉推杆所必需的。这里我们将重点讨论 actuator_lengthrange 的含义和设置方法。

        mjModel 的所有其他字段都是精确的物理或几何量,而 actuator_lengthrange 则不同,它是一个近似值。直观地说,它对应于在模型的所有 "可行 "配置中,执行器传输所能达到的最小和最大长度。然而,MuJoCo 约束是柔性的,因此原则上任何配置都是可行的。然而,我们需要一个明确定义的肌肉建模范围。有三种方法可以设置这个范围:(1)使用所有执行器都有的新属性 lengthrange 明确提供;(2)从执行器所连接的关节或肌腱的极限中复制;(3)自动计算,如本节其余部分所解释的。这里有很多选择,可以用新的 XML 元素 lengthrange 来控制。

        推杆长度范围的自动计算在编译时完成,计算结果存储在编译模型的 mjModel.actuator_lengthrange 中。如果模型被保存(XML 或 MJB),下次加载时就不需要重复计算。这一点非常重要,因为在使用大型肌肉骨骼模型时,计算会减慢模型编译器的运行速度。事实上,我们将编译器设置为多线程,就是为了加速这一操作(不同的执行器在不同的线程中并行处理)。顺便提一下,这也是为什么在 Linux 和 macOS 上将用户代码与 MuJoCo 库链接时需要使用"-pthread "标记的原因。

        自动计算依赖于修改后的物理仿真。对于每个执行器,我们通过执行器的传动装置施加力(计算最小值时施加负力,计算最大值时施加正力),在避免不稳定性的阻尼状态下推进仿真,给它足够的时间稳定下来并记录结果。这与带动量的梯度下降有关,事实上,我们已经尝试过基于梯度的显式优化,但问题是,我们不清楚应该优化什么目标(考虑到软性约束的混合)。通过仿真,我们基本上可以让物理学告诉我们应该优化什么。但请记住,这仍然是一个优化过程,因此它的参数可能需要调整。我们提供了保守的默认值,这些默认值应适用于大多数模型,但如果不适用,可使用 lengthrange 的属性进行微调。

        在使用这一功能时,必须牢记模型的几何形状。这里隐含的假设是可行的推杆长度确实有限。此外,我们并不认为接触是限制因素(事实上,在本仿真中我们在内部禁用了接触,同时禁用的还有被动力、重力、摩擦损耗和推杆力)。这是因为带有接触的模型会纠结在一起,产生许多局部极小值。因此,推杆应受到限制,要么是由于模型中定义的关节或肌腱限制(在本次仿真中启用),要么是由于几何限制。为了说明后者,请考虑一条一端与世界相连,另一端与围绕与世界相连的铰链接头旋转的物体相连的肌腱。在这种情况下,肌腱的最小长度和最大长度是明确定义的,并且取决于连接点在空间中划出的圆的大小,即使关节和肌腱都没有用户定义的限制。但是,如果推杆连接到关节上,或者连接到与关节等长的固定腱上,那么它的长度就是无限的。在这种情况下,编译器会返回错误,但它无法判断错误是由于收敛性不足,还是因为执行器长度不受限制。所有这一切听起来都过于复杂,因为我们在这里考虑了所有可能的角情况。在实际应用中,长度范围几乎总是与连接到空间肌腱上的肌肉致动器一起使用,模型中会定义关节限制,从而有效限制肌肉执行器的长度。如果在这样的模型中出现收敛错误,最有可能的解释是你忘了包含关节限制。

2.9.5 状态执行器

        正如 "计算 "一章的 "执行器模型 "部分所述,MuJoCo 支持具有内部动力学的致动器,其状态称为 "激活"。

2.9.5.1 激活限制

        有状态执行器的一个有用应用是 "综合速度 "执行器,由 intvelocity 快捷键实现。与直接反馈传输目标速度的纯速度执行器不同,综合速度执行器将积分器与位置反馈执行器结合在一起。在这种情况下,激活状态的语义是 "位置执行器的设定点",而控制信号的语义是 "位置执行器设定点的速度"。请注意,在实际的机器人系统中,这种集成速度致动器是最常见的具有速度语义的致动器实现方式,而不是纯粹的速度反馈,后者往往相当不稳定(无论是在现实生活中还是在仿真中)。

        在集成速度致动器的情况下,通常需要对激活状态进行箝位,否则位置目标会不断积分,超出关节极限,从而导致失控。要了解激活箝位的效果,请加载下面的示例模型:

        带激活限制的示例模型

  1. <mujoco>
  2. <default>
  3. <joint axis="0 0 1" limited="true" range="-90 90" damping="0.3"/>
  4. <geom size=".1 .1 .1" type="box"/>
  5. </default>
  6. <worldbody>
  7. <body>
  8. <joint name="joint1"/>
  9. <geom/>
  10. </body>
  11. <body pos=".3 0 0">
  12. <joint name="joint2"/>
  13. <geom/>
  14. </body>
  15. </worldbody>
  16. <actuator>
  17. <general name="unclamped" joint="joint1" gainprm="1" biastype="affine"
  18. biasprm="0 -1" dyntype="integrator"/>
  19. <intvelocity name="clamped" joint="joint2" actrange="-1.57 1.57"/>
  20. </actuator>
  21. </mujoco>


        请注意,尽管关节范围可以是度(默认)或弧度(取决于编译器/角度属性),但 actrange 属性始终以本地单位(弧度)指定。

2.9.5.2 肌肉

        我们提供了一套生物肌肉建模工具。如果用户想添加肌肉,只需在执行器部分添加一行 XML 即可:

  1. <actuator>
  2. <muscle name="mymuscle" tendon="mytendon">
  3. </actuator>

        生物肌肉的外观大相径庭,但一旦应用了一定的缩放比例,它们的表现却极为相似。我们的默认设置就采用了这种缩放比例,因此无需调整任何参数就能获得合理的肌肉模型。当然,要构建更详细的模型则需要调整参数,本节将对此进行说明。

        请记住,尽管肌肉模型相当精细,但它仍然是 MuJoCo 执行器的一种类型,与所有其他执行器一样遵守相同的约定。肌肉的定义可以使用一般定义,但快捷键 "肌肉 "更为方便。与所有其他致动器一样,力的产生机制和传递是独立定义的。然而,肌肉只有在与肌腱或关节传动装置相连时才具有(生物)物理意义。为具体起见,我们在此假定为肌腱传动。

        首先,我们讨论长度和长度缩放。传动装置(即 MuJoCo 肌腱)的可行长度范围将起到重要作用;请参见上文的长度范围部分。在生物力学中,肌肉和肌腱串联在一起,形成肌肉-肌腱致动器。我们的习惯略有不同:在 MuJoCo 中,具有空间属性(尤其是长度和速度)的实体是肌腱,而肌肉是一种抽象的发力机制,对肌腱产生拉力。因此,MuJoCo 中的肌腱长度对应于生物力学中的肌肉+肌腱长度。我们假设生物肌腱是无弹性的,长度 L T 保持不变,而生物肌肉长度 L M 则随时间变化。MuJoCo 的肌腱长度是生物肌肉和肌腱长度的总和:

eq?%5Ctext%7Bactuator%20-length%7D%3DL_T&plus;L_M

        另一个重要的常数是肌肉的最佳静止长度,用 L 0 表示,它等于肌肉在零速度下产生最大主动力的长度 L M。我们不要求用户直接指定 L 0 和 L T,因为考虑到肌腱布线和缠绕的空间复杂性,很难知道它们的数值。相反,我们会自动计算 L 0 和 L T 如下。上述长度范围计算已经提供了 L T+L M 的工作范围。此外,我们还要求用户指定肌肉长度 L M 的工作范围,该范围由常数 L 0(仍然未知)缩放。现在我们可以利用实际范围和缩放范围必须相互映射这一事实来计算这两个常数:

L_0%26%3D%5Cmathrm%7Brange%7D%5B1%5D%5Cend%7Baligned%7D

        在运行时,我们按以下方式计算按比例缩放的肌肉长度和速度:

L_0%5Cend%7Baligned%7D

        缩放量的优势在于所有肌肉在该表示法中的表现相似。许多实验论文中测得的力-长度-速度(FLV)函数可以捕捉到这种行为。我们将该函数近似如下:

aacf3e5951fd4909990d7102755709bf.png

        函数的形式是

eq?%5Coperatorname%7BFLV%7D%28L%2CV%2C%5Cmathsf%7Bact%7D%29%3DF_L%28L%29%5Ccdot%20F_V%28V%29%5Ccdot%5Cmathsf%7Bact%7D&plus;F_P%28L%29

        与 MuJoCo 激励器的一般形式相比,我们发现 F L⋅F V 是激励器增益,F P 是激励器偏置。FL 是作为长度函数的主动力,而 F V 是作为速度函数的主动力。二者相乘即可得到总的主动力(注意按 act 缩放,act 是致动器的激活力)。F P 是被动力,无论启动与否都始终存在。FLV 函数的输出是缩放肌力。我们将缩放力乘以肌肉特定常数 F 0,以获得实际力:

eq?%5Ctext%7Bactuator%5C_force%7D%3D-%5Cmathrm%7BFLV%7D%28L%2CV%2C%5Cmathtt%7Bact%7D%29%5Ccdot%20F_0

        负号是因为正向肌肉激活会产生拉力。常数 F 0 是零速度时的峰值作用力。它与肌肉厚度(即生理横截面积或 PCSA)有关。如果已知,可通过元素肌肉的属性力进行设置。如果不知道,我们将其默认设置为-1。在这种情况下,我们所依赖的事实是,较大的肌肉往往作用于移动重量较大的关节。属性标度将这种关系定义为

actuator%20-acc%7D0

。。。。。。省略(肌肉因为暂时用不到,眼花了,暂时不翻译了) 

2.10 传感器

        MuJoCo 可仿真各种传感器,如下文传感器元素所述。也可定义用户传感器类型,并通过回调 mjcb_sensor 进行评估。传感器不会影响仿真。相反,它们的输出会复制到数组 mjData.sensordata 中,供用户处理。

        在此,我们将描述所有传感器类型共有的 XML 属性,以避免以后重复。

name:字符串,可选
        传感器名称。

noise:实数,"0"
        启用传感器噪声属性标志后,添加到传感器输出中的零均值高斯噪声的标准偏差。传感器噪声尊重传感器数据类型:四元数和单位矢量保持归一化,非负量保持非负。

截止值:实数,"0
        当此值为正时,它将限制传感器输出的绝对值。它也用于对 simulate.cc 中传感器数据图中的传感器输出进行归一化处理。

user:real(nuser_sensor), "0 0 ..."
        请参阅用户参数。

2.11 摄像机

        除了默认的、用户可控的自由摄像机外,"固定 "摄像机也可附加到运动学树上。

外在参数
        默认情况下,摄像机坐标系会附加到包含的主体上。可选的模式和目标属性可用于指定摄像机跟踪(与主体一起移动)或瞄准(观察)主体或子树。摄像机朝向摄像机坐标系的负 Z 轴,而正 X 轴和正 Y 轴分别对应图像平面的右侧和上侧。

内在参数
        摄像机本征使用 ipd(瞳孔间距,立体渲染和 VR 所需的距离)和 fovy(垂直视场角,单位为度)来指定。

        上述规范意味着完美的点阵相机没有像差。然而,在校准实际相机时,可以使用标准渲染管道表达两种线性像差。第一种是垂直和水平方向的焦距不同(轴对齐散光)。第二种是非中心主点。这些都可以使用焦点和主点属性来指定。使用这些校准相关属性时,还必须指定物理传感器尺寸和摄像机分辨率。在这种情况下,可以直观地看到渲染球面。

2.12 复合对象

        复合对象不是新的模型元素。相反,它们是现有元素的(大型)集合,旨在仿真粒子系统、绳索、布料和柔性体。这些集合由模型编译器自动生成。用户可以使用新的 XML 元素复合体及其属性和子元素对自动生成器进行高级配置,详见 XML 参考章节。如果保存编译后的模型,复合元素就不再存在,取而代之的是自动生成的常规模型元素集合。因此,可以把它看作是由模型编译器扩展的宏。

        复合对象由常规的 MuJoCo 主体组成,在这里我们称之为 "元素主体"。元素体是作为复合对象所在体的子体创建的;因此,复合对象会出现在 XML 中定义常规子体的相同位置。每个自动生成的元素体都附有一个几何体,通常是一个球体,但也可能是一个囊体或椭圆体。因此,复合物体本质上是一个粒子系统,但粒子可以通过仿真各种柔性物体的方式一起移动。元素体的初始位置在一维、二维或三维中形成一个规则的网格。它们都可以是父体(可以是世界或另一个规则体;复合对象不能嵌套)的子体,并具有允许相对于父体运动的关节,或者它们可以形成一个运动树,元素体之间具有关节。它们还可以用肌腱连接起来,肌腱长度上有柔性相等约束,形成必要的耦合。在某些情况下也会使用关节相等约束。用户可以调整这些相等约束的 solref 和 solimp 属性,从而调整复合对象的柔性和弹性。

        除了设置物理特性外,复合对象生成器还能创建合适的渲染。二维和三维对象都可以渲染为皮肤。表皮是自动生成的,可以使用双立方体插值进行纹理和细分。实际的物理效果,尤其是碰撞检测,都是基于元素体及其几何体,而表皮则纯粹是一个可视化对象。但在大多数情况下,我们更愿意看到皮肤的表现。为方便起见,生成器会将所有几何体、场地和肌腱归入组 3,默认情况下可视化将被禁用。因此,举例来说,当您加载一个 2D 网格时,您将看到一个连续的柔性表面,而不是一个与筋相连的球体集合。不过,在微调模型并试图理解其背后的物理原理时,渲染球体和腱是非常有用的。要切换渲染风格,请禁用皮肤渲染,并启用第 3 组来渲染球体和筋腱。

        在设计复合对象生成器时,我们尽可能采用直观的高级控制,但同时也提供了大量选项,这些选项之间会相互影响,并对生成的物理效果产生深远影响。因此,用户应该仔细阅读参考文档。作为快速入门,MuJoCo 提供了每种复合对象类型的示例。下面我们将详细介绍这些示例,并解释其中不太明显的地方。在所有示例中,我们都有一个包含在模型中的静态场景,然后是一个单一的复合对象。静态场景有一个 mocap 主体(大胶囊),可以用鼠标移动来探测系统的行为。下面的 XML 片段只是复合对象的定义;完整示例请参阅发行版中的 XML 模型文件。

2.12.1 粒子 Particle.

456450347beb47bb9a0501e6a079abb0.png1401fc4da5e84e71b5befab4e514cba6.png

  1. <worldbody>
  2. <composite type="particle" count="10 10 10" spacing="0.07" offset="0 0 1">
  3. <geom size=".02" rgba=".8 .2 .1 1"/>
  4. </composite>
  5. </worldbody>

        只需使用上述 XML 即可创建一个包含 1000 个粒子的系统,粒子的初始位置为 10-10-10 网格,并可设置粒子的大小、颜色、间距和偏移量。生成的元素体将成为世界体的子元素。人们还可以调整许多其他属性,包括触点的柔性和关节属性。右图显示了关节。每个元素体都有 3 个正交的滑块关节,可以平移但不能旋转。我们的想法是,粒子应该有位置,但没有方向。MuJoCo 主体总是有方向的,但通过只使用滑块关节,我们不允许改变方向。我们会自动调整几何体的默认设置,使它们相互之间以及与模型的其他部分无摩擦接触。因此,该系统有 1000 个体(每个体都有一个 geom)、3000 个自由度和大约 1000 个活动触点。在现代处理器的单核上评估动态效果大约需要 1 毫秒。与其他大多数 MuJoCo 模型一样,柔性约束允许在更大的时间步长下进行仿真(该模型在 30 毫秒时间步长甚至更高的时间步长下都很稳定)。

        粒子还与被动力 2D 和 3D 插件兼容,这将在可变形部分讨论。不过,碰撞仅限于粒子本身,而不是包围粒子的整个表皮边界。这使得接触速度非常快,但并不能保证避免所有穿透。如需了解更全面的处理方法,请再次参阅 "可变形 "部分,其中概述了如何使用 flexcomp 创建此类对象。将使用复合粒子创建的模型移植到可弯曲模型中也很容易,请参阅文件夹 elasticity/(弹性/)中的多个示例。

2.12.2 1D 网格。1D grid.

62ee3495bf804a8493586b5043f2f215.pngd4942d3375c64181aa4a1ee6371b6d88.png

  1. <composite type="grid" count="20 1 1" spacing="0.045" offset="0 0 1">
  2. <joint kind="main" damping="0.001"/>
  3. <tendon kind="main" width="0.01"/>
  4. <geom size=".02" rgba=".8 .2 .1 1"/>
  5. <pin coord="1"/>
  6. <pin coord="13"/>
  7. </composite>

        网格类型可以创建一维或二维网格,具体取决于计数属性。在此,我们以一维网格为例进行说明。这些网格是用筋连接的球串,其长度受柔性-质量限制。柔性可以调整。与粒子类似,这里的元素体也有滑动接头,但没有旋转接头。右图展示了销钉。销钉子元素用于指定销钉体的网格坐标,模型编译器不会为这些体生成关节,从而将它们刚性固定在父体(在本例中为世界)上。这使得右图中的字符串悬挂在空间中。例如,同样的机制也可以用来制作鞭子模型;在这种情况下,父体会移动,而第一个元素体会固定在父体上。

2.12.3 2D grid.

5e164719ce324d639782bb3058295a96.png8aa2c84bf8c34367b78cd3803d3403e4.png

  1. <composite type="grid" count="9 9 1" spacing="0.05" offset="0 0 1">
  2. <skin material="matcarpet" inflate="0.001" subgrid="3" texcoord="true"/>
  3. <geom size=".02"/>
  4. <pin coord="0 0"/>
  5. <pin coord="8 0"/>
  6. </composite>

        二维网格可用于仿真布料。它真正仿真的是一个由球体组成的 2D 网格,球体之间用平等约束的筋连接(未显示)。模型编译器还可以生成皮肤,可通过上述 XML 中的皮肤子元素启用。一些元素体也可以被钉住,与一维网格类似,但使用两个网格坐标。右图显示的是一块布被固定在世界体的两个角上,并悬挂在我们的胶囊探针上。右侧的皮肤使用双立方体插值法进行细分,在没有纹理的情况下可以提高视觉质量。有纹理时(左图),细分的好处就不那么明显了。

2.12.4 Cable.

745cefd3c5984f6ca46a6e0279ac7f97.png

  1. <extension>
  2. <plugin plugin="mujoco.elasticity.cable"/>
  3. </extension>
  4. <worldbody>
  5. <composite prefix="actuated" type="cable" curve="cos(s) sin(s) s" count="41 1 1"
  6. size="0.25 .1 4" offset="0.25 0 .05" initial="none">
  7. <plugin plugin="mujoco.elasticity.cable">
  8. <!--Units are in Pa (SI)-->
  9. <config key="twist" value="5e8"/>
  10. <config key="bend" value="15e8"/>
  11. <config key="vmax" value="0"/>
  12. </plugin>
  13. <joint kind="main" damping="0.15" armature="0.01"/>
  14. <geom type="capsule" size=".005" rgba=".8 .2 .1 1"/>
  15. </composite>
  16. </worldbody>

        缆线仿真的是具有扭曲和弯曲刚度的不可拉伸一维弹性物体。它是通过一系列胶囊或盒子离散化的。它的刚度和惯性属性是根据给定参数和横截面形状直接计算得出的,因此可以实现各向异性行为,例如在皮带或计算机电缆中可以发现的行为。它是一棵单一的运动树,因此在不使用额外约束的情况下是完全不可扩展的,从而可以使用较大的时间步长。弹性模型在几何上是精确的,基于计算中心线的毕肖普或无扭转坐标系,即通过横截面中心的线。几何体的方向相对于该坐标系表示,然后分解为扭转和弯曲部分,因此可以独立设置不同的刚度。此外,还可以指定无应力配置是平面还是曲线,例如螺旋弹簧。拉索需要使用第一方引擎插件,将来可能会直接集成到引擎中。

2.12.5 绳索和绳圈

        绳索和绳圈已被弃用。建议使用缆绳仿真弯曲和扭曲的不可拉伸弹性杆,使用一维挠性变形对象仿真拉伸加载场景中的可拉伸弦(如拉伸的橡皮筋)。

2.12.6 布

布已废弃。建议使用二维可弯曲变形对象来仿真薄弹性结构。

2.12.7 盒子 box

3c1df1f63e794285bb899b41bf4ccf60.pngd1d8335c4aed402ea3cd352bc7185944.png

  1. <body pos="0 0 1">
  2. <freejoint/>
  3. <composite type="box" count="7 7 7" spacing="0.04">
  4. <skin texcoord="true" material="matsponge" rgba=".7 .7 .7 1"/>
  5. <geom type="capsule" size=".015 0.05" rgba=".8 .2 .1 1"/>
  6. </composite>
  7. </body>

        方框类型以及下面的圆柱体和椭圆体类型都用于模拟柔性三维物体。元素体沿外壳形成网格,因此元素体的数量与线性维度的平方成比例。这比仿真三维网格要有效得多。复合体所在的父体位于柔性物体的中心。所有元素体都是母体的子体。每个元素体都有一个滑动连接点,该连接点远离母体。这些关节允许软性物体的表面在任意点压缩和膨胀。为了保持形状,这些关节都受到初始位置的相等约束。此外,每个关节与相邻关节之间都有相等约束,因此当柔性物体发生变形时,变形是平滑的。最后,还有一个腱相等约束,规定所有关节的总和应保持不变。这试图近似地保持柔性物体的体积。如果物体受到来自四面八方的挤压,它就会被压缩,体积就会减小,否则一些元素体就会伸出来补偿其他地方的挤压。左侧的图显示了这种效果;我们使用胶囊探针压缩了一个角,立方体相对的两侧就会膨胀一些,而变形仍保持平滑。计数属性决定了每个维度中元素体的数量,因此如果计数不同,生成的对象将是一个矩形盒子而不是立方体。连接到元素体的几何体可以是球体、胶囊或椭圆体。球体在碰撞检测时速度更快,但会导致外壳变薄,使其他物体 "钻入 "柔性物体的 "皮肤"。使用胶囊或椭圆体时,它们会自动调整方向,使长轴指向外部,从而形成较厚的外壳,不易被穿透。

2.12.8 圆柱体和椭圆体

aed15388b2e34fbc8bf071321dc34353.pngd5085799491b46b7872dfe5739b12443.png

  1. <body pos="0 0 1">
  2. <freejoint/>
  3. <composite type="ellipsoid" count="5 7 9" spacing="0.05">
  4. <skin texcoord="true" material="matsponge" rgba=".7 .7 .7 1"/>
  5. <geom type="capsule" size=".015 0.05" rgba=".8 .2 .1 1"/>
  6. </composite>
  7. </body>

        圆柱体和椭圆体的创建方式与方框相同。唯一的区别是,元素体的参考位置(相对于父体)被投影到圆柱体或椭圆体上,其大小由计数属性暗示。自动皮肤生成器可以识别光滑表面,并相应调整皮肤法线。在图中,我们使用胶囊探针按压每个肢体,然后暂停仿真并将探针移开(这是可能的,因为探针是一个可以独立于物理特性移动的 mocap 肢体)。通过这种方式,我们可以看到探针造成的压痕以及由此导致的身体其他部分的变形。通过改变将柔性物体固定在一起的相等约束的 solref 和 solimp 属性,我们可以调整系统的行为,使其变得更软或更硬、有阻尼或有弹性等。请注意,箱体、圆柱体和椭圆体对象不涉及长运动链,可以在较大的时间步长下进行仿真--这与粒子和网格类似,而与绳索和布料不同。

2.13 可变形对象

        前面描述的复合物体旨在在实际上是刚体仿真器的情况下模拟柔性体。由于 MuJoCo 的约束条件是柔性的,这一点成为可能,但尽管如此,它的功能和建模能力还是受到了限制。在 MuJoCo 3.0 中,我们引入了涉及新模型元素的真正可变形对象。前面描述的皮肤实际上就是这样一个元素,但它只是用于可视化。现在,我们有了一个相关的元素 flex,它可以根据需要产生接触力、约束力和被动力,为各种可变形实体建模。现在,皮肤和柔性都定义在 XML 中一个名为 "可变形 "的新分组元素中。柔性是一种低级元素,可指定运行时所需的一切,但在建模时很难设计。为了帮助建模,我们进一步引入了元素 flexcomp,它可以自动创建低级柔性,类似于 composite 可以自动创建模拟柔性体所需的 MuJoCo 对象(集合)。柔性体最终可能会取代复合体,但目前两者的用途略有不同。

        柔性体是用无质量可伸缩元素连接的 MuJoCo 体的集合。这些元素可以是胶囊(一维柔性体)、三角形(二维柔性体)或四面体(三维柔性体)。在所有情况下,我们都允许有一个半径,这使得元素在一维和二维中既平滑又有体积感。原始元素如下图所示:

541e833a012d42deaf4e2ea8608f301b.png

        到目前为止,它们看起来就像几何体。但关键区别在于它们会变形:当体(顶点)相互独立移动时,元素的形状会发生实时变化。现在,碰撞和接触力已通用于处理这些可变形的几何元素。请注意,当两个此类元素发生碰撞时,接触不再只涉及两个体,而是可能涉及多达 8 个体(如果两个元素都是四面体)。接触力的计算方法和以前一样,给定接触坐标系和以该坐标系表示的相关量。但是,接触力会在所有相互作用体之间分配。接触雅各布的概念比较复杂,因为不能认为接触点在任何体坐标系中都是固定的。相反,我们使用加权方案将每个接触点 "分配 "给多个体。通过将所有顶点分配给同一个体,也可以创建刚性柔体。这是一种重新利用新的柔性碰撞机制来实现刚性非凸网格碰撞的方法(与网格几何体不同,后者是为了碰撞目的而进行凸化的)。

2.13.1 变形模型。

        为了保持柔性的形状(在软性意义上),我们需要生成被动力或约束力。在 MuJoCo 3.0 之前,这需要大量的肌腱以及对肌腱和关节的约束。在这里这仍然是可能的,但在挠度较大时,建模和仿真的效率都很低。取而代之的是,设计理念是使用单一参数集,并提供两种建模选择:一种是适用于给定挠度所有边缘的新(柔性)相等约束类型,它允许大时间步长;另一种是离散连续体表示法,其中每个元素都处于恒定应力状态,它等同于分片线性有限元,实现了更高的逼真度和精确度。基于边缘的模型可视为 "叠加 "刚度模型,其中变形模式(如剪切和体积)的正确耦合被平均到一个单一的量中。而连续体模型则可以使用材料的泊松比分别指定剪切刚度和体积刚度。更多详情,请参阅 Saint Venant-Kirchhoff 超弹性模型。该功能目前基于 MuJoCo 3.0 的第一方引擎插件,但可能会在未来版本中集成到引擎中。

创建和可视化。

  1. <option timestep=".001"/>
  2. <extension>
  3. <plugin plugin="mujoco.elasticity.solid"/>
  4. </extension>
  5. <worldbody>
  6. <flexcomp type="grid" count="24 4 4" spacing=".1 .1 .1" pos=".1 0 1.5"
  7. radius=".0" rgba="0 .7 .7 1" name="softbody" dim="3" mass="7">
  8. <contact condim="3" solref="0.01 1" solimp=".95 .99 .0001" selfcollide="none"/>
  9. <edge damping="1"/>
  10. <plugin plugin="mujoco.elasticity.solid">
  11. <config key="poisson" value="0.2"/>
  12. <!--Units are in Pa (SI)-->
  13. <config key="young" value="5e4"/>
  14. </plugin>
  15. </flexcomp>
  16. </worldbody>

        使用 flexcomp 元素,我们可以从网格(包括四面体网格)创建挠性体,自动生成所有体/顶点,并用合适的元素将它们连接起来。我们还可以自动创建网格和其他拓扑结构。有了这套设备,我们就可以轻松创建涉及数千甚至数万个体、元素和边的超大挠曲。显然,这样的仿真速度不会很快。即使是中等规模的挠性体,剪切碰撞对也是必不可少的。因此,我们开发了精心设计的自碰撞修剪方法,请参见 XML 参考文献。

        对于由四面体组成的三维挠性体,检查挠性体的内部 "三角化 "情况可能会有所帮助。我们有一种特殊的可视化模式,可以剥离外层。下面是斯坦福兔子的示例。请注意,它的外层是较小的四面体,而内层是较大的四面体。这种网格设计是合理的,因为我们希望碰撞表面是精确的,但在内部我们只需要柔性材料属性--这对空间分辨率的要求较低。为了将曲面网格转换为四面体网格,我们推荐使用 fTetWild 库等开放式工具。

e33eb509a307451999c266eb20fb1671.pngb3d7f2f1539942d18076bbdcbda806a1.png

 

2.14 包含文件 Including files

        MJCF 文件可以使用 include 元素包含其他 XML 文件。从机制上讲,解析器会将主文件中与包含元素相对应的 DOM 节点替换为主文件中作为包含文件中顶级元素子元素的 XML 元素列表。顶层元素本身会被丢弃,因为它是 XML 的分组元素,如果包含在内,就会违反 MJCF 格式。

        此功能可实现模块化 MJCF 模型;请参阅模型库中的 MPL 模型系列。模块化的一个例子是构建一个机器人模型(往往很复杂),然后将其包含在多个 "场景 "中,即定义机器人环境中对象的 MJCF 模型。另一个例子是创建一个包含常用资产(例如经过精心调整的 rgba 值的材料)的文件,并将其包含在引用这些资产的多个模型中。

        包含的文件本身并不需要是有效的 MJCF 文件,但它们通常都是有效的。事实上,我们设计这一机制是为了让 MJCF 模型包含在其他 MJCF 模型中。为了实现这一点,我们允许重复的 MJCF 部分,即使这在单一模型的语境中语义上并不合理。例如,我们允许运动树有多个根(即多个世界体元素),并由解析器自动合并。否则,将机器人纳入场景将是不可能的。

        重复 MCJF 部分的灵活性是有代价的:适用于整个模型的全局设置,例如编译器的角度属性,可以定义多次。MuJoCo 允许这样做,并在处理完所有包含元素后,使用复合模型中遇到的最后一个定义。因此,如果模型 A 是以度为单位定义的,而模型 B 是以弧度为单位定义的,并且 A 被包含在 B 中的编译器元素之后,那么整个复合模型将被视为是以度为单位定义的--在这种情况下会导致不良后果。用户必须确保相互包含的模型在这个意义上是兼容的;局部坐标与全局坐标是另一个兼容要求。

        最后,正如接下来所解释的,元素名称在所有相同类型的元素中必须是唯一的。因此,举例来说,如果两个模型中使用了相同的 geom 名称,而其中一个模型包含在另一个模型中,这将导致编译错误。多次包含同一个 XML 文件会导致解析错误。之所以有这样的限制,是因为我们希望避免重复的元素名称以及由包含引起的无限递归。

2.15 命名元素

        MJCF 中的大多数模型元素都可以命名。它们与相应 XML 元素的属性名称一起定义。当一个给定的模型元素被命名时,它的名称必须在所有相同类型的元素中是唯一的。名称区分大小写。名称在编译时用于引用相应的元素,在运行时也会保存在 mjModel 中,以方便用户使用。

        名称通常是一个可选属性。我们建议不定义它(以缩短模型文件),除非有特殊原因需要定义它。这样的原因可能有几个:

  • 有些模型元素在创建时需要引用其他元素。例如,空间筋需要引用站点,以指定其通过的经点。引用只能通过名称进行。需要注意的是,资产存在的唯一目的就是被引用,因此它们必须有一个名称,但可以省略,并从相应的文件名中隐含设置。
  • 可视化器提供了对给定类型的所有模型元素进行标注的选项。如果有名称,就会打印在三维视图中对象的旁边;否则就会打印一个格式为 "body 7 "的通用标签。
  • 函数 mj_name2id 返回具有给定类型和名称的模型元素的索引。反之,函数 mj_id2name 则返回给定索引的名称。这对于涉及模型元素的自定义计算非常有用,因为模型元素是通过 XML 中的名称来识别的(而不是依赖于一个固定的索引,因为索引会在编辑模型时发生变化)。
  • 通过命名某些元素,模型文件原则上可以变得更易阅读。但请记住,XML 本身也有注释机制,而且这种机制更适合实现可读性,尤其是大多数文本编辑器都提供了语法高亮功能,可以检测 XML 注释。

2.16 URDF 扩展

        统一机器人描述格式(URDF)是一种流行的 XML 文件格式,许多现有的机器人都是用这种格式建模的。因此,尽管 URDF 只能代表 MuJoCo 中可用的模型元素的一部分,我们还是对其提供了支持。除了标准的 URDF 文件外,MuJoCo 还可以加载将自定义(从 URDF 的角度来看)mujoco 元素作为顶级元素机器人的子元素的文件。这种自定义元素可以有编译器、选项、尺寸等子元素,其功能与 MJCF 中的相同,只是默认的编译器设置做了修改,以适应 URDF 建模约定。事实证明,编译器扩展非常有用,事实上,它的几个属性之所以被引入,是因为许多现有的 URDF 模型都有非物理动力学参数,如果不对这些参数进行修改,MuJoCo 的内置编译器将拒绝接受这些参数。指定网格目录也需要这个扩展。

        请注意,虽然 MJCF 模型是由解析器根据自定义 XML 模式检查的,但 URDF 模型不是。即使是嵌入 URDF 文件中的 MuJoCo 特定元素也不会被检查。因此,输入错误的属性名称会被默默忽略,如果错字没有被发现,就会造成严重的混乱。

        下面是一个 URDF 模型扩展部分的示例:

  1. <robot name="darwin">
  2. <mujoco>
  3. <compiler meshdir="../mesh/darwin/" balanceinertia="true" discardvisual="false"/>
  4. </mujoco>
  5. <link name="MP_BODY">
  6. ...
  7. </robot>

        上述扩展使 URDF 更好用,但仍有局限性。如果用户想充分利用 MuJoCo 建立模型,同时保持 URDF 的兼容性,我们建议采用以下步骤。根据需要在 URDF 中引入扩展,加载并保存为 MJCF。然后尽可能使用 include 元素向 MJCF 添加信息。这样,如果 URDF 被修改,相应的 MJCF 就可以很容易地重新创建。不过,根据我们的经验,URDF 文件往往是静态的,而 MJCF 文件经常会被编辑。因此,在实践中,通常只需将 URDF 转换为 MJCF 一次,之后只需使用 MJCF 即可。

2.17 MoCap 体

        mocap 体是世界的静态子体(即没有关节),其 mocap 属性设置为 "true"。它们可用于将来自动作捕捉设备的数据流输入到 MuJoCo 仿真中。假设你正拿着一个 VR 控制器,或一个装有动作捕捉标记(如 Vicon)的物体,并想让一个仿真物体以同样的方式移动,同时还与其他仿真物体进行交互。这里有一个两难的问题:虚拟物体无法推动你的物理手,因此你的手(以及你正在控制的物体)可能会违反仿真物理原理。但同时我们又希望所产生的仿真结果是合理的。我们该如何做到这一点呢?

        第一步是在 MJCF 模型中定义一个 mocap body,并执行代码在运行时读取数据流,将 mjModel.mocap_pos 和 mjModel.mocap_quat 设置为从动作捕捉系统接收到的位置和方向。simulate.cc 代码示例使用鼠标作为动作捕捉设备,允许用户移动 mocap 主体:

6e58db5c94744e139c3cb630a14db937.gif

        我们需要了解的关于 mocap 主体的关键一点是,仿真器将它们视为固定的。我们通过直接更新它们的位置和方向,使它们从一个仿真时间步移动到下一个仿真时间步,但就物理模型而言,它们的位置和方向是不变的。那么,如果我们与一个规则的动态物体接触会发生什么情况,就像在 MuJoCo 发行版提供的复合物体示例中那样(请注意,在这些示例中,我们有一个胶囊探针,它是一个用鼠标移动的模拟物体)。两个普通物体之间的接触会产生穿透力和相对速度,而与 mocap 体的接触则缺少相对速度分量,因为仿真器不知道 mocap 体本身在移动。因此,由此产生的接触力较小,而且需要更长的时间才能将动态物体推开。此外,在更复杂的仿真中,我们所做的与物理原理不一致的操作可能会导致不稳定。

        不过,还有一个更好的选择。除了模拟体外,我们还包括第二个常规体,并通过焊接相等约束将其与模拟体连接起来。在下面的图中,粉色方框是 mocap 主体,它与手的基部相连。在没有其他约束的情况下,手几乎可以完美地跟踪 mocap 本体(比弹簧减震器好得多),因为约束是隐式处理的,可以产生很大的力而不会破坏仿真的稳定性。但是,如果手被迫与桌子接触(例如右图),它就无法同时遵守接触约束和跟踪模拟体。这是因为模拟体可以自由穿过桌面。那么哪个约束条件更有利呢?这取决于焊接约束相对于接触约束的柔性。需要调整相应的 solref 和 solimp 参数,以实现所需的权衡。请参阅 MuJoCo 论坛上提供的模块化义肢 (MPL) 手部模型,以了解示例;下面的曲线图就是使用该模型生成的。

10d03e8ae3a4493d90bd0baadca06655.png49113c34369a4d63a9913fa9d7ded7cb.png

 

2.18 内存分配

        MuJoCo 在 mjData 中预先分配了运行时所需的所有内存,在创建模型后不会访问堆分配器。mjData 中的内存由 mj_makeData 以两个连续块的形式分配:

  • mjData.buffer 包含固定大小的数组。
  • mjData.arena 包含动态大小的数组。

        在 arena 内存空间中分配了两种类型的动态数组。

  • 与联系人和约束相关的数组从竞技场开始布置。
  • 堆栈数组从竞技场的末端开始分配。

        通过从竞技场空间两侧分配动态数量,可变大小的内存分配由一个数字控制:大小 MJCF 元素的内存属性。与缓冲区中的固定大小数组不同,竞技场中的可变大小数组可以是 NULL,例如在调用 mj_resetData 之后。当竞技场内存耗尽时,会发生三种情况之一,具体取决于所请求的内存类型:

  • 如果内存在触点分配过程中耗尽,系统将发出警告,并且不会在此步骤中添加后续触点,但仿真仍会照常进行。
  • 如果在与约束相关的分配过程中内存耗尽,则会发出警告,并在此步骤中禁用约束求解器,但仿真仍照常进行。需要注意的是,没有约束求解器的物理效果通常会有很大不同,但允许仿真继续进行仍然是有用的,例如在场景初始化过程中,当许多物体暂时重叠时。
  • 如果在堆栈数组分配过程中内存耗尽,就会出现硬性错误。

        与缓冲区的大小不同,竞技场的大小是无法预先计算的,因为接触点的数量和堆栈的使用情况是无法预先知道的。那么应该如何选择呢?目前使用的是以下简单的启发式方法,不过将来可能会有所改进:在最坏情况下,为 100 个触点和 500 个标量约束分配足够的内存。如果这个启发式不够,我们建议采用以下程序。使用内存属性大幅增加竞技场内存,并检查运行时实际使用的内存。mjData.maxuse_arena 会记录上次重置后竞技场内存的最大使用率。仿真查看器会将这个数字显示为竞技场总空间的一部分(在左下角的信息窗口中)。因此,我们可以从一个较大的数字开始,仿真一段时间,如果分数较小,就返回 XML 并减少分配大小。不过请记住,内存利用率在仿真过程中会发生很大变化,这取决于有多少约束处于活动状态以及使用了哪种约束求解器。CG 求解器的内存效率最高,其次是牛顿求解器,而 PGS 求解器的内存占用率最高。我们在设计模型时,通常会将探索模型时遇到的最坏情况下的利用率设定为 50%。如果只打算使用 CG 求解器,则可以大大减少舞台分配。

注意事项

        在 MuJoCo 2.3.0 中,内存分配行为发生了变化。在此版本之前,大小 MJCF 元素的 njmax、nconmax 和 nstack 属性分别具有为触点、约束和堆栈分配最大内存的语义。如果您使用的是较早版本的 MuJoCo,请切换到较早版本的文档以了解以前的行为。

三、技巧和窍门

        在此,我们将就如何完成一些常见建模任务提供指导。这里没有新材料,因为本节中的所有内容都可以从文档的其他部分推断出来。尽管如此,推理过程并不总是显而易见的,因此将其详细说明可能会有所帮助。

3.1 反冲力

        许多机器人关节都存在间隙。它通常是由齿轮箱中齿轮之间的微小间隙造成的,但也可能是由关节机构中的某些马虎造成的。其影响是,电机可以在关节转动之前转动一个小角度,反之亦然(当关节上施加外力时)。反向间隙可在 MuJoCo 中进行如下建模。在机身内定义两个位置和方向相同的铰链关节,而不是一个铰链关节:

  1. <body>
  2. <joint name="J1" type="hinge" pos="0 0 0" axis="0 0 1" armature="0.01"/>
  3. <joint name="J2" type="hinge" pos="0 0 0" axis="0 0 1" limited="true" range="-1 1"/>
  4. </body>

        因此,车身相对于其母体的整体旋转角度为 J1+J2。现在定义一个仅作用于 J1 的致动器。J2 上的关节范围较小,使其接近于 0,但允许其在作用力的方向上移动一些,从而产生反向间隙效果。注意 J1 中的电枢属性。如果没有它,关节空间惯性矩阵将是奇异的,因为两个关节可以向相反方向加速而不会遇到任何惯性。造成反向间隙的物理齿轮实际上具有转动惯量(我们称之为电枢),因此这是一种现实的建模方法。本示例中的数字应加以调整,以获得所需的行为。还可以调整联合限制约束的 solref 和 solimp 参数,使反向间隙旋转以较软或较硬的限制结束。

        我们可以指定一个保持 J2=0 的柔性相等约束,而不是在 J2 中指定关节限位。然后应调整约束阻抗函数,使约束在 J2=0 附近较弱,在远离 0 的地方变强。与关节限位相比,相等约束方法将在反向间隙机制和限位机制之间产生更柔和的过渡。它还将一直处于激活状态,这对于需要将违反约束条件或约束力作为输入的用户代码来说非常方便。

3.2 阻尼

        阻尼会产生一个与速度成正比的反向力。在物理系统中,阻尼总是能增加稳定性。但这只是因为宇宙配备了理想的连续时间积分器,不会因时间离散化而累积误差。在时间离散化的计算机仿真中,大阻尼会因积分误差而破坏系统的稳定性。这在 "计算 "一章中已经讨论过。

        减少积分误差的标准方法是减小时间步长或使用 Runge-Kutta 积分器,这两种方法都很有效,但会减慢仿真速度。另一种方法是将所有阻尼置于关节中,并使用欧拉积分器。在这种情况下,阻尼力会被隐式集成,这意味着惯性矩阵会作为速度更新的一部分在内部进行调整和重构,这种方式对用户来说是透明的。隐式积分比显式积分更稳定,时间步长也更大。请注意,Runge-Kutta 积分器是显式的,欧拉积分器也是显式的,但它处理阻尼力的方式除外。理想情况下,我们会有一个完全隐式的积分器,但目前还没有公开可用的物理引擎有这样的积分器。这已列入我们未来 MuJoCo 版本的待办事项清单。

        在这种情况下,关节阻尼比肌腱或致动器中的阻尼表现得更好,因为后者没有进行隐式积分。现在考虑一个产生力的速度伺服器:

force = gain * (desired_velocity - current_velocity)

        这可以建模为一个速度致动器,但这种致动器会增加系统的阻尼,在增益较高时可能会导致不稳定。相反,我们可以将上述力分成两个项。对于第一项,定义一个产生力 = 增益 * 预期速度的电机,将预期速度视为控制信号。对于第二项,在关节中添加阻尼,阻尼系数等于上述伺服增益。现在总的力是相同的,但力的阻尼分量是隐式积分。

3.3 恢复

        另一种指定 solref 的机制在求解器参数中已有说明。当这两个数字都不是正数时,它们会被解释为(-刚度、-阻尼),并根据约束阻抗进行缩放。要实现接触和其他约束的完美复原,可将刚度设为某个合理的大值,阻尼设为零。下面是一个球体在平面上弹跳的示例,恢复系数为 1,因此接触前后的能量大致保持不变。由于接触本身是柔性的,需要几个时间步长,而这些时间步长内的(隐含)变形并不完全保密。但总体效果是,球反弹了很长时间,其峰值高度并没有明显变化,能量围绕初始值波动,而不是漂移。

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/天景科技苑/article/detail/929770
推荐阅读
相关标签
  

闽ICP备14008679号