🔩 Joint#
A joint defines the degrees of freedom (DoF) between its associated rigid body (Body) and its parent body. Each rigid body can define multiple joints to combine various degrees of freedom. If a body does not define any joints, it is rigidly connected to its parent. Joints cannot be defined in the world body. The state data (position, velocity) of joints is stored in SceneData. Since joints can define different numbers of DoF, the length of the state data varies accordingly.
Joint Types#
Type |
DoF |
Rotation Representation |
Limits |
Description |
|---|---|---|---|---|
Slide Joint |
1 translation |
None |
Configurable |
Defined by joint position and sliding direction. |
Hinge Joint |
1 rotation |
Angle |
Configurable |
Rotates about a specified axis and position; this is the default joint type. |
Ball Joint |
3 rotations |
Quaternion |
Configurable |
Rotates about a specified point; can be combined with slide joints, but not with other ball or hinge joints simultaneously. |
Unlike Mujoco, the <freejoint> element in an mjcf file is parsed as a FloatingBase in MotrixSim.
Configuration Example#
Joints are configured via MJCF files. See examples/assets/joint.xml for reference.
API Usage Example#
Load an MJCF file in MotrixSim to create a scene and data:
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)
Access all joints in the scene:
# ----------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}")
Get joint index and access by joint name:
# 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}")
Get the value and velocity of the DoF associated with a joint:
# 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} ")
Get joint limits:
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]}")
Set joint position and velocity:
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])
For the complete code, see joint.py
API Reference#
For more APIs related to Joint, see Joint API