Generate the printed parts that hold a robot together.
Robotics prototyping is the same problem over and over: connect interface A to interface B. A depth camera onto an extrusion. A servo horn onto a wrist. A finger onto a gripper jaw. A sensor bracket onto an arm. Each time you redraw the same bolt pattern, guess the same clearances, and find out whether you got it right only after a print.
roboparts makes that a composition problem instead of a modeling problem. You describe the two things being joined; it generates the part between them, and tells you how much to trust the result before you spend an hour printing it.
roboparts generate extrusion.hfs6_3030.end mount.pantilt_stack --style socket -o adapterAn Interface is a mating surface whose geometry you do not control — a camera's bolt pattern, an extrusion's T-slot, a robot's tool flange. Each entry bundles:
- a frame — origin on the mating datum, +Z the outward normal, +X a keying direction;
- the features it stamps into whatever mates with it — holes, insert bores, patterns;
- an envelope — the keepout volume of the mating part;
- provenance — where the numbers came from, and how far to trust them.
Two consequences fall out of that, and they are the whole point of the project.
Every dimension records its source, ranked worst to best: unverified, estimated,
measured_mesh, measured_physical, datasheet, vendor_cad, fit_confirmed,
standard. The generator then absorbs its own uncertainty in geometry rather than
pretending it knows. Numbers scraped off a photo get slotted, oversized holes and a
suggestion to print a test coupon. Numbers from vendor CAD get a tight fit and dowel
pins.
fit_confirmed outranks both datasheet and vendor_cad, which is deliberate. A
datasheet gives you nominal design intent and calipers read a single sample; both are
proxies for the only question that matters, which is whether the parts actually go
together. A printed part that assembled answers it directly, so its numbers are used
exactly as they are and the tool stays quiet about them.
A part derived from a bad measurement still bolts up, because the tool knew it was guessing. Conversely, weak provenance on a tapped hole or an insert bore cannot be absorbed — you cannot slot either — so roboparts warns instead of quietly generating something that will not fit.
The same interface frame that positions a mount is the joint origin a URDF or MJCF export needs, so CAD and simulation stay consistent by construction rather than by being hand-reconciled.
Early. The interface schema, feature geometry, YAML registry, adapter generation, and validation checks work and are tested.
The validation target is a four-part active pan-tilt head — HFS6-3030 extrusion,
Feetech ST3215 servo, Arducam B0560 camera — that was originally written by hand in
build123d and physically printed and fitted. Its sources are kept in
Camera Mount Alu/ as reference.
Regenerating its post_adapter from the registry alone matches the hand-built solid to
0.0006% by volume, with an identical bounding box. The only residual is a five-micron
boolean epsilon in the original source.
That comparison earns its keep: it immediately caught a real bug, where provenance slop was widening a lone M8 bore that had no pattern-position error to absorb.
Clone and install into a virtualenv. Requires Python 3.11+; the OCP wheels that build123d pulls in are the fragile part, so verify before building anything:
git clone <this repo>
cd roboparts
py -3.12 -m venv .venv # Windows; use python3 -m venv on Linux/macOS
.venv/Scripts/python -m pip install -e ".[dev]"
.venv/Scripts/python -m pytesttests/test_cad_stack.py checks what later work depends on — B-rep booleans, STEP
round-trip, tessellation, and the inertia tensor via OCP. If those pass, the stack is
sound.
roboparts list # every interface, its provenance tier, and the fit it gets
roboparts list --kind camera # filter by kind
roboparts generate A B --style plate|socket -o outroboparts list marks entries nobody has confirmed with ! and tells you what to do
about each one.
roboparts/src/roboparts/
├─ interfaces/ schema, feature vocabulary, YAML registry
│ └─ data/ footprint entries: extrusion, servo, camera, fastener, mount
├─ adapters/ plate and socket bodies, plus validation checks
└─ cli.py
Camera Mount Alu/ hand-built pan-tilt head, kept as the validation reference
Footprint data is YAML, not Python, so adding a camera is a short reviewable diff with no code execution. Only genuinely parametric families need code.
roboparts deliberately does not try to be a CAD engine or a text-to-CAD generator. It composes known interfaces; these solve adjacent problems well:
- earthtojake/text-to-cad — agent skills for STEP-first parametric CAD, DXF, URDF/SRDF/SDF, slicing, and a local viewer.
- neka-nat/freecad-mcp — MCP server driving a
live FreeCAD session over XML-RPC. Useful as an escape hatch for vendor
.FCStdfiles with the feature tree intact, messy STEP repair, and CalculiX FEM. - Pan-Chera/Multi-Agent-CAD —
token-efficient text→STEP via a LangGraph pipeline. Its
_safe_filletidea (back the radius off when OpenCascade refuses) is used here.
Hardware references: TheRobotStudio/SO-ARM100 (Apache-2.0) and enactic/openarm_hardware (CERN-OHL-2-S — note the reciprocal terms). roboparts stores dimensional facts, never vendored geometry, which keeps the registry clean of both licences' obligations.
MIT.