Skip to content

personalrobotics/geodude_assets

geodude_assets

MuJoCo models for the Geodude bimanual robot.

Geodude Robot

Installation

uv add geodude_assets

Or from source:

git clone https://github.com/personalrobotics/geodude_assets.git
cd geodude_assets
uv sync

Quick Start

import mujoco
from geodude_assets import get_model_path

# Load the Geodude robot
model = mujoco.MjModel.from_xml_path(str(get_model_path()))
data = mujoco.MjData(model)

# Reset to ready pose
ready_key = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_KEY, "ready")
mujoco.mj_resetDataKeyframe(model, data, ready_key)

# Step simulation
mujoco.mj_step(model, data)

View the robot in MuJoCo's interactive viewer:

uv run python -m mujoco.viewer --mjcf="$(uv run python -c 'from geodude_assets import get_model_path; print(get_model_path())')"

Collision Viewer

An interactive collision viewer is available to visualize collision geometry and contact detection:

uv run python -u examples/view_collisions.py
  • Use joint sliders to move the robot (Tab to show/hide control panel)
  • Colliding bodies turn red
  • Press 0 to toggle collision geometry visibility
  • Press C to toggle contact point visualization
  • Press Backspace to reset (or R if using mjpython)

Note on macOS: The viewer automatically falls back to blocking mode when using uv's Python. For non-blocking mode with launch_passive, you need a "framework" Python build (e.g., from Homebrew or python.org) and can run: mjpython examples/view_collisions.py

Swapping End Effectors

The default Geodude model has Robotiq 2F-140 grippers on both arms. To use different end effectors (e.g., Ability Hands), use the assembly module:

uv sync --extra assembly

Python API

from geodude_assets.assembly import attach_arms_to_vention

# Robotiq grippers on both arms (default)
model = attach_arms_to_vention(
    save_file=False,
    dir=".",
    filename="geodude.xml",
    left_gripper_type="2f140",
    right_gripper_type="2f140",
)

# Ability Hands on both arms
model = attach_arms_to_vention(
    save_file=False,
    dir=".",
    filename="geodude.xml",
    left_gripper_type="abhl",
    right_gripper_type="abhr",
)

# Mixed: Ability Hand on left, Robotiq on right
model = attach_arms_to_vention(
    save_file=False,
    dir=".",
    filename="geodude.xml",
    left_gripper_type="abhl",
    right_gripper_type="2f140",
)

# No grippers (bare UR5e arms)
model = attach_arms_to_vention(
    save_file=False,
    dir=".",
    filename="geodude.xml",
    left_gripper_type=None,
    right_gripper_type=None,
)

Command Line

# Generate and save a custom configuration
uv run python -m geodude_assets.assembly --save-mjcf -d ./output -l abhl -r 2f140

Available End Effectors

Type Description
2f140 Robotiq 2F-140 parallel jaw gripper
abhl Psyonic Ability Hand (left)
abhr Psyonic Ability Hand (right)
None No gripper (bare UR5e wrist)

Robot Configuration

The Geodude robot consists of:

  • Vention frame with vertical linear rails (enclosed lead screw actuators)
  • Two UR5e arms mounted on the linear rails
  • End effectors on each arm (configurable)
  • Worktop - a named site marking the usable work surface

Named Sites

Site Position Size Description
worktop (0, -0.35, 0.755) 1.2m × 0.8m Usable work surface on the Vention base

The worktop site is visualized as a semi-transparent green box and can be used by planners to define placement regions:

import mujoco
from geodude_assets import get_model_path

model = mujoco.MjModel.from_xml_path(str(get_model_path()))
site_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_SITE, "worktop")
worktop_pos = model.site_pos[site_id]   # [0, -0.35, 0.755]
worktop_size = model.site_size[site_id]  # [0.6, 0.4, 0.005] (half-extents)

Actuators

Actuator Range Description
left_linear_actuator 0-0.5m Left arm vertical position (0=bottom, 0.5=top)
right_linear_actuator 0-0.5m Right arm vertical position
left_ur5e/shoulder_pan ±π Left arm joint 1
left_ur5e/shoulder_lift ±π Left arm joint 2
left_ur5e/elbow ±π Left arm joint 3
left_ur5e/wrist_1 ±π Left arm joint 4
left_ur5e/wrist_2 ±π Left arm joint 5
left_ur5e/wrist_3 ±π Left arm joint 6
right_ur5e/... ... Right arm joints (same as left)
left_ur5e/gripper/fingers_actuator 0-255 Left gripper (0=open, 255=closed)
right_ur5e/gripper/fingers_actuator 0-255 Right gripper

Force/Torque Sensors

Each UR5e arm has a simulated 6-axis force/torque sensor at the tool flange, matching the built-in sensor on the real robot.

Sensor Output Description
left_ur5e/ft_sensor_force Fx, Fy, Fz Force at left tool flange (Newtons)
left_ur5e/ft_sensor_torque Tx, Ty, Tz Torque at left tool flange (Nm)
right_ur5e/ft_sensor_force Fx, Fy, Fz Force at right tool flange (Newtons)
right_ur5e/ft_sensor_torque Tx, Ty, Tz Torque at right tool flange (Nm)

Coordinate Frame (tool0): Z+ points out of the flange (toward the tool), X+ points left, Y+ points up.

import mujoco
from geodude_assets import get_model_path

model = mujoco.MjModel.from_xml_path(str(get_model_path()))
data = mujoco.MjData(model)

# Get sensor IDs
force_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_SENSOR, "right_ur5e/ft_sensor_force")
torque_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_SENSOR, "right_ur5e/ft_sensor_torque")

# Step simulation
mujoco.mj_step(model, data)

# Read sensor values
force_adr = model.sensor_adr[force_id]
torque_adr = model.sensor_adr[torque_id]
force = data.sensordata[force_adr:force_adr + 3]   # [Fx, Fy, Fz]
torque = data.sensordata[torque_adr:torque_adr + 3]  # [Tx, Ty, Tz]

Available Models

Model Description
geodude Full robot: two UR5e arms on Vention base with Robotiq 2F-140 grippers
universal_robots_ur5e Single UR5e arm
robotiq_2f140 Robotiq 2F-140 parallel jaw gripper
vention Vention aluminum frame base with linear rails
abh_left_small Psyonic Ability Hand (left, small)
abh_right_small Psyonic Ability Hand (right, small)

Load individual component models:

from geodude_assets import get_model_path

ur5e_path = get_model_path("universal_robots_ur5e")
gripper_path = get_model_path("robotiq_2f140")

Development

uv sync --dev

# Lint
uv run ruff check .
uv run ruff format .

# Test
uv run pytest

Regenerating the Geodude Model

To regenerate the default geodude model after modifying component XMLs:

uv sync --extra assembly
uv run python -m geodude_assets.assembly --save-mjcf -d src/geodude_assets/models/geodude -l 2f140 -r 2f140

Note: The assembly module uses dm_control.mjcf. The pyproject.toml includes a uv override to exclude labmaze (which requires Bazel to build) since it's not needed for MJCF model assembly.

License

MIT

About

MuJoCo assets for Geodude

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages