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 --part identifier 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: 0 when the arm base is at z: 500 will 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

SymptomLikely causeWhat to check
“no valid path found”Target unreachable or blocked by obstaclesIs the target inside an obstacle? Is it within the arm’s reach?
Collision errorObstacle geometry intersects the planned pathAre obstacles positioned correctly? Are they the right size?
Path goes through the tableTable obstacle missing or too smallIs there a geometry covering the table surface? Does it extend far enough?
Arm takes an unexpected routeObstacles force the planner to go aroundAre there obstacles you did not intend to add? Is geometry oversized?
Self-collision errorArm links collide with each otherDo link geometries overlap in the failing configuration?

What’s next