Move an arm with motion constraints | Move an arm
Move an arm with motion constraints
Welding requires the torch to follow a straight line. Carrying a cup of water requires the end effector to stay level. The motion planner’s default behavior satisfies neither: it finds any collision-free path, which typically curves through intermediate poses and tilts the end effector along the way. Constraints let you bound what the planner will accept.
Prerequisites
- A running machine with an arm and frame system configured
- Familiarity with Move arm to pose
Steps
1. Welding: straight-line tool path
Use a LinearConstraint to keep the end effector within a tolerance of the direct line between start and goal.
from viam.services.motion import MotionClient
from viam.proto.service.motion import Constraints, LinearConstraint
from viam.proto.common import PoseInFrame, Pose
motion_service = MotionClient.from_robot(machine, "builtin")
constraints = Constraints(
linear_constraint=[
LinearConstraint(line_tolerance_mm=5.0)
]
)
destination = PoseInFrame(
reference_frame="world",
pose=Pose(x=400, y=200, z=300, o_x=0, o_y=0, o_z=-1, theta=0)
)
await motion_service.move(
component_name="my-arm",
destination=destination,
constraints=constraints
)
import "go.viam.com/rdk/motionplan"
constraints := &motionplan.Constraints{
LinearConstraint: []motionplan.LinearConstraint{
{LineToleranceMm: 5.0},
},
}
_, err = motionService.Move(ctx, motion.MoveReq{
ComponentName: "my-arm",
Destination: destination,
Constraints: constraints,
})
2. Carrying a liquid: level end effector
Use an OrientationConstraint to keep the end effector level (or at any fixed orientation) throughout the motion.
from viam.proto.service.motion import OrientationConstraint
constraints = Constraints(
orientation_constraint=[
OrientationConstraint(orientation_tolerance_degs=5.0)
]
)
await motion_service.move(
component_name="my-arm",
destination=destination,
constraints=constraints
)
constraints := &motionplan.Constraints{
OrientationConstraint: []motionplan.OrientationConstraint{
{OrientationToleranceDegs: 5.0},
},
}
3. Combine constraints
Linear and orientation constraints compose: pass both in the same Constraints object and the planner enforces both simultaneously. This is the usual setup for welding and other tasks that require a straight-line path plus a fixed tool orientation.
# Straight line, level orientation
constraints = Constraints(
linear_constraint=[
LinearConstraint(line_tolerance_mm=5.0)
],
orientation_constraint=[
OrientationConstraint(orientation_tolerance_degs=3.0)
]
)
constraints := &motionplan.Constraints{
LinearConstraint: []motionplan.LinearConstraint{
{LineToleranceMm: 5.0},
},
OrientationConstraint: []motionplan.OrientationConstraint{
{OrientationToleranceDegs: 3.0},
},
}
4. Use proportional tolerances
PseudolinearConstraint scales the tolerance with the motion distance. Useful when the same code handles both short and long moves.
from viam.proto.service.motion import PseudolinearConstraint
constraints = Constraints(
pseudolinear_constraint=[
PseudolinearConstraint(
line_tolerance_factor=0.1,
orientation_tolerance_factor=0.1
)
]
)
constraints := &motionplan.Constraints{
PseudolinearConstraint: []motionplan.PseudolinearConstraint{
{
LineToleranceFactor: 0.1,
OrientationToleranceFactor: 0.1,
},
},
}
Tips
- Constraints and obstacles compete. If an obstacle blocks the straight-line path, no path satisfies both the constraint and the collision check, so the planner returns no-path. Widen the constraint or move the obstacle.
- Orientation is checked against the nearer endpoint. The planner compares the current orientation to the start and goal, then uses whichever is closer as the reference. This lets the constraint track intent as the motion progresses rather than locking to one endpoint.
For tolerance selection guidance and more on planning cost, see the Performance considerations section in the constraints reference.