ETS-backed mutable state for robot instances.
This module manages joint configurations, velocities, and computed transforms for robot instances. Each robot instance has its own ETS table for concurrent read access.
Configurations, not positions
A joint's configuration is a point in its own configuration space, and its shape depends on the joint's type:
| Joint type | DoF | Configuration | Velocity |
|---|---|---|---|
:fixed | 0 | 0.0, the only one it has | 0.0 |
:revolute, :continuous | 1 | float angle in radians | float rad/s |
:prismatic | 1 | float displacement in metres | float m/s |
:planar | 3 | BB.Math.Transform2D | BB.Message.Geometry.Twist2D |
:floating | 6 | BB.Math.Transform | BB.Message.Geometry.Twist |
"Position" is the wrong word for a 4x4 homogeneous transform, which is why these functions say "configuration" — the standard term for a point in a robot's configuration space, and correct for every joint type.
Writes are whole-configuration and atomic. There is no API for setting part of a floating joint, because a partial update invites inconsistent intermediate states and the natural producer of such a configuration is an estimator emitting a complete pose.
A fixed joint has zero degrees of freedom, so its configuration space is a
single point and 0.0 is the only value it accepts. It is still present in
get_all_configurations/1 so that map can be handed straight back to
set_configurations/2.
Usage
# Create state for a robot instance
{:ok, state} = BB.Robot.State.new(robot)
# Set/get a joint configuration
:ok = BB.Robot.State.set_configuration(state, :shoulder, 0.5)
{:ok, angle} = BB.Robot.State.get_configuration(state, :shoulder)
# Get every joint's configuration as a map
configurations = BB.Robot.State.get_all_configurations(state)
# Clean up when done
:ok = BB.Robot.State.delete(state)
Summary
Functions
Delete a state table and free resources.
Find the schema that applies to a given parameter path.
Get every joint's configuration as a map.
Get every joint's velocity as a map.
Get the configurations of joints along a path from root to a target link.
Get the current configuration of a joint.
Get a parameter value by path.
Get the registered schema for a path prefix.
Get the current robot state machine state.
Get the current velocity of a joint.
List all parameters, optionally filtered by path prefix.
Create a new state table for a robot.
Register a parameter schema for a component path.
Reset all joints to their identity configurations and zero velocities.
Set the configuration of a joint.
Set multiple joint configurations at once.
Set a parameter value by path.
Set multiple parameters atomically.
Set the robot state machine state.
Set multiple joint velocities at once.
Set the velocity of a joint.
Types
@type configuration() :: float() | BB.Math.Transform2D.t() | BB.Math.Transform.t()
A joint's configuration, shaped to its type.
See the module documentation for which shape belongs to which joint type.
@type t() :: %BB.Robot.State{robot: BB.Robot.t(), table: :ets.table()}
@type velocity() :: float() | BB.Message.Geometry.Twist2D.t() | BB.Message.Geometry.Twist.t()
A joint's velocity, shaped to its type.
Functions
@spec delete(t()) :: :ok
Delete a state table and free resources.
@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.
@spec get_all_configurations(t()) :: %{required(atom()) => configuration()}
Get every joint's configuration as a map.
Every joint in the robot is present, shaped to its own type.
Examples
iex> BB.Robot.State.get_all_configurations(state)
%{shoulder: 0.5, elbow: -0.2, base: %BB.Math.Transform{}}
Get every joint's velocity as a map.
@spec get_chain_configurations(t(), atom()) :: [{atom(), configuration()}]
Get the configurations of joints along a path from root to a target link.
Returns a list of {joint_name, configuration} tuples in traversal order.
@spec get_configuration(t(), atom()) :: {:ok, configuration()} | {:error, BB.Error.Kinematics.UnknownJoint.t()}
Get the current configuration of a joint.
Examples
{:ok, 0.5} = BB.Robot.State.get_configuration(state, :shoulder)
{:ok, %BB.Math.Transform{}} = BB.Robot.State.get_configuration(state, :base)
Get a parameter value by path.
Returns {:ok, value} if the parameter exists, {:error, :not_found} otherwise.
@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 the current robot state machine state.
Returns the state atom (e.g., :disarmed, :idle, :executing).
@spec get_velocity(t(), atom()) :: {:ok, velocity()} | {:error, BB.Error.Kinematics.UnknownJoint.t()}
Get the current velocity of a joint.
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.
@spec new(BB.Robot.t()) :: {:ok, t()}
Create a new state table for a robot.
Returns {:ok, state} on success.
@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.
@spec reset(t()) :: :ok
Reset all joints to their identity configurations and zero velocities.
@spec set_configuration(t(), atom(), configuration()) :: :ok | {:error, BB.Error.Kinematics.UnknownJoint.t() | BB.Error.Invalid.JointConfig.t()}
Set the configuration of a joint.
The value's shape must match the joint's type, so a BB.Math.Transform2D
aimed at a revolute joint is an error rather than a wrong pose.
Examples
:ok = BB.Robot.State.set_configuration(state, :shoulder, 0.5)
:ok = BB.Robot.State.set_configuration(state, :base, transform)
@spec set_configurations(t(), %{required(atom()) => configuration()}) :: :ok | {:error, BB.Error.Kinematics.UnknownJoint.t() | BB.Error.Invalid.JointConfig.t()}
Set multiple joint configurations at once.
Every value is validated before anything is written, so a rejected map leaves the table untouched rather than applying part of itself.
Examples
:ok = BB.Robot.State.set_configurations(state, %{
shoulder: 0.5,
elbow: -0.3,
base: transform
})
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 multiple parameters atomically.
This is a low-level function that does not validate or notify.
Set the robot state machine state.
@spec set_velocities(t(), %{required(atom()) => velocity()}) :: :ok | {:error, BB.Error.Kinematics.UnknownJoint.t() | BB.Error.Invalid.JointConfig.t()}
Set multiple joint velocities at once.
@spec set_velocity(t(), atom(), velocity()) :: :ok | {:error, BB.Error.Kinematics.UnknownJoint.t() | BB.Error.Invalid.JointConfig.t()}
Set the velocity of a joint.