函数#
主头文件 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,其大小必须为 error_sz。
可为空: vfs, error
mj_parseXML#
mjSpec* mj_parseXML(const char* filename, const mjVFS* vfs, char* error, int error_sz);
从 XML 文件解析 spec。
可为空: vfs, error
mj_parseXMLString#
mjSpec* mj_parseXMLString(const char* xml, const mjVFS* vfs, char* error, int error_sz);
从 XML 字符串解析 spec。
可为空: vfs, error
mj_parse#
mjSpec* mj_parse(const char* filename, const char* content_type,
const mjVFS* vfs, char* error, int error_sz);
从文件解析 spec。
可为空: vfs, error
mj_compile#
mjModel* mj_compile(mjSpec* s, const mjVFS* vfs);
将 mjSpec 编译为 mjModel。一个 spec 可以被多次编辑和编译,每次都会返回一个新的 mjModel 实例,其中包含了所做的编辑。如果编译失败,mj_compile 返回 NULL;错误信息可以通过 mjs_getError 读取。
mj_copyBack#
int mj_copyBack(mjSpec* s, const mjModel* m);
将实值数组从模型复制到 spec,成功返回 1。
mj_recompile#
int mj_recompile(mjSpec* s, const mjVFS* vfs, mjModel* m, mjData* d);
将 spec 重新编译为模型,同时保留状态。与 mj_compile 类似,此函数将 mjSpec 编译为 mjModel,但有两个不同之处。首先,它不是返回一个全新的模型,而是就地重新分配现有的 mjModel 和 mjData 实例。其次,它会保留在提供的 mjData 实例中给出的积分状态,同时考虑到新增或移除的自由度。这允许用户在以编程方式编辑模型时,使用相同的模型和数据结构指针继续仿真。
如果编译成功,mj_recompile 返回 0。如果失败,给定的 mjModel 和 mjData 实例将被删除;与 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,其大小必须为 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);
将 spec 保存为 XML 字符串,成功返回 0,失败返回 -1。如果输出缓冲区长度太小,则返回所需大小。XML 保存会自动在保存前编译 spec。
mj_saveXML#
int mj_saveXML(const mjSpec* s, const char* filename, char* error, int error_sz);
将 spec 保存到 XML 文件,成功返回 0,否则返回 -1。XML 保存要求 spec 首先被编译。
mju_getXMLDependencies#
void mju_getXMLDependencies(const char* filename, mjStringVec* dependencies);
给定 MJCF 文件名,用其依赖的所有其他资源文件的列表填充 dependencies。
搜索是递归的,列表中包含文件名本身。
主仿真#
这些是模拟器的主要入口点。大多数用户只需要调用 mj_step,它会计算所有内容并将仿真状态推进一个时间步。控制和施加的力必须事先设置(在 mjData.{ctrl, qfrc_applied, xfrc_applied} 中),或者必须安装一个控制回调 mjcb_control,它将在需要控制和施加力之前被调用。或者,可以使用 mj_step1 和 mj_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_forward 和 mj_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。
支持#
这些是需要访问 mjModel 和 mjData 的支持函数,与不需要此类访问的工具函数不同。支持函数在模拟器内部被调用,但其中一些对于自定义计算也很有用,下面将对其进行更详细的说明。
mj_stateSize#
int mj_stateSize(const mjModel* m, unsigned int sig);
mj_getState#
void mj_getState(const mjModel* m, const mjData* d, mjtNum* state, unsigned int sig);
将由 sig 指定的串联状态分量从 d 复制到 state。整数 sig 的位对应于 mjtState 的元素字段。如果 sig 无效,则会失败并抛出 mju_error。
mj_extractState#
void mj_extractState(const mjModel* m, const mjtNum* src, unsigned int srcsig,
mjtNum* dst, unsigned int dstsig);
从先前通过 mj_getState 获得的状态 src(其分量由 srcsig 指定)中,提取由 dstsig 指定的分量子集到 dst 中。如果 dstsig 中设置的位不是 srcsig 中设置的位的子集,则会失败并抛出 mju_error。
mj_setState#
void mj_setState(const mjModel* m, mjData* d, const mjtNum* state, unsigned int sig);
将由 sig 指定的串联状态分量从 state 复制到 d。整数 sig 的位对应于 mjtState 的元素字段。如果 sig 无效,则会失败并抛出 mju_error。
mj_copyState#
void mj_copyState(const mjModel* m, const mjData* src, mjData* dst, unsigned int sig);
将状态从 src 复制到 dst。
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 将跳过该部分的计算。每个分量都是一个 3xnv 的矩阵。该矩阵的每一行是指定点的相应坐标相对于自由度的梯度。计算雅可比矩阵的参考系以物体质心为中心,但与世界坐标系对齐。为使雅可比矩阵计算与当前广义位置 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_kinematics、mj_comPos、mj_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,如果未找到 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 nv,M 的结构必须与 mjData.qM 相同。
mjData 成员 qM 和 M 以不同格式表示相同的矩阵;前者是 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, const mjData* d, int geom1, int geom2,
mjtNum distmax, mjtNum fromto[6]);
返回两个几何体之间的最小有符号距离,并可选地返回从 geom1 到 geom2 的线段。返回的距离上限为 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_step、mj_forward 和 mj_inverse 内部调用。用户不太可能需要调用它们。
mj_fwdKinematics#
void mj_fwdKinematics(const mjModel* m, mjData* d);
运行所有类运动学计算(运动学、comPos、camlight、flex、肌腱)。
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);
龙格-库塔显式 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);
将惯性和运动自由度映射到以质心为中心的全局坐标系。
mj_camlight#
void mj_camlight(const mjModel* m, mjData* d);
计算相机和光源的位置及方向。
mj_flex#
void mj_flex(const mjModel* m, mjData* d);
计算与柔性体相关的量。
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.qM 和 mjData.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 数组,所有数组都在基于子树质心的c-frame中定义,并按 [rotation(3), translation(3)] 顺序排列。
cacc: 物体加速度,mj_objectAcceleration 所需。cfrc_int: 与父物体的相互作用力。cfrc_ext: 作用在物体上的外力。
如果模型中存在以下传感器,此函数会自动触发:accelerometer、force、torque、framelinacc、frameangacc。对于阶段为 “acc” 的用户传感器,此函数也会被触发。
计算出的力数组 cfrc_int 和 cfrc_ext 目前存在一个已知错误,它们没有考虑空间肌腱的影响,请参阅 #832。
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 以及(可选的)锥海森矩阵。如果 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_multiRay#
void mj_multiRay(const mjModel* m, mjData* d, const mjtNum pnt[3], const mjtNum vec[3],
const mjtByte* geomgroup, mjtByte flg_static, int bodyexclude,
int* geomid, mjtNum* dist, int nray, mjtNum cutoff);
与从单点发出的多条光线求交。
语义与 mj_ray 类似,但 vec 是一个 (nray x 3) 方向的数组。
可为空: geomgroup
mj_ray#
mjtNum mj_ray(const mjModel* m, const mjData* d, const mjtNum pnt[3], const mjtNum vec[3],
const mjtByte* geomgroup, mjtByte flg_static, int bodyexclude,
int geomid[1]);
与可见几何体相交光线 (pnt+x*vec, x >= 0),但不包括 bodyexclude 中的几何体。
返回 geomid 和到最近表面的距离 (x),如果没有交点则返回 -1。
geomgroup 是一个长度为 mjNGROUP 的数组,其中 1 表示应包含该组。传递 geomgroup=NULL 以跳过组排除。
如果 flg_static 为 0,则将排除静态几何体。
bodyexclude=-1 可用于表示包含所有物体。
可为空: geomgroup, geomid
mj_rayHfield#
mjtNum mj_rayHfield(const mjModel* m, const mjData* d, int geomid,
const mjtNum pnt[3], const mjtNum vec[3]);
与高度场相交光线,返回最近距离,如果没有交点则返回 -1。
mj_rayMesh#
mjtNum mj_rayMesh(const mjModel* m, const mjData* d, int geomid,
const mjtNum pnt[3], const mjtNum vec[3]);
与网格相交光线,返回最近距离,如果没有交点则返回 -1。
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);
与纯几何体相交光线,返回最近距离,如果没有交点则返回 -1。
mju_rayFlex#
mjtNum mju_rayFlex(const mjModel* m, const mjData* d, int flex_layer, mjtByte flg_vert,
mjtByte flg_edge, mjtByte flg_face, mjtByte flg_skin, int flexid,
const mjtNum pnt[3], const mjtNum vec[3], int vertid[1]);
与柔性体相交光线,返回最近距离,如果没有交点则返回 -1,并输出最近的顶点 ID。
可为空: vertid
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]);
与皮肤相交光线,返回最近距离,如果没有交点则返回 -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_loadModel 或 mj_loadXML。当此指针不为 NULL 时,加载器将首先检查 VFS 中是否有它们要加载的任何文件,并且仅在 VFS 中找不到文件时才访问磁盘。
VFS 必须首先使用 mj_defaultVFS 进行分配,并且必须使用 mj_deleteVFS 进行释放。
mj_defaultVFS#
void mj_defaultVFS(mjVFS* vfs);
初始化一个空的 VFS,必须调用 mj_deleteVFS 来释放 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_deleteVFS#
void mj_deleteVFS(mjVFS* vfs);
从 VFS 中删除所有文件并释放 VFS 内部内存。
初始化#
本节包含加载/初始化模型或其他数据结构的函数。它们的使用在代码示例中得到了很好的说明。
mj_defaultLROpt#
void mj_defaultLROpt(mjLROpt* opt);
设置长度范围计算的默认选项。
mj_defaultSolRefImp#
void mj_defaultSolRefImp(mjtNum* solref, mjtNum* solimp);
将求解器参数设置为默认值。
可为空: 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 则分配新的。
可为空: dest
mj_saveModel#
void mj_saveModel(const mjModel* m, const char* filename, void* buffer, int buffer_sz);
将模型保存到二进制 MJB 文件或内存缓冲区;给定缓冲区时优先使用缓冲区。
可为空: filename, buffer
mj_loadModel#
mjModel* mj_loadModel(const char* filename, const mjVFS* vfs);
从二进制 MJB 文件加载模型。
如果 vfs 不为 NULL,则在从磁盘读取文件之前先在 vfs 中查找文件。
可为空: vfs
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 堆栈上分配 mjtNum 数组。在堆栈溢出时调用 mju_error。
mj_stackAllocInt#
int* mj_stackAllocInt(mjData* d, size_t size);
在 mjData 堆栈上分配 int 数组。在堆栈溢出时调用 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。
可为空: 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);
将 [日期时间, 类型: 消息] 写入 MUJOCO_LOG.TXT。
mjs_getError#
const char* mjs_getError(mjSpec* s);
从 spec 获取编译器错误消息。
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 函数
交互#
这些函数实现了抽象的鼠标交互,允许控制相机和扰动。它们的使用在 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]);
通过 (0,1) 和 (forward_x,forward_y) 之间的角度在水平面上旋转 3D 向量。
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 点下的 geom 的 id,如果没有 geom 则返回 -1(注意,如果存在,天空盒不是模型 geom)。被点击点的 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]);
当给定的 geom 字段不为 NULL 时初始化它们,将其余字段设置为其默认值。
可为 Null: size, pos, mat, rgba
mjv_connector#
void mjv_connector(mjvGeom* geom, int type, mjtNum width,
const mjtNum from[3], const mjtNum to[3]);
为给定点之间的连接器类型 geom 设置 (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,跳过抽象可视化不需要的大数组。
可为空: dest
mjv_addGeoms#
void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* opt,
const mjvPerturb* pert, int catmask, mjvScene* scn);
从选定类别添加 geom。
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);
计算相机位置和前向、上向和右向向量。
可为 Null: headpos, forward, up, right
mjv_cameraFrustum#
void mjv_cameraFrustum(float zver[2], float zhor[2], float zclip[2], const mjModel* m,
const mjvCamera* cam);
计算相机视锥:垂直、水平和裁剪平面。
可为 Null: 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。
如果只有一个缓冲区可用,则设置该缓冲区并忽略 framebuffer 参数。
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 主题间距 (ind: 0-1)。
mjui_themeColor#
mjuiThemeColor mjui_themeColor(int ind);
获取内置 UI 主题颜色 (ind: 0-3)。
mjui_add#
void mjui_add(mjUI* ui, const mjuiDef* def);
这是用于构建 UI 的辅助函数。第二个参数指向一个 mjuiDef 结构数组,每个结构对应一个项目。最后一个(未使用的)项目的类型设置为 -1,以标记终止。这些项目被添加到最后一个已使用部分的末尾。此函数还有另一个版本 (mjui_addToSection),它将项目添加到指定部分,而不是在 UI 的末尾添加。请记住,每个部分和每个部分的项目都有预先分配的最大数量,由 mjMAXUISECT 和 mjMAXUIITEM 给出。超过这些最大值会导致低级错误。
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 发生更改时调用。dsffsdg
导数#
下面的函数提供了各种函数的有用导数,包括解析导数和有限差分导数。后者的名称带有后缀 FD。请注意,与 API 的大部分内容不同,导数函数的输出是尾随参数而不是前导参数。
mjd_transitionFD#
void mjd_transitionFD(const mjModel* m, mjData* d, mjtNum eps, mjtByte flg_centered,
mjtNum* A, mjtNum* B, mjtNum* C, mjtNum* D);
计算有限差分离散时间转换矩阵。
设 \(x, u\) 表示 mjData 实例中当前的状态和控制向量,设 \(y, s\) 表示下一个状态和传感器值,顶层 mj_step 函数计算 \((x,u) \rightarrow (y,s)\)。mjd_transitionFD 使用有限差分计算四个相关的雅可比矩阵。这些矩阵及其维度是
矩阵 |
雅可比 |
维度 |
|---|---|---|
|
\(\partial y / \partial x\) |
|
|
\(\partial y / \partial u\) |
|
|
\(\partial s / \partial x\) |
|
|
\(\partial s / \partial u\) |
|
所有输出都是可选的(可以为 NULL)。
eps是有限差分 epsilon。flg_centered表示是使用前向(0)还是中心(1)差分。不支持龙格-库塔积分器 (mjINT_RK4)。
提高速度和准确性
- 热启动
如果热启动没有被禁用,那么在每次相关管线调用开始时,都会加载调用时存在的暖启动加速度
mjData.qacc_warmstart,以保持确定性。如果求解器计算是模拟中昂贵的一部分,以下技巧可以显著提高速度:首先调用 mj_forward 让求解器收敛,然后显著减少求解器迭代次数,然后调用 mjd_transitionFD,最后恢复迭代次数的原始值。因为我们已经接近解,所以只需要很少的迭代就能找到新的最小值。这对于牛顿求解器尤其如此,在最小值附近收敛所需的迭代次数可以低至 1。- tolerance
如果将求解器容差设置为 0,则可以提高准确性。这意味着对求解器的所有调用都将执行完全相同的迭代次数,从而防止由于提前终止而产生的数值误差。当然,这意味着求解器迭代次数应该很小,以免在最小值处做无用功。此方法和上述方法可以并且应该结合使用。
可为 Null: A, B, D, C
mjd_inverseFD#
void mjd_inverseFD(const mjModel* m, mjData* d, mjtNum eps, mjtByte 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 使用有限差分计算七个相关的雅可比矩阵。这些矩阵及其维度是
矩阵 |
雅可比 |
维度 |
|---|---|---|
|
\(\partial f / \partial q\) |
|
|
\(\partial f / \partial v\) |
|
|
\(\partial f / \partial a\) |
|
|
\(\partial s / \partial q\) |
|
|
\(\partial s / \partial v\) |
|
|
\(\partial s / \partial a\) |
|
|
\(\partial M / \partial q\) |
|
所有输出都是可选的(可以为 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 求解器。
可为 Null: 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 的导数(四元数差)。
可为 Null: 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\) 表示修改前的四元数
请注意,导数仅取决于 \(h\) 和 \(v\)(实际上是 \(s = h v\))。所有输出都是可选的。
可为 Null: Dquat, Dvel, Dscale
插件#
mjp_defaultPlugin#
void mjp_defaultPlugin(mjpPlugin* plugin);
设置默认插件定义。
mjp_registerPlugin#
int mjp_registerPlugin(const mjpPlugin* plugin);
全局注册一个插件。此函数是线程安全的。
如果已经注册了相同的 mjpPlugin,此函数不执行任何操作。
如果已经注册了一个名称相同但内容不同的 mjpPlugin,则会引发 mju_error。
如果所有成员函数指针和数字都相等,并且名称和属性字符串都相同,则认为两个 mjpPlugin 是相同的,但是指向字符串的 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 的槽号。
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。
线程#
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 指定力或运动类型。
可为 Null: 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_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,包含密集部分。所需的总内存是块大小的总和。![]()
例如,考虑一个箭头矩阵,其中
nband = 3,ndense = 2和ntotal = 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,
mjtByte 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, mjtByte 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*ng- 偏置向量nlower- 下界nupper- 上界nres- 解的热启动n- 返回值
nfree <= n- 无约束子空间的秩,如果失败则为 -1- 输出(必需)
res- 解nR- 子空间 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 中一样,index、lower 和 upper 是可选的。使用 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);
将子物体添加到物体,返回子物体。
可为 Null: def
mjs_addSite#
mjsSite* mjs_addSite(mjsBody* body, const mjsDefault* def);
将站点添加到物体,返回站点规范。
可为 Null: def
mjs_addJoint#
mjsJoint* mjs_addJoint(mjsBody* body, const mjsDefault* def);
将关节添加到物体。
可为 Null: def
mjs_addFreeJoint#
mjsJoint* mjs_addFreeJoint(mjsBody* body);
将自由关节添加到物体。
mjs_addGeom#
mjsGeom* mjs_addGeom(mjsBody* body, const mjsDefault* def);
将几何体添加到物体。
可为 Null: def
mjs_addCamera#
mjsCamera* mjs_addCamera(mjsBody* body, const mjsDefault* def);
将相机添加到物体。
可为 Null: def
mjs_addLight#
mjsLight* mjs_addLight(mjsBody* body, const mjsDefault* def);
将灯光添加到物体。
可为 Null: def
mjs_addFrame#
mjsFrame* mjs_addFrame(mjsBody* body, mjsFrame* parentframe);
将坐标帧添加到物体。
mjs_delete#
int mjs_delete(mjSpec* spec, mjsElement* element);
移除与给定元素对应的对象,成功返回 0。
非树元素#
mjs_addActuator#
mjsActuator* mjs_addActuator(mjSpec* s, const mjsDefault* def);
添加执行器。
可为 Null: def
mjs_addSensor#
mjsSensor* mjs_addSensor(mjSpec* s);
添加传感器。
mjs_addFlex#
mjsFlex* mjs_addFlex(mjSpec* s);
添加柔性体。
mjs_addPair#
mjsPair* mjs_addPair(mjSpec* s, const mjsDefault* def);
添加接触对。
可为 Null: def
mjs_addExclude#
mjsExclude* mjs_addExclude(mjSpec* s);
添加排除的物体对。
mjs_addEquality#
mjsEquality* mjs_addEquality(mjSpec* s, const mjsDefault* def);
添加等式约束。
可为 Null: def
mjs_addTendon#
mjsTendon* mjs_addTendon(mjSpec* s, const mjsDefault* def);
添加肌腱。
可为 Null: 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);
添加默认值。
可为 Null: parent
资源#
mjs_addMesh#
mjsMesh* mjs_addMesh(mjSpec* s, const mjsDefault* def);
添加网格。
可为 Null: 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);
添加材质。
可为 Null: def
mjs_makeMesh#
int mjs_makeMesh(mjsMesh* mesh, mjtMeshBuiltin builtin, double* params, int nparams);
设置网格的顶点和法线。
查找和获取工具#
mjs_getSpec#
mjSpec* mjs_getSpec(mjsElement* element);
从物体获取规范。
mjs_findSpec#
mjSpec* mjs_findSpec(mjSpec* spec, const char* name);
按名称查找规范(模型资源)。
mjs_findBody#
mjsBody* mjs_findBody(mjSpec* s, const char* name);
按名称在规范中查找物体。
mjs_findElement#
mjsElement* mjs_findElement(mjSpec* s, mjtObj type, const char* name);
按名称在规范中查找元素。
mjs_findChild#
mjsBody* mjs_findChild(mjsBody* body, const char* name);
按名称查找子物体。
mjs_getParent#
mjsBody* mjs_getParent(mjsElement* element);
获取父物体。
mjs_getFrame#
mjsFrame* mjs_getFrame(mjsElement* element);
获取父坐标帧。
mjs_findFrame#
mjsFrame* mjs_findFrame(mjSpec* s, const char* name);
按名称查找坐标帧。
mjs_getDefault#
mjsDefault* mjs_getDefault(mjsElement* element);
获取与元素对应的默认值。
mjs_findDefault#
mjsDefault* mjs_findDefault(mjSpec* s, const char* classname);
按类名在模型中查找默认值。
mjs_getSpecDefault#
mjsDefault* mjs_getSpecDefault(mjSpec* s);
从模型获取全局默认值。
mjs_getId#
int mjs_getId(mjsElement* element);
获取元素 ID。
mjs_firstChild#
mjsElement* mjs_firstChild(mjsBody* body, mjtObj type, int recurse);
返回物体的给定类型的第一个子元素。如果 recurse 非零,则也搜索物体的子树。
mjs_nextChild#
mjsElement* mjs_nextChild(mjsBody* body, mjsElement* child, int recurse);
返回物体的相同类型的下一个子元素;如果子元素是最后一个,则返回 NULL。
如果 recurse 非零,也搜索物体的子树。
mjs_firstElement#
mjsElement* mjs_firstElement(mjSpec* s, mjtObj type);
返回规范中选定类型的第一个元素。
mjs_nextElement#
mjsElement* mjs_nextElement(mjSpec* s, mjsElement* element);
返回规范的下一个元素;如果元素是最后一个,则返回 NULL。
mjs_getWrapTarget#
mjsElement* mjs_getWrapTarget(mjsWrap* wrap);
获取肌腱路径中被包裹的元素。
mjs_getWrapSideSite#
mjsSite* mjs_getWrapSideSite(mjsWrap* wrap);
如果肌腱路径中被包裹的元素有侧站点,则获取该站点,否则返回 nullptr。
mjs_getWrapDivisor#
double mjs_getWrapDivisor(mjsWrap* wrap);
获取包裹滑轮的 mjsWrap 的除数。
mjs_getWrapCoef#
double mjs_getWrapCoef(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#
mjtByte 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);
将 int 数组复制到向量。
mjs_appendIntVec#
void mjs_appendIntVec(mjIntVecVec* dest, const int* array, int size);
将 int 数组附加到数组向量。
mjs_setFloat#
void mjs_setFloat(mjFloatVec* dest, const float* array, int size);
将 float 数组复制到向量。
mjs_appendFloatVec#
void mjs_appendFloatVec(mjFloatVecVec* dest, const float* array, int size);
将 float 数组附加到数组向量。
mjs_setDouble#
void mjs_setDouble(mjDoubleVec* dest, const double* array, int size);
将 double 数组复制到向量。
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);
获取插件属性。
Spec 实用程序#
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);
默认 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。