PyMJCF 使用教程

devtools/2024/11/10 13:40:29/

系列文章目录


前言

重要:如果您在使用 PyMJCF 时发现自己卡住了,请查看本页上的各个重要方框和底部的常见问题部分,看看其中是否有相关内容。

        该库为 MuJoCo 基于 XML 的 MJCF 物理建模语言提供了一个 Python 对象模型。该库的目标是让用户能够在 Python 中轻松地与 MJCF 模型交互并对其进行修改,就像 JavaScript DOM 对 HTML 所做的那样。

        该库的一个主要特点是能够轻松地将多个独立的 MJCF 模型组成一个更大的模型。不同模型或同一模型的多个实例中的重复名称会自动进行消歧处理。

        下面的代码段提供了该库典型用例的一个快速示例。在这里,UpperBody 类可以简单地实例化 Arm 的两个副本,从而减少代码重复。每个 Arm 的身体、关节或 geoms 的名称都自动以其父名称为前缀,因此不会发生名称碰撞。


一、基本操作

1.1 创建 MJCF 模型

        在 PyMJCF 中,模型的基本构件是 mjcf.Element。它对应于生成的 XML 中的一个元素。然而,用户代码不能直接实例化一个通用的 mjcf.Element 对象。

        一个有效的模型总是由一个根 <mujoco> 元素组成。这在 PyMJCF 中被表示为特殊的 mjcf.RootElement 类型,它可以在用户代码中被实例化以创建一个空模型。

from dm_control import mjcfmjcf_model = mjcf.RootElement()
print(mjcf_model)  # MJCF Element: <mujoco/>

1.2 添加新元素

        新元素的属性可以作为 kwargs 传递:

my_box = mjcf_model.worldbody.add('geom', name='my_box',type='box', pos=[0, .1, 0])
print(my_box)  # MJCF Element: <geom name="my_box" type="box" pos="0. 0.1 0."/>

1.3 解析现有的 XML 文档

        另外,如果已有一个 XML 文件,PyMJCF 也可以对其进行解析,以创建一个 Python 对象:

from dm_control import mjcf# Parse from path
mjcf_model = mjcf.from_path(filename)# Parse from file
with open(filename) as f:mjcf_model = mjcf.from_file(f)# Parse from string
with open(filename) as f:xml_string = f.read()
mjcf_model = mjcf.from_xml_string(xml_string)print(type(mjcf_model))  # <type 'mjcf.RootElement'>

1.4 遍历模型

        请看下面的 MJCF 模型:

<mujoco model="test"><default><default class="brick"><geom rgba="1 0 0 1"/></default></default><worldbody><body name="foo"><freejoint/><inertial pos="0 0 0" mass="1"/><body name="bar"><joint name="my_hinge" type="hinge"/><geom name="my_geom" pos="0 1 2" class="brick"/></body></body></worldbody>
</mujoco>

        Element 对象的子元素和 XML 属性都作为 Python 属性公开。这些属性的名称都与它们的 XML 对应属性相同,只有一个例外:class XML 属性被命名为 dclass,以避免与 Python class 关键字冲突:

my_geom = mjcf_model.worldbody.body['foo'].body['bar'].geom['my_geom']
print(isinstance(mjcf_model, mjcf.Element)) # True
print(my_geom.name)    # 'my_geom'
print(my_geom.pos)     # np.array([0., 1., 2.], dtype=float)
print(my_geom.class)   # SyntaxError
print(my_geom.dclass)  # 'brick'

        请注意,对象模型中的属性值不受默认值的影响:

print(mjcf_model.default.default['brick'].geom.rgba)  # [1, 0, 0, 1]
print(my_geom.rgba)  # None

1.5 无需遍历即可查找元素

        我们还可以直接查找元素,而无需遍历对象层次结构:

found_geom = mjcf_model.find('geom', 'my_geom')
print(found_geom == my_geom)  # True

        查找给定类型的所有元素

# Note that <freejoint> is also considered a joint
joints = mjcf_model.find_all('joint')
print(len(joints))  # 2
print(joints[0] == mjcf_model.worldbody.body['foo'].freejoint)  # True
print(joints[1] == mjcf_model.worldbody.body['foo'].body['bar'].joint[0])  # True

        请注意,find_all 返回元素的顺序与它们在模型中声明的顺序相同。

1.6 修改 XML 属性

        属性可以修改、添加或删除:

my_geom.pos = [1, 2, 3]
print(my_geom.pos)   # np.array([1., 2., 3.], dtype=float)
my_geom.quat = [0, 1, 0, 0]
print(my_geom.quat)  # np.array([0., 1., 0., 0.], dtype=float)
del my_geom.quat
print(my_geom.quat)   # None

        违反模式会导致错误:

print(my_geom.poss)  # raise AttributeError (no child or attribute called poss)
my_geom.pos = 'invalid'  # raise ValueError (assigning string to array)
my_geom.pos = [1, 2, 3, 4, 5, 6]  # raise ValueError (array length is too long)# raise ValueError (mass is a required attribute of <inertial>)
del mjcf_model.find('body', 'foo').inertial.mass

1.7 标识符的唯一性

        PyMJCF 强化了模型中 "标识符 "属性的唯一性。标识符由 <default> 的类属性和所有名称属性组成。它们的唯一性只在特定命名空间内强制执行。例如,<body> 可以与 <geom> 具有相同的名称,而 <position> 和 <velocity> 执行器则不能具有相同的名称。

mjcf_model.worldbody.add('geom', name='my_geom')
foo = mjcf_model.worldbody.find('body', 'foo')
foo.add('my_geom')  # Error, duplicated geom name
foo.add('foo')  # OK, a geom can have the same name as a body
mjcf_model.find('geom', 'foo').name = 'my_geom'  # Error, duplicated geom name

1.8 引用属性

        有些属性是对其他元素的引用。例如,执行器的关节属性指向模型中的 <joint> 元素。

mjcf.Element 可以直接分配给这些引用属性:

my_hinge = mjcf_model.find('joint', 'my_hinge')
my_actuator = mjcf_model.actuator.add('velocity', joint=my_hinge)

        这是分配引用属性的推荐方式,因为它能保证在被引用元素重命名时引用不会失效。另外,字符串也可以分配给引用属性。在这种情况下,PyMJCF 不会尝试验证命名的元素是否确实存在于模型中。

重要:如果被引用的元素与引用属性在不同的模型中(例如在附加模型中),则必须通过直接将 mjcf.Element 对象而不是字符串赋值给属性来创建引用。分配给引用属性的字符串不能包含"/",因为 PyMJCF 会在附加时自动对它们进行作用域划分。

二、附加模型

        在本节中,我们将 mjcf.RootElement 简单地称为 "模型"。模型可以附加到其他模型上,以创建合成场景。

arena = mjcf.RootElement()
arena.worldbody.add('geom', name='ground', type='plane', size=[10, 10, 1])robot = mjcf.from_xml_file('robot.xml')
arena.attach(robot)

我们把 arena 称为父模型,把机器人称为子模型(或附着模型)。

2.1 附加 frames

        当一个模型被附加到一个场地时,会在父模型中创建一个空体。这个空体称为附着 frame。

        附着 frame 是作为包含附着点的主体的子体创建的,其位置和方向与站点相同。生成 XML 时,附着 frame 的内容会与所附模型的 <worldbody> 内容一致。在生成的 XML 中,附着 frame 的名称是子代的完全/限定/前缀/。尾部的斜线确保附着 frame 的名称不会与用户定义的主体相冲突。

        更具体地说,如果我们有以下父模型和子模型:

<mujoco model="parent"><worldbody><body><geom name="foo" type="box" pos="-0.2 0 0.3" size="0.5 0.3 0.1"/><site name="attachment_site" pos="1. 2. 3." quat="1. 0. 0. 1."/></body></worldbody>
</mujoco><mujoco model="child"><worldbody><geom name="bar" type="box" pos="0.5 0.25 1." size="0.1 0.2 0.3"/></worldbody>
</mujoco>

        那么最终生成的 XML 将是

<!-- PyMJCF-generated XML, contains implementation details -->
<mujoco model="parent"><worldbody><body><geom name="foo" type="box" pos="-0.2 0 0.3" size="0.5 0.3 0.1"/><site name="attachment_site" pos="1. 2. 3." quat="1. 0. 0. 1."/><body name="child/" pos="1. 2. 3." quat="1. 0. 0. 1."><geom name="child/my_box" type="box" pos="0.5 0.25 1." size="0.1 0.2 0.3"/></body></body></worldbody>
</mujoco>

        重要:附着 frame 是以对用户透明的方式创建的。特别是,PyMJCF 不会将其作为常规正文处理。生成的 XML 中的名称应视为实现细节,不应依赖。

        尽管如此,有时还是有必要访问附着 frame ,例如在父模型和子模型之间添加一个连接点。最简单的方法是持有对 attach 调用所返回对象的引用:

attachment_frame = parent_model.attach('child')
attachment_frame.add('freejoint')

        另外,如果模型已经被附加,则可以使用附着框架命名空间中的 find 函数来检索附着 frame 。mjcf.traversal_utils 中的 get_attachment_frame 方便函数可以查找子模型的附着 frame ,而无需访问父模型。

frame_1 = parent_model.find('attachment_frame', 'child')# Convenience function: get the attachment frame directly from a child model
frame_2 = mjcf.traversal_utils.get_attachment_frame(child_model)
print(frame_1 == frame_2)  # True

重要: 为鼓励良好的建模实践,附着 frame 的直接子元素只能是 <joint> 和 <inertial>。其他类型的元素应添加到附加模型的 <worldbody> 中。

2.2 元素所有权

重要:当遍历父模型时,子模型的元素不会出现。

2.3 默认类

        PyMJCF 确保父模型的默认类永远不会影响它的任何子模型。这最大限度地减少了两个模型发生微妙的 "不兼容 "的可能性,因为无论模型附属于哪个模型,其行为方式总是相同的。

        PyMJCF 在实践中实现这一点的方法是将模型的全局 <default> 上下文中的所有内容移到一个名为 / 的默认类中。换句话说,PyMJCF 生成的模型永远不会在全局默认上下文中出现任何内容。相反,生成的模型总是看起来像这样:

<!-- PyMJCF-generated XML, contains implementation details -->
<mujoco><default><default class="/"><!-- "global defaults" go here --><geom rgba="1. 0. 0. 1."/></default></default>
</mujoco>

        重要:这种转换对用户是透明的。在 Python 中,上述 geom rgba 设置被当作全局默认值访问,即 mjcf_model.default.geom.rgba。一般来说,用户不必担心 PyMJCF 对默认值的内部处理。

        当模型被附加时,它的 / 默认类会变成 fully/qualified/prefix/。尾部的斜线确保了这种转换不会与用户命名的默认类发生冲突。更具体地说,如果我们有以下父模型和子模型:

<mujoco model="parent"><default><geom rgba="1. 0. 0. 1."/><default class="green"><geom rgba="0. 1. 0. 1."/></default></default>
</mujoco><mujoco model="child"><default><joint range="0. 1."/><default class="stiff"><joint stiffness="0.1"/></default></default>
</mujoco>

        那么最终生成的 XML 将是

<!-- PyMJCF-generated XML, contains implementation details -->
<mujoco model="parent"><default><default class="/"><geom rgba="1. 0. 0. 1."/><default class="green"><geom rgba="0. 1. 0. 1."/></default></default><default class="child/"><joint range="0. 1."/><default class="child/stiff"><joint stiffness="0.1"/></default></default></default>
</mujoco>

2.4 全局选项

        如果任何全局选项不同,则无法将一个模型附加到另一个模型。全局选项由 <compiler>, <option>, <size> 和 <visual> 属性组成。与处理默认类一样,这是为了确保两个模型不会出现微妙的 "不兼容"。例如

model_1 = mjcf.RootElement()
model_1.compiler.angle = 'radian'model_2 = mjcf.RootElement()
model_2.compiler.angle = 'degree'model_1.attach(model_2)  # Error!

        只有当两个模型明确赋予一个选项不同的值时,该选项才会被认为是冲突的。下面举例说明冲突选项可能产生的问题:

model_1 = mjcf.RootElement()model_2 = mjcf.RootElement()
model_2.compiler.angle = 'degree'model_1.attach(model_2)  # No error, but all angles in model_1 are now wrong!

在这里,model_1 假设 MuJoCo 的默认角度单位为弧度。由于没有显式地给 compiler.angle 赋值,PyMJCF 没有检测到与 model_2 中的 angle=degree 冲突。现在,model_1 中的所有角度都被错误地解释为度。

2.5 <worldbody> 以外的元素

        当连接模型时,所有非世界体元素的子元素(如致动器或肌腱)都会自动合并到适当的位置。已命名元素的前缀如前所述。

三、常见问题 {#common-gotchas}

3.1 使用 foo.dclass,而不是 foo.class

        class XML 属性与 PyMJCF 中的 dclass Python 属性相对应。这是因为 class 在 Python 中是一个保留关键字。不过,在 getattr 中使用 "class "也是可以的。

<geom name="my_geom" class="red"/>
print(my_geom.class)   # SyntaxError
print(my_geom.dclass)  # 'red'
print(getattr(my_geom, 'class'))  # 'red'

3.2 foo.type 和 foo.range 没问题

        type 和 range 属性在 Cider 中会触发语法高亮,但它们在 Python 中不是保留字。

my_geom.type = 'capsule'  # OK!
my_joint.range = [-1, 1]  # OK!

3.3 一个模型只能附加一次

一个模型不能附加两次。如果在模拟中需要同一模型的多个副本,可以制作深拷贝。最好是定义一个类来构造模型,然后根据需要多次调用构造函数。


http://www.ppmy.cn/devtools/28883.html

相关文章

Rust特征

一、Rust特征是什么、怎么用 1、Rust特征是什么 我认为Rust特征和Java中的接口类似&#xff0c;但是扩展了语义 特征定义了一组可以被共享的行为&#xff0c;只要实现了特征&#xff0c;你就能使用这组行为 2、Rust特征怎么使用 &#xff08;1&#xff09;特征定义 pub tra…

javascrip对象如何区分属性和方法

在JavaScript中&#xff0c;对象是由属性和方法构成的。属性是对象的特征或状态&#xff0c;而方法是对象能够执行的动作。 属性的特点&#xff1a; 属性是对象的成员&#xff0c;用来描述对象的状态或特征。属性可以是基本数据类型&#xff08;如字符串、数字、布尔值等&…

第一阶段--Day2--信息安全法律法规、网络安全相关标准

目录 1. 针对信息安全的规定 2. 网络安全相关标准 1. 针对信息安全的规定 《中华人民共和国计算机信息系统安全保护条例》1994年2月18日颁布并实施 中华人民共和国计算机信息系统安全保护条例__增刊20111国务院公报_中国政府网 《中华人民共和国国际联网安全保护管理…

介绍一下传统vgg,gan- based,diffusion-based风格迁移路线的优缺点

一、VGG风格迁移是一种基于深度学习的图像风格迁移技术。 其核心在于使用卷积神经网络&#xff08;CNN&#xff09;&#xff0c;特别是VGG网络&#xff0c;来提取和融合源图像的内容特征与目标图像的风格特征。在VGG风格迁移中&#xff0c;通常会使用预训练的VGG网络来提取特征…

Hive EXPLAIN 执行计划解析

Hive EXPLAIN 执行计划解析 EXPLAIN 语法 Hive提供了一个EXPLAIN命令&#xff0c;用于显示查询的执行计划。该语句的语法如下&#xff1a; EXPLAIN [EXTENDED|CBO|AST|DEPENDENCY|AUTHORIZATION|LOCKS|VECTORIZATION|ANALYZE] query 在EXPLAIN语句中使用EXTENDED会提供关于计…

axios.get请求 重复键问题??

封装的接口方法&#xff1a; 数据&#xff1a; 多选框多选后 能得到对应的数组 但是请求的载荷却是这样的,导致会请求不到数据 departmentChecks 的格式看起来是一个数组&#xff0c;但是通常 HTTP 请求的查询参数不支持使用相同的键&#xff08;key&#xff09;名多次。如…

【简单讲解下FastStone Capture】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

羊大师分解,羊奶滋养孩子成长的秘密武器

羊大师分解&#xff0c;羊奶滋养孩子成长的秘密武器 羊奶作为孩子成长的秘密武器&#xff0c;确实在滋养和促进孩子健康方面发挥着重要作用。以下是一些羊奶滋养孩子成长的秘密&#xff1a; 营养成分丰富&#xff1a;羊奶是营养最全面丰富的食品之一&#xff0c;含有较牛奶更…