Payload
A typical task for a robotic arm often involves carrying payloads, which can vary in weight and significantly impact motion control. To address this, many robot control systems offer the option to specify a payload, ensuring that the system accounts for the payload weight during motion planning. This chapter shows how to read and modify the current payload.
Note
SetPayload is implemented by VorausIndustrialRobotArm and YuRobotArm only, so payload
configuration is not available on KukaRobotArm or FanucRobotArm.
Setting a Payload
To configure an additional payload mass, call set_payload() with a Payload: the mass as Kilograms and,
optionally, the center of mass as a Translation in the tool coordinate system. Payload::new(mass) alone places
the center of mass at the tool origin. The call returns once the robot control reports the new mass; the center of
mass cannot be read back, so it is not confirmed.
Important
The payload is the mass carried in addition to the selected tool, for example a picked part. The tool’s own mass is part of the tool configuration on the control, so do not include the gripper: a 1 kg gripper holding a 0.5 kg part is a payload of 0.5 kg. The control attaches the payload to the active tool, so set it again after selecting another tool rather than relying on it being kept.
robot.set_payload(
Payload::new(Kilograms(1.0)).with_center_of_mass(Translation::new(
Meters(0.1),
Meters(0.1),
Meters(0.1),
)),
)?;
The current payload is removed with remove_payload(). It sets the payload mass to 0 kg and the center of
mass to the origin of the tool coordinate system:
robot.remove_payload()?;
Reading the Current Payload Mass
The currently configured payload mass is read with payload_mass(), which returns the mass in Kilograms.
Reading the corresponding center of mass is not supported by the control.
let mass = robot.payload_mass()?;
info!("Payload mass: {mass}"); // Should print 1kg
Full Example
Payload example
//! Payload examples.
//!
//! Demonstrates how to set, read, and remove the robot's payload mass offset.
mod common;
use tracing::info;
use voraus_robot_arm::prelude::*;
/// Example showing how to set and get the robot's payload.
fn run_payload_example(robot: &impl SetPayload) -> Result<()> {
info!("--- Payload ---");
// A 1 kg payload with its center of mass at (0.1, 0.1, 0.1) in the tool
// coordinate system. `Payload::new(mass)` alone places it at the tool
// origin.
robot.set_payload(
Payload::new(Kilograms(1.0)).with_center_of_mass(Translation::new(
Meters(0.1),
Meters(0.1),
Meters(0.1),
)),
)?;
let mass = robot.payload_mass()?;
info!("Payload mass: {mass}"); // Should print 1kg
robot.remove_payload()?;
let mass = robot.payload_mass()?;
info!("Payload mass after removal: {mass}"); // Should print 0kg
Ok(())
}
fn main() -> voraus_robot_arm::error::Result<()> {
common::init_logging();
let robot = common::create_connected_robot()?;
run_payload_example(&robot)?;
info!("Done.");
Ok(())
}
Trait Definitions
GetPayload
pub trait GetPayload {
/// The configured payload mass.
///
/// The value does not include the mass of the tool. After
/// [`remove_payload`](SetPayload::remove_payload), the value is
/// 0 kg.
///
/// # Example
///
/// ```rust
/// # use voraus_robot_arm::prelude::*;
/// # fn demo(robot: &impl GetPayload) -> Result<()> {
/// let Kilograms(mass) = robot.payload_mass()?;
/// println!("payload: {mass} kg");
/// # Ok(())
/// # }
/// ```
///
/// # Returns
///
/// The payload mass, without the mass of the tool.
///
/// # Errors
///
/// Returns [`RobotArmError`](crate::error::RobotArmError) if the value
/// cannot be read.
fn payload_mass(&self) -> Result<Kilograms>;
}
SetPayload
pub trait SetPayload: GetPayload {
/// Configure the payload.
///
/// The call replaces the mass and the center of mass of the previous
/// payload. It checks the payload before it writes anything, so a
/// rejected payload leaves the control unchanged. The call does not wait
/// for the robot to stand still. Set the payload again after
/// [`SelectTool::select_tool`](crate::traits::SelectTool::select_tool),
/// because the control attaches the payload to the active tool.
///
/// # Example
///
/// ```rust
/// # use voraus_robot_arm::prelude::*;
/// # fn demo(robot: &impl SetPayload) -> Result<()> {
/// // A 0.5 kg part, 5 cm from the tool origin along the tool z axis.
/// let part = Payload::new(Kilograms(0.5))
/// .with_center_of_mass(Translation::new(Meters(0.0), Meters(0.0), Meters(0.05)));
/// robot.set_payload(part)?;
/// # Ok(())
/// # }
/// ```
///
/// # Arguments
///
/// * `payload` - The mass and center of mass, in the tool coordinate system.
///
/// # Returns
///
/// `Ok(())` once the control reports the new mass. The center of mass
/// cannot be read back and is not confirmed, so a call that only moves
/// the center of mass returns at once.
///
/// # Errors
///
/// Returns [`RobotArmError::UnitLimit`](crate::error::RobotArmError::UnitLimit)
/// for a negative mass or a non-finite value,
/// [`RobotArmError::RobotInErrorState`](crate::error::RobotArmError::RobotInErrorState)
/// with the control's error if the control refuses the write,
/// [`RobotArmError::NotConfirmed`](crate::error::RobotArmError::NotConfirmed)
/// if the control does not report the new mass within the command
/// timeout, or the error the write failed with.
fn set_payload(&self, payload: Payload) -> Result<()> {
self.send_payload(payload)?.confirm()
}
/// Send the payload.
///
/// The call returns before the control confirms the payload mass. Call
/// [`confirm`](CommandHandle::confirm) on the returned handle to wait
/// for it.
///
/// # Arguments
///
/// * `payload` - The mass and center of mass, in the tool coordinate system.
///
/// # Returns
///
/// The handle that confirms the payload mass. [`CommandHandle::confirm`]
/// returns
/// [`RobotArmError::RobotInErrorState`](crate::error::RobotArmError::RobotInErrorState)
/// with the control's error if the control refuses the write, or
/// [`RobotArmError::NotConfirmed`](crate::error::RobotArmError::NotConfirmed)
/// if the control does not confirm the payload mass within the command
/// timeout.
///
/// # Errors
///
/// Returns [`RobotArmError::UnitLimit`](crate::error::RobotArmError::UnitLimit)
/// for a negative mass or a non-finite value, or the error the write
/// failed with.
fn send_payload(&self, payload: Payload) -> Result<CommandHandle<'_>>;
/// Remove the payload: a mass of 0 kg at the tool origin.
///
/// The call is the same as
/// [`set_payload`](Self::set_payload) with
/// `Payload::new(Kilograms(0.0))`. Call it after the robot puts down a
/// part. If no payload is set, the call also succeeds.
///
/// # Example
///
/// ```rust
/// # use voraus_robot_arm::prelude::*;
/// # fn demo(robot: &impl SetPayload) -> Result<()> {
/// robot.remove_payload()?;
/// # Ok(())
/// # }
/// ```
///
/// # Returns
///
/// `Ok(())` once the control reports a mass of 0 kg.
///
/// # Errors
///
/// As for [`set_payload`](Self::set_payload).
fn remove_payload(&self) -> Result<()> {
self.send_remove_payload()?.confirm()
}
/// Send the removal of the payload.
///
/// The call returns before the control confirms the removal. Call
/// [`confirm`](CommandHandle::confirm) on the returned handle to wait
/// for it.
///
/// # Returns
///
/// The handle that confirms the payload mass of 0 kg. [`CommandHandle::confirm`]
/// returns
/// [`RobotArmError::RobotInErrorState`](crate::error::RobotArmError::RobotInErrorState)
/// with the control's error if the control refuses the write, or
/// [`RobotArmError::NotConfirmed`](crate::error::RobotArmError::NotConfirmed)
/// if the control does not confirm the payload mass of 0 kg within the command
/// timeout.
///
/// # Errors
///
/// Returns the error the write failed with.
fn send_remove_payload(&self) -> Result<CommandHandle<'_>>;
}
Payload
pub struct Payload {
/// The payload mass, carried in addition to the selected tool. The tool's
/// own mass is part of the tool configuration on the control; do not
/// include it here.
pub mass: Kilograms,
/// The center of mass in the tool coordinate system.
pub center_of_mass: Translation,
}
impl Payload {
/// A payload of the given mass at the tool origin.
///
/// # Arguments
///
/// * `mass` - The payload mass.
///
/// # Returns
///
/// The payload with its center of mass at the tool origin.
#[must_use]
pub const fn new(mass: Kilograms) -> Self {
Self {
mass,
center_of_mass: Translation {
x: Meters(0.0),
y: Meters(0.0),
z: Meters(0.0),
},
}
}
/// Place the center of mass.
///
/// # Arguments
///
/// * `center_of_mass` - The center of mass in the tool coordinate system.
///
/// # Returns
///
/// The payload with the center of mass set.
#[must_use]
pub const fn with_center_of_mass(mut self, center_of_mass: Translation) -> Self {
self.center_of_mass = center_of_mass;
self
}
/// Check that the mass is finite and non-negative and the center of
/// mass is finite.
///
/// # Returns
///
/// `self` if the mass is finite and non-negative and the center of mass
/// is finite.
///
/// # Errors
///
/// Returns [`UnitLimitError`] for a negative or non-finite mass or a
/// non-finite center-of-mass component.
pub fn validate(self) -> Result<Self, UnitLimitError> {
self.mass.ensure_non_negative()?;
self.center_of_mass.validate()?;
Ok(self)
}
}