初始化提交
This commit is contained in:
69
arduino-cli/libraries/ESP32Servo/README.adoc
Normal file
69
arduino-cli/libraries/ESP32Servo/README.adoc
Normal file
@@ -0,0 +1,69 @@
|
||||
= Servo Library for ESP32 =
|
||||
|
||||
This library attempts to faithfully replicate the semantics of the
|
||||
Arduino Servo library (see http://www.arduino.cc/en/Reference/Servo)
|
||||
for the ESP32, with two (optional) additions. The two new functions
|
||||
expose the ability of the ESP32 PWM timers to vary timer width.
|
||||
|
||||
== License ==
|
||||
|
||||
Copyright (c) 2017 John K. Bennett. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Library Description:
|
||||
--------------------
|
||||
Servo - Class for manipulating servo motors connected to ESP32 pins.
|
||||
int attach(pin ) - Attaches the given GPIO pin to the next free channel
|
||||
(channels that have previously been detached are used first),
|
||||
returns channel number or 0 if failure. All pin numbers are allowed,
|
||||
but only pins 2,4,12-19,21-23,25-27,32-33 are recommended.
|
||||
int attach(pin, min, max ) - Attaches to a pin setting min and max
|
||||
values in microseconds; enforced minimum min is 500, enforced max
|
||||
is 2500. Other semantics are the same as attach().
|
||||
void write () - Sets the servo angle in degrees; a value below 500 is
|
||||
treated as a value in degrees (0 to 180). These limit are enforced,
|
||||
i.e., values are constrained as follows:
|
||||
Value Becomes
|
||||
----- -------
|
||||
< 0 0
|
||||
0 - 180 value (treated as degrees)
|
||||
181 - 499 180
|
||||
500 - (min-1) min
|
||||
min-max (from attach or default) value (treated as microseconds)
|
||||
(max+1) - 2500 max
|
||||
|
||||
void writeMicroseconds() - Sets the servo pulse width in microseconds.
|
||||
min and max are enforced (see above).
|
||||
int read() - Gets the last written servo pulse width as an angle between 0 and 180.
|
||||
int readMicroseconds() - Gets the last written servo pulse width in microseconds.
|
||||
bool attached() - Returns true if this servo instance is attached to a pin.
|
||||
void detach() - Stops an the attached servo, frees the attached pin, and frees
|
||||
its channel for reuse.
|
||||
|
||||
*** New ESP32-specific functions **
|
||||
setTimerWidth(value) - Sets the PWM timer width (must be 16-20) (ESP32 ONLY);
|
||||
as a side effect, the pulse width is recomputed.
|
||||
int readTimerWidth() - Gets the PWM timer width (ESP32 ONLY)
|
||||
|
||||
Useful Defaults:
|
||||
----------------
|
||||
default min pulse width for attach(): 1000us
|
||||
default max pulse width for attach(): 2000us
|
||||
default timer width 16 (if timer width is not set)
|
||||
default pulse width 1500us (servos are initialized with this value)
|
||||
MINIMUM pulse with: 500us
|
||||
MAXIMUM pulse with: 2500us
|
||||
MAXIMUM number of servos: 16 (this is the number of PWM channels in the ESP32)
|
||||
69
arduino-cli/libraries/ESP32Servo/examples/Knob/Knob.ino
Normal file
69
arduino-cli/libraries/ESP32Servo/examples/Knob/Knob.ino
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
Controlling a servo position using a potentiometer (variable resistor)
|
||||
by Michal Rinott <http://people.interaction-ivrea.it/m.rinott>
|
||||
|
||||
modified on 8 Nov 2013
|
||||
by Scott Fitzgerald
|
||||
|
||||
modified for the ESP32 on March 2017
|
||||
by John Bennett
|
||||
|
||||
see http://www.arduino.cc/en/Tutorial/Knob for a description of the original code
|
||||
|
||||
* 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.
|
||||
*
|
||||
* Circuit: (using an ESP32 Thing from Sparkfun)
|
||||
* 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 pin 18.
|
||||
*
|
||||
* In this example, we assume a Tower Pro SG90 small servo connected to VBat.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Include the ESP32 Arduino Servo Library instead of the original Arduino Servo Library
|
||||
#include <ESP32_Servo.h>
|
||||
|
||||
Servo myservo; // create servo object to control a servo
|
||||
|
||||
// Possible PWM GPIO pins on the ESP32: 0(used by on-board button),2,4,5(used by on-board LED),12-19,21-23,25-27,32-33
|
||||
int servoPin = 18; // GPIO pin used to connect the servo control (digital out)
|
||||
// Possible ADC pins on the ESP32: 0,2,4,12-15,32-39; 34-39 are recommended for analog input
|
||||
int potPin = 34; // GPIO pin used to connect the potentiometer (analog in)
|
||||
int ADC_Max = 4096; // This is the default ADC max value on the ESP32 (12 bit ADC width);
|
||||
// this width can be set (in low-level oode) from 9-12 bits, for a
|
||||
// a range of max values of 512-4096
|
||||
|
||||
int val; // variable to read the value from the analog pin
|
||||
|
||||
void setup()
|
||||
{
|
||||
myservo.attach(servoPin, 500, 2400); // attaches the servo on pin 18 to the servo object
|
||||
// using SG90 servo min/max of 500us and 2400us
|
||||
// for MG995 large servo, use 1000us and 2000us,
|
||||
// which are the defaults, so this line could be
|
||||
// "myservo.attach(servoPin);"
|
||||
}
|
||||
|
||||
void loop() {
|
||||
val = analogRead(potPin); // read the value of the potentiometer (value between 0 and 1023)
|
||||
val = map(val, 0, ADC_Max, 0, 180); // scale it to use it with the servo (value between 0 and 180)
|
||||
myservo.write(val); // set the servo position according to the scaled value
|
||||
delay(200); // wait for the servo to get there
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* ESP32 Servo Example Using Arduino ESP32 Servo Library
|
||||
* John K. Bennett
|
||||
* March, 2017
|
||||
*
|
||||
* This sketch uses the Arduino ESP32 Servo Library to sweep 4 servos in sequence.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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, 550 and 2350 are pretty close to 0 and 180.
|
||||
*/
|
||||
|
||||
#include <ESP32_Servo.h>
|
||||
|
||||
// create four servo objects
|
||||
Servo servo1;
|
||||
Servo servo2;
|
||||
Servo servo3;
|
||||
Servo servo4;
|
||||
|
||||
// Published values for SG90 servos; adjust if needed
|
||||
int minUs = 500;
|
||||
int maxUs = 2400;
|
||||
|
||||
// These are all GPIO pins on the ESP32
|
||||
// Recommended pins include 2,4,12-19,21-23,25-27,32-33
|
||||
int servo1Pin = 18;
|
||||
int servo2Pin = 19;
|
||||
int servo3Pin = 22;
|
||||
int servo4Pin = 23;
|
||||
|
||||
int pos = 0; // position in degrees
|
||||
|
||||
void setup()
|
||||
{
|
||||
servo1.attach(servo1Pin, minUs, maxUs);
|
||||
servo2.attach(servo2Pin, minUs, maxUs);
|
||||
servo3.attach(servo3Pin, minUs, maxUs);
|
||||
servo4.attach(servo4Pin, minUs, maxUs);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
for (pos = 0; pos <= 180; pos += 1) { // sweep from 0 degrees to 180 degrees
|
||||
// in steps of 1 degree
|
||||
servo1.write(pos);
|
||||
delay(20); // waits 20ms for the servo to reach the position
|
||||
}
|
||||
for (pos = 180; pos >= 0; pos -= 1) { // sweep from 180 degrees to 0 degrees
|
||||
servo1.write(pos);
|
||||
delay(20);
|
||||
}
|
||||
|
||||
for (pos = 0; pos <= 180; pos += 1) { // sweep from 0 degrees to 180 degrees
|
||||
// in steps of 1 degree
|
||||
servo2.write(pos);
|
||||
delay(20); // waits 20ms for the servo to reach the position
|
||||
}
|
||||
for (pos = 180; pos >= 0; pos -= 1) { // sweep from 180 degrees to 0 degrees
|
||||
servo2.write(pos);
|
||||
delay(20);
|
||||
}
|
||||
|
||||
for (pos = 0; pos <= 180; pos += 1) { // sweep from 0 degrees to 180 degrees
|
||||
// in steps of 1 degree
|
||||
servo3.write(pos);
|
||||
delay(20); // waits 20ms for the servo to reach the position
|
||||
}
|
||||
for (pos = 180; pos >= 0; pos -= 1) { // sweep from 180 degrees to 0 degrees
|
||||
servo3.write(pos);
|
||||
delay(20);
|
||||
}
|
||||
|
||||
for (pos = 0; pos <= 180; pos += 1) { // sweep from 0 degrees to 180 degrees
|
||||
// in steps of 1 degree
|
||||
servo4.write(pos);
|
||||
delay(20); // waits 20ms for the servo to reach the position
|
||||
}
|
||||
for (pos = 180; pos >= 0; pos -= 1) { // sweep from 180 degrees to 0 degrees
|
||||
servo4.write(pos);
|
||||
delay(20);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
66
arduino-cli/libraries/ESP32Servo/examples/Sweep/Sweep.ino
Normal file
66
arduino-cli/libraries/ESP32Servo/examples/Sweep/Sweep.ino
Normal file
@@ -0,0 +1,66 @@
|
||||
/* Sweep
|
||||
by BARRAGAN <http://barraganstudio.com>
|
||||
This example code is in the public domain.
|
||||
|
||||
modified 8 Nov 2013
|
||||
by Scott Fitzgerald
|
||||
|
||||
modified for the ESP32 on March 2017
|
||||
by John Bennett
|
||||
|
||||
see http://www.arduino.cc/en/Tutorial/Sweep for a description of the original code
|
||||
|
||||
* 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.
|
||||
*
|
||||
* Circuit: (using an ESP32 Thing from Sparkfun)
|
||||
* 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 pin 18.
|
||||
*
|
||||
* In this example, we assume a Tower Pro MG995 large servo connected to an external power source.
|
||||
* The published min and max for this servo is 1000 and 2000, respectively, so the defaults are fine.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <ESP32_Servo.h>
|
||||
|
||||
Servo myservo; // create servo object to control a servo
|
||||
// 16 servo objects can be created on the ESP32
|
||||
|
||||
int pos = 0; // variable to store the servo position
|
||||
// Recommended PWM GPIO pins on the ESP32 include 2,4,12-19,21-23,25-27,32-33
|
||||
int servoPin = 18;
|
||||
|
||||
void setup() {
|
||||
myservo.attach(servoPin); // attaches the servo on pin 18 to the servo object
|
||||
// using default min/max of 1000us and 2000us
|
||||
// different servos may require different min/max settings
|
||||
// for an accurate 0 to 180 sweep
|
||||
}
|
||||
|
||||
void loop() {
|
||||
for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
|
||||
// in steps of 1 degree
|
||||
myservo.write(pos); // tell servo to go to position in variable 'pos'
|
||||
delay(15); // waits 15ms for the servo to reach the position
|
||||
}
|
||||
for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
|
||||
myservo.write(pos); // tell servo to go to position in variable 'pos'
|
||||
delay(15); // waits 15ms for the servo to reach the position
|
||||
}
|
||||
}
|
||||
|
||||
26
arduino-cli/libraries/ESP32Servo/keywords.txt
Normal file
26
arduino-cli/libraries/ESP32Servo/keywords.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
#######################################
|
||||
# Syntax Coloring Map ESP32_Servo
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
Servo KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
attach KEYWORD2
|
||||
detach KEYWORD2
|
||||
write KEYWORD2
|
||||
read KEYWORD2
|
||||
attached KEYWORD2
|
||||
writeMicroseconds KEYWORD2
|
||||
readMicroseconds KEYWORD2
|
||||
setTimerWidth KEYWORD2
|
||||
readTimerWidth KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
9
arduino-cli/libraries/ESP32Servo/library.properties
Normal file
9
arduino-cli/libraries/ESP32Servo/library.properties
Normal file
@@ -0,0 +1,9 @@
|
||||
name=ESP32_Servo
|
||||
version=1.0
|
||||
author=John K. Bennett
|
||||
maintainer=John K. Bennett <jkb@colorado.edu>
|
||||
sentence=Allows ESP32 boards to control servo motors using Arduino semantics.
|
||||
paragraph=This library can control a many types of servos.<br />It makes use of the ESP32 PWM timers: the library can control up to 16 servos on individual channels<br />No attempt has been made to support multiple servos per channel.<br />
|
||||
category=Device Control
|
||||
url=http://www.arduino.cc/en/Reference/Servo
|
||||
architectures=esp32
|
||||
267
arduino-cli/libraries/ESP32Servo/src/ESP32_Servo.cpp
Normal file
267
arduino-cli/libraries/ESP32Servo/src/ESP32_Servo.cpp
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
Copyright (c) 2017 John K. Bennett. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
* Notes on the implementation:
|
||||
* The ESP32 supports 16 hardware LED PWM channels that are intended
|
||||
* to be used for LED brightness control. The low level ESP32 code
|
||||
* (esp32-hal-ledc.*) allows us to set the PWM frequency and bit-depth,
|
||||
* and then manipulate them by setting bits in the relevant control
|
||||
* registers.
|
||||
*
|
||||
* 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 180
|
||||
* degrees. We vary pulse width (recall that the pulse period is already set to 20ms) as follows:
|
||||
*
|
||||
* 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 the 20ms cycle 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))
|
||||
*
|
||||
* So, for example, if I want a 1500us pulse_high_width, I set pulse_period to 20ms (20000us)
|
||||
* (this value is set in the ledcSetup call), and count (used in the ledcWrite call) to
|
||||
* 1500/(20000/65536), or 4924. This is the value we write to the timer in the ledcWrite call.
|
||||
* If we increase the timer_width, the timer_count values need to be adjusted.
|
||||
*
|
||||
* The servo signal pins connect to any available GPIO pins on the ESP32, but not all pins are
|
||||
* GPIO pins.
|
||||
*
|
||||
* The ESP32 is a 32 bit processor that includes FP support; this code reflects that fact.
|
||||
*/
|
||||
|
||||
#include "ESP32_Servo.h"
|
||||
#include "esp32-hal-ledc.h"
|
||||
#include "Arduino.h"
|
||||
|
||||
// initialize the class variable ServoCount
|
||||
int Servo::ServoCount = 0;
|
||||
|
||||
// The ChannelUsed array elements are 0 if never used, 1 if in use, and -1 if used and disposed
|
||||
// (i.e., available for reuse)
|
||||
int Servo::ChannelUsed[MAX_SERVOS+1] = {0}; // we ignore the zeroth element
|
||||
|
||||
Servo::Servo()
|
||||
{
|
||||
this->servoChannel = 0;
|
||||
// see if there is a servo channel available for reuse
|
||||
bool foundChannelForReuse = false;
|
||||
for (int i = 1; i < MAX_SERVOS+1; i++)
|
||||
{
|
||||
if (ChannelUsed[i] == -1)
|
||||
{
|
||||
// reclaim this channel
|
||||
ChannelUsed[i] = 1;
|
||||
this->servoChannel = i;
|
||||
foundChannelForReuse = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundChannelForReuse)
|
||||
{
|
||||
// no channels available for reuse; get a new one if we can
|
||||
if (ServoCount < MAX_SERVOS)
|
||||
{
|
||||
this->servoChannel = ++ServoCount; // assign a servo channel number to this instance
|
||||
ChannelUsed[this->servoChannel] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->servoChannel = 0; // too many servos in use
|
||||
}
|
||||
}
|
||||
// if we got a channel either way, finish initializing it
|
||||
if (this->servoChannel > 0)
|
||||
{
|
||||
// initialize this channel with plausible values, except pin # (we set pin # when attached)
|
||||
this->ticks = DEFAULT_PULSE_WIDTH_TICKS;
|
||||
this->timer_width = DEFAULT_TIMER_WIDTH;
|
||||
this->pinNumber = -1; // make it clear that we haven't attached a pin to this channel
|
||||
this->min = DEFAULT_uS_LOW;
|
||||
this->max = DEFAULT_uS_HIGH;
|
||||
this->timer_width_ticks = pow(2,this->timer_width);
|
||||
}
|
||||
}
|
||||
|
||||
int Servo::attach(int pin)
|
||||
{
|
||||
return (this->attach(pin, DEFAULT_uS_LOW, DEFAULT_uS_HIGH));
|
||||
}
|
||||
|
||||
int Servo::attach(int pin, int min, int max)
|
||||
{
|
||||
if ((this->servoChannel <= MAX_SERVOS) && (this->servoChannel > 0))
|
||||
{
|
||||
// Recommend only the following pins 2,4,12-19,21-23,25-27,32-33 (enforcement commented out)
|
||||
//if ((pin == 2) || (pin ==4) || ((pin >= 12) && (pin <= 19)) || ((pin >= 21) && (pin <= 23)) ||
|
||||
// ((pin >= 25) && (pin <= 27)) || (pin == 32) || (pin == 33))
|
||||
//{
|
||||
// OK to proceed; first check for new/reuse
|
||||
if (this->pinNumber < 0) // we are attaching to a new or previously detached pin; we need to initialize/reinitialize
|
||||
{
|
||||
// claim/reclaim this channel
|
||||
ChannelUsed[this->servoChannel] = 1;
|
||||
this->ticks = DEFAULT_PULSE_WIDTH_TICKS;
|
||||
this->timer_width = DEFAULT_TIMER_WIDTH;
|
||||
this->timer_width_ticks = pow(2,this->timer_width);
|
||||
}
|
||||
this->pinNumber = pin;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
// min/max checks
|
||||
if (min < MIN_PULSE_WIDTH) // ensure pulse width is valid
|
||||
min = MIN_PULSE_WIDTH;
|
||||
if (max > MAX_PULSE_WIDTH)
|
||||
max = MAX_PULSE_WIDTH;
|
||||
this->min = min; //store this value in uS
|
||||
this->max = max; //store this value in uS
|
||||
// Set up this channel
|
||||
// if you want anything other than default timer width, you must call setTimerWidth() before attach
|
||||
ledcSetup(this->servoChannel, REFRESH_CPS, this->timer_width); // channel #, 50 Hz, timer width
|
||||
ledcAttachPin(this->pinNumber, this->servoChannel); // GPIO pin assigned to channel
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
|
||||
void Servo::detach()
|
||||
{
|
||||
if (this->attached())
|
||||
{
|
||||
ledcDetachPin(this->pinNumber);
|
||||
//keep track of detached servos channels so we can reuse them if needed
|
||||
ChannelUsed[this->servoChannel] = -1;
|
||||
this->pinNumber = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void Servo::write(int value)
|
||||
{
|
||||
// treat values less than MIN_PULSE_WIDTH (500) as angles in degrees (valid values in microseconds are handled as microseconds)
|
||||
if (value < MIN_PULSE_WIDTH)
|
||||
{
|
||||
if (value < 0)
|
||||
value = 0;
|
||||
else if (value > 180)
|
||||
value = 180;
|
||||
|
||||
value = map(value, 0, 180, this->min, this->max);
|
||||
}
|
||||
this->writeMicroseconds(value);
|
||||
}
|
||||
|
||||
void Servo::writeMicroseconds(int value)
|
||||
{
|
||||
// calculate and store the values for the given channel
|
||||
if ((this->servoChannel <= MAX_SERVOS) && (this->attached())) // ensure channel is valid
|
||||
{
|
||||
if (value < this->min) // ensure pulse width is valid
|
||||
value = this->min;
|
||||
else if (value > this->max)
|
||||
value = this->max;
|
||||
|
||||
value = usToTicks(value); // convert to ticks
|
||||
this->ticks = value;
|
||||
// do the actual write
|
||||
ledcWrite(this->servoChannel, this->ticks);
|
||||
}
|
||||
}
|
||||
|
||||
int Servo::read() // return the value as degrees
|
||||
{
|
||||
return (map(readMicroseconds()+1, this->min, this->max, 0, 180));
|
||||
}
|
||||
|
||||
int Servo::readMicroseconds()
|
||||
{
|
||||
int pulsewidthUsec;
|
||||
if ((this->servoChannel <= MAX_SERVOS) && (this->attached()))
|
||||
{
|
||||
pulsewidthUsec = ticksToUs(this->ticks);
|
||||
}
|
||||
else
|
||||
{
|
||||
pulsewidthUsec = 0;
|
||||
}
|
||||
|
||||
return (pulsewidthUsec);
|
||||
}
|
||||
|
||||
bool Servo::attached()
|
||||
{
|
||||
return (ChannelUsed[this->servoChannel]);
|
||||
}
|
||||
|
||||
void Servo::setTimerWidth(int value)
|
||||
{
|
||||
// only allow values between 16 and 20
|
||||
if (value < 16)
|
||||
value = 16;
|
||||
else if (value > 20)
|
||||
value = 20;
|
||||
|
||||
// Fix the current ticks value after timer width change
|
||||
// The user can reset the tick value with a write() or writeUs()
|
||||
int widthDifference = this->timer_width - value;
|
||||
// if positive multiply by diff; if neg, divide
|
||||
if (widthDifference > 0)
|
||||
{
|
||||
this->ticks << widthDifference;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->ticks >> widthDifference;
|
||||
}
|
||||
|
||||
this->timer_width = value;
|
||||
this->timer_width_ticks = pow(2,this->timer_width);
|
||||
|
||||
// If this is an attached servo, clean up
|
||||
if ((this->servoChannel <= MAX_SERVOS) && (this->attached()))
|
||||
{
|
||||
// detach, setup and attach again to reflect new timer width
|
||||
ledcDetachPin(this->pinNumber);
|
||||
ledcSetup(this->servoChannel, REFRESH_CPS, this->timer_width);
|
||||
ledcAttachPin(this->pinNumber, this->servoChannel);
|
||||
}
|
||||
}
|
||||
|
||||
int Servo::readTimerWidth()
|
||||
{
|
||||
return (this->timer_width);
|
||||
}
|
||||
|
||||
int Servo::usToTicks(int usec)
|
||||
{
|
||||
return (int)((float)usec / ((float)REFRESH_USEC / (float)this->timer_width_ticks));
|
||||
}
|
||||
|
||||
int Servo::ticksToUs(int ticks)
|
||||
{
|
||||
return (int)((float)ticks * ((float)REFRESH_USEC / (float)this->timer_width_ticks));
|
||||
}
|
||||
|
||||
|
||||
144
arduino-cli/libraries/ESP32Servo/src/ESP32_Servo.h
Normal file
144
arduino-cli/libraries/ESP32Servo/src/ESP32_Servo.h
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
Copyright (c) 2017 John K. Bennett. All right reserved.
|
||||
|
||||
ESP32_Servo.h - Servo library for ESP32 - Version 1
|
||||
|
||||
Original Servo.h written by Michael Margolis in 2009
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
A servo is activated by creating an instance of the Servo class, and passing
|
||||
the desired GPIO pin to the attach() method.
|
||||
The servos are pulsed in the background using the value most recently
|
||||
written using the write() method.
|
||||
|
||||
The class methods are:
|
||||
|
||||
Servo - Class for manipulating servo motors connected to ESP32 pins.
|
||||
int attach(pin ) - Attaches the given GPIO pin to the next free channel
|
||||
(channels that have previously been detached are used first),
|
||||
returns channel number or 0 if failure. All pin numbers are allowed,
|
||||
but only pins 2,4,12-19,21-23,25-27,32-33 are recommended.
|
||||
int attach(pin, min, max ) - Attaches to a pin setting min and max
|
||||
values in microseconds; enforced minimum min is 500, enforced max
|
||||
is 2500. Other semantics same as attach().
|
||||
void write () - Sets the servo angle in degrees; a value below 500 is
|
||||
treated as a value in degrees (0 to 180). These limit are enforced,
|
||||
i.e., values are treated as follows:
|
||||
Value Becomes
|
||||
----- -------
|
||||
< 0 0
|
||||
0 - 180 value (treated as degrees)
|
||||
181 - 499 180
|
||||
500 - (min-1) min
|
||||
min-max (from attach or default) value (treated as microseconds)
|
||||
(max+1) - 2500 max
|
||||
|
||||
void writeMicroseconds() - Sets the servo pulse width in microseconds.
|
||||
min and max are enforced (see above).
|
||||
int read() - Gets the last written servo pulse width as an angle between 0 and 180.
|
||||
int readMicroseconds() - Gets the last written servo pulse width in microseconds.
|
||||
bool attached() - Returns true if this servo instance is attached.
|
||||
void detach() - Stops an the attached servo, frees its attached pin, and frees
|
||||
its channel for reuse).
|
||||
|
||||
*** ESP32-specific functions **
|
||||
setTimerWidth(value) - Sets the PWM timer width (must be 16-20) (ESP32 ONLY);
|
||||
as a side effect, the pulse width is recomputed.
|
||||
int readTimerWidth() - Gets the PWM timer width (ESP32 ONLY)
|
||||
*/
|
||||
|
||||
#ifndef ESP32_Servo_h
|
||||
#define ESP32_Servo_h
|
||||
|
||||
// Values for TowerPro MG995 large servos (and many other hobbyist servos)
|
||||
#define DEFAULT_uS_LOW 1000 // 1000us
|
||||
#define DEFAULT_uS_HIGH 2000 // 2000us
|
||||
|
||||
// Values for TowerPro SG90 small servos
|
||||
//#define DEFAULT_uS_LOW 400
|
||||
//#define DEFAULT_uS_HIGH 2400
|
||||
|
||||
#define DEFAULT_TIMER_WIDTH 16
|
||||
#define DEFAULT_TIMER_WIDTH_TICKS 65536
|
||||
|
||||
#define ESP32_Servo_VERSION 1 // software version of this library
|
||||
|
||||
#define MIN_PULSE_WIDTH 500 // the shortest pulse sent to a servo
|
||||
#define MAX_PULSE_WIDTH 2500 // the longest pulse sent to a servo
|
||||
#define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached
|
||||
#define DEFAULT_PULSE_WIDTH_TICKS 4825
|
||||
#define REFRESH_CPS 50
|
||||
#define REFRESH_USEC 20000
|
||||
|
||||
#define MAX_SERVOS 16 // no. of PWM channels in ESP32
|
||||
|
||||
/*
|
||||
* This group/channel/timmer mapping is for information only;
|
||||
* the details are handled by lower-level code
|
||||
*
|
||||
* LEDC Chan to Group/Channel/Timer Mapping
|
||||
** ledc: 0 => Group: 0, Channel: 0, Timer: 0
|
||||
** ledc: 1 => Group: 0, Channel: 1, Timer: 0
|
||||
** ledc: 2 => Group: 0, Channel: 2, Timer: 1
|
||||
** ledc: 3 => Group: 0, Channel: 3, Timer: 1
|
||||
** ledc: 4 => Group: 0, Channel: 4, Timer: 2
|
||||
** ledc: 5 => Group: 0, Channel: 5, Timer: 2
|
||||
** ledc: 6 => Group: 0, Channel: 6, Timer: 3
|
||||
** ledc: 7 => Group: 0, Channel: 7, Timer: 3
|
||||
** ledc: 8 => Group: 1, Channel: 0, Timer: 0
|
||||
** ledc: 9 => Group: 1, Channel: 1, Timer: 0
|
||||
** ledc: 10 => Group: 1, Channel: 2, Timer: 1
|
||||
** ledc: 11 => Group: 1, Channel: 3, Timer: 1
|
||||
** ledc: 12 => Group: 1, Channel: 4, Timer: 2
|
||||
** ledc: 13 => Group: 1, Channel: 5, Timer: 2
|
||||
** ledc: 14 => Group: 1, Channel: 6, Timer: 3
|
||||
** ledc: 15 => Group: 1, Channel: 7, Timer: 3
|
||||
*/
|
||||
|
||||
class Servo
|
||||
{
|
||||
public:
|
||||
Servo();
|
||||
// Arduino Servo Library calls
|
||||
int attach(int pin); // attach the given pin to the next free channel, returns channel number or 0 if failure
|
||||
int attach(int pin, int min, int max); // as above but also sets min and max values for writes.
|
||||
void detach();
|
||||
void write(int value); // if value is < MIN_PULSE_WIDTH its treated as an angle, otherwise as pulse width in microseconds
|
||||
void writeMicroseconds(int value); // Write pulse width in microseconds
|
||||
int read(); // returns current pulse width as an angle between 0 and 180 degrees
|
||||
int readMicroseconds(); // returns current pulse width in microseconds for this servo
|
||||
bool attached(); // return true if this servo is attached, otherwise false
|
||||
|
||||
// ESP32 only functions
|
||||
void setTimerWidth(int value); // set the PWM timer width (ESP32 ONLY)
|
||||
int readTimerWidth(); // get the PWM timer width (ESP32 ONLY)
|
||||
|
||||
private:
|
||||
int usToTicks(int usec);
|
||||
int ticksToUs(int ticks);
|
||||
static int ServoCount; // the total number of attached servos
|
||||
static int ChannelUsed[]; // used to track whether a channel is in service
|
||||
int servoChannel = 0; // channel number for this servo
|
||||
int min = DEFAULT_uS_LOW; // minimum pulse width for this servo
|
||||
int max = DEFAULT_uS_HIGH; // maximum pulse width for this servo
|
||||
int pinNumber = 0; // GPIO pin assigned to this channel
|
||||
int timer_width = DEFAULT_TIMER_WIDTH; // ESP32 allows variable width PWM timers
|
||||
int ticks = DEFAULT_PULSE_WIDTH_TICKS; // current pulse width on this channel
|
||||
int timer_width_ticks = DEFAULT_TIMER_WIDTH_TICKS; // no. of ticks at rollover; varies with width
|
||||
};
|
||||
#endif
|
||||
Reference in New Issue
Block a user