Search documentation of bb

# BB.Command behaviour (bb v0.8.0)

View Source

Behaviour for implementing robot commands.

Commands execute in a supervised task and receive a goal (arguments) and context (robot state). The handler runs to completion and returns a result.

## Example

    defmodule NavigateToPose do
      @behaviour BB.Command

      @impl true
      def handle_command(%{target_pose: pose, tolerance: tol}, context) do
        # Access robot state
        current_pose = get_current_pose(context.robot_state)

        # Do the work (this runs in a task, so blocking is fine)
        case navigate_to(pose, tolerance: tol) do
          :ok -> {:ok, %{final_pose: pose}}
          {:error, reason} -> {:error, reason}
        end
      end
    end

## State Transitions

By default, when a command completes successfully, the robot transitions to `:idle`. Commands can override this by returning a `next_state` option:

    def handle_command(_goal, _context) do
      {:ok, :disarmed, next_state: :disarmed}
    end

This is useful for commands like `Arm` and `Disarm` that need to control the robot's state machine.

## Execution Model

Commands run in supervised tasks spawned by the Runtime. The caller receives a `Task.t()` and can use `Task.await/2` or `Task.yield/2` to get the result.

Cancellation is handled by killing the task - handlers don't need to implement cancellation logic. If graceful shutdown is needed, handlers can trap exits.

# Summary

## Types

goal()
options()
result()

## Callbacks

handle_command(goal, t)

Execute the command with the given goal.

# Types

# goal()

    @type goal() :: map()

# options()

    @type options() :: [{:next_state, BB.Robot.Runtime.robot_state()}]

# result()

    @type result() :: term()

# Callbacks

# handle_command(goal, t)

    @callback handle_command(goal(), BB.Command.Context.t()) ::
      {:ok, result()} | {:ok, result(), options()} | {:error, term()}

Execute the command with the given goal.

Called in a supervised task. The handler should perform the work and return the result. Blocking operations are fine since this runs in a separate process.

The context provides access to:

- `robot_module` - The robot module
- `robot` - The static robot struct (topology)
- `robot_state` - The dynamic robot state (ETS-backed joint positions etc)
- `execution_id` - Unique identifier for this execution

## Return Values

- `{:ok, result}` - Command succeeded, robot transitions to `:idle`
- `{:ok, result, options}` - Command succeeded with options:
  - `next_state: state` - Robot transitions to specified state instead of `:idle`
- `{:error, reason}` - Command failed, robot transitions to `:idle`