Moving a Robot on a Circular Path
A circular motion is a movement where the robot travels to a target position along a circular path in Cartesian space. Unlike point-to-point (PTP) motion, which follows the shortest path in joint space, a circular 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 circular movements. For detailed information on how to use these methods synchronously or asynchronously, see the asynchronous instructions chapter.
Performing a Circular Movement
Performing a circular movement can be done using the method move_circular(),
which requires a target pose and a via pose of either type JointPose or CartesianPose.
The via pose is an intermediate pose used to define the circular path between the start and target pose.
Perform a Circular Movement using CartesianPose Parameters
To perform a circular movement to a target defined in Cartesian space, use a CartesianPose as an input target argument:
robot.move_ptp(HOME).result()
cartesian_target = HOME_C + y(0.4)
cartesian_via = HOME_C + x(0.2) + y(0.2)
robot.move_circular(
target=cartesian_target, via=cartesian_via, velocity_mps=1.0
).result()
The velocity_mps argument defines the maximum translational velocity for the tool center point in meter per second.
Giving no argument results in a speed of 1 m/s.
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
The CartesianPose is interpreted in the world coordinate system. No specific tool is assumed. The behavior depends on the specific robot in use.
A CartesianPose itself can be ambiguous in regards to the exact joint configuration of the robot. It is at the discretion of the underlying robot control to choose a convenient joint configuration to reach the given pose. This means, that the robot configuration reached depends on the starting position.
Perform a Circular Movement using JointPose Parameters
To perform a circular movement to a target defined in joint space, use a JointPose as an input target argument:
robot.move_ptp(HOME).result()
target_joints = HOME + JointPose.from_list(
[radians(d) for d in [90, 0, 0, 0, 0, 0]]
)
via_joints = HOME + JointPose.from_list(
[radians(d) for d in [45, 0, 0, 0, 0, 0]]
)
robot.move_circular(
target=target_joints, via=via_joints, velocity_mps=1.0
).result()
The via argument can be given as a JointPose or a CartesianPose, depending on the circumstances.
Perform a Relative Circular Movement
For moving on a circular path relative to the current end effector pose, use the move_circular_relative() method,
which accepts the same arguments as move_circular().
robot.move_ptp(HOME).result()
cartesian_target: CartesianPose = y(0.4)
cartesian_via: CartesianPose = x(0.2) + y(0.2)
robot.move_circular_relative(
target=cartesian_target, via=cartesian_via, velocity_mps=1.0
).result()
In this example, the robot moves relative in the positive x- and y-direction from its current pose. The x and y
input arguments are a CartesianPose, where every argument except the specified value is zero.
Perform a Circular Movement with Blending
Circular movements can use blending by supplying a Factor or Percent input to the blending argument. The higher the
blending factor, the more and earlier the blended path will deviate 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 instructions used for blending are known to robot control in advance. As such, it is not
possible to blend two instructions, which are synced to the Python interpreter.
cartesian_target_1 = HOME_C + y(0.2)
cartesian_target_2 = HOME_C + x(0.2) + y(0.2)
cartesian_via = HOME_C + x(0.1) + y(0.1)
robot.move_ptp(HOME).result()
robot.move_circular(
target=cartesian_target_1, via=cartesian_via, blending=Percent(50)
)
robot.move_circular(
target=cartesian_target_2, via=cartesian_via, blending=Factor(0.5)
)
robot.move_circular(target=HOME_C, via=cartesian_target_1).result()
Note how the .result(), which syncs the instruction to the Python interpreter, is only used for the last movement
command which itself does not contain a blending argument.
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 how to use and how not to use the blending functionality, please refer to the asynchronous instructions chapter.
Amending blending parameters
If your robot supports sending delayed blending parameters, it is possible to amend a blending parameter after sending
the motion instruction using the amend_blending_parameters() method.
cartesian_target_1 = HOME_C + y(0.2)
cartesian_target_2 = HOME_C + x(0.2) + y(0.2)
cartesian_via = HOME_C + x(0.1) + y(0.1)
robot.move_ptp(HOME).result()
robot.move_circular(target=cartesian_target_1, via=cartesian_via)
robot.amend_blending_parameter(blending=Percent(50))
robot.move_circular(target=cartesian_target_2, via=cartesian_via)
robot.amend_blending_parameter(blending=Factor(0.5))
robot.move_circular(target=HOME_C, via=cartesian_target_1).result()
In this example the robot will blend the poses cartesian_target_1 and cartesian_target_2 just like in the previous
example, but the blending parameters are supplied after sending the motion instruction.
Note that amending the parameter too late - i.e. such that the robot already reached the previous target pose - may result in a drop of the blend request by the robot control.
Full Example of Performing Circular Movements
The following example shows a simple application in which the move_circular() method is being used:
Using move_circular() example
"""An example on how to perform circular movements."""
from math import radians
from typing import Protocol, runtime_checkable
from voraus_robot_arm import (
AmendBlendingParametersTrait,
CartesianPose,
Factor,
JointPose,
MoveCircularTrait,
MovePTPTrait,
Percent,
VorausIndustrialRobotArm,
configure_logging,
x,
y,
)
VORAUS_CORE_IP = "localhost"
VORAUS_CORE_PORT = 48401
HOME = JointPose().from_list(
[radians(d) for d in [0, -90, 90, -90, -90, 0]]
)
HOME_C = CartesianPose().from_list(
[0.550, -0.1382, 0.4743, -3.14, -0, 1.57]
)
@runtime_checkable
class _RequiredRobotTraits(MoveCircularTrait, MovePTPTrait, Protocol): ...
@runtime_checkable
class _AmendBlendingTraits(
MoveCircularTrait,
AmendBlendingParametersTrait,
MovePTPTrait,
Protocol,
): ...
def run_circular_movement_using_a_joint_pose(
robot: _RequiredRobotTraits,
) -> None:
"""Simple circular movement using JointPoses."""
robot.move_ptp(HOME).result()
target_joints = HOME + JointPose.from_list(
[radians(d) for d in [90, 0, 0, 0, 0, 0]]
)
via_joints = HOME + JointPose.from_list(
[radians(d) for d in [45, 0, 0, 0, 0, 0]]
)
robot.move_circular(
target=target_joints, via=via_joints, velocity_mps=1.0
).result()
def run_circular_movement_using_a_cartesian_pose(
robot: _RequiredRobotTraits,
) -> None:
"""Simple absolute circular movement using CartesianPoses."""
robot.move_ptp(HOME).result()
cartesian_target = HOME_C + y(0.4)
cartesian_via = HOME_C + x(0.2) + y(0.2)
robot.move_circular(
target=cartesian_target, via=cartesian_via, velocity_mps=1.0
).result()
def run_relative_circular_movement(
robot: _RequiredRobotTraits,
) -> None:
"""Simple relative circular movement using a CartesianPose."""
robot.move_ptp(HOME).result()
cartesian_target: CartesianPose = y(0.4)
cartesian_via: CartesianPose = x(0.2) + y(0.2)
robot.move_circular_relative(
target=cartesian_target, via=cartesian_via, velocity_mps=1.0
).result()
def run_circular_movement_with_blending(
robot: _RequiredRobotTraits,
) -> None:
"""Simple circular instruction block with blending."""
cartesian_target_1 = HOME_C + y(0.2)
cartesian_target_2 = HOME_C + x(0.2) + y(0.2)
cartesian_via = HOME_C + x(0.1) + y(0.1)
robot.move_ptp(HOME).result()
robot.move_circular(
target=cartesian_target_1, via=cartesian_via, blending=Percent(50)
)
robot.move_circular(
target=cartesian_target_2, via=cartesian_via, blending=Factor(0.5)
)
robot.move_circular(target=HOME_C, via=cartesian_target_1).result()
def run_amend_blending_parameters_example(
robot: _AmendBlendingTraits,
) -> None:
"""Amending blending parameters to a circular motion instruction."""
cartesian_target_1 = HOME_C + y(0.2)
cartesian_target_2 = HOME_C + x(0.2) + y(0.2)
cartesian_via = HOME_C + x(0.1) + y(0.1)
robot.move_ptp(HOME).result()
robot.move_circular(target=cartesian_target_1, via=cartesian_via)
robot.amend_blending_parameter(blending=Percent(50))
robot.move_circular(target=cartesian_target_2, via=cartesian_via)
robot.amend_blending_parameter(blending=Factor(0.5))
robot.move_circular(target=HOME_C, via=cartesian_target_1).result()
if __name__ == "__main__":
configure_logging()
robot = VorausIndustrialRobotArm()
with robot.connect(host=VORAUS_CORE_IP, port=VORAUS_CORE_PORT):
robot.enable()
run_circular_movement_using_a_joint_pose(robot)
run_circular_movement_using_a_cartesian_pose(robot)
run_relative_circular_movement(robot)
run_circular_movement_with_blending(robot)
run_amend_blending_parameters_example(robot)
Definition of the Move Circular Method
The move circular method is defined in the MoveCircularTrait:
MoveCircularTrait
- protocol MoveCircularTrait
Trait to perform a circular movement using an intermediate via pose.
This protocol is runtime checkable.
Classes that implement this protocol must have the following methods / attributes:
- abstractmethod move_circular(target, via, *, velocity_mps=1.0, blending=None)
Instruction that moves the robot end effector on a circular path in the Cartesian workspace.
The circle is defined by the start pose, the target pose and an intermediate via pose.
The CartesianPose is interpreted in the world coordinate system. No specific tool is assumed. The behavior depends on the specific robot in use.
A CartesianPose itself can be ambiguous in regards to the exact joint configuration of the robot. It is at the discretion of the underlying robot control to choose a convenient joint configuration to reach the given pose. This means, that the robot configuration reached depends on the starting position. With this generic interface it is not possible to force a specific robot configuration in Cartesian space. Please use a robot specific trait for this purpose.
The velocity_mps argument defines the maximum translational velocity for the tool center point in m/s. Giving no argument results in a velocity of 1 m/s.
If blending is activated, the given target pose will not be reached exactly. The higher the blending factor, the more and earlier the blended path will deviate 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.
The exact behavior and interpretation of the blending parameter as well as implicit limitations are highly dependent on the specific robot used.
Blending only works, if this instruction is not synchronized to the Python interpreter and the next instruction is received prior to the execution of this instruction. Otherwise, the robot will hold at the starting point of this instruction. If in that case the instruction leading to the starting point of this instruction also contained a blending parameter, the blending parameter of the previous instruction will be ignored. As a result, the previous instruction will not be blended.
- Parameters:
target (
CartesianPose|JointPose) – The target pose of the desired motion.via (
CartesianPose|JointPose) – An intermediate pose used to define the circular path between the start and target pose.velocity_mps (
float) – Maximum translational velocity for the tool center point in m/s. Defaults to 1 m/s.blending (
Factor|Percent|None) – Blending with next instruction in percent or as factor. Only works if this instruction is not synchronized to the Python interpreter.
- Return type:
- Returns:
A Future to track the state of this operation.
- abstractmethod move_circular_relative(target, via, *, velocity_mps=1.0, blending=None)
Instruction that moves the robot end effector on a circular path in the Cartesian workspace.
The target and via pose must be provided relative to the start pose. Please see
move_circularfor a detailed description of parameter options.- Return type:
- Returns:
A Future to track the state of this operation.