函数#

提示

点击下方的函数名称将跳转至 GitHub 仓库中的源代码实现。

主头文件 mujoco.h 暴露了大量函数。然而,大多数用户真正需要的函数仅占其中一小部分。

API 函数可分类如下:

解析并编译#

这里的关键函数是 mj_loadXML。它调用内置的解析器和编译器,返回指向有效 mjModel 的指针或 NULL(此时用户应检查用户提供的字符串中的错误信息)。模型及其引用的所有文件可以从磁盘加载,如果提供了 VFS,也可以从 VFS 加载。

mj_loadXML#

mjModel* mj_loadXML(const char* filename, const mjVFS* vfs, char* error, int error_sz);

解析 MJCF 或 URDF 格式的 XML 文件并编译;返回低级模型。

如果 vfs 不为 NULL,则在从磁盘读取前先在 vfs 中查找文件。

如果 error 不为 NULL,则其必须具有 size error_sz。

可空: vfs, error

mj_parseXML#

mjSpec* mj_parseXML(const char* filename, const mjVFS* vfs, char* error, int error_sz);

从 XML 文件解析规范。

可空: vfs, error

mj_parseXMLString#

mjSpec* mj_parseXMLString(const char* xml, const mjVFS* vfs, char* error, int error_sz);

从 XML 字符串解析规范。

可空: vfs, error

mj_parse#

mjSpec* mj_parse(const char* filename, const char* content_type,
                 const mjVFS* vfs, char* error, int error_sz);

从文件解析规范。

可空: vfs, error

mj_encode#

int mj_encode(const mjSpec* s, const mjModel* m, const char* filename,
              const char* content_type, const mjVFS* vfs, char* error,
              int error_sz);

使用已注册的编码器将规范/模型编码到文件。

成功返回写入的字节数,失败返回 -1。

可空: m, vfs, error

mj_compile#

mjModel* mj_compile(mjSpec* s, const mjVFS* vfs);

mjSpec 编译为 mjModel。规范可以被多次编辑和编译,返回一个新的 mjModel 实例,该实例考虑了编辑内容。如果编译失败,mj_compile 返回 NULL;错误信息可通过 mjs_getError 读取。

mj_copyBack#

int mj_copyBack(mjSpec* s, const mjModel* m);

将实值数组从模型复制回规范;成功返回 1。

mj_recompile#

int mj_recompile(mjSpec* s, const mjVFS* vfs, mjModel* m, mjData* d);

在保留状态的同时将规范重新编译为模型。与 mj_compile 类似,此函数将 mjSpec 编译为 mjModel,但有两点不同。首先,它不会返回全新的模型,而是原地重新分配现有的 mjModelmjData 实例。其次,它将保留提供的 mjData 实例中给出的积分状态,同时考虑新增或移除的自由度。这允许用户在以编程方式编辑模型的同时,使用相同的模型和数据结构指针继续仿真。

如果编译成功,mj_recompile 返回 0。如果失败,给定的 mjModelmjData 实例将被删除;与 mj_compile 一样,编译错误可以通过 mjs_getError 读取。

mj_saveLastXML#

int mj_saveLastXML(const char* filename, const mjModel* m, char* error, int error_sz);

使用 mj_loadXML 创建的低级模型中的信息更新 XML 数据结构,并保存为 MJCF。如果 error 不为 NULL,则必须具有 size error_sz。

注意,此函数仅保存通过传统加载机制 mj_loadXML 加载的模型。请参阅模型编辑章节,了解新旧模型加载与保存机制的区别。

mj_freeLastXML#

void mj_freeLastXML(void);

释放上次加载的 XML 模型(如有)。在每次加载时内部调用。

mj_saveXMLString#

int mj_saveXMLString(const mjSpec* s, char* xml, int xml_sz, char* error, int error_sz);

将规范保存为 XML 字符串,成功返回 0,失败返回 -1。如果输出缓冲区长度太小,则返回所需的长度。保存 XML 时会自动在保存前编译规范。

mj_saveXML#

int mj_saveXML(const mjSpec* s, const char* filename, char* error, int error_sz);

将规范保存为 XML 文件,成功返回 0,否则返回 -1。保存 XML 要求规范必须先经过编译。

mju_getXMLDependencies#

void mju_getXMLDependencies(const char* filename, mjStringVec* dependencies);

给定 MJCF 文件名,填充依赖列表,包含其依赖的所有其他资源文件。

搜索是递归的,且列表包含文件名本身。

主仿真#

这些是仿真器的主要入口点。大多数用户仅需要调用 mj_step,它会计算所有内容并将仿真状态推进一个时间步长。控制量和施加的力必须预先设置(在 mjData.{ctrl, qfrc_applied, xfrc_applied} 中),或者必须安装一个控制回调函数 mjcb_control,它会在需要控制量和外力之前被调用。或者,可以使用 mj_step1mj_step2,它们将仿真流水线分解为在需要控制量之前和之后执行的计算;通过这种方式,可以设置依赖于 mj_step1 结果的控制量。请记住,RK4 求解器不适用于 mj_step1/2。有关更详细的描述,请参见仿真流水线

mj_forward 执行与 mj_step 相同的计算,但不进行积分。它在加载或重置模型后(以使整个 mjData 处于有效状态)以及涉及采样或有限差分近似的乱序计算中非常有用。

mj_inverse 运行逆动力学,并将输出写入 mjData.qfrc_inverse。注意,在调用此函数前必须设置 mjData.qacc。给定状态(qpos, qvel, act),mj_forward 将力映射为加速度,而 mj_inverse 将加速度映射为力。在数学上,这两个函数互为逆运算,但在数值上并非总是如此,因为正向动力学依赖于通常会提前终止的约束优化算法。正向与逆向动力学结果之间的差异可以通过函数 mj_compareFwdInv 进行计算,这可被视为另一种求解器精度检查(以及一般的健全性检查)。

mj_forwardmj_inverse 的跳过版本在某些情况下很有用,例如当 qpos 未变但 qvel 发生变化时(通常在有限差分的上下文中)。此时无需重复仅依赖于 qpos 的计算。以 skipstage = mjSTAGE_POS 调用动力学即可节省计算开销。

mj_step#

void mj_step(const mjModel* m, mjData* d);

推进仿真,使用控制回调函数获取外力和控制量。

mj_step1#

void mj_step1(const mjModel* m, mjData* d);

分两步推进仿真:在用户设置外力和控制量之前。

mj_step2#

void mj_step2(const mjModel* m, mjData* d);

分两步推进仿真:在用户设置外力和控制量之后。

mj_forward#

void mj_forward(const mjModel* m, mjData* d);

正向动力学:与 mj_step 相同,但不进行时间积分。

mj_inverse#

void mj_inverse(const mjModel* m, mjData* d);

逆动力学:调用前必须设置 qacc。

mj_forwardSkip#

void mj_forwardSkip(const mjModel* m, mjData* d, int skipstage, int skipsensor);

带跳过逻辑的正向动力学;skipstage 为 mjtStage。

mj_inverseSkip#

void mj_inverseSkip(const mjModel* m, mjData* d, int skipstage, int skipsensor);

带跳过逻辑的逆动力学;skipstage 为 mjtStage。

支持#

这些支持函数需要访问 mjModelmjData,这与不需要此类访问的工具函数不同。支持函数在仿真器内部被调用,但其中一些对于自定义计算也很有用,详情见下文。

mj_stateSize#

int mj_stateSize(const mjModel* m, int sig);

返回给定状态签名所需的 mjtNum 数量。整数 sig 的位对应于 mjtState 的元素字段。

mj_getState#

void mj_getState(const mjModel* m, const mjData* d, mjtNum* state, int sig);

sig 指定的拼接状态组件从 d 复制到 state。整数 sig 的位对应于 mjtState 的元素字段。如果 sig 无效,则以 mju_error 失败。

mj_extractState#

void mj_extractState(const mjModel* m, const mjtNum* src, int srcsig,
                     mjtNum* dst, int dstsig);

从通过 mj_getState 获取的、具有 srcsig 组件的状态 src 中,提取 dstsig 指定的组件子集到 dst。如果 dstsig 中设置的位不是 srcsig 设置位的子集,则以 mju_error 失败。

mj_setState#

void mj_setState(const mjModel* m, mjData* d, const mjtNum* state, int sig);

sig 指定的拼接状态组件从 state 复制到 d。整数 sig 的位对应于 mjtState 的元素字段。如果 sig 无效,则以 mju_error 失败。

mj_copyState#

void mj_copyState(const mjModel* m, const mjData* src, mjData* dst, int sig);

将状态从 src 复制到 dst。

mj_readCtrl#

mjtNum mj_readCtrl(const mjModel* m, const mjData* d, int id, mjtNum time, int interp);

在给定时间读取执行器的控制值,并考虑延迟。如果不存在历史缓冲区,返回 mjData.ctrl[id]。如果存在历史缓冲区(nsample > 0),则使用请求的插值阶数,从延迟缓冲区在 time - actuator_delay[id] 处读取。

  • interp = 0:零阶保持(分段常数)

  • interp = 1:分段线性

  • interp = 2:三次样条(Catmull-Rom)

  • interp = -1:使用执行器的 interp 值。

在缓冲区边界之外使用常数外推。

注意,减去延迟会将 time 参数的语义从“值被推入延迟缓冲区的时间”更改为“值从延迟缓冲区输出的时间”。详情请参阅延迟

mj_readSensor#

const mjtNum* mj_readSensor(const mjModel* m, const mjData* d, int id, mjtNum time,
                            mjtNum* result, int interp);

在给定时间读取传感器值,并考虑延迟。如果不存在历史缓冲区,返回指向 mjData.sensordata 中传感器切片的指针。如果存在历史缓冲区(nsample > 0),则在 time - sensor_delay[id] 处读取。注意,减去延迟会将 time 参数的语义从“值被推入延迟缓冲区的时间”更改为“值从延迟缓冲区输出的时间”。详情请参阅延迟

返回值语义

  • 如果不存在历史缓冲区(nsample = 0),返回指向 mjData.sensordata 中传感器切片的指针。

  • 如果存在历史缓冲区(nsample > 0)且请求的时间匹配存储的样本(对于 interp = 0 总是成立),则返回指向历史缓冲区数据的指针。

  • 如果需要插值(interp = 1 2),则返回 NULL 并将插值结果写入 result(其大小必须为 dim)。

插值

  • interp = 0:零阶保持(分段常数)

  • interp = 1:分段线性

  • interp = 2:三次样条(Catmull-Rom)

  • interp = -1:使用 interp 中的值

在缓冲区边界之外使用常数外推。

用法

// read sensor 0 of data size `dim` at time t
mjtNum result[dim];
const mjtNum* ptr = mj_readSensor(m, d, 0, t, result, /* interp = */ 1);
const mjtNum* data = ptr ? ptr : result;

mj_initCtrlHistory#

void mj_initCtrlHistory(const mjModel* m, mjData* d, int id,
                        const mjtNum* times, const mjtNum* values);

使用自定义值初始化执行器的历史缓冲区。times 数组指定每个样本的时间戳(长度必须为 nsample),values 指定控制值。如果 timesNULL,则使用缓冲区中现有的时间戳,仅更新值。详情请参阅延迟

mj_initSensorHistory#

void mj_initSensorHistory(const mjModel* m, mjData* d, int id,
                          const mjtNum* times, const mjtNum* values, mjtNum phase);

使用自定义值初始化传感器的历史缓冲区。times 数组指定每个样本的时间戳(长度必须为 nsample),values 指定传感器值(大小必须为 nsample * dim)。如果 timesNULL,则使用缓冲区中现有的时间戳。phase 参数设置用户槽,用于存储间隔传感器的最后计算时间。详情请参阅延迟

mj_setKeyframe#

void mj_setKeyframe(mjModel* m, const mjData* d, int k);

将当前状态复制到第 k 个模型关键帧。

mj_addContact#

int mj_addContact(const mjModel* m, mjData* d, const mjContact* con);

将接触添加到 d->contact 列表;成功返回 0;缓冲区满返回 1。

mj_isPyramidal#

int mj_isPyramidal(const mjModel* m);

确定摩擦锥类型。

mj_isSparse#

int mj_isSparse(const mjModel* m);

确定约束雅可比矩阵类型。

mj_isDual#

int mj_isDual(const mjModel* m);

确定求解器类型(PGS 是对偶的,CG 和 Newton 是原始的)。

mj_mulJacVec#

void mj_mulJacVec(const mjModel* m, const mjData* d, mjtNum* res, const mjtNum* vec);

此函数将约束雅可比矩阵 mjData.efc_J 乘以一个向量。注意,雅可比矩阵可以是稠密的也可以是稀疏的;该函数能自动识别。乘以 J 将速度从关节空间映射到约束空间。

mj_mulJacTVec#

void mj_mulJacTVec(const mjModel* m, const mjData* d, mjtNum* res, const mjtNum* vec);

与 mj_mulJacVec 相同,但乘以雅可比矩阵的转置。这会将力从约束空间映射到关节空间。

mj_jac#

void mj_jac(const mjModel* m, const mjData* d, mjtNum* jacp, mjtNum* jacr,
            const mjtNum point[3], int body);

此函数计算末端执行器的运动学雅可比矩阵,描述自由度与给定点之间的局部线性关系。给定由整数 id(body)指定的物体,以及视为附着在该物体上的世界坐标系中的 3D 点(point),雅可比矩阵包含平移(jacp)和旋转(jacr)分量。为任一指针传递 NULL 将跳过该部分的计算。每个分量都是 3-by-nv 矩阵。该矩阵的每一行是指定点的对应坐标相对于自由度的梯度。雅可比矩阵计算所参考的坐标系以物体质心为中心,但与世界坐标系对齐。为使雅可比计算与当前的广义位置 mjData.qpos 一致,所需的最小流水线阶段mj_kinematics 随后是 mj_comPos

可空: jacp, jacr

mj_jacBody#

void mj_jacBody(const mjModel* m, const mjData* d, mjtNum* jacp, mjtNum* jacr, int body);

此函数及后续的雅可比函数变体在内部调用 mj_jac,并使用物体、几何体或站点的中心。它们只是快捷方式;直接调用 mj_jac 即可实现相同功能。

可空: jacp, jacr

mj_jacBodyCom#

void mj_jacBodyCom(const mjModel* m, const mjData* d, mjtNum* jacp, mjtNum* jacr, int body);

计算物体质心末端执行器雅可比矩阵。

可空: jacp, jacr

mj_jacSubtreeCom#

