ROS 2 package containing the IGRIS-C robot description xacro sources, meshes, RViz config, MuJoCo xacro sources, and helper scripts to visualize and simulate the robot.
urdf/— robot xacro sources. The main entry point isurdf/igris_c_v2.urdf.xacro; the standalone parallel-link models are generated fromurdf/igris_c_v2_parallel_links.urdf.xacro.mujoco/— MuJoCo xacro sourcemujoco/igris_c_v2.xml.xacroplus the specialty static models that are intentionally kept separate:igris_c_v2_parallel_collision.xmlandigris_c_v2_parallel_toe.xml.meshes/— Geometry referenced by the URDF / MJCF models.launch/display_urdf_with_gui.launch.py— Launch RViz with joint-state sliders androbot_state_publisher.rviz/urdf.rviz— Preconfigured RViz view.scripts/imu_tf_broadcaster.py— ROS 2 node that republishes an/igris_c/imuorientation as a TF onbase_link.scripts/export_model.py— Standalone exporter that expands the canonical URDF or MuJoCo xacro and writes generated files intourdf/ormujoco/.scripts/mujoco_file_test.py— Minimal MuJoCo passive-viewer runner that expandsmujoco/igris_c_v2.xml.xacro, writes a temporary MJCF, and steps the simulation.
The description package now treats the xacro sources as the canonical robot
models. Legacy generated .urdf / .xml files are no longer the primary
authoring format.
urdf/igris_c_v2.urdf.xacro- Args:
base_type,parallel,end_effector,ankle_version,wrist_version base_type: selects the torso-base or pelvis-base assembly order.parallel: adds the waist / ankle / wrist parallel-link substructures.end_effector: selects the lower-arm attachment (dummy,none,hand,magnet,1dof).ankle_version:v1(original foot) orv2(reinforced foot). Selects the foot link inertial and mesh.wrist_version:v1(intersecting roll/pitch axes) orv2(offset axes, both four-bars reworked). Selects the wrist link geometry, limits and meshes.
- Args:
urdf/igris_c_v2_parallel_links.urdf.xacro- Args:
variant,ankle_version,wrist_version variant: which single linkage to emit --waist,left_ankle,right_ankle,left_wrist,right_wrist.ankle_version/wrist_version: same meaning as above; only the matchingvariantreads them.- Purpose: standalone 4-bar linkage models used by
JointManager.
- Args:
mujoco/igris_c_v2.xml.xacro- Args:
base_type,parallel,end_effector,fixed,ankle_version,wrist_version base_type: torso floating-base chain vs pelvis floating/fixed chain.parallel: selects serial vs parallel waist / ankle / wrist topology.end_effector: selects the lower-arm payload module.fixed: selects floating-base vs fixed-base MuJoCo model setup.ankle_version:v1(original foot) orv2(reinforced foot). Selects the foot<inertial>, visual mesh, and the ankle parallel-link<connect>anchors.wrist_version:v1orv2. v2 offsets the pitch axis from the roll axis, replaces the universal+hinge rod pair with a ball joint, and moves every wrist<connect>anchor. The ball joint adds 8 qpos, so the parallel keyframes branch on it too.
- Args:
In both URDF and MuJoCo:
parallelshould only change the closed-loop mechanism topology and its directly dependent inertial / actuator / keyframe data.end_effectorshould only change the wrist-end payload module and its directly dependent assets.ankle_versionis a shared physical fact (single keyigris_c.description.common.ankle_version) and must match between the URDF and MuJoCo models. It changes only the foot link / geometry (and, in MuJoCo, the ankle parallel-link<connect>anchors).wrist_versionis the same kind of shared physical fact (single keyigris_c.description.common.wrist_version), applied to both wrists at once. It also selects theigris_c_v2_parallel_links.urdf.xacrowrist sub-model thatJointManagerloads, so the model and the kinematics constants stay in step.- Common body chains stay in the main entry xacro so that variant-specific logic remains localized.
- ROS 2 with
ament_cmake,robot_state_publisher,joint_state_publisher_gui,rviz2, andxacro. - Python 3.8+.
- MuJoCo Python package:
pip install mujoco(only needed forscripts/mujoco_file_test.py). - A working X / Wayland display and OpenGL drivers for the MuJoCo viewer. If you hit GLX errors under Conda, prefer a venv that uses system libGL.
cd /path/to/your/ros2_ws/src
git clone <this repo> igris_c_description
cd ..
colcon build --packages-select igris_c_description
source install/setup.bashLaunch the URDF / xacro with sliders and RViz:
ros2 launch igris_c_description display_urdf_with_gui.launch.pyLaunch arguments (all optional):
| Argument | Default | Description |
|---|---|---|
urdf_package |
igris_c_description |
Package the URDF / xacro is loaded from. |
urdf_path |
urdf/igris_c_v2.urdf.xacro |
URDF or xacro path inside the package's share directory. |
end_effector |
dummy |
End-effector variant when loading a xacro. See below. |
end_effector accepts:
dummy— dummy spherical payload.none— no end effector.hand— articulated hand variant.magnet— magnet end-effector variant.1dof— 1-DOF gripper variant.
Examples:
# Build the canonical xacro with the default dummy payload
ros2 launch igris_c_description display_urdf_with_gui.launch.py \
urdf_path:=urdf/igris_c_v2.urdf.xacro
# Build the xacro with the articulated hand
ros2 launch igris_c_description display_urdf_with_gui.launch.py \
urdf_path:=urdf/igris_c_v2.urdf.xacro end_effector:=handThe joint-state GUI publishes on /igris_c/joint_states (remapped from
/joint_states), and robot_state_publisher subscribes to the same topic.
scripts/imu_tf_broadcaster.py subscribes to /igris_c/imu (sensor_msgs/Imu)
and broadcasts the orientation as a TF whose parent and child are both
base_link (translation zeroed). It is installed as an executable, so after
sourcing the workspace:
ros2 run igris_c_description imu_tf_broadcaster.pyscripts/mujoco_file_test.py expands mujoco/igris_c_v2.xml.xacro with
hard-coded defaults near the top of the file, writes a temporary MJCF, and
opens MuJoCo's passive viewer until the window is closed.
Recommendation: use a local venv to avoid Conda libGL conflicts.
python3 -m venv .venv
source .venv/bin/activate
pip install mujoco
python scripts/mujoco_file_test.pyTo try a different variant, edit the constants in
scripts/mujoco_file_test.py:
BASE_TYPE:torsoorpelvisPARALLEL:trueorfalseEND_EFFECTOR:dummy,none,hand,magnet, or1dofFIXED:trueorfalse
If you want to inspect a standalone generated .urdf or .xml file directly,
use scripts/export_model.py.
Examples:
# Generate only URDF into urdf/
python3 igris_c_description/scripts/export_model.py \
--format urdf \
--base-type pelvis \
--parallel false \
--end-effector dummy
# Generate only MuJoCo XML into mujoco/
python3 igris_c_description/scripts/export_model.py \
--format xml \
--base-type pelvis \
--parallel true \
--end-effector dummy \
--fixed trueDefault output naming:
- URDF:
urdf/igris_c_v2_<base_type>_[parallel_]<end_effector>_<ankle_version>_<wrist_version>.urdf - XML:
mujoco/igris_c_v2_<base_type>_[parallel_]<end_effector>_<free|fixed>_<ankle_version>_<wrist_version>.xml
The script writes into the package's urdf/ and mujoco/ directories so the
generated files can be opened independently without going through launch files
or the temporary-file path used by the MuJoCo viewer helper.
mujoco/igris_c_lowerarm_module.xml.xacro gives solreflimit="0.002 1" to the
12 wrist joints (*_wrist_flange_{front,back}, *_wrist_{roll,pitch}).
Their range limits act as the load-bearing stops of the wrist four-bar.
MuJoCo's default limit solref timeconst is 0.02 s, 42x the timestep, which is
soft enough for a floor impact to push *_wrist_roll about 13 deg past its
limit. That drives the two *_wrist_flange_* joints to a pair
Parallel4BarLink::fk() cannot invert, and fk() then spends tens of
milliseconds failing — inside the MuJoCo control callback, on the physics
thread, which stalls stepping and rendering together.
Limit solreflimit timeconst |
Roll overshoot | Worst motor2Joint |
|---|---|---|
| 0.02 (MuJoCo default) | 13.4 deg | 79,304 us |
| 0.01 | 7.7 deg | 59,530 us |
| 0.005 | 3.1 deg | 2,306 us |
| 0.002 (current) | 0.8 deg | 2,272 us |
solimplimit is left at the MuJoCo default: raising the impedance on top of
the timeconst change moved overshoot only from 0.8 to 0.4 deg. dampratio
stays 1 (critically damped).
This narrows how the wrist enters the unsolvable range; it does not remove the
underlying fk() cost. A hard enough impact still reaches it.
The repository config uses this description structure:
igris_c:
description:
config_root_dir: "/path/to/igris_c_description"
urdf:
robot_model_path: "urdf/igris_c_v2.urdf.xacro"
parallel_links_path: "urdf/igris_c_v2_parallel_links.urdf.xacro"
mujoco:
robot_model_path: "mujoco/igris_c_v2.xml.xacro"
base_type: "pelvis"
parallel: "true"
fixed: "true"
end_effector:
type: "none"igris_c_v2.xml.xacro covers the normal MuJoCo model variants. Only
igris_c_v2_parallel_collision.xml and igris_c_v2_parallel_toe.xml remain as
specialty static MJCF files.
Path handling rules:
igris_c.description.config_root_dirpoints at the description package root.igris_c.description.urdf.robot_model_pathmay be relative toconfig_root_diror absolute. Launch accepts.urdfand.urdf.xacro.igris_c.description.urdf.parallel_links_pathmay be relative toconfig_root_diror absolute, but it is consumed as a xacro entry for the five parallel-link variants.igris_c.description.mujoco.robot_model_pathmay be relative toconfig_root_diror absolute. Launch accepts.xmland.xml.xacro.- For
.xacropaths, launch expects a compatible entry contract:- URDF main model xacro must declare
base_type,parallel,end_effector - Parallel-links xacro must declare
variant - MuJoCo main model xacro must declare
base_type,parallel,end_effector,fixed
- URDF main model xacro must declare
Generate the default controller URDF from xacro:
xacro igris_c_description/urdf/igris_c_v2.urdf.xacro \
base_type:=pelvis \
parallel:=false \
end_effector:=dummyGenerate the default simulation MJCF from xacro:
xacro igris_c_description/mujoco/igris_c_v2.xml.xacro \
base_type:=pelvis \
parallel:=true \
end_effector:=dummy \
fixed:=trueRun the full simulation stack with the development config:
ros2 launch igris_c_controller simulation.launch.py \
config_file:=/home/robros3/ros2_ws/src/igris_c/configs/robot/dev_robot.yamlThe current development config maps to this MuJoCo variant:
base_type:=pelvisparallel:=trueend_effector:=dummyfixed:=true
Examples of other useful combinations:
base_type:=torso parallel:=false end_effector:=hand fixed:=falsebase_type:=pelvis parallel:=true end_effector:=magnet fixed:=truebase_type:=torso parallel:=true end_effector:=1dof fixed:=true
Config-to-xacro mapping:
igris_c.description.urdf.robot_model_path→ main URDF xacro entryigris_c.description.urdf.parallel_links_path→ standalone parallel-link URDF xacro entryigris_c.description.mujoco.robot_model_path→ main MuJoCo xacro entryigris_c.description.mujoco.base_type→ xacrobase_typeigris_c.description.mujoco.parallel→ xacroparalleligris_c.end_effector.type→ xacroend_effectordirectlyigris_c.description.mujoco.fixed→ xacrofixed
Runtime consumers:
igris_c_controllerlaunch path- resolves description paths first
- expands the main controller URDF once with fixed controller defaults:
base_type:=pelvis parallel:=false end_effector:=<igris_c.end_effector.type> - expands the main MuJoCo XML once with
base_type,parallel,end_effector,fixedfrom robot config - publishes:
igris_c.description.urdf.robot_model_xml- resolved absolute
igris_c.description.urdf.parallel_links_path - resolved/generated
igris_c.description.mujoco.robot_model_path
igris_c_controller/RobotManager- reads
igris_c.description.urdf.robot_model_xml - does not expand xacro itself anymore
- reads
igris_c_lib/JointManager- loads
igris_c.description.urdf.parallel_links_path - expands the xacro five times with
variant:=...
- loads
igris_c_mujoco- reads the already generated/resolved
igris_c.description.mujoco.robot_model_path - does not expand xacro itself anymore
- reads the already generated/resolved
igris_c_controller/MujocoSimController- reads
igris_c.description.mujoco.parallel - when
parallel:=false, treats the MuJoCo actuator set as serial joint-space actuators and remaps controller motor-space outputs back to joint space before writing commands into MuJoCo SHM - uses the same
igris_c.description.urdf.parallel_links_pathsource asJointManagerso sim-only remapping stays aligned with the controller's parallel-link kinematics
- reads
- Run from a terminal inside your desktop session (
DISPLAYset,glxinfo -Bworks). - If the viewer fails with GLX errors under Conda, switch to the venv above or ensure system libGL is picked up.