BB.Actuator.Server (bb v0.31.2)

Copy Markdown View Source

Wrapper GenServer for actuator callback modules.

This module manages the lifecycle of user-defined actuator modules, handling:

  • Parameter reference resolution at startup
  • Subscription to parameter changes
  • Subscription to the actuator's own command topic
  • Delegation of GenServer callbacks to user module
  • Automatic safety registration

User modules implement the BB.Actuator behaviour and define callbacks. This server wraps them, providing the actual GenServer implementation.

The inbound command pipeline

Commands reach an actuator by three transports - published to [:actuator | path], cast via BB.Process.cast/3, or called via BB.Process.call/4. All three converge here and pass through the same checks before the driver sees them:

  1. The actuator must accept the payload — see BB.Actuator.command_payloads/1. A driver is never handed a command it didn't declare, so it can't be crashed by one it has no clause for.
  2. The robot must be armed.
  3. The command must carry the current arm epoch — see BB.Safety.epoch/1. BB.Actuator's send functions stamp it; a command built by hand and delivered straight to an actuator carries none and is refused. This is what stops a command outliving the arming session that authorised it, which the armed check alone cannot see.
  4. The payload is translated from joint-space into motor-space using the joint's transmission.

The driver then receives it in BB.Actuator.handle_command/2, and its reply is routed back to whichever transport delivered the command. Messages from topics the driver subscribed to itself are not part of this pipeline - they reach BB.Actuator.handle_info/2 untouched.

Reporting a refusal

Only the call transport can answer its caller directly. A cast may name a process to be told about a refusal, which BB.Actuator's reply_on_reject?: true uses: the command arrives as {:command, message, reply_to}, and a refusal sends

{:bb, :command_rejected, actuator_name, command_id, error}

to reply_to. nil there means nobody is listening, which is the case for every published command - the topic has no one caller to answer.

Summary

Functions

Returns a specification to start this module under a supervisor.

Types

t()

@type t() :: %BB.Actuator.Server{
  actuator_name: atom() | nil,
  bb: %{robot: module(), path: [atom()]},
  callback_module: module(),
  command_payloads: [module()],
  command_topic: [atom()],
  joint: map() | nil,
  joint_name: atom() | nil,
  param_subscriptions: %{required([atom()]) => atom()},
  raw_opts: keyword(),
  resolved_opts: keyword(),
  transmission: BB.Transmission.t() | nil,
  transmission_subscriptions: %{required(atom()) => [atom()]},
  user_state: term()
}

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.