# `BB.Robot.State`
[🔗](https://github.com/beam-bots/bb/blob/main/lib/bb/robot/state.ex#L5)

ETS-backed mutable state for robot instances.

This module manages joint positions, velocities, and computed transforms
for robot instances. Each robot instance has its own ETS table for
concurrent read access.

## State Structure

For each joint, the following state is stored:
- `position`: current joint position (radians for revolute, meters for prismatic)
- `velocity`: current joint velocity (rad/s or m/s)

## Usage

    # Create state for a robot instance
    {:ok, state} = BB.Robot.State.new(robot)

    # Set/get joint positions
    :ok = BB.Robot.State.set_joint_position(state, :shoulder, 0.5)
    pos = BB.Robot.State.get_joint_position(state, :shoulder)

    # Get all joint positions as a map
    positions = BB.Robot.State.get_all_positions(state)

    # Clean up when done
    :ok = BB.Robot.State.delete(state)

# `t`

```elixir
@type t() :: %BB.Robot.State{robot: BB.Robot.t(), table: :ets.table()}
```

# `delete`

```elixir
@spec delete(t()) :: :ok
```

Delete a state table and free resources.

# `find_schema_for_parameter`

```elixir
@spec find_schema_for_parameter(t(), [atom()]) ::
  {:ok, [atom()], Spark.Options.t()} | {:error, :not_found}
```

Find the schema that applies to a given parameter path.

Searches for the longest matching schema prefix.

# `get_all_positions`

```elixir
@spec get_all_positions(t()) :: %{required(atom()) =&gt; float()}
```

Get all joint positions as a map.

## Examples

    iex> positions = BB.Robot.State.get_all_positions(state)
    %{shoulder: 0.0, elbow: 0.5, wrist: -0.3}

# `get_all_velocities`

```elixir
@spec get_all_velocities(t()) :: %{required(atom()) =&gt; float()}
```

Get all joint velocities as a map.

# `get_chain_positions`

```elixir
@spec get_chain_positions(t(), atom()) :: [{atom(), float()}]
```

Get the positions of joints along a path from root to a target link.

Returns a list of {joint_name, position} tuples in traversal order.

# `get_joint_position`

```elixir
@spec get_joint_position(t(), atom()) :: float() | nil
```

Get the current position of a joint.

Returns `nil` if the joint doesn't exist.

# `get_joint_velocity`

```elixir
@spec get_joint_velocity(t(), atom()) :: float() | nil
```

Get the current velocity of a joint.

Returns `nil` if the joint doesn't exist.

# `get_parameter`

```elixir
@spec get_parameter(t(), [atom()]) :: {:ok, term()} | {:error, :not_found}
```

Get a parameter value by path.

Returns `{:ok, value}` if the parameter exists, `{:error, :not_found}` otherwise.

# `get_parameter_schema`

```elixir
@spec get_parameter_schema(t(), [atom()]) ::
  {:ok, Spark.Options.t()} | {:error, :not_found}
```

Get the registered schema for a path prefix.

Returns `{:ok, schema}` if found, `{:error, :not_found}` otherwise.

# `get_robot_state`

```elixir
@spec get_robot_state(t()) :: atom()
```

Get the current robot state machine state.

Returns the state atom (e.g., `:disarmed`, `:idle`, `:executing`).

# `list_parameters`

```elixir
@spec list_parameters(t(), [atom()]) :: [{[atom()], map()}]
```

List all parameters, optionally filtered by path prefix.

Returns a list of `{path, metadata}` tuples where metadata includes
the current value and schema information if registered.

# `new`

```elixir
@spec new(BB.Robot.t()) :: {:ok, t()}
```

Create a new state table for a robot.

Returns `{:ok, state}` on success.

# `register_parameter_schema`

```elixir
@spec register_parameter_schema(t(), [atom()], Spark.Options.t()) :: :ok
```

Register a parameter schema for a component path.

The schema is stored and used for validation and metadata.

# `reset`

```elixir
@spec reset(t()) :: :ok
```

Reset all joints to their default positions (0.0).

# `set_joint_position`

```elixir
@spec set_joint_position(t(), atom(), float()) :: :ok
```

Set the position of a joint.

# `set_joint_velocity`

```elixir
@spec set_joint_velocity(t(), atom(), float()) :: :ok
```

Set the velocity of a joint.

# `set_parameter`

```elixir
@spec set_parameter(t(), [atom()], term()) :: :ok
```

Set a parameter value by path.

This is a low-level function that does not validate or notify.
Use `BB.Parameter.set/3` for the validated, notifying version.

# `set_parameters`

```elixir
@spec set_parameters(t(), [{[atom()], term()}]) :: :ok
```

Set multiple parameters atomically.

This is a low-level function that does not validate or notify.

# `set_positions`

```elixir
@spec set_positions(t(), %{required(atom()) =&gt; float()}) :: :ok
```

Set multiple joint positions at once.

## Examples

    :ok = BB.Robot.State.set_positions(state, %{
      shoulder: 0.5,
      elbow: -0.3,
      wrist: 0.0
    })

# `set_robot_state`

```elixir
@spec set_robot_state(t(), atom()) :: :ok
```

Set the robot state machine state.

# `set_velocities`

```elixir
@spec set_velocities(t(), %{required(atom()) =&gt; float()}) :: :ok
```

Set multiple joint velocities at once.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
