mujoco快速上手

mujoco学习笔记与问题记录。官方jupyter入门教程:https://github.com/google-deepmind/mujoco/blob/main/python/tutorial.ipynb

仿真器

1
2
3
4
5
6
# 安装mujoco
pip install mujoco
pip install mujoco-python-viewer

# 启动可视化界面,可以直接把模型拖进去预览
python -m mujoco.viewer

Tutorial

mjModel

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
34
35
36
37
38
39
40
41
42
# 原始模型xml文件
xml = """
<mujoco>
  <worldbody>
  <light name="top" pos="0 0 1"/>
    <geom name="red_box" type="box" size=".2 .2 .2" rgba="1 0 0 1"/>
    <geom name="green_sphere" pos=".2 .2 .2" size=".1" rgba="0 1 0 1"/>
  </worldbody>
</mujoco>
"""

# 从xml生成model模型
model = mujoco.MjModel.from_xml_string(xml)

model.ngeom # model里有几个geom
model.geom_rgba # 每个geom的颜色

# 快捷知道有哪些可用的geom
model.geom()

# 直接叫geom不指定属性会打印所有属性
model.geom('green_sphere')

# 打印rgba
model.geom('green_sphere').rgba

# name与id相互转换
id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_GEOM, 'green_sphere')
model.geom('green_sphere').id
model.geom(1).name
model.body(0).name # id为0的一定是world且不可改名

# 打印model中所有geom的name
[model.geom(i).name for i in range(model.ngeom)]

# 所有物理选项(如重力、时间步等)
''' 也可以直接在XML中<mujoco>的子标签中更改:
<mujoco>
<option gravity="0 0 10"/>
</mujoco>
'''
model.opt

mjData

1
2
3
4
5
6
7
8
9
10
11
12
13
# 使用model创建data
data = mujoco.MjData(model)

# 打印所有geom的(x,y,z)位置
print(data.geom_xpos)

# 打印某一个geom的(x,y,z)位置
print(data.geom('green_sphere').xpos)

# 计算全局笛卡尔姿态, 必须要做几何对齐
mujoco.mj_kinematics(model, data)
print('raw access:\n', data.geom_xpos)

rendering

1
2
3
4
5
# 开启可视化渲染
with mujoco.Renderer(model) as renderer:
  mujoco.mj_forward(model, data) # 渲染也要计算后使用
  renderer.update_scene(data)
  media.show_image(renderer.render())

Simulation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# enable joint visualization option:
scene_option = mujoco.MjvOption()
scene_option.flags[mujoco.mjtVisFlag.mjVIS_JOINT] = True # 开关节显示

duration = 3.8  # (seconds)
framerate = 60  # (Hz)

# Simulate and display video.
frames = []
mujoco.mj_resetData(model, data)
with mujoco.Renderer(model) as renderer:
  while data.time < duration:
    mujoco.mj_step(model, data)
    if len(frames) < data.time * framerate:
      renderer.update_scene(data, scene_option=scene_option)
      pixels = renderer.render()
      frames.append(pixels)
     
media.show_video(frames, fps=framerate)

Degrees of Freedom

Dof,即自由度,注意在mujoco中旋转使用四元数表示,有四个自由度(见问题记录)。

1
2
3
print('Total number of DoFs in the model:', model.nv)
print('Generalized positions:', data.qpos) # 所有geom的qpos写在一起
print('Generalized velocities:', data.qvel) # 旋转

Tendons

1
2
3
4
5
6
  <tendon>
    <spatial name="wire" limited="true" range="0 0.35" width="0.003">
      <site site="anchor"/>
      <site site="hook"/>
    </spatial>
  </tendon>

模型

用户以名为 MJCF 的 XML 文件格式定义 MuJoCo 模型。然后,内置编译器将该模型编译为低级数据结构 mjModel,该结构为运行时计算进行了交叉索引和优化。编译后的模型也可以保存在二进制 MJB 文件中。
所谓MJCF,是对XML文件内容的一种约定,即以<mujoco>为唯一顶层元素的XML文件会被识别为mujoco模型文件。

示例:

1
2
3
4
5
6
7
8
9
10
<mujoco>  <!-- 唯一的顶级元素,将 XML 文件标识为 MJCF模型文件 -->
<worldbody> <!-- 有且只有一个世界 -->
<light diffuse=".5 .5 .5" pos="0 0 3" dir="0 0 -1"/>
<geom type="plane" size="1 1 0.1" rgba=".9 0 0 1"/>
<body pos="0 0 1">
<joint type="free"/>
<geom type="box" size=".1 .2 .3" rgba="0 .9 0 1"/>
</body>
</worldbody>
</mujoco>
  • worldbody顶层体,唯一,不能有子元素inertial和joint,它的name默认为"world"。

  • body其他体,可以有属性joint。

  • joint关节,是body的属性,定义其所属body与所属body的父体之间的自由度。类型有四种free, ball, slide, hinge,如下:

    • free:自由,有6个自由度,分别是3个平移以及3个旋转。只能用于worldbody的子body
    • ball:球体,只有3个旋转自由度,使用四元数表示状态(w,x,y,z),初始状态为(1,0,0,0)**。如果一个body有一个球状关节,它就不能有其他的旋转关节(球或铰链)。在同一个body中,允许将球状关节和滑动关节结合起来。
    • slide:滑动,只有1个平移自由度,使用一个位置(用于渲染)和一个方向(用于模拟)来描述。
    • hinge:铰链,只有1个旋转自由度,使用一个轴线与一个通过位置来描述,为默认类型
  • geom几何体,是body的属性,决定body的渲染外观与碰撞体积(以及可选的惯性属性)。类型有以下几种:

    • plane:平面

问题记录

  1. keyframe对应的每种joint的qpos维数是多少?
    mujoco是面向过程设计的,因此大量的数据格式被设为向量,需要使用者自己知道向量中每一维度的含义。
    对应于上述关节类型,旋转的三自由度使用四元数(w,x,y,z)表示,平移的三自由度使用(x,y,z)表示。因此一个浮动基机器人本体的自由度是6,qpos维数是7。同理,四种关节对应的qpos维数如下:
关节类型 自由度 qpos 维数 说明
自由关节 6 7 3平移 + 4旋转四元数
滑动关节 1 1 1平移
铰链关节 1 1 1旋转角度
球形关节 3 4 4旋转四元数

环境bug

1. A module that was compiled using NumPy 1.x cannot be run in NumPy 2.2.2 as it may crash. To support both 1.x and 2.x versions of NumPy, modules must be compiled with NumPy 2.0. Some module may need to rebuild instead e.g. with ‘pybind11>=2.12’.

报错中给了提示:If you are a user of the module, the easiest solution will be to
downgrade to ‘numpy<2’ or try to upgrade the affected module.
We expect that some modules will need time to support NumPy 2.

所以:

1
pip install numpy==1.22.4

2. python: /builds/florianrhiem/pyGLFW/glfw-3.4/src/window.c:711: glfwGetFramebufferSize: Assertion `window != NULL’ failed.

参考:stackoverflow

3. mujoco报错:ValueError: XML Error: Schema violation: unrecognized attribute: ‘kv’

mujoco 2.3.0报错:

1
ValueError: XML Error: Schema violation: unrecognized attribute: 'kv'

升级到最新版(3.2.7),又报错:

1
AttributeError: 'mujoco._structs.MjData' object has no attribute 'solver_iter'.

这俩问题无法兼容解决。
最终在3.2.7版下修改mujoco_rendering.py,将593行代码中的 self.data.solver_iter 更改为 self.data.solver_niter,解决。

4. libGL error: MESA-LOADER: failed to open iris

参考:stackoverflow
conda install -c conda-forge libstdcxx-ng

5. 多线程训练时出现too many open files

从字面意思上看就是说程序打开的文件数过多,不过这里的files不单是文件的意思,也包括打开的通讯链接(比如socket),正在监听的端口等等,所以有时候也可以叫做句柄(handle),这个错误通常也可以叫做句柄数超出系统限制。
查看允许打开文件数:

1
ulimit -n

修改它:

1
ulimit -n 2048

成功解决。

6. RuntimeError: Numpy is not available;ModuleNotFoundError: No module named ‘numpy._core‘

https://blog.csdn.net/m0_45276337/article/details/143689539