void mj_jacSubtreeCom(const mjModel* m, mjData* d, mjtNum* jacp, int body);

计算子树质心末端执行器雅可比矩阵。

mj_jacGeom#

void mj_jacGeom(const mjModel* m, const mjData* d, mjtNum* jacp, mjtNum* jacr, int geom);

计算几何体末端执行器雅可比矩阵。

可空: jacp, jacr

mj_jacSite#

void mj_jacSite(const mjModel* m, const mjData* d, mjtNum* jacp, mjtNum* jacr, int site);

计算站点末端执行器雅可比矩阵。

可空: jacp, jacr

mj_jacPointAxis#

void mj_jacPointAxis(const mjModel* m, mjData* d, mjtNum* jacPoint, mjtNum* jacAxis,
                     const mjtNum point[3], const mjtNum axis[3], int body);

计算点的平移末端执行器雅可比矩阵,以及轴的旋转雅可比矩阵。

可空: jacPoint, jacAxis

mj_jacDot#

void mj_jacDot(const mjModel* m, const mjData* d, mjtNum* jacp, mjtNum* jacr,
               const mjtNum point[3], int body);

此函数计算 mj_jac 计算的末端执行器运动学雅可比矩阵的时间导数。为使计算与当前的广义位置和速度 mjData.{qpos, qvel} 一致,所需的最小流水线阶段依次为 mj_kinematicsmj_comPosmj_comVel

可空: jacp, jacr

mj_angmomMat#

void mj_angmomMat(const mjModel* m, mjData* d, mjtNum* mat, int body);

此函数计算 3 x nv 的角动量矩阵 \(H(q)\),提供从广义速度到子树角动量的线性映射。更准确地说,如果 \(h\)mjData.subtree_angmom 中索引为 body 的物体的子树角动量(由 subtreeangmom 传感器报告),且 \(\dot q\) 是广义速度 mjData.qvel,则 \(h = H \dot q\)

mj_name2id#

int mj_name2id(const mjModel* m, int type, const char* name);

根据指定的 mjtObj 类型和名称获取对象的 id,未找到则返回 -1。

mj_id2name#

const char* mj_id2name(const mjModel* m, int type, int id);

根据指定的 mjtObj 类型和 id 获取对象的名称,未找到则返回 NULL

mj_fullM#

void mj_fullM(const mjModel* m, mjtNum* dst, const mjtNum* M);

将稀疏惯性矩阵 M 转换为完整(即稠密)矩阵。
dst 大小必须为 nv x nvM 的结构必须与 mjData.qM 相同。

mjData 成员 qMM 以不同格式表示同一个矩阵;前者是 MuJoCo 特有的,后者是标准的压缩稀疏行格式(仅存储下三角)。惯性矩阵的 \(L^T D L\) 分解因子 mjData.qLD 使用与 mjData.M 相同的 CSR 格式。参见 engine_support_test 获取教学示例。

mj_mulM#

void mj_mulM(const mjModel* m, const mjData* d, mjtNum* res, const mjtNum* vec);

此函数将存储在 mjData.M 中的关节空间惯性矩阵乘以一个向量。

mj_mulM2#

void mj_mulM2(const mjModel* m, const mjData* d, mjtNum* res, const mjtNum* vec);

将向量乘以(惯性矩阵)^(1/2)。

mj_addM#

void mj_addM(const mjModel* m, mjData* d, mjtNum* dst, int* rownnz, int* rowadr, int* colind);

将惯性矩阵添加到目标矩阵(仅限下三角)。

当所有 int* 为 NULL 时,目标矩阵可以是稀疏的或稠密的。

可空: rownnz, rowadr, colind

mj_applyFT#

void mj_applyFT(const mjModel* m, mjData* d, const mjtNum force[3], const mjtNum torque[3],
                const mjtNum point[3], int body, mjtNum* qfrc_target);

此函数可用于在物体上的某一点施加笛卡尔力和力矩,并将结果添加到所有已施加力的向量 mjData.qfrc_applied 中。注意,该函数需要此向量的指针,因为有时我们希望将结果添加到不同的向量中。

mj_objectVelocity#

void mj_objectVelocity(const mjModel* m, const mjData* d,
                       int objtype, int objid, mjtNum res[6], int flg_local);

计算以物体为中心的坐标系、世界/局部朝向下的 6D 物体速度(旋转:平移)。

mj_objectAcceleration#

void mj_objectAcceleration(const mjModel* m, const mjData* d,
                           int objtype, int objid, mjtNum res[6], int flg_local);

计算以物体为中心的坐标系、世界/局部朝向下的 6D 物体加速度(旋转:平移)。如果模型中没有加速度或力传感器,则必须手动调用 mj_rnePostConstraint 以计算 mjData.cacc——即包括约束求解器贡献在内的总物体加速度。

mj_geomDistance#

mjtNum mj_geomDistance(const mjModel* m, mjData* d, int geom1, int geom2, mjtNum distmax,
                       mjtNum fromto[6]);

返回两个几何体之间的最小有向距离,并可选择性返回从 geom1geom2 的线段。返回的距离上限为 distmax
如果未找到距离小于 distmax 的碰撞,函数将返回 distmax,如果提供了 fromto,则将其设置为 (0, 0, 0, 0, 0, 0)。

可空: fromto

nativeccd 下表现出不同(正确)的行为

碰撞检测中所述,使用传统 CCD 流水线时距离是不准确的,不建议使用。

mj_contactForce#

void mj_contactForce(const mjModel* m, const mjData* d, int id, mjtNum result[6]);

在接触坐标系中,给定接触 id 提取 6D 力:力矩。

mj_differentiatePos#

void mj_differentiatePos(const mjModel* m, mjtNum* qvel, mjtNum dt,
                         const mjtNum* qpos1, const mjtNum* qpos2);

此函数以 qpos 格式减去两个向量(并将结果除以 dt),同时遵循四元数的性质。回想一下,单位四元数表示空间朝向。它们是 4D 单位球面上的点。该球面的切线是 3D 旋转速度平面。因此,当我们以正确方式减去两个四元数时,结果是一个 3D 向量而不是 4D 向量。因此,输出 qvel 的维度为 nv,而输入的维度为 nq。

mj_integratePos#

void mj_integratePos(const mjModel* m, mjtNum* qpos, const mjtNum* qvel, mjtNum dt);

这是 mj_differentiatePos 的反操作。它将一个 qvel 格式的向量(乘以 dt)加到一个 qpos 格式的向量上。

mj_normalizeQuat#

void mj_normalizeQuat(const mjModel* m, mjtNum* qpos);

归一化 qpos 型向量中的所有四元数。

mj_local2Global#

void mj_local2Global(mjData* d, mjtNum xpos[3], mjtNum xmat[9], const mjtNum pos[3],
                     const mjtNum quat[4], int body, mjtByte sameframe);

从物体局部坐标系映射到全局笛卡尔坐标系,sameframe 采用 mjtSameFrame 中的值。

mj_getTotalmass#

mjtNum mj_getTotalmass(const mjModel* m);

对所有物体质量求和。

mj_setTotalmass#

void mj_setTotalmass(mjModel* m, mjtNum newmass);

缩放物体质量和惯性以达到指定的总质量。

mj_getPluginConfig#

const char* mj_getPluginConfig(const mjModel* m, int plugin_id, const char* attrib);

返回插件实例的配置属性值;

NULL:无效的插件实例 ID 或属性名称

mj_loadPluginLibrary#

void mj_loadPluginLibrary(const char* path);

加载动态库。动态库被假定注册了一个或多个插件。

mj_loadAllPluginLibraries#

void mj_loadAllPluginLibraries(const char* directory, mjfPluginLibraryLoadCallback callback);

扫描目录并加载所有动态库。指定目录中的动态库被假定注册了一个或多个插件。可选地,如果指定了回调,它将为遇到的每个注册了插件的动态库被调用。

mj_version#

int mj_version(void);

返回版本号:1.0.2 编码为 102。

mj_versionString#

const char* mj_versionString(void);

返回当前 MuJoCo 版本作为空终止字符串。

组件#

这些是仿真流水线的组件,由 mj_stepmj_forwardmj_inverse 在内部调用。用户通常不需要直接调用它们。

mj_fwdKinematics#

void mj_fwdKinematics(const mjModel* m, mjData* d);

运行所有运动学相关计算(运动学、comPos、camlight、flex、tendon)。

mj_fwdPosition#

void mj_fwdPosition(const mjModel* m, mjData* d);

运行位置相关的计算。

mj_fwdVelocity#

void mj_fwdVelocity(const mjModel* m, mjData* d);

运行速度相关的计算。

mj_fwdActuation#

void mj_fwdActuation(const mjModel* m, mjData* d);

计算执行器力 qfrc_actuator。

mj_fwdAcceleration#

void mj_fwdAcceleration(const mjModel* m, mjData* d);

累加所有非约束力,计算 qacc_smooth。

mj_fwdConstraint#

void mj_fwdConstraint(const mjModel* m, mjData* d);

运行所选的约束求解器。

mj_Euler#

void mj_Euler(const mjModel* m, mjData* d);

欧拉积分器,在速度上采用半隐式。

mj_RungeKutta#

void mj_RungeKutta(const mjModel* m, mjData* d, int N);

Runge-Kutta 显式 N 阶积分器。

mj_implicit#

void mj_implicit(const mjModel* m, mjData* d);

使用隐式速度积分器(“implicit”或“implicitfast”,见数值积分)积分仿真状态,并推进仿真时间。有关此函数计算的字段,请参阅 mjdata.h

mj_invPosition#

void mj_invPosition(const mjModel* m, mjData* d);

在逆动力学中运行位置相关的计算。

mj_invVelocity#

void mj_invVelocity(const mjModel* m, mjData* d);

在逆动力学中运行速度相关的计算。

mj_invConstraint#

void mj_invConstraint(const mjModel* m, mjData* d);

应用逆约束动力学的解析公式。

mj_compareFwdInv#

void mj_compareFwdInv(const mjModel* m, mjData* d);

比较正向和逆向动力学,将结果保存在 fwdinv 中。

子组件#

这些是仿真流水线的子组件,由上述组件在内部调用。

mj_sensorPos#

void mj_sensorPos(const mjModel* m, mjData* d);

评估位置相关的传感器。

mj_sensorVel#

void mj_sensorVel(const mjModel* m, mjData* d);

评估速度相关的传感器。

mj_sensorAcc#

void mj_sensorAcc(const mjModel* m, mjData* d);

评估加速度和力相关的传感器。

mj_energyPos#

void mj_energyPos(const mjModel* m, mjData* d);

评估位置相关的能量(势能)。

mj_energyVel#

void mj_energyVel(const mjModel* m, mjData* d);

评估速度相关的能量(动能)。

mj_checkPos#

void mj_checkPos(const mjModel* m, mjData* d);

检查 qpos,如果任何元素过大或为 nan 则重置。

mj_checkVel#

void mj_checkVel(const mjModel* m, mjData* d);

检查 qvel,如果任何元素过大或为 nan 则重置。

mj_checkAcc#

void mj_checkAcc(const mjModel* m, mjData* d);

检查 qacc,如果任何元素过大或为 nan 则重置。

mj_kinematics#

void mj_kinematics(const mjModel* m, mjData* d);

运行正向运动学。

mj_comPos#

void mj_comPos(const mjModel* m, mjData* d);

将惯性和运动自由度映射到以 CoM 为中心的全局坐标系。

mj_camlight#

void mj_camlight(const mjModel* m, mjData* d);

计算摄像机和灯光的位置与朝向。

mj_flex#

void mj_flex(const mjModel* m, mjData* d);

计算与 flex 相关的量。

mj_tendon#

void mj_tendon(const mjModel* m, mjData* d);

计算肌腱长度、速度和力臂。

mj_transmission#

void mj_transmission(const mjModel* m, mjData* d);

计算执行器传输长度和力矩。

mj_crb#

void mj_crb(const mjModel* m, mjData* d);

运行复合刚体惯性算法 (CRB)。

mj_makeM#

void mj_makeM(const mjModel* m, mjData* d);

使用 mj_crb 计算复合刚体惯性,并添加由于 肌腱电枢 产生的项。关节空间惯性矩阵存储在 mjData.qMmjData.M 中。这些数组使用不同的布局(分别为基于父节点的布局和压缩稀疏行布局)表示相同的量。

mj_factorM#

void mj_factorM(const mjModel* m, mjData* d);

计算惯性矩阵的稀疏 \(L^T D L\) 分解。

mj_solveM#

void mj_solveM(const mjModel* m, mjData* d, mjtNum* x, const mjtNum* y, int n);

使用分解求解线性方程组 \(M x = y\)\(x = (L^T D L)^{-1} y\)

mj_solveM2#

void mj_solveM2(const mjModel* m, mjData* d, mjtNum* x, const mjtNum* y,
                const mjtNum* sqrtInvD, int n);

线性求解的一半:\(x = \sqrt{D^{-1}} (L^T)^{-1} y\)

mj_comVel#

void mj_comVel(const mjModel* m, mjData* d);

计算 cvel, cdof_dot。

mj_passive#

void mj_passive(const mjModel* m, mjData* d);

计算弹簧阻尼器、重力补偿和流体力产生的 qfrc_passive。

mj_subtreeVel#

void mj_subtreeVel(const mjModel* m, mjData* d);

子树线速度和角动量:计算 subtree_linvel, subtree_angmom。如果模型中存在子树速度动量传感器,该函数会自动触发。它也针对 阶段 为“vel”的 用户传感器 触发。

mj_rne#

void mj_rne(const mjModel* m, mjData* d, int flg_acc, mjtNum* result);

递归牛顿-欧拉法:计算 \(M(q) \ddot q + C(q,\dot q)\)flg_acc=0 移除惯性项(即假设 \(\ddot q = 0\))。

mj_rnePostConstraint#

void mj_rnePostConstraint(const mjModel* m, mjData* d);

带最终计算力和加速度的递归牛顿-欧拉法。计算三个物体级 nv x 6 数组,全部定义在基于 subtreecom 的 c-frame 中,并以 [rotation(3), translation(3)] 顺序排列。

  • cacc:物体加速度,mj_objectAcceleration 所需。

  • cfrc_int:与父物体的交互力。

  • cfrc_ext:作用于物体的外力。

如果模型中存在以下传感器,该函数会自动触发:加速度计力矩framelinaccframeangacc。它也针对 阶段 为“acc”的 用户传感器 触发。

计算得出的力数组 cfrc_intcfrc_ext 目前存在一个已知 Bug,它们未考虑空间肌腱的影响,参见 issue #832

mj_maxContact#

int mj_maxContact(const mjModel* m, int g1, int g2, int has_margin);

返回两个几何体之间可能产生的最大接触数量。

如果 has_margin 为 -1,则边缘从模型中获取;否则如果 has_margin > 0,则表示几何体具有正边缘。

mj_collision#

void mj_collision(const mjModel* m, mjData* d);

运行碰撞检测。

mj_makeConstraint#

void mj_makeConstraint(const mjModel* m, mjData* d);

构建约束。

mj_island#

void mj_island(const mjModel* m, mjData* d);

寻找约束孤岛。

mj_projectConstraint#

void mj_projectConstraint(const mjModel* m, mjData* d);

计算逆约束惯性 efc_AR。

mj_referenceConstraint#

void mj_referenceConstraint(const mjModel* m, mjData* d);

计算 efc_vel, efc_aref。

mj_constraintUpdate#

void mj_constraintUpdate(const mjModel* m, mjData* d, const mjtNum* jar,
                         mjtNum cost[1], int flg_coneHessian);

计算 efc_state, efc_force, qfrc_constraint,以及(可选)锥 Hessian 矩阵。如果 cost 不为 NULL,则设置 *cost = s(jar),其中 jar = Jac*qacc - aref

可空: cost

射线投射#

射线碰撞(也称为射线投射)用于寻找射线与几何体相交处的距离 x,其中射线是起点为 3D 点 p 方向为 v 的直线,即 (p + x*v, x >= 0)。此族中的所有函数都返回到最近几何体表面的距离,若无相交则返回 -1。注意,如果 p 在几何体内部,射线将从内部与表面相交,这仍计为相交。

所有射线碰撞函数都依赖于 mj_kinematics 计算的量(见 mjData),因此必须在 mj_kinematics 或调用它的函数(如 mj_fwdPosition)之后调用。顶层函数(用于与所有几何体类型相交)包括投射单条射线的 mj_ray,以及从单点投射多条射线的 mj_multiRay

mj_ray#

mjtNum mj_ray(const mjModel* m, const mjData* d, const mjtNum pnt[3], const mjtNum vec[3],
              const mjtByte* geomgroup, mjtBool flg_static, int bodyexclude,
              int geomid[1], mjtNum normal[3]);

将射线 pnt+x*vec, x >= 0 与几何体相交。

  • 返回到最近表面的距离 x,若无相交返回 -1。

  • 如果 geomid 不为 NULL,写入相交几何体的 id,若无相交则为 -1。

  • 如果 normal 不为 NULL,写入相交点的表面法线。无论射线方向如何(即包括从内部击中表面的射线),法线始终指向几何体外部

  • 排除 id 为 bodyexclude 的物体中的几何体,使用 -1 包含所有物体。

  • geomgroup 是长度为 mjNGROUP 的数组,其中 1 表示应包含该组。传递 NULL 以跳过几何体组排除。

  • 如果 flg_static 为 0,则排除静态几何体。

可空: geomgroup, geomid, normal

mj_multiRay#

void mj_multiRay(const mjModel* m, mjData* d, const mjtNum pnt[3], const mjtNum* vec,
                 const mjtByte* geomgroup, mjtBool flg_static, int bodyexclude,
                 int* geomid, mjtNum* dist, mjtNum* normal, int nray, mjtNum cutoff);

将从单点发射的多条射线与几何体相交,如果提供了法线则计算法线。

语义与 mj_ray 类似,但 vec、normal 和 dist 为数组。

忽略超过截止距离的几何体。

可空: geomgroup, geomid, normal

mj_rayHfield#

mjtNum mj_rayHfield(const mjModel* m, const mjData* d, int geomid,
                    const mjtNum pnt[3], const mjtNum vec[3], mjtNum normal[3]);

将射线与高度场相交;返回最近距离,若无相交返回 -1。

可空: normal

mj_rayMesh#

mjtNum mj_rayMesh(const mjModel* m, const mjData* d, int geomid,
                  const mjtNum pnt[3], const mjtNum vec[3], mjtNum normal[3]);

将射线与网格相交;返回最近距离,若无相交返回 -1。

可空: normal

mju_rayGeom#

mjtNum mju_rayGeom(const mjtNum pos[3], const mjtNum mat[9], const mjtNum size[3],
                   const mjtNum pnt[3], const mjtNum vec[3], int geomtype,
                   mjtNum normal[3]);

将射线与纯几何体相交;返回最近距离,若无相交返回 -1。

可空: normal

mj_rayFlex#

mjtNum mj_rayFlex(const mjModel* m, const mjData* d, int flex_layer,
                  mjtBool flg_vert, mjtBool flg_edge, mjtBool flg_face,
                  mjtBool flg_skin, int flexid, const mjtNum pnt[3],
                  const mjtNum vec[3], int vertid[1], mjtNum normal[3]);

将射线与 flex 相交;返回最近距离,若无相交返回 -1,并输出最近的顶点 id 和表面法线。

可空: vertid, normal

mju_raySkin#

mjtNum mju_raySkin(int nface, int nvert, const int* face, const float* vert,
                   const mjtNum pnt[3], const mjtNum vec[3], int vertid[1]);

将射线与 skin 相交;返回最近距离,若无相交返回 -1,并输出最近的顶点 id。

可空: vertid

打印#

这些函数可用于将各种量打印到屏幕上以进行调试。

mj_printFormattedModel#

void mj_printFormattedModel(const mjModel* m, const char* filename, const char* float_format);

将 mjModel 打印到文本文件,指定格式。float_format 必须是用于单个浮点值的有效 printf 风格格式字符串。

mj_printModel#

void mj_printModel(const mjModel* m, const char* filename);

将模型打印到文本文件。

mj_printFormattedData#

void mj_printFormattedData(const mjModel* m, const mjData* d, const char* filename,
                           const char* float_format);

将 mjData 打印到文本文件,指定格式。float_format 必须是用于单个浮点值的有效 printf 风格格式字符串。

mj_printData#

void mj_printData(const mjModel* m, const mjData* d, const char* filename);

将数据打印到文本文件。

mju_printMat#

void mju_printMat(const mjtNum* mat, int nr, int nc);

将矩阵打印到屏幕。

mju_printMatSparse#

void mju_printMatSparse(const mjtNum* mat, int nr,
                        const int* rownnz, const int* rowadr, const int* colind);

将稀疏矩阵打印到屏幕。

mj_printSchema#

int mj_printSchema(const char* filename, char* buffer, int buffer_sz,
                   int flg_html, int flg_pad);

将内部 XML 模式打印为纯文本或 HTML,带有样式填充或  

mj_printScene#

void mj_printScene(const mjvScene* s, const char* filename);

将场景打印到文本文件。

mj_printFormattedScene#

void mj_printFormattedScene(const mjvScene* s, const char* filename,
                            const char* float_format);

将场景打印到文本文件,指定格式。float_format 必须是用于单个浮点值的有效 printf 风格格式字符串。

虚拟文件系统#

虚拟文件系统 (VFS) 允许用户将所有必要文件加载到内存中,包括 MJB 二进制模型文件、XML 文件(MJCF、URDF 和包含的文件)、STL 网格、用于纹理和高度场的 PNG,以及我们自定义高度场格式的 HF 文件。VFS 中的模型和资源文件也可以通过编程方式构建(例如,使用向内存写入的 Python 库)。一旦所有所需文件都在 VFS 中,用户就可以调用带有 VFS 指针的 mj_loadModelmj_loadXML。当此指针不为 NULL 时,加载器将首先检查 VFS 中是否存在即将加载的文件,仅在 VFS 中找不到该文件时才访问磁盘。

VFS 必须先使用 mj_defaultVFS 分配,并必须使用 mj_deleteVFS 释放。

mj_defaultVFS#

void mj_defaultVFS(mjVFS* vfs);

初始化一个空 VFS,必须调用 mj_deleteVFS 来取消分配 VFS。

mj_mountVFS#

int mj_mountVFS(mjVFS* vfs, const char* filepath, const mjpResourceProvider* provider);

挂载一个 ResourceProvider 以在给定路径下处理文件操作;返回 0:成功,2:重复名称,-1:无效的资源提供者。

mj_unmountVFS#

int mj_unmountVFS(mjVFS* vfs, const char* filename);

卸载先前挂载的 ResourceProvider;返回 0:成功,-1:在 VFS 中未找到。

mj_addFileVFS#

int mj_addFileVFS(mjVFS* vfs, const char* directory, const char* filename);

将文件添加到 VFS。directory 参数是可选的,可以为 NULL 或为空。成功返回 0,名称冲突返回 2,内部错误返回 -1。

可空: directory

mj_addBufferVFS#

int mj_addBufferVFS(mjVFS* vfs, const char* name, const void* buffer, int nbuffer);

从缓冲区将文件添加到 VFS;返回 0:成功,2:重复名称,-1:加载失败。

mj_deleteFileVFS#

int mj_deleteFileVFS(mjVFS* vfs, const char* filename);

从 VFS 删除文件;返回 0:成功,-1:在 VFS 中未找到。

mj_containsBufferVFS#

int mj_containsBufferVFS(mjVFS* vfs, const char* name);

检查缓冲区是否存在于 VFS 中;返回 1:存在,0:未找到。

mj_containsFileVFS#

int mj_containsFileVFS(mjVFS* vfs, const char* directory, const char* filename);

检查文件是否存在于 VFS 中;返回 1:存在,0:未找到。

mj_deleteVFS#

void mj_deleteVFS(mjVFS* vfs);

删除 VFS 中的所有文件并取消分配 VFS 内部内存。

资源缓存#

资源缓存是一种用于缓存资源(如纹理、网格等)的机制,以避免重复且缓慢的重新编译。以下方法提供了控制缓存容量或完全禁用它的方式。

mj_getCacheSize#

size_t mj_getCacheSize(const mjCache* cache);

获取资源缓存的当前大小(字节)。

mj_getCacheCapacity#

size_t mj_getCacheCapacity(const mjCache* cache);

获取资源缓存的容量(字节)。

mj_setCacheCapacity#

size_t mj_setCacheCapacity(mjCache* cache, size_t size);

设置资源缓存的容量(字节,0 为禁用);返回新容量。

mj_getCache#

mjCache* mj_getCache(void);

获取编译器使用的内部资源缓存。

mj_clearCache#

void mj_clearCache(mjCache* cache);

清除资源缓存。

资源#

资源是资源提供者与 MuJoCo 模型编译代码之间的接口。这些函数提供了查询资源提供者并获取资源的方法。

mju_openResource#

mjResource* mju_openResource(const char* dir, const char* name,
                             const mjVFS* vfs, char* error, size_t nerror);

打开资源;如果名称没有匹配已注册资源提供者的前缀,则使用操作系统文件系统。

可空: dir, vfs, error

mju_closeResource#

void mju_closeResource(mjResource* resource);

关闭资源;若资源为 NULL,则为空操作。

mju_readResource#

int mju_readResource(mjResource* resource, const void** buffer);

设置缓冲区为从资源中读取的字节,并返回缓冲区中的字节数;若出错则返回负值。

mju_getResourceDir#

void mju_getResourceDir(mjResource* resource, const char** dir, int* ndir);

对于名称被划分为 {dir}{filename} 的资源,获取 dir 和 ndir 指针。

mju_isModifiedResource#

int mju_isModifiedResource(const mjResource* resource, const char* timestamp);

比较资源时间戳与提供的时间戳。

如果时间戳匹配返回 0,如果资源较新返回 >0,如果资源较旧返回 <0。

mju_decodeResource#

mjSpec* mju_decodeResource(mjResource* resource, const char* content_type,
                           const mjVFS* vfs);

查找资源的解码器并返回解码后的 spec。

调用者获取 spec 的所有权并负责对其进行清理。

可为空 (Nullable): vfs

初始化#

本节包含加载/初始化模型或其他数据结构的函数。代码示例中很好地展示了它们的用法。

mj_defaultLROpt#

void mj_defaultLROpt(mjLROpt* opt);

设置长度范围计算的默认选项。

mj_defaultSolRefImp#

void mj_defaultSolRefImp(mjtNum* solref, mjtNum* solimp);

将求解器参数设置为默认值。

可为空 (Nullable): solref, solimp

mj_defaultOption#

void mj_defaultOption(mjOption* opt);

将物理选项设置为默认值。

mj_defaultVisual#

void mj_defaultVisual(mjVisual* vis);

将视觉选项设置为默认值。

mj_copyModel#

mjModel* mj_copyModel(mjModel* dest, const mjModel* src);

复制 mjModel,如果 dest 为 NULL 则分配新的空间。

可为空 (Nullable): dest

mj_saveModel#

void mj_saveModel(const mjModel* m, const char* filename, void* buffer, int buffer_sz);

将模型保存到二进制 MJB 文件或内存缓冲区;给定缓冲区时优先级更高。

可为空 (Nullable): filename, buffer

mj_loadModel#

mjModel* mj_loadModel(const char* filename, const mjVFS* vfs);

从二进制 MJB 文件加载模型。

如果 vfs 不为 NULL,在从磁盘读取之前先在 vfs 中查找文件。

可为空 (Nullable): vfs

mj_loadModelBuffer#

mjModel* mj_loadModelBuffer(const void* buffer, int buffer_sz);

从内存缓冲区加载模型。

mj_deleteModel#

void mj_deleteModel(mjModel* m);

释放模型中的内存分配。

mj_sizeModel#

mjtSize mj_sizeModel(const mjModel* m);

返回容纳模型所需的缓冲区大小。

mj_makeData#

mjData* mj_makeData(const mjModel* m);

分配对应给定模型的 mjData。

如果模型缓冲区未分配,则不会设置初始配置。

mj_copyData#

mjData* mj_copyData(mjData* dest, const mjModel* m, const mjData* src);

复制 mjData。m 仅需要包含来自 MJMODEL_INTS 的大小字段。

mjv_copyData#

mjData* mjv_copyData(mjData* dest, const mjModel* m, const mjData* src);

复制 mjData,跳过可视化不需要的大型数组。

mj_resetData#

void mj_resetData(const mjModel* m, mjData* d);

将数据重置为默认值。

mj_resetDataDebug#

void mj_resetDataDebug(const mjModel* m, mjData* d, unsigned char debug_value);

将数据重置为默认值,所有其他内容填充 debug_value。

mj_resetDataKeyframe#

void mj_resetDataKeyframe(const mjModel* m, mjData* d, int key);

重置数据。如果 0 <= key < nkey,则从指定的关键帧设置字段。

mj_markStack#

void mj_markStack(mjData* d);

在 mjData 堆上标记一个新帧。

mj_freeStack#

void mj_freeStack(mjData* d);

释放当前 mjData 堆帧。自上次调用 mj_markStack 以来由 mj_stackAlloc 返回的所有指针在此之后不得再使用。

mj_stackAllocByte#

void* mj_stackAllocByte(mjData* d, size_t bytes, size_t alignment);

在 mjData 堆上以特定对齐方式分配字节数。

堆溢出时调用 mju_error。

mj_stackAllocNum#

mjtNum* mj_stackAllocNum(mjData* d, size_t size);

在 mjData 堆上分配 mjtNums 数组。堆溢出时调用 mju_error。

mj_stackAllocInt#

int* mj_stackAllocInt(mjData* d, size_t size);

在 mjData 堆上分配 ints 数组。堆溢出时调用 mju_error。

mj_deleteData#

void mj_deleteData(mjData* d);

释放 mjData 中的内存分配。

mj_resetCallbacks#

void mj_resetCallbacks(void);

将所有回调重置为 NULL 指针(NULL 是默认值)。

mj_setConst#

void mj_setConst(mjModel* m, mjData* d);

设置 mjModel 的常量字段,对应 qpos0 配置。

mj_setLengthRange#

int mj_setLengthRange(mjModel* m, mjData* d, int index,
                      const mjLROpt* opt, char* error, int error_sz);

设置指定执行器的 actuator_lengthrange;如果成功返回 1,如果出错返回 0。

可为空 (Nullable): error

mj_makeSpec#

mjSpec* mj_makeSpec(void);

创建一个空的 spec。

mj_copySpec#

mjSpec* mj_copySpec(const mjSpec* s);

复制 spec。

mj_deleteSpec#

void mj_deleteSpec(mjSpec* s);

释放 mjSpec 中的内存分配。

mjs_activatePlugin#

int mjs_activatePlugin(mjSpec* s, const char* name);

激活插件;成功时返回 0。

mjs_setDeepCopy#

int mjs_setDeepCopy(mjSpec* s, int deepcopy);

开启或关闭深拷贝附加;成功时返回 0。

错误和内存#

mju_error#

void mju_error(const char* msg, ...) mjPRINTFLIKE(1, 2);

主错误函数;不返回给调用者。

mju_error_i#

void mju_error_i(const char* msg, int i);

已弃用:使用 mju_error。

mju_error_s#

void mju_error_s(const char* msg, const char* text);

已弃用:使用 mju_error。

mju_warning#

void mju_warning(const char* msg, ...) mjPRINTFLIKE(1, 2);

主警告函数;返回给调用者。

mju_warning_i#

void mju_warning_i(const char* msg, int i);

已弃用:使用 mju_warning。

mju_warning_s#

void mju_warning_s(const char* msg, const char* text);

已弃用:使用 mju_warning。

mju_clearHandlers#

void mju_clearHandlers(void);

清除用户错误和内存处理程序。

mju_malloc#

void* mju_malloc(size_t size);

分配内存;字节对齐到 64;将大小填充为 64 的倍数。

mju_free#

void mju_free(void* ptr);

释放内存,默认使用 free()。

mj_warning#

void mj_warning(mjData* d, int warning, int info);

高级警告函数:计算 mjData 中的警告,仅打印第一个。

mju_writeLog#

void mju_writeLog(const char* type, const char* msg);

将 [datetime, type: message] 写入 MUJOCO_LOG.TXT。

mjs_getError#

const char* mjs_getError(mjSpec* s);

从 spec 获取编译器错误消息。

mjs_getTimer#

const double* mjs_getTimer(mjSpec* s);

从 spec 获取编译器计时诊断,返回指向大小为 mjNCTIMER 的数组的指针。

mjs_isWarning#

int mjs_isWarning(mjSpec* s);

如果编译器错误是警告则返回 1。

杂项#

mju_muscleGain#

mjtNum mju_muscleGain(mjtNum len, mjtNum vel, const mjtNum lengthrange[2],
                      mjtNum acc0, const mjtNum prm[9]);

肌肉主动力,prm = (range[2], force, scale, lmin, lmax, vmax, fpmax, fvmax)。

mju_muscleBias#

mjtNum mju_muscleBias(mjtNum len, const mjtNum lengthrange[2],
                      mjtNum acc0, const mjtNum prm[9]);

肌肉被动力,prm = (range[2], force, scale, lmin, lmax, vmax, fpmax, fvmax)。

mju_muscleDynamics#

mjtNum mju_muscleDynamics(mjtNum ctrl, mjtNum act, const mjtNum prm[3]);

肌肉激活动力学,prm = (tau_act, tau_deact, smoothing_width)。

mju_encodePyramid#

void mju_encodePyramid(mjtNum* pyramid, const mjtNum* force, const mjtNum* mu, int dim);

将接触力转换为金字塔表示。

mju_decodePyramid#

void mju_decodePyramid(mjtNum* force, const mjtNum* pyramid, const mjtNum* mu, int dim);

将金字塔表示转换为接触力。

mju_springDamper#

mjtNum mju_springDamper(mjtNum pos0, mjtNum vel0, mjtNum Kp, mjtNum Kv, mjtNum dt);

解析积分弹簧阻尼器;返回 pos(dt)。

mju_min#

mjtNum mju_min(mjtNum a, mjtNum b);

返回 min(a,b),仅评估一次 a 和 b。

mju_max#

mjtNum mju_max(mjtNum a, mjtNum b);

返回 max(a,b),仅评估一次 a 和 b。

mju_clip#

mjtNum mju_clip(mjtNum x, mjtNum min, mjtNum max);

将 x 剪切到 [min, max] 范围内。

mju_sign#

mjtNum mju_sign(mjtNum x);

返回 x 的符号:+1、-1 或 0。

mju_round#

int mju_round(mjtNum x);

将 x 四舍五入到最接近的整数。

mju_type2Str#

const char* mju_type2Str(int type);

将类型 ID (mjtObj) 转换为类型名称。

mju_str2Type#

int mju_str2Type(const char* str);

将类型名称转换为类型 ID (mjtObj)。

mju_writeNumBytes#

const char* mju_writeNumBytes(size_t nbytes);

使用标准字母后缀返回人类可读的字节数。

mju_warningText#

const char* mju_warningText(int warning, size_t info);

根据警告类型和信息构建警告消息。

mju_isBad#

int mju_isBad(mjtNum x);

如果 nan 或 abs(x)>mjMAXVAL 则返回 1,否则返回 0。供检查函数使用。

mju_isZero#

int mju_isZero(const mjtNum* vec, int n);

如果所有元素均为 0 则返回 1。

mju_standardNormal#

mjtNum mju_standardNormal(mjtNum* num2);

标准正态随机数生成器(可选第二个数字)。

mju_f2n#

void mju_f2n(mjtNum* res, const float* vec, int n);

从 float 转换为 mjtNum。

mju_n2f#

void mju_n2f(float* res, const mjtNum* vec, int n);

从 mjtNum 转换为 float。

mju_d2n#

void mju_d2n(mjtNum* res, const double* vec, int n);

从 double 转换为 mjtNum。

mju_n2d#

void mju_n2d(double* res, const mjtNum* vec, int n);

从 mjtNum 转换为 double。

mju_insertionSort#

void mju_insertionSort(mjtNum* list, int n);

插入排序,结果列表按升序排列。

mju_insertionSortInt#

void mju_insertionSortInt(int* list, int n);

整数插入排序,结果列表按升序排列。

mju_Halton#

mjtNum mju_Halton(int index, int base);

生成 Halton 序列。

mju_strncpy#

char* mju_strncpy(char *dst, const char *src, int n);

调用 strncpy,然后设置 dst[n-1] = 0。

mju_sigmoid#

mjtNum mju_sigmoid(mjtNum x);

使用五次多项式进行两次连续可微的 Sigmoid 函数

\[s(x) = \begin{cases} 0, & & x \le 0 \\ 6x^5 - 15x^4 + 10x^3, & 0 \lt & x \lt 1 \\ 1, & 1 \le & x \qquad \end{cases} \]

交互#

这些函数实现了抽象鼠标交互,允许控制摄像机和扰动。在 simulate 中很好地说明了它们的用法。

mjv_defaultCamera#

void mjv_defaultCamera(mjvCamera* cam);

设置默认摄像机。

mjv_defaultFreeCamera#

void mjv_defaultFreeCamera(const mjModel* m, mjvCamera* cam);

设置默认自由摄像机。

mjv_defaultPerturb#

void mjv_defaultPerturb(mjvPerturb* pert);

设置默认扰动。

mjv_room2model#

void mjv_room2model(mjtNum modelpos[3], mjtNum modelquat[4], const mjtNum roompos[3],
                    const mjtNum roomquat[4], const mjvScene* scn);

将位姿从房间空间转换为模型空间。

mjv_model2room#

void mjv_model2room(mjtNum roompos[3], mjtNum roomquat[4], const mjtNum modelpos[3],
                    const mjtNum modelquat[4], const mjvScene* scn);

将位姿从模型空间转换为房间空间。

mjv_cameraInModel#

void mjv_cameraInModel(mjtNum headpos[3], mjtNum forward[3], mjtNum up[3],
                       const mjvScene* scn);

在模型空间中获取摄像机信息;取左右 OpenGL 摄像机的平均值。

mjv_cameraInRoom#

void mjv_cameraInRoom(mjtNum headpos[3], mjtNum forward[3], mjtNum up[3],
                      const mjvScene* scn);

在房间空间中获取摄像机信息;取左右 OpenGL 摄像机的平均值。

mjv_frustumHeight#

mjtNum mjv_frustumHeight(const mjvScene* scn);

获取距离摄像机单位距离处的视锥体高度;取左右 OpenGL 摄像机的平均值。

mjv_alignToCamera#

void mjv_alignToCamera(mjtNum res[3], const mjtNum vec[3], const mjtNum forward[3]);

在水平面内将 3D 向量旋转 (0,1) 和 (forward_x,forward_y) 之间的角度。

mjv_moveCamera#

void mjv_moveCamera(const mjModel* m, int action, mjtNum reldx, mjtNum reldy,
                    const mjvScene* scn, mjvCamera* cam);

用鼠标移动摄像机;动作为 mjtMouse。

mjv_movePerturb#

void mjv_movePerturb(const mjModel* m, const mjData* d, int action, mjtNum reldx,
                     mjtNum reldy, const mjvScene* scn, mjvPerturb* pert);

用鼠标移动扰动对象;动作为 mjtMouse。

mjv_moveModel#

void mjv_moveModel(const mjModel* m, int action, mjtNum reldx, mjtNum reldy,
                   const mjtNum roomup[3], mjvScene* scn);

用鼠标移动模型;动作为 mjtMouse。

mjv_initPerturb#

void mjv_initPerturb(const mjModel* m, mjData* d, const mjvScene* scn, mjvPerturb* pert);

从所选物体复制扰动位置、四元数;设置扰动比例。

mjv_applyPerturbPose#

void mjv_applyPerturbPose(const mjModel* m, mjData* d, const mjvPerturb* pert,
                          int flg_paused);

当所选物体是 mocap 时设置 d->mocap 中的扰动位置、四元数,否则设置在 d->qpos 中。

仅在 flg_paused 且所选物体的子树根部具有自由关节时写入 d->qpos。

mjv_applyPerturbForce#

void mjv_applyPerturbForce(const mjModel* m, mjData* d, const mjvPerturb* pert);

如果所选物体是动态的,则在 d->xfrc_applied 中设置扰动作用力、力矩。

mjv_averageCamera#

mjvGLCamera mjv_averageCamera(const mjvGLCamera* cam1, const mjvGLCamera* cam2);

返回两个 OpenGL 摄像机的平均值。

mjv_select#

int mjv_select(const mjModel* m, const mjData* d, const mjvOption* vopt,
               mjtNum aspectratio, mjtNum relx, mjtNum rely,
               const mjvScene* scn, mjtNum selpnt[3],
               int geomid[1], int flexid[1], int skinid[1]);

此函数用于鼠标选择,依赖于射线交叉。aspectratio 为视口宽高比。relx 和 rely 为视口中感兴趣 2D 点的相对坐标(通常为鼠标光标)。函数返回指定 2D 点下的几何体 ID,如果没有几何体则返回 -1(注意天空盒如果存在,不是模型几何体)。点击点的 3D 坐标在 selpnt 中返回。参见 simulate 中的插图。

可视化#

本节中的函数实现了抽象可视化。结果由 OpenGL 渲染器使用,也可以由希望实现自己的渲染器,或将 MuJoCo 连接到诸如 Unity 或 Unreal Engine 等高级渲染工具的用户使用。参见 simulate 了解如何使用这些函数的插图。

mjv_defaultOption#

void mjv_defaultOption(mjvOption* opt);

设置默认可视化选项。

mjv_defaultFigure#

void mjv_defaultFigure(mjvFigure* fig);

设置默认图表。

mjv_initGeom#

void mjv_initGeom(mjvGeom* geom, int type, const mjtNum size[3],
                  const mjtNum pos[3], const mjtNum mat[9], const float rgba[4]);

当不为 NULL 时初始化给定的几何体字段,将其余部分设置为其默认值。

可为空 (Nullable): size, pos, mat, rgba

mjv_connector#

void mjv_connector(mjvGeom* geom, int type, mjtNum width,
                   const mjtNum from[3], const mjtNum to[3]);

为给定点之间的连接器类型几何体设置 (type, size, pos, mat)。

假设已调用 mjv_initGeom 来设置所有其他属性。

mjGEOM_LINE 的宽度以像素为单位。

mjv_defaultScene#

void mjv_defaultScene(mjvScene* scn);

设置默认抽象场景。

mjv_makeScene#

void mjv_makeScene(const mjModel* m, mjvScene* scn, int maxgeom);

在抽象场景中分配资源。

mjv_freeScene#

void mjv_freeScene(mjvScene* scn);

释放抽象场景。

mjv_updateScene#

void mjv_updateScene(const mjModel* m, mjData* d, const mjvOption* opt,
                     const mjvPerturb* pert, mjvCamera* cam, int catmask, mjvScene* scn);

根据模型状态更新整个场景。

mjv_copyModel#

void mjv_copyModel(mjModel* dest, const mjModel* src);

复制 mjModel,跳过抽象可视化不需要的大型数组。

可为空 (Nullable): dest

mjv_addGeoms#

void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* opt,
                  const mjvPerturb* pert, int catmask, mjvScene* scn);

从选定类别添加几何体。

mjv_makeLights#

void mjv_makeLights(const mjModel* m, const mjData* d, mjvScene* scn);

制作灯光列表。

mjv_updateCamera#

void mjv_updateCamera(const mjModel* m, const mjData* d, mjvCamera* cam, mjvScene* scn);

更新摄像机。

mjv_updateSkin#

void mjv_updateSkin(const mjModel* m, const mjData* d, mjvScene* scn);

更新皮肤。

mjv_cameraFrame#

void mjv_cameraFrame(mjtNum headpos[3], mjtNum forward[3], mjtNum up[3], mjtNum right[3],
                     const mjData* d, const mjvCamera* cam);

计算摄像机位置以及前向、上向和右向向量。

可为空 (Nullable): headpos, forward, up, right

mjv_cameraFrustum#

void mjv_cameraFrustum(float zver[2], float zhor[2], float zclip[2],  const mjModel* m,
                       const mjvCamera* cam);

计算摄像机视锥体:垂直、水平和裁剪平面。

可为空 (Nullable): zver, zhor, zclip

OpenGL 渲染#

这些函数公开 OpenGL 渲染器。参见 simulate 了解如何使用这些函数的插图。

mjr_defaultContext#

void mjr_defaultContext(mjrContext* con);

设置默认 mjrContext。

mjr_makeContext#

void mjr_makeContext(const mjModel* m, mjrContext* con, int fontscale);

在自定义 OpenGL 上下文中分配资源;fontscale 为 mjtFontScale。

mjr_changeFont#

void mjr_changeFont(int fontscale, mjrContext* con);

更改现有上下文的字体。

mjr_addAux#

void mjr_addAux(int index, int width, int height, int samples, mjrContext* con);

向上下文添加具有给定索引的 Aux 缓冲区;释放之前的 Aux 缓冲区。

mjr_freeContext#

void mjr_freeContext(mjrContext* con);

释放自定义 OpenGL 上下文中的资源,设置为默认值。

mjr_resizeOffscreen#

void mjr_resizeOffscreen(int width, int height, mjrContext* con);

调整离屏缓冲区大小。

mjr_uploadTexture#

void mjr_uploadTexture(const mjModel* m, const mjrContext* con, int texid);

将纹理上传到 GPU,覆盖之前的任何上传(如果有)。

mjr_uploadMesh#

void mjr_uploadMesh(const mjModel* m, const mjrContext* con, int meshid);

将网格上传到 GPU,覆盖之前的任何上传(如果有)。

mjr_uploadHField#

void mjr_uploadHField(const mjModel* m, const mjrContext* con, int hfieldid);

将高度场上传到 GPU,覆盖之前的任何上传(如果有)。

mjr_restoreBuffer#

void mjr_restoreBuffer(const mjrContext* con);

使 con->currentBuffer 再次成为当前状态。

mjr_setBuffer#

void mjr_setBuffer(int framebuffer, mjrContext* con);

设置用于渲染的 OpenGL 帧缓冲区:mjFB_WINDOW 或 mjFB_OFFSCREEN。

如果仅可用一个缓冲区,设置该缓冲区并忽略帧缓冲区参数。

mjr_readPixels#

void mjr_readPixels(unsigned char* rgb, float* depth,
                    mjrRect viewport, const mjrContext* con);

将像素从当前 OpenGL 帧缓冲区读取到客户端缓冲区。

视口位于 OpenGL 帧缓冲区中;客户端缓冲区从 (0,0) 开始。

mjr_drawPixels#

void mjr_drawPixels(const unsigned char* rgb, const float* depth,
                    mjrRect viewport, const mjrContext* con);

将像素从客户端缓冲区绘制到当前 OpenGL 帧缓冲区。

视口位于 OpenGL 帧缓冲区中;客户端缓冲区从 (0,0) 开始。

mjr_blitBuffer#

void mjr_blitBuffer(mjrRect src, mjrRect dst,
                    int flg_color, int flg_depth, const mjrContext* con);

从当前帧缓冲区中的 src 视口位块传输到其他帧缓冲区中的 dst 视口。

如果 src 和 dst 大小不同且 flg_depth==0,则颜色使用 GL_LINEAR 进行插值。

mjr_setAux#

void mjr_setAux(int index, const mjrContext* con);

设置用于自定义 OpenGL 渲染的 Aux 缓冲区(完成后调用 restoreBuffer)。

mjr_blitAux#

void mjr_blitAux(int index, mjrRect src, int left, int bottom, const mjrContext* con);

从 Aux 缓冲区位块传输到 con->currentBuffer。

mjr_text#

void mjr_text(int font, const char* txt, const mjrContext* con,
              float x, float y, float r, float g, float b);

在相对坐标 (x,y) 处绘制文本;字体为 mjtFont。

mjr_overlay#

void mjr_overlay(int font, int gridpos, mjrRect viewport,
                 const char* overlay, const char* overlay2, const mjrContext* con);

绘制文本叠加层;字体为 mjtFont;gridpos 为 mjtGridPos。

mjr_maxViewport#

mjrRect mjr_maxViewport(const mjrContext* con);

获取活动缓冲区的最大视口。

mjr_rectangle#

void mjr_rectangle(mjrRect viewport, float r, float g, float b, float a);

绘制矩形。

mjr_label#

void mjr_label(mjrRect viewport, int font, const char* txt,
               float r, float g, float b, float a, float rt, float gt, float bt,
               const mjrContext* con);

绘制带有居中文字的矩形。

mjr_figure#

void mjr_figure(mjrRect viewport, mjvFigure* fig, const mjrContext* con);

绘制 2D 图表。

mjr_render#

void mjr_render(mjrRect viewport, mjvScene* scn, const mjrContext* con);

渲染 3D 场景。

mjr_finish#

void mjr_finish(void);

调用 glFinish。

mjr_getError#

int mjr_getError(void);

调用 glGetError 并返回结果。

mjr_findRect#

int mjr_findRect(int x, int y, int nrect, const mjrRect* rect);

查找包含鼠标的第一个矩形,-1:未找到。

UI 框架#

有关 UI 框架的高级描述,请参阅 用户界面

mjui_themeSpacing#

mjuiThemeSpacing mjui_themeSpacing(int ind);

获取内置 UI 主题间距(索引:0-1)。

mjui_themeColor#

mjuiThemeColor mjui_themeColor(int ind);

获取内置 UI 主题颜色(索引:0-3)。

mjui_add#

void mjui_add(mjUI* ui, const mjuiDef* def);

这是用于构建 UI 的辅助函数。第二个参数指向一个 mjuiDef 结构数组,每个结构对应一个项目。最后一个(未使用的)项目的类型设置为 -1,以标记终止。项目添加在最后一个使用部分的末尾之后。此函数还有另一个版本 (mjui_addToSection),它将项目添加到指定部分,而不是添加到 UI 末尾。请记住,每个部分预分配的章节数和项目数有一个最大值,由 mjMAXUISECTmjMAXUIITEM 给定。超过这些最大值会导致底层错误。

mjui_addToSection#

void mjui_addToSection(mjUI* ui, int sect, const mjuiDef* def);

将定义添加到 UI 部分。

mjui_resize#

void mjui_resize(mjUI* ui, const mjrContext* con);

计算 UI 大小。

mjui_update#

void mjui_update(int section, int item, const mjUI* ui,
                 const mjuiState* state, const mjrContext* con);

这是主 UI 更新函数。每当用户数据(由项目数据指针指向)发生变化,或 UI 状态本身发生变化时,都需要调用它。它通常由用户实现的更高级函数(在 simulate.cc 中的 UiModify)调用,该函数还会重新计算所有矩形和相关辅助缓冲区的布局。该函数更新离屏 OpenGL 缓冲区中的像素。为了执行最小更新,用户指定已修改的部分和项目。值 -1 表示所有项目和/或部分都需要更新(在大规模更改后需要此操作)。

mjui_event#

mjuiItem* mjui_event(mjUI* ui, mjuiState* state, const mjrContext* con);

此函数是底层事件处理程序。它对 UI 进行必要的更改,并返回接收到事件的项目的指针(如果未记录有效事件,则返回 NULL)。这通常在用户实现的事件处理程序(simulate.cc 中的 UiEvent)中调用,然后用户代码根据修改了哪个 UI 项目以及在处理事件后该项目的状态采取某些操作。

mjui_render#

void mjui_render(mjUI* ui, const mjuiState* state, const mjrContext* con);

此函数在屏幕刷新循环中调用。它将离屏 OpenGL 缓冲区复制到窗口帧缓冲区。如果应用程序中有多个 UI,则应为每个 UI 调用一次。因此 mjui_render 一直在被调用,而 mjui_update 仅在 UI 发生变化时调用。

导数#

下面的函数提供各种函数的有用导数,包括解析的和有限差分的。后者名称带有后缀 FD。请注意,与 API 的大部分不同,导数函数的输出是尾随参数而不是主要参数。

mjd_transitionFD#

void mjd_transitionFD(const mjModel* m, mjData* d, mjtNum eps, mjtBool flg_centered,
                      mjtNum* A, mjtNum* B, mjtNum* C, mjtNum* D);

计算有限差分离散时间转移矩阵。

\(x, u\) 表示 mjData 实例中的当前 状态控制 向量,令 \(y, s\) 表示下一个状态和传感器值,顶层 mj_step 函数计算 \((x,u) \rightarrow (y,s) mjd_transitionFD 计算使用有限差分的四个相关雅可比矩阵。这些矩阵及其维度为

矩阵

雅可比

维度

A

\(\partial y / \partial x\)

2*nv+na x 2*nv+na

B

\(\partial y / \partial u\)

2*nv+na x nu

C

\(\partial s / \partial x\)

nsensordata x 2*nv+na

D

\(\partial s / \partial u\)

nsensordata x nu

  • 所有输出都是可选的(可以为 NULL)。

  • eps 是有限差分 epsilon。

  • flg_centered 表示是否使用前向 (0) 或中心 (1) 差分。

  • 不支持龙格-库塔积分器 (mjINT_RK4)。

提高速度和精度

热启动 (warmstart)

如果未 禁用 热启动,则调用时存在的热启动加速度 mjData.qacc_warmstart 会在每次相关的流水线调用开始时加载,以保持确定性。如果求解器计算是模拟中昂贵的一部分,以下技巧可以带来显著的加速:首先调用 mj_forward 让求解器收敛,然后显著减少 求解器迭代次数,然后调用 mjd_transitionFD,最后恢复 迭代次数 的原始值。因为我们已经接近解,所以只需要很少的迭代就能找到新的极小值。这对于 牛顿 求解器尤其如此,在该求解器中,接近极小值时收敛所需的迭代次数可以低至 1。

tolerance

如果将求解器 容差 设置为 0,可以提高精度。这意味着对求解器的所有调用将执行完全相同次数的迭代,从而防止由于过早终止而产生的数值误差。当然,这意味着 求解器迭代次数 应该较小,以避免在极小值处原地踏步。此方法与上述方法可以且应该结合使用。

可为空 (Nullable): A, B, D, C

mjd_inverseFD#

void mjd_inverseFD(const mjModel* m, mjData* d, mjtNum eps, mjtBool flg_actuation,
                   mjtNum *DfDq, mjtNum *DfDv, mjtNum *DfDa,
                   mjtNum *DsDq, mjtNum *DsDv, mjtNum *DsDa,
                   mjtNum *DmDq);

有限差分连续时间逆动力学雅可比矩阵。

\(x, a\) 表示 mjData 实例中的当前 状态 和加速度向量,令 \(f, s\) 表示由逆动力学计算的力(qfrc_inverse),函数 mj_inverse 计算 \((x,a) \rightarrow (f,s) mjd_inverseFD 计算使用有限差分的七个相关雅可比矩阵。这些矩阵及其维度为

矩阵

雅可比

维度

DfDq

\(\partial f / \partial q\)

nv x nv

DfDv

\(\partial f / \partial v\)

nv x nv

DfDa

\(\partial f / \partial a\)

nv x nv

DsDq

\(\partial s / \partial q\)

nv x nsensordata

DsDv

\(\partial s / \partial v\)

nv x nsensordata

DsDa

\(\partial s / \partial a\)

nv x nsensordata

DmDq

\(\partial M / \partial q\)

nv x nM

  • 所有输出都是可选的(可以为 NULL)。

  • 相对于控制理论约定,所有输出都是转置的(即,按列优先)。

  • DmDq 包含 nv x nv x nv 张量 \(\partial M / \partial q\) 的稀疏表示,它不严格属于逆动力学雅可比矩阵,但在相关应用中很有用。由于如果请求其他两个 \(\partial / \partial q\) 雅可比矩阵中的任何一个,所需的值已被计算出来,因此将其提供给用户以方便使用。

  • eps 是(前向)有限差分 epsilon。

  • flg_actuation 表示是否从逆动力学的输出中减去驱动力(qfrc_actuator)。如果此标志为正,则不将执行器力视为外部力。

  • 模型选项标志 invdiscrete 应对应于 mjData.qacc 的表示,以便计算正确的导数信息。

注意

  • 不支持龙格-库塔 4 阶积分器 (mjINT_RK4)。

  • 不支持 noslip 求解器。

可为空 (Nullable): DfDq, DfDv, DfDa, DsDq, DsDv, DsDa, DmDq

mjd_subQuat#

void mjd_subQuat(const mjtNum qa[4], const mjtNum qb[4], mjtNum Da[9], mjtNum Db[9]);

mju_subQuat(四元数差)的导数。

可为空 (Nullable): Da, Db

mjd_quatIntegrate#

void mjd_quatIntegrate(const mjtNum vel[3], mjtNum scale,
                       mjtNum Dquat[9], mjtNum Dvel[9], mjtNum Dscale[3]);

mju_quatIntegrate 的导数。

\({\tt \small mju\_quatIntegrate}(q, v, h)\) 执行原位旋转 \(q \leftarrow q + v h\),其中 \(q \in \mathbf{S}^3\) 是单位四元数,\(v \in \mathbf{R}^3\) 是 3D 角速度,\(h \in \mathbf{R^+}\) 是时间步长。这等同于 \({\tt \small mju\_quatIntegrate}(q, s, 1.0)\),其中 \(s\) 是缩放速度 \(s = h v\)

\({\tt \small mjd\_quatIntegrate}(v, h, D_q, D_v, D_h)\) 计算输出 \(q\) 相对于输入的雅可比矩阵。下面,\(\bar q\) 表示修改前的四元数

\[\begin{aligned} D_q &= \partial q / \partial \bar q \\ D_v &= \partial q / \partial v \\ D_h &= \partial q / \partial h \end{aligned} \]

注意,导数仅取决于 \(h\)\(v\)(实际上取决于 \(s = h v\))。所有输出都是可选的。

可为空 (Nullable): Dquat, Dvel, Dscale

符号距离函数 (SDF)#

mjc_getSDF#

const mjpPlugin* mjc_getSDF(const mjModel* m, int id);

从几何体 ID 获取 sdf

mjc_distance#

mjtNum mjc_distance(const mjModel* m, const mjData* d, const mjSDF* s, const mjtNum x[3]);

符号距离函数

mjc_gradient#

void mjc_gradient(const mjModel* m, const mjData* d, const mjSDF* s, mjtNum gradient[3],
                  const mjtNum x[3]);

sdf 的梯度

插件#

mjp_defaultPlugin#

void mjp_defaultPlugin(mjpPlugin* plugin);

设置默认插件定义。

mjp_registerPlugin#

int mjp_registerPlugin(const mjpPlugin* plugin);

全局注册一个插件。此函数是线程安全的。

如果已注册相同的 mjpPlugin,则此函数不执行任何操作。

如果已注册名称相同但不同的 mjpPlugin,则会引发 mju_error。

如果所有成员函数指针和数字均相等,且名称和属性字符串均相同,则认为两个 mjpPlugins 是相同的,但指向字符串的 char 指针不必相同。

mjp_pluginCount#

int mjp_pluginCount(void);

返回全局注册的插件数量。

mjp_getPlugin#

const mjpPlugin* mjp_getPlugin(const char* name, int* slot);

按名称查找插件。如果 slot 不为 NULL,也将注册的槽号写入其中。

mjp_getPluginAtSlot#

const mjpPlugin* mjp_getPluginAtSlot(int slot);

按 mjp_registerPlugin 返回的注册槽号查找插件。

mjp_defaultResourceProvider#

void mjp_defaultResourceProvider(mjpResourceProvider* provider);

设置默认资源提供者定义。

mjp_registerResourceProvider#

int mjp_registerResourceProvider(const mjpResourceProvider* provider);

以线程安全的方式全局注册资源提供者。提供者必须具有一个前缀,该前缀不是任何当前注册提供者的子前缀或超前缀。

成功时返回 >= 0 的槽号,失败时返回 -1。

mjp_resourceProviderCount#

int mjp_resourceProviderCount(void);

返回全局注册的资源提供者数量。

mjp_getResourceProvider#

const mjpResourceProvider* mjp_getResourceProvider(const char* resource_name);

返回其前缀与资源名称匹配的资源提供者。

如果没有匹配,返回 NULL。

mjp_getResourceProviderAtSlot#

const mjpResourceProvider* mjp_getResourceProviderAtSlot(int slot);

按 mjp_registerResourceProvider 返回的槽号查找资源提供者。

如果槽号无效,返回 NULL。

mjp_registerDecoder#

void mjp_registerDecoder(const mjpDecoder* decoder);

全局注册解码器。此函数是线程安全的。

如果已注册相同的 mjpDecoder,则此函数不执行任何操作。

如果已注册名称相同但不同的 mjpDecoder,则会引发 mju_error。

mjp_defaultDecoder#

void mjp_defaultDecoder(mjpDecoder* decoder);

设置默认资源解码器定义。

mjp_findDecoder#

const mjpDecoder* mjp_findDecoder(const mjResource* resource, const char* content_type);

返回其前缀与资源名称匹配的资源提供者。

如果没有匹配,返回 NULL。

mjp_registerEncoder#

void mjp_registerEncoder(const mjpEncoder* encoder);

全局注册编码器。此函数是线程安全的。

如果已注册相同的 mjpEncoder,则此函数不执行任何操作。

如果已注册名称相同但不同的 mjpEncoder,则会引发 mju_error。

mjp_defaultEncoder#

void mjp_defaultEncoder(mjpEncoder* encoder);

设置默认资源编码器定义。

mjp_findEncoder#

const mjpEncoder* mjp_findEncoder(const char* filename, const char* content_type);

返回与内容类型或文件扩展名匹配的编码器。

如果没有匹配,返回 NULL。

线程#

mju_threadPoolCreate#

mjThreadPool* mju_threadPoolCreate(size_t number_of_threads);

创建一个包含指定数量运行线程的线程池。

mju_bindThreadPool#

void mju_bindThreadPool(mjData* d, void* thread_pool);

将线程池添加到 mjData 并对其进行多线程配置。

mju_threadPoolEnqueue#

void mju_threadPoolEnqueue(mjThreadPool* thread_pool, mjTask* task);

在线程池中排队一个任务。

mju_threadPoolDestroy#

void mju_threadPoolDestroy(mjThreadPool* thread_pool);

销毁一个线程池。

mju_defaultTask#

void mju_defaultTask(mjTask* task);

初始化一个 mjTask。

mju_taskJoin#

void mju_taskJoin(mjTask* task);

等待任务完成。

标准数学#

本节中的“函数”是预处理器宏,它们被替换为相应的 C 标准库数学函数。当 MuJoCo 使用单精度编译(目前不对公众开放,但我们在内部有时使用它)时,这些宏被替换为相应的单精度函数(此处未显示)。因此可以认为它们的输入和输出类型为 mjtNum,其中 mjtNum 根据 MuJoCo 的编译方式定义为 double 或 float。我们不在此记录这些函数;请参阅 C 标准库规范。

mju_sqrt#

#define mju_sqrt    sqrt

mju_exp#

#define mju_exp     exp

mju_sin#

#define mju_sin     sin

mju_cos#

#define mju_cos     cos

mju_tan#

#define mju_tan     tan

mju_asin#

#define mju_asin    asin

mju_acos#

#define mju_acos    acos

mju_atan2#

#define mju_atan2   atan2

mju_tanh#

#define mju_tanh    tanh

mju_pow#

#define mju_pow     pow

mju_abs#

#define mju_abs     fabs

mju_log#

#define mju_log     log

mju_log10#

#define mju_log10   log10

mju_floor#

#define mju_floor   floor

mju_ceil#

#define mju_ceil    ceil

向量数学#

mju_zero3#

void mju_zero3(mjtNum res[3]);

设置 res = 0。

mju_copy3#

void mju_copy3(mjtNum res[3], const mjtNum data[3]);

设置 res = vec。

mju_scl3#

void mju_scl3(mjtNum res[3], const mjtNum vec[3], mjtNum scl);

设置 res = vec*scl。

mju_add3#

void mju_add3(mjtNum res[3], const mjtNum vec1[3], const mjtNum vec2[3]);

设置 res = vec1 + vec2。

mju_sub3#

void mju_sub3(mjtNum res[3], const mjtNum vec1[3], const mjtNum vec2[3]);

设置 res = vec1 - vec2。

mju_addTo3#

void mju_addTo3(mjtNum res[3], const mjtNum vec[3]);

设置 res = res + vec。

mju_subFrom3#

void mju_subFrom3(mjtNum res[3], const mjtNum vec[3]);

设置 res = res - vec。

mju_addToScl3#

void mju_addToScl3(mjtNum res[3], const mjtNum vec[3], mjtNum scl);

设置 res = res + vec*scl。

mju_addScl3#

void mju_addScl3(mjtNum res[3], const mjtNum vec1[3], const mjtNum vec2[3], mjtNum scl);

设置 res = vec1 + vec2*scl。

mju_normalize3#

mjtNum mju_normalize3(mjtNum vec[3]);

归一化向量;返回归一化前的长度。

mju_norm3#

mjtNum mju_norm3(const mjtNum vec[3]);

返回向量长度(不归一化向量)。

mju_dot3#

mjtNum mju_dot3(const mjtNum vec1[3], const mjtNum vec2[3]);

返回 vec1 和 vec2 的点积。

mju_dist3#

mjtNum mju_dist3(const mjtNum pos1[3], const mjtNum pos2[3]);

返回 3D 向量 pos1 和 pos2 之间的笛卡尔距离。

mju_mulMatVec3#

void mju_mulMatVec3(mjtNum res[3], const mjtNum mat[9], const mjtNum vec[3]);

将 3x3 矩阵乘以向量:res = mat * vec。

mju_mulMatTVec3#

void mju_mulMatTVec3(mjtNum res[3], const mjtNum mat[9], const mjtNum vec[3]);

将转置的 3x3 矩阵乘以向量:res = mat’ * vec。

mju_cross#

void mju_cross(mjtNum res[3], const mjtNum a[3], const mjtNum b[3]);

计算叉积:res = cross(a, b)。

mju_zero4#

void mju_zero4(mjtNum res[4]);

设置 res = 0。

mju_unit4#

void mju_unit4(mjtNum res[4]);

设置 res = (1,0,0,0)。

mju_copy4#

void mju_copy4(mjtNum res[4], const mjtNum data[4]);

设置 res = vec。

mju_normalize4#

mjtNum mju_normalize4(mjtNum vec[4]);

归一化向量;返回归一化前的长度。

mju_zero#

void mju_zero(mjtNum* res, int n);

设置 res = 0。

mju_fill#

void mju_fill(mjtNum* res, mjtNum val, int n);

设置 res = val。

mju_copy#

void mju_copy(mjtNum* res, const mjtNum* vec, int n);

设置 res = vec。

mju_sum#

mjtNum mju_sum(const mjtNum* vec, int n);

返回 sum(vec)。

mju_L1#

mjtNum mju_L1(const mjtNum* vec, int n);

返回 L1 范数:sum(abs(vec))。

mju_scl#

void mju_scl(mjtNum* res, const mjtNum* vec, mjtNum scl, int n);

设置 res = vec*scl。

mju_add#

void mju_add(mjtNum* res, const mjtNum* vec1, const mjtNum* vec2, int n);

设置 res = vec1 + vec2。

mju_sub#

void mju_sub(mjtNum* res, const mjtNum* vec1, const mjtNum* vec2, int n);

设置 res = vec1 - vec2。

mju_addTo#

void mju_addTo(mjtNum* res, const mjtNum* vec, int n);

设置 res = res + vec。

mju_subFrom#

void mju_subFrom(mjtNum* res, const mjtNum* vec, int n);

设置 res = res - vec。

mju_addToScl#

void mju_addToScl(mjtNum* res, const mjtNum* vec, mjtNum scl, int n);

设置 res = res + vec*scl。

mju_addScl#

void mju_addScl(mjtNum* res, const mjtNum* vec1, const mjtNum* vec2, mjtNum scl, int n);

设置 res = vec1 + vec2*scl。

mju_normalize#

mjtNum mju_normalize(mjtNum* res, int n);

归一化向量;返回归一化前的长度。

mju_norm#

mjtNum mju_norm(const mjtNum* res, int n);

返回向量长度(不归一化向量)。

mju_dot#

mjtNum mju_dot(const mjtNum* vec1, const mjtNum* vec2, int n);

返回 vec1 和 vec2 的点积。

mju_mulMatVec#

void mju_mulMatVec(mjtNum* res, const mjtNum* mat, const mjtNum* vec, int nr, int nc);

矩阵与向量相乘:res = mat * vec。

mju_mulMatTVec#

void mju_mulMatTVec(mjtNum* res, const mjtNum* mat, const mjtNum* vec, int nr, int nc);

转置矩阵与向量相乘:res = mat’ * vec。

mju_mulVecMatVec#

mjtNum mju_mulVecMatVec(const mjtNum* vec1, const mjtNum* mat, const mjtNum* vec2, int n);

方阵与两侧向量相乘:返回 vec1’ * mat * vec2。

mju_transpose#

void mju_transpose(mjtNum* res, const mjtNum* mat, int nr, int nc);

转置矩阵:res = mat’。

mju_symmetrize#

void mju_symmetrize(mjtNum* res, const mjtNum* mat, int n);

对称化方阵 \(R = \frac{1}{2}(M + M^T)\)

mju_eye#

void mju_eye(mjtNum* mat, int n);

将 mat 设置为单位矩阵。

mju_mulMatMat#

void mju_mulMatMat(mjtNum* res, const mjtNum* mat1, const mjtNum* mat2,
                   int r1, int c1, int c2);

矩阵相乘:res = mat1 * mat2。

mju_mulMatMatT#

void mju_mulMatMatT(mjtNum* res, const mjtNum* mat1, const mjtNum* mat2,
                    int r1, int c1, int r2);

矩阵相乘,第二个参数转置:res = mat1 * mat2’。

mju_mulMatTMat#

void mju_mulMatTMat(mjtNum* res, const mjtNum* mat1, const mjtNum* mat2,
                    int r1, int c1, int c2);

矩阵相乘,第一个参数转置:res = mat1’ * mat2。

mju_sqrMatTD#

void mju_sqrMatTD(mjtNum* res, const mjtNum* mat, const mjtNum* diag, int nr, int nc);

如果 diag 不为 NULL,设置 res = mat’ * diag * mat,否则 res = mat’ * mat。

mju_transformSpatial#

void mju_transformSpatial(mjtNum res[6], const mjtNum vec[6], int flg_force,
                          const mjtNum newpos[3], const mjtNum oldpos[3],
                          const mjtNum rotnew2old[9]);

以旋转:平移格式的 6D 运动或力向量的坐标变换。rotnew2old 是 3x3,NULL 表示不旋转;flg_force 指定力或运动类型。

可为空 (Nullable): rotnew2old

稀疏数学#

mju_dense2sparse#

int mju_dense2sparse(mjtNum* res, const mjtNum* mat, int nr, int nc,
                     int* rownnz, int* rowadr, int* colind, int nnz);
将矩阵从稠密转换为稀疏。

nnz 是 res 和 colind 的大小;如果太小返回 1,否则返回 0。

mju_sparse2dense#

void mju_sparse2dense(mjtNum* res, const mjtNum* mat, int nr, int nc,
                      const int* rownnz, const int* rowadr, const int* colind);

将矩阵从稀疏转换为稠密。

mju_sym2dense#

void mju_sym2dense(mjtNum* res, const mjtNum* mat, int n,
                   const int* rownnz, const int* rowadr, const int* colind);

将下三角对称 CSR 矩阵转换为完整稠密矩阵。

四元数#

mju_rotVecQuat#

void mju_rotVecQuat(mjtNum res[3], const mjtNum vec[3], const mjtNum quat[4]);

通过四元数旋转向量。

mju_negQuat#

void mju_negQuat(mjtNum res[4], const mjtNum quat[4]);

四元数共轭,对应相反旋转。

mju_mulQuat#

void mju_mulQuat(mjtNum res[4], const mjtNum quat1[4], const mjtNum quat2[4]);

四元数相乘。

mju_mulQuatAxis#

void mju_mulQuatAxis(mjtNum res[4], const mjtNum quat[4], const mjtNum axis[3]);

四元数和轴相乘。

mju_axisAngle2Quat#

void mju_axisAngle2Quat(mjtNum res[4], const mjtNum axis[3], mjtNum angle);

将轴角转换为四元数。

mju_quat2Vel#

void mju_quat2Vel(mjtNum res[3], const mjtNum quat[4], mjtNum dt);

将四元数(对应方位差)转换为 3D 速度。

mju_subQuat#

void mju_subQuat(mjtNum res[3], const mjtNum qa[4], const mjtNum qb[4]);

四元数相减,表示为 3D 速度:qb*quat(res) = qa。

mju_quat2Mat#

void mju_quat2Mat(mjtNum res[9], const mjtNum quat[4]);

将四元数转换为 3D 旋转矩阵。

mju_mat2Quat#

void mju_mat2Quat(mjtNum quat[4], const mjtNum mat[9]);

将 3D 旋转矩阵转换为四元数。

mju_derivQuat#

void mju_derivQuat(mjtNum res[4], const mjtNum quat[4], const mjtNum vel[3]);

给定 3D 旋转速度,计算四元数的时间导数。

mju_quatIntegrate#

void mju_quatIntegrate(mjtNum quat[4], const mjtNum vel[3], mjtNum scale);

给定 3D 角速度积分四元数。

mju_quatZ2Vec#

void mju_quatZ2Vec(mjtNum quat[4], const mjtNum vec[3]);

构造执行从 z 轴到给定向量旋转的四元数。

mju_mat2Rot#

int mju_mat2Rot(mjtNum quat[4], const mjtNum mat[9]);

通过细化输入四元数从任意 3x3 矩阵中提取 3D 旋转。

返回收敛所需的迭代次数。

mju_euler2Quat#

void mju_euler2Quat(mjtNum quat[4], const mjtNum euler[3], const char* seq);

将欧拉角序列(弧度)转换为四元数。seq[0,1,2] 必须为 ‘xyzXYZ’,大小写表示内/外旋转。

位姿#

mju_mulPose#

void mju_mulPose(mjtNum posres[3], mjtNum quatres[4],
                 const mjtNum pos1[3], const mjtNum quat1[4],
                 const mjtNum pos2[3], const mjtNum quat2[4]);

两个位姿相乘。

mju_negPose#

void mju_negPose(mjtNum posres[3], mjtNum quatres[4],
                 const mjtNum pos[3], const mjtNum quat[4]);

位姿共轭,对应相反的空间变换。

mju_trnVecPose#

void mju_trnVecPose(mjtNum res[3], const mjtNum pos[3], const mjtNum quat[4],
                    const mjtNum vec[3]);

通过位姿变换向量。

分解 / 求解器#

mju_cholFactor#

int mju_cholFactor(mjtNum* mat, int n, mjtNum mindiag);

Cholesky 分解:mat = L*L’;返回秩,分解原位在 mat 中执行。

mju_cholSolve#

void mju_cholSolve(mjtNum* res, const mjtNum* mat, const mjtNum* vec, int n);

求解 (mat*mat’) * res = vec,其中 mat 是 Cholesky 因子。

mju_cholUpdate#

int mju_cholUpdate(mjtNum* mat, mjtNum* x, int n, int flg_plus);

Cholesky 一阶更新:L*L’ +/- x*x’;返回秩。

mju_cholFactorBand#

mjtNum mju_cholFactorBand(mjtNum* mat, int ntotal, int nband, int ndense,
                          mjtNum diagadd, mjtNum diagmul);

带状稠密 Cholesky 分解。
在分解前将 diagadd + diagmul*mat_ii 添加到对角线。
返回因式分解对角线的最小值,如果秩亏则返回 0。

对称带状稠密矩阵

mju_cholFactorBand 和包含子字符串“band”的后续函数对矩阵进行操作,这些矩阵是对称 带状矩阵 的泛化。*对称带状稠密*或“箭头”矩阵在近对角带上具有非零值,在底部行和右侧列具有稠密块。这些矩阵的特性是 Cholesky 分解不会产生填入,因此可以在原位高效执行。矩阵结构由三个整数定义

  • ntotal:对称矩阵的行(列)数。

  • nband:对角线下方(上方)的带数,包含对角线。

  • ndense:底部(右侧)的稠密行(列)数。

非零值在内存中存储为两个连续的行优先块,如下图中的绿色和蓝色所示。第一个块的大小为 nband x (ntotal-ndense),包含对角线及其下方的带。第二个块的大小为 ndense x ntotal,包含稠密部分。总所需内存是块大小之和。

../_images/arrowhead.svg

例如,考虑一个带状箭头矩阵(arrowhead matrix),其中 nband = 3ndense = 2ntotal = 8。在此示例中,所需的总内存为 3*(8-2) + 2*8 = 34 个 mjtNum,布局如下

0   1   2
    3   4   5
        6   7   8
            9   10  11
                12  13  14
                    15  16  17
        18  19  20  21  22  23  24  25
        26  27  28  29  30  31  32  33

对角元素为 2, 5, 8, 11, 14, 17, 24, 33
元素 0, 1, 3, 25 存在于内存中,但从未被访问。

mju_cholSolveBand#

void mju_cholSolveBand(mjtNum* res, const mjtNum* mat, const mjtNum* vec,
                       int ntotal, int nband, int ndense);

求解 (mat*mat’)*res = vec,其中 mat 为带状稠密 Cholesky 因子。

mju_band2Dense#

void mju_band2Dense(mjtNum* res, const mjtNum* mat, int ntotal, int nband, int ndense,
                    mjtBool flg_sym);

将带状矩阵转换为稠密矩阵,若 flg_sym>0 则填充上三角部分。

mju_dense2Band#

void mju_dense2Band(mjtNum* res, const mjtNum* mat, int ntotal, int nband, int ndense);

将稠密矩阵转换为带状矩阵。

mju_bandMulMatVec#

void mju_bandMulMatVec(mjtNum* res, const mjtNum* mat, const mjtNum* vec,
                       int ntotal, int nband, int ndense, int nvec, mjtBool flg_sym);

将带状对角矩阵与 nvec 个向量相乘,若 flg_sym>0 则包含上三角部分。

mju_bandDiag#

int mju_bandDiag(int i, int ntotal, int nband, int ndense);

带状稠密矩阵表示中第 i 个对角元素的地址。

mju_eig3#

int mju_eig3(mjtNum eigval[3], mjtNum eigvec[9], mjtNum quat[4], const mjtNum mat[9]);

对称 3x3 矩阵的特征值分解,mat = eigvec * diag(eigval) * eigvec’。

mju_boxQP#

int mju_boxQP(mjtNum* res, mjtNum* R, int* index, const mjtNum* H, const mjtNum* g, int n,
              const mjtNum* lower, const mjtNum* upper);

最小化 \(\tfrac{1}{2} x^T H x + x^T g \quad \text{s.t.} \quad l \le x \le u\),返回秩,失败则返回 -1。

输入

n - 问题维度

H - SPD 矩阵 n*n

g - 偏置向量 n

lower - 下界 n

upper - 上界 n

res - 解的冷启动/热启动向量 n

返回值

nfree <= n - 无约束子空间的秩,失败则返回 -1

输出(必需)

res - 解向量 n

R - 子空间 Cholesky 因子 nfree*nfree,已分配:n*(n+7)

输出(可选)

index - 自由维度集合 nfree,已分配:n

备注

res 的初始值用于求解器的热启动。R 必须分配大小为 n*(n+7),但输出时仅使用 nfree*nfree 个值。index(若提供)必须分配大小为 n,但输出时仅使用 nfree 个值。辅助函数 mju_boxQPmalloc 可分配所需的数据结构。H 和 R 的下三角部分分别被读取和写入。

mju_boxQPmalloc#

void mju_boxQPmalloc(mjtNum** res, mjtNum** R, int** index, mjtNum** H, mjtNum** g, int n,
                     mjtNum** lower, mjtNum** upper);

为盒约束二次规划分配堆内存。与 mju_boxQP 一样,indexlowerupper 为可选。使用 mju_free() 释放所有指针。

附加#

mjs_attach#

mjsElement* mjs_attach(mjsElement* parent, const mjsElement* child,
                       const char* prefix, const char* suffix);

将子元素附加到父元素;成功则返回附加的元素,否则返回 NULL。

树元素#

mjs_addBody#

mjsBody* mjs_addBody(mjsBody* body, const mjsDefault* def);

将子刚体添加到刚体;返回子刚体。

可为空: def

mjs_addSite#

mjsSite* mjs_addSite(mjsBody* body, const mjsDefault* def);

将位点(site)添加到刚体;返回位点规范。

可为空: def

mjs_addJoint#

mjsJoint* mjs_addJoint(mjsBody* body, const mjsDefault* def);

将关节添加到刚体。

可为空: def

mjs_addFreeJoint#

mjsJoint* mjs_addFreeJoint(mjsBody* body);

将自由关节添加到刚体。

mjs_addGeom#

mjsGeom* mjs_addGeom(mjsBody* body, const mjsDefault* def);

将几何体(geom)添加到刚体。

可为空: def

mjs_addCamera#

mjsCamera* mjs_addCamera(mjsBody* body, const mjsDefault* def);

将相机添加到刚体。

可为空: def

mjs_addLight#

mjsLight* mjs_addLight(mjsBody* body, const mjsDefault* def);

将光源添加到刚体。

可为空: def

mjs_addFrame#

mjsFrame* mjs_addFrame(mjsBody* body, mjsFrame* parentframe);

将坐标系(frame)添加到刚体。

mjs_delete#

int mjs_delete(mjSpec* spec, mjsElement* element);

移除对应给定元素的对象;成功返回 0。

非树元素#

mjs_addActuator#

mjsActuator* mjs_addActuator(mjSpec* s, const mjsDefault* def);

添加执行器。

可为空: def

mjs_addSensor#

mjsSensor* mjs_addSensor(mjSpec* s);

添加传感器。

mjs_addFlex#

mjsFlex* mjs_addFlex(mjSpec* s);

添加柔性体(flex)。

mjs_addPair#

mjsPair* mjs_addPair(mjSpec* s, const mjsDefault* def);

添加接触对。

可为空: def

mjs_addExclude#

mjsExclude* mjs_addExclude(mjSpec* s);

添加排除刚体对。

mjs_addEquality#

mjsEquality* mjs_addEquality(mjSpec* s, const mjsDefault* def);

添加等式约束。

可为空: def

mjs_addTendon#

mjsTendon* mjs_addTendon(mjSpec* s, const mjsDefault* def);

添加肌腱。

可为空: def

mjs_wrapSite#

mjsWrap* mjs_wrapSite(mjsTendon* tendon, const char* name);

使用肌腱包裹位点。

mjs_wrapGeom#

mjsWrap* mjs_wrapGeom(mjsTendon* tendon, const char* name, const char* sidesite);

使用肌腱包裹几何体。

mjs_wrapJoint#

mjsWrap* mjs_wrapJoint(mjsTendon* tendon, const char* name, double coef);

使用肌腱包裹关节。

mjs_wrapPulley#

mjsWrap* mjs_wrapPulley(mjsTendon* tendon, double divisor);

使用肌腱包裹滑轮。

mjs_addNumeric#

mjsNumeric* mjs_addNumeric(mjSpec* s);

添加数值项。

mjs_addText#

mjsText* mjs_addText(mjSpec* s);

添加文本项。

mjs_addTuple#

mjsTuple* mjs_addTuple(mjSpec* s);

添加元组。

mjs_addKey#

mjsKey* mjs_addKey(mjSpec* s);

添加关键帧。

mjs_addPlugin#

mjsPlugin* mjs_addPlugin(mjSpec* s);

添加插件。

mjs_addDefault#

mjsDefault* mjs_addDefault(mjSpec* s, const char* classname, const mjsDefault* parent);

添加默认属性。

可为空: parent

设置执行器参数#

mjs_setToMotor#

const char* mjs_setToMotor(mjsActuator* actuator);

将执行器设为电机;如有错误则返回。

mjs_setToPosition#

const char* mjs_setToPosition(mjsActuator* actuator, double kp, double kv[1],
                              double dampratio[1], double timeconst[1], double inheritrange);

将执行器设为位置伺服;如有错误则返回。

mjs_setToIntVelocity#

const char* mjs_setToIntVelocity(mjsActuator* actuator, double kp, double kv[1],
                                 double dampratio[1], double timeconst[1], double inheritrange);

将执行器设为积分速度控制;如有错误则返回。

mjs_setToVelocity#

const char* mjs_setToVelocity(mjsActuator* actuator, double kv);

将执行器设为速度伺服;如有错误则返回。

mjs_setToDamper#

const char* mjs_setToDamper(mjsActuator* actuator, double kv);

将执行器设为阻尼器;如有错误则返回。

mjs_setToCylinder#

const char* mjs_setToCylinder(mjsActuator* actuator, double timeconst,
                              double bias, double area, double diameter);

将执行器设为液压或气压缸;如有错误则返回。

mjs_setToMuscle#

const char* mjs_setToMuscle(mjsActuator* actuator, double timeconst[2], double tausmooth,
                            double range[2], double force, double scale, double lmin,
                            double lmax, double vmax, double fpmax, double fvmax);

将执行器设为肌肉模型;如有错误则返回。

mjs_setToAdhesion#

const char* mjs_setToAdhesion(mjsActuator* actuator, double gain);

将执行器设为主动附着;如有错误则返回。

mjs_setToDCMotor#

const char* mjs_setToDCMotor(mjsActuator* actuator, double motorconst[2], double resistance,
                             double nominal[3], double saturation[3], double inductance[2],
                             double cogging[3], double controller[6], double thermal[6],
                             double lugre[5], int input_mode);

将执行器设为直流电机;如有错误则返回。

可为空: motorconst, nominal, saturation, inductance, cogging, controller, thermal, lugre

资源#

mjs_addMesh#

mjsMesh* mjs_addMesh(mjSpec* s, const mjsDefault* def);

添加网格。

可为空: def

mjs_addHField#

mjsHField* mjs_addHField(mjSpec* s);

添加高度场。

mjs_addSkin#

mjsSkin* mjs_addSkin(mjSpec* s);

添加蒙皮。

mjs_addTexture#

mjsTexture* mjs_addTexture(mjSpec* s);

添加纹理。

mjs_addMaterial#

mjsMaterial* mjs_addMaterial(mjSpec* s, const mjsDefault* def);

添加材质。

可为空: def

mjs_makeMesh#

int mjs_makeMesh(mjsMesh* mesh, mjtMeshBuiltin builtin, double* params, int nparams);

设置网格的顶点和法线。

查找与获取工具#

mjs_getSpec#

mjSpec* mjs_getSpec(const mjsElement* element);

从刚体获取规格(spec)。

mjs_getOriginSpec#

mjSpec* mjs_getOriginSpec(const mjsElement* element);

获取最初定义元素的规格,与 mjs_getSpec 不同,此值在附加后不会更改。

mjs_getCompiler#

mjsCompiler* mjs_getCompiler(const mjsElement* element);

获取与元素原始规格关联的编译器。

mjs_findSpec#

mjSpec* mjs_findSpec(const mjSpec* spec, const char* name);

按名称查找规格(模型资产)。

mjs_findBody#

mjsBody* mjs_findBody(const mjSpec* s, const char* name);

按名称在规格中查找刚体。

mjs_findElement#

mjsElement* mjs_findElement(const mjSpec* s, mjtObj type, const char* name);

按名称在规格中查找元素。

mjs_findChild#

mjsBody* mjs_findChild(const mjsBody* body, const char* name);

按名称查找子刚体。

mjs_getParent#

mjsBody* mjs_getParent(const mjsElement* element);

获取父刚体。

mjs_getFrame#

mjsFrame* mjs_getFrame(const mjsElement* element);

获取父坐标系。

mjs_findFrame#

mjsFrame* mjs_findFrame(const mjSpec* s, const char* name);

按名称查找坐标系。

mjs_getDefault#

mjsDefault* mjs_getDefault(const mjsElement* element);

获取与元素对应的默认属性。

mjs_findDefault#

mjsDefault* mjs_findDefault(const mjSpec* s, const char* classname);

按类名查找模型中的默认属性。

mjs_getSpecDefault#

mjsDefault* mjs_getSpecDefault(const mjSpec* s);

获取模型中的全局默认属性。

mjs_getId#

int mjs_getId(const mjsElement* element);

获取元素 ID。

mjs_firstChild#

mjsElement* mjs_firstChild(const mjsBody* body, mjtObj type, int recurse);

返回刚体给定类型的第一个子元素。如果 recurse 非零,则同时搜索刚体的子树。

mjs_nextChild#

mjsElement* mjs_nextChild(const mjsBody* body, const mjsElement* child, int recurse);

返回刚体相同类型的下一个子元素;如果子元素是最后一个,则返回 NULL。

如果 recurse 非零,则同时搜索刚体的子树。

mjs_firstElement#

mjsElement* mjs_firstElement(const mjSpec* s, mjtObj type);

返回规格中选定类型的第一个元素。

mjs_nextElement#

mjsElement* mjs_nextElement(const mjSpec* s, const mjsElement* element);

返回规格的下一个元素;如果元素是最后一个,则返回 NULL。

mjs_getWrapTarget#

mjsElement* mjs_getWrapTarget(const mjsWrap* wrap);

获取肌腱路径中包裹的目标元素。

mjs_getWrapSideSite#

mjsSite* mjs_getWrapSideSite(const mjsWrap* wrap);

获取肌腱路径中包裹元素的侧边位点(如果存在),否则返回 nullptr。

mjs_getWrapDivisor#

double mjs_getWrapDivisor(const mjsWrap* wrap);

获取包裹滑轮的 mjsWrap 除数。

mjs_getWrapCoef#

double mjs_getWrapCoef(const mjsWrap* wrap);

获取包裹关节的 mjsWrap 系数。

属性设置器#

mjs_setName#

int mjs_setName(mjsElement* element, const char* name);

设置元素名称;成功返回 0。

mjs_setBuffer#

void mjs_setBuffer(mjByteVec* dest, const void* array, int size);

复制缓冲区。

mjs_setString#

void mjs_setString(mjString* dest, const char* text);

将文本复制到字符串。

mjs_setStringVec#

void mjs_setStringVec(mjStringVec* dest, const char* text);

将文本拆分为多个条目并复制到字符串向量。

mjs_setInStringVec#

mjtBool mjs_setInStringVec(mjStringVec* dest, int i, const char* text);

设置字符串向量中的条目。

mjs_appendString#

void mjs_appendString(mjStringVec* dest, const char* text);

将文本条目追加到字符串向量。

mjs_setInt#

void mjs_setInt(mjIntVec* dest, const int* array, int size);

将整数数组复制到向量。

mjs_appendIntVec#

void mjs_appendIntVec(mjIntVecVec* dest, const int* array, int size);

将整数数组追加到数组向量。

mjs_setFloat#

void mjs_setFloat(mjFloatVec* dest, const float* array, int size);

将浮点数数组复制到向量。

mjs_appendFloatVec#

void mjs_appendFloatVec(mjFloatVecVec* dest, const float* array, int size);

将浮点数数组追加到数组向量。

mjs_setDouble#

void mjs_setDouble(mjDoubleVec* dest, const double* array, int size);

将双精度浮点数组复制到向量。

mjs_setPluginAttributes#

void mjs_setPluginAttributes(mjsPlugin* plugin, void* attributes);

设置插件属性。

属性获取器#

mjs_getName#

mjString* mjs_getName(mjsElement* element);

获取元素名称。

mjs_getString#

const char* mjs_getString(const mjString* source);

获取字符串内容。

mjs_getDouble#

const double* mjs_getDouble(const mjDoubleVec* source, int* size);

获取双精度数组内容及其大小(可选)。

可为空: size

mjs_getWrapNum#

int mjs_getWrapNum(const mjsTendon* tendonspec);

获取肌腱包裹的元素数量。

mjs_getWrap#

mjsWrap* mjs_getWrap(const mjsTendon* tendonspec, int i);

获取肌腱路径中索引 i 处的 mjsWrap 元素。

mjs_getPluginAttributes#

const void* mjs_getPluginAttributes(const mjsPlugin* plugin);

获取插件属性。

规格工具#

mjs_setDefault#

void mjs_setDefault(mjsElement* element, const mjsDefault* def);

设置元素的默认属性。

mjs_setFrame#

int mjs_setFrame(mjsElement* dest, mjsFrame* frame);

设置元素的从属坐标系;成功返回 0。

mjs_resolveOrientation#

const char* mjs_resolveOrientation(double quat[4], mjtByte degree, const char* sequence,
                                   const mjsOrientation* orientation);

将可选的方位解析为四元数;如有错误则返回。

mjs_bodyToFrame#

mjsFrame* mjs_bodyToFrame(mjsBody** body);

将刚体转换为坐标系。

mjs_setUserValue#

void mjs_setUserValue(mjsElement* element, const char* key, const void* data);

设置用户有效载荷,若指定键已存在则覆盖原值。

mjs_setUserValueWithCleanup#

void mjs_setUserValueWithCleanup(mjsElement* element, const char* key,
                                 const void* data,
                                 void (*cleanup)(const void*));

设置用户有效载荷,若指定键已存在则覆盖原值。此版本与 mjs_setUserValue 的区别在于,它接收一个在用户有效载荷被删除时调用的清理函数。

mjs_getUserValue#

const void* mjs_getUserValue(mjsElement* element, const char* key);

返回用户有效载荷,未找到则返回 NULL。

mjs_deleteUserValue#

void mjs_deleteUserValue(mjsElement* element, const char* key);

删除用户有效载荷。

mjs_sensorDim#

int mjs_sensorDim(const mjsSensor* sensor);

返回传感器维度。

元素初始化#

mjs_defaultSpec#

void mjs_defaultSpec(mjSpec* spec);

默认规格属性。

mjs_defaultOrientation#

void mjs_defaultOrientation(mjsOrientation* orient);

默认方位属性。

mjs_defaultBody#

void mjs_defaultBody(mjsBody* body);

默认刚体属性。

mjs_defaultFrame#

void mjs_defaultFrame(mjsFrame* frame);

默认坐标系属性。

mjs_defaultJoint#

void mjs_defaultJoint(mjsJoint* joint);

默认关节属性。

mjs_defaultGeom#

void mjs_defaultGeom(mjsGeom* geom);

默认几何体属性。

mjs_defaultSite#

void mjs_defaultSite(mjsSite* site);

默认位点属性。

mjs_defaultCamera#

void mjs_defaultCamera(mjsCamera* camera);

默认相机属性。

mjs_defaultLight#

void mjs_defaultLight(mjsLight* light);

默认光源属性。

mjs_defaultFlex#

void mjs_defaultFlex(mjsFlex* flex);

默认柔性体属性。

mjs_defaultMesh#

void mjs_defaultMesh(mjsMesh* mesh);

默认网格属性。

mjs_defaultHField#

void mjs_defaultHField(mjsHField* hfield);

默认高度场属性。

mjs_defaultSkin#

void mjs_defaultSkin(mjsSkin* skin);

默认蒙皮属性。

mjs_defaultTexture#

void mjs_defaultTexture(mjsTexture* texture);

默认纹理属性。

mjs_defaultMaterial#

void mjs_defaultMaterial(mjsMaterial* material);

默认材质属性。

mjs_defaultPair#

void mjs_defaultPair(mjsPair* pair);

默认对属性。

mjs_defaultEquality#

void mjs_defaultEquality(mjsEquality* equality);

默认等式属性。

mjs_defaultTendon#

void mjs_defaultTendon(mjsTendon* tendon);

默认肌腱属性。

mjs_defaultActuator#

void mjs_defaultActuator(mjsActuator* actuator);

默认执行器属性。

mjs_defaultSensor#

void mjs_defaultSensor(mjsSensor* sensor);

默认传感器属性。

mjs_defaultNumeric#

void mjs_defaultNumeric(mjsNumeric* numeric);

默认数值属性。

mjs_defaultText#

void mjs_defaultText(mjsText* text);

默认文本属性。

mjs_defaultTuple#

void mjs_defaultTuple(mjsTuple* tuple);

默认元组属性。

mjs_defaultKey#

void mjs_defaultKey(mjsKey* key);

默认关键帧属性。

mjs_defaultPlugin#

void mjs_defaultPlugin(mjsPlugin* plugin);

默认插件属性。

元素类型转换#

mjs_asBody#

mjsBody* mjs_asBody(mjsElement* element);

将元素安全转换为 mjsBody,若元素不是 mjsBody 则返回 NULL。

mjs_asGeom#

mjsGeom* mjs_asGeom(mjsElement* element);

将元素安全转换为 mjsGeom,若元素不是 mjsGeom 则返回 NULL。

mjs_asJoint#

mjsJoint* mjs_asJoint(mjsElement* element);

将元素安全转换为 mjsJoint,若元素不是 mjsJoint 则返回 NULL。

mjs_asSite#

mjsSite* mjs_asSite(mjsElement* element);

将元素安全转换为 mjsSite,若元素不是 mjsSite 则返回 NULL。

mjs_asCamera#

mjsCamera* mjs_asCamera(mjsElement* element);

将元素安全转换为 mjsCamera,若元素不是 mjsCamera 则返回 NULL。

mjs_asLight#

mjsLight* mjs_asLight(mjsElement* element);

将元素安全转换为 mjsLight,若元素不是 mjsLight 则返回 NULL。

mjs_asFrame#

mjsFrame* mjs_asFrame(mjsElement* element);

将元素安全转换为 mjsFrame,若元素不是 mjsFrame 则返回 NULL。

mjs_asActuator#

mjsActuator* mjs_asActuator(mjsElement* element);

将元素安全转换为 mjsActuator,若元素不是 mjsActuator 则返回 NULL。

mjs_asSensor#

mjsSensor* mjs_asSensor(mjsElement* element);

将元素安全转换为 mjsSensor,若元素不是 mjsSensor 则返回 NULL。

mjs_asFlex#

mjsFlex* mjs_asFlex(mjsElement* element);

将元素安全转换为 mjsFlex,若元素不是 mjsFlex 则返回 NULL。

mjs_asPair#

mjsPair* mjs_asPair(mjsElement* element);

将元素安全转换为 mjsPair,若元素不是 mjsPair 则返回 NULL。

mjs_asEquality#

mjsEquality* mjs_asEquality(mjsElement* element);

将元素安全转换为 mjsEquality,若元素不是 mjsEquality 则返回 NULL。

mjs_asExclude#

mjsExclude* mjs_asExclude(mjsElement* element);

将元素安全转换为 mjsExclude,若元素不是 mjsExclude 则返回 NULL。

mjs_asTendon#

mjsTendon* mjs_asTendon(mjsElement* element);

将元素安全转换为 mjsTendon,若元素不是 mjsTendon 则返回 NULL。

mjs_asNumeric#

mjsNumeric* mjs_asNumeric(mjsElement* element);

将元素安全转换为 mjsNumeric,若元素不是 mjsNumeric 则返回 NULL。

mjs_asText#

mjsText* mjs_asText(mjsElement* element);

将元素安全转换为 mjsText,若元素不是 mjsText 则返回 NULL。

mjs_asTuple#

mjsTuple* mjs_asTuple(mjsElement* element);

将元素安全转换为 mjsTuple,若元素不是 mjsTuple 则返回 NULL。

mjs_asKey#

mjsKey* mjs_asKey(mjsElement* element);

将元素安全转换为 mjsKey,若元素不是 mjsKey 则返回 NULL。

mjs_asMesh#

mjsMesh* mjs_asMesh(mjsElement* element);

将元素安全转换为 mjsMesh,若元素不是 mjsMesh 则返回 NULL。

mjs_asHField#

mjsHField* mjs_asHField(mjsElement* element);

将元素安全转换为 mjsHField,若元素不是 mjsHField 则返回 NULL。

mjs_asSkin#

mjsSkin* mjs_asSkin(mjsElement* element);

将元素安全转换为 mjsSkin,若元素不是 mjsSkin 则返回 NULL。

mjs_asTexture#

mjsTexture* mjs_asTexture(mjsElement* element);

将元素安全转换为 mjsTexture,若元素不是 mjsTexture 则返回 NULL。

mjs_asMaterial#

mjsMaterial* mjs_asMaterial(mjsElement* element);

将元素安全转换为 mjsMaterial,若元素不是 mjsMaterial 则返回 NULL。

mjs_asPlugin#

mjsPlugin* mjs_asPlugin(mjsElement* element);

将元素安全转换为 mjsPlugin,若元素不是 mjsPlugin 则返回 NULL。