全局变量#
全局变量和常量的定义可分为以下几类:
错误回调#
所有用户回调(即,名称以 'mjcb' 开头的全局函数指针)初始时都设置为 NULL,这会禁用它们并允许默认处理流程执行。要安装一个回调,只需将相应的全局指针设置为一个正确类型的用户函数。请记住,这些是全局的,而非特定于模型。因此,如果您并行模拟多个模型,它们将使用同一组回调。
mju_user_error#
该函数在主错误函数 mju_error 内部被调用。安装后,此函数会覆盖默认的错误处理。一旦它打印出错误消息(或用户想做的任何其他事情),它必须退出程序。MuJoCo 的编写是基于 mju_error 不会返回的假设。如果它返回,软件的行为将是未定义的。
extern void (*mju_user_error)(const char*);
mju_user_warning#
该函数在主警告函数 mju_warning 内部被调用。它类似于错误处理器,但它必须返回而不能退出程序。
extern void (*mju_user_warning)(const char*);
内存回调#
内存回调的目的是允许用户安装自定义的内存分配和释放机制。我们发现在 MATLAB 的 MuJoCo 包装器中这是一个很有用的例子,其中 mex 文件需要使用 MATLAB 的内存机制来进行永久内存分配。
mju_user_malloc#
如果安装了此回调,MuJoCo 运行时将使用它来分配所需的所有堆内存(而不是使用对齐的 malloc)。用户分配器必须分配在 8 字节边界上对齐的内存。请注意,解析器和编译器是用 C++ 编写的,有时会使用 “new” 运算符分配内存,这会绕过此机制。
extern void* (*mju_user_malloc)(size_t);
mju_user_free#
如果安装了此回调,MuJoCo 将通过调用此函数来释放它分配的任何堆内存(而不是使用对齐的 free)。
extern void (*mju_user_free)(void*);
物理回调#
物理回调是除了设置各种选项之外,修改模拟器行为的主要机制。选项控制默认管线的操作,而回调则在明确定义的位置扩展管线。这使得高级用户能够实现许多我们没有想到的有趣功能,同时仍然利用默认管线的优势。与所有其他回调一样,这里没有自动的错误检查——我们假设回调函数的作者知道他们在做什么。
自定义物理回调通常需要 MJCF 中非标准的参数。这在很大程度上是我们提供自定义字段以及 MJCF 中用户数据数组的原因。其思想是通过输入必要的用户参数来“检测” MJCF 模型,然后编写回调函数来查找这些参数并执行相应的计算。我们强烈建议用户编写的回调函数在访问用户参数前先检查模型中是否存在这些参数——这样,当加载常规模型时,回调会自动禁用自身,而不是导致软件崩溃。
mjcb_passive#
这用于在关节空间中实现自定义的被动力;如果力在笛卡尔空间中定义更自然,请使用末端执行器雅可比矩阵将其映射到关节空间。我们所说的“被动”,并非指不做正功的力(如物理学中的定义),而仅指仅依赖于位置和速度,而不依赖于控制的力。MuJoCo 中有标准的被动力,来自弹簧、阻尼器、介质的粘性和密度。它们在调用 mjcb_passive 之前在 mjData.qfrc_passive 中计算。用户回调应该加到这个向量上,而不是覆盖它(否则标准的被动力将会丢失)。
extern mjfGeneric mjcb_passive;
mjcb_control#
这是最常用的回调。它通过写入控制向量 mjData.ctrl 来实现控制律。它也可以写入 mjData.qfrc_applied 和 mjData.xfrc_applied。写入这些向量的值可以依赖于位置、速度以及所有由它们派生的量,但不能依赖于接触力和其他在指定控制后才计算的量。如果回调访问了后者字段,它们的值将不对应于当前时间步。
控制回调在 mj_forward 和 mj_step 内部,在需要控制和施加力之前被调用。使用 RK 积分器时,每个步骤它将被调用 4 次。指定控制和施加力的另一种方法是在 mj_step 之前设置它们,或者使用 mj_step1 和 mj_step2。后一种方法允许在 mj_step1 执行完位置和速度计算后设置控制,从而可以在计算控制时利用这些结果(类似于使用 mjcb_control)。然而,在 RK 积分器的子步骤之间改变控制的唯一方法是定义控制回调。
extern mjfGeneric mjcb_control;
mjcb_contactfilter#
此回调可用于替换 MuJoCo 的默认碰撞过滤。安装后,对于每一对通过了广相测试(或在 MJCF 中预定义了几何体对)并且是近相碰撞候选的几何体,都会调用此函数。默认处理使用 contype 和 conaffinity 掩码、父子过滤器以及与焊接体相关的一些其他考虑来决定是否应允许碰撞。此回调替换了默认处理,但请记住,整个机制都被替换了。因此,例如,如果您仍想利用 contype/conaffinity,您必须在回调中重新实现它。
extern mjfConFilt mjcb_contactfilter;
mjcb_sensor#
此回调填充 mjData.sensordata 中对应于用户自定义传感器的字段。如果安装了此回调并且模型包含用户自定义传感器,则会调用它。每个计算阶段(mjSTAGE_POS、mjSTAGE_VEL、mjSTAGE_ACC)调用一次,并且必须为该阶段填充所有用户传感器值。用户自定义传感器的维度和数据类型在 MJCF 模型中定义,回调必须遵守这些定义。
extern mjfSensor mjcb_sensor;
mjcb_time#
安装此回调可启用内置的性能分析器,并在 mjData.timer 中保留计时统计信息。返回类型为 mjtNum,而时间单位由用户决定。simulate.cc 假设单位是 1 毫秒。为了有用,回调应使用至少微秒精度的高分辨率计时器。这是因为被计时的计算非常快。
extern mjfTime mjcb_time;
mjcb_act_dyn#
此回调实现自定义的激活动态:它必须为指定的执行器返回 mjData.act_dot 的值。这是激活状态向量 mjData.act 的时间导数。对于具有用户动态(mjDYN_USER)的模型执行器,会调用它。如果模型中存在此类执行器但未安装回调,它们的时间导数将设置为 0。
extern mjfAct mjcb_act_dyn;
mjcb_act_gain#
此回调实现自定义的执行器增益:它必须为 mjModel.actuator_gaintype 设置为 mjGAIN_USER 的指定执行器返回增益。如果模型中存在此类执行器但未安装此回调,它们的增益将设置为 1。
extern mjfAct mjcb_act_gain;
mjcb_act_bias#
此回调实现自定义的执行器偏置:它必须为 mjModel.actuator_biastype 设置为 mjBIAS_USER 的指定执行器返回偏置。如果模型中存在此类执行器但未安装此回调,它们的偏置将设置为 0。
extern mjfAct mjcb_act_bias;
碰撞表#
mjCOLLISIONFUNC#
按几何体类型索引的成对碰撞函数表。仅使用右上三角部分。用户可以用自定义例程替换这些函数指针,从而替换 MuJoCo 的碰撞机制。如果给定条目为 NULL,则相应的几何体类型对不能发生碰撞。请注意,这些函数仅适用于近相碰撞。广相机制是内置的,无法修改。
extern mjfCollision mjCOLLISIONFUNC[mjNGEOMTYPES][mjNGEOMTYPES];
字符串常量#
此处描述的字符串常量为用户提供了方便。它们对应于选项列表的英文名称,可以显示在 GUI 的菜单或对话框中。代码示例 simulate.cc 说明了如何使用它们。
mjDISABLESTRING#
由 mjtDisableBit 定义的禁用位的名称。
extern const char* mjDISABLESTRING[mjNDISABLE];
mjENABLESTRING#
由 mjtEnableBit 定义的启用位的名称。
extern const char* mjENABLESTRING[mjNENABLE];
mjTIMERSTRING#
由 mjtTimer 定义的 mjData 计时器的名称。
extern const char* mjTIMERSTRING[mjNTIMER];
mjLABELSTRING#
由 mjtLabel 定义的可视化标签模式的名称。
extern const char* mjLABELSTRING[mjNLABEL];
mjFRAMESTRING#
由 mjtFrame 定义的坐标系可视化模式的名称。
extern const char* mjFRAMESTRING[mjNFRAME];
mjVISSTRING#
由 mjtVisFlag 定义的抽象可视化标志的描述。每个标志有三个字符串,
含义如下:
[0]: 标志名称;
[1]: 字符串 “0” 或 “1”,表示该标志默认是关闭还是开启,由 mjv_defaultOption 设置;
[2]: 单字符字符串,带有建议的键盘快捷键,在 simulate.cc 中使用。
extern const char* mjVISSTRING[mjNVISFLAG][3];
mjRNDSTRING#
由 mjtRndFlag 定义的 OpenGL 渲染标志的描述。每个标志的三个字符串格式与上述相同,但此处的默认值由 mjv_makeScene 设置。
extern const char* mjRNDSTRING[mjNRNDFLAG][3];
数值常量#
许多整数常量已在上面的基本类型中记录。此外,头文件还定义了此处记录的其他几个常量。除非另有说明,下表中的每个条目都在 mjmodel.h 中定义。请注意,一些扩展键码在 mjui.h 中定义,未在下表中显示。它们的名称格式为 mjKEY_XXX。它们对应于 GLFW 键码。
符号 |
值 |
描述 |
|---|---|---|
|
1E-15 |
任何分母中允许的最小值,以及通常情况下不允许为 0 的任何数学运算。在几乎所有情况下,MuJoCo 都会静默地将较小的值钳制到 mjMINVAL。 |
|
\(\pi\) |
\(\pi\) 的值。它用于各种三角函数,也用于编译器中从度到弧度的转换。 |
|
1E+10 |
mjData.qpos、mjData.qvel、mjData.qacc 中允许的最大绝对值。API 函数 mj_checkPos、mj_checkVel、mj_checkAcc 使用此常量来检测不稳定性。 |
|
1E-5 |
任何摩擦系数中允许的最小值。回想一下,MuJoCo 的接触模型允许包含不同数量的摩擦维度,由 condim 属性指定。然而,如果包含某个摩擦维度,其摩擦系数不允许小于此常量。较小的值会自动钳制到此常量。 |
|
0.0001 |
任何约束阻抗中允许的最小值。较小的值会自动钳制到此常量。 |
|
0.9999 |
任何约束阻抗中允许的最大值。较大的值会自动钳制到此常量。 |
|
50 |
每个几何体对可以生成的最大接触点数。MuJoCo 的内置碰撞函数遵守此限制,用户定义的函数也应遵守它。调用此类函数时会提供一个大小为 |
|
50 |
每个物体和网格包围体层次结构的最大深度。如果超过这个较大的限制,将发出警告,并且光线投射可能无法进行。对于一个平衡的层次结构,这意味着 1E15 个包围体。 |
|
27 |
需要 Alessio 记录的一些数字。我猜它与三线性柔性体有关? |
|
10 |
一棵树被唤醒后必须经过的最小时间步数,之后才允许它重新进入休眠状态。 |
|
11 |
用于定义每个等式约束的最大实值参数数量。决定 |
|
10 |
用于定义每个执行器激活动态的最大实值参数数量。决定 |
|
10 |
用于定义每个执行器增益的最大实值参数数量。决定 |
|
10 |
用于定义每个执行器偏置的最大实值参数数量。决定 |
|
12 |
椭球模型所需的每个几何体流体相互作用参数的数量。 |
|
2 |
用于定义每个标量约束参考加速度的最大实值参数数量。决定所有 |
|
5 |
用于定义每个标量约束阻抗的最大实值参数数量。决定所有 |
|
3 |
传感器参数的数量。决定 |
|
200 |
求解器统计信息可以存储在 |
|
20 |
求解器统计信息可以存储在 |
|
6 |
可以通过 mjvOption 启用和禁用渲染的几何体、站点、关节、肌腱和执行器组的数量。在 mjvisualize.h 中定义。 |
|
500 |
用于渲染的覆盖文本中的最大字符数。在 mjvisualize.h 中定义。 |
|
100 |
每个 2D 图形 (mjvFigure) 的最大行数。在 mjvisualize.h 中定义。 |
|
1001 |
2D 图形中每条线的最大点数。请注意,缓冲区 |
|
200 |
渲染平面时每个维度的最大网格线数。在 mjvisualize.h 中定义。 |
|
10 |
可以在 mjrContext 中分配的辅助缓冲区的数量。在 mjrender.h 中定义。 |
|
1000 |
允许的最大纹理数量。在 mjrender.h 中定义。 |
|
128 |
线程池中可以使用的最大操作系统线程数。在 mjthread.h 中定义。 |
|
10 |
UI 部分的最大数量。在 mjui.h 中定义。 |
|
200 |
每个 UI 部分的最大项目数。在 mjui.h 中定义。 |
|
500 |
UI 字段 ‘edittext’ 和 ‘other’ 中的最大字符数。在 mjui.h 中定义。 |
|
40 |
任何 UI 名称中的最大字符数。在 mjui.h 中定义。 |
|
20 |
UI 组中单选和选择项的最大数量。在 mjui.h 中定义。 |
|
5 |
UI 编辑列表中的最大元素数。在 mjui.h 中定义。 |
|
15 |
UI 矩形的最大数量。在 mjui.h 中定义。 |
|
340 |
MuJoCo 头文件的版本;每次发布都会更改。这是一个等于软件版本乘以 100 的整数,因此 210 对应于版本 2.1。在 mujoco.h 中定义。API 函数 mj_version 返回一个具有相同含义的数字,但用于已编译的库。 |
宏#
mjUSESINGLE#
编译时标志,请参阅 mjtNum。
mjDISABLED#
#define mjDISABLED(x) (m->opt.disableflags & (x))
检查某个标准功能是否已通过物理选项禁用,假设已定义 mjModel* m。x 的类型为 mjtDisableBit。
mjENABLED#
#define mjENABLED(x) (m->opt.enableflags & (x))
检查某个可选功能是否已通过物理选项启用,假设已定义 mjModel* m。x 的类型为 mjtEnableBit。
mjMAX#
#define mjMAX(a,b) (((a) > (b)) ? (a) : (b))
返回最大值。为避免对 mjtNum 类型进行重复求值,请使用函数 mju_max。
mjMIN#
#define mjMIN(a,b) (((a) < (b)) ? (a) : (b))
返回最小值。为避免对 mjtNum 类型进行重复求值,请使用函数 mju_min。
mjPLUGIN_LIB_INIT#
#define mjPLUGIN_LIB_INIT \
static void _mjplugin_dllmain(void); \
mjEXTERNC int __stdcall mjDLLMAIN(void* hinst, unsigned long reason, void* reserved) { \
if (reason == 1) { \
_mjplugin_dllmain(); \
} \
return 1; \
} \
static void _mjplugin_dllmain(void)
将插件注册为动态库。有关更多详细信息,请参阅插件注册。
X 宏#
大多数用户项目不需要 X 宏。它们在内部分配模型时使用,也可供了解如何使用此编程技术的用户使用。有关实际定义,请参见头文件 mjxmacro.h。它们在为脚本语言编写 MuJoCo 包装器时特别有用,在这种情况下,需要以编程方式构建与 MuJoCo 数据结构匹配的动态结构。