Documentation

Integrate Repose

From an empty Copper project to a moving (simulated) arm, using only library components. If you only want to run a supported robot, the template is shorter; this page is for building your own application.

1. Depend on it

Cargo.toml
[dependencies]
repose = { git = "https://github.com/ReposeRobotics/repose", tag = "v0.7.1" }
cu29 = { version = "1.3.1", features = ["units"] }
cu-spatial-payloads = "1.3.0"

Pre-1.0 there is no crates.io release, so pin a release tag. The umbrella re-exports everything (repose::kinematics, repose::motion_planning, …). Depend on single crates instead — same repo, same tag, e.g. repose-kinematics = { git = "…", tag = "v0.7.1" } — when you need only a prefix of the stack. RON type names are always the component crates' own paths, umbrella or not. Embedded target? Keep the default features off and enable std only where parsing happens (Architecture).

2. Wire the graph in RON

A complete goal → plan → time → follow → control loop needs no application code — this is the MuJoCo example's graph, trimmed to the essentials:

copperconfig.ron (abridged — full file in the example)
tasks: [
    (id: "goal", type: "repose_motion_planning::CuJointGoalTask<6>",
     config: {"goal": [{"revolute": 0.4}, {"revolute": -0.3}, {"revolute": 0.5},
                       {"revolute": 0.0}, {"revolute": 0.4}, {"revolute": 0.0}]}),
    (id: "planner", type: "repose_joint_rrt_star::CuJointRrtStarTask<6>",
     background: true, anytime: (time_budget_ms: 250.0, quality_target: 0.95),
     resources: {"rng": "planner_rng.rng"},
     config: {"chain": "igus_rebel", "collision_model": "igus_rebel",
              "base_budget": 256, "refine_budget": 64}),
    (id: "timing", type: "repose_motion_planning::CuPlanToTrajectoryTask<6, 1024>",
     config: {"profile": "cubic", "sample_period": 0.02, "limits": { ... }}),
    (id: "follower", type: "repose_trajectory::CuFollowTrajectoryTask<6, 1024>"),
    (id: "controller", type: "repose_controller::CuControllerTask<6>",
     config: {"tracking_error_limit": 0.5, "state_timeout": 0.2,
              "rate_limit": {"max_speed": 1.5, "max_acceleration": 6.0}}),
],
resources: [(id: "planner_rng", provider: "cu_rng::CuRngBundle", config: {"seed": 42})]

Connect them with cnx entries matching payload types (CuJointStatePayload<6> → CuJointPlanRequest<6> → CuJointPlanPath<6> → CuTrajectoryPayload<6, 1024> → CuTrajectoryFollowOutput<6> → CuJointCommandPayload<6>), and attach a bridge — MuJoCo, igus or UR — by its standard channels. Joint values in RON are typed: {"revolute": 0.4} radians, {"prismatic": 0.1} metres.

3. Bring your own robot

  1. Model it. Import URDF/SRDF at startup (Robot description) and pass chain()/the collision model via from_params, or write "chain"/"collision_model" inline in RON (preset name, or a spec with exactly N joints / its shapes + safety_margin). N must match every task's type parameter.
  2. Check capacities. Shape capacity M, trajectory MAX_POINTS, planner node caps and scene capacities are compile-time. Size them for your robot and paths; exhaustion is a reported status, not a panic — but it does fail the job.
  3. Feed it state. Any bridge implementing the standard channels works; for a new device, write that bridge, not application glue.

4. Extend it

Custom goal sourcePublish CuJointPlanRequest<N> from your own task (perception, UI, sequencer) and drop CuJointGoalTask.
Custom plannerImplement CuJointPlanner, register one line in repose::planners (Motion planning).
Custom sequencingDrive the library directly, like the template's runner: pre-flight every step with IK + collision checks, plan, parameterize, then stream — refusing to start if any step fails.
No Copper graphCall the libraries in your own loop: forward_kinematics/inverse_kinematics_dls, check_configuration, a planner's begin/step/write_best, parameterize, payload.sample(..). Same code the tasks wrap.