Current section

Files

Jump to
bb_servo_pigpio usage-rules.md
Raw

usage-rules.md

<!--
SPDX-FileCopyrightText: 2026 James Harton
SPDX-License-Identifier: Apache-2.0
-->
# BB.Servo.Pigpio Usage Rules
`bb_servo_pigpio` provides `BB.Servo.Pigpio.Actuator`, a `BB.Actuator`
implementation that drives an RC servo from a Raspberry Pi GPIO pin via the
`pigpiod` daemon (over `pigpiox`) for [Beam Bots](https://hexdocs.pm/bb). For BB
framework basics, see `bb`'s rules (`mix usage_rules.sync <file> bb:all`); this
file covers only what's specific to this driver.
## Core principles
1. **It is a per-joint actuator, not a robot-level controller.** There is no bus
manager to declare — `pigpiod` is the "bus". Attach the actuator directly to
the joint it drives; the framework wraps it in `BB.Actuator.Server` and
supervises it for you.
2. **Configuration is derived from the joint, not the actuator options.** The
servo's travel and speed come from the joint's `limit` (lower, upper,
velocity) via the injected `motor_profile`. You do not set a rotation range
or speed on the actuator. The lower/upper limits map linearly onto the pulse
range; the velocity limit sets the motion timing.
3. **It drives real hardware.** `pigpiod` must be running on the target host
(`sudo pigpiod`), and `disarm/1` cuts the PWM output (pulse width `0`). Under
simulation the framework swaps in `BB.Sim.Actuator`, so no Pi is required to
run the robot in sim.
## Wiring it in
Attach the actuator to a `revolute`/`prismatic` joint, paired with the core
open-loop estimator for position feedback (RC servos have no feedback of their
own):
```elixir
joint :shoulder do
type :revolute
limit lower: ~u(-45 degree), upper: ~u(45 degree),
velocity: ~u(60 degree_per_second), effort: ~u(1 newton_meter)
actuator :servo, {BB.Servo.Pigpio.Actuator, pin: 17}
sensor :feedback, {BB.Sensor.OpenLoopPositionEstimator, actuator: :servo}
end
```
The joint **must** define lower, upper, and velocity limits — the actuator
refuses to start (`BB.Error.Invalid.JointConfig`) without them.
Once the robot is **armed** (see `bb:safety-and-commands`), command it in
joint-space through `BB.Actuator`; the framework applies the joint transmission
and hands the driver motor-space values:
```elixir
# Either the actuator's unique name or its full path — `[:base, :shoulder, :servo]`
# here. A partial path matches no subscriber and the command goes nowhere.
BB.Actuator.set_position(MyRobot.Robot, :servo, 0.5)
```
## Options
Passed in the `{Module, opts}` tuple.
| Option | Default | Meaning |
|---|---|---|
| `:pin` | required | Broadcom GPIO pin number for the PWM output |
| `:min_pulse` | `500` | Pulse width (µs) mapped to the joint's lower limit |
| `:max_pulse` | `2500` | Pulse width (µs) mapped to the joint's upper limit |
| `:update_speed` | `~u(50 hertz)` | PWM update frequency (a `~u` unit value) |
`:min_pulse`/`:max_pulse` are per-servo hardware calibration — adjust them to
match the datasheet, not to change the joint's range.
## Anti-patterns
- **Don't declare it as a `controller` or invent a bus manager.** It is a
`BB.Actuator` on a joint. `pigpiod` is a system daemon the driver talks to
directly; there is no robot-level process to add.
- **Don't put the servo's travel range or speed on the actuator.** Those come
from the joint `limit`. To reverse direction, use the joint's `transmission`
(`reversed?`), not an actuator option — there is no `reverse?` option.
- **Don't skip `pigpiod` or arming.** `init/1` opens the pin through the daemon,
so it must be running first; and a disarmed robot ignores motion commands —
arm before you expect the servo to move.
## Further reading
- [bb_servo_pigpio docs](https://hexdocs.pm/bb_servo_pigpio)
- `bb`'s actuator and safety rules (`bb:actuators`, `bb:safety-and-commands`)
and [Writing an Actuator](https://hexdocs.pm/bb/12-writing-an-actuator.html)