BB.Safety.Controller (bb v0.15.0)
View SourceGlobal safety controller that owns arm/disarm state for all robots.
Part of BB's application supervision tree (not per-robot), so it survives robot crashes and maintains safety state. Runs at high scheduler priority.
Uses two ETS tables:
- Robots table (protected set) - safety state per robot, writes only via GenServer
- Handlers table (public bag) - direct writes for registration
Monitors robot supervisors and cleans up state when they terminate.
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.
Note: The executing/idle distinction is handled by Runtime as it's not safety-critical.
Summary
Functions
Arm the robot.
Check if a robot is armed.
Returns a specification to start this module under a supervisor.
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).
Register a robot when it starts.
Get list of registered handler modules for a robot.
Report a hardware error from a component.
Get current safety state for a robot.
Types
Functions
@spec arm(module()) :: :ok | {:error, :already_armed | :in_error | :not_registered}
Arm the robot.
Goes through GenServer to ensure proper state transitions and event publishing.
Cannot arm if robot is in :error state - must call force_disarm/1 first.
Check if a robot is armed.
Fast ETS read - does not go through GenServer.
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec disarm( module(), keyword() ) :: :ok | {:error, :already_disarmed | :not_registered | {:disarm_failed, list()}}
Disarm the robot.
Goes through GenServer. Calls all registered disarm/1 callbacks before
updating state. If any callback fails, the robot transitions to :error
state instead of :disarmed, and this function returns an error with
details of the failures.
When in :error state, the robot cannot be armed until force_disarm/1
is called to acknowledge the failure and reset to :disarmed.
Options
:timeout- timeout in milliseconds for each disarm callback. Defaults to 5000ms. The GenServer call timeout is set totimeout + 5000to allow for processing overhead.
Check if a robot is currently disarming.
Returns true while disarm callbacks are running.
Fast ETS read - does not go through GenServer.
@spec force_disarm(module()) :: :ok | {:error, :not_in_error | :not_registered}
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.
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. Uses a cast to set up process monitoring for cleanup on handler restart.
Register a robot when it starts.
Called by BB.Supervisor during robot startup. Sets up monitoring of the
robot's supervision tree for automatic cleanup on crash.
Get list of registered handler modules for a robot.
Used by Runtime to verify all safety handlers have registered on startup.
Report a hardware error from a component.
Publishes a HardwareError message and optionally triggers disarm based on
the robot's auto_disarm_on_error setting.
@spec state(module()) :: safety_state()
Get current safety state for a robot.
Fast ETS read - does not go through GenServer.
Returns :armed, :disarmed, or :error.