简介:面向C++开发者和机器人学习者的Mujoco CMake工程资源,演示如何借助CMake组织一个基于Mujoco 2.3.5的简单动力学计算项目。包内不仅给出完整的CMakeLists配置(包含项目名称、最小版本、find_package与target_link_libraries),还提供main.cpp示例源码,展示使用mj_loadXML加载XML模型、mj_makeData初始化数据、mj_setZero设置初始状态,再通过循环调用mj_step执行100步动力学更新的典型流程。压缩包共217个文件,约26.29MB,以txt说明、cmake/make构建脚本、h/cpp源文件、json配置、stl模型等为主,同时包含libmujoco.so、libws.a等运行库及编译生成的o、bin、ninja产物,目录结构完整,可作为本地环境搭建和排错参考。已有307人学习下载,适合希望快速上手Mujoco仿真、理解CMake与MuJoCo库协同方式的开发者和入门者。 如果你只在Python里用过mujoco,第一次接触CMake时大概会有一段很痛苦的经历。我自己就是这样的:Python环境里跑仿真跑得飞起,结果换到C++工程里,卡在“链接不上库”“找不到头文件”“CMake版本不够”这些琐事上,一折腾就是大半天。后来把整个流程捋顺了才发现,其实核心就三件事:环境变量、CMakeLists、API调用。这篇文章把我实际踩过的坑和最终跑通的方案整理出来,内容围绕用CMake搭建一个C++工程,调用MuJoCo完成一次简单的动力学计算。适合想在C++环境下使用MuJoCo做仿真或机器人控制的人参考,也适合那些已经装了MuJoCo但还没成功用CMake把工程跑起来的同学。
1. 为什么我在MuJoCo的动力学计算上选了CMake这条路
1.1 MuJoCo的C/C++接口才是引擎本体
先明确一个很多人忽略的事实:MuJoCo本质上是一个C/C++物理引擎,Python里的mujoco包只是它的Python绑定。你用python -c "import mujoco"能跑起来,不代表你在C++工程里也一定能顺利链接上它,因为Python绑定自带了编译好的动态库和处理依赖的开销,很多细节被藏起来了。
当你需要把MuJoCo嵌入到自己的C++项目里——比如做机械臂实时控制、写自定义传感器、或者和ROS/其他控制框架集成——直接使用C接口是不可避免的。我最初做逆向运动学(IK)相关实验时就卡在这里,Python里调mujoco的mj_step很简单,但要在C++里稳定地做状态设置、调用mj_forward、读取广义加速度,得先把CMake这套构建流程搞定。
1.2 动力学计算的基本面:正向与逆向
标题里说的“简单动力学计算”,对应MuJoCo里两个最核心的接口:mj_forward和mj_inverse。它们的区别说白了就是因果方向不同。
正向动力学(mj_forward)是给定当前的状态(关节位置qpos和关节速度qvel)以及外加的控制力/力矩,求解出系统的广义加速度qacc。这相当于牛顿第二定律F=ma的矩阵版本:已知力,求运动。仿真器里的mj_step本质上就是先做正向动力学,然后对加速度做时间积分得到下一帧的状态。
逆向动力学(mj_inverse)则反过来,给定状态和目标加速度,反推出需要多大的关节力矩才能产生这个加速度。这在机器人轨迹规划里非常有用,比如你想让机械臂末端沿指定轨迹运动,就可以先计算每个时刻需要的关节加速度,再用逆向动力学算出对应的力矩。
2. 环境准备:版本、目录结构和PATH
2.1 release包解开之后长什么样
MuJoCo官方的预编译release包解压后,目录结构一般是这样的:
mujoco-3.2.x/ ├── bin/ │ ├── mujoco.dll # Windows动态库 │ └── simulate.exe # 官方可视化工具 ├── include/ │ └── mujoco/ │ └── mujoco.h # 核心头文件 ├── lib/ │ ├── mujoco.lib # Windows导入库 │ └── cmake/ │ └── mujoco/ │ ├── mujoco-config.cmake │ └── mujoco-targets.cmake ├── model/ └── doc/关键就是include和lib这两个目录,以及lib/cmake/mujoco下那套CMake配置文件。只要你下载的版本足够新(3.x),官方就自带CMake package配置文件,不需要自己写find_library之类的逻辑,这是最省心的方式。
2.2 编译器与CMake版本的匹配检查
MuJoCo 3.x要求CMake的最低版本逐代提高,比如新版本可能会要求CMake 3.26以上。我第一次碰到报错时,检查发现系统里跑的是某个老项目捆绑安装的CMake 2.8,完全是旧时代的东西了。
解决方式很简单:去官网下载新版CMake安装包,装完后确认一下当前PATH里生效的是哪个版本。Windows上特别容易踩这个坑:安装完新版CMake后,如果终端是安装之前打开的,PATH不会自动刷新,你在终端里敲cmake --version看到的还是旧版本。我的习惯是装完CMake后新开一个终端,再执行:
cmake --version看到版本号对上了再继续。
编译器这边同理。Windows环境下MuJoCo官方预编译库默认按MSVC工具链构建,建议用Visual Studio 2022(对应MSVC v143)配合x64架构。你如果用MinGW,理论上能用,但导入库和运行时依赖的坑会多不少,新手不建议在这里浪费时间。如果之前装的VS版本比较老,缺失C++17的支持,同样会编译报错,后面第5章会详细讲。
2.3 启动前把bin目录加进PATH
这一条容易被忽略但影响巨大。动态库和静态库不一样,程序运行时需要自行找到mujoco.dll。即使CMake链接顺利通过,如果系统PATH里没有MuJoCo的bin目录,运行生成的exe会直接报错,提示找不到mujoco.dll。
我在Windows上的做法是把release包解压到固定目录,比如C:/mujoco,然后把C:/mujoco/bin加进系统环境变量PATH。Linux下则把libmujoco.so所在目录加入LD_LIBRARY_PATH,或者用rpath的方式在CMake里指定。
3. CMakeLists.txt如何组织:find_package与手动指定
3.1 官方CMake配置的接入方式
MuJoCo官方提供CMake配置文件后,接入方式变得非常清爽。我推荐的CMakeLists.txt长这样:
cmake_minimum_required(VERSION 3.16) project(mujoco_forward_dynamics LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 指定MuJoCo安装根目录,改成你自己的实际路径 set(CMAKE_PREFIX_PATH "C:/mujoco" CACHE PATH "MuJoCo安装目录") find_package(mujoco REQUIRED) add_executable(forward_dynamics main.cpp) target_link_libraries(forward_dynamics PRIVATE mujoco::mujoco)要点有两个:find_package(mujoco REQUIRED)会自动去CMAKE_PREFIX_PATH下寻找lib/cmake/mujoco里的配置文件;链接时用的是mujoco::mujoco这个imported target,它会自动处理头文件目录、导入库以及必要的编译定义。
如果你已经通过某种方式把MuJoCo的路径加进了CMAKE_PREFIX_PATH(比如IDE里配置过),这一行可以省略。但在命令行操作时,显式写出来更稳。
3.2 不依赖官方配置时的手写方式
有些场景下你拿不到官方release包的CMake配置文件,比如公司内部库管理、自编译版本或者嵌入式交叉编译环境。这时候可以用最朴素的方式手动指定:
cmake_minimum_required(VERSION 3.16) project(mujoco_forward_dynamics LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(MUJOCO_ROOT "C:/mujoco") add_executable(forward_dynamics main.cpp) target_include_directories(forward_dynamics PRIVATE ${MUJOCO_ROOT}/include) target_link_directories(forward_dynamics PRIVATE ${MUJOCO_ROOT}/lib) target_link_libraries(forward_dynamics PRIVATE mujoco)注意Windows下这种方式要求链接时能找到mujoco.lib导入库,运行时能找到mujoco.dll。建议优先用find_package方式,因为官方配置里还包含了一些必要的接口定义和依赖项,手写容易漏。
3.3 从配置到编译的完整命令流
CMakeLists写好之后,我用的是典型的out-of-source构建,命令如下:
cmake -S . -B build -DCMAKE_PREFIX_PATH="C:/mujoco" cmake --build build --config Release-S .指定源码目录,-B build指定构建目录,-DCMAKE_PREFIX_PATH把MuJoCo目录传给CMake。Windows下这时CMake会自动生成Visual Studio的工程,--config Release指定用Release配置构建。构建完成后,可执行文件在build/Release/forward_dynamics.exe。
如果你用Visual Studio的IDE直接打开CMake工程,方式也类似,只需要在CMake配置里把mujoco_DIR变量指向C:/mujoco/lib/cmake/mujoco,效果是一样的。
4. 一个能直接跑的动力学计算示例
4.1 用XML字符串定义一个单摆模型
MuJoCo里建模有两种方式:从MJCF/URDF文件加载,或者直接用XML字符串。在演示小例子里我个人更喜欢字符串,因为不依赖外部文件路径,可移植性好。
下面这个模型是一个单摆:一根胶囊形杆子挂在距地面1米的高度,绕y轴做铰链转动,重力沿z轴向下:
<mujoco> <option gravity="0 0 -9.81"/> <worldbody> <body name="pendulum" pos="0 0 1"> <joint name="hinge" type="hinge" axis="0 1 0"/> <geom name="rod" type="capsule" fromto="0 0 0 0 0 -1" size="0.03" mass="1.0"/> </body> </worldbody> </mujoco>fromto表示杆子从(0,0,0)延伸到(0,0,-1),也就是杆子从关节中心往下垂1米。这样质心不在关节轴上,才能产生重力矩,做单摆运动才合理。
4.2 正向动力学:给定状态求加速度
主程序很简单,但逻辑要清楚。加载模型,创建数据,设置初始摆角,调用mj_forward,然后读取qacc:
#include <mujoco/mujoco.h> #include <cstdio> static const char* kXml = R"( <mujoco> <option gravity="0 0 -9.81"/> <worldbody> <body name="pendulum" pos="0 0 1"> <joint name="hinge" type="hinge" axis="0 1 0"/> <geom name="rod" type="capsule" fromto="0 0 0 0 0 -1" size="0.03" mass="1.0"/> </body> </worldbody> </mujoco> )"; int main() { char error[1024] = {0}; mjModel* model = mj_loadXMLString(kXml, nullptr, error, sizeof(error)); if (!model) { std::printf("加载XML失败: %s\n", error); return 1; } mjData* data = mj_makeData(model); // 设置初始状态:摆角0.5 rad,角速度0 >set(CMAKE_BUILD_RPATH "${MUJOCO_ROOT}/bin")也可以设置环境变量LD_LIBRARY_PATH,效果类似。
这套流程跑通之后,MuJoCo在C++环境下做动力学计算就不再神秘了,无非是“环境准备、CMake组织、API调用、运行期排错”四个环节的反复打磨。对我个人而言,最大的体会是:遇到编译错误先别急着改代码,把CMake版本、编译器工具链、动态库路径这三件事理清楚,大部分问题都能迎刃而解。这个小案例算是起步的敲门砖,之后无论是接强化学习环境还是做机械臂控制,都有了可靠的工程底座。
本文还有配套的精品资源,点击获取