Mujoco入门:手把手教你Ubuntu安装、机械臂模型与末端位置追踪

Mujoco(Multi-Joint dynamics with Contact)是一款用于机器人学、生物力学等领域的高性能物理仿真引擎,其核心功能包括动力学模拟、接触力建模及多关节系统仿真。该工具提供直观的操作界面、丰富的物理参数配置以及灵活的约束条件设置,适用于复杂机械系统或生物运动的模拟分析。

你是否想了解如何使用Mujoco呢?接下来,就让我们跟随EEWorld论坛网友LitchiCheng的脚步,开启Mujoco的精彩探索之旅吧!


Ubuntu 装 Mujoco 居然这么简单?


图片

直接进入MuJoCo Github 地址,Releases · google-deepmind/mujoco,最新版本为3.3.0 

图片

创建放mujoco程序的文件夹,下载后进行解压

mdkir MuJoCoBincd MuJoCoBinwget https://github.com/google-deepmind/mujoco/releases/download/3.3.0/mujoco-3.3.0-linux-x86_64.tar.gztar xvzf mujoco-3.3.0-linux-x86_64.tar.gz

展开后的目录结构 

图片

export将执行程序导入环境中,使用simulate指令将humanoid场景加载测试

echo"export PATH=$PATH:/home/dar/MuJoCoBin/mujoco-3.3.0/bin" >> ~/.bashrcsource ~/.bashrcsimulate ~/MuJoCoBin/mujoco-3.3.0/model/humanoid/humanoid.xml

默认仿真就是Run的,先鞠躬给大家 

图片


常见机械臂模型不用找!Mujoco这儿都有!


高质量的模型集合,franka panda,so-arm100,ur之类的机械臂都有

git clone git@github.com:google-deepmind/mujoco_menagerie.git 

图片

大概346M,网速不行的可以下载zip

simulate mujoco_menagerie/trs_so_arm100/scene.xml 

图片

simulate mujoco_menagerie/franka_emika_panda/scene.xml

图片

simulate mujoco_menagerie/aloha/scene.xml

图片


MuJoCo 仿真 Panda 机械臂!末端位置实时追踪 + 可视化(含缩放交互)


本期介绍下,mujoco_py这个库很老了,最新的版本可以通过mujoco的python库,可视化模型及获取模型body的实时位置,下面开始,首先安装如下依赖库

pip3 install mujoco glfw

关于模型有哪些body,可以通过代码的形式,或者查看xml描述文件 

图片

新建get_body_pos.py的文件夹

import mujocoimport numpy as npimport glfw# 定义鼠标滚轮滚动的回调函数,用于处理界面缩放defscroll_callback(window, xoffset, yoffset):# 使用 global 关键字声明 cam 为全局变量,以便在函数内部修改它global cam# 根据鼠标滚轮的垂直滚动量 yoffset 调整相机的距离,实现缩放效果# 0.1 是缩放的比例因子,可以根据需要调整cam.distance *= 1 - 0.1 * yoffsetdefmain():# 声明 cam 为全局变量,方便在其他函数中使用global cam# 从指定的 XML 文件路径加载 MuJoCo 模型model = mujoco.MjModel.from_xml_path('/home/dar/MuJoCoBin/mujoco_menagerie/franka_emika_panda/scene.xml')# 创建与模型对应的 MjData 实例,用于存储模拟过程中的动态数据data = mujoco.MjData(model)# 初始化 GLFW 库,用于创建窗口和处理输入事件ifnot glfw.init():# 如果初始化失败,直接返回return# 创建一个 1200x900 像素的窗口,标题为 'Panda Arm Control'window = glfw.create_window(1200900'Panda Arm Control'NoneNone)ifnot window:# 如果窗口创建失败,终止 GLFW 并返回glfw.terminate()return# 将当前上下文设置为新创建的窗口,以便后续的 OpenGL 操作在该窗口上进行glfw.make_context_current(window)# 设置鼠标滚轮事件的回调函数为 scroll_callback,当鼠标滚轮滚动时会调用该函数glfw.set_scroll_callback(window, scroll_callback)# 初始化相机对象,用于定义观察视角cam = mujoco.MjvCamera()# 初始化渲染选项对象,用于设置渲染的一些参数opt = mujoco.MjvOption()# 设置相机的默认参数mujoco.mjv_defaultCamera(cam)# 设置渲染选项的默认参数mujoco.mjv_defaultOption(opt)# 初始化扰动对象,用于处理用户对模型的交互操作pert = mujoco.MjvPerturb()# 初始化渲染上下文对象,用于管理渲染资源con = mujoco.MjrContext(model, mujoco.mjtFontScale.mjFONTSCALE_150.value)# 创建一个场景对象,用于存储要渲染的几何元素scene = mujoco.MjvScene(model, maxgeom=10000)# 根据名称 'hand' 查找末端执行器的 body IDend_effector_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_BODY, 'hand')print(f"End effector ID: {end_effector_id}")if end_effector_id == -1:# 如果未找到指定名称的末端执行器,打印警告信息并终止 GLFWprint("Warning: Could not find the end effector with the given name.")glfw.terminate()return# 进入主循环,直到用户关闭窗口whilenot glfw.window_should_close(window):# 获取末端执行器在世界坐标系下的位置end_effector_pos = data.body(end_effector_id).xpos# 打印末端执行器的位置信息,方便调试print(f"End effector position: {end_effector_pos}")# 执行一步模拟,更新模型的状态mujoco.mj_step(model, data)# 定义视口的大小和位置viewport = mujoco.MjrRect(001200900)# 更新场景对象,将模型的最新状态反映到场景中mujoco.mjv_updateScene(model, data, opt, pert, cam, mujoco.mjtCatBit.mjCAT_ALL.value, scene)# 将场景渲染到视口中mujoco.mjr_render(viewport, scene, con)# 交换前后缓冲区,将渲染结果显示在窗口上glfw.swap_buffers(window)# 处理所有待处理的事件,如鼠标、键盘事件等glfw.poll_events()# 终止 GLFW 库,释放相关资源glfw.terminate()if __name__ == "__main__":# 当脚本作为主程序运行时,调用 main 函数main()

运行代码,python3 get_body_pos.py,可以看到出现panda机械臂场景,同时控制台不停的输出hand body的位置

图片


MuJoCo 仿真 Panda 机械臂关节空间运动|含完整代码


下面介绍下data的另一个控制量,qpos,也就是关节位置,关键代码就一行

data.qpos[:7] = new_q

panda机械臂有七个关节的控制量,弧度单位,对应link0到link6,演示代码,控制某一个关节一直自增位置,但注意自增的量不能太大,不然控制台会输出如下,表示DOF 0不对劲,故需要归一到+-180°内

EEWORLDIMGTK1

完整代码如下:

import mujocoimport numpy as npimport glfwdefscroll_callback(window, xoffset, yoffset):global cam# 调整相机的缩放比例cam.distance *= 1 - 0.1 * yoffsetdeflimit_angle(angle):while angle > np.pi:angle -= 2 * np.piwhile angle < -np.pi:angle += 2 * np.pireturn angledefmain():global cam# 加载模型model = mujoco.MjModel.from_xml_path('/home/dar/MuJoCoBin/mujoco_menagerie/franka_emika_panda/scene.xml')data = mujoco.MjData(model)# 打印所有 body 的 ID 和名称print("All bodies in the model:")for i in range(model.nbody):body_name = mujoco.mj_id2name(model, mujoco.mjtObj.mjOBJ_BODY, i)print(f"ID: {i}, Name: {body_name}")# 初始化 GLFWifnot glfw.init():returnwindow = glfw.create_window(1200900'Panda Arm Control', None, None)ifnot window:glfw.terminate()returnglfw.make_context_current(window)# 设置鼠标滚轮回调函数glfw.set_scroll_callback(window, scroll_callback)# 初始化渲染器cam = mujoco.MjvCamera()opt = mujoco.MjvOption()mujoco.mjv_defaultCamera(cam)mujoco.mjv_defaultOption(opt)pert = mujoco.MjvPerturb()con = mujoco.MjrContext(model, mujoco.mjtFontScale.mjFONTSCALE_150.value)scene = mujoco.MjvScene(model, maxgeom=10000)# 找到末端执行器的 body idend_effector_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_BODY, 'hand')print(f"End effector ID: {end_effector_id}")if end_effector_id == -1:print("Warning: Could not find the end effector with the given name.")glfw.terminate()return# 初始关节角度initial_q = data.qpos[:7].copy()whilenot glfw.window_should_close(window):# 获取当前末端执行器位置mujoco.mj_forward(model, data)end_effector_pos = data.body(end_effector_id).xposinitial_q[0] = initial_q[0] + 0.1initial_q[0] = limit_angle(initial_q[0])new_q = initial_q# 设置关节目标位置data.qpos[:7] = new_q# 模拟一步mujoco.mj_step(model, data)# 更新渲染场景viewport = mujoco.MjrRect(001200900)mujoco.mjv_updateScene(model, data, opt, pert, cam, mujoco.mjtCatBit.mjCAT_ALL.value, scene)mujoco.mjr_render(viewport, scene, con)# 交换前后缓冲区glfw.swap_buffers(window)glfw.poll_events()# 清理资源glfw.terminate()if __name__ == "__main__":main()

图片

 

· END ·