Problem
bb already exports BB robot definitions to URDF (BB.Urdf.Exporter / mix bb.to_urdf) for use with ROS tools like RViz and Gazebo. The reverse — taking an existing URDF file and producing an equivalent BB DSL module — would be a much bigger lever for adoption. Most off-the-shelf robot arms (Universal Robots, Franka, WidowX, SO-101, etc.) ship URDFs from the manufacturer or community, and porting them to BB by hand is tedious and error-prone.
Proposal
Add a mix bb.from_urdf Igniter task that reads a URDF XML file and writes a defmodule MyRobot do ... use BB ... end module to lib/.
# Generate lib/my_app/robot.ex from a URDF
mix bb.from_urdf path/to/robot.urdf --module MyApp.Robot
# With explicit output path
mix bb.from_urdf path/to/robot.urdf --module MyApp.Robot --output lib/my_app/robot.ex
The generator should:
- Walk the URDF
<link> and <joint> graph and emit nested link/joint blocks in topology order.
- Convert URDF values (which are SI base units already — metres, radians, kg) into
~u(...) sigil literals for clarity.
- Emit
visual/collision/inertial/origin/axis/limit/dynamics blocks, mapping URDF's <box>/<cylinder>/<sphere>/<mesh> geometries to bb's box/cylinder/sphere/mesh DSL entities.
- Set the robot's
name setting from the URDF <robot name="..."> attribute.
- Default any optional fields bb expects but URDF doesn't provide.
Runtime parsing (loading URDF into a BB.Robot struct on the fly without code generation) is explicitly not in scope — bb is built around compile-time DSL processing, and generating source code keeps the resulting robot first-class with everything else (Spark transformers, supervision tree, etc.).
Things URDF has that BB doesn't (or treats differently)
These need either a translation, a warning-and-skip, or a documented limitation:
| URDF feature |
Notes |
<joint type="floating">/"planar" |
bb has both, should map directly |
<joint type="fixed"> |
bb has fixed, direct map |
<mimic> |
URDF allows a joint to mirror another; bb has no equivalent. Warn and skip, point to the proposals repo. |
<safety_controller> |
URDF position/velocity safety limits; could map to bb's limit block but the semantics differ. Probably skip with a notice. |
<transmission> |
Maps a joint to an actuator with a transmission ratio. bb doesn't model transmissions explicitly; skip with a notice that the user will need to define the actuator manually. |
<gazebo> extensions |
Simulator-specific. Skip. |
<material> definitions outside <visual> |
URDF allows top-level material defs that visuals reference by name. Resolve them at parse time and inline into each visual's material block. |
<mesh filename="..."> |
URDF mesh paths use package:// URIs from ROS. The importer can either copy the mesh files into the project's priv/ and rewrite paths, or emit the path as-is with a notice. Probably the latter as v1 — file management is a separate concern. |
Implementation notes
- Parse XML with
:xmerl_scan from stdlib (no extra dep needed) or SweetXml if we want better ergonomics.
- The generator should use Sourceror to emit formatted Elixir source, not string templating.
- Handle the topology by building an in-memory link→joint→link adjacency map first, then emitting nested blocks starting from the root link (the one that's never a child of any joint).
- Unit handling: URDF values are floats in SI base. Emit them via
~u(<n> meter) / ~u(<n> radian) etc. The choice of unit literal is purely cosmetic — bb's DSL accepts any compatible unit and converts to SI internally anyway, but ~u(0.1 meter) reads better in source than the equivalent float.
Open questions
mesh resolution. Do we copy mesh files into the project (and rewrite filename to a relative path), leave them where they are (referenced via absolute path), or just emit a comment and require the user to handle them? Leaning toward the comment-and-require-manual-step for v1.
- Round-trip fidelity. Should
mix bb.from_urdf foo.urdf then mix bb.to_urdf MyRobot produce a URDF equivalent to the input? Probably approximately yes, but lossless round-trip is hard because bb normalises some things (e.g. axis orientations) at compile time.
- Validation. Should the importer reject URDFs that contain features bb doesn't support, or always emit something and warn? Probably the latter — fail-soft for adoption.
- The example robots. Could we use this importer to regenerate
bb_example_wx200's robot definition from a vendor URDF, as a smoke test and demo of the workflow?
Related
- Existing exporter:
lib/bb/urdf/exporter.ex, BB.Urdf.Xml helpers
- DSL reference:
documentation/dsls/DSL-BB.md
- Tutorial:
documentation/tutorials/06-urdf-export.md — the export tutorial; an 07-urdf-import.md would be a natural pair
Problem
bb already exports BB robot definitions to URDF (
BB.Urdf.Exporter/mix bb.to_urdf) for use with ROS tools like RViz and Gazebo. The reverse — taking an existing URDF file and producing an equivalent BB DSL module — would be a much bigger lever for adoption. Most off-the-shelf robot arms (Universal Robots, Franka, WidowX, SO-101, etc.) ship URDFs from the manufacturer or community, and porting them to BB by hand is tedious and error-prone.Proposal
Add a
mix bb.from_urdfIgniter task that reads a URDF XML file and writes adefmodule MyRobot do ... use BB ... endmodule tolib/.The generator should:
<link>and<joint>graph and emit nestedlink/jointblocks in topology order.~u(...)sigil literals for clarity.visual/collision/inertial/origin/axis/limit/dynamicsblocks, mapping URDF's<box>/<cylinder>/<sphere>/<mesh>geometries to bb'sbox/cylinder/sphere/meshDSL entities.namesetting from the URDF<robot name="...">attribute.Runtime parsing (loading URDF into a
BB.Robotstruct on the fly without code generation) is explicitly not in scope — bb is built around compile-time DSL processing, and generating source code keeps the resulting robot first-class with everything else (Spark transformers, supervision tree, etc.).Things URDF has that BB doesn't (or treats differently)
These need either a translation, a warning-and-skip, or a documented limitation:
<joint type="floating">/"planar"<joint type="fixed">fixed, direct map<mimic><safety_controller>limitblock but the semantics differ. Probably skip with a notice.<transmission><gazebo>extensions<material>definitions outside<visual>visual'smaterialblock.<mesh filename="...">package://URIs from ROS. The importer can either copy the mesh files into the project'spriv/and rewrite paths, or emit the path as-is with a notice. Probably the latter as v1 — file management is a separate concern.Implementation notes
:xmerl_scanfrom stdlib (no extra dep needed) orSweetXmlif we want better ergonomics.~u(<n> meter)/~u(<n> radian)etc. The choice of unit literal is purely cosmetic — bb's DSL accepts any compatible unit and converts to SI internally anyway, but~u(0.1 meter)reads better in source than the equivalent float.Open questions
meshresolution. Do we copy mesh files into the project (and rewritefilenameto a relative path), leave them where they are (referenced via absolute path), or just emit a comment and require the user to handle them? Leaning toward the comment-and-require-manual-step for v1.mix bb.from_urdf foo.urdfthenmix bb.to_urdf MyRobotproduce a URDF equivalent to the input? Probably approximately yes, but lossless round-trip is hard because bb normalises some things (e.g. axis orientations) at compile time.bb_example_wx200's robot definition from a vendor URDF, as a smoke test and demo of the workflow?Related
lib/bb/urdf/exporter.ex,BB.Urdf.Xmlhelpersdocumentation/dsls/DSL-BB.mddocumentation/tutorials/06-urdf-export.md— the export tutorial; an07-urdf-import.mdwould be a natural pair