library/Arduino/libraries/ESP32Servo/examples/Multiple-Servo-Example-ESP32/Multiple-Servo-Example-ESP32.ino
2018-12-01 23:51:18 +01:00

110 lines
4.6 KiB
C++

/*
* ESP32 Servo Example
* John K. Bennett
* March, 2017
*
* This sketch uses low-level ESP32 PWM functionality to sweep 4 servos in sequence.
* It does NOT use the ESP32_Servo library for Arduino.
*
* The ESP32 supports 16 hardware LED PWM channels that are intended
* to be used for LED brightness control. The low level ESP32 code allows us to set the
* PWM frequency and bit-depth, and then control them by setting bits in the relevant control
* register. The core files esp32-hal-ledc.* provides helper functions to make this set up
* straightforward.
*
* Different servos require different pulse widths to vary servo angle, but the range is
* an approximately 500-2500 microsecond pulse every 20ms (50Hz). In general, hobbyist servos
* sweep 180 degrees, so the lowest number in the published range for a particular servo
* represents an angle of 0 degrees, the middle of the range represents 90 degrees, and the top
* of the range represents 180 degrees. So for example, if the range is 1000us to 2000us,
* 1000us would equal an angle of 0, 1500us would equal 90 degrees, and 2000us would equal 1800
* degrees.
*
* The ESP32 PWM timers allow us to set the timer width (max 20 bits). Thus
* the timer "tick" length is (pulse_period/2**timer_width), and the equation for pulse_high_width
* (the portion of cycle (20ms in our case) that the signal is high) becomes:
*
* pulse_high_width = count * tick_length
* = count * (pulse_period/2**timer_width)
*
* and count = (pulse_high_width / (pulse_period/2**timer_width))
*
* For example, if we want a 1500us pulse_high_width, we set pulse_period to 20ms (20000us)
* (this value is set in the ledcSetup call), and count (used in the ledcWrite call) to
* 1500/(20000/65655), or 4924. This is the value we write to the timer in the ledcWrite call.
*
* As a concrete example, suppose we want to repeatedly sweep four Tower Pro SG90 servos
* from 0 to 180 degrees. The published pulse width range for the SG90 is 500-2400us. Thus,
* we should vary the count used in ledcWrite from 1638 to 7864.
*
* Circuit:
* Servo motors have three wires: power, ground, and signal. The power wire is typically red,
* the ground wire is typically black or brown, and the signal wire is typically yellow,
* orange or white. Since the ESP32 can supply limited current at only 3.3V, and servos draw
* considerable power, we will connect servo power to the VBat pin of the ESP32 (located
* near the USB connector). THIS IS ONLY APPROPRIATE FOR SMALL SERVOS.
*
* We could also connect servo power to a separate external
* power source (as long as we connect all of the grounds (ESP32, servo, and external power).
* In this example, we just connect ESP32 ground to servo ground. The servo signal pins
* connect to any available GPIO pins on the ESP32 (in this example, we use pins
* 22, 19, 23, & 18).
*
* In this example, we assume four Tower Pro SG90 small servos.
* The published min and max for this servo are 500 and 2400, respectively.
* These values actually drive the servos a little past 0 and 180, so
* if you are particular, adjust the min and max values to match your needs.
* Experimentally, 550us and 2350us are pretty close to 0 and 180.
*
* This code was inspired by a post on Hackaday by Elliot Williams.
*/
// Values for TowerPro SG90 small servos; adjust if needed
#define COUNT_LOW 1638
#define COUNT_HIGH 7864
#define TIMER_WIDTH 16
#include "esp32-hal-ledc.h"
void setup() {
ledcSetup(1, 50, TIMER_WIDTH); // channel 1, 50 Hz, 16-bit width
ledcAttachPin(22, 1); // GPIO 22 assigned to channel 1
ledcSetup(2, 50, TIMER_WIDTH); // channel 2, 50 Hz, 16-bit width
ledcAttachPin(19, 2); // GPIO 19 assigned to channel 2
ledcSetup(3, 50, TIMER_WIDTH); // channel 3, 50 Hz, 16-bit width
ledcAttachPin(23, 3); // GPIO 23 assigned to channel 3
ledcSetup(4, 50, TIMER_WIDTH); // channel 4, 50 Hz, 16-bit width
ledcAttachPin(18, 4); // GPIO 18 assigned to channel 4
}
void loop() {
for (int i=COUNT_LOW ; i < COUNT_HIGH ; i=i+100)
{
ledcWrite(1, i); // sweep servo 1
delay(200);
}
for (int i=COUNT_LOW ; i < COUNT_HIGH ; i=i+100)
{
ledcWrite(2, i); // sweep servo 2
delay(200);
}
for (int i=COUNT_LOW ; i < COUNT_HIGH ; i=i+100)
{
ledcWrite(3, i); // sweep the servo
delay(200);
}
for (int i=COUNT_LOW ; i < COUNT_HIGH ; i=i+100)
{
ledcWrite(4, i); // sweep the servo
delay(200);
}
}