BB.Robot.Runtime (bb v0.13.2)

View Source

Runtime process for a BB robot.

Manages the robot's runtime state including:

  • The BB.Robot struct (static topology)
  • The BB.Robot.State ETS table (dynamic joint state)
  • Robot state machine (disarmed/idle/executing)
  • Command execution lifecycle
  • Sensor telemetry collection (subscribes to JointState messages)

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 :disarmed

Command 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.

Check if the robot is in one of the allowed states.

Returns a specification to start this module under a supervisor.

Execute a command with the given goal.

Get the static robot struct (topology).

Get the robot state (ETS-backed joint positions/velocities).

Get all joint positions as a map.

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.

Get all joint velocities as a map.

Returns the via tuple for process registration.

Types

robot_state()

@type robot_state() :: :disarmed | :disarming | :idle | :executing | :error

simulation_mode()

@type simulation_mode() :: nil | :kinematic | :external

t()

@type t() :: %BB.Robot.Runtime{
  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,
  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(),
  state: robot_state()
}

Functions

cancel(robot_module)

@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.

check_allowed(robot_module, allowed_states)

@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.

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

execute(robot_module, command_name, goal)

@spec execute(module(), atom(), map()) :: {:ok, pid()} | {:error, term()}

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)
end

Errors

  • {:error, %StateError{}} - Robot not in allowed state
  • {:error, {:unknown_command, name}} - Command not found
  • Other errors are returned through BB.Command.await/2

get_robot(robot_module)

@spec get_robot(module()) :: BB.Robot.t()

Get the static robot struct (topology).

get_robot_state(robot_module)

@spec get_robot_state(module()) :: BB.Robot.State.t()

Get the robot state (ETS-backed joint positions/velocities).

positions(robot_module)

@spec positions(module()) :: %{required(atom()) => float()}

Get all joint positions as a map.

Reads directly from ETS for fast concurrent access. Returns a map of joint names to their current positions (in radians for revolute joints, metres for prismatic joints).

Positions are updated automatically by the Runtime when sensors publish JointState messages.

Examples

iex> BB.Robot.Runtime.positions(MyRobot)
%{pan_joint: 0.0, tilt_joint: 0.0}

simulation_mode(robot_module)

@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.

start_link(arg)

Starts the runtime for a robot module.

state(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 state (:idle or :executing).

Reads directly from ETS for fast concurrent access.

transition(robot_module, new_state)

@spec transition(module(), robot_state()) :: {:ok, robot_state()} | {:error, term()}

Transition the robot to a new state.

velocities(robot_module)

@spec velocities(module()) :: %{required(atom()) => float()}

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 (in rad/s for revolute joints, m/s for prismatic joints).

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}

via(robot_module)

Returns the via tuple for process registration.