### Calculate Power Supply Requirements Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/README.md Example calculation for determining the total current and voltage requirements for a multi-servo setup. ```text Total Current ≥ 1 A Supply: 5–6 V, ≥1 A regulated ``` -------------------------------- ### Servo write() Usage Examples Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/servo-class.md Examples demonstrating angle control, microsecond pulse control, and continuous rotation servo operation. ```cpp #include Servo myServo; void setup() { myServo.attach(9); } void loop() { myServo.write(0); // Move to 0° delay(1000); myServo.write(90); // Move to 90° delay(1000); myServo.write(180); // Move to 180° delay(1000); } ``` ```cpp #include Servo myServo; void setup() { myServo.attach(9); } void loop() { // Directly control pulse width in microseconds myServo.write(1500); // Mid-point (standard) delay(500); myServo.write(1000); // Full counter-clockwise delay(500); myServo.write(2000); // Full clockwise delay(500); } ``` ```cpp #include Servo continuousServo; void setup() { continuousServo.attach(9); } void loop() { continuousServo.write(90); // Stop delay(1000); continuousServo.write(45); // Reverse half-speed delay(1000); continuousServo.write(135); // Forward half-speed delay(1000); } ``` -------------------------------- ### Servo writeMicroseconds() Usage Examples Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/servo-class.md Examples showing fine pulse control for sweeping and custom range calibration. ```cpp #include Servo myServo; void setup() { myServo.attach(9); // Default range 544–2400 µs } void loop() { // Sweep through full pulse range for (int us = 1000; us <= 2000; us += 10) { myServo.writeMicroseconds(us); delay(15); } delay(500); } ``` ```cpp #include Servo servo; void setup() { Serial.begin(9600); servo.attach(9, 900, 2100); // Custom range Serial.println("Enter microsecond value (900-2100):"); } void loop() { if (Serial.available()) { int us = Serial.parseInt(); if (us >= 900 && us <= 2100) { servo.writeMicroseconds(us); Serial.print("Servo set to: "); Serial.print(us); Serial.println(" µs"); } } } ``` -------------------------------- ### Minimal Servo Implementation Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/00-START-HERE.txt A basic example demonstrating how to include the library, instantiate a Servo object, attach it to a pin, and set a position. ```cpp #include Servo myServo; void setup() { myServo.attach(9); } void loop() { myServo.write(90); } ``` -------------------------------- ### Check Attachment Before Use Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/servo-class.md Example of using attached() to safely initialize a servo. ```cpp #include Servo myServo; void setup() { if (!myServo.attached()) { myServo.attach(9); } } void loop() { if (myServo.attached()) { myServo.write(90); } delay(1000); } ``` -------------------------------- ### Cross-Platform Microsecond Handling Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/servo-class.md Example showing how to retrieve microsecond values after a standard write call. ```cpp #include Servo servo; void setup() { Serial.begin(9600); servo.attach(9, 1000, 2000); // Custom calibration servo.write(90); // Write 90 degrees delay(50); int micros = servo.readMicroseconds(); Serial.print("90° = "); Serial.print(micros); Serial.println(" µs"); } void loop() { delay(1000); } ``` -------------------------------- ### Sub-Micro Servo Configuration Example Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/configuration.md Demonstrates attaching a sub-micro servo and writing positions to trigger specific pulse widths. ```cpp servo.attach(9, 900, 2100); servo.write(0); // Sends 900 µs pulse servo.write(180); // Sends 2100 µs pulse ``` -------------------------------- ### Initialize and Control Servo Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/README.md Basic setup and loop structure for moving a servo to a specific angle. ```cpp #include Servo myServo; void setup() { myServo.attach(9); // Attach to pin 9 } void loop() { myServo.write(90); // Move to 90 degrees delay(1000); } ``` -------------------------------- ### Track Servo State Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/servo-class.md Example showing how to track the state of multiple servos using read(). ```cpp #include Servo servo1, servo2; void setup() { servo1.attach(9); servo2.attach(10); } void loop() { servo1.write(0); servo2.write(180); delay(500); // Verify both servos moved to expected positions int pos1 = servo1.read(); // Returns 0 int pos2 = servo2.read(); // Returns 180 servo1.write(90); servo2.write(90); delay(500); } ``` -------------------------------- ### Safe Multiple Servo Management Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/servo-class.md Example of managing multiple servos using the attached() check. ```cpp #include Servo servos[3]; const int pins[3] = {9, 10, 11}; void setup() { for (int i = 0; i < 3; i++) { if (!servos[i].attached()) { servos[i].attach(pins[i]); } } } void loop() { for (int i = 0; i < 3; i++) { if (servos[i].attached()) { servos[i].write(i * 60); // 0°, 60°, 120° } } delay(500); } ``` -------------------------------- ### Microsecond Readback Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/servo-class.md Example of reading back the pulse width after a writeMicroseconds call. ```cpp #include Servo myServo; void setup() { Serial.begin(9600); myServo.attach(9); myServo.writeMicroseconds(1500); int us = myServo.readMicroseconds(); Serial.print("Last write (µs): "); Serial.println(us); // Approximately 1500 } void loop() { // Readback reflects last write delay(1000); } ``` -------------------------------- ### Initialize Multiple Servos Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/servo-class.md Demonstrates creating and attaching multiple servo instances to different digital pins. ```cpp #include Servo servo1; Servo servo2; void setup() { servo1.attach(9); servo2.attach(10); } void loop() { servo1.write(90); servo2.write(45); } ``` -------------------------------- ### Demonstrate Multiple Attach Calls Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/errors.md Shows the behavior of calling attach multiple times on the same Servo object. ```cpp Servo servo; void setup() { servo.attach(9); servo.attach(10); // Attach again to different pin } ``` -------------------------------- ### Out-of-Range Pin Assignment Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/errors.md Example of an invalid pin assignment that may fail silently due to internal bit-field limitations. ```cpp Servo servo; servo.attach(99); // Pin 99 likely doesn't exist ``` -------------------------------- ### Architecture Selection Logic Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/platform-implementations.md Uses preprocessor conditionals to include the appropriate timer configuration header based on the target architecture. ```cpp #if defined(ARDUINO_ARCH_AVR) #include "avr/ServoTimers.h" #elif defined(ARDUINO_ARCH_MEGAAVR) #include "megaavr/ServoTimers.h" #elif defined(ARDUINO_ARCH_SAM) #include "sam/ServoTimers.h" // ... (similar for other architectures) #endif ``` -------------------------------- ### Test Pin Functionality Before Attaching Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/README.md Verify that a specific pin is capable of outputting a signal before initializing the servo library on that pin. ```cpp // Verify pin can output before attaching servo const int TEST_PIN = 9; pinMode(TEST_PIN, OUTPUT); digitalWrite(TEST_PIN, HIGH); delay(500); digitalWrite(TEST_PIN, LOW); // If LED toggles or oscilloscope shows signal, pin works // Then attach servo ``` -------------------------------- ### Servo() Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/servo-class.md Constructor to create a new Servo object instance. ```APIDOC ## Servo() ### Description Creates a new Servo object. The servo is not yet attached to any pin; call attach() to activate it. ### Syntax Servo myServo; ### Return Value - Servo object instance ``` -------------------------------- ### Define ESP32 timer conversion macros Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/types.md Placeholder macros for LEDC-based time conversion on ESP32 hardware. ```cpp #define LEDC_US_TO_TICKS(duration_us) ... #define LEDC_TICKS_TO_US(ticks) ... ``` -------------------------------- ### Basic Servo Attachment Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/configuration.md Initializes a servo on a specified pin using default pulse width limits. ```cpp uint8_t attach(int pin); ``` -------------------------------- ### Demonstrate Silent Clamping Behavior Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/errors.md Shows how the library silently clamps out-of-range pulse width values to the user-specified min/max bounds. ```cpp servo.attach(9, 1000, 2000); servo.writeMicroseconds(500); // User tries to send 500 µs // Library clamps to 1000 µs (user-specified min) servo.writeMicroseconds(2500); // User tries to send 2500 µs // Library clamps to 2000 µs (user-specified max) ``` -------------------------------- ### Managing Timer Exhaustion Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/errors.md Illustrates the limit of servo attachments based on available hardware timers and a pattern for safe initialization. ```cpp Servo servo1, servo2, servo3, servo4; void setup() { servo1.attach(9); // Uses Timer 1, slot 0 servo2.attach(10); // Uses Timer 1, slot 1 servo3.attach(11); // Uses Timer 1, slot 2 // ... up to 12 servos servo4.attach(12); // Would require Timer 2 (if available) } ``` ```cpp const int MAX_SERVOS_SAFE = 10; // Leave 2-servo headroom Servo servos[MAX_SERVOS_SAFE]; void setup() { int attached = 0; for (int pin = 9; pin <= 9 + MAX_SERVOS_SAFE; pin++) { uint8_t ch = servos[attached].attach(pin); if (ch != INVALID_SERVO) { attached++; } else { Serial.println("Max servos reached"); break; } } } ``` -------------------------------- ### Design for platform limits Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/errors.md Use preprocessor directives to define the maximum number of servos based on the target board architecture. ```cpp #if defined(ARDUINO_AVR_MEGA) #define MAX_SERVOS_AVAILABLE 48 #elif defined(ARDUINO_SAMD_ZERO) #define MAX_SERVOS_AVAILABLE 24 #else #define MAX_SERVOS_AVAILABLE 12 #endif // Create only as many as platform supports Servo servos[MAX_SERVOS_AVAILABLE / 2]; // Half capacity as safety margin ``` -------------------------------- ### Configure ESP32 Servo Channel Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/configuration.md Initializes the LEDC PWM controller for a specific servo channel on ESP32 hardware. ```cpp // ESP32 setup per servo: ledcSetup(_channel, (1000000 / REFRESH_INTERVAL), LEDC_MAX_BIT_WIDTH); ledcAttachPin(pin, _channel); ``` -------------------------------- ### Initialize SAM Timer ISR Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/platform-implementations.md Configures the Timer Counter peripheral, enables the clock, and sets up the NVIC interrupt. ```cpp static void _initISR(Tc *tc, uint32_t channel, uint32_t id, IRQn_Type irqn) { pmc_enable_periph_clk(id); // Enable peripheral clock TC_Configure(tc, channel, TC_CMR_TCCLKS_TIMER_CLOCK3 | // Prescaler TC_CMR_WAVE | // Waveform mode TC_CMR_WAVSEL_UP_RC); // Count up, reset on match TC_SetRA(tc, channel, 2625); // 1 ms initial pulse NVIC_EnableIRQ(irqn); // Enable NVIC interrupt tc->TC_CHANNEL[channel].TC_IER = TC_IER_CPAS; // Enable RA compare TC_Start(tc, channel); // Start timer } ``` -------------------------------- ### Servo::attach() Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/INDEX.md Attaches the servo to a specific pin and initializes the PWM signal. Optionally allows setting custom pulse width bounds. ```APIDOC ## Servo::attach() ### Description Attaches the servo to a pin and initializes PWM. Returns the channel index or an error code on failure. ### Signature `uint8_t attach(int pin)` `uint8_t attach(int pin, int min, int max)` ### Returns - **uint8_t**: Channel index (0–MAX_SERVOS-1) or INVALID_SERVO (255) on failure. ``` -------------------------------- ### Verify Last Command Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/servo-class.md Demonstrates reading back the last angle written to a servo. ```cpp #include Servo myServo; void setup() { Serial.begin(9600); myServo.attach(9); myServo.write(45); delay(100); int lastAngle = myServo.read(); Serial.print("Last written angle: "); Serial.println(lastAngle); // Output: 45 } void loop() { // Read does not update; servo position is maintained } ``` -------------------------------- ### Initialize a single servo with error checking Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/usage-patterns.md Validates the attachment process using the INVALID_SERVO constant to ensure the pin was successfully configured. ```cpp #include Servo myServo; void setup() { uint8_t channel = myServo.attach(9); if (channel == INVALID_SERVO) { // Handle attach failure Serial.println("Error: servo attach failed"); while(1); } Serial.print("Servo attached to channel: "); Serial.println(channel); } void loop() { myServo.write(90); delay(1000); } ``` -------------------------------- ### Configure Architecture-Specific Timers Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/configuration.md Preprocessor directives used to include the correct timer definitions based on the target board architecture. ```cpp #if defined(ARDUINO_ARCH_AVR) #include "avr/ServoTimers.h" #elif defined(ARDUINO_ARCH_SAM) #include "sam/ServoTimers.h" #elif defined(ARDUINO_ARCH_SAMD) #include "samd/ServoTimers.h" #elif defined(ARDUINO_ARCH_STM32F4) #include "stm32f4/ServoTimers.h" #elif defined(ARDUINO_ARCH_NRF52) #include "nrf52/ServoTimers.h" // ... more platforms #else #error "This library only supports boards with ..." #endif ``` -------------------------------- ### Implement Clamping Detection and Logging Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/errors.md A wrapper function to validate pulse width values and log warnings before calling writeMicroseconds. ```cpp void writeWithLog(Servo& servo, int us, int min_us, int max_us) { if (us < min_us || us > max_us) { Serial.print("Warning: clamping "); Serial.print(us); Serial.print(" µs to ["); Serial.print(min_us); Serial.print(", "); Serial.print(max_us); Serial.println("]"); } servo.writeMicroseconds(us); } void setup() { servo.attach(9, 1000, 2000); writeWithLog(servo, 2500, 1000, 2000); // Warns before clamping } ``` -------------------------------- ### Resolving PWM Conflicts Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/errors.md Shows how Servo library usage can conflict with analogWrite() on specific pins and provides patterns to avoid these issues. ```cpp Servo servo; void setup() { servo.attach(9); // Seizes Timer1 analogWrite(9, 128); // Timer1 now managed by servo; PWM behavior undefined } ``` ```cpp void setup() { servo.attach(9); // Do NOT use analogWrite() on Timer1 pins (9, 10) // Use other timers or digital I/O with digitalWrite() pinMode(6, OUTPUT); // Timer4 (Mega example) analogWrite(6, 128); // Use only if servo not using Timer4 } ``` ```cpp // Reserve pins for servos; use other pins for PWM const int SERVO_PINS[] = {9, 10}; // Servo-controlled const int PWM_PINS[] = {3, 5, 6}; // For analogWrite() void setup() { for (int pin : SERVO_PINS) { // servo.attach(pin); } for (int pin : PWM_PINS) { analogWrite(pin, 128); } } ``` -------------------------------- ### Manage multiple servos with individual instances Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/usage-patterns.md Explicitly defines and attaches multiple servo instances, checking for errors on each individual attachment. ```cpp #include Servo servoLeft; Servo servoRight; Servo servoCenter; void setup() { if (servoLeft.attach(9) == INVALID_SERVO) return; if (servoRight.attach(10) == INVALID_SERVO) return; if (servoCenter.attach(11) == INVALID_SERVO) return; servoLeft.write(0); servoRight.write(180); servoCenter.write(90); } void loop() { // ... servo control } ``` -------------------------------- ### Configure Mega AVR Servo Timers Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/platform-implementations.md Defines the timer usage and sequence for Mega AVR architectures. ```cpp #define _useTimer1 typedef enum { _timer1, _Nbr_16timers } timer16_Sequence_t; ``` -------------------------------- ### Define SAM/SAMD timer conversion macros Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/types.md Macros for converting microseconds to ticks and vice versa using a 32x prescaler on SAM/SAMD architectures. ```cpp #define usToTicks(_us) (( clockCyclesPerMicrosecond() * _us) / 32) #define ticksToUs(_ticks) (( (unsigned)_ticks * 32)/ clockCyclesPerMicrosecond() ) ``` -------------------------------- ### Custom Pulse Range Attachment Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/configuration.md Initializes a servo on a specified pin with custom minimum and maximum pulse width values. ```cpp uint8_t attach(int pin, int min, int max); ``` -------------------------------- ### Implement Bounded Servo Writes Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/usage-patterns.md Wraps the standard write method to clamp input angles within the valid 0-180 degree range. ```cpp #include Servo servo; void safeWrite(int angle) { // Ensure angle is within bounds before writing if (angle < 0) angle = 0; if (angle > 180) angle = 180; servo.write(angle); } void setup() { servo.attach(9); } void loop() { safeWrite(-10); // Safely clamps to 0 delay(500); safeWrite(200); // Safely clamps to 180 delay(500); safeWrite(90); // Valid angle delay(500); } ``` -------------------------------- ### Define AVR timer conversion macros Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/types.md Macros for converting microseconds to ticks and vice versa using an 8x prescaler on AVR architectures. ```cpp #define usToTicks(_us) (( clockCyclesPerMicrosecond()* _us) / 8) #define ticksToUs(_ticks) (( (unsigned)_ticks * 8)/ clockCyclesPerMicrosecond() ) ``` -------------------------------- ### ESP32 Servo Implementation Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/platform-implementations.md Internal ServoImpl class using hardware LEDC channels for PWM generation on ESP32. ```cpp class ServoImpl { uint8_t pin; public: ServoImpl(const uint8_t _pin, const uint8_t _channel) { ledcSetup(_channel, (1000000 / REFRESH_INTERVAL), LEDC_MAX_BIT_WIDTH); ledcAttachPin(pin, _channel); } void set(const uint8_t _channel, const uint32_t duration_us) { ledcWrite(_channel, LEDC_US_TO_TICKS(duration_us)); } uint32_t get(const uint8_t _channel) const { return LEDC_TICKS_TO_US(ledcRead(_channel)); } }; ``` -------------------------------- ### Dynamic servo management Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/servo-class.md Shows how to toggle servo attachment status based on serial input. ```cpp #include Servo servo; bool servoActive = true; void setup() { Serial.begin(9600); servo.attach(9); } void loop() { if (Serial.available()) { char cmd = Serial.read(); if (cmd == '1' && !servoActive) { servo.attach(9); servoActive = true; Serial.println("Servo attached"); } else if (cmd == '0' && servoActive) { servo.detach(); servoActive = false; Serial.println("Servo detached"); } } if (servoActive) { servo.write(90); } delay(100); } ``` -------------------------------- ### Prevent Multiple Attach Issues Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/errors.md Best practice for switching pins by checking the attachment status and detaching before re-attaching. ```cpp Servo servo; void setup() { if (!servo.attached()) { servo.attach(9); } // Later, if you need to switch pins: if (servo.attached()) { servo.detach(); } servo.attach(10); } ``` -------------------------------- ### Instantiate a Servo Object Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/servo-class.md Creates a new Servo instance. The object remains inactive until the attach() method is called. ```cpp Servo myServo; ``` -------------------------------- ### Include Servo Library Source: https://github.com/arduino-libraries/servo/blob/master/docs/readme.md Include the Servo library to enable servo motor control functionality in your Arduino sketch. ```cpp #include ``` -------------------------------- ### Configure SAM Servo Timers Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/platform-implementations.md Defines the timer usage and sequence for SAM architectures, supporting up to 5 timers. ```cpp #define _useTimer1 #define _useTimer2 #define _useTimer3 #define _useTimer4 #define _useTimer5 typedef enum { _timer1, _timer2, _timer3, _timer4, _timer5, _Nbr_16timers } timer16_Sequence_t; ``` -------------------------------- ### Map servo index to timer Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/types.md Uses a macro to calculate the timer sequence based on the servo index and the number of servos per timer. ```cpp // Internal macro to determine which timer controls a servo index #define SERVO_INDEX_TO_TIMER(_servo_nbr) \ ((timer16_Sequence_t)(_servo_nbr / SERVOS_PER_TIMER)) // Example: servo #15 uses timer 1 (15 / 12 = 1) timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(15); ``` -------------------------------- ### Timer1 Initialization Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/platform-implementations.md Configures Timer1 registers for normal counting mode with an 8x prescaler and enables output compare interrupts. ```cpp TCCR1A = 0; // Normal counting mode TCCR1B = _BV(CS11); // Set prescaler to 8 TCNT1 = 0; // Clear timer counter TIFR1 |= _BV(OCF1A); // Clear pending interrupts TIMSK1 |= _BV(OCIE1A); // Enable Output Compare A interrupt ``` -------------------------------- ### Custom Servo Calibration with Pulse Ranges Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/usage-patterns.md Configures custom minimum and maximum pulse widths during attach to map the 0-180 degree range to specific hardware limits. ```cpp #include Servo servo; const int SERVO_PIN = 9; const int MIN_PULSE = 900; // Custom minimum const int MAX_PULSE = 2100; // Custom maximum void setup() { Serial.begin(9600); // Attach with custom pulse range servo.attach(SERVO_PIN, MIN_PULSE, MAX_PULSE); Serial.println("Servo calibrated to:"); Serial.print("Min: "); Serial.print(MIN_PULSE); Serial.print(" µs, Max: "); Serial.print(MAX_PULSE); Serial.println(" µs"); } void loop() { // Now write(0) sends MIN_PULSE, write(180) sends MAX_PULSE servo.write(0); delay(1000); servo.write(90); delay(1000); servo.write(180); delay(1000); } ``` -------------------------------- ### Control up to 12 Servos on Uno/Nano Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/usage-patterns.md Utilizes a single timer (Timer1) to support a maximum of 12 servos on ATmega328P based boards. ```cpp #include // Single timer (Timer1) supports 12 servos max Servo servos[12]; int servoCount = 0; void attachServo(int pin) { if (servoCount < 12) { if (servos[servoCount].attach(pin) != INVALID_SERVO) { servoCount++; Serial.print("Attached servo #"); Serial.println(servoCount - 1); } } else { Serial.println("Maximum servos (12) reached"); } } void setup() { Serial.begin(9600); attachServo(9); attachServo(10); } void loop() { // Control up to 12 servos for (int i = 0; i < servoCount; i++) { servos[i].write(90 + (i * 10)); } delay(500); } ``` -------------------------------- ### Monitor Servo Readback Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/errors.md Verifies that the servo position set via write() matches the value returned by read(). ```cpp servo.write(90); Serial.println(servo.read()); // Should return 90 ``` -------------------------------- ### Define ServoImpl class for ESP32 Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/types.md Internal class for managing ESP32 LEDC hardware interaction, including PWM frequency and duty-cycle management. ```cpp class ServoImpl { uint8_t pin; public: ServoImpl(const uint8_t _pin, const uint8_t _channel); ~ServoImpl(); void set(const uint8_t _channel, const uint32_t duration_us); uint32_t get(const uint8_t _channel) const; }; ``` -------------------------------- ### Ensure Servo Attachment Before Write Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/servo-class.md Always attach a servo before attempting to write a position to avoid undefined behavior. ```cpp Servo servo; // servo.write(90); // UNSAFE: servo not attached, behavior undefined servo.attach(9); servo.write(90); // SAFE: servo now attached ``` -------------------------------- ### Compile-Time Pin Constraints Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/errors.md Use preprocessor directives to ensure the correct pin is used based on the target board architecture. ```cpp #if defined(ARDUINO_AVR_UNO) const int SERVO_PIN = 9; // Only valid on Uno #elif defined(ARDUINO_AVR_MEGA2560) const int SERVO_PIN = 11; // Valid on Mega #endif servo.attach(SERVO_PIN); ``` -------------------------------- ### Handling Multiple Detach Calls Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/errors.md Demonstrates that calling detach() multiple times is safe and acts as a no-op. ```cpp Servo servo; void setup() { servo.attach(9); servo.detach(); servo.detach(); // Second detach } ``` ```cpp if (servo.attached()) { servo.detach(); } ``` -------------------------------- ### PWM Timer Management Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/configuration.md Demonstrates how attaching and detaching a servo affects the availability of analogWrite() on timer-controlled pins. ```cpp Servo servo; void setup() { // Pin 9 initially available for analogWrite() servo.attach(9); // Now pin 9 controlled by servo; analogWrite() fails servo.detach(); // Pin 9 again available; analogWrite() works } ``` -------------------------------- ### Implement RobustServo Wrapper for Arduino Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/usage-patterns.md A wrapper class that tracks attachment status and validates angles or pulse widths before sending commands to the servo. ```cpp #include class RobustServo { private: Servo servo; int pin; int lastWritten; bool attached; public: RobustServo(int p) : pin(p), lastWritten(-1), attached(false) {} bool initialize() { uint8_t ch = servo.attach(pin); if (ch == INVALID_SERVO) { Serial.print("FAIL: servo attach "); Serial.println(pin); return false; } attached = true; servo.write(90); // Safe initial position lastWritten = 90; return true; } bool write(int angle) { if (!attached) { Serial.println("ERROR: servo not attached"); return false; } if (angle < 0 || angle > 180) { Serial.print("ERROR: angle "); Serial.print(angle); Serial.println(" out of range"); return false; } if (angle == lastWritten) { return true; // No change, skip write } servo.write(angle); lastWritten = angle; return true; } bool writeMicroseconds(int us, int minUS = 544, int maxUS = 2400) { if (!attached) { Serial.println("ERROR: servo not attached"); return false; } if (us < minUS || us > maxUS) { Serial.print("ERROR: pulse "); Serial.print(us); Serial.print(" µs outside "); Serial.print(minUS); Serial.print("-"); Serial.println(maxUS); return false; } servo.writeMicroseconds(us); return true; } int read() { if (!attached) return -1; return servo.read(); } bool shutdown() { if (!attached) return true; servo.detach(); attached = false; return true; } bool isAttached() const { return attached; } }; RobustServo myServo(9); void setup() { Serial.begin(9600); if (!myServo.initialize()) { Serial.println("Servo init failed"); while(1); } } void loop() { if (myServo.write(90)) { delay(500); } else { Serial.println("Write failed"); } } ``` -------------------------------- ### Servo Library - writeMicroseconds() Source: https://github.com/arduino-libraries/servo/blob/master/docs/api.md Writes a value in microseconds to the servo, allowing for precise control over the shaft's position or speed. ```APIDOC ## Servo.writeMicroseconds() ### Description Writes a value in microseconds (us) to the servo, controlling the shaft accordingly. On a standard servo, this will set the angle of the shaft. On standard servos a parameter value of 1000 is fully counter-clockwise, 2000 is fully clockwise, and 1500 is in the middle. Note that some manufactures do not follow this standard very closely so that servos often respond to values between 700 and 2300. Feel free to increase these endpoints until the servo no longer continues to increase its range. Note however that attempting to drive a servo past its endpoints (often indicated by a growling sound) is a high-current state, and should be avoided. Continuous-rotation servos will respond to the writeMicrosecond function in an manner analogous to the write function. ### Syntax ``` servo.writeMicroseconds(us) ``` ### Parameters * **servo** (Servo) - a variable of type Servo * **us** (int) - the value of the parameter in microseconds (int) ### Request Example ```cpp #include Servo myservo; void setup() { myservo.attach(9); myservo.writeMicroseconds(1500); // set servo to mid-point } void loop() {} ``` ### See also * [attach()](#attach) * [read()](#read) ``` -------------------------------- ### Wiring Platform Interrupt Attachment Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/platform-implementations.md Uses the Wiring framework's custom interrupt attachment method when applicable. ```cpp #if defined(WIRING) timerAttach(TIMER1OUTCOMPAREA_INT, Timer1Service); #endif ``` -------------------------------- ### void writeMicroseconds(int value) Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/servo-class.md Directly sets the servo pulse width in microseconds, bypassing degree-to-microsecond conversion. ```APIDOC ## void writeMicroseconds(int value) ### Description Directly sets the servo pulse width in microseconds. This method bypasses the degree-to-microsecond conversion logic and is useful for precise control or calibration. ### Parameters - **value** (int) - Required - Pulse width in microseconds (typically 544–2400) ### Return Value None ``` -------------------------------- ### Mbed PwmOut Implementation Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/platform-implementations.md Uses the Mbed PwmOut API to set the period and duty cycle for servo control. ```cpp PwmOut servo_pwm(pin); servo_pwm.period(0.020f); // 20 ms period servo_pwm.write(duty_cycle); // 0.0–1.0 ``` -------------------------------- ### Internal Pin Configuration Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/configuration.md The library automatically sets the pin to output mode when attach() is invoked. ```cpp pinMode(pin, OUTPUT); // Called internally in attach() ``` -------------------------------- ### Control up to 16 Servos on ESP32 Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/usage-patterns.md Uses the LEDC peripheral to support up to 16 servos on ESP32 hardware. ```cpp #include Servo servos[16]; // ESP32 LEDC limit int servoCount = 0; void attachServo(int pin) { if (servoCount < 16) { if (servos[servoCount].attach(pin) != INVALID_SERVO) { Serial.print("Servo #"); Serial.print(servoCount); Serial.print(" on GPIO "); Serial.println(pin); servoCount++; } } else { Serial.println("Maximum ESP32 servos (16) reached"); } } void setup() { Serial.begin(115200); // Attach servos to GPIO pins attachServo(25); attachServo(26); attachServo(27); } void loop() { for (int i = 0; i < servoCount; i++) { servos[i].write(90); } delay(1000); } ``` -------------------------------- ### Attach Servo with Error Handling Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/servo-class.md Attaches a servo to a pin and verifies the assignment by checking the returned channel index against INVALID_SERVO. ```cpp uint8_t attach(int pin); ``` ```cpp #include Servo myServo; void setup() { uint8_t channel = myServo.attach(9); if (channel != INVALID_SERVO) { Serial.print("Servo attached to channel: "); Serial.println(channel); } } void loop() { myServo.write(90); delay(1000); } ``` -------------------------------- ### void write(int value) Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/servo-class.md Commands the servo to move to a specified angle (0–180 degrees) or pulse width in microseconds. ```APIDOC ## void write(int value) ### Description Commands the servo to move to a specified angle (0–180 degrees) or pulse width. Values less than 544 are treated as degrees, while values 544 and greater are treated as microseconds. ### Parameters - **value** (int) - Required - Angle (0–180°) or pulse width (544–2400+ µs) ### Return Value None ``` -------------------------------- ### Direct Microsecond Control with Servo Library Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/usage-patterns.md Uses writeMicroseconds to control servo position directly via pulse width rather than degrees. Useful for precise control outside the standard 0-180 degree range. ```cpp #include Servo servo; void setup() { Serial.begin(9600); servo.attach(9); Serial.println("Servo microsecond control demo"); } void loop() { // Sweep using microseconds instead of degrees for (int us = 1000; us <= 2000; us += 10) { servo.writeMicroseconds(us); Serial.print(us); Serial.print(" µs -> "); Serial.print(servo.read()); Serial.println(" degrees"); delay(50); } delay(500); // Return to center servo.writeMicroseconds(1500); delay(500); } ``` -------------------------------- ### Smooth Continuous Sweep Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/usage-patterns.md Implement a continuous sweep using a state-based approach to handle direction changes at boundaries. ```cpp #include Servo servo; const int MIN_ANGLE = 0; const int MAX_ANGLE = 180; const int INCREMENT = 2; const int DELAY_MS = 30; int currentAngle = MIN_ANGLE; int direction = INCREMENT; // 1 = forward, -1 = backward void setup() { servo.attach(9); servo.write(currentAngle); } void loop() { currentAngle += direction; // Reverse direction at boundaries if (currentAngle >= MAX_ANGLE) { direction = -INCREMENT; currentAngle = MAX_ANGLE; } else if (currentAngle <= MIN_ANGLE) { direction = INCREMENT; currentAngle = MIN_ANGLE; } servo.write(currentAngle); delay(DELAY_MS); } ``` -------------------------------- ### Simple Sweep Motion Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/usage-patterns.md Perform a basic back-and-forth sweep between 0 and 180 degrees using a loop. ```cpp #include Servo myServo; void setup() { myServo.attach(9); } void loop() { // Sweep from 0 to 180 degrees for (int angle = 0; angle <= 180; angle += 1) { myServo.write(angle); delay(15); // 15 ms per degree = 2.7 seconds for full sweep } // Sweep back from 180 to 0 degrees for (int angle = 180; angle >= 0; angle -= 1) { myServo.write(angle); delay(15); } } ``` -------------------------------- ### Handling Maximum Servo Limits Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/configuration.md Check the return value of attach() to determine if the maximum number of supported servos has been reached. ```cpp uint8_t channel = servo.attach(9); if (channel == INVALID_SERVO) { // All MAX_SERVOS slots occupied // Detach an unused servo first } ``` -------------------------------- ### ESP32 Frequency Calculation Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/platform-implementations.md Calculation for setting the 50 Hz PWM frequency for servos. ```cpp ledcSetup(_channel, (1000000 / REFRESH_INTERVAL), LEDC_MAX_BIT_WIDTH); // (1000000 µs/s) / (20000 µs period) = 50 Hz ``` -------------------------------- ### Control up to 48 Servos on Mega Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/usage-patterns.md Leverages four hardware timers to enable control of up to 48 servos on Arduino Mega boards. ```cpp #include // Four timers enable up to 48 servos Servo servos[48]; int servoCount = 0; void attachServo(int pin) { if (servoCount < 48) { if (servos[servoCount].attach(pin) != INVALID_SERVO) { servoCount++; Serial.print("Servo #"); Serial.print(servoCount - 1); Serial.print(" attached to pin "); Serial.println(pin); } } else { Serial.println("Maximum servos (48) reached"); } } void setup() { Serial.begin(9600); // Attach many servos across different pins int pins[] = {2, 3, 5, 6, 7, 8, 11, 12, 44, 45, 46}; for (int pin : pins) { attachServo(pin); } } void loop() { // Sweep all servos for (int angle = 0; angle <= 180; angle += 5) { for (int i = 0; i < servoCount; i++) { servos[i].write(angle); } delay(50); } } ``` -------------------------------- ### Control Servo with Potentiometer Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/usage-patterns.md Maps analog input from a potentiometer (0-1023) to a servo angle (0-180). Requires a potentiometer connected to the specified analog pin. ```cpp #include Servo servo; const int POTPIN = A0; void setup() { Serial.begin(9600); servo.attach(9); } void loop() { // Read potentiometer (0-1023) int rawValue = analogRead(POTPIN); // Map to servo angle (0-180) int angle = map(rawValue, 0, 1023, 0, 180); // Write to servo servo.write(angle); // Optional: display for debugging Serial.print("Raw: "); Serial.print(rawValue); Serial.print(" -> Angle: "); Serial.println(angle); delay(15); // Servo update rate } ``` -------------------------------- ### SAMD Timer Definitions Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/platform-implementations.md Defines the timers and sequence enumeration for SAMD-based boards. ```cpp #define _useTimer1 #define _useTimer2 typedef enum { _timer1, _timer2, _Nbr_16timers } timer16_Sequence_t; ``` -------------------------------- ### attach(int pin, int min, int max) Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/configuration.md Attaches the servo to a specific digital pin with custom pulse width limits. ```APIDOC ## attach(int pin, int min, int max) ### Description Attaches the Servo variable to a pin with custom pulse width settings for the 0° and 180° positions. ### Parameters - **pin** (int) - Required - The Arduino digital pin number (0–63). - **min** (int) - Required - The pulse width in microseconds for the 0° position (range 544–2400). - **max** (int) - Required - The pulse width in microseconds for the 180° position (range 544–2400). ### Example ```cpp servo.attach(9, 900, 2100); servo.write(0); // Sends 900 µs pulse servo.write(180); // Sends 2100 µs pulse ``` ``` -------------------------------- ### Simulate Mechanical Stall Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/errors.md Demonstrates driving a servo beyond its mechanical limits, which causes high current draw and potential hardware damage. ```cpp servo.attach(9, 500, 2500); // Extended range: 500–2500 µs servo.writeMicroseconds(3000); // Beyond mechanical range // Servo stalls; draws 500+ mA; produces "growling" sound ``` -------------------------------- ### Define Servo Pulse Width Bounds Source: https://github.com/arduino-libraries/servo/blob/master/_autodocs/configuration.md Defines the minimum, maximum, and default pulse widths in microseconds for standard servo operation. ```cpp #define MIN_PULSE_WIDTH 544 // Minimum pulse (microseconds) #define MAX_PULSE_WIDTH 2400 // Maximum pulse (microseconds) #define DEFAULT_PULSE_WIDTH 1500 // Default after attach (microseconds) ```