Skip to content

Commit 0ce5242

Browse files
committed
Update
- New Servo Easing feature easily controlled with only 2 parameters - New Servo Easing examples and simulations - For the ESP32, enable use of gpio pins 25 and 26 for pwm - Improved attach functions
1 parent 4ea6965 commit 0ce5242

File tree

7 files changed

+404
-192
lines changed

7 files changed

+404
-192
lines changed

README.md

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# ESP32 PWM, SERVO, TONE and NOTE Library
1+
# ESP32 PWM, Servo, Easing and Tone Library
22

33
[![arduino-library-badge](https://www.ardu-badge.com/badge/ESP32%20ESP32S2%20AnalogWrite.svg?)](https://www.ardu-badge.com/ESP32%20ESP32S2%20AnalogWrite) <a href="https://registry.platformio.org/libraries/dlloydev/ESP32 ESP32S2 AnalogWrite"><img src="https://badges.registry.platformio.org/packages/dlloydev/library/ESP32 ESP32S2 AnalogWrite.svg" alt="PlatformIO Registry" /></a>
44

@@ -10,18 +10,28 @@ This library wraps the ESP32 Arduino framework's [ledc](https://github.com/espre
1010

1111
PWM can be inverted, phase shifted and asynchronously aligned with the timing of other pwm channels.
1212

13-
Servo read and write functions are included that work with *float* values for more precise control. An optionally inverted servo pwm feature allows using a simple NPN or N-Channel MOSFET driver for the servo's control signal.
13+
Servo Easing is fully integrated into the servo write and attach functions. Only 2 parameters give complete control over the speed and the easing characteristic of the servo. The method used for easing is a [Normalized Tunable Sigmoid](https://www.desmos.com/calculator/ejkcwglzd1) ([reference](https://dhemery.github.io/DHE-Modules/technical/sigmoid/)). An optionally inverted servo pwm feature allows using a simple NPN or N-Channel MOSFET driver for the servo's control signal.
1414

15-
Also included are non blocking Tone and Note functions that include *duration* and *interval* parameters.
15+
#### Servo Easing
1616

17-
### Coming Soon...
17+
Just 2 easing parameters (speed and easing constant) for unlimited control ...
18+
19+
```c++
20+
pwm.writeServo(servoPin1, pos1, speed1, 0.0); // move 90 deg, 70 deg/s, linear
21+
pwm.writeServo(servoPin2, pos2, speed2, 0.6); // mpve 180 deg, 140 deg/s, avg sigmoid
22+
pwm.writeServo(servoPin3, pos3, speed3, 0.8); // move 90 deg, 180 deg/s, steep sigmoid
23+
```
24+
25+
#### ![ServoEasing](https://user-images.githubusercontent.com/63488701/227943891-87cb7555-fe56-4064-a83a-38b99ad58e1d.gif)
1826

19-
#### Servo Easing (soft-start, soft-stop)
2027

21-
#### ![Easing_Linear](https://user-images.githubusercontent.com/63488701/212481603-d811b9ac-ffbe-4190-9dd9-47e191919a11.gif)
2228

2329
##### **Examples:**
2430

31+
- [![Wokwi_badge](https://user-images.githubusercontent.com/63488701/212449119-a8510897-c860-4545-8c1a-794169547ba1.svg)](https://wokwi.com/projects/360276061783595009) [Servo Easing](https://github.com/Dlloydev/ESP32-ESP32S2-AnalogWrite/blob/main/examples/Servo-Easing.ino) Controls three servos with different easing settings
32+
33+
- [![Wokwi_badge](https://user-images.githubusercontent.com/63488701/212449119-a8510897-c860-4545-8c1a-794169547ba1.svg)](https://wokwi.com/projects/355852275661848577) [ESP32_C3_6_Servo_Knob](https://github.com/Dlloydev/ESP32-ESP32S2-AnalogWrite/blob/main/examples/ESP32_C3_6_Servo_Knob.ino) Potentiometer control of 6 servos on an ESP32-C3
34+
2535
- [![Wokwi_badge](https://user-images.githubusercontent.com/63488701/212449119-a8510897-c860-4545-8c1a-794169547ba1.svg)](https://wokwi.com/projects/349232255258853970) [16 PWM Fade](https://github.com/Dlloydev/ESP32-ESP32S2-AnalogWrite/blob/main/examples/ESP32_Fade16/ESP32_Fade16.ino) ESP32 fading 16 pairs of LEDs
2636

2737
- [![Wokwi_badge](https://user-images.githubusercontent.com/63488701/212449119-a8510897-c860-4545-8c1a-794169547ba1.svg)](https://wokwi.com/projects/349978851105833554) [14 PWM Fade 2 Servo](https://github.com/Dlloydev/ESP32-ESP32S2-AnalogWrite/blob/main/examples/ESP32_Fade_Servo/ESP32_Fade_Servo.ino) ESP32 fading 14 pairs of LEDs and controlling 2 servo motors
@@ -54,11 +64,11 @@ Also included are non blocking Tone and Note functions that include *duration* a
5464

5565

5666

57-
| Board | PWM Pins | PWM, Duty and Phase Channels | Frequency and Resolution Channels |
58-
| -------- | --------------------------------- | ---------------------------- | --------------------------------- |
59-
| ESP32 | 2, 4, 5, 12-19, 21-23, 27, 32, 33 | 16 | 8 |
60-
| ESP32‑S2 | 1- 14, 21, 33-42, 45 | 8 | 4 |
61-
| ESP32‑C3 | 0- 9, 18, 19 | 6 | 3 |
67+
| Board | PWM Pins | PWM, Duty and Phase Channels | Frequency and Resolution Channels |
68+
| -------- | ------------------------------------ | ---------------------------- | --------------------------------- |
69+
| ESP32 | 2, 4, 5, 12-19, 21-23, 25-27, 32, 33 | 16 | 8 |
70+
| ESP32‑S2 | 1- 14, 21, 33-42, 45 | 8 | 4 |
71+
| ESP32‑C3 | 0- 9, 18, 19 | 6 | 3 |
6272

6373
### PWM Channel Configuration
6474

@@ -149,16 +159,20 @@ This process is automatic - the servo pin will be attached to the next free chan
149159

150160
```c++
151161
pwm.writeServo(pin, value)
162+
pwm.writeServo(pin, value, speed, ke)
152163
```
153164

154165
##### Parameters
155166

156167
- **pin** The pin number which (if necessary) will be attached to the next free channel *(uint8_t)*
157168
- **value** This value is converted to the pwm duty. See above table for range and units *(float)
169+
- **speed** This value has units degrees/second (float). For example, if `speed` is set to 100 deg/s and the servo position value is changed from 0 to 180 deg, then the servo will take 1.8 sec (1800 ms) to complete its travel. Its motion (response) will be determined by `ke`,
170+
- **ke** Servo easing constant for a [Normalized Tunable Sigmoid](https://www.desmos.com/calculator/ejkcwglzd1). A `ke` value of 0.0 represents a linear response. As you increase `ke`, this increases the steepness of a sigmoid response. When `ke` is 1.0, normal "instantaneous" servo response is enabled and the speed parameter is ignored.
158171

159172
##### Returns
160173

161-
The pwm duty value *(uint32_t)*
174+
- If the servo easing constant `ke` is 1.0 (default) then the pwm duty value *(uint32_t)* is returned.
175+
- If `ke` is less than 1.0, then a normalized float value (0.0 to 1.0) is returned. This represents the programmed servo position from start to stop as it moves over time. When the returned value reaches 0.5, this represents both 50% travel and 50% time duration, no matter what easing constant is set.
162176

163177

164178

@@ -283,11 +297,12 @@ This function allows auto-attaching a pin to the first available channel if only
283297
**Syntax**
284298

285299
```c++
286-
attach(pin) // auto attach to first open channel
287-
attach(pin, ch, invert) // attach to ch, optional invert
288-
attach(pin, minUs, defUs, maxUs) // auto attach incl servo timer values
289-
attach(pin, ch, minUs, defUs, maxUs) // attach to ch with servo limits
290-
attach(pin, ch, minUs, defUs, maxUs, invert) // attach to ch, servo limits and invert
300+
attach(pin) // auto attach to 1st free channel
301+
attach(pin, ch, invert) // attach to ch, optional invert
302+
attach(pin, minUs, defUs, maxUs) // auto attach incl servo timer values
303+
attach(pin, ch, minUs, defUs, maxUs) // attach to ch with servo limits
304+
attach(pin, ch, minUs, defUs, maxUs, speed, ke) // as above with speed, easing constant
305+
attach(pin, ch, minUs, defUs, maxUs, speed, ke, invert) // as above with invert
291306
```
292307
293308
##### Parameters
@@ -302,6 +317,10 @@ attach(pin, ch, minUs, defUs, maxUs, invert) // attach to ch, servo limits and i
302317
303318
- **maxUs** Maximum timer width in microseconds *(uint16_t)*
304319
320+
- **speed** This servo easing parameter has units degrees/second (float). For example, if `speed` is set to 100 deg/s and the servo position value is changed from 0 to 180 deg, then the servo will take 1.8 sec (1800 ms) to complete its travel. Its motion (response) will be determined by `ke`,
321+
322+
- **ke** Servo easing constant for a [Normalized Tunable Sigmoid](https://www.desmos.com/calculator/ejkcwglzd1). A `ke` value of 0.0 represents a linear response. As you increase `ke`, this increases the steepness of a sigmoid response. When `ke` is 1.0, normal "instantaneous" servo response is enabled and the speed parameter is ignored.
323+
305324
- **invert** Inverts the PWM output. Allows using a simpler driver for higher voltage servo control. Only one NPN transistor or N-Channel MOSFET needed. No additional latency added as found with software inversion because the inverted pulse remains at the start of the refresh period rather than being flipped to the end of the refresh period *(bool)*.
306325
307326
[Servo_Sweep_Inverted](https://wokwi.com/projects/351967394028061269)
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
Independent potentiometer control of 6 servos on an ESP32-C3
3+
https://wokwi.com/projects/355852275661848577
4+
by dlloydev, February 2023.
5+
*/
6+
7+
#include <pwmWrite.h>
8+
9+
Pwm pwm = Pwm();
10+
11+
const int potPin1 = 0, servoPin1 = 6;
12+
const int potPin2 = 1, servoPin2 = 7;
13+
const int potPin3 = 2, servoPin3 = 8;
14+
const int potPin4 = 3, servoPin4 = 9;
15+
const int potPin5 = 4, servoPin5 = 18;
16+
const int potPin6 = 5, servoPin6 = 19;
17+
18+
void setup() {
19+
}
20+
21+
void loop() {
22+
23+
int val1 = analogRead(potPin1); // read the pot value (0-4095)
24+
val1 = map(val1, 700, 3395, 0, 180); // align pot pointer to servo arm
25+
pwm.writeServo(servoPin1, val1); // set the servo position (degrees)
26+
27+
int val2 = analogRead(potPin2); // read the pot value (0-4095)
28+
val2 = map(val2, 700, 3395, 0, 180); // align pot pointer to servo arm
29+
pwm.writeServo(servoPin2, val2); // set the servo position (degrees)
30+
31+
int val3 = analogRead(potPin3); // read the pot value (0-4095)
32+
val3 = map(val3, 700, 3395, 0, 180); // align pot pointer to servo arm
33+
pwm.writeServo(servoPin3, val3); // set the servo position (degrees)
34+
35+
int val4 = analogRead(potPin4); // read the pot value (0-4095)
36+
val4 = map(val4, 700, 3395, 0, 180); // align pot pointer to servo arm
37+
pwm.writeServo(servoPin4, val4); // set the servo position (degrees)
38+
39+
int val5 = analogRead(potPin5); // read the pot value (0-4095)
40+
val5 = map(val5, 700, 3395, 0, 180); // align pot pointer to servo arm
41+
pwm.writeServo(servoPin5, val5); // set the servo position (degrees)
42+
43+
int val6 = analogRead(potPin6); // read the pot value (0-4095)
44+
val6 = map(val6, 700, 3395, 0, 180); // align pot pointer to servo arm
45+
pwm.writeServo(servoPin6, val6); // set the servo position (degrees)
46+
47+
delay(10);
48+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
Controls three servos with different easing settings
3+
https://wokwi.com/projects/360276061783595009
4+
by dlloydev, March 2023.
5+
6+
⚪ The green servo moves from 0 to 90 deg at 70 deg/s with linear motion.
7+
⚪ The orange servo moves from 0 to 180 deg at 140 deg/s with sigmoid motion.
8+
⚪ The purple servo moves from 45 to 135 deg at 180 deg/s with steep sigmoid motion.
9+
*/
10+
11+
#include <pwmWrite.h>
12+
13+
const int servoPin1 = 21;
14+
const int servoPin2 = 22;
15+
const int servoPin3 = 23;
16+
17+
float speed1 = 70.0;
18+
float speed2 = 140.0;
19+
float speed3 = 180.0;
20+
21+
uint32_t prevMs1, prevMs2, prevMs3;
22+
uint8_t pos1 = 90;
23+
uint8_t pos2 = 180;
24+
uint8_t pos3 = 135;
25+
26+
float dur1 = 90.0 / speed1 * 1000.0;
27+
float dur2 = 180.0 / speed2 * 1000.0;
28+
float dur3 = 90.0 / speed3 * 1000.0;
29+
30+
Pwm pwm = Pwm();
31+
32+
void setup() {
33+
Serial.begin(115200);
34+
}
35+
36+
void loop() {
37+
uint32_t ms1 = millis();
38+
uint32_t ms2 = ms1;
39+
uint32_t ms3 = ms1;
40+
float ye1, ye2, ye3;
41+
42+
if (ms1 - prevMs1 > dur1) {
43+
prevMs1 = ms1;
44+
pos1 = (pos1 == 0) ? 90 : 0;
45+
}
46+
if (ms2 - prevMs2 > dur2) {
47+
prevMs2 = ms2;
48+
pos2 = (pos2 == 0) ? 180 : 0;
49+
}
50+
if (ms3 - prevMs3 > dur3) {
51+
prevMs3 = ms3;
52+
pos3 = (pos3 == 45) ? 135 : 45;
53+
}
54+
ye1 = pwm.writeServo(servoPin1, pos1, speed1, 0.0);
55+
ye2 = pwm.writeServo(servoPin2, pos2, speed2, 0.6);
56+
ye3 = pwm.writeServo(servoPin3, pos3, speed3, 0.8);
57+
Serial.print(ye1);
58+
Serial.print(",");
59+
Serial.print(ye2);
60+
Serial.print(",");
61+
Serial.println(ye3);
62+
delay(6);
63+
}

library.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
22
"name": "ESP32 ESP32S2 AnalogWrite",
33
"keywords": "pwm, servo, tone, esp32, analogWrite, esp32-s2, esp32-s3, esp32-c3, ledc",
4-
"description": "ESP32 PWM, SERVO, TONE and NOTE. Smart GPIO pin management and advanced control features.",
4+
"description": "ESP32 PWM, Servo, Easing and Tone. Smart GPIO pin management and advanced control features.",
55
"license": "MIT",
6-
"version": "4.2.5",
6+
"version": "4.3.0",
77
"frameworks": "arduino",
88
"platforms": "espressif32",
99
"repository": {

library.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
name=ESP32 ESP32S2 AnalogWrite
2-
version=4.2.5
2+
version=4.3.0
33
author=David Lloyd
44
maintainer=David Lloyd <[email protected]>
5-
sentence=ESP32 PWM, SERVO, TONE and NOTE.
5+
sentence=ESP32 PWM, Servo, Easing and Tone.
66
paragraph=Smart GPIO pin managementSmart GPIO pin management and advanced control features.
77
category=Signal Input/Output
88
url=https://github.com/Dlloydev/ESP32-ESP32S2-AnalogWrite

0 commit comments

Comments
 (0)