BB.Safety (bb v0.15.0)
View SourceSafety system API.
This module provides the API for arming/disarming robots and managing safety state.
The disarm/1 callback that components implement is now defined in BB.Controller
and BB.Actuator behaviours.
Safety States
:disarmed- Robot is safely disarmed, all disarm callbacks succeeded:armed- Robot is armed and ready to operate:disarming- Disarm in progress, callbacks running concurrently:error- Disarm attempted but one or more callbacks failed; hardware may not be safe
When in :error state, the robot cannot be armed until force_disarm/1 is called
to acknowledge the error and reset to :disarmed.
Disarm callbacks run concurrently with a timeout. If any callback fails or times out,
the robot transitions to :error state.
Implementing Disarm Callbacks
Controllers and actuators implement the disarm/1 callback via their behaviours:
defmodule MyActuator do
use GenServer
use BB.Actuator
@impl BB.Actuator
def disarm(opts) do
pin = Keyword.fetch!(opts, :pin)
MyHardware.disable(pin)
:ok
end
def init(opts) do
BB.Safety.register(__MODULE__,
robot: opts[:bb].robot,
path: opts[:bb].path,
opts: [pin: opts[:pin]]
)
# ...
end
endIf your actuator doesn't need special disarm logic, you can implement a no-op:
@impl BB.Actuator
def disarm(_opts), do: :okImportant Limitations
The BEAM virtual machine provides soft real-time guarantees, not hard real-time. Disarm callbacks may be delayed by garbage collection, scheduler load, or other system activity. For safety-critical applications, always implement hardware-level safety controls as your primary protection.
See the Safety documentation topic for detailed recommendations.
Summary
Functions
Arm the robot.
Check if a robot is armed.
Disarm the robot.
Check if a robot is currently disarming.
Force disarm from error state.
Check if a robot is in error state.
Register a safety handler (actuator/sensor/controller).
Report a hardware error from a component.
Get current safety state for a robot.
Functions
Arm the robot.
Goes through the safety controller GenServer to ensure proper state transitions.
Cannot arm if robot is in :error state - must call force_disarm/1 first.
Returns :ok or {:error, :already_armed | :in_error | :not_registered}.
Check if a robot is armed.
Fast ETS read - does not go through GenServer.
Disarm the robot.
Goes through the safety controller GenServer. Calls all registered disarm/1
callbacks before updating state. If any callback fails, the robot transitions
to :error state instead of :disarmed.
Options
:timeout- timeout in milliseconds for each disarm callback. Defaults to 5000ms.
Returns :ok or {:error, :already_disarmed | {:disarm_failed, failures}}.
Check if a robot is currently disarming.
Returns true while disarm callbacks are running.
Fast ETS read - does not go through GenServer.
Force disarm from error state.
Use this function to acknowledge a failed disarm operation and reset the
robot to :disarmed state. This should only be called after manually
verifying that hardware is in a safe state.
WARNING: This bypasses safety checks. Only use when you have manually verified that all actuators are disabled and the robot is safe.
Returns :ok or {:error, :not_in_error | :not_registered}.
Check if a robot is in error state.
Returns true if a disarm operation failed and the robot requires
manual intervention via force_disarm/1.
Fast ETS read - does not go through GenServer.
Register a safety handler (actuator/sensor/controller).
Called by processes in their init/1. The opts should contain all
hardware-specific parameters needed to call disarm/1 without GenServer state.
Writes directly to ETS to avoid blocking on the Controller's mailbox.
Options
:robot(required) - The robot module:path(required) - The path to this component (for logging):opts- Hardware-specific options passed todisarm/1
Example
BB.Safety.register(__MODULE__,
robot: MyRobot,
path: [:arm, :shoulder_joint, :servo],
opts: [pin: 18]
)
Report a hardware error from a component.
This function should be called by controllers, actuators, or sensors when
they detect a hardware error condition. The behaviour depends on the robot's
auto_disarm_on_error setting:
- If
true(default): The robot is automatically disarmed - If
false: The error is published but no automatic action is taken
In both cases, a BB.Safety.HardwareError message is published to
[:safety, :error] for subscribers to handle.
Parameters
robot_module- The robot modulepath- Path to the component reporting the error (e.g.,[:dynamixel, :servo_1])error- Component-specific error details
Example
# In a controller detecting servo overheating:
BB.Safety.report_error(MyRobot, [:dynamixel, :servo_1], {:hardware_error, 0x04})Customising Error Handling
To implement custom error handling instead of auto-disarm:
defmodule MyRobot do
use BB
settings do
auto_disarm_on_error false
end
end
# Then subscribe to error events:
BB.subscribe(MyRobot, [:safety, :error])
Get current safety state for a robot.
Fast ETS read - does not go through GenServer.
Returns :armed, :disarmed, :disarming, or :error.