🔩 关节(Joint)#

关节用来定义它所在的刚体 (Body) 与父刚体之间的运动自由度。每个刚体可以定义多个关节,组合多种自由度。如果一个刚体没有定义关节,该刚体与父刚体刚性连接。世界刚体 (world body) 中不能定义关节。关节的状态数据(位置、速度)保存在 SceneData 中,由于关节定义的自由度不同,状态数据的长度也有所不同。

关节类型#

类型

自由度

旋转表示

限制

说明

滑动关节(Slide)

1 位移

可配置

由关节位置和滑动方向定义。

铰链关节(Hinge)

1 旋转

角度

可配置

绕指定旋转轴旋转,旋转通过指定位置,是默认的关节类型。

球形关节(Ball)

3 旋转

四元数

可配置

绕指定点旋转,可与滑动关节组合,不可与球形关节或铰链关节同时定义。

与 Mujoco 不同,mjcf 文件中的<freejoint>元素在 MotrixSim 中会解析为FloatingBase

配置示例#

关节通过 MJCF 文件进行配置,可参考 examples/assets/joint.xml

MJCF 关节相关标签说明

API 使用示例#

在 MotrixSim 中加载 MJCF 文件创建场景和数据

import time

import numpy as np

from motrixsim import SceneData, load_model, run, step
from motrixsim.render import RenderApp

# Mouse controls:
# - Press and hold left button then drag to rotate the camera/view
# - Press and hold right button then drag to pan/translate the view


def main():
    # Create render window for visualization
    with RenderApp() as render:
        # The scene description file
        path = "examples/assets/joint.xml"
        # Load the scene model
        model = load_model(path)

        # Create the render instance of the model
        render.launch(model)
        # Create the physics data of the model
        data = SceneData(model)

获取场景中的所有关节

# ----------Try to access joint data----------
# How many joints in the model?
num_joints = model.num_joints
# Get the all joints in the model
joints = model.joints
# The name list of joints in the model
joint_names = model.joint_names
print(f"num_joints :{num_joints}, joint_names : {joint_names}, joints : {joints}")

通过关节名称获取关节索引和访问

# Try to visit "joint_A"
joint_A_index = model.get_joint_index("joint_A")
joint_A = model.get_joint(joint_A_index)
assert joint_A is not None, "Expect joint_A in the model"
print(f"joint_addr is {joint_A_index}, joint_A is : {joint_A}, name is : {joint_A.name}")

获取关节对应自由度的值和速度

# Indicate the first pos data index of each joint in SceneData.dof_pos
pos_indices = model.joint_dof_pos_indices
# Indicate the first vel data index of each joint in SceneData.dof_vel
vel_indices = model.joint_dof_vel_indices

# The pos of joint_A (hinge joint ,num_dof_pos is 1, num_dof_vel is 1)
joint_A_pos_0 = data.dof_pos[pos_indices[joint_A_index]]
joint_A_vel_0 = data.dof_vel[vel_indices[joint_A_index]]
print(f"joint_A_pos_0 is :{joint_A_pos_0}, joint_A_vel_0 is : {joint_A_vel_0} ")

获取关节的限制

joint_limits = model.joint_limits
assert joint_limits.shape == (2, num_joints), (
    f"joint_limits shape is {joint_limits.shape}, but should be (2, {num_joints})"
)
# Limits of joint_A
limits = joint_limits[:, joint_A_index]
print(f"limit of joint_A in radian, min: {limits[0]}, max: {limits[1]}")

# Limits of joint_B
limits = joint_limits[:, joint_B_index]
print(f"limit of joint_B is radian, min: {limits[0]}, max: {limits[1]}")

配置关节的位置和速度

print("-------Set vel and get-------")
# Try to set vel directly
joint_A.set_dof_vel(data, np.array([0.1]))
# Use joint dof_vel_index to get dof_vel
dof_vel_index = joint_A.dof_pos_index
dof_vel = data.dof_vel[dof_vel_index]
print(f"dof_vel of joint_A is : {dof_vel}")
# Or use get_dof_vel() directly. It's the same with dof_pos
dof_vel = joint_A.get_dof_vel(data)
print(f"dof_vel of joint_A is : {dof_vel}")
print("-----------------------------")
# Set positions
# joint_A, num_dof_pos is 1
joint_A.set_dof_pos(data, [0.1])
# joint_B, num_dof_pos is 4
joint_B.set_dof_pos(data, [0.0, 0.0, 0.0, 1.0])

完整代码见 joint.py

API Reference#

更多与 Joint 相关的 API,请参考 Joint API