This repository contains a complete MuJoCo model of the Solo-12 quadruped, including high fidelity visuals:
The model has been optimized for loading time and rendering performance by:
- Removing duplicate geometry and reusing meshes as much as possible
- Simplifying large meshes
- Manually filtering and removing internal components
🤗 Please feel free to submit improvements to the model by opening a pull request!
- Install requirements:
pip3 install -r requirements.txt - Generate the Solo-12 model:
python3 ./generate_model.py- This will write an
.xmlfile with the geometry of the four legs imported and correctly oriented
- This will write an
- Start MuJoCo:
python3 -m mujoco.viewer - Drag-and-drop
scene.xmlto the MuJoCo viewer to load the scene
ℹ️ This section contains details about how the model was created, for reference. ℹ️
-
The robot's URDF and SRDF were obtained from the robot_properties_solo repository.
-
MuJoCo compilation directives were added to the URDF:
<mujoco> <compiler meshdir="meshes/" discardvisual="true" fusestatic="false"/> </mujoco>
These ensure MuJoCo doesn't optimize links away by assuming the base is fixed.
-
MuJoCo's
compile.ccconverted the URDF to an.xmlwhich was manually cleaned up and annotated.The compiler re-expresses link moment of inertia along the principal axes, so original values are not preserved. The two representations are equivalent.
-
SRDF
<disable_collisions>elements are manually converted to<contact>/<exclude>tags.
MuJoCo calculates collisions by replacing concave meshes with their convex hull. This means that despite the contact exclusions, the upper leg can sometimes collide with the convex hull of the body.
We therefore convex decompose the collision meshes:
-
The
.stlmeshes referenced by the URDF were converted to.obj. -
The
obj2mjcftool was ran on the meshes (source). This uses VHACD approximate convex decomposition:- For the leg meshes we used 6 convex hulls:
obj2mjcf --obj-dir .\ --save-mjcf --compile-model --verbose --vhacd-args.enable --vhacd-args.max-output-convex-hulls 6 --vhacd-args.max-hull-vert-count 256 --vhacd-args.split-hull --vhacd-args.voxel-resolution 5000000 --vhacd-args.volume-error-percent 0.1
- For the body mesh we used 12, as it's a more complicated shape:
obj2mjcf --obj-dir .\ --save-mjcf --compile-model --verbose --vhacd-args.enable --vhacd-args.max-output-convex-hulls 12 --vhacd-args.max-hull-vert-count 256 --vhacd-args.split-hull --vhacd-args.voxel-resolution 1000000 --vhacd-args.volume-error-percent 0.01 --overwrite --obj-filter "solo_12_base.obj"
Before VHACD After VHACD 

-
The robot was loaded in Solidworks and coloured according to the PLA colours I have at home 😄 (source).
-
For each collision mesh, the appropriate visual mesh was exported in
.plyformat.-
A Python script was added to import and orient
<geom>elements multiple times (generate_model.py). This is so that duplicated geometry (eg. actuator modules) is not saved and loaded from disk more than once.⚠️ MuJoCo's<include>element cannot import the same file more than once.
-
-
The
.plymeshes were converted to.objwith Meshlab.⚠️ Meshlab creates .obj meshes with materials. Other software might assign colours on each vertex which won't be processed byobj2mjcf. -
For each mesh, Solidworks was used to figure out the correct orientation and offset from the export origin. Visuals were oriented to match collision meshes using Meshlab.
-
MuJoCo doesn't support multimaterial / composite meshes. The
obj2mjcftool was run to split the meshes into groups with the same material:obj2mjcf --obj-dir ./ --save-mjcf --compile-model --verbose
-
For each submesh group, the following simplification steps were performed to reduce loading times and improve rendering performance:
- Internal geometry was removed
- Mesh decimation was performed using Meshlab's
Simplification: Quadric Edge Collapse Decimationfilter - Materials used across meshes were merged and reused
-
The hip adapter components were exported and manually added to the FR and HL legs.
-
The materials were finally roughly adjusted for reflectivity and colour.
-
The collision model
<geoms>were merged with visuals and saved in separate files. Both are imported for each link using the custom<import_with_attrs>component (seegenerate_model.py). -
A
<joint type="free">was added so the robot's base is free floating. -
Joint position actuators were added for each joint with test
Kpvalues. -
A skybox, floor and lights were added (see this scene from the MuJoCo Menagerie).
