Go to the documentation of this file.
24 #ifndef _SERVO_EASING_H
25 #define _SERVO_EASING_H
27 #define VERSION_SERVO_EASING "3.2.0"
28 #define VERSION_SERVO_EASING_MAJOR 3
29 #define VERSION_SERVO_EASING_MINOR 2
30 #define VERSION_SERVO_EASING_PATCH 0
37 #define VERSION_HEX_VALUE(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
38 #define VERSION_SERVO_EASING_HEX VERSION_HEX_VALUE(VERSION_SERVO_EASING_MAJOR, VERSION_SERVO_EASING_MINOR, VERSION_SERVO_EASING_PATCH)
40 #define MILLIS_IN_ONE_SECOND 1000L
45 #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.
71 #if defined(USE_LEIGHTWEIGHT_SERVO_LIB) && !(defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__))
72 #error USE_LEIGHTWEIGHT_SERVO_LIB can only be activated for the Atmega328 CPU
81 #if defined(ENABLE_EXTERNAL_SERVO_TIMER_HANDLER)
85 #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))
86 #warning No periodic timer support existent (or known) for this platform. Only blocking functions and simple example will run!
92 #if !defined(USE_PCA9685_SERVO_EXPANDER) || defined(USE_SERVO_LIB)
98 #include <ESP32Servo.h>
100 # elif defined(MEGATINYCORE)
101 #include <Servo_megaTinyCore.h>
103 # elif defined(MEGACOREX)
104 # if __has_include("ServoMegaCoreX.h")
105 #include <ServoMegaCoreX.h>
110 # else // defined(ESP32)
111 # if defined(USE_LEIGHTWEIGHT_SERVO_LIB)
113 # if !defined(MAX_EASING_SERVOS)
114 #define MAX_EASING_SERVOS 2 // default value for UNO etc.
118 # endif // !defined(USE_LEIGHTWEIGHT_SERVO_LIB)
119 # endif // defined(ESP32)
120 #endif // defined(USE_SERVO_LIB)
122 #if defined(ARDUINO_ARCH_MBED) // Arduino Nano 33 BLE
128 #if defined(USE_PCA9685_SERVO_EXPANDER)
129 # if !defined(MAX_EASING_SERVOS)
130 #define MAX_EASING_SERVOS 16 // One PCA9685 has 16 outputs. You must MODIFY this, if you have more than one PCA9685 attached!
131 # endif // defined(USE_PCA9685_SERVO_EXPANDER)
137 # define I2C_CLOCK_FREQUENCY 100000 // 200000 does not work for my ESP32 module together with the timer even with external pullups :-(
138 # elif defined(ESP8266)
139 #define I2C_CLOCK_FREQUENCY 400000 // 400000 is the maximum for 80 MHz clocked ESP8266 (I measured real 330000 Hz for this setting)
141 #define I2C_CLOCK_FREQUENCY 800000 // 1000000 does not work for my Arduino Nano, maybe because of parasitic breadboard capacities
143 #endif // defined(USE_PCA9685_SERVO_EXPANDER)
153 #if !defined(MAX_EASING_SERVOS)
154 # if defined(MAX_SERVOS)
155 #define MAX_EASING_SERVOS MAX_SERVOS // =12 use default value from Servo.h for UNO etc.
157 #define MAX_EASING_SERVOS 12 // just take default value from Servo.h for UNO etc.
159 #endif // !defined(MAX_EASING_SERVOS)
161 #if !defined(DEFAULT_PULSE_WIDTH)
162 #define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached (from Servo.h)
164 #if !defined(REFRESH_INTERVAL)
165 #define REFRESH_INTERVAL 20000 // // minimum time to refresh servos in microseconds (from Servo.h)
167 #if !defined(INVALID_SERVO)
168 #define INVALID_SERVO 255 // flag indicating an invalid servo index (from Servo.h)
170 #define REFRESH_INTERVAL_MICROS REFRESH_INTERVAL // 20000
171 #define REFRESH_INTERVAL_MILLIS (REFRESH_INTERVAL/1000) // 20 - used for delay()
172 #define REFRESH_FREQUENCY (MILLIS_IN_ONE_SECOND/REFRESH_INTERVAL_MILLIS) // 50
181 #if !defined(DISABLE_COMPLEX_FUNCTIONS)
188 #if !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
197 #if !defined(THRESHOLD_VALUE_FOR_INTERPRETING_VALUE_AS_MICROSECONDS)
198 #define THRESHOLD_VALUE_FOR_INTERPRETING_VALUE_AS_MICROSECONDS 360 // treat values less than 360 as angles in degrees, others are handled as microseconds
208 #define DEFAULT_MICROSECONDS_FOR_0_DEGREE 544
209 #define DEFAULT_MICROSECONDS_FOR_45_DEGREE (544 + ((2400 - 544) / 4)) // 1008
210 #define DEFAULT_MICROSECONDS_FOR_90_DEGREE (544 + ((2400 - 544) / 2)) // 1472
211 #define DEFAULT_MICROSECONDS_FOR_135_DEGREE (2400 - ((2400 - 544) / 4)) // 1936
212 #define DEFAULT_MICROSECONDS_FOR_180_DEGREE 2400
215 #define DEFAULT_PCA9685_UNITS_FOR_0_DEGREE 111 // 111.411 = 544 us
216 #define DEFAULT_PCA9685_UNITS_FOR_45_DEGREE (111 + ((491 - 111) / 4)) // 206
217 #define DEFAULT_PCA9685_UNITS_FOR_90_DEGREE (111 + ((491 - 111) / 2)) // 301 = 1472 us
218 #define DEFAULT_PCA9685_UNITS_FOR_135_DEGREE (491 - ((491 - 111) / 4)) // 369
219 #define DEFAULT_PCA9685_UNITS_FOR_180_DEGREE 491 // 491.52 = 2400 us
230 #if !defined(MICROSECONDS_FOR_ROTATING_SERVO_STOP)
231 #define MICROSECONDS_FOR_ROTATING_SERVO_STOP 1500 // Change this value to your servos real stop value
236 #define MICROSECONDS_FOR_ROTATING_SERVO_CLOCKWISE_MAX (MICROSECONDS_FOR_ROTATING_SERVO_STOP - 200)
237 #define MICROSECONDS_FOR_ROTATING_SERVO_CLOCKWISE_HALF (MICROSECONDS_FOR_ROTATING_SERVO_STOP - 100)
238 #define MICROSECONDS_FOR_ROTATING_SERVO_CLOCKWISE_QUARTER (MICROSECONDS_FOR_ROTATING_SERVO_STOP - 50)
239 #define MICROSECONDS_FOR_ROTATING_SERVO_COUNTER_CLOCKWISE_MAX (MICROSECONDS_FOR_ROTATING_SERVO_STOP + 200)
240 #define MICROSECONDS_FOR_ROTATING_SERVO_COUNTER_CLOCKWISE_HALF (MICROSECONDS_FOR_ROTATING_SERVO_STOP + 100)
241 #define MICROSECONDS_FOR_ROTATING_SERVO_COUNTER_CLOCKWISE_QUARTER (MICROSECONDS_FOR_ROTATING_SERVO_STOP + 50)
243 #if (!(defined(ENABLE_EASE_QUADRATIC) || defined(ENABLE_EASE_CUBIC) || defined(ENABLE_EASE_QUARTIC) \
244 || defined(ENABLE_EASE_SINE) || defined(ENABLE_EASE_CIRCULAR) || defined(ENABLE_EASE_BACK) \
245 || defined(ENABLE_EASE_USER) \
246 || defined(ENABLE_EASE_ELASTIC) || defined(ENABLE_EASE_BOUNCE)|| defined(ENABLE_EASE_PRECISION) \
248 #define ENABLE_EASE_QUADRATIC
249 #define ENABLE_EASE_CUBIC
250 #define ENABLE_EASE_QUARTIC
251 #define ENABLE_EASE_USER
252 # if !defined(DISABLE_COMPLEX_FUNCTIONS)
253 #define ENABLE_EASE_SINE
254 #define ENABLE_EASE_CIRCULAR
255 #define ENABLE_EASE_BACK
256 #define ENABLE_EASE_ELASTIC
257 #define ENABLE_EASE_BOUNCE
258 #define ENABLE_EASE_PRECISION
279 #define EASE_FUNCTION_DEGREE_INDICATOR_OFFSET 200 // Returns 20 for -180°, 110 for -90°, 200 for 0° and 380 for 180°.
280 #define EASE_FUNCTION_DEGREE_THRESHOLD (EASE_FUNCTION_DEGREE_INDICATOR_OFFSET - 180) // allows -180°.
281 #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.
287 #define CALL_STYLE_DIRECT 0x00 // == IN
288 #define CALL_STYLE_IN 0x00
289 #define CALL_STYLE_OUT 0x40
290 #define CALL_STYLE_IN_OUT 0x80
291 #define CALL_STYLE_BOUNCING_OUT_IN 0xC0 // Bouncing has double movement, so double time (half speed) is taken for this modes
293 #define CALL_STYLE_MASK 0xC0
294 #define EASE_TYPE_MASK 0x0F
296 #define EASE_LINEAR 0x00 // No bouncing available
298 #if defined(ENABLE_EASE_QUADRATIC)
299 #define EASE_QUADRATIC_IN 0x01
300 #define EASE_QUADRATIC_OUT 0x41
301 #define EASE_QUADRATIC_IN_OUT 0x81
302 #define EASE_QUADRATIC_BOUNCING 0xC1
305 #if defined(ENABLE_EASE_CUBIC)
306 #define EASE_CUBIC_IN 0x02
307 #define EASE_CUBIC_OUT 0x42
308 #define EASE_CUBIC_IN_OUT 0x82
309 #define EASE_CUBIC_BOUNCING 0xC2
312 #if defined(ENABLE_EASE_QUARTIC)
313 #define EASE_QUARTIC_IN 0x03
314 #define EASE_QUARTIC_OUT 0x43
315 #define EASE_QUARTIC_IN_OUT 0x83
316 #define EASE_QUARTIC_BOUNCING 0xC3
319 #if defined(ENABLE_EASE_USER)
320 #define EASE_USER_DIRECT 0x06
321 #define EASE_USER_IN 0x06
322 #define EASE_USER_OUT 0x46
323 #define EASE_USER_IN_OUT 0x86
324 #define EASE_USER_BOUNCING 0xC6
327 #define EASE_DUMMY_MOVE 0x07 // can be used as delay
329 #if defined(ENABLE_EASE_SINE)
330 #define EASE_SINE_IN 0x08
331 #define EASE_SINE_OUT 0x48
332 #define EASE_SINE_IN_OUT 0x88
333 #define EASE_SINE_BOUNCING 0xC8
336 #if defined(ENABLE_EASE_CIRCULAR)
337 #define EASE_CIRCULAR_IN 0x09
338 #define EASE_CIRCULAR_OUT 0x49
339 #define EASE_CIRCULAR_IN_OUT 0x89
340 #define EASE_CIRCULAR_BOUNCING 0xC9
343 #if defined(ENABLE_EASE_BACK)
344 #define EASE_BACK_IN 0x0A
345 #define EASE_BACK_OUT 0x4A
346 #define EASE_BACK_IN_OUT 0x8A
347 #define EASE_BACK_BOUNCING 0xCA
350 #if defined(ENABLE_EASE_ELASTIC)
351 #define EASE_ELASTIC_IN 0x0B
352 #define EASE_ELASTIC_OUT 0x4B
353 #define EASE_ELASTIC_IN_OUT 0x8B
354 #define EASE_ELASTIC_BOUNCING 0xCB
357 #if defined(ENABLE_EASE_BOUNCE)
359 #define EASE_BOUNCE_IN 0x4C // call OUT function inverse
360 #define EASE_BOUNCE_OUT 0x0C // call OUT function direct
363 #if defined(ENABLE_EASE_PRECISION)
364 #define EASE_PRECISION_IN 0x0D // Negative bounce for movings from above (go in to origin)
365 #define EASE_PRECISION_OUT 0x4D // Positive bounce for movings from below (go out from origin)
370 extern const char easeTypeLinear[]
PROGMEM;
371 #if !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
372 extern const char easeTypeQuadratic[]
PROGMEM;
373 extern const char easeTypeCubic[]
PROGMEM;
374 extern const char easeTypeQuartic[]
PROGMEM;
375 extern const char easeTypePrecision[]
PROGMEM;
376 extern const char easeTypeUser[]
PROGMEM;
377 extern const char easeTypeDummy[]
PROGMEM;
378 # if !defined(DISABLE_COMPLEX_FUNCTIONS)
379 extern const char easeTypeSine[]
PROGMEM;
380 extern const char easeTypeCircular[]
PROGMEM;
381 extern const char easeTypeBack[]
PROGMEM;
382 extern const char easeTypeElastic[]
PROGMEM;
383 extern const char easeTypeBounce[]
PROGMEM;
384 # endif // !defined(DISABLE_COMPLEX_FUNCTIONS)
385 #endif // !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
387 extern const char *
const easeTypeStrings[]
PROGMEM;
390 #define PCA9685_GENERAL_CALL_ADDRESS 0x00
391 #define PCA9685_SOFTWARE_RESET 6
392 #define PCA9685_DEFAULT_ADDRESS 0x40
393 #define PCA9685_MAX_CHANNELS 16 // 16 PWM channels on each PCA9685 expansion module
394 #define PCA9685_MODE1_REGISTER 0x0
395 #define PCA9685_MODE_1_RESTART 7
396 #define PCA9685_MODE_1_AUTOINCREMENT 5
397 #define PCA9685_MODE_1_SLEEP 4
398 #define PCA9685_FIRST_PWM_REGISTER 0x06
399 #define PCA9685_PRESCALE_REGISTER 0xFE
400 #if !defined(PCA9685_ACTUAL_CLOCK_FREQUENCY)
402 #define PCA9685_ACTUAL_CLOCK_FREQUENCY 25000000L // 25 MHz this is the default frequency
405 #define PCA9685_PRESCALER_FOR_20_MS ((PCA9685_ACTUAL_CLOCK_FREQUENCY /(4096L * 50)) - 1) // = 121 / 0x79 at 50 Hz
408 #define START_UPDATE_BY_INTERRUPT true
409 #define DO_NOT_START_UPDATE_BY_INTERRUPT false
415 #if (!defined(USE_PCA9685_SERVO_EXPANDER) || defined(USE_SERVO_LIB)) && !defined(USE_LEIGHTWEIGHT_SERVO_LIB)
421 #if defined(USE_PCA9685_SERVO_EXPANDER)
422 # if defined(ARDUINO_SAM_DUE)
423 ServoEasing(uint8_t aPCA9685I2CAddress, TwoWire *aI2CClass = &Wire1);
425 # if defined(USE_SOFT_I2C_MASTER)
428 ServoEasing(uint8_t aPCA9685I2CAddress, TwoWire *aI2CClass = &Wire);
434 void I2CWriteByte(uint8_t aAddress, uint8_t aData);
435 void setPWM(uint16_t aPWMOffValueAsUnits);
436 void setPWM(uint16_t aPWMOnStartValueAsUnits, uint16_t aPWMPulseDurationAsUnits);
438 int MicrosecondsToPCA9685Units(
int aMicroseconds);
439 int PCA9685UnitsToMicroseconds(
int aPCA9685Units);
440 #endif // defined(USE_PCA9685_SERVO_EXPANDER)
445 uint8_t
attach(
int aPin,
int aInitialDegreeOrMicrosecond);
446 uint8_t
attachWithTrim(
int aPin,
int aTrimDegreeOrMicrosecond,
int aInitialDegreeOrMicrosecond);
448 uint8_t
attach(
int aPin,
int aMicrosecondsForServo0Degree,
int aMicrosecondsForServo180Degree);
449 uint8_t
attach(
int aPin,
int aInitialDegreeOrMicrosecond,
int aMicrosecondsForServo0Degree,
int aMicrosecondsForServo180Degree);
450 uint8_t
attachWithTrim(
int aPin,
int aTrimDegreeOrMicrosecond,
int aInitialDegreeOrMicrosecond,
451 int aMicrosecondsForServo0Degree,
int aMicrosecondsForServo180Degree);
452 uint8_t
attach(
int aPin,
int aMicrosecondsForServoLowDegree,
int aMicrosecondsForServoHighDegree,
int aServoLowDegree,
453 int aServoHighDegree);
454 uint8_t
attach(
int aPin,
int aInitialDegreeOrMicrosecond,
int aMicrosecondsForServoLowDegree,
455 int aMicrosecondsForServoHighDegree,
int aServoLowDegree,
int aServoHighDegree);
456 uint8_t
attachWithTrim(
int aPin,
int aTrimDegreeOrMicrosecond,
int aInitialDegreeOrMicrosecond,
457 int aMicrosecondsForServoLowDegree,
int aMicrosecondsForServoHighDegree,
int aServoLowDegree,
int aServoHighDegree);
462 void setTrim(
int aTrimDegreeOrMicrosecond,
bool aDoWrite =
false);
465 #if !defined(DISABLE_MIN_AND_MAX_CONSTRAINTS)
471 #if !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
477 # if defined(ENABLE_EASE_USER)
479 void *aUserDataPointer = NULL);
484 void write(
int aTargetDegreeOrMicrosecond);
487 void easeTo(
int aTargetDegreeOrMicrosecond);
488 void easeTo(
int aTargetDegreeOrMicrosecond, uint_fast16_t aDegreesPerSecond);
489 void easeToD(
int aTargetDegreeOrMicrosecond, uint_fast16_t aMillisForMove);
491 bool setEaseTo(
int aTargetDegreeOrMicrosecond);
492 bool setEaseTo(
int aTargetDegreeOrMicrosecond, uint_fast16_t aDegreesPerSecond);
494 bool startEaseTo(
int aTargetDegreeOrMicrosecond, uint_fast16_t aDegreesPerSecond,
bool aStartUpdateByInterrupt =
496 bool setEaseToD(
int aTargetDegreeOrMicrosecond, uint_fast16_t aDegreesPerSecond);
497 bool startEaseToD(
int aTargetDegreeOrMicrosecond, uint_fast16_t aMillisForMove,
bool aStartUpdateByInterrupt =
501 void write(
float aTargetDegreeOrMicrosecond);
503 void easeTo(
float aTargetDegreeOrMicrosecond);
504 void easeTo(
float aTargetDegreeOrMicrosecond, uint_fast16_t aDegreesPerSecond);
505 void easeToD(
float aTargetDegreeOrMicrosecond, uint_fast16_t aMillisForMove);
507 bool setEaseTo(
float aTargetDegreeOrMicrosecond);
508 bool setEaseTo(
float aTargetDegreeOrMicrosecond, uint_fast16_t aDegreesPerSecond);
509 bool startEaseTo(
float aTargetDegreeOrMicrosecond);
510 bool startEaseTo(
float aTargetDegreeOrMicrosecond, uint_fast16_t aDegreesPerSecond,
bool aStartUpdateByInterrupt =
512 bool setEaseToD(
float aTargetDegreeOrMicrosecond, uint_fast16_t aDegreesPerSecond);
513 bool startEaseToD(
float aTargetDegreeOrMicrosecond, uint_fast16_t aMillisForMove,
bool aStartUpdateByInterrupt =
518 void setSpeed(uint_fast16_t aDegreesPerSecond);
536 bool isMovingAndCallYield() __attribute__ ((deprecated (
"Replaced by isMoving(). Often better to use areInterruptsActive() instead.")));
548 void print(Print *aSerial,
bool doExtendedOutput =
true);
549 void printDynamic(Print *aSerial,
bool doExtendedOutput =
true);
558 static float CubicEaseIn(
float aPercentageOfCompletion);
560 static float SineEaseIn(
float aPercentageOfCompletion);
562 static float BackEaseIn(
float aPercentageOfCompletion);
597 #if !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
599 # if defined(ENABLE_EASE_USER)
607 #if defined(USE_PCA9685_SERVO_EXPANDER)
608 # if defined(USE_SERVO_LIB)
610 bool mServoIsConnectedToExpander;
612 uint8_t mPCA9685I2CAddress;
613 # if !defined(USE_SOFT_I2C_MASTER)
623 #if !defined(DISABLE_PAUSE_RESUME)
634 #if !defined(DISABLE_MIN_AND_MAX_CONSTRAINTS)
668 #define areInterruptsActive() ServoEasing::areInterruptsActive()
669 #define sServoArray ServoEasing::ServoEasingArray
670 #define sServoNextPositionArray ServoEasing::ServoEasingNextPositionArray
680 void setDegreeForAllServos(uint_fast8_t aNumberOfValues, va_list *aDegreeValues);
682 #if defined(va_start)
683 void setDegreeForAllServos(uint_fast8_t aNumberOfValues, ...);
693 #if !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
715 #if defined(__AVR_ATmega328P__)
716 void setTimer1InterruptMarginMicros(uint16_t aInterruptMarginMicros);
731 #if !defined(STR_HELPER)
732 #define STR_HELPER(x) #x
733 #define STR(x) STR_HELPER(x)
879 #if !defined(_SERVO_EASING_HPP) && !defined(SUPPRESS_HPP_WARNING)
880 #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.
883 #endif // _SERVO_EASING_H
int getDeltaMicrosecondsOrUnits()
void setEaseToForAllServosSynchronizeAndWaitForAllServosToStop()
Synchronize and blocking wait until all servos are stopped.
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 registerUserEaseInFunction(float(*aUserEaseInFunction)(float aPercentageOfCompletion, void *aUserDataPointer), void *aUserDataPointer=NULL)
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...
int mMinMicrosecondsOrUnits
Min value checked at _writeMicrosecondsOrUnits(), before trim and reverse is applied.
bool setEaseTo(int aTargetDegreeOrMicrosecond)
void synchronizeAllServosAndStartInterrupt(bool aStartUpdateByInterrupt=START_UPDATE_BY_INTERRUPT)
Take the longer duration in order to move all servos synchronously.
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.
int mMaxMicrosecondsOrUnits
Max value checked at _writeMicrosecondsOrUnits(), before trim and reverse is applied.
void setUserDataPointer(void *aUserDataPointer)
void printArrayPositions(Print *aSerial)
Prints content of ServoNextPositionArray for debugging purposes.
bool InitializeAndCheckI2CConnection(Stream *aSerial)
bool delayAndUpdateAndWaitForAllServosToStop(unsigned long aMillisDelay, bool aTerminateDelayIfAllServosStopped=false)
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.
void setMinConstraint(int aMinDegreeOrMicrosecond)
void synchronizeServosAndStartInterrupt(bool doUpdateByInterrupt)
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.
void setMinMaxConstraint(int aMinDegreeOrMicrosecond, int aMaxDegreeOrMicrosecond)
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)
void setMaxConstraint(int aMaxDegreeOrMicrosecond)
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()
Mark a detached servo in the array by setting the object pointer to NULL The next attach() then uses ...
uint32_t mMillisAtStopMove
bool startEaseTo(int aTargetDegreeOrMicrosecond)
Starts interrupt for update()
int getEndMicrosecondsOrUnitsWithTrim()
Not used internally.
void _writeMicrosecondsOrUnits(int aTargetDegreeOrMicrosecond)
Internal function Before sending the value to the underlying Servo library, trim and reverse is appli...
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 ...
#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...
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)
Sets easing parameter, but does not start.
uint8_t mServoIndex
Index in sServoArray or INVALID_SERVO if error while attach() or if detached.
volatile int mCurrentMicrosecondsOrUnits
Internally only microseconds (or units (= 4.88 us) if using PCA9685 expander) and not degree are used...
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)
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)