Debug a motion plan
When a motion plan fails with a collision error, or the arm ends up somewhere unexpected, the first question is the same: is the frame system wrong, or is the plan wrong? You can answer it two ways. If your machine has the 3D SCENE tab, inspect the world the planner sees by eye. From any shell, the Viam CLI reports the same frame poses and tests reachability. This page covers both.
To render the plan’s trajectory itself, the path the arm takes from start to goal, see Visualize a motion plan.
Prerequisites
- A machine with an arm or gantry configured and at least one frame defined.
- A motion plan that is failing or producing unexpected results.
- For the CLI checks: the Viam CLI installed and authenticated, and the
--partidentifier for the machine part you want to inspect.
In the 3D scene
Open the 3D SCENE tab on your machine’s page in the Viam app. It loads your frame system configuration and, when the machine is online, connects for live pose data. Work through the checks below; most planning failures show up in one of them.
Check frame positions
In the World panel in the upper-left, expand the tree and click each component in turn. The Details panel on the right shows the selected entity’s world position and world orientation, plus editable local position and local orientation relative to the parent frame. Compare these values to your physical measurements.
Three common mismatches to look for:
- Wrong location: translation values in the frame configuration do not match the physical setup. Compare local position (mm) to your physical measurements.
- Wrong orientation: the arm base is rotated 90 degrees, or a camera points the wrong direction. Check local orientation in the Details panel.
- Wrong parent: the component is attached to the wrong parent, which places it in an unexpected part of the scene. Check the parent frame field in the Details panel.
Check obstacle geometry
Obstacles appear as translucent shapes in the scene and as child rows under their parent frame in the World panel. Select each obstacle from the tree to see its geometry type and dimensions in the Details panel.
Verify that:
- Every physical obstacle in your workspace has a corresponding geometry in the scene.
- Each geometry covers the actual physical object. If a box geometry is too small, the planner will find paths that clip the real obstacle.
- Geometries are positioned correctly. A table surface defined at
z: 0when the arm base is atz: 500will not protect against table collisions.
If obstacles are missing or misplaced, see Verify obstacles.
Look for impossible targets
If the motion plan target is outside the arm’s reach or inside an obstacle, the planner cannot find a path.
In the World panel, expand the arm and select its tip link or the gripper frame (whichever is configured as the motion target). Read the world position and compare it to the target pose your code commanded. Then place the target: is it inside an obstacle geometry? Is it further than the arm can reach from its base?
If the target is inside an obstacle geometry, either move the target or adjust the obstacle definition.
Check for self-collision geometry
Some arm models include collision geometry for each link. If a motion plan fails with a self-collision error, inspect the arm’s link geometries for overlap in the current configuration.
If the arm renders without collision geometry, the feature may be disabled: open Settings → Scene → Arm Models and verify that the rendering mode includes colliders.
Self-collisions can happen when wrist joints are commanded to positions that bring adjacent
links too close together. If the overlap is a modeling artifact rather than a real collision,
allow the frame pair with
CollisionSpecification.
With the CLI
When the 3D scene tab is not available, or you want to script the checks, the Viam CLI
reports the same information from the shell. Three commands cover most cases: print-config
dumps the configured frame tree, print-status prints every frame’s current world-frame
pose, and set-pose drives a component to a pose to test reachability. For the full flag
reference, see Motion CLI commands.
Frames are in the wrong place
The arm reports reaching x=300, y=200 but physically sits elsewhere, or the
scene shows the gripper off to the side of the arm. Both symptoms point to a frame
configuration that disagrees with the physical setup. Dump the configured frame tree:
viam machines part motion print-config --part "my-machine-main"
Each frame part shows its name, parent, translation, and orientation. Compare against your JSON configuration and physical measurements. Common issues: a wrong parent (a component parented to the world frame instead of the arm, or vice versa), wrong units (centimeters instead of millimeters), or a missing frame (a component with no entry, usually because its frame configuration did not save).
Then check the live world-frame poses:
viam machines part motion print-status --part "my-machine-main"
print-status prints one line per frame part with its computed world-frame pose:
my-arm : X: 0.00 Y: 0.00 Z: 0.00 OX: 0.00 OY: 0.00 OZ: 1.00 Theta: 0.00
my-gripper : X: 0.00 Y: 0.00 Z: 110.00 OX: 0.00 OY: 0.00 OZ: 1.00 Theta: 90.00
A pose that does not match where the component physically sits means the frame configuration is wrong. Edit the configuration in the Viam app, then run both commands again to confirm the change took effect.
Some frames are not linked to the world frame
The motion service refuses to plan when a frame in your configuration does not connect to the
world frame through its parent chain, and the error lists the unlinked parts. Renaming a
component without updating the parent field on the components attached to it is the usual
cause. Dump the frame tree to see each part’s declared parent:
viam machines part motion print-config --part "my-machine-main"
Look for parts whose parent names do not match any other part in the output. A typo, a stale
reference to a deleted or renamed component, or a circular reference all produce this error.
In the Viam app, open the CONFIGURE tab, find each unlinked
component’s Frame configuration, and correct the parent field so that it references an
existing component or world. Save the configuration, then run print-config again and
confirm that every part traces back to the world frame before you retry the motion call.
Find where one component is
To read a single component’s pose without the rest of the frame tree:
viam machines part motion get-pose \
--part "my-machine-main" \
--component "my-arm"
The output is the same single-line format as print-status, limited to the component. This
is useful for scripting: log it, compare between runs, or read the arm’s position before and
after a physical move to check it matches what the arm reports.
Check whether a target pose is reachable
Drive toward the target in small steps to find where planning fails. First read the current
pose with get-pose, then move a small distance:
viam machines part motion set-pose \
--part "my-machine-main" \
--component "my-arm" \
--x 100
set-pose overrides only the fields you pass, so this moves the arm to X=100 while keeping
the current Y, Z, and orientation. If this small step fails, the planner cannot reach any pose
near the current position, which usually means a configuration error rather than a
target-reachability issue. If it succeeds, increase the delta and work toward the pose you
want. The last successful pose and the first failing pose bracket the problem. If set-pose
fails at a pose that should be reachable, return to print-config and print-status: frame
configuration errors often show up as unexpected unreachability.
The arm moved to the wrong place after a motion call
Your code called motion.Move or arm.MoveToPosition and the arm ended up somewhere other
than the commanded pose. Immediately after the motion, capture the actual final pose with
get-pose and compare it to the pose you commanded. Differences beyond the arm’s positioning
tolerance suggest a frame configuration mismatch or a kinematics calibration problem.
If print-status shows the arm where it physically is but that does not match the pose you
commanded, the pose may have been interpreted in an unexpected reference frame. Check the
reference_frame on the target PoseInFrame: the same (x, y, z) in the arm’s frame and in
the world frame describes two different places.
The CLI commands print-status, get-pose, and set-pose call the motion service’s
GetPose, which is deprecated in favor of the frame system service’s GetPose; the
commands and their output format are stable.
set-pose calls the motion service’s Move and blocks until the motion finishes or fails,
returning a non-zero exit status with the error message on failure.
Common causes of motion plan failures
| Symptom | Likely cause | What to check |
|---|---|---|
| “no valid path found” | Target unreachable or blocked by obstacles | Is the target inside an obstacle? Is it within the arm’s reach? |
| Collision error | Obstacle geometry intersects the planned path | Are obstacles positioned correctly? Are they the right size? |
| Path goes through the table | Table obstacle missing or too small | Is there a geometry covering the table surface? Does it extend far enough? |
| Arm takes an unexpected route | Obstacles force the planner to go around | Are there obstacles you did not intend to add? Is geometry oversized? |
| Self-collision error | Arm links collide with each other | Do link geometries overlap in the failing configuration? |
What’s next
- Visualize a motion plan: render the plan’s trajectory and goals as custom visuals when a visual check is not enough.
- Verify obstacles: check obstacle geometry against the real workspace.
- Motion CLI commands: the full flag reference for the motion commands.
- How motion planning works: why a plan can be infeasible and what to adjust.
Was this page helpful?
Glad to hear it! If you have any other feedback please let us know:
We're sorry about that. To help us improve, please tell us what we can do better:
Thank you!