An actuator that uses a Robotis controller to drive a Dynamixel servo.
Configuration is derived from the joint's motor_profile injected by
BB.Actuator.Server:
- Position limits from
motor_profile.motor_lower/motor_upper - Velocity limit from
motor_profile.motor_velocity_limit - Position range maps to the servo's goal_position register
When initialised, the actuator:
- Disables torque on the servo
- Asks the servo what model it is, and sets its operating mode if it isn't already in the configured one
- Registers with the controller, receiving the shared ETS table reference
- Writes
profile_velocityfrom the joint's velocity limit - Subscribes to the commands its mode admits
Operating modes
A Dynamixel does one thing at a time, and :mode picks which. It's set once at
startup and never changed while running: switching modes resets the servo's PID
gains, its profile velocity and acceleration to 0, and its goal current to the
current limit — including tuning applied through
BB.Servo.Robotis.Bridge, which this driver has no way to put back.
:mode | commands it accepts |
|---|---|
:position (default) | Position, Hold, Stop |
:velocity | Velocity, Hold, Stop |
:current | Effort, Stop |
:current_position | Position, Effort, Hold, Stop |
Anything outside that list is refused by the framework with
BB.Error.State.UnsupportedCommand before it reaches the driver. Hold is
absent from :current because a servo in current control is a torque source
with no position to hold.
Not every servo implements every mode — an XL430 has no current control at all
— so the mode is checked against the model the servo reports, and the actuator
refuses to start rather than run in a mode nobody asked for. See
BB.Servo.Robotis.Model.
Commands
Command.Position— travel to a position. Clamped to the joint's limits.Command.Velocity— turn at a rate, clamped to the joint's velocity limit.Command.Effort— in:currentmode, the torque to aim for; in:current_positionmode, a ceiling on the current a position move may draw. Newton metres are converted using the model's published torque constant, which is quoted at the recommended supply voltage and drifts with it — treat effort as approximate rather than calibrated.Command.Stop— cut torque, leaving the joint passive and free to be backdriven. Both:immediateand:deceleratedo the same thing, because becoming passive is a single register write with no ramp available.Command.Hold— stay under power without driving. A servo already doing that needs nothing; after aStopit re-applies torque where the joint has come to rest.
A Position, Velocity or Effort command sent to a joint left passive by
Stop re-applies torque on the way past, so callers don't have to pair the two.
Velocity and Effort carry a duration. When it runs out, :expiry_action
decides whether the joint goes passive (:stop, the default) or stays under
power without driving (:hold) — the same choice the controller's
:disarm_action makes for the whole bus.
Beware that a passive joint under load will move, and Stop does not wait for
it to settle. Hold and Position both re-apply torque from the servo's own
present position, so neither snaps back to a pre-Stop goal, but a joint that
has sagged will still be somewhere the caller may not expect.
None of this is the safety path: making the hardware safe is disarm/1, which
is robot-wide and leaves the robot unable to move until it is armed again.
Example DSL Usage
controllers do
controller :dynamixel, {BB.Servo.Robotis.Controller,
port: "/dev/ttyUSB0",
baud_rate: 1_000_000
}
end
joint :shoulder, type: :revolute do
limit lower: ~u(-90 degree), upper: ~u(90 degree), velocity: ~u(60 degree_per_second)
actuator :servo, {BB.Servo.Robotis.Actuator, servo_id: 1, controller: :dynamixel}
end
Summary
Functions
Safety disarm callback.