做网站这么便宜可以吗,如何优化网站打开速度,室内设计风格都有哪些,企业网站博客上如何推广系列文章目录 前言 从 2.1.2 版开始#xff0c;MuJoCo 附带使用 pybind11 以 C 开发的本地 Python 绑定。Python API 与底层的 C API 保持一致。这导致了一些非 Python 代码结构#xff08;如函数参数的顺序#xff09;#xff0c;但其好处是 API 文档适用于两种语言。 Pyt…系列文章目录 前言 从 2.1.2 版开始MuJoCo 附带使用 pybind11 以 C 开发的本地 Python 绑定。Python API 与底层的 C API 保持一致。这导致了一些非 Python 代码结构如函数参数的顺序但其好处是 API 文档适用于两种语言。 Python 绑定作为 mujoco 包发布在 PyPI 上。这些都是底层绑定旨在尽可能直接访问 MuJoCo 库。不过为了提供开发人员期望在典型 Python 库中使用的 API 和语义这些绑定在许多地方故意与原始 MuJoCo API 有所不同本页将对此进行详细记录。 Google DeepMind 的 dm_control 强化学习库在 1.0.0 版本之前该库基于 ctypes 实现了自己的 MuJoCo 绑定已更新为依赖于 mujoco 包并继续得到 Google DeepMind 的支持。dm_control 中的更改对以前版本的用户来说应该基本透明但直接依赖于其底层 API 的代码可能需要更新。详情请查阅迁移指南。 对于 mujoco-py 用户我们在下文中提供了帮助迁移的说明。 一、教程笔记本 这里有使用 Python 绑定的 MuJoCo 教程colab
二、安装 建议通过 PyPI 安装此软件包
pip install mujoco MuJoCo 库的副本作为软件包的一部分提供无需单独下载或安装。
三、交互式查看器 作为 Python 软件包的一部分mujoco.viewer 模块提供了一个交互式图形用户界面查看器。它与随 MuJoCo 二进制版本一起发布的仿真应用程序基于相同的代码库。支持三种不同的使用情况
3.1 独立应用程序 python -m mujoco.viewer 会启动一个空的可视化会话可通过拖放方式加载模型。 python -m mujoco.viewer --mjcf/path/to/some/mjcf.xml 启动指定模型文件的可视化会话。 3.2 托管查看器 通过函数 viewer.launch 从 Python 程序/脚本中调用。该函数会阻塞用户代码以支持物理循环的精确计时。如果用户代码是作为引擎插件或物理回调实现的并在 mj_step 期间被 MuJoCo 调用则应使用此模式。 viewer.launch() 会启动一个空的可视化会话可通过拖放方式加载模型。 viewer.launch(model) 为给定的 mjModel 启动一个可视化会话在该会话中可视化器会在内部创建自己的 mjData 实例 viewer.launch(model, data) 与上述操作相同但可视化器会直接对给定的 mjData 实例进行操作退出时数据对象将被修改。
3.3 被动查看器 调用 viewer.launch_passive(model,data)。该函数不会阻塞允许用户代码继续执行。在此模式下用户脚本负责计时和推进物理状态除非用户明确同步传入事件否则鼠标拖动扰动将不起作用。 警告 在 MacOS 上launch_passive 要求通过特殊的 mjpython 启动器执行用户脚本。mjpython 命令是作为 mujoco 软件包的一部分安装的可直接用于替代常用的 python 命令并支持相同的命令行标志和参数集。例如脚本可以通过 mjpython my_script.py 执行IPython shell 可以通过 mjpython -m IPython 启动。 launch_passive 函数返回一个句柄可用于与查看器交互。它具有以下属性
cam、opt 和 pert 属性分别对应 mjvCamera、mjvOption 和 mjvPerturb 结构。lock()为作为上下文管理器的查看器提供一个互斥锁。由于查看器运行自己的线程用户代码必须确保在修改任何物理或可视化状态之前持有查看器锁。这些属性包括传递给 launch_passive 的 mjModel 和 mjData 实例以及查看器句柄的 cam、opt 和 pert 属性。sync()同步 mjModel、mjData 和 GUI 用户输入自上次调用 sync 后的状态。为了允许用户脚本在无需锁定查看器的情况下对 mjModel 和 mjData 进行任意修改被动查看器不会在同步调用之外访问或修改这些结构。用户脚本必须调用同步才能使查看器反映物理状态的变化。同步函数还会将用户输入从图形用户界面传回 mjOption位于 mjModel 内部和 mjData包括启用/禁用标志、控制输入和鼠标扰动。update_hfield(hfieldid)更新指定 hfieldid 处的高度字段数据以便后续渲染。update_mesh(meshid): 更新指定网格 ID 上的网格数据以便后续渲染使用。update_texture(texid): 更新指定 texid 处的纹理数据以便后续渲染使用。close()以编程方式关闭查看器窗口。该方法可以在不锁定的情况下安全调用。is_running()如果查看器窗口正在运行则返回 True如果已关闭则返回 False。该方法可在不加锁的情况下安全调用。user_scn一个 mjvScene 对象允许用户在渲染场景中添加更改渲染标志和添加自定义可视化地形。它与查看器内部用于渲染最终场景的 mjvScene 是分开的完全由用户控制。用户脚本可以调用 mjv_initGeom 或 mjv_makeConnector 等脚本向 user_scn 添加可视化几何图形在下一次调用 sync() 时查看器就会将这些几何图形添加到未来渲染的图像中。同样用户脚本也可以更改 user_scn.flags这些更改将在下一次调用 sync() 时被接收。同步()调用还会将通过图形用户界面对渲染标志所做的更改复制到 user_scn 中以保持一致性。例如 with mujoco.viewer.launch_passive(m, d, key_callbackkey_callback) as viewer:# Enable wireframe rendering of the entire scene.viewer.user_scn.flags[mujoco.mjtRndFlag.mjRND_WIREFRAME] 1viewer.sync()while viewer.is_running():...# Step the physics.mujoco.mj_step(m, d)# Add a 3x3x3 grid of variously colored spheres to the middle of the scene.viewer.user_scn.ngeom 0i 0for x, y, z in itertools.product(*((range(-1, 2),) * 3)):mujoco.mjv_initGeom(viewer.user_scn.geoms[i],typemujoco.mjtGeom.mjGEOM_SPHERE,size[0.02, 0, 0],pos0.1*np.array([x, y, z]),matnp.eye(3).flatten(),rgba0.5*np.array([x 1, y 1, z 1, 2]))i 1viewer.user_scn.ngeom iviewer.sync()... 查看器句柄还可用作上下文管理器在退出时自动调用 close()。使用 launch_passive 的用户脚本的最小示例如下。(请注意该示例只是一个简单的说明性示例并不一定能使物理程序以正确的挂钟速度运行。
import timeimport mujoco
import mujoco.viewerm mujoco.MjModel.from_xml_path(/path/to/mjcf.xml)
d mujoco.MjData(m)with mujoco.viewer.launch_passive(m, d) as viewer:# Close the viewer automatically after 30 wall-seconds.start time.time()while viewer.is_running() and time.time() - start 30:step_start time.time()# mj_step can be replaced with code that also evaluates# a policy and applies a control signal before stepping the physics.mujoco.mj_step(m, d)# Example modification of a viewer option: toggle contact points every two seconds.with viewer.lock():viewer.opt.flags[mujoco.mjtVisFlag.mjVIS_CONTACTPOINT] int(d.time % 2)# Pick up changes to the physics state, apply perturbations, update options from GUI.viewer.sync()# Rudimentary time keeping, will drift relative to wall clock.time_until_next_step m.opt.timestep - (time.time() - step_start)if time_until_next_step 0:time.sleep(time_until_next_step)
作为选项viewer.launch_passive 接受以下关键字参数。
key_callback 每次查看器窗口中发生键盘事件时都会被调用的可调用函数。这允许用户脚本对各种按键做出反应例如按下空格键时暂停或恢复运行循环。 paused Falsedef key_callback(keycode):if chr(keycode) :nonlocal pausedpaused not paused...with mujoco.viewer.launch_passive(m, d, key_callbackkey_callback) as viewer:while viewer.is_running():...if not paused:mujoco.mj_step(m, d)viewer.sync()...
show_left_ui 和 show_right_ui 布尔参数用于指示启动查看器时用户界面面板是可见还是隐藏。请注意无论指定的值是多少用户仍可在启动后通过按 Tab 或 ShiftTab 键切换这些面板的可见性。
四、基本用法
安装后可通过 import mujoco 导入软件包。结构体、函数、常量和枚举可直接从顶层的 mujoco 模块中获取。
4.1 结构体 绑定包括暴露 MuJoCo 数据结构的 Python 类。为了获得最佳性能这些类提供了对 MuJoCo 所用原始内存的访问而无需复制或缓冲。这意味着某些 MuJoCo 函数如 mj_step会在原处更改字段的内容。因此建议用户在需要时创建副本。例如在记录正文的位置时可以写入 positions.append(data.body(my_body).xpos.copy())。如果没有 .copy()列表中将包含完全相同的元素所有元素都指向最近的值。 为了符合 PEP 8 命名指南结构体名称以大写字母开头例如 mjData 在 Python 中就变成了 mujoco.MjData。 除 mjModel 之外的所有结构体在 Python 中都有构造函数。对于有 mj_defaultFoo 样式初始化函数的结构体Python 构造函数会自动调用默认初始化函数例如 mujoco.MjOption() 会创建一个新的 mjOption 实例该实例已预先用 mj_defaultOption 初始化。否则Python 构造函数将零初始化底层 C 结构。 具有 mj_makeFoo 风格初始化函数的结构体在 Python 中有相应的构造函数重载例如 Python 中的 mujoco.MjvScene(model, maxgeom10) 会创建一个新的 mjvScene 实例在 C 语言中用 mjv_makeScene(model, [the new mjvScene instance], 10) 进行初始化。使用这种形式的初始化时删除 Python 对象时会自动调用相应的去分配函数 mj_freeFoo/mj_deleteFoo。用户无需手动释放资源。 mujoco.MjModel 类没有 Python 构造函数。相反我们提供了三个静态工厂函数来创建新的 mjModel 实例mujoco.MjModel.from_xml_string、mujoco.MjModel.from_xml_path 和 mujoco.MjModel.from_binary_path。第一个函数接受 XML 模型字符串后两个函数接受 XML 或 MJB 模型文件的路径。所有这三个函数都可选择接受一个 Python 字典该字典会被转换成一个 MuJoCo 虚拟文件系统供模型编译时使用。
4.2 函数 MuJoCo 函数与 Python 函数同名。与结构体不同我们并不试图使函数名符合 PEP 8 标准因为 MuJoCo 同时使用下划线和 CamelCases。在大多数情况下函数参数与 C 语言中的参数完全相同关键字参数也支持与 mujoco.h 中声明的相同名称。接受数组输入参数的 C 函数的 Python 绑定需要 NumPy 数组或可转换为 NumPy 数组的迭代对象如列表。输出参数即 MuJoCo 希望将值写回给调用者的数组参数必须始终是可写的 NumPy 数组。 在 C API 中将动态大小数组作为输入的函数需要一个指向数组的指针参数和一个指定数组大小的整数参数。在 Python 中由于我们可以从 NumPy 数组中自动而且更安全地推导出大小参数因此省略了大小参数。调用这些函数时除了数组大小之外的所有参数都要按照 mujoco.h 中的顺序传递或者使用关键字参数。例如mj_jac 在 Python 中应调用为 mujoco.mj_jac(m,d,jacp,jacr,point,body)。 绑定会在调用底层 MuJoCo 函数之前释放 Python 全局解释器锁GIL。这允许一些基于线程的并行性但用户应注意GIL 只在 MuJoCo C 函数本身的持续时间内释放而不会在任何其他 Python 代码执行期间释放。 注意事项 绑定提供附加功能的一个地方是顶层的 mj_step 函数。由于它经常在循环中被调用我们增加了一个额外的 nstep 参数指示底层 mj_step 应被调用多少次。如果没有指定nstep 的默认值为 1。以下两个代码片段执行了相同的计算但第一个代码片段在后续物理步骤之间没有获取 GIL mj_step(model, data, nstep20) for _ in range(20):mj_step(model, data) 4.3 枚举和常量 MuJoCo 枚举以 mujoco.mjtEnumType.ENUM_VALUE 的形式提供例如 mujoco.mjtObj.mjOBJ_SITE。MuJoCo 常量可直接在 mujoco 模块下以相同名称使用例如 mujoco.mjVISSTRING。
4.4 最小示例
import mujocoXMLr
mujocoassetmesh filegizmo.stl//assetworldbodybodyfreejoint/geom typemesh namegizmo meshgizmo//body/worldbody
/mujoco
ASSETSdict()
with open(/path/to/gizmo.stl, rb) as f:ASSETS[gizmo.stl] f.read()model mujoco.MjModel.from_xml_string(XML, ASSETS)
data mujoco.MjData(model)
while data.time 1:mujoco.mj_step(model, data)print(data.geom_xpos) 4.5 命名访问 大多数设计良好的 MuJoCo 模型都会为感兴趣的对象关节、几何体、主体等指定名称。当模型被编译成 mjModel 实例时这些名称就会与数字 ID 相关联这些数字 ID 用于索引各种数组成员。为了方便和提高代码可读性Python 绑定为 MjModel 和 MjData 提供了 命名访问 API。mjModel 结构中的每个 name_fooadr 字段都定义了一个名称类别 foo。 对于每个名称类别 foomujoco.MjModel 和 mujoco.MjData 对象都提供了一个方法 foo该方法接收一个字符串参数并返回与给定名称的实体 foo 相对应的所有数组的访问器对象。访问器对象包含的属性名称与 mujoco.MjModel 或 mujoco.MjData 的字段相对应但去掉了下划线前的部分。此外访问器对象还提供 id 和 name 属性可分别用于替换 mj_name2id 和 mj_id2name。例如
m.geom(gizmo) 返回 MjModel 对象 m 中与名为 gizmo 的 geom 相关联的数组的访问器。m.geom(gizmo).rgba 是一个长度为 4 的 NumPy 数组视图用于指定 geom 的 RGBA 颜色。具体来说它对应 m.geom_rgba[4*i:4*i4] 中的部分其中 i mujoco.mj_name2id(m,mujoco.mjtObj.mjOBJ_GEOM,gizmo)。m.geom(gizmo).id 与 mujoco.mj_name2id(m, mujoco.mjtObj.mjOBJ_GEOM, gizmo)返回的数字相同。m.geom(i).name 为 gizmo其中 i mujoco.mj_name2id(m,mujoco.mjtObj.mjOBJ_GEOM,gizmo)。 此外Python API 还为某些名称类别定义了一些别名这些别名与 MJCF 模式中定义该类别实体的 XML 元素名称相对应。例如m.joint(foo) 与 m.jnt(foo) 相同。这些别名的完整列表如下。 关节的访问器与其他类别的访问器有些不同。一些 mjModel 和 mjData 字段大小为 nq 或 nv 的字段与自由度 (DoF) 而不是关节相关联。这是因为不同类型的关节具有不同数量的自由度。尽管如此我们还是会通过 d.joint(foo).qpos 和 d.joint(foo).qvel 等方式将这些字段与相应的关节关联起来但这些数组的大小会因关节类型的不同而在不同的访问器中有所不同。 命名访问保证与模型中实体的数量成 O(1)关系。换句话说通过名称访问实体所需的时间不会随着模型中名称或实体数量的增加而增加。 为完整起见我们在此提供了 MuJoCo 中所有名称类别的完整列表以及它们在 Python API 中定义的相应别名。 body jnt or joint geom site cam or camera light mesh skin hfield tex or texture mat or material pair exclude eq or equality tendon or ten actuator sensor numeric text tuple key or keyframe 4.6 渲染 MuJoCo 本身希望用户在调用其 mjr_ 渲染例程之前先设置一个可用的 OpenGL 上下文。Python 绑定提供了一个基本类 mujoco.GLContext帮助用户为离屏渲染设置这样一个上下文。要创建上下文请调用 ctx mujoco.GLContext(max_width,max_height)。创建上下文后必须在调用 MuJoCo 渲染函数前将其设置为当前可以通过 ctx.make_current() 来实现。请注意在任何时候都只能在一个线程上将上下文设置为当前状态而且所有后续的渲染调用都必须在同一线程上进行。 删除 ctx 对象时上下文会被自动释放但在某些多线程情况下可能需要显式释放底层 OpenGL 上下文。为此请调用 ctx.free()之后用户有责任确保不再对上下文进行渲染调用。 一旦创建了上下文用户就可以按照 MuJoCo 的标准进行渲染例如可视化部分所记录的渲染。
4.7 错误处理 MuJoCo 通过 mju_error 机制报告不可恢复的错误并立即终止整个进程。允许用户通过 mju_user_error 回调安装自定义错误处理程序但它也应终止进程否则回调返回后 MuJoCo 的行为将是未定义的。实际上只要确保错误回调不返回 MuJoCo 就足够了但允许使用 longjmp 跳过 MuJoCo 的调用栈返回外部调用站点。 Python 绑定利用 longjmp 允许它将不可恢复的 MuJoCo 错误转换为 mujoco.FatalError 类型的 Python 异常这种异常可以用通常的 Pythonic 方式捕获和处理。此外它还使用当前私有的 API 以线程本地的方式安装了错误回调从而允许从多个线程并发调用 MuJoCo。
4.8 回调函数 MuJoCo 允许用户安装自定义回调函数以修改其计算管道的某些部分。例如mjcb_sensor 可用来实现自定义传感器mjcb_control 可用来实现自定义执行器。回调通过 mujoco.h 中以 mjcb_ 为前缀的函数指针进行公开。 对于每个回调 mjcb_foo用户可以通过 mujoco.set_mjcb_foo(some_callable) 将其设置为 Python 可调用函数。要重置它请调用 mujoco.set_mjcb_foo(None)。要检索当前已安装的回调请调用 mujoco.get_mjcb_foo()如果没有通过 Python 绑定安装回调则不应使用 getter。每次进入回调时绑定都会自动获取 GIL并在重新进入 MuJoCo 之前释放它。这可能会对性能造成严重影响因为回调会在整个 MuJoCo 的计算管道中多次触发因此不太适合 生产 用例。不过预计这一功能将有助于复杂模型的原型设计。 另外如果回调是在本地动态库中实现的用户可以使用 ctypes 获取指向 C 函数指针的 Python 句柄并将其传递给 mujoco.set_mjcb_foo。然后绑定将检索底层函数指针并将其直接赋值给原始回调指针而且每次输入回调时都不会获取 GIL。
五、开环滚动 我们提供了一个代码示例展示如何通过 pybind11 以 Python 模块的形式添加额外的 C/C 功能。该示例在 rollout.cc 中实现并封装在 rollout.py 中实现了一个在 Python 之外实现紧密循环的常见用例在给定初始状态和控制序列的情况下推出轨迹即在循环中调用 mj_step()并返回后续状态和传感器值。基本使用形式为
state, sensordata rollout.rollout(model, data, initial_state, control) initial_state 是一个 nroll x nstate 数组包含 nroll 个大小为 nstate 的初始状态其中 nstate mj_stateSize(model,mjtState.mjSTATE_FULLPHYSICS)是完整物理状态的大小。 control 是一个 nroll x nstep x ncontrol 的控制数组。默认情况下控制是 mjModel.nu 标准执行器但也可以通过传递可选的 control_spec bitflag 来指定用户输入数组的任意组合。 如果滚动出现偏离当前状态和传感器值将用于填充轨迹的剩余部分。因此非递增时间值可用于检测发散滚动。 滚动功能设计为完全无状态因此步进流水线的所有输入都已设置给定 MjData 实例中已存在的任何值都不会对输出产生影响。 由于全局解释器锁可以释放因此该函数可以使用 Python 线程进行高效线程化。请参阅 rollout_test.py 中的 test_threading 函数了解线程操作的示例以及更广泛的使用示例。 六、从 mujoco-py 移植 在 mujoco-py 中主要入口点是 MjSim 类。用户通过 MJCF 模型类似于 dm_control.Physics构建一个有状态的 MjSim 实例该实例持有对 mjModel 实例及其相关 mjData 的引用。相比之下如上所述MuJoCo Python 绑定mujoco采用了更底层的方法遵循 C 库的设计原则mujoco 模块本身是无状态的只是封装了底层的本地结构和函数。 本文档无法对 mujoco-py 进行全面介绍但我们在下文中提供了一些实现说明这些说明并不是 mujoco-py 具体功能的详尽列表
mujoco_py.load_model_from_xml(bstring)该工厂函数构建了一个有状态的 MjSim 实例。使用 mujoco 时用户应调用上述工厂函数 mujoco.MjModel.from_xml_*。然后用户负责保存生成的 MjModel 结构实例并通过调用 mujoco.MjData(model) 明确生成相应的 MjData。sim.reset(), sim.forward(), sim.step()同上mujoco 用户需要调用底层库函数并传递 MjModel 和 MjData 实例mujoco.mj_resetData(model, data)、mujoco.mj_forward(model, data) 和 mujoco.mj_step(model, data)。sim.get_state()、sim.set_state(state)、sim.get_flattened_state()、sim.set_state_from_flattened(state)mujoco-py 实现了获取和设置某些相关字段的方法类似地dm_control.Physics 提供了与扁平化情况相对应的方法。Mujoco 没有提供这种抽象用户需要明确地获取/设置相关字段的值。sim.model.get_joint_qvel_addr(joint_name)这是 mujoco-py 中的一个便利方法用于返回与此关节相对应的连续索引列表。该列表从 model.jnt_qposadr[joint_index] 开始其长度取决于关节类型。mujoco 不提供此功能但可以使用 model.jnt_qposadr[joint_index] 和 xrange 轻松构建此列表。sim.model.*_name2id(name)mujoco-py 在 MjSim 中创建了 dicts可以高效查找不同类型对象的索引site_name2id、body_name2id 等。这些函数取代了 mujoco.mj_name2id(model, type_enum, name) 函数。mujoco 为使用实体名称提供了一种不同的方法--命名访问以及本地 mj_name2id 访问。sim.save(fstream, format_name)在这种情况下MuJoCo 库因此也包括 mujoco是有状态的它在内存中保存了最后编译的 XML 的副本该副本在 mujoco.mj_saveLastXML(fname) 中使用。请注意mujoco-py 的实现有一个方便的额外功能即姿势由 sim.data 的状态决定会转换为关键帧在保存前添加到模型中。而 mujoco 目前还没有这项额外功能。 七、从源构建 注意 只有在修改 Python 绑定或试图在特别老的 Linux 系统上运行时才有必要从源代码构建。如果不是这种情况我们建议从 PyPI 安装预编译的二进制文件。 确保已安装 CMake 和 C17 编译器。从 GitHub 下载最新的二进制版本。在 macOS 上下载对应的是一个 DMG 文件你可以将 MuJoCo.app 拖入你的 /Applications 文件夹。从 GitHub 克隆整个 mujoco 代码库然后 cd 进入 python 目录 git clone https://github.com/google-deepmind/mujoco.git
cd mujoco/python 创建虚拟环境 python3 -m venv /tmp/mujoco
source /tmp/mujoco/bin/activate 使用 make_sdist.sh 脚本生成源代码发布压缩包。 cd python
bash make_sdist.sh make_sdist.sh 脚本会生成构建绑定所需的其他 C 头文件并将 Python 目录之外的其他版本库中的所需文件拉入 sdist。完成后脚本将创建一个包含 mujoco-x.y.z.tar.gz 文件其中 x.y.z 是版本号的 dist 目录。使用生成的源代码分发版构建并安装绑定。你需要在 MUJOCO_PATH 环境变量中指定之前下载的 MuJoCo 库的路径。 注释 对于 macOS这可以是包含 mujoco.framework 的目录路径。特别是如果按照步骤 1 中的建议安装了 MuJoCo可以设置 MUJOCO_PATH/Applications/MuJoCo.app。 cd dist
MUJOCO_PATH/PATH/TO/MUJOCO MUJOCO_PLUGIN_PATH/PATH/TO/MUJOCO_PLUGIN pip install mujoco-x.y.z.tar.gz 现在应该已经安装了 Python 绑定要检查它们是否已成功安装请跳出 mujoco 目录并运行 python -c import mujoco。 提示 作为参考可在 GitHub 上的 MuJoCo 持续集成设置中找到可行的构建配置。