Runtime process for a BB robot.
Manages the robot's runtime state including:
- The
BB.Robotstruct (static topology) - The
BB.Robot.StateETS table (dynamic joint state) - Robot state machine (disarmed/idle/executing)
- Command execution lifecycle
- Sensor telemetry collection (subscribes to
JointStatemessages)
Robot States
The robot progresses through these states:
:disarmed- Robot is not armed, commands restricted:idle- Robot is armed and ready for commands:executing- A command is currently executing
State Transitions
:disarmed ──arm──→ :idle
:idle ──execute──→ :executing
:executing ──complete──→ :idle
:executing ──disarm──→ :disarmed
:idle ──disarm──→ :disarmedCommand Execution
Commands execute as supervised GenServers. The caller receives the command
pid and can use BB.Command.await/2 or BB.Command.yield/2 to get the
result. The Runtime monitors the command server and transitions back to
:idle when it completes.
Summary
Functions
Cancel the currently executing command.
Get the availability of each command category.
Check if the robot is in one of the allowed states.
Returns a specification to start this module under a supervisor.
Get all joint configurations as a map.
Execute a command with the given goal.
Check if any command is currently executing.
Check if a specific category has commands executing.
Get information about all currently executing commands.
Get the static robot struct (topology).
Get the robot state (ETS-backed joint positions/velocities).
Get the actual operational state, without backwards compatibility translation.
Get the simulation mode for a robot.
Starts the runtime for a robot module.
Get the current robot state machine state.
Transition the robot to a new state.
Transition the operational state during command execution.
Get all joint velocities as a map.
Returns the via tuple for process registration.
Types
@type robot_state() :: :disarmed | :disarming | :idle | :executing | :error | atom()
@type simulation_mode() :: nil | :kinematic | :external
@type t() :: %BB.Robot.Runtime{ category_counts: %{required(atom()) => non_neg_integer()}, category_limits: %{required(atom()) => pos_integer()}, commands: %{required(atom()) => BB.Dsl.Command.t()}, current_command_name: atom() | nil, current_command_pid: pid() | nil, current_command_ref: reference() | nil, current_execution_id: reference() | nil, executing_commands: %{required(reference()) => BB.Robot.CommandInfo.t()}, operational_state: atom(), parameter_store: module() | nil, parameter_store_state: term() | nil, robot: BB.Robot.t(), robot_module: module(), robot_state: BB.Robot.State.t(), simulation_mode: simulation_mode(), valid_states: [atom()] }
Functions
@spec cancel(module()) :: :ok | {:error, :no_execution}
Cancel the currently executing command.
Stops the command server with :cancelled reason. Awaiting callers
will receive the result from the command's result/1 callback.
@spec category_availability(module()) :: %{ required(atom()) => {non_neg_integer(), pos_integer()} }
Get the availability of each command category.
Returns a map of category names to {current_count, limit} tuples.
@spec check_allowed(module(), [robot_state()]) :: :ok | {:error, BB.Error.State.NotAllowed.t()}
Check if the robot is in one of the allowed states.
Reads directly from ETS for fast concurrent access.
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec configurations(module()) :: %{ required(atom()) => BB.Robot.State.configuration() }
Get all joint configurations as a map.
Reads directly from ETS for fast concurrent access. Returns a map of joint
names to their current configurations, each shaped to its joint's type — a
float for single-DoF joints, a BB.Math.Transform2D for planar and a
BB.Math.Transform for floating. See BB.Robot.State for the full table.
Configurations are updated automatically by the Runtime when sensors publish
JointState messages.
Examples
iex> BB.Robot.Runtime.configurations(MyRobot)
%{pan_joint: 0.0, tilt_joint: 0.0}
Execute a command with the given goal.
Returns {:ok, pid} where pid is the command server process.
Use BB.Command.await/2 or BB.Command.yield/2 to get the result.
Examples
{:ok, cmd} = Runtime.execute(MyRobot, :navigate, %{target: pose})
{:ok, result} = BB.Command.await(cmd)
# Or with timeout
case BB.Command.yield(cmd, 5000) do
nil -> still_running()
{:ok, result} -> handle_result(result)
{:error, reason} -> handle_error(reason)
endErrors
{:error, %StateError{}}- Robot not in allowed state{:error, {:unknown_command, name}}- Command not found- Other errors are returned through
BB.Command.await/2
Check if any command is currently executing.
Reads directly from ETS for fast concurrent access.
Check if a specific category has commands executing.
Get information about all currently executing commands.
@spec get_robot(module()) :: BB.Robot.t()
Get the static robot struct (topology).
@spec get_robot_state(module()) :: BB.Robot.State.t()
Get the robot state (ETS-backed joint positions/velocities).
Get the actual operational state, without backwards compatibility translation.
Unlike state/1, this returns the actual operational state regardless of
whether commands are executing. Use this when you need to know the true
operational context (e.g., :idle, :recording, :reacting).
Reads directly from ETS for fast concurrent access.
@spec simulation_mode(module()) :: simulation_mode()
Get the simulation mode for a robot.
Returns nil if running in hardware mode, or the simulation mode atom
(e.g., :kinematic, :external) if running in simulation.
Starts the runtime for a robot module.
@spec state(module()) :: robot_state()
Get the current robot state machine state.
Returns :disarmed if the robot is not armed (via BB.Safety),
otherwise returns the internal operational state.
For backwards compatibility:
- When
operational_stateis:idlebut commands are executing, returns:executing - Custom operational states (e.g.,
:recording) are returned directly
Reads directly from ETS for fast concurrent access.
@spec transition(module(), robot_state()) :: {:ok, robot_state()} | {:error, term()}
Transition the robot to a new state.
Transition the operational state during command execution.
This is called by BB.Command.transition_state/2 to change the robot's
operational state mid-execution. Only the command with the matching
execution_id can trigger a transition.
@spec velocities(module()) :: %{required(atom()) => BB.Robot.State.velocity()}
Get all joint velocities as a map.
Reads directly from ETS for fast concurrent access. Returns a map of joint
names to their current velocities, each shaped to its joint's type — a float
for single-DoF joints, a BB.Message.Geometry.Twist2D for planar and a
BB.Message.Geometry.Twist for floating. See BB.Robot.State for the full
table.
Velocities are updated automatically by the Runtime when sensors publish
JointState messages.
Examples
iex> BB.Robot.Runtime.velocities(MyRobot)
%{pan_joint: 0.0, tilt_joint: 0.0}
Returns the via tuple for process registration.