Lifecycle of a Robot
A robot transitions through multiple states during its operation, often for safety and convenience purposes. The robot’s state is also essential for error handling within the automation system it is part of. Therefore, decisions must be based on the robot’s current state, making it crucial to both read and manipulate this state.
The robot instance provided by this library includes multiple states that reflect both the current state of the robot and the status of the interaction between this library and the robot control system. The term lifecycle refers to the typical operational stages of a robot, such as connected, error or ready to move. Additionally, methods to manipulate those states are provided.
Note
To interact with a robot successfully, this library assumes a stable network connection to the robot control is available. Ensure that the robot control is accessible from the machine running this library.
The Lifecycle States of a Robot
A robot of this library always supports the following states:
- class LifecycleState(value)
Enum that represents the state of the robot lifecycle.
- DISCONNECTED = 'DISCONNECTED'
The
robotinstance is created. Default value.
- CONNECTED = 'CONNECTED'
A connection is established, but the robot is not ready to move.
- ENABLED = 'ENABLED'
The robot is ready to move and can receive instructions.
- ERROR = 'ERROR'
The robot is in an error state and not ready to move.
Note
A robot might have more specific states, which are accessible in special functions. See Reading the Robot State for details. Note that those states are specific to a robot behavior group and may require additional effort when porting to another robot. If possible, stick to the lifecycle states, as those are available on every robot.
Reading the Lifecycle State
The current lifecycle state of a robot can be read by invoking the get_lifecycle_state() method:
current_state = robot.get_lifecycle_state()
_logger.info("Current state: %s", current_state) # State DISCONNECTED
Output:
[INFO ] Current state: DISCONNECTED
Connecting to a Robot
First, the desired robot class must be imported:
from voraus_robot_arm import VorausIndustrialRobotArm
Then, a robot instance is created from it:
robot = VorausIndustrialRobotArm()
After creation, the robot instance will be in the DISCONNECTED state, meaning that no connection to the robot
was established yet.
The recommended way of establishing a connection is to use a runtime context.
This ensures that the connection is properly closed once the context is left.
However, it is also possible to use the connect() and disconnect() methods directly.
In order to establish a connection, a robot control host (e.g. IP address or a hostname) and its port must be provided.
with robot.connect(host=VORAUS_CORE_HOST, port=VORAUS_CORE_PORT):
_logger.info(
"Current state: %s", robot.get_lifecycle_state()
) # State CONNECTED
Enabling the Robot
Most actions require the robot to be put into a moveable state.
This is done by using the enable() method.
robot.enable()
Afterwards, the main application logic can be implemented using the functionality provided by this library, as well as any other Python code that helps to solve the given problem.
Once the robot is no longer required to be in a moveable state, the state can be switched again using
the disable() method.
robot.disable()
Lastly, the context is left and the connection to the robot is closed automatically.
If the context is left while the robot is still in the ENABLED state, disable() will be implicitly called
before disconnecting.
Full Example of Lifecycle Handling
The full example on how to work with the robot lifecycle is provided below:
Lifecycle example
"""A simple example on how to use the LifecycleTrait."""
# In the next line ruff is instructed to not organize the imports
# for better readability in the documentation.
from logging import Logger, getLogger # noqa: I001
from voraus_robot_arm import VorausIndustrialRobotArm
from voraus_robot_arm import configure_logging
_logger: Logger = getLogger(__name__)
VORAUS_CORE_HOST = "localhost"
VORAUS_CORE_PORT = 48401
if __name__ == "__main__":
configure_logging()
robot = VorausIndustrialRobotArm()
current_state = robot.get_lifecycle_state()
_logger.info("Current state: %s", current_state) # State DISCONNECTED
with robot.connect(host=VORAUS_CORE_HOST, port=VORAUS_CORE_PORT):
_logger.info(
"Current state: %s", robot.get_lifecycle_state()
) # State CONNECTED
robot.enable()
_logger.info(
"Current state: %s", robot.get_lifecycle_state()
) # State ENABLED
# <configure your application here>
robot.disable()
_logger.info(
"Current state: %s", robot.get_lifecycle_state()
) # State CONNECTED
_logger.info(
"Current state: %s", robot.get_lifecycle_state()
) # State DISCONNECTED
Definition of the Lifecycle Methods
The methods for reading and manipulating the lifecycle state are defined in the LifecycleTrait:
LifecycleTrait
- protocol LifecycleTrait
Trait to read and manipulate the general lifecycle of a robot.
A typical lifecycle consist of the following steps:
The
RobotArmobject is created. It can be configured as desired, but has no connection to any robot.After calling connect,
RobotArmestablishes a connection to the robot it would like to control. Utility interactions are now possible e.g. configuring robot settings but the robot is not ready to move and regulators are off.Calling
enablewill bring the robot into an operational state, in which it is ready to move. This is usually the state in which all functionality ofRobotArmis available.Once the movement and operations have finished,
disablebrings the robot into a state where it is connected but cannot move. This is the same state as in step 2.If
RobotArmshould not be used anymore,disconnectcan be called. This step will execute any necessary operations to bring the robot in a clean state and then disconnect.
Because
disableanddisconnectmay contain clean up operations, they should always be called. Otherwise the robot might be left in an unclean state. In order to guarantee this, a context manager for this class is available:It is assumed that a dedicated error handler is responsible for resetting errors.
Typical state transitions are:
DISCONNECTED -> connect() -> CONNECTED -> disconnect() -> DISCONNECTEDCONNECTED -> enable() -> ENABLED -> disable() -> CONNECTEDThis protocol is runtime checkable.
Classes that implement this protocol must have the following methods / attributes:
- abstractmethod connect(host, port)
Establish communication with the robot.
This function has to be called prior to any other operation. Use the result as a context manager to automatically disconnect on error.
- Parameters:
host (
str) – The host (e.g. IP address or hostname) to connect to.port (
int) – The port to use.
- Return type:
Self- Returns:
The connected self instance.
- abstractmethod enable()
Bring the robot into a state where it is ready to move.
- Return type:
None
- abstractmethod disable()
Bring the robot into a state where it does not move anymore.
- Return type:
None
- abstractmethod disconnect()
Tear down communication with the robot.
This function has to be called as the last operation. A manual usage of disconnect is discouraged. Use the context manager instead.
- Return type:
None
- abstractmethod get_lifecycle_state()
Get the current state of the lifecycle.
- Return type:
- Returns:
The current lifecycle state.
- abstractmethod __enter__()
Enter the context for clean up and disconnection handling after the robot is connected.
- Return type:
Self
- abstractmethod __exit__(exception_type, exception_instance, exception_traceback)
Exit the context and automatically clean up and disconnect.
- Parameters:
exception_type (
type[BaseException] |None) – The exception type, if an exception was raised.exception_instance (
BaseException|None) – The exception instance, if an exception was raised.exception_traceback (
TracebackType|None) – The exception traceback, if an exception was raised.
- Return type:
None