Why we're building Repose
Robot arms need software that behaves the same way every time. Repose is a manipulation stack for Copper built around that idea: fixed sizes, no allocation while moving, and runs you can replay exactly.
Today we want to explain what Repose is and why we're building it. Repose is a manipulation stack for robot arms: kinematics, collision checking, motion planning, trajectory timing and control. It is written in Rust as components for Copper, a deterministic robotics runtime, and its goal is to be comparable in scope to MoveIt, without being a port of it.
The short version: we want robot arm software that never surprises you. The same inputs should produce the same motion, every time, and when something does go wrong you should be able to replay exactly what happened.
The problem
Planning motion for a robot arm is a solved problem in the textbook sense. There are good algorithms for inverse kinematics, for finding collision-free paths and for turning a path into a smooth trajectory. The hard part is everything around them.
A typical stack grows memory at runtime, so timing depends on what the allocator is doing. Sampling planners draw random numbers, so the same request can produce a different path on the next run. Components talk over loosely typed messages, so a joint angle in degrees can end up where radians were expected. And when an arm does something unexpected, reproducing it often means trying to recreate the conditions by hand.
None of these are bugs on their own. Together they make a system that is hard to trust and hard to debug, which is the last thing you want from software that moves a physical machine.
The idea
Repose takes a different starting point: build manipulation natively on a runtime that is already deterministic, and keep every component inside those rules.
- Fixed sizes. The joint count and every capacity are compile-time constants. A 6-axis arm is a
CuKinematicChain<6>, and a trajectory holds a fixed number of points. Memory use is known before the program runs. - No allocation while moving. Hot-path functions write into buffers you own instead of returning new data. Forward kinematics, inverse kinematics and collision checks allocate nothing, so they are safe inside a real-time loop.
no_stdfirst. The runtime crates build without Rust's standard library, so the same code can run on a workstation or on an embedded controller. Parsing a URDF needs the standard library and happens once, at startup.- Units in the type system. Angles, lengths and velocities are typed SI quantities. A prismatic joint can't be handed radians, and a speed limit can't be confused with an acceleration.
- Configured, not coded. An application is a Copper task graph in RON. You choose the robot model, the planner and the motion limits in configuration and name library tasks directly, rather than wrapping them in glue code.
Replay, concretely
Determinism is easy to claim, so here is what it means in practice.
Every sampling planner in Repose takes its randomness from a seeded generator, CuRng. The seed is part of the planning job. Copper, in turn, logs every message that passes between tasks: the measured joint states, the plan request, the planner's output, the trajectory and the commands sent to the robot.
Put those together and a run becomes a recording. If a planner produced a strange path, you don't have to guess which random draws led there. You replay the log, the planner receives the same request with the same seed, and it produces the same path, step for step. You can then change one thing, such as the planner's budget or the collision margin, and see exactly what that changes.
What exists today
Repose is pre-1.0, but the core of the stack is in place:
- Kinematics. Serial chains with forward kinematics, space and body Jacobians, damped least-squares inverse kinematics, and differential IK with singularity and joint-limit damping.
- Collision checking. Fixed-capacity sphere and capsule models with exact signed distances, planning scenes, and self-collision checks.
- Robot descriptions. URDF and SRDF import into fixed-size kinematic and collision models.
- Motion planning. One planner contract,
CuJointPlanner, and one anytime Copper task that runs any planner. Seven planners implement it: RRT*, RRT-Connect, PRM, A* on a joint lattice, STOMP, a gradient path optimizer, and a direct joint line. - Trajectories and control. Trajectory timing within joint limits, Cartesian blending zones, a trajectory follower, and a joint controller with a watchdog and command rate limiting.
- Simulation. A MuJoCo bridge and an example that runs goal → plan → time → follow → control entirely from a RON config.
Every failure is explicit. A planner that can't find a path publishes a status such as invalid_start or exhausted instead of silently producing nothing, and inverse kinematics reports whether it converged and how close it got.
What Repose is not
Being clear about scope matters as much as the features.
- Not a ROS package. Repose has no ROS nodes, messages or MoveIt plugin compatibility. It does read URDF and SRDF files, because those are file formats, not a runtime dependency.
- Not a perception stack. It doesn't do point clouds, object detection or grasp synthesis. Perception can publish into the planning scene; building it is a different project.
- Not general yet. Today Repose handles serial chains: one base, one tool. Branched and closed-chain mechanisms come later, deliberately, once the serial case is solid.
Where it's going
The roadmap runs from here to real hardware. Next are a versioned planning scene and pose-goal planning, then a production servo loop with collision monitoring during execution, then robot bridges, starting with the igus ReBeL over its CRI interface. Version 1.0 comes when the planning, servo and robot-bridge APIs are stable, and that is also when the crates are published to crates.io.
Until then, every release is tagged, every change is recorded in the changelog, and the versioning policy spells out exactly what a release may change.
Try it
The getting started guide walks through installing Repose and running a first program. The code is on GitHub, and issues and questions are welcome there.