Motion planning · repose-motion-planning

The planner task

Every planner runs inside one generic Copper task, CuJointPlannerTask<P, N, M>. It owns everything planners would otherwise each reimplement: config, budgets, seeding, publishing, and state for replay.

Anytime planning

The task is a Copper anytime task. It can do a little work per cycle, publish a usable answer early and improve it while time allows:

  1. base() runs when a new request arrives: start a job with a fresh seed, then spend base_budget work units.
  2. refine() runs on later cycles and spends refine_budget more each time, until the job is final or Copper's anytime budget stops it.
  3. Publishing: the output changes only when the path cost strictly improves, so downstream tasks see each better path exactly once. A final failure is published too.

In RON, background: true runs the planner off the main loop, and anytime: sets the time budget and the quality at which to stop early:

ron
(
    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",
        "params": {"step_size": 0.3, "max_nodes": 200},
        "base_budget": 256,
        "refine_budget": 64,
    },
),

Config: CuJointPlannerParams

chain (required)Preset or inline chain.
collision_model (required)Preset or inline collision model.
paramsThe planner's own parameters. Omit for defaults. See Choosing a planner.
base_budget, refine_budgetWork units per base() and refine(). Default 64 and 32 unless the planner sets its own. Must be positive.

Quality

Quality is straight-line cost divided by path cost, from 0 to 1. A path of quality 1 is the straight joint line; 0.95 means at most about 5 % longer. quality_target in the anytime config uses this number.

Seeds and replay

Sampling planners draw randomness only from the job seed. The task takes a base seed once from its rng resource (a cu_rng::CuRngBundle with a fixed seed) and derives each job's seed from it and a job counter. The base seed and counter are frozen into Copper's log, so replaying a .copper log reproduces every plan exactly.

ron
resources: [
    (id: "planner_rng", provider: "cu_rng::CuRngBundle", config: {"seed": 42}),
],

Task aliases

repose_motion_planning::CuJointRrtConnectTask<N>RRT-Connect
repose_joint_rrt_star::CuJointRrtStarTask<N>RRT*
repose_motion_planning::CuJointPrmTask<N>PRM
repose_motion_planning::CuJointAStarTask<N>A*
repose_motion_planning::CuJointStompTask<N>STOMP
repose_motion_planning::CuJointPathOptimizerTask<N>Path optimizer
repose_motion_planning::CuJointDirectTask<N>Direct

Add M for robots with more collision shapes than joints: CuJointPrmTask<6, 12>.

Choosing the planner by name

The umbrella crate's CuAnyPlanner<N> dispatches to any planner chosen in config, which is how the robot-app template's "planner": "rrt_connect" works. Run it as CuJointPlannerTask<CuAnyPlanner<N>, N> with "params": "rrt_star" (or any name from CuPlannerChoice::ALL). Each planner then uses its default parameters.

Inspecting progress

task.status() and task.debug_state() (status, effort, published cost and quality) are available in Rust and through Copper's debug-state registry for remote inspection.

API reference