Skip to content

Commit

Permalink
Version 3.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
ArminJo committed Feb 16, 2023
1 parent ace416b commit 4a641e9
Show file tree
Hide file tree
Showing 21 changed files with 448 additions and 393 deletions.
33 changes: 17 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,22 +108,22 @@ For instructions how to enable these alternatives, see [Compile options / macros


### All easing functions can be used in the following variants:
All ease functions are called internally with the value: `PercentageOfCompletion / 100` resulting in values from 0 and 1.
All ease functions are called internally with the value: `PercentageOfCompletion / 100` giving a call value from 0 to 1.

- In (start the function with 0 and go to 1) for PRECISION, do a bounce if approaching from above (go in to origin), else linear.
- Out (start the function with 1 and go to 0) for PRECISION, do a bounce if approaching from below (go out from origin), else linear.
- InOut (start the function with 0 go to 1 and back to 0)
- Bouncing (start with OUT, then return with IN to start degree) e.g. Bouncing of the Sine function results in the upper (positive) half of the sine.
- In: Start the function with 0 and go to 1 linear. Except for PRECISION, where we do a bounce if approaching from above (go in to origin).
- Out: Start the function with 1 and go to 0 linear. Except for PRECISION, where we do a bounce if approaching from below (go out from origin).
- InOut: Start the function with 0 go to 1 and back to 0.
- Bouncing: Start with OUT, then return with IN to start degree. E.g. Bouncing of the SINE function results in the upper (positive) half of the sine.

All easing types (starting in flavor IN_OUT, then IN, OUT and BOUNCE) in one plot.<br/>
#### All easing types (starting in flavor IN_OUT, then IN, OUT and BOUNCE) in one plot.<br/>
Since the values are computed in a fixed 20 ms raster, the last degree increment or decrement
in an easing may be much smaller than the increment/decrement before,
resulting in some small discontinuities between adjacent movements.<br/>
![Arduino Plotter Output for Linear->Quadratic->Cubic->Quartic->Sine-Circular->Back->Elastic](https://github.com/ArminJo/ServoEasing/blob/master/pictures/NonlinearMovements.png)

### Constraints
To restrict servo movements to a fixed range, you can specify constraints with `setMinMaxConstraint(int aMinDegreeOrMicrosecond, int aMaxDegreeOrMicrosecond)`.<br/>
Arduino Plotter Output with constraints at 5 degree and 175 degree activated.
#### Arduino Plotter Output with constraints at 5 degree and 175 degree activated.
![Arduino Plotter Output with constraints at 5 degree and 175 degree activated](https://github.com/ArminJo/ServoEasing/blob/master/pictures/Constraints.png)

### Disable easing temporarily
Expand Down Expand Up @@ -160,7 +160,7 @@ Just call `myServo.startEaseTo()` instead of `myServo.write()` and you are done.
<br/>

# Multiple servo handling
You can handle multiple servos simultaneously by [special functions](https://github.com/ArminJo/ServoEasing/blob/master/src/ServoEasing.h#L667) like
You can handle multiple servos simultaneously by [special functions](https://github.com/ArminJo/ServoEasing/blob/master/src/ServoEasing.h#L674) like
`writeAllServos()`, `setSpeedForAllServos()`, `setDegreeForAllServos()`, `setEaseToDForAllServos()`, `updateAndWaitForAllServosToStop()`, `setEaseToForAllServosSynchronizeAndWaitForAllServosToStop()`, `setEaseToForAllServosSynchronizeAndStartInterrupt()` and much more.<br/>
[See below](https://github.com/ArminJo/ServoEasing#handling-multiple-servos-with-the-internal-servoeasingarray).

Expand All @@ -175,7 +175,7 @@ You can handle multiple servos simultaneously by [special functions](https://git
# Useful resources
- [Easings Cheat Sheet](https://easings.net/)
- [Robert Penner](http://www.robertpenner.com/easing/)
- [C functions on Github](https://github.com/warrenm/AHEasing/blob/master/AHEasing/easing.c)
- [Easing C functions on Github](https://github.com/warrenm/AHEasing/blob/master/AHEasing/easing.c)
- [Interactive cubic-bezier](http://cubic-bezier.com)
- Servo signal gif from https://workshop.pglu.ch/arduino-servo/
[![Servo signal gif from https://workshop.pglu.ch/arduino-servo/](pictures/ServoFunktion_workshop.pglu.ch.gif)](https://workshop.pglu.ch/arduino-servo/)
Expand Down Expand Up @@ -271,7 +271,7 @@ Modify them by enabling / disabling them, or change the values if applicable.
| `PROVIDE_ONLY_LINEAR_MOVEMENT` | disabled | Disables all but LINEAR movement. Saves up to 1540 bytes program memory. |
| `DISABLE_COMPLEX_FUNCTIONS` | disabled | Disables the SINE, CIRCULAR, BACK, ELASTIC, BOUNCE and PRECISION easings. Saves up to 1850 bytes program memory. |
| `MAX_EASING_SERVOS` | 12, 16(for PCA9685) | Saves 4 byte RAM per servo. If this value is smaller than the amount of servos declared, attach() will return error and other library functions will not work as expected.<br/>Of course all *AllServos*() functions and isOneServoMoving() can't work correctly! |
| `DISABLE_MICROS_AS_DEGREE_PARAMETER` | disabled | Disables passing also microsecond values as (target angle) parameter (see [OneServo example](https://github.com/ArminJo/ServoEasing/blob/master/examples/OneServo/OneServo.ino#L93)). Saves up to 128 bytes program memory. |
| `DISABLE_MICROS_AS_DEGREE_PARAMETER` | disabled | Disables passing also microsecond values as (target angle) parameter. Saves up to 128 bytes program memory. |
| `DISABLE_MIN_AND_MAX_CONSTRAINTS` | disabled | Disables servo movement constraints. Saves 4 bytes RAM per servo but strangely enough no program memory. |
| `DISABLE_PAUSE_RESUME` | disabled | Disables pause and resume functionality. Saves 5 bytes RAM per servo. |
| `PRINT_FOR_SERIAL_PLOTTER` | disabled | Generate serial output for Arduino Plotter (Ctrl-Shift-L). |
Expand All @@ -281,7 +281,7 @@ Modify them by enabling / disabling them, or change the values if applicable.
<br/>

# Using PCA9685 16-Channel Servo Expander
Using the expander makes the servo pulse generating immune to other libraries blocking interrupts for a longer time like SoftwareSerial, Adafruit_NeoPixel and DmxSimple.<br/>
Using the PCA9685 expander makes the servo pulse generating immune to other libraries blocking interrupts for a longer time like SoftwareSerial, Adafruit_NeoPixel and DmxSimple.<br/>
To enable the use of the expander, activate [the line `#define USE_PCA9685_SERVO_EXPANDER`](https://github.com/ArminJo/ServoEasing/blob/master/examples/OneServo/OneServo.ino#L28) before `#include <ServoEasing.hpp>`.<br/>
In expander mode, timer1 is only required for the startEaseTo* functions and not for the blocking easeTo* functions, since no servo signal must be generated by it.

Expand Down Expand Up @@ -316,14 +316,14 @@ The ServoEasing library provides two arrays to ease the handling of multiple ser

Every ServoEasing object is appended to the ServoEasingArray by the attach() function.
**Only the order of the attach() statements determines the position in the array.**
So you can access your servo, which you attached secondly, also by `ServoEasing::ServoEasingArray[1]->setEaseTo(135)` as it is done [here](https://github.com/ArminJo/ServoEasing/blob/master/examples/ThreeServos/ThreeServos.ino#L144).<br/>
So you can access your servo, which you attached secondly, also by `ServoEasing::ServoEasingArray[1]->setEaseTo(135)` as it is done [here](https://github.com/ArminJo/ServoEasing/blob/master/examples/ThreeServos/ThreeServos.ino#L149).<br/>
There are also many other `*AllServos*` functions like `stopAllServos()`.

To move multiple servo, you can fill up the `ServoEasing::ServoEasingNextPositionArray` with the desired positions and then use e.g. the function `setEaseToForAllServos()`.
Then you must enable interrupt with `enableServoEasingInterrupt()` or call `updateAllServos()` in your main loop until it returns true.<br/>
If you want to move all your servos synchronized, i.e. they all stop at the same time,
you can use the `setEaseToForAllServosSynchronizeAndWaitForAllServosToStop()` or `setEaseToForAllServosSynchronizeAndStartInterrupt` function.<br/>
An example can be found [here](https://github.com/ArminJo/ServoEasing/blob/master/examples/ThreeServos/ThreeServos.ino#L162).<br/>
An example can be found [here](https://github.com/ArminJo/ServoEasing/blob/master/examples/ThreeServos/ThreeServos.ino#L174).<br/>
The [Quadruped example](https://github.com/ArminJo/ServoEasing/blob/master/examples/QuadrupedControl/QuadrupedServoControl.hpp#L32) makes heavy use of the `*AllServos*` functions.

If you **detach** a servo and then attach another one, the latter will get the index of the former detached one.
Expand Down Expand Up @@ -357,7 +357,7 @@ The API accepts degrees or microseconds as float or integer values, but internal

# Supported Arduino architectures
**Every Arduino architecture with a Servo library** will work without any modifications in blocking mode.<br/>
Non blocking behavior can always be achieved manually by calling `update()` in a loop - see last movement in [Simple example](examples/Simple/Simple.ino).<br/>
Non blocking behavior can always be achieved manually by calling `update()` or `updateAllServos()` in a loop - see [ThreeServos example](examples/ThreeServos/ThreeServos.ino#L153).<br/>
Interrupt based movement (movement without calling `update()` manually in a loop) is supported for the following Arduino architectures:<br/>
**avr, megaavr, sam, samd, esp8266, esp32, stm32, STM32F1 and apollo3.**<br/>
**It is not planned to support the ATtiny architecture, but you are invited to [do it by yourself](https://github.com/ArminJo/ServoEasing#adding-a-new-platform--board) and send a pull request.**
Expand All @@ -379,7 +379,7 @@ On **AVR** Timer1 is used for the Arduino Servo library. To have non blocking ea
| Teensy | | IntervalTimer |
| apollo3 | timer 3 segment A | |
| Mbed | mbed::Ticker | Ticker.h |
| [RP2040 / Pi Pico](https://github.com/earlephilhower/arduino-pico | [default alarm pool](https://raspberrypi.github.io/pico-sdk-doxygen/group__repeating__timer.html) | time.h |
| [RP2040 / Pi Pico](https://github.com/earlephilhower/arduino-pico) | [default alarm pool](https://raspberrypi.github.io/pico-sdk-doxygen/group__repeating__timer.html) | time.h |

<br/>

Expand All @@ -404,7 +404,8 @@ This will print internal information visible in the Arduino *Serial Monitor* whi
<br/>

# Revision History
### Version 3.1.1
### Version 3.2.0
- ATmega4808 support added.
- Added function `getCurrentMicroseconds()`.
- Improved many and added workaround for ESP32 bug in while loops in examples.
- Added `PCA9685_ACTUAL_CLOCK_FREQUENCY` macro.
Expand Down
22 changes: 11 additions & 11 deletions examples/EndPositionsTest/ADCUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,23 +137,23 @@ uint8_t checkAndWaitForReferenceAndChannelToSwitch(uint8_t aChannelNumber, uint8
/*
* readVCC*() functions store the result in sVCCVoltageMillivolt or sVCCVoltage
*/
float getVCCVoltageSimple();
void readVCCVoltageSimple();
uint16_t getVCCVoltageMillivoltSimple();
void readVCCVoltageMillivoltSimple();
float getVCCVoltage();
void readVCCVoltage();
uint16_t getVCCVoltageMillivolt();
void readVCCVoltageMillivolt();
uint16_t getVCCVoltageReadingFor1_1VoltReference();
float getVCCVoltageSimple(void);
void readVCCVoltageSimple(void);
uint16_t getVCCVoltageMillivoltSimple(void);
void readVCCVoltageMillivoltSimple(void);
float getVCCVoltage(void);
void readVCCVoltage(void);
uint16_t getVCCVoltageMillivolt(void);
void readVCCVoltageMillivolt(void);
uint16_t getVCCVoltageReadingFor1_1VoltReference(void);
uint16_t printVCCVoltageMillivolt(Print *aSerial);
void readAndPrintVCCVoltageMillivolt(Print *aSerial);

uint16_t getVoltageMillivolt(uint16_t aVCCVoltageMillivolt, uint8_t aADCChannelForVoltageMeasurement);
uint16_t getVoltageMillivolt(uint8_t aADCChannelForVoltageMeasurement);
uint16_t getVoltageMillivoltWith_1_1VoltReference(uint8_t aADCChannelForVoltageMeasurement);
float getTemperatureSimple();
float getTemperature();
float getTemperatureSimple(void);
float getTemperature(void);

bool isVCCTooLowMultipleTimes();
void resetVCCTooLowMultipleTimes();
Expand Down
22 changes: 11 additions & 11 deletions examples/EndPositionsTest/ADCUtils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ uint16_t readUntil4ConsecutiveValuesAreEqual(uint8_t aChannelNumber, uint8_t aDe
* Use it ONLY if you only call getVCCVoltageSimple() or getVCCVoltageMillivoltSimple() in your program.
* !!! Resolution is only 20 millivolt !!!
*/
float getVCCVoltageSimple() {
float getVCCVoltageSimple(void) {
// use AVCC with (optional) external capacitor at AREF pin as reference
float tVCC = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4);
return ((1023 * 1.1 * 4) / tVCC);
Expand All @@ -373,7 +373,7 @@ float getVCCVoltageSimple() {
* Use it ONLY if you only call getVCCVoltageSimple() or getVCCVoltageMillivoltSimple() in your program.
* !!! Resolution is only 20 millivolt !!!
*/
uint16_t getVCCVoltageMillivoltSimple() {
uint16_t getVCCVoltageMillivoltSimple(void) {
// use AVCC with external capacitor at AREF pin as reference
uint16_t tVCC = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4);
return ((1023L * ADC_INTERNAL_REFERENCE_MILLIVOLT * 4) / tVCC);
Expand All @@ -383,7 +383,7 @@ uint16_t getVCCVoltageMillivoltSimple() {
* Gets the hypothetical 14 bit reading of VCC using 1.1 volt reference
* Similar to getVCCVoltageMillivolt() * 1023 / 1100
*/
uint16_t getVCCVoltageReadingFor1_1VoltReference() {
uint16_t getVCCVoltageReadingFor1_1VoltReference(void) {
uint16_t tVCC = waitAndReadADCChannelWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT); // 225 for 1.1 V at 5 V VCC
/*
* Do not switch back ADMUX to enable checkAndWaitForReferenceAndChannelToSwitch() to work correctly for the next measurement
Expand All @@ -394,7 +394,7 @@ uint16_t getVCCVoltageReadingFor1_1VoltReference() {
/*
* !!! Resolution is only 20 millivolt !!!
*/
float getVCCVoltage() {
float getVCCVoltage(void) {
return (getVCCVoltageMillivolt() / 1000.0);
}

Expand All @@ -403,7 +403,7 @@ float getVCCVoltage() {
* Handles reference and channel switching by introducing the appropriate delays.
* !!! Resolution is only 20 millivolt !!!
*/
uint16_t getVCCVoltageMillivolt() {
uint16_t getVCCVoltageMillivolt(void) {
uint16_t tVCC = waitAndReadADCChannelWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT);
/*
* Do not switch back ADMUX to enable checkAndWaitForReferenceAndChannelToSwitch() to work correctly for the next measurement
Expand All @@ -430,7 +430,7 @@ void readAndPrintVCCVoltageMillivolt(Print *aSerial) {
* Use it ONLY if you only call getVCCVoltageSimple() or getVCCVoltageMillivoltSimple() in your program.
* !!! Resolution is only 20 millivolt !!!
*/
void readVCCVoltageSimple() {
void readVCCVoltageSimple(void) {
// use AVCC with (optional) external capacitor at AREF pin as reference
float tVCC = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4);
sVCCVoltage = (1023 * 1.1 * 4) / tVCC;
Expand All @@ -441,7 +441,7 @@ void readVCCVoltageSimple() {
* Use it ONLY if you only call getVCCVoltageSimple() or getVCCVoltageMillivoltSimple() in your program.
* !!! Resolution is only 20 millivolt !!!
*/
void readVCCVoltageMillivoltSimple() {
void readVCCVoltageMillivoltSimple(void) {
// use AVCC with external capacitor at AREF pin as reference
uint16_t tVCCVoltageMillivoltRaw = readADCChannelWithReferenceMultiSamples(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT, 4);
sVCCVoltageMillivolt = (1023L * ADC_INTERNAL_REFERENCE_MILLIVOLT * 4) / tVCCVoltageMillivoltRaw;
Expand All @@ -450,7 +450,7 @@ void readVCCVoltageMillivoltSimple() {
/*
* !!! Resolution is only 20 millivolt !!!
*/
void readVCCVoltage() {
void readVCCVoltage(void) {
sVCCVoltage = getVCCVoltageMillivolt() / 1000.0;
}

Expand All @@ -460,7 +460,7 @@ void readVCCVoltage() {
* !!! Resolution is only 20 millivolt !!!
* Sets also the sVCCVoltageMillivolt variable.
*/
void readVCCVoltageMillivolt() {
void readVCCVoltageMillivolt(void) {
uint16_t tVCCVoltageMillivoltRaw = waitAndReadADCChannelWithReference(ADC_1_1_VOLT_CHANNEL_MUX, DEFAULT);
/*
* Do not switch back ADMUX to enable checkAndWaitForReferenceAndChannelToSwitch() to work correctly for the next measurement
Expand Down Expand Up @@ -574,7 +574,7 @@ bool isVoltageTooLow(){
* !!! Function without handling of switched reference and channel.!!!
* Use it ONLY if you only use INTERNAL reference (call getTemperatureSimple()) in your program.
*/
float getTemperatureSimple() {
float getTemperatureSimple(void) {
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
return 0.0;
#else
Expand All @@ -587,7 +587,7 @@ float getTemperatureSimple() {
/*
* Handles reference and channel switching by introducing the appropriate delays.
*/
float getTemperature() {
float getTemperature(void) {
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
return 0.0;
#else
Expand Down
6 changes: 5 additions & 1 deletion examples/OneServo/OneServo.ino
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ void loop() {
#if !defined(DISABLE_PAUSE_RESUME)
# if !defined(PRINT_FOR_SERIAL_PLOTTER)
Serial.println(F("Interrupt movement with pause() for 1 second at 90 degree"));
#endif
# endif
/*
* Demonstrate pause and resume in the middle of a movement
*/
Expand All @@ -247,6 +247,10 @@ void loop() {
#endif
while (Servo1.isMoving()); // wait for servo to stop

# if !defined(PRINT_FOR_SERIAL_PLOTTER)
Serial.println(F("Detach the servo for 5 seconds. During this time you can move the servo manually."));
# endif

Servo1.detach();
/*
* After detach the servo is "not powered" for 5 seconds, i.e. no servo signal is generated.
Expand Down
22 changes: 11 additions & 11 deletions examples/QuadrupedControl/ADCUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,23 +137,23 @@ uint8_t checkAndWaitForReferenceAndChannelToSwitch(uint8_t aChannelNumber, uint8
/*
* readVCC*() functions store the result in sVCCVoltageMillivolt or sVCCVoltage
*/
float getVCCVoltageSimple();
void readVCCVoltageSimple();
uint16_t getVCCVoltageMillivoltSimple();
void readVCCVoltageMillivoltSimple();
float getVCCVoltage();
void readVCCVoltage();
uint16_t getVCCVoltageMillivolt();
void readVCCVoltageMillivolt();
uint16_t getVCCVoltageReadingFor1_1VoltReference();
float getVCCVoltageSimple(void);
void readVCCVoltageSimple(void);
uint16_t getVCCVoltageMillivoltSimple(void);
void readVCCVoltageMillivoltSimple(void);
float getVCCVoltage(void);
void readVCCVoltage(void);
uint16_t getVCCVoltageMillivolt(void);
void readVCCVoltageMillivolt(void);
uint16_t getVCCVoltageReadingFor1_1VoltReference(void);
uint16_t printVCCVoltageMillivolt(Print *aSerial);
void readAndPrintVCCVoltageMillivolt(Print *aSerial);

uint16_t getVoltageMillivolt(uint16_t aVCCVoltageMillivolt, uint8_t aADCChannelForVoltageMeasurement);
uint16_t getVoltageMillivolt(uint8_t aADCChannelForVoltageMeasurement);
uint16_t getVoltageMillivoltWith_1_1VoltReference(uint8_t aADCChannelForVoltageMeasurement);
float getTemperatureSimple();
float getTemperature();
float getTemperatureSimple(void);
float getTemperature(void);

bool isVCCTooLowMultipleTimes();
void resetVCCTooLowMultipleTimes();
Expand Down
Loading

0 comments on commit 4a641e9

Please sign in to comment.