feature: model URDF <transmission> in the BB DSL#110
Open
jimsynz wants to merge 4 commits into
Open
Conversation
Adds a `transmission` block to joints in the BB DSL, mirroring URDF's `<transmission>` element for the simple 1:1 case (one joint, one actuator). The block carries `reduction` (gear ratio), `offset` (zero-point calibration in radians or metres depending on joint type), and `reversed?` (polarity). All three fields accept `param/1` references for runtime adjustment. Runtime model: `BB.Actuator.Server` (the wrapper around every actuator driver) resolves the joint's transmission at init and applies it to incoming `Command.Position`, `Command.Velocity`, `Command.Effort`, and `Command.Trajectory` messages before delegating to the user driver. User drivers operate purely in motor-space. The transmission is exposed to callbacks via `BB.Actuator.current_transmission/0` for the outbound direction (e.g. publishing joint-space JointState from motor-space hardware readings). `BB.Sim.Actuator` follows the same pipeline: receives motor-space from the wrapper, calls `BB.Transmission.unapply_position/2` to recover joint-space, then runs the existing clamp + motion-timing logic and publishes joint-space `BeginMotion` as before. Simulated motion matches real-hardware motion through the transmission. Coupled transmissions (differential, four-bar) and the top-level `transmissions` section are deliberately out of scope for this PR; the internal data model keeps the runtime as a per-joint concept so they can land as non-breaking additions later. Refs: #108
The URDF parser now captures `<transmission>` blocks (URDF-standard SimpleTransmission only — coupled types warn and skip as before) and exposes them on the parsed robot keyed by joint name. The importer emits a `transmission do reduction N end` block inside each joint with a non-1.0 mechanical reduction. The exporter emits `<transmission>` XML for joints with a non-1.0 reduction. URDF does not have a standard place for the BB-specific `offset` and `reversed?` fields, so transmissions with only those extensions are deliberately not round-tripped through URDF — that's a documented limitation rather than a bug. `BB.Urdf.Xml.element/3` now also accepts a binary text body for elements like `<type>...</type>` and `<mechanicalReduction>...</mechanicalReduction>`. Refs: #108
Provides the shared Igniter logic each driver package's upgrade task
delegates to. Given a driver module and a `lift_offset?` flag, walks
every module in the project and for each `joint :name do ... end` block:
- Finds `actuator :_, {Driver, opts}` calls (also matches the
Sourceror-wrapped form `{:__block__, _, [{Driver, opts}]}`).
- Removes the `reverse?:` key from `opts`.
- If `reverse?: true` was present, inserts a `transmission do reversed?
true end` block after the joint's `limit` block.
- With `lift_offset?: true` (Feetech and Robotis), additionally computes
`offset = (lower + upper) / 2` from the joint's literal limits and
emits it in the transmission, preserving the auto-centering the
drivers used to do internally for asymmetric joints.
Refs: #108
- Format the verifier and Igniter upgrader to satisfy mix format. - Reorder aliases in BB.Transmission.Resolver alphabetically. - Refactor BB.Urdf.Parser.parse_transmission/1 (split a cond branch out into smaller classify/build_transmission heads to drop the cyclomatic complexity below the credo threshold). - Refactor BB.Igniter.Transmission.lift_reverse_question/3 (extracted lift_in_module/4) and unit_literal/1 (collapsed the nested case statements via with) so neither nests past two levels. - Use Enum.map_join/3 in BB.Urdf.Parser.text_content/1. - Drop the unreachable format_number/1 fallback clause flagged by dialyzer. Refs: #108
This was referenced May 20, 2026
Open
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #108.
Summary
Adds a
transmissionblock to joints in the BB DSL, mirroring URDF's<transmission>element for the simple 1:1 case (one joint, oneactuator). Each transmission carries:
reduction— gear ratio (default1.0)offset— joint-space angle (or metres) corresponding to the actuator's zeroreversed?— polarity (defaultfalse)All three fields accept
param/1references for runtime adjustment.Runtime model
BB.Actuator.Server(the wrapper around every actuator driver) resolvesthe joint's transmission at init and applies it to incoming
Command.Position/Command.Velocity/Command.Effort/Command.Trajectorymessages before delegating to the user driver. Userdrivers see motor-space only.
The transmission is exposed to callbacks via
BB.Actuator.current_transmission/0for the outbound direction (driversthat publish joint-space
JointStatefrom motor-space hardware readings).BB.Sim.Actuatorruns through the same pipeline: it receives motor-spacefrom the wrapper, calls
BB.Transmission.unapply_position/2to recoverjoint-space, runs the existing clamp + motion-timing logic, and
publishes joint-space
BeginMotionexactly as before. Simulated motionmatches real-hardware motion through the transmission.
URDF
BB.Urdf.Parsercaptures<transmission>(SimpleTransmission only —coupled types warn and skip) and exposes them keyed by joint name.
BB.Urdf.Importeremits atransmission do reduction N endblockinside each joint with a non-1.0 mechanical reduction.
BB.Urdf.Exporteremits<transmission>blocks for joints with anon-1.0 reduction.
URDF doesn't have a standard place for BB-specific
offsetandreversed?, so transmissions with only those extensions don'tround-trip through URDF — documented limitation.
Out of scope
Coupled transmissions (differential, four-bar) and the top-level
transmissionssection are deliberately deferred to a follow-upissue. The internal data model is per-joint, so they can land as
non-breaking additions later.
Igniter upgrade helper
BB.Igniter.Transmission.lift_reverse_question/3is a shared upgradehelper used by the four driver packages
(bb_servo_feetech, bb_servo_robotis, bb_servo_pca9685, bb_servo_pigpio)
to lift their now-removed
reverse?opt into the joint's transmission.Companion PRs
This PR is the prerequisite; the driver PRs depend on
BB.Transmission,BB.Transmission.Resolver, and the wrapper changes here.Test plan
mix check --no-retrycleanthe math module, DSL surface, wrapper integration, sim
round-trip, URDF parser/importer/exporter, and Igniter upgrader
simulation: :kinematicmode after their respective upgrader runs