|
Mujoco KDL Wrapper
0.2.2
MuJoCo + KDL bridge for robot kinematics and dynamics
|
This page collects the Python wrapper usage notes that are too detailed for the README. For complete function signatures, see the generated stubs in python/mj_kdl_wrapper/*.pyi.
The Python package exposes the same scene, robot, reset, viewer, and recorder concepts as the C++ wrapper. It owns MuJoCo mjModel/mjData through Scene or Env and returns KDL values through the upstream PyKDL module.
The wheel bundles PyKDL as a top-level extension module built from the same Orocos KDL fork as the wrapper. import PyKDL works after installation, but PyKDL does not appear in pip list / uv pip list because it is not installed as a separate Python distribution with its own .dist-info.
mj_kdl_wrapper.menagerie.model_path(name) resolves bundled-example model paths without hard-coding a checkout location. It checks overrides first, then known local or cached MuJoCo Menagerie checkouts:
menagerie.asset_path(rel) resolves bundled assets (gripper, table, mug) the same way: an optional per-asset env override, otherwise the user cache ~/.cache/mj_kdl_wrapper/assets. mj-kdl-fetch-menagerie populates both, and the same cache backs the C++ examples (see the C++ guide).
Overrides: the example scripts wire these per-file env vars – MJ_KDL_MODEL (arm), MJ_KDL_GRIPPER, MJ_KDL_TABLE, MJ_KDL_BOTTLE, MJ_KDL_RECEIVER. Each must point at an existing file or resolution raises a clear error. MJ_KDL_MENAGERIE overrides the Menagerie checkout root.
For other MJCF sources, set the relevant environment variable or assign RobotSpec.path directly.
SceneSpec has no defaults for timestep, add_floor, or add_skybox. Those are explicit scene choices. Scene.build() rejects timestep <= 0. spec.robots may be empty; object-only scenes are valid.
For an object-only scene, put MJCF or primitive objects in spec.objects and leave spec.robots empty:
Scene owns the compiled MuJoCo model/data. Call close() when you want to release native resources deterministically. Use time(), timestep(), step(), and step_n(n) when you want to advance the scene without a Robot control loop.
Set wrapper log verbosity globally when debugging scene construction:
mjk.__version__ is the Python package version. mjk.__mujoco_version__ is the MuJoCo version the extension was built against.
After init, joint_names, joint_limits, and all joint port vectors are in KDL chain order. Assignment to command ports must match n_joints; the bindings raise ValueError/RuntimeError for wrong sizes or closed handles.
When a tool or gripper is attached, pass ToolFrameSpec so the KDL chain uses the TCP site and includes the tool transform:
For a wrist force-torque sensor, attach the sensor MJCF first, then attach the gripper to a site exported by that sensor asset:
Then register the logical force-torque sensor on the same tool spec. MuJoCo models one FT sensor as separate <force> and <torque> sensors; the wrapper returns a PyKDL.Wrench.
AttachTarget is a tagged pair of AttachKind and an element name. The Kinova GEN3 MJCF exports pinch_site on the bracelet, so a Robotiq gripper can attach without manual pose offsets:
Optional pos and euler on the attachment spec are composed with the parent site pose, so small calibration offsets can stay local to the attachment:
Chains are supported by appending multiple AttachmentSpec objects in order. Each later attachment may reference a body, site, or frame added by an earlier attachment.
Use prefixes to keep MuJoCo names distinct when loading the same MJCF more than once. The prefix is also passed when creating the corresponding Robot handle.
SceneObject and RobotSpec share the same attach_to field, so robots and objects can be mounted to sites or bodies created earlier in the scene spec. Build order is decorations, objects in declaration order, robots, then cameras.
For primitive objects, shape, size, rgba, mass, and friction are required. For MJCF-backed objects, mjcf_path takes precedence and primitive geometry fields are ignored at runtime.
MuJoCo restricts free joints to top-level bodies, so a non-fixed primitive with a free joint must stay world-anchored.
Add fixed world cameras through SceneSpec.cameras. pos and fovy are required; euler defaults to identity.
SimulateViewer.use_camera(name) and VideoRecorder.use_camera(name) switch to a fixed camera. Pass "" to return to the free camera.
Use body_frame() and site_frame() to read world poses as PyKDL.Frame. Scene.set_body_pose() teleports a free body; Python quaternions for this method use xyzw order and are converted before calling MuJoCo.
For named actuators that are not part of a Robot joint mapping, use the direct actuator helpers:
The binding layer constructs standard PyKDL objects for KDL return types. Downstream code can use the regular PyKDL solvers:
Robot.set_joint_pos() and Robot.fk_frame(q) accept either Python sequences or PyKDL.JntArray. Scene.body_frame() and Scene.site_frame() return PyKDL.Frame.
Robot.gravity_torques(gravity_z=-9.81) is a convenience wrapper around KDL::ChainDynParam::JntToGravity() using the robot's measured positions. For full dynamics, get the chain with kdl_chain() and construct the PyKDL solver you need.
update() reads MuJoCo state into jnt_pos_msr, jnt_vel_msr, and jnt_trq_msr, then applies the command ports. In POSITION mode it writes jnt_pos_cmd to actuator controls. In TORQUE mode it writes jnt_trq_cmd to generalized forces. Robot.step() advances the owning scene data and returns False only when the underlying simulation loop has been closed by an interactive viewer.
Use set_joint_pos(q, call_forward=True) to seed joint state directly in KDL order:
Env is the resettable owner variant. It keeps registered robots synchronized across resets and runtime scene rebuilds.
Env.reset() restores MuJoCo state, calls the optional reset hook, re-seeds registered robot command ports from measured state, and clears stale forces. ResetContext.options and ResetContext.info expose the active reset request inside the hook. ResetOptions.use_keyframe = False forces a default MuJoCo reset instead of loading a keyframe.
Env mirrors the scene-level helpers for runtime state:
Scene.add_object(), Scene.remove_object(), Env.add_object(), and Env.remove_object() rebuild the native MuJoCo model/data and rebind existing Python Robot handles. Calling Scene.close() or Env.close() invalidates dependent robot handles; using one raises RuntimeError("robot is closed").
Use Env.add_object() / Env.remove_object() when the scene is resettable and registered robots should remain synchronized with future resets.
Use VideoRecorder.open(scene_or_env, path, width, height, fps) for explicit frame sizes, or open_preset() for VideoResolution presets. record_frame() captures the current state; step the scene or robot before each call.
The recorder camera list includes Current, Free, Tracking, robot MJCF cameras, and cameras added through SceneSpec.cameras.
SimulateViewer.open(robot) starts the custom MuJoCo Simulate UI and binds it to a robot handle. For object-only scenes, pass the Scene instead:
The UI exposes the same wrapper panels as the C++ viewer: Frames, Trace, Perturb, Recorder, and RTF. Use viewer.add_trace_segment() for Python trace overlays and viewer.use_camera(name) to switch to a named camera. viewer.realtime_factor controls pacing; 1.0 is real time, 0.0 runs as fast as the loop allows.