🔩 关节#
关节用来定义它所在的刚体 (Body) 与父刚体之间的运动自由度。每个刚体可以定义多个关节,组合多种自由度。如果一个刚体没有定义关节,该刚体与父刚体刚性连接。世界刚体 (world body) 中不能定义关节。关节的状态数据(位置、速度)保存在 SceneData 中,由于关节定义的自由度不同,状态数据的长度也有所不同。
关节类型#
类型 |
自由度 |
旋转表示 |
限制 |
说明 |
|---|---|---|---|---|
滑动关节(Slide) |
1 位移 |
无 |
可配置 |
由关节位置和滑动方向定义。 |
铰链关节(Hinge) |
1 旋转 |
角度 |
可配置 |
绕指定旋转轴旋转,旋转通过指定位置,是默认的关节类型。 |
球形关节(Ball) |
3 旋转 |
四元数 |
可配置 |
绕指定点旋转,可与滑动关节组合,不可与球形关节或铰链关节同时定义。 |
与 Mujoco 不同,mjcf 文件中的<freejoint>元素在 MotrixSim 中会解析为FloatingBase。
配置示例#
关节通过 MJCF 文件进行配置,可参考 examples/assets/joint.xml
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