Skip to content

feat: add param() references and wrapper GenServer pattern#19

Merged
jimsynz merged 3 commits intomainfrom
feature/start-link-params
Dec 24, 2025
Merged

feat: add param() references and wrapper GenServer pattern#19
jimsynz merged 3 commits intomainfrom
feature/start-link-params

Conversation

@jimsynz
Copy link
Contributor

@jimsynz jimsynz commented Dec 24, 2025

Summary

  • Add param() references in actuator/sensor/controller options with automatic resolution and runtime updates
  • Add param() references for topology fields (joint limits, link origins, etc.)
  • Allow setting parameter values via start_link options
  • Implement wrapper GenServer pattern for actuators, sensors, and controllers

Wrapper GenServer Pattern

User modules now define callbacks only. Framework-controlled wrapper GenServers (BB.Actuator.Server, BB.Sensor.Server, BB.Controller.Server) manage the process lifecycle and delegate to user callbacks.

# Before: User modules ARE GenServers
defmodule MyActuator do
  use BB.Actuator
  @impl GenServer
  def init(opts), do: ...
end

# After: User modules define callbacks only
defmodule MyActuator do
  use BB.Actuator,
    options_schema: [pin: [type: :pos_integer, required: true]]

  @impl BB.Actuator
  def init(opts), do: ...

  @impl BB.Actuator
  def handle_options(new_opts, state), do: {:ok, state}
end

param() References

Parameters can now be referenced in actuator/sensor/controller options:

parameters do
  parameter [:motion, :max_effort], type: :float, default: 1.0
end

joint :shoulder do
  actuator :motor, {MyMotor, max_effort: param([:motion, :max_effort])}
end

When the parameter changes, the actuator's handle_options/2 callback is invoked.

Breaking Changes

  • @impl GenServer@impl BB.Actuator (or Controller/Sensor) for all callbacks
  • options_schema moved from callback to use macro option
  • Safety registration remains explicit via BB.Safety.register/2 in init/1

Test plan

  • All 529 tests passing
  • Verified param() resolution in child specs
  • Verified handle_options callback on param changes
  • Updated bb_servo_pigpio, bb_servo_pca9685, bb_servo_robotis (separate PRs)

Adds support for passing parameter overrides when starting a robot:

```elixir
# config/runtime.exs
config :my_app, MyRobot,
  params: [motion: [max_speed: 2.0]]

# application.ex
opts = Application.get_env(:my_app, MyRobot, [])
{BB.Supervisor, {MyRobot, opts}}
```

Priority order: DSL defaults → persisted values → start_link params

- Add `BB.Parameter.Schema` module for building nested Spark.Options
  schemas from flat parameter definitions
- Validate params in `Runtime.init/1` using Spark.Options
- Return `{:stop, reason}` on validation failure
- Add `:startup` source to `BB.Parameter.Changed` message
- Fix lifecycle test expecting wrong state transition for disarm command
Allow DSL topology fields (joint limits, origins, dynamics, etc.) to
reference runtime parameters instead of literal unit values:

```elixir
parameters do
  group :motion do
    param :max_effort, type: {:unit, :newton_meter}, default: ~u(10 newton_meter)
  end
end

topology do
  link :base do
    joint :shoulder do
      limit do
        effort(param([:motion, :max_effort]))
      end
    end
  end
end
```

Features:
- Compile-time validation that referenced parameters exist
- Unit type compatibility checking between param and field
- Runtime resolution at robot startup
- Automatic subscription to parameter changes
- Robot struct updates when parameters change

New modules:
- `BB.Dsl.ParamRef` - struct for parameter references
- `BB.Robot.ParamResolver` - runtime resolution and updates
- `BB.Dsl.Verifiers.ValidateParamRefs` - compile-time validation
- `BB.Parameter.Type` - parameter type validation (refactored from DSL)
…ions

Implement wrapper GenServer pattern for actuators, sensors, and controllers.
User modules now define callbacks only - the framework provides wrapper
GenServers that manage parameter resolution and subscriptions.

Changes:
- Add `BB.Actuator.Server`, `BB.Sensor.Server`, `BB.Controller.Server`
  wrapper GenServers that delegate to user callback modules
- Update behaviours to define callbacks without `use GenServer`
- Add `handle_options/2` callback for reacting to parameter changes
- Import `BB.Dsl.ParamRef` in actuator/sensor/controller DSL entities
- Allow `param([...])` references in child_spec options
- Remove component-level parameters feature (wasn't needed)
- Update supervisors to use wrapper servers via `BB.Process.child_spec/5`

When a parameter changes, the wrapper re-resolves all param refs and
calls `handle_options/2` with the new resolved options.

Safety registration remains explicit - users call `BB.Safety.register/2`
in their `init/1` with the opts needed for stateless `disarm/1`.
@jimsynz jimsynz merged commit 8d9f50c into main Dec 24, 2025
14 checks passed
@jimsynz jimsynz deleted the feature/start-link-params branch December 24, 2025 07:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant