
简介一份配合CMake构建MuJoCo项目的入门指南与可运行工程面向C开发者、机器人学研究人员及强化学习爱好者。内容从MuJoCo物理引擎的核心动力学求解器讲起说明如何通过CMakeLists.txt正确链接Mujoco库、加载XML模型并调用mj_step执行多体系统模拟同时涵盖安装配置、编译构建、命令行运行等基本流程帮助读者快速搭建自己的动力学计算环境。资源共217个文件压缩包约26.29MB主要包含C/C源程序、CMake配置、Makefile、头文件、URDF/STL三维模型以及编译中间产物等另有txt文档、json配置和js脚本可辅助理解参数设置与数据组织目录内还保留构建缓存与日志便于对照排错。已有307人学习下载。借助这份资料可得到完整的工程模板与示例代码理解MuJoCo与CMake协作的关键细节后续可直接扩展应用于机器人仿真或真实控制项目。 做机器人仿真这几年MuJoCo基本成了绕不开的标配。从足式机器人、机械臂规划到强化学习环境很多工作都是在这个物理引擎上跑出来的。但有一件事我一直觉得挺可惜大多数人接触MuJoCo都是从Python绑定开始的pip install mujoco一装就开跑确实方便。可真到要把MuJoCo接进自研的C控制器、部署到机器人实机或者要在嵌入式平台上做动力学解算时Python那层壳就成了瓶颈。这时候就得用C API直接调MuJoCo的动力学求解器而第一步就是写CMake。这个项目就是用CMake搭建一个最简单的MuJoCo动力学计算工程跑通正向动力学forward dynamics和逆向动力学inverse dynamics。我不会只贴一堆代码就完事而是把构建过程、版本坑、链接方式、代码里最容易糊涂的几个API全部拆开讲。适合已经玩过MuJoCo Python版、正打算转C的开发者也适合刚入门CMake、想拿一个真实项目练手的朋友。1. 项目思路为什么非要用CMake来调MuJoCo1.1 MuJoCo的动力学计算到底能做什么MuJoCoMulti-Joint dynamics with Contact是个基于广义坐标和凸优化的物理引擎做动力学解算是它的看家本领。所谓动力学计算核心就两件事正向动力学给定当前关节位置、速度和驱动力矩求解出加速度逆向动力学反过来给定状态和期望加速度反推出需要施加的关节力矩。这两者在机器人控制里都是日常操作——正向动力学用于仿真推演逆向动力学用于计算前馈力矩。很多人会问Python里mj_step一行就能仿真为什么还要用C因为在实际工程里动力学计算很少是独立运行的它要被嵌进实时控制循环要么跟视觉、规划模块做进程间通信要么直接跑在机载电脑上。Python解释器的延迟和GIL在这种场景下都是麻烦C编译出的原生程序在性能和可控性上有天然优势。而只要用到C就绕不开CMake这个构建工具。1.2 CMake在这里扮演什么角色MuJoCo官方提供了预编译的动态库和头文件但有库和能编译运行之间还隔着一层编译器要能找到头文件链接器要能找到库文件运行时还要能找到动态库。这些路径、依赖关系、编译选项手写Makefile也不是不行但跨平台就痛苦了。CMake的价值在于它把如何构建这件事声明式地写进CMakeLists.txt同一份配置在Windows、Linux、macOS上都能跑还能自动处理编译器差异和库依赖。这个项目里CMake主要解决三件事定位MuJoCo的头文件和库、配置C标准MuJoCo要求C11以上建议直接用17、生成跑得起来的可执行文件。整个过程看起来不复杂但里面藏着不少坑比如版本匹配、编译器不一致、运行时DLL找不到后面我都会逐个拆解。1.3 项目最终要实现什么效果最终交付物很简单一个CMake工程编译出一个命令行动力学计算程序。程序加载一个单摆模型分别做一次正向动力学和逆向动力学计算输出关键数值然后跑一小段仿真步进验证结果符合物理直觉。麻雀虽小五脏俱全跑通这个你就有了一套可以往里面继续加东西的骨架——换机械臂模型、加控制器、接强化学习环境都是在这个基础上做加法。2. 环境准备MuJoCo和CMake的版本博弈2.1 MuJoCo库的获取与目录结构先说MuJoCo的获取方式。官方GitHub仓库的Release页面提供Windows、Linux和macOS的预编译包下载解压后是一个清晰的目录结构bin目录里是动态库Windows下是mujoco.dllLinux下是libmujoco.soinclude/mujoco目录里是全部头文件lib目录下是导入库Windows下为mujoco.lib有的版本还会附带model目录放官方示例模型。这里有一个很多人第一次都会犯的错误在Windows下把mujoco.dll当成链接对象。实际上编译器链接需要的是导入库mujoco.lib生成exe后再把DLL复制到exe旁边程序运行时才能加载。我用的是MuJoCo 2.3.7版本这个版本的CMake支持已经比较完善官方也提供了mujoco-config.cmake文件可以配合find_package使用后面细说。提示下载MuJoCo时建议优先选官方Release版本GitHub上的源码包需要自己编译会有额外的工具链要求对初学者不友好。3.x版本把Python和C库合并了项目结构有所调整但核心API和CMake链接思路没有本质变化。2.2 CMake版本低版本引发的血泪教训热搜里有一条非常典型的报错“CMake 3.1.3...3.26 or higher is required. You are running version 2.8.12.2”。这说的就是MuJoCo 2.3之后的mujoco-config.cmake规定了最低CMake版本而系统自带的老版CMake2.8.12.2通常是CentOS 7系统自带的根本没法解析新语法一配置就直接报错。我个人的建议是不要纠结版本下限直接用最新稳定版CMake。MuJoCo不同版本对CMake版本要求不一样与其在旧版本上缝缝补补不如直接一步到位。下载安装很简单Windows下用安装包装完勾选“Add CMake to the system PATH”Linux下建议不要用发行版自带的仓库版本往往偏老直接去官网下载Linux tar.gz包解压后把bin目录加进PATH。验证版本就两条命令Windows和Linux通用cmake --version如果输出里显示大版本号低于3.16我建议立刻升级别等踩坑。另外强调一下如果你只是用CMake配置MuJoCo不需要CMake的GUI工具命令行版就够用了。2.3 编译器选型与CUDA的坑MuJoCo库本身是纯C语言写的编译调用方的代码只需要一个能编C11以上的编译器。Windows下VS和MinGW都能用但有个大坑编译器的C运行时必须和库一致。MuJoCo官方预编译包在Windows下是用MSVC编译的所以如果你用MinGW的g去链接很可能遇到诡异的符号错误或运行时崩溃。保险的做法是直接安装Visual Studio社区版免费装的时候勾选“使用C的桌面开发”用MSVC编译器。另外热搜里有一条“cmake errorcmake_cuda_compiler not set”这是有人在CMake里启用了CUDA语言支持但系统里没有配置CUDA编译器。MuJoCo的纯动力学计算根本不依赖CUDA除非你要用它的深度渲染功能mujoco.render里的GPU加速否则完全不需要在CMake中开启CUDA。记住能不开CUDA就不开省掉一票麻烦。3. CMakeLists.txt编写与三种链接方式3.1 一个能用的基础CMake配置无论用哪种链接方式公共部分是一样的。先定义工程名、最低版本和C标准cmake_minimum_required(VERSION 3.16) project(simple_dynamics CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif()这里有几个细节值得说。第一C标准至少设到17虽然MuJoCo要求是C11但后续加Eigen、加各类算法库时17是起步线。第二务必设置CMAKE_BUILD_TYPE为Release因为这个项目是算动力学的Release下编译器优化对性能影响极大Debug版本解算速度可能慢好几倍一开始容易误以为是MuJoCo本身慢。3.2 方式一用find_package查找已安装的MuJoCoMuJoCo 2.3.0之后安装包里的lib/cmake/mujoco目录下提供了CMake包配置文件于是可以用最标准的CMake方式查找set(MUJOCO_INSTALL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/mujoco) find_package(mujoco REQUIRED PATHS ${MUJOCO_INSTALL_DIR}/lib/cmake/mujoco NO_DEFAULT_PATH ) add_executable(simple_dynamics src/main.cpp) target_link_libraries(simple_dynamics PRIVATE mujoco::mujoco)这里NO_DEFAULT_PATH的意思是不要去系统默认路径找只用我们指定的路径避免装到系统里的其他版本串台。mujoco::mujoco是官方CMake配置里导出的target名链接它之后头文件路径和库路径都自动配置好了非常省心。这也是我最推荐的方式。3.3 方式二直接指定头文件和库路径如果你的MuJoCo版本较老没有提供CMake配置文件或者你想完全手动控制路径可以直接用传统方式set(MUJOCO_INCLUDE_DIR ${MUJOCO_INSTALL_DIR}/include) set(MUJOCO_LIBRARY ${MUJOCO_INSTALL_DIR}/lib/mujoco.lib) add_executable(simple_dynamics src/main.cpp) target_include_directories(simple_dynamics PRIVATE ${MUJOCO_INCLUDE_DIR}) target_link_libraries(simple_dynamics PRIVATE ${MUJOCO_LIBRARY}) if(WIN32) add_custom_command(TARGET simple_dynamics POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${MUJOCO_INSTALL_DIR}/bin/mujoco.dll $TARGET_FILE_DIR:simple_dynamics) endif()后边那个add_custom_command是很多人忽略的一步Windows下编译成功不代表运行成功exe运行时要加载mujoco.dll如果不把它复制到exe同级目录下一启动就报“找不到mujoco.dll”。这个POST_BUILD命令能自动完成复制属于我踩过坑之后总结出来的必备操作。3.4 方式三用FetchContent从源码构建还有一条路是用CMake的FetchContent模块从GitHub拉取MuJoCo源码并编译include(FetchContent) FetchContent_Declare(mujoco GIT_REPOSITORY https://github.com/google-deepmind/mujoco.git GIT_TAG 2.3.7 ) FetchContent_MakeAvailable(mujoco)FetchContent的优点是全自动不依赖预编译包还能自己改源码。但代价是每次配置都要拉取和编译整个引擎耗时长对网络要求也高而且源码编译依赖ABI兼容性检查。我的建议是能用预编译包就别用FetchContent前者几分钟搞定后者可能折腾一个下午。4. 动力学计算代码实现4.1 加载模型与创建仿真数据现在进入核心环节。先准备一个简单的单摆模型pendulum.xml这是我在MuJoCo XML格式里写的一个绕Y轴转动的摆锤带一个电机执行器mujoco modelsimple_pendulum worldbody light namelight pos0 0 1/ body namependulum pos0 0 0 joint namehinge typehinge axis0 1 0/ geom namerod typecapsule fromto0 0 0 0 0 -0.5 size0.02/ geom namemass typesphere pos0 0 -0.5 size0.05 mass0.5/ /body /worldbody actuator motor jointhinge namemotor/ /actuator /mujoco模型结构很简单一个摆杆加一个球状质量块关节是绕Y轴的铰链执行器是直接施加在铰链上的电机。这个模型的关键在于只有一个自由度动力学数值容易验证适合做第一个C程序。加载模型的代码是固定套路#include mujoco/mujoco.h #include cstdio int main() { char error[1024] {0}; mjModel* model mj_loadXML(pendulum.xml, nullptr, error, 1024); if (!model) { std::fprintf(stderr, 模型加载失败: %s\n, error); return 1; } mjData* data mj_makeData(model); // ... 动力学计算 ... mj_deleteData(data); mj_deleteModel(model); return 0; }mj_loadXML加载的是XML描述文件mj_makeData创建对应的一整套仿真状态数据。这里有个新手特别容易犯错的地方mjData是动态分配的内存用完必须用mj_deleteData释放否则内存泄漏。我在实际项目里见过有人在一个仿真循环里反复调用mj_makeData不释放跑一会儿内存就爆了要特别注意。4.2 正向动力学从力矩到加速度正向动力学回答的问题是给定当前状态和施加的力矩系统会怎么运动。在MuJoCo里先设置状态量再调用mj_forward// 设置初始状态摆角0.5弧度角速度0>// 仍用刚才的状态但把期望加速度直接设进 qacc>const double dt model-opt.timestep; for (int i 0; i 2000; i) { // 简单控制律把摆角稳定在0比例控制 >project(simple_dynamics LANGUAGES C CXX)如果你确实需要MuJoCo的GPU渲染功能那就要单独安装CUDA Toolkit并且在CMake里指定CUDA编译器路径但那已经不是“简单动力学计算”的范畴了。记住纯动力学解算跑在CPU上和CUDA无关。5.3 头文件找不到和库找不到的排查路径“fatal errormujoco/mujoco.hNo such file or directory”这可能是编译第一步最常见的报错。头文件找不到要么是include路径没加对要么是编译器没按你想要的路径来找。可以用message()调试message(STATUS MuJoCo include dir: ${MUJOCO_INCLUDE_DIR})CMake输出里就能看到实际的路径确认是否指向include目录而不是include/mujoco。头文件里的写法是#include mujoco/mujoco.h所以编译器需要能找到include这一层——我个人第一次就是这里弄错了把include写成了include/mujoco。链接阶段的“无法解析的外部符号”或“undefined reference”则比较复杂常见原因是库路径错了或者库架构不对64位程序链接了32位库或反之。逐一核对库路径、库文件名、编译平台位数基本能定位。5.4 Windows下exe运行时找不到DLL这个坑在Windows下几乎是100%会遇到。编译很顺利一运行就弹“由于找不到mujoco.dll无法继续执行代码”。原因是CMake和编译器只管生成exe不会帮你把运行时依赖打包。解决方案就是前面3.3节里写的add_custom_command(POST_BUILD ...)把DLL复制到生成目录。这里我建议用copy_if_different而不是copy已经存在时跳过复制能节省一点编译时间。如果你用了find_package的方式官方CMake配置里有时会自动处理DLL复制这就更省心了。5.5 动力学数值异常时的检查思路最后一个问题不报错但更恶心——代码跑得好好的输出数值却不对。我做动力学计算时总结了一套排查套路。首先检查单位MuJoCo的默认单位是SI制千克、米、秒、弧度XML里手动写mass0.5就是0.5千克如果直觉上想让质量是500克但写成了500数值就会千差万别。其次检查状态量是否真的设置进了qposqpos[0]对单摆来说是摆角但多关节模型的qpos含义完全不同一定要对着官方文档确认关节顺序。最后检查是不是把mj_inverse和mj_forward的结果读混了这两个API的字段完全不同qfrc_inverse只在逆向动力学里有意义。写在最后这套CMake加MuJoCo的工程骨架我现在几乎每个项目都在用。从最初在Windows上折腾DLL复制到后来Linux服务器上做批量动力学计算都是一样的套路mj_loadXML加载模型mj_makeData创建数据mj_step或者mj_forward/mj_inverse解算然后从data里取结果。最后再分享一个小经验很多人在写完CMakeLists之后习惯性地每次改一点就重新配置一次其实完全没必要。CMake有缓存机制只要你没有新增或删除源文件、没有改链接库只改代码的话重新cmake --build build就能增量编译。另外强烈建议把编译目录比如build/单独建在源码目录外这样即使构建产物出问题删掉build重建即可源码始终干净。等你把这套跑通再往里面加机械臂URDF模型、加PPO强化学习环境、接逆向运动学求解就都只是在这个骨架上做加法了。本文还有配套的精品资源点击获取