Stop

Stopping the robot’s movement can be useful to react to external events during program execution. When a stop command is sent, the robot decelerates along its current path until it comes to a complete stop. All active and pending instructions are aborted. In contrast to a pause, new instructions cannot be registered until the stop signal is revoked. A stop overrides a pause: after the stop signal is reset, the robot is ready to move again, even if it was paused before.

Stopping the Robot’s Movement

To stop the robot, call stop_motion() from the Stop trait. It blocks until the robot has come to a stop, bounded by the robot’s command timeout, and returns RobotArmError::DidNotStop if the robot fails to settle in time. It can be called either at standstill or while the robot is moving:

robot.move_ptp(poses::home()).start()?.join()?;
robot.move_ptp(poses::vertical()).start()?;
let move_to_zero = robot.move_ptp(JointPose::default()).start()?;

// Stop all motion. Blocks until the robot has settled, bounded by the
// robot's command timeout.
info!("Stopping motion...");
robot.stop_motion()?;
info!("Robot stopped.");

Note that the motions to the vertical and zero poses are started without join(), which allows a stop during the movement.

After stop_motion(), the registration of new motion instructions is blocked and all active and pending instructions are aborted. A new instruction fails at start() with NotAllowed. A pending instruction resolves with StopTriggered on its handle:

match robot.move_ptp(poses::home()).start() {
    Err(RobotArmError::NotAllowed(_)) => info!("Expected: robot is stopped."),
    Err(e) => info!("Unexpected error: {e}"),
    Ok(_) => info!("Instruction accepted (unexpected)."),
}

// Pending handles resolve with StopTriggered.
match move_to_zero.join() {
    Err(RobotArmError::StopTriggered(_)) => info!("Pending instruction aborted."),
    Err(e) => info!("Unexpected error: {e}"),
    Ok(()) => info!("Instruction completed (unexpected)."),
}

Before sending new motion instructions, unstop_motion() must be called. The robot stays at standstill until new instructions arrive. If a stop is still in progress, unstop_motion() first waits until the robot control has completed it, bounded by the command timeout (DidNotStop otherwise), because the control drops a motion it receives during a stop. At standstill it returns at once:

robot.unstop_motion()?;
info!("Robot unstopped, ready for new instructions.");

// Now we can move again.
robot.move_ptp(JointPose::default()).start()?.join()?;
info!("Moved to zero after unstop.");

Stopping from Another Thread

stop_motion() takes &self and the robots are Sync, so a watchdog thread can stop the robot while another thread is blocked waiting on a motion. The waiting thread sees the stop as StopTriggered as soon as the stop is raised, while the watchdog’s stop_motion() still waits for the robot to come to a stop. The waiting thread does not have to wait for the watchdog before it calls unstop_motion(), which waits for the stop in progress itself:

fn stop_from_watchdog(robot: &(impl MovePtp + Stop + Sync)) -> Result<()> {
    info!("--- Stop from a watchdog thread ---");

    scope(|scope| -> Result<()> {
        scope.spawn(|| {
            sleep(Duration::from_millis(100));
            if let Err(e) = robot.stop_motion() {
                info!("Watchdog could not stop: {e}");
            }
        });

        match robot
            .move_ptp(poses::vertical())
            .move_ptp(JointPose::default())
            .start()?
            .join()
        {
            Err(RobotArmError::StopTriggered(_)) => {
                info!("Block was stopped by the watchdog.");
            }
            other => other?,
        }
        Ok(())
    })?;

    // The watchdog may have stopped the robot after the block had already
    // finished; either way the stop has to be reset before moving on.
    // `unstop_motion` waits for a stop that is still in progress.
    robot.unstop_motion()?;

    robot.move_ptp(poses::home()).start()?.join()?;
    Ok(())
}

Configuring the Stop Behavior

How the robot decelerates, and how quickly, can be configured per stop source with the SetStopBehavior trait. See Stop Behavior.

Full Example

Trait Definition