Problem / motivation
We build one MotionPlanner for a multi-arm robot and dispatch per-arm goals at call time via goal_tool_poses. Arms without a goal are held by the planner's optimizer, not hard-locked, so trajopt frequently routes them through significant joint-space detours.
We want to hard-lock an arbitrary subset of joints at their current values per plan call, then unlock them on the next call where we plan all arms together. Today this means changing the lock_joints set, which is baked into the kinematics tensor shapes at MotionPlanner construction. Kinematics.update_kinematics_config is shape-preserving and refuses any change to the set. Rebuilding the planner per call costs many seconds (kinematics rebuild plus CUDA graph re-capture plus warmup), so it is not practical for interactive use.
Proposed solution
Per-call `lock_joints` override on `MotionPlanner.plan_pose` and `MotionPlanner.plan_cspace` that hard-locks a chosen subset of joints at supplied values for that one call, with no rebuild and no CUDA graph re-capture:
mp = MotionPlanner(MotionPlannerCfg.create(...))
# Plan only arm A. Hard-lock arm B's joints at their current values.
mp.plan_pose(
goal_tool_poses={"arm_a_tool": target_a},
current_state=full_js,
lock_joints_override={"arm_b_j1": q1, "arm_b_j2": q2, ...},
)
# Same planner. Plan both arms. Override is per-call only.
mp.plan_pose(
goal_tool_poses={"arm_a_tool": target_a, "arm_b_tool": target_b},
current_state=full_js,
)
The override should accept an arbitrary subset of joints by name and should not assume the arms share structure or DOF count.
Alternatives considered
- Custom cspace cost penalizing motion of the joints we want held: weight tuning is brittle and a soft cost is not equivalent to a hard lock. Requires tuning.
- Pre-built planner pool, one planner per lock-set permutation: workable but each planner pays its own compilation cost at startup and again whenever the scene changes enough to force a recompile, GPU memory scales with the pool size, and the number of subsets grows quickly with the number of arms.
- Rebuild the
MotionPlanner on every switch: latency is too high for an interactive UI.
- Goal-hold the idle arm by passing its current FK as a target: still a soft objective; we have observed idle-joint drifts from a few degrees up to a full revolution.
- Post-check that rejects plans whose idle joints drifted: catches the symptom, does not prevent it, and wastes the plan compute.
Additional context
cuRobo version: 0.8.0.
Problem / motivation
We build one
MotionPlannerfor a multi-arm robot and dispatch per-arm goals at call time viagoal_tool_poses. Arms without a goal are held by the planner's optimizer, not hard-locked, so trajopt frequently routes them through significant joint-space detours.We want to hard-lock an arbitrary subset of joints at their current values per plan call, then unlock them on the next call where we plan all arms together. Today this means changing the
lock_jointsset, which is baked into the kinematics tensor shapes atMotionPlannerconstruction.Kinematics.update_kinematics_configis shape-preserving and refuses any change to the set. Rebuilding the planner per call costs many seconds (kinematics rebuild plus CUDA graph re-capture plus warmup), so it is not practical for interactive use.Proposed solution
Alternatives considered
MotionPlanneron every switch: latency is too high for an interactive UI.Additional context
cuRobo version: 0.8.0.