Search documentation of bb

# BB.Robot.Runtime (bb v0.8.0)

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 in supervised tasks. The caller receives a `Task.t()` and can use `Task.await/2` or `Task.yield/2` to get the result. The Runtime monitors the task and transitions back to `:idle` when it completes.

# Summary

## Types

robot_state()
t()

## Functions

cancel(robot_module)

Cancel the currently executing command.

check_allowed(robot_module, allowed_states)

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

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

execute(robot_module, command_name, goal)

Execute a command with the given goal.

get_robot(robot_module)

Get the static robot struct (topology).

get_robot_state(robot_module)

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

positions(robot_module)

Get all joint positions as a map.

start_link(arg)

Starts the runtime for a robot module.

state(robot_module)

Get the current robot state machine state.

transition(robot_module, new_state)

Transition the robot to a new state.

velocities(robot_module)

Get all joint velocities as a map.

via(robot_module)

Returns the via tuple for process registration.

# Types

# robot_state()

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

# t()

    @type t() :: %BB.Robot.Runtime{
      commands: %{required(atom()) => BB.Dsl.Command.t()},
      current_command_name: atom() | nil,
      current_execution_id: reference() | nil,
      current_task: Task.t() | nil,
      current_task_ref: reference() | nil,
      parameter_store: module() | nil,
      parameter_store_state: term() | nil,
      robot: BB.Robot.t(),
      robot_module: module(),
      robot_state: BB.Robot.State.t(),
      state: robot_state()
    }

# Functions

# cancel(robot_module)

    @spec cancel(module()) :: :ok | {:error, :no_execution}

Cancel the currently executing command.

Terminates the command task immediately. The caller will receive an exit when awaiting the task.

# check_allowed(robot_module, allowed_states)

    @spec check_allowed(module(), [robot_state()]) ::
      :ok | {:error, BB.Robot.Runtime.StateError.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, Task.t()}

Execute a command with the given goal.

Returns `{:ok, task}` where `task` can be awaited for the result. The task handles subscription to command events internally.

## Examples

    {:ok, task} = Runtime.execute(MyRobot, :navigate, %{target: pose})
    {:ok, result} = Task.await(task)

    # Or with timeout
    case Task.yield(task, 5000) || Task.shutdown(task) do
      {:ok, result} -> handle_result(result)
      nil -> handle_timeout()
    end

## Errors

Errors are returned through the awaited task result:

- `{:error, %StateError{}}` - Robot not in allowed state
- `{:error, {:unknown_command, name}}` - Command not found
- `{:error, reason}` - Command handler returned an error

# 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}

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