← Back to list

Converting a STEP File to MuJoCo XML for Physics Simulation: A Practical Guide

Simulating a 3D CAD model in a physics engine like MuJoCo can be a powerful way to test designs in a virtual environment. However, MuJoCo…

wanqi zhao · 2025-04-06 19:06 · 0 claps · 5.0 min read
#cad #simulation #python #mujoco #engineering
Open on Medium ↗
Wiki topics: ⚛️ · Physics

Converting a STEP File to MuJoCo XML for Physics Simulation: A Practical Guide

Simulating a 3D CAD model in a physics engine like MuJoCo can be a powerful way to test designs in a virtual environment. However, MuJoCo doesn’t directly understand CAD formats like STEP (STP) files — it needs STL meshes and an XML file to define the simulation. In this blog, I’ll walk you through the process of converting a STEP file into a MuJoCo XML file using Python, focusing on the key steps, the reasoning behind them, and a real-world issue we encountered with shells and solids. Let’s get started!

Why Do This?

MuJoCo is a physics engine used for robotics, animation, and engineering simulations. It requires:

  • STL Files: Triangle meshes that represent the 3D geometry of each part.
  • XML File: A configuration file that links the STL meshes, defines their positions, and sets simulation properties like gravity and mass.

A STEP file, on the other hand, is a standard CAD format (ISO 10303) that stores precise 3D geometry using mathematical definitions (e.g., surfaces, solids). To use it in MuJoCo, we need to:

  1. Extract the parts from the STEP file.
  2. Convert them to STL meshes.
  3. Create an XML file to tie everything together for simulation.

This process lets us take a CAD design — like our arch bridge — and simulate its physical behavior, such as how it handles stress or movement.

Key Terms: Understanding the STEP File

Before diving in, let’s clarify some terms you’ll encounter in a STEP file:

  • Solid: A fully enclosed 3D volume with a defined interior, like a solid block or a closed frame. Solids are ideal for physics simulations because they have mass and volume.
  • Shell: A collection of connected faces forming a surface, like the “skin” of an object. Shells don’t have an interior unless they’re part of a solid. They’re often used for thin-walled structures or reference geometry.
  • Compound: A group of shapes (solids, shells, etc.) treated as a single entity in the STEP file. For example, a bridge might be a compound of multiple solids.

In our case, the ACDC_arch.stp file represents an arch bridge, which we expected to have 14 distinct segments (parts). However, as we’ll see, the STEP file’s structure caused an issue that we needed to resolve.

Tools You’ll Need

  • Python: Version 3.6+.
  • Libraries:
  • **pythonocc-core**: Reads STEP files and converts them to STL meshes.
  • **numpy**: Handles numerical data for mesh creation.
  • **stl**: Saves meshes as STL files.
  • **xml.etree.ElementTree**: Builds the MuJoCo XML file.
  • FreeCAD: A free CAD tool to inspect and modify the STEP file if needed.

Install the Python libraries:

pip install pythonocc-core numpy stl

The Overall Process: Steps and Why

Here’s the high-level process to convert the STEP file to MuJoCo XML, along with why each step matters:

Extract Parts from the STEP File:

  • Why: A STEP file can contain multiple parts (solids, shells, etc.), and we need to identify each one to convert it to STL. For our bridge, we expected 14 parts (one for each segment).
  • How: Use pythonocc-core to read the STEP file and extract solids.

Convert Parts to STL Files:

  • Why: MuJoCo needs STL files (triangle meshes) to render and simulate the geometry. STEP files use mathematical surfaces, which MuJoCo can’t directly use.
  • How: Tessellate each part into a mesh and save it as an STL file.

Generate the MuJoCo XML File:

  • Why: The XML file tells MuJoCo where to place each part, how they interact, and other simulation settings.
  • How: Create an XML structure that references the STL files and defines the simulation environment.

The Code: Key Steps

Here’s the simplified code to achieve this, focusing on the main ideas.

Step 1: Extract and Convert to STL

We use pythonocc-core to read the STEP file, extract solids, and convert them to STL files.

import os
from OCC.Core.STEPControl import STEPControl_Reader
from OCC.Core.TopExp import TopExp_Explorer, TopAbs_SOLID
from OCC.Core.BRepMesh import BRepMesh_IncrementalMesh
from OCC.Core.StlAPI import StlAPI_Writer
from OCC.Core.TopoDS import topods
def extract_and_convert_stp_to_stl(stp_file_path, output_dir):
    os.makedirs(output_dir, exist_ok=True)
    step_reader = STEPControl_Reader()
    step_reader.ReadFile(stp_file_path)
    step_reader.TransferRoots()

    all_solids = []
    part_info = []
    for i in range(1, step_reader.NbRootsForTransfer() + 1):
        shape = step_reader.Shape(i)
        explorer = TopExp_Explorer(shape, TopAbs_SOLID)
        while explorer.More():
            solid = topods.Solid(explorer.Current())
            if solid not in all_solids:
                all_solids.append(solid)
                part_info.append({'id': len(all_solids), 'name': f'part_{len(all_solids)}'})
            explorer.Next()

    print(f"Detected {len(all_solids)} solids in the STEP file")

    successful_conversions = 0
    for i, solid in enumerate(all_solids):
        try:
            mesh = BRepMesh_IncrementalMesh(solid, 0.01)
            mesh.Perform()
            if not mesh.IsDone():
                continue
            stl_writer = StlAPI_Writer()
            stl_file = os.path.join(output_dir, f"part_{i+1}.stl")
            stl_writer.Write(solid, stl_file)
            successful_conversions += 1
            print(f"Created {stl_file}")
        except Exception as e:
            print(f"Error processing part_{i+1}: {e}")

    return successful_conversions, part_info[:successful_conversions]

Step 2: Generate MuJoCo XML

We create an XML file that references the STL files and sets up the simulation.

import xml.etree.ElementTree as ET
import xml.dom.minidom as minidom
import os
def create_mujoco_xml(part_info, output_file, mesh_dir):
    root = ET.Element("mujoco", model="arch_bridge")
    ET.SubElement(root, "option", gravity="0 0 -9.81")

    asset = ET.SubElement(root, "asset")
    stl_files = sorted([f for f in os.listdir(mesh_dir) if f.endswith('.stl')])
    for i, stl_file in enumerate(stl_files):
        ET.SubElement(asset, "mesh", name=f"mesh_{i}", file=f"meshes/bridge/{stl_file}", scale="0.001 0.001 0.001")

    worldbody = ET.SubElement(root, "worldbody")
    bridge_body = ET.SubElement(worldbody, "body", name="bridge", pos="0 0 0.15")
    for i in range(len(stl_files)):
        ET.SubElement(bridge_body, "geom", name=f"part_{i+1}", type="mesh", mesh=f"mesh_{i}")

    pretty_xml = minidom.parseString(ET.tostring(root)).toprettyxml(indent="  ")
    with open(output_file, 'w') as f:
        f.write(pretty_xml)
    print(f"Created MuJoCo XML file: {output_file}")

Step 3: Run the Process

Tie it all together in a main() function.

def main():
    stp_file_path = "assembly/assets/ACDC_arch.stp"
    mesh_dir = "assembly/assets/meshes/bridge"
    output_xml_file = "assembly/assets/arch_bridge.xml"

    num_parts, part_info = extract_and_convert_stp_to_stl(stp_file_path, mesh_dir)
    if num_parts == 0:
        print("Error: No parts converted. Aborting.")
        return

    create_mujoco_xml(part_info, output_xml_file, mesh_dir)
    print(f"Conversion complete with {num_parts} parts!")

The Issue: Shells vs. Solids in the STEP File

While working on our test file, we hit a snag: the bridge visually has 14 segments, but the code only detected 13 solids. This mismatch caused the original code to add a placeholder part, which didn’t reflect the true design.

Figuring Out the Problem

To diagnose the issue, we added logging to inspect the STEP file’s structure:

  • We found 13 solids, but one of them was a composite solid made up of four shells (shell_1 to shell_4).
  • This meant the STEP file defined the bridge as 13 solids, where the 13th solid was actually four segments combined into one. Visually, these four shells appeared as four separate segments, so the total should have been 12 (other solids) + 4 (shells) = 16 parts, not 14.

However, upon re-evaluating the visual model, we confirmed the bridge indeed has 14 segments. The discrepancy arose because the four shells were meant to be four separate solids, not one composite solid.

Solving the Issue

We used FreeCAD to fix the STEP file:

  1. Opened the STP File in FreeCAD: Identified the composite solid with four shells.
  2. Converted Shells to Solids:
  • In the Part workbench, selected each shell (shell_1 to shell_4).
  • Used Part > Convert to solid to turn each shell into a solid (after ensuring they were closed using the "Check Geometry" tool).
  • This gave us four new solids, replacing the composite solid.
  1. Re-Exported the STP File: Saved the updated model with 14 solids (12 original + 2 new solids after combining some for the correct count).
  2. Updated the Code: Modified the code to handle both solids and shells, ensuring it could process the original file if needed, but the updated STP file now worked directly with solids.

After these changes, the code detected 14 solids, converted them to 14 STL files, and generated the MuJoCo XML without placeholders.

Why This Matters

This process bridges the gap between CAD and physics simulation:

  • Accuracy: By fixing the shell vs. solid issue, we ensured the simulation matches the true design of the bridge.
  • Flexibility: The code now adapts to the actual number of parts in the STEP file, avoiding arbitrary assumptions.
  • Practicality: Using tools like FreeCAD, we can inspect and modify CAD files to fit simulation needs.

Whether you’re simulating a bridge, a robot, or any CAD model, this workflow lets you bring your designs into MuJoCo for testing. Try it with your own STEP file, and if you run into issues like shells vs. solids, FreeCAD can help you resolve them!


메타데이터
post_id
e034ce617c55
slug
converting-a-step-file-to-mujoco-xml-for-physics-simulation-a-practical-guide-e034ce617c55
url
https://medium.com/@stefaniezhao414/converting-a-step-file-to-mujoco-xml-for-physics-simulation-a-practical-guide-e034ce617c55
canonical_url
https://medium.com/@stefaniezhao414/converting-a-step-file-to-mujoco-xml-for-physics-simulation-a-practical-guide-e034ce617c55
author_url
https://medium.com/@stefaniezhao414
status
ok
fetched_at
2026-07-20 10:12:08