Expand description
A device abstraction for hobby servos on ESP LEDC PWM.
This module provides both direct servo control (servo!) and
servo animationl (servo_player!).
Use servo! for a keyword-driven typed constructor.
After reading the examples below, see also:
servo!— Direct servo control without animation support.servo_player!— Macro to generate a servo player struct type (includes syntax details). SeeServoPlayerGeneratedfor a sample of a generated type.combine!&linear— Macro and function for creating complex motion sequences.Servo— Trait defining core methods and constants for direct servo control.ServoPlayer— Trait defining core methods and constants for animatable servos.
§How Servos Work
When you call set_degrees(45), the microcontroller starts sending a LEDC control
signal to the servo, telling it to move to and hold at 45 degrees. The hardware generates this control
signal automatically in the background, taking no CPU time. The control signal remains active until
you change it or call relax().
The servo itself has no idea what angle it is currently at. It simply moves as fast as it can
to match whatever angle the current control signal specifies. The library does not, and cannot, wait
for the servo to reach a position. This is why you must wait (for example, using Timer::after())
after calling set_degrees() to give the servo time to physically reach the target position.
This device abstraction, servo_player, adds a background software task around the hardware
control signal.
§Controlling Multiple Servos
Supports multiple servos, where each servo consumes one LEDC timer resource and one LEDC channel resource. The macro-generated link-time ownership claims enforce this exclusivity so duplicate timer/channel selections fail at link time.
§Example: Basic Servo Control
This example demonstrates basic servo control: moving to a position, relaxing,
and using animation. Here, the generated struct type is named Servo11.
use device_envoy_esp::{Result, init_and_start, servo::{Servo as _, servo}};
use embassy_time::{Duration, Timer};
servo! {
Servo11 {
pin: GPIO11,
timer: Timer0,
channel: Channel0,
}
}
async fn inner_main() -> Result<Infallible> {
init_and_start!(p, ledc: ledc);
let servo11 = Servo11::new(&ledc, p.GPIO11)?;
servo11.set_degrees(45);
Timer::after(Duration::from_secs(1)).await;
servo11.relax();
core::future::pending().await
}§Example: Multi-Step Animation
This example combines 40 animation steps using linear and combine! to
sweep up, hold, sweep down, hold pattern. Here, the generated struct type is named
ServoSweep.
use device_envoy_esp::{Result, init_and_start, servo::{AtEnd, Servo as _, ServoPlayer as _, combine, linear, servo_player}};
use embassy_time::Duration;
servo_player! {
ServoSweep {
pin: GPIO12,
timer: Timer1,
channel: Channel1,
max_steps: 40,
}
}
async fn inner_main(spawner: embassy_executor::Spawner) -> Result<Infallible> {
init_and_start!(p, ledc: ledc);
let servo_sweep = ServoSweep::new(&ledc, p.GPIO12, spawner)?;
const STEPS: [(u16, Duration); 40] = combine!(
linear::<19>(0, 180, Duration::from_secs(2)),
[(180, Duration::from_millis(400))],
linear::<19>(180, 0, Duration::from_secs(2)),
[(0, Duration::from_millis(400))]
);
servo_sweep.animate(STEPS, AtEnd::Loop);
core::future::pending().await
}Modules§
- servo_
player_ generated - Sample generated servo-player type documentation.
Macros§
- combine
- Combine multiple animation step arrays into one larger array.
- servo
- Macro to generate a direct-servo struct type (includes syntax details).
- servo_
player - Macro to generate a servo player struct type (includes syntax details).
Structs§
- Servo
Static - LEDC-backed servo static resources and motion configuration.
Enums§
- AtEnd
- Animation end behavior.
Constants§
- SERVO_
MAX_ US_ DEFAULT - Default maximum pulse width for hobby servos (microseconds).
- SERVO_
MIN_ US_ DEFAULT - Default minimum pulse width for hobby servos (microseconds).
Traits§
- Servo
- Platform-agnostic servo device contract.
- Servo
Player - Platform-agnostic servo-player device contract.