ManipulationModule β that is the planning stack. The third lives in the ControlCoordinator and you will rarely touch it.
This layer is where your time goes. It is deliberately pluggable: the planner, the IK solver, and the collision world are all protocols you can swap β and a learned policy can replace the whole thing.
Your first plan
Start the planner and a mock arm, then drive it from Python:skip
plan β preview β execute rhythm is the whole API in miniature. Preview is cheap and execute is explicit, so you always see a motion before the robot performs it.
The API
Everything below is an RPC onManipulationModule. The building blocks:
And the one-shot skills that agents call β
move_to_pose(x, y, z), move_to_joints("0.1, -0.5, ..."), go_home(), open_gripper() β each wrap plan-and-execute into a single step.
Poses land in IK, IK lands in the planner, and the planner only ever talks to the world through WorldSpec β which is what makes the backends swappable.
Picking backends
Three independent choices, set onManipulationModuleConfig or with -o overrides:
Two rules, enforced at startup rather than at your first plan: the
roboplan planner needs the roboplan world, and drake_optimization IK needs the drake world. Everything else combines freely.
If you are not sure, the defaults are right: Drake world, RRT-Connect, Pink IK.
Plugging in your own
The three protocols live indimos/manipulation/planning/spec/protocols.py, and they are duck-typed β no base class, just the methods.
A planner is one method:
skip
solve(world, robot_id, target_pose, seed, ...) -> IKResult.
Wiring it up is a two-line change in dimos/manipulation/planning/factory.py: add your name to the PlannerName (or KinematicsName) literal, and add a branch in create_planner (or create_kinematics) that constructs your class. There is no plugin registry to learn β the factory is the registry.
Stay on WorldSpec methods inside your implementation and it will work with every world backend, current and future. RRTConnectPlanner (planning/planners/rrt_planner.py) is a readable reference β pure Python, backend-agnostic.
One naming trap: PinocchioIK exists in the kinematics folder but is not a planning backend β it is the fast in-loop IK used by the teleop and servo control tasks. You cannot select it via kinematics.backend.
Where learned policies fit
A learned policy does not extend the planner β it replaces it. Both are just producers of joint targets, and the coordinator accepts either:LeRobotPolicyModule streams joint_command at the policyβs rate into a coordinator servo task β no IK, no collision world, no planner in the loop. Which path to use is a per-task decision: structured, obstacle-aware motion suits planning; contact-rich or hard-to-model skills suit a policy trained from demonstrations.
Collecting those demonstrations and training that policy is the learning loop.