# Move an arm with motion constraints

Move an arm along a straight line or with a fixed orientation using motion constraints.
> Source: https://docs.viam.com/motion-planning/move-an-arm/move-with-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](/motion-planning/frame-system/) configured
- Familiarity with [Move arm to pose](/motion-planning/move-an-arm/move-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.




### Python

```python
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
)
```

### Go

The Go tabs on this page continue from
[Move an arm to a pose](/motion-planning/move-an-arm/move-to-pose/):
`motionService` and `destination` are defined there.

```go
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.




### Python

```python
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
)
```

### Go

```go
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.




### Python

```python
# Straight line, level orientation
constraints = Constraints(
    linear_constraint=[
        LinearConstraint(line_tolerance_mm=5.0)
    ],
    orientation_constraint=[
        OrientationConstraint(orientation_tolerance_degs=3.0)
    ]
)
```

### Go

```go
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. Use it
when the same code handles both short and long moves.




### Python

```python
from viam.proto.service.motion import PseudolinearConstraint

constraints = Constraints(
    pseudolinear_constraint=[
        PseudolinearConstraint(
            line_tolerance_factor=0.1,
            orientation_tolerance_factor=0.1
        )
    ]
)
```

### Go

```go
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](/motion-planning/move-an-arm/constraints/#performance-considerations)
section in the constraints reference.

## What's next

- [Configure motion constraints](/motion-planning/move-an-arm/constraints/):
  full reference for all four constraint types.
- [Allow frame collisions](/motion-planning/obstacles/allow-frame-collisions/):
  the fourth constraint type, for letting specific frame pairs touch.
- [Plan collision-free paths](/motion-planning/obstacles/avoid-obstacles/):
  combine constraints with obstacle avoidance.

