Go to the documentation of this file.
23 #ifndef _SERVO_EASING_H
24 #define _SERVO_EASING_H
26 #define VERSION_SERVO_EASING "3.6.0"
27 #define VERSION_SERVO_EASING_MAJOR 3
28 #define VERSION_SERVO_EASING_MINOR 6
29 #define VERSION_SERVO_EASING_PATCH 0
32 #if defined(USE_LEIGHTWEIGHT_SERVO_LIB)
33 #define USE_LIGHTWEIGHT_SERVO_LIBRARY // for backwards compatibility
40 #define VERSION_HEX_VALUE(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
41 #define VERSION_SERVO_EASING_HEX VERSION_HEX_VALUE(VERSION_SERVO_EASING_MAJOR, VERSION_SERVO_EASING_MINOR, VERSION_SERVO_EASING_PATCH)
43 #if !defined(MILLIS_IN_ONE_SECOND)
44 #define MILLIS_IN_ONE_SECOND 1000L
50 #define START_EASE_TO_SPEED 5 // If not specified use 5 degree per second. It is chosen so low in order to signal that it was forgotten to specify by program.
85 #if defined(USE_LIGHTWEIGHT_SERVO_LIBRARY) && !(defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined (__AVR_ATmega328PB__) || defined(__AVR_ATmega2560__))
86 #error USE_LIGHTWEIGHT_SERVO_LIBRARY can only be activated for the Atmega328 or ATmega2560 CPU
98 #if defined(ENABLE_EXTERNAL_SERVO_TIMER_HANDLER)
102 #if !( defined(__AVR__) || defined(ESP8266) || defined(ESP32) || defined(STM32F1xx) || defined(__STM32F1__) || defined(__SAM3X8E__) || defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_APOLLO3) || defined(ARDUINO_ARCH_MBED) || defined(ARDUINO_ARCH_RP2040) || defined(TEENSYDUINO))
103 #warning No periodic timer support existent (or known) for this platform. Only blocking functions and simple example will run!
109 #if !defined(USE_USER_PROVIDED_SERVO_LIB) && (!defined(USE_PCA9685_SERVO_EXPANDER) || defined(USE_SERVO_LIB))
115 #include <ESP32Servo.h>
117 # elif defined(MEGATINYCORE)
118 #include <Servo_megaTinyCore.h>
120 # elif defined(MEGACOREX)
121 # if __has_include("ServoMegaCoreX.h")
122 #include <ServoMegaCoreX.h>
127 # else // defined(ESP32)
128 # if defined(USE_LIGHTWEIGHT_SERVO_LIBRARY)
130 # if !defined(MAX_EASING_SERVOS)
131 # if defined(__AVR_ATmega2560__)
132 #define MAX_EASING_SERVOS 3 // default value for Mega.
134 #define MAX_EASING_SERVOS 2 // default value for Uno etc.
139 # endif // !defined(USE_LIGHTWEIGHT_SERVO_LIBRARY)
140 # endif // defined(ESP32)
141 #endif // defined(USE_SERVO_LIB)
143 #if defined(ARDUINO_ARCH_MBED) // Arduino Nano 33 BLE
147 #if defined(USE_PCA9685_SERVO_EXPANDER)
148 # if !defined(MAX_EASING_SERVOS)
149 #define MAX_EASING_SERVOS 16 // One PCA9685 has 16 outputs. You must MODIFY this, if you have more than one PCA9685 attached!
150 # endif // defined(USE_PCA9685_SERVO_EXPANDER)
153 # if !defined(I2C_CLOCK_FREQUENCY)
157 # define I2C_CLOCK_FREQUENCY 100000 // 200000 does not work for my ESP32 module together with the timer even with external pullups :-(
158 # elif defined(ESP8266)
159 #define I2C_CLOCK_FREQUENCY 400000 // 400000 is the maximum for 80 MHz clocked ESP8266 (I measured real 330000 Hz for this setting)
161 #define I2C_CLOCK_FREQUENCY 800000 // 1 MHz from datasheet does not work for my Arduino Nano, maybe because of parasitic breadboard capacities
164 #endif // defined(USE_PCA9685_SERVO_EXPANDER)
173 #if !defined(MAX_EASING_SERVOS)
174 # if defined(MAX_SERVOS) // defined in Sevos.h
175 #define MAX_EASING_SERVOS MAX_SERVOS // =12 use default value from Servo.h for Uno etc.
177 #define MAX_EASING_SERVOS 12 // just take default value from Servo.h for Uno etc.
179 #endif // !defined(MAX_EASING_SERVOS)
181 #if !defined(DEFAULT_PULSE_WIDTH)
182 #define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached (from Servo.h)
184 #if !defined(SERVO_REFRESH_INTERVAL) && defined(REFRESH_INTERVAL)
185 #define SERVO_REFRESH_INTERVAL_MICROS REFRESH_INTERVAL // // minimum time to refresh servos in microseconds (from Servo.h)
187 #if !defined(SERVO_REFRESH_INTERVAL) && defined(REFRESH_USEC)
188 #define SERVO_REFRESH_INTERVAL_MICROS REFRESH_USEC // // minimum time to refresh servos in microseconds (from ESP32Servo.h)
190 #if !defined(SERVO_REFRESH_INTERVAL_MICROS)
191 #define SERVO_REFRESH_INTERVAL_MICROS 20000 // // minimum time to refresh servos in microseconds (from Servo.h)
193 #if !defined(INVALID_SERVO)
194 #define INVALID_SERVO 255 // flag indicating an invalid servo index (from Servo.h)
196 #define SERVO_REFRESH_INTERVAL_MILLIS (SERVO_REFRESH_INTERVAL_MICROS/1000) // 20 - used for delay()
197 #define SERVO_REFRESH_FREQUENCY (MILLIS_IN_ONE_SECOND/SERVO_REFRESH_INTERVAL_MILLIS) // 50
206 #if !defined(DISABLE_COMPLEX_FUNCTIONS)
213 #if !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
222 #if !defined(THRESHOLD_VALUE_FOR_INTERPRETING_VALUE_AS_MICROSECONDS)
223 #define THRESHOLD_VALUE_FOR_INTERPRETING_VALUE_AS_MICROSECONDS 360 // treat values less than 360 as angles in degrees, others are handled as microseconds
238 #if !defined(MINIMUM_PULSE_WIDTH)
239 #define MINIMUM_PULSE_WIDTH 400 // The shortest pulse which can be sent to a servo by this library. Checked by underlying Arduino writeMicroseconds().
241 #if !defined(MAXIMUM_PULSE_WIDTH)
242 #define MAXIMUM_PULSE_WIDTH 3500 // the longest pulse which can be sent sent to a servo by this library. Checked by underlying Arduino writeMicroseconds().
246 #define DEFAULT_MICROSECONDS_FOR_0_DEGREE 544
247 #define DEFAULT_MICROSECONDS_FOR_45_DEGREE (544 + ((2400 - 544) / 4)) // 1008
248 #define DEFAULT_MICROSECONDS_FOR_90_DEGREE (544 + ((2400 - 544) / 2)) // 1472
249 #define DEFAULT_MICROSECONDS_FOR_135_DEGREE (2400 - ((2400 - 544) / 4)) // 1936
250 #define DEFAULT_MICROSECONDS_FOR_180_DEGREE 2400
253 #define DEFAULT_PCA9685_UNITS_FOR_0_DEGREE 111 // 111.411 = 544 us
254 #define DEFAULT_PCA9685_UNITS_FOR_45_DEGREE (111 + ((491 - 111) / 4)) // 206
255 #define DEFAULT_PCA9685_UNITS_FOR_90_DEGREE (111 + ((491 - 111) / 2)) // 301 = 1472 us
256 #define DEFAULT_PCA9685_UNITS_FOR_135_DEGREE (491 - ((491 - 111) / 4)) // 369
257 #define DEFAULT_PCA9685_UNITS_FOR_180_DEGREE 491 // 491.52 = 2400 us
268 #if !defined(MICROSECONDS_FOR_ROTATING_SERVO_STOP)
269 #define MICROSECONDS_FOR_ROTATING_SERVO_STOP 1500 // Change this value to your servos real stop value
274 #define MICROSECONDS_FOR_ROTATING_SERVO_CLOCKWISE_MAX (MICROSECONDS_FOR_ROTATING_SERVO_STOP - 200)
275 #define MICROSECONDS_FOR_ROTATING_SERVO_CLOCKWISE_HALF (MICROSECONDS_FOR_ROTATING_SERVO_STOP - 100)
276 #define MICROSECONDS_FOR_ROTATING_SERVO_CLOCKWISE_QUARTER (MICROSECONDS_FOR_ROTATING_SERVO_STOP - 50)
277 #define MICROSECONDS_FOR_ROTATING_SERVO_COUNTER_CLOCKWISE_MAX (MICROSECONDS_FOR_ROTATING_SERVO_STOP + 200)
278 #define MICROSECONDS_FOR_ROTATING_SERVO_COUNTER_CLOCKWISE_HALF (MICROSECONDS_FOR_ROTATING_SERVO_STOP + 100)
279 #define MICROSECONDS_FOR_ROTATING_SERVO_COUNTER_CLOCKWISE_QUARTER (MICROSECONDS_FOR_ROTATING_SERVO_STOP + 50)
281 #if (!(defined(ENABLE_EASE_QUADRATIC) || defined(ENABLE_EASE_CUBIC) || defined(ENABLE_EASE_QUARTIC) \
282 || defined(ENABLE_EASE_SINE) || defined(ENABLE_EASE_CIRCULAR) || defined(ENABLE_EASE_BACK) \
283 || defined(ENABLE_EASE_USER) \
284 || defined(ENABLE_EASE_ELASTIC) || defined(ENABLE_EASE_BOUNCE)|| defined(ENABLE_EASE_PRECISION) \
286 #define ENABLE_EASE_QUADRATIC
287 #define ENABLE_EASE_CUBIC
288 #define ENABLE_EASE_QUARTIC
289 #define ENABLE_EASE_USER
290 # if !defined(DISABLE_COMPLEX_FUNCTIONS)
291 #define ENABLE_EASE_SINE
292 #define ENABLE_EASE_CIRCULAR
293 #define ENABLE_EASE_BACK
294 #define ENABLE_EASE_ELASTIC
295 #define ENABLE_EASE_BOUNCE
296 #define ENABLE_EASE_PRECISION
317 #define EASE_FUNCTION_DEGREE_INDICATOR_OFFSET 200 // Returns 20 for -180 degree, 110 for -90 degree, 200 for 0 degree and 380 for 180 degree.
318 #define EASE_FUNCTION_DEGREE_THRESHOLD (EASE_FUNCTION_DEGREE_INDICATOR_OFFSET - 180) // allows -180 degree.
319 #define EASE_FUNCTION_MICROSECONDS_INDICATOR_OFFSET (EASE_FUNCTION_DEGREE_INDICATOR_OFFSET + 200) // Offset to decide if the user function returns microseconds instead of 0.0 to 1.0. => returns 256 for 0 degree.
325 #define CALL_STYLE_DIRECT 0x00 // == IN
326 #define CALL_STYLE_IN 0x00
327 #define CALL_STYLE_OUT 0x40
328 #define CALL_STYLE_IN_OUT 0x80
329 #define CALL_STYLE_BOUNCING_OUT_IN 0xC0 // Bouncing has double movement, so double time (half speed) is taken for this modes
331 #define CALL_STYLE_MASK 0xC0
332 #define EASE_TYPE_MASK 0x0F
334 #define EASE_LINEAR 0x00 // No bouncing available
336 #if defined(ENABLE_EASE_QUADRATIC)
337 #define EASE_QUADRATIC_IN 0x01
338 #define EASE_QUADRATIC_OUT 0x41
339 #define EASE_QUADRATIC_IN_OUT 0x81
340 #define EASE_QUADRATIC_BOUNCING 0xC1
343 #if defined(ENABLE_EASE_CUBIC)
344 #define EASE_CUBIC_IN 0x02
345 #define EASE_CUBIC_OUT 0x42
346 #define EASE_CUBIC_IN_OUT 0x82
347 #define EASE_CUBIC_BOUNCING 0xC2
350 #if defined(ENABLE_EASE_QUARTIC)
351 #define EASE_QUARTIC_IN 0x03
352 #define EASE_QUARTIC_OUT 0x43
353 #define EASE_QUARTIC_IN_OUT 0x83
354 #define EASE_QUARTIC_BOUNCING 0xC3
357 #if defined(ENABLE_EASE_USER)
358 #define EASE_USER_DIRECT 0x06
359 #define EASE_USER_IN 0x06
360 #define EASE_USER_OUT 0x46
361 #define EASE_USER_IN_OUT 0x86
362 #define EASE_USER_BOUNCING 0xC6
365 #define EASE_DUMMY_MOVE 0x07 // can be used as delay
367 #if defined(ENABLE_EASE_SINE)
368 #define EASE_SINE_IN 0x08
369 #define EASE_SINE_OUT 0x48
370 #define EASE_SINE_IN_OUT 0x88
371 #define EASE_SINE_BOUNCING 0xC8
374 #if defined(ENABLE_EASE_CIRCULAR)
375 #define EASE_CIRCULAR_IN 0x09
376 #define EASE_CIRCULAR_OUT 0x49
377 #define EASE_CIRCULAR_IN_OUT 0x89
378 #define EASE_CIRCULAR_BOUNCING 0xC9
381 #if defined(ENABLE_EASE_BACK)
382 #define EASE_BACK_IN 0x0A
383 #define EASE_BACK_OUT 0x4A
384 #define EASE_BACK_IN_OUT 0x8A
385 #define EASE_BACK_BOUNCING 0xCA
388 #if defined(ENABLE_EASE_ELASTIC)
389 #define EASE_ELASTIC_IN 0x0B
390 #define EASE_ELASTIC_OUT 0x4B
391 #define EASE_ELASTIC_IN_OUT 0x8B
392 #define EASE_ELASTIC_BOUNCING 0xCB
395 #if defined(ENABLE_EASE_BOUNCE)
397 #define EASE_BOUNCE_IN 0x4C // call OUT function inverse
398 #define EASE_BOUNCE_OUT 0x0C // call OUT function direct
401 #if defined(ENABLE_EASE_PRECISION)
402 #define EASE_PRECISION_IN 0x0D // Negative bounce for movings from above (go in to origin)
403 #define EASE_PRECISION_OUT 0x4D // Positive bounce for movings from below (go out from origin)
408 extern const char easeTypeLinear[]
PROGMEM;
409 #if !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
410 extern const char easeTypeQuadratic[]
PROGMEM;
411 extern const char easeTypeCubic[]
PROGMEM;
412 extern const char easeTypeQuartic[]
PROGMEM;
413 extern const char easeTypePrecision[]
PROGMEM;
414 extern const char easeTypeUser[]
PROGMEM;
415 extern const char easeTypeDummy[]
PROGMEM;
416 # if !defined(DISABLE_COMPLEX_FUNCTIONS)
417 extern const char easeTypeSine[]
PROGMEM;
418 extern const char easeTypeCircular[]
PROGMEM;
419 extern const char easeTypeBack[]
PROGMEM;
420 extern const char easeTypeElastic[]
PROGMEM;
421 extern const char easeTypeBounce[]
PROGMEM;
422 # endif // !defined(DISABLE_COMPLEX_FUNCTIONS)
423 #endif // !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
425 extern const char *
const easeTypeStrings[]
PROGMEM;
428 #define PCA9685_GENERAL_CALL_ADDRESS 0x00
429 #define PCA9685_SOFTWARE_RESET 6
430 #define PCA9685_DEFAULT_ADDRESS 0x40
431 #define PCA9685_MAX_CHANNELS 16 // 16 PWM channels on each PCA9685 expansion module
432 #define PCA9685_MODE1_REGISTER 0x0
433 #define PCA9685_MODE_1_RESTART 7
434 #define PCA9685_MODE_1_AUTOINCREMENT 5
435 #define PCA9685_MODE_1_SLEEP 4
436 #define PCA9685_MODE1_EXTCLK 6 // Use EXTCLK pin clock
437 #define PCA9685_FIRST_PWM_REGISTER 0x06
438 #define PCA9685_PRESCALE_REGISTER 0xFE
439 #if !defined(PCA9685_ACTUAL_CLOCK_FREQUENCY)
441 #define PCA9685_ACTUAL_CLOCK_FREQUENCY 25000000L // 25 MHz this is the default frequency
444 #define PCA9685_PRESCALER_FOR_20_MS ((PCA9685_ACTUAL_CLOCK_FREQUENCY /(4096L * 50)) - 1) //for 25 MHz it is: 121 / 0x79 for 20 ms or 50 Hz
447 #define START_UPDATE_BY_INTERRUPT true
448 #define DO_NOT_START_UPDATE_BY_INTERRUPT false
450 #define mCurrentMicrosecondsOrUnits mLastTargetMicrosecondsOrUnits // to be backwards compatible
455 #if (!defined(USE_PCA9685_SERVO_EXPANDER) || defined(USE_SERVO_LIB)) && !defined(USE_LIGHTWEIGHT_SERVO_LIBRARY)
461 #if defined(USE_PCA9685_SERVO_EXPANDER)
462 # if defined(ARDUINO_SAM_DUE)
463 ServoEasing(uint8_t aPCA9685I2CAddress, TwoWire *aI2CClass = &Wire1);
465 # if defined(USE_SOFT_I2C_MASTER)
468 ServoEasing(uint8_t aPCA9685I2CAddress, TwoWire *aI2CClass = &Wire);
474 void PCA9685Init(uint32_t aActualPCA9685ClockFrequencyHertz);
475 void PCA9685InitWithExternalClock(uint32_t aExternalClockFrequencyHertz);
476 void I2CWriteByte(uint8_t aAddress, uint8_t aData);
477 void setPWM(uint16_t aPWMOffValueAsUnits);
478 void setPWM(uint16_t aPWMOnStartValueAsUnits, uint16_t aPWMPulseDurationAsUnits);
480 int MicrosecondsToPCA9685Units(
int aMicroseconds);
481 int PCA9685UnitsToMicroseconds(
int aPCA9685Units);
482 #endif // defined(USE_PCA9685_SERVO_EXPANDER)
487 uint8_t
attach(
int aPin,
int aInitialDegreeOrMicrosecond);
488 uint8_t
attachWithTrim(
int aPin,
int aTrimDegreeOrMicrosecond,
int aInitialDegreeOrMicrosecond);
490 uint8_t
attach(
int aPin,
int aMicrosecondsForServo0Degree,
int aMicrosecondsForServo180Degree);
491 uint8_t
attach(
int aPin,
int aInitialDegreeOrMicrosecond,
int aMicrosecondsForServo0Degree,
int aMicrosecondsForServo180Degree);
492 uint8_t
attachWithTrim(
int aPin,
int aTrimDegreeOrMicrosecond,
int aInitialDegreeOrMicrosecond,
493 int aMicrosecondsForServo0Degree,
int aMicrosecondsForServo180Degree);
494 uint8_t
attach(
int aPin,
int aMicrosecondsForServoLowDegree,
int aMicrosecondsForServoHighDegree,
int aServoLowDegree,
495 int aServoHighDegree);
496 uint8_t
attach(
int aPin,
int aInitialDegreeOrMicrosecond,
int aMicrosecondsForServoLowDegree,
497 int aMicrosecondsForServoHighDegree,
int aServoLowDegree,
int aServoHighDegree);
498 uint8_t
attachWithTrim(
int aPin,
int aTrimDegreeOrMicrosecond,
int aInitialDegreeOrMicrosecond,
499 int aMicrosecondsForServoLowDegree,
int aMicrosecondsForServoHighDegree,
int aServoLowDegree,
int aServoHighDegree);
505 void setTrim(
int aTrimDegreeOrMicrosecond,
bool aDoWrite =
false);
508 #if defined(ENABLE_MIN_AND_MAX_CONSTRAINTS)
509 void setMaxConstraint(
int aMaxDegreeOrMicrosecond);
510 void setMinConstraint(
int aMinDegreeOrMicrosecond);
511 void setMinMaxConstraint(
int aMinDegreeOrMicrosecond,
int aMaxDegreeOrMicrosecond);
514 #if !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
520 # if defined(ENABLE_EASE_USER)
522 void *aUserDataPointer =
nullptr);
527 void write(
int aTargetDegreeOrMicrosecond);
530 void easeTo(
int aTargetDegreeOrMicrosecond);
531 void easeTo(
int aTargetDegreeOrMicrosecond, uint_fast16_t aDegreesPerSecond);
532 void easeToD(
int aTargetDegreeOrMicrosecond, uint_fast16_t aMillisForMove);
534 bool setEaseTo(
int aTargetDegreeOrMicrosecond);
535 bool setEaseTo(
unsigned int aTargetDegreeOrMicrosecond);
536 bool setEaseTo(
int aTargetDegreeOrMicrosecond, uint_fast16_t aDegreesPerSecond);
538 bool startEaseTo(
unsigned int aTargetDegreeOrMicrosecond);
539 bool startEaseTo(
int aTargetDegreeOrMicrosecond, uint_fast16_t aDegreesPerSecond,
bool aStartUpdateByInterrupt =
541 bool startEaseTo(
unsigned int aTargetDegreeOrMicrosecond, uint_fast16_t aDegreesPerSecond,
bool aStartUpdateByInterrupt =
543 bool setEaseToD(
int aTargetDegreeOrMicrosecond, uint_fast16_t aDegreesPerSecond);
544 bool setEaseToD(
unsigned int aTargetDegreeOrMicrosecond, uint_fast16_t aDegreesPerSecond);
545 bool startEaseToD(
int aTargetDegreeOrMicrosecond, uint_fast16_t aMillisForMove,
bool aStartUpdateByInterrupt =
547 bool startEaseToD(
unsigned int aTargetDegreeOrMicrosecond, uint_fast16_t aMillisForMove,
bool aStartUpdateByInterrupt =
550 void write(
float aTargetDegreeOrMicrosecond);
552 void easeTo(
float aTargetDegreeOrMicrosecond);
553 void easeTo(
float aTargetDegreeOrMicrosecond, uint_fast16_t aDegreesPerSecond);
554 void easeToD(
float aTargetDegreeOrMicrosecond, uint_fast16_t aMillisForMove);
556 bool setEaseTo(
float aTargetDegreeOrMicrosecond);
557 bool setEaseTo(
float aTargetDegreeOrMicrosecond, uint_fast16_t aDegreesPerSecond);
558 bool startEaseTo(
float aTargetDegreeOrMicrosecond);
559 bool startEaseTo(
float aTargetDegreeOrMicrosecond, uint_fast16_t aDegreesPerSecond,
bool aStartUpdateByInterrupt =
561 bool setEaseToD(
float aTargetDegreeOrMicrosecond, uint_fast16_t aDegreesPerSecond);
562 bool startEaseToD(
float aTargetDegreeOrMicrosecond, uint_fast16_t aMillisForMove,
bool aStartUpdateByInterrupt =
567 void setSpeed(uint_fast16_t aDegreesPerSecond);
590 __attribute__ ((deprecated (
"Replaced by isMoving(). Often better to use areInterruptsActive() instead.")));
601 void print(Print *aSerial,
bool doExtendedOutput =
true);
602 void printDynamic(Print *aSerial,
bool doExtendedOutput =
true);
612 static float CubicEaseIn(
float aPercentageOfCompletion);
614 static float SineEaseIn(
float aPercentageOfCompletion);
616 static float BackEaseIn(
float aPercentageOfCompletion);
626 #if defined(USE_PCA9685_SERVO_EXPANDER)
627 # if defined(__AVR__)
628 bool InitializeAndCheckI2CConnection(Print *aSerial) __attribute__ ((deprecated (
"Use initializeAndCheckI2CConnection()")));
629 bool initializeAndCheckI2CConnection(Print *aSerial);
631 bool InitializeAndCheckI2CConnection(Stream *aSerial); __attribute__ ((deprecated (
"Use initializeAndCheckI2CConnection()")));
632 bool initializeAndCheckI2CConnection(Stream *aSerial);
655 #if !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
657 # if defined(ENABLE_EASE_USER)
665 #if defined(USE_PCA9685_SERVO_EXPANDER)
666 # if defined(USE_SERVO_LIB)
668 bool mServoIsConnectedToExpander;
670 uint8_t mPCA9685I2CAddress;
671 # if !defined(USE_SOFT_I2C_MASTER)
681 #if !defined(DISABLE_PAUSE_RESUME)
692 #if defined(ENABLE_MIN_AND_MAX_CONSTRAINTS)
693 int mMaxMicrosecondsOrUnits;
694 int mMinMicrosecondsOrUnits;
726 #define areInterruptsActive() ServoEasing::areInterruptsActive()
727 #define sServoArray ServoEasing::ServoEasingArray
728 #define sServoNextPositionArray ServoEasing::ServoEasingNextPositionArray
738 void setIntegerDegreeForAllServos(uint_fast8_t aNumberOfValues, va_list *aDegreeValues);
739 void setFloatDegreeForAllServos(uint_fast8_t aNumberOfValues, va_list *aDegreeValues);
741 #if defined(va_start)
742 void setDegreeForAllServos(uint_fast8_t aNumberOfValues, ...)
743 __attribute__ ((deprecated ("Please use setIntegerDegreeForAllServos().")));
744 void setIntegerDegreeForAllServos(uint_fast8_t aNumberOfValues, ...);
745 void setFloatDegreeForAllServos(uint_fast8_t aNumberOfValues, ...);
755 #if !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
767 __attribute__ ((deprecated ("Please use setEaseToForAllServosSynchronizeAndWait().")));
778 #if defined(__AVR_ATmega328P__)
779 void setTimer1InterruptMarginMicros(uint16_t aInterruptMarginMicros);
794 #if !defined(STR_HELPER) && !defined(STR)
795 #define STR_HELPER(x) #x
796 #define STR(x) STR_HELPER(x)
969 #if !defined(_SERVO_EASING_HPP) && !defined(SUPPRESS_HPP_WARNING)
970 #warning You probably must change the line #include "ServoEasing.h" to #include "ServoEasing.hpp" in your ino file or define SUPPRESS_HPP_WARNING before the include to suppress this warning.
973 #endif // _SERVO_EASING_H
int getDeltaMicrosecondsOrUnits()
void setEaseToForAllServosSynchronizeAndWaitForAllServosToStop()
Synchronize and blocking wait until all servos are stopped Take the longer duration in order to move ...
void enableServoEasingInterrupt()
Timer1 is used for the Arduino Servo library.
void _setTrimMicrosecondsOrUnits(int aTrimMicrosecondsOrUnits, bool aDoWrite=false)
int MicrosecondsOrUnitsToDegree(int aMicrosecondsOrUnits)
Used to convert e.g.
uint_fast16_t mSpeed
max speed is 450 degree/sec for SG90 and 540 degree/second for MG90 servos -> see speedTest....
volatile bool mServoMoves
void _writeMicrosecondsOrUnits(int aTargetMicrosecondsOrUnits)
Internal function Before sending the value to the underlying Servo library, trim and reverse is appli...
volatile int mLastTargetMicrosecondsOrUnits
Internally only microseconds (or units (= 4.88 us) if using PCA9685 expander) and not degree are used...
void updateAndWaitForAllServosToStop()
Blocking wait until all servos are stopped.
uint8_t attach(int aPin)
Specify the microseconds values for 0 and 180 degree for the servo.
void setReverseOperation(bool aOperateServoReverse)
uint_fast8_t getEasingType()
void disableServoEasingInterrupt()
void(* TargetPositionReachedHandler)(ServoEasing *)
Is called any time when target servo position is reached.
int mStartMicrosecondsOrUnits
Only used with millisAtStartMove to compute currentMicrosecondsOrUnits in update()
int getMillisForCompleteMove()
void setTargetPositionReachedHandler(void(*aTargetPositionReachedHandler)(ServoEasing *))
int mServo0DegreeMicrosecondsOrUnits
Values contain always microseconds except for servos connected to a PCA9685 expander,...
int mTrimMicrosecondsOrUnits
This value is always added by the function _writeMicrosecondsOrUnits() to the requested degree/units/...
#define areInterruptsActive()
uint8_t mServoPin
pin number / port number of PCA9685 [0-15] or NO_SERVO_ATTACHED_PIN_NUMBER - at least required for Li...
bool setEaseTo(int aTargetDegreeOrMicrosecond)
int getEndMicrosecondsOrUnits()
void resumeWithInterrupts()
void synchronizeAndEaseToArrayPositions() __attribute__((deprecated("Please use setEaseToForAllServosSynchronizeAndWait().")))
void stop()
This stops the servo at any position.
bool setEaseToForAllServos()
Sets target position using content of ServoEasingNextPositionArray.
uint8_t attachWithTrim(int aPin, int aTrimDegreeOrMicrosecond, int aInitialDegreeOrMicrosecond)
Combination of attach with initial setTrim() and write().
bool noMovement(uint_fast16_t aMillisToWait)
stay at the position for aMillisToWait Used as delay for callback
bool checkI2CConnection(uint8_t aI2CAddress, Stream *aSerial)
bool isMoving()
Test if servo is moving yet.
void setUserDataPointer(void *aUserDataPointer)
void printArrayPositions(Print *aSerial)
Prints content of ServoNextPositionArray for debugging purposes.
bool delayAndUpdateAndWaitForAllServosToStop(unsigned long aMillisDelay, bool aTerminateDelayIfAllServosStopped=false)
void printExtra(Print *aSerial)
static float BackEaseIn(float aPercentageOfCompletion)
see: https://easings.net/#easeInOutBack and https://github.com/warrenm/AHEasing/blob/master/AHEasing/...
int mEndMicrosecondsOrUnits
Only used once as last value if movement was finished to provide exact end position.
int DegreeToMicrosecondsOrUnitsWithTrimAndReverse(int aDegree)
Mainly for testing, since trim and reverse are applied at each write.
int applyTrimAndReverseToTargetMicrosecondsOrUnits(int aTargetMicrosecondsOrUnits)
float LinearWithQuadraticBounce(float aPercentageOfCompletion)
PRECISION (LinearWithQuadraticBounce) is like linear, but adds a 5 degree bounce in the last 20 % of ...
void setTrim(int aTrimDegreeOrMicrosecond, bool aDoWrite=false)
void printDynamic(Print *aSerial, bool doExtendedOutput=true)
Prints values which may change from move to move.
int clipDegreeSpecial(uint_fast8_t aDegreeToClip)
Clips the unsigned degree value and handles unsigned underflow.
int MicrosecondsOrUnitsToMicroseconds(int aMicrosecondsOrUnits)
uint_fast16_t mMillisForCompleteMove
static float EaseOutBounce(float aPercentageOfCompletion)
!!! ATTENTION !!! we have only the out function implemented see: https://easings.net/de#easeOutBounce...
void setEasingTypeForAllServos(uint_fast8_t aEasingType)
60 us for single servo + 160 us per servo if using I2C e.g.for PCA9685 expander at 400 kHz or + 100 a...
void resumeWithoutInterrupts()
void print(Print *aSerial, bool doExtendedOutput=true)
Do a printDynamic() and a printStatic()
uint32_t mMillisAtStartMove
void easeToD(int aTargetDegreeOrMicrosecond, uint_fast16_t aMillisForMove)
float(* mUserEaseInFunction)(float aPercentageOfCompletion, void *aUserDataPointer)
int MicrosecondsToDegree(int aMicroseconds)
Only used in startEaseTo to compute target degree For PCA9685, we have stored units in mServo0DegreeM...
void setEasingTypeForMultipleServos(uint_fast8_t aNumberOfServos, uint_fast8_t aEasingType)
Sets easing type aEasingType for the first aNumberOfServos in ServoEasingArray[].
void resumeWithInterruptsAllServos()
void printStatic(Print *aSerial)
Prints values which normally does NOT change from move to move.
const char easeTypeLinear[] PROGMEM
void setSpeedForAllServos(uint_fast16_t aDegreesPerSecond)
float callEasingFunction(float aPercentageOfCompletion)
bool startEaseToD(int aTargetDegreeOrMicrosecond, uint_fast16_t aMillisForMove, bool aStartUpdateByInterrupt=START_UPDATE_BY_INTERRUPT)
Sets up all the values required for a smooth move to new value Lower level function with time instead...
static float CircularEaseIn(float aPercentageOfCompletion)
It is very fast in the middle! see: https://easings.net/#easeInOutCirc and https://github....
void handleServoTimerInterrupt()
Update all servos from list and check if all servos have stopped.
void detach()
No servo signal is generated for a detached servo / the output is constant LOW.
uint32_t mMillisAtStopMove
bool startEaseTo(int aTargetDegreeOrMicrosecond)
int getEndMicrosecondsOrUnitsWithTrim()
Not used internally.
void setEaseToForAllServosSynchronizeAndStartInterrupt()
static float ServoEasingNextPositionArray[MAX_EASING_SERVOS]
Used exclusively for *ForAllServos() functions.
int getCurrentMicroseconds()
static volatile bool sInterruptsAreActive
It is required for ESP32, where the timer interrupt routine does not block the loop.
int mServo180DegreeMicrosecondsOrUnits
static void printEasingType(Print *aSerial, uint_fast8_t aEasingType)
static ServoEasing * ServoEasingArray[MAX_EASING_SERVOS]
#define MAX_EASING_SERVOS
int DegreeOrMicrosecondToMicrosecondsOrUnits(int aDegreeOrMicrosecond)
We have around 10 us per degree Used to convert (external) provided degree values to internal microse...
static float QuadraticEaseIn(float aPercentageOfCompletion)
The simplest non linear easing function.
bool setEaseToDForAllServos(uint_fast16_t aMillisForMove)
Sets target position using content of ServoEasingNextPositionArray and use aMillisForMove instead of ...
void registerUserEaseInFunction(float(*aUserEaseInFunction)(float aPercentageOfCompletion, void *aUserDataPointer), void *aUserDataPointer=nullptr)
#define START_UPDATE_BY_INTERRUPT
static float SineEaseIn(float aPercentageOfCompletion)
Take half of negative cosines of first quadrant Is behaves almost like QUADRATIC.
bool mOperateServoReverse
Reverse means, that values for 180 and 0 degrees are swapped by: aValue = mServo180DegreeMicroseconds...
void synchronizeAllServosAndStartInterrupt(bool aStartUpdateByInterrupt=START_UPDATE_BY_INTERRUPT, bool aSynchronizeToMinimumDuration=false)
Take the longest duration in order to move all servos synchronously.
static uint_fast8_t sServoArrayMaxIndex
Two arrays of all servos to enable synchronized movings Servos are inserted in the order,...
void synchronizeAllServosStartAndWaitForAllServosToStop()
Synchronize and blocking wait until all servos are stopped.
void writeAllServos(int aTargetDegreeOrMicrosecond)
int mDeltaMicrosecondsOrUnits
end - start
bool setEaseToD(int aTargetDegreeOrMicrosecond, uint_fast16_t aDegreesPerSecond)
uint8_t mServoIndex
Index in sServoArray or INVALID_SERVO if error while attach() or if detached.
void setSpeed(uint_fast16_t aDegreesPerSecond)
bool isMovingAndCallYield() __attribute__((deprecated("Replaced by isMoving(). Often better to use areInterruptsActive() instead.")))
Call yield here (actually only for ESP8266), so the user do not need to care for it in long running l...
void write(int aTargetDegreeOrMicrosecond)
Tested value of 400 for my PCA9685 expander 10/25 (was effectively 382 us / - 2 %,...
void resumeWithoutInterruptsAllServos()
static float CubicEaseIn(float aPercentageOfCompletion)
void easeTo(int aTargetDegreeOrMicrosecond)
static float ElasticEaseIn(float aPercentageOfCompletion)
see: https://easings.net/#easeInOutElastic and https://github.com/warrenm/AHEasing/blob/master/AHEasi...
static float QuarticEaseIn(float aPercentageOfCompletion)
void setEasingType(uint_fast8_t aEasingType)