Moving a Robot on a Linear Path

A linear motion is a movement where the robot travels to a target position along a straight-line path in Cartesian space. Unlike point-to-point (PTP) motion, which follows the shortest path in joint space, a linear motion ensures a predictable trajectory in Cartesian coordinates. However, depending on the robot’s kinematics, this type of movement may not always be the fastest.

This chapter specifically explains linear movements. For detailed information on how to use these methods synchronously or asynchronously, see the asynchronous instructions section and the instructions chapter.

Performing a Linear Movement

A linear movement is started with move_linear() from the MoveLinear trait. It moves the tool center point on a straight line to the target and requires two arguments: a target pose of type JointPose, CartesianPose or CartesianTarget, and the maximum translational speed of the tool center point along the path, written as MetersPerSecond(0.25). By default the motion does not blend; .blending() changes that, further motions can be chained, and start() sends the motion to the robot.

The speed is a MetersPerSecond value, or any unit that converts into it, and a maximum: the direction comes from the target, so a negative or non-finite speed is rejected by start() with a UnitLimitError, like every other invalid motion parameter. A literal is written inline as MetersPerSecond(0.25). A constant uses MetersPerSecond::from_static(0.25), which is const and asserts, so an invalid value in a const item or in an inline const { .. } block does not compile. A speed computed at runtime is MetersPerSecond::new(value)?, which returns the UnitLimitError for a non-finite value. A bare f64 is not a MetersPerSecond and is rejected by the compiler.

The speed is a required argument, not an optional modifier. A PTP motion can default to the maximum speed of the axes, but the speed of the tool center point on a linear path depends on the robot, the tool, and the application, so there is no default that is safe everywhere. Every call site states the speed it wants. Name the value once per application rather than repeating a magic number, as the examples do:

/// Cartesian speed used by the examples for linear and circular motions.
///
/// Those motions have no default speed: the safe value depends on the
/// application, so the API makes every call site say what it wants. Naming
/// the value here is the pattern to copy — one constant per application
/// rather than a magic number at each call. The speed is a `MetersPerSecond`;
/// a constant uses `from_static`, which is `const` and asserts, so an
/// invalid constant (or an inline `const { .. }`) does not compile. A
/// speed computed at runtime uses `MetersPerSecond::new(..)?`, and a
/// negative speed fails at `start()`.
pub const TRAVEL_SPEED: MetersPerSecond = MetersPerSecond::from_static(1.0);

/// A deliberately slow Cartesian speed, for motions that should be observable.
pub const SLOW_TRAVEL_SPEED: MetersPerSecond = MetersPerSecond::from_static(0.25);

Perform a Linear Movement Using a CartesianPose

To perform a linear movement to a target defined in Cartesian space, pass a CartesianPose:

let target = CartesianPose::new(
    Meters(0.1382),
    Meters(0.550),
    Meters(0.296),
    Radians(PI),
    Radians(0.0),
    Radians(0.0),
);
robot
    .move_linear(target, common::TRAVEL_SPEED)
    .start()?
    .join()?;
info!("Cartesian target reached via linear interpolation.");

Since a Cartesian pose is ambiguous for a six-axis robot, the resulting joint configuration at the target can differ depending on the starting pose of the robot.

Note

A CartesianPose is interpreted in the robot coordinate system. To move to a pose in another coordinate system, or to let another frame arrive at it, pass a CartesianTarget instead; see Coordinate Systems. A linear motion interpolates the path, so it ignores the configuration vector of a CartesianTarget.

Perform a Linear Movement Using a JointPose

To perform a linear movement to a target defined in joint space, pass a JointPose. The robot control resolves it to a Cartesian pose and moves there on a straight line:

let target = JointPose::new(
    Radians(FRAC_PI_2),
    Radians(-FRAC_PI_2),
    Radians(FRAC_PI_2),
    Radians(-FRAC_PI_2),
    Radians(-FRAC_PI_2),
    Radians(0.0),
);
robot
    .move_linear(target, common::TRAVEL_SPEED)
    .start()?
    .join()?;
info!("Joint target reached via linear interpolation.");

Perform a Relative Linear Movement

For moving linearly relative to the current pose, use move_linear_relative(). Other than that, it accepts the same arguments as move_linear().

In this example, the robot moves 10 cm in the positive z-direction from its current pose. The z() helper builds a CartesianPose in which every component is zero except z:

robot
    .move_linear_relative(z(Meters(0.1)), common::TRAVEL_SPEED)
    .start()?
    .join()?;
info!("Moved +10cm in Z (relative linear).");

Perform a Linear Movement with Blending

Linear movements can use blending by chaining .blending() with a Factor or Percent, or with a radius in Meters (see Blending Radius and Motion Profile). The higher the blending value, the more and earlier the blended path deviates from the original path that would reach the target pose. In most cases this allows the robot to maintain a higher path velocity and complete the overall path faster.

Blending only works if the instruction that follows is known to the robot control in advance, so blended motions form one block. .blending() is the transition into the next step, and the block is sent as a whole by start():

fn linear_with_blending(robot: &impl MoveLinear) -> Result<()> {
    info!("--- Linear with blending ---");

    robot
        .move_linear(poses::blending_1(), common::TRAVEL_SPEED)
        .blending(Percent(50.0))
        .move_linear(poses::blending_2(), common::TRAVEL_SPEED)
        .blending(Factor(0.5))
        .move_linear(poses::blending_3(), common::TRAVEL_SPEED)
        .start()?
        .join()?;
    info!("Blending sequence complete.");
    Ok(())
}

Note how the block ends on a step without blending; a block that ends on a blended step does not compile.

Motion types can be mixed within a block, for example a PTP approach blended into a linear contact move:

fn mixed_block(robot: &(impl MovePtp + MoveLinear)) -> Result<()> {
    info!("--- Mixed PTP/linear block ---");

    robot
        .move_ptp(poses::home_c())
        .blending(Percent(20.0))
        .move_linear(poses::blending_1(), common::SLOW_TRAVEL_SPEED)
        .start()?
        .join()?;
    info!("Mixed block complete.");
    Ok(())
}

Note

The exact behavior and interpretation of the blending parameter as well as implicit limitations are highly dependent on the specific robot used. For more details on blending, please refer to the instructions chapter.

Blending parameters can also be amended after an instruction was sent with amend_blending(); see Amending Blending Parameters.

Blending Radius and Motion Profile

A linear step accepts two more modifiers:

  • .blending(Meters(0.05)), an absolute blending radius in meters; Millimeters and Centimeters convert into it. It needs a linear or circular successor: before a PTP step it is dropped with a warning, so blend into a PTP step with Factor or Percent instead.

  • .parameters(CartesianMotionParameters), a motion profile with the maximum translational acceleration (max_acceleration, a MetersPerSecondSquared), the maximum rotational speed and acceleration (max_rotation_speed, a RadiansPerSecond, and max_rotation_acceleration, a RadiansPerSecondSquared), and orientation interpolation. The maxima are validated by start(): a negative or non-finite value is rejected. Without it, the motion uses the robot control’s defaults, CartesianMotionParameters::DEFAULT. Build a profile from that constant with struct update syntax. The translational speed is not part of the profile; it stays the argument of the motion.

/// A gentler motion profile for linear motions.
///
/// Built with struct-update syntax from the control defaults.
const GENTLE: CartesianMotionParameters = CartesianMotionParameters {
    max_acceleration: MetersPerSecondSquared(0.5),
    ..CartesianMotionParameters::DEFAULT
};

/// Linear motion with a motion profile and an absolute blending radius.
///
/// The radius needs a linear or circular successor: a PTP step has no
/// blending radius.
fn linear_with_parameters(robot: &impl MoveLinear) -> Result<()> {
    info!("--- Linear with a motion profile ---");

    robot
        .move_linear(poses::blending_1(), common::SLOW_TRAVEL_SPEED)
        .parameters(GENTLE)
        .blending(Meters(0.05))
        .move_linear(poses::blending_2(), common::SLOW_TRAVEL_SPEED)
        .start()?
        .join()?;
    info!("Linear motion with a profile complete.");
    Ok(())
}

Full Example

Trait Definition

The trait carries the entry points as default methods, which return a MotionBlock builder; its required method is what a robot type implements.