RSeries astromech firmware
ServoDispatchPCA9685.h
Go to the documentation of this file.
1 #ifndef ServoDispatchPCA9685_h
2 #define ServoDispatchPCA9685_h
3 
4 #include "ServoDispatch.h"
5 #include <Wire.h>
6 
7 #ifdef USE_SERVO_DEBUG
8 #define SERVO_DEBUG_PRINT(s) DEBUG_PRINT(s)
9 #define SERVO_DEBUG_PRINTLN(s) DEBUG_PRINTLN(s)
10 #define SERVO_DEBUG_PRINT_HEX(s) DEBUG_PRINT_HEX(s)
11 #define SERVO_DEBUG_PRINTLN_HEX(s) DEBUG_PRINTLN_HEX(s)
12 #else
13 #define SERVO_DEBUG_PRINT(s)
14 #define SERVO_DEBUG_PRINTLN(s)
15 #define SERVO_DEBUG_PRINT_HEX(s)
16 #define SERVO_DEBUG_PRINTLN_HEX(s)
17 #endif
18 
19 #ifdef USE_VERBOSE_SERVO_DEBUG
20 #define VERBOSE_SERVO_DEBUG_PRINT(s) DEBUG_PRINT(s)
21 #define VERBOSE_SERVO_DEBUG_PRINTLN(s) DEBUG_PRINTLN(s)
22 #define VERBOSE_SERVO_DEBUG_PRINT_HEX(s) DEBUG_PRINT_HEX(s)
23 #define VERBOSE_SERVO_DEBUG_PRINTLN_HEX(s) DEBUG_PRINTLN_HEX(s)
24 #else
25 #define VERBOSE_SERVO_DEBUG_PRINT(s)
26 #define VERBOSE_SERVO_DEBUG_PRINTLN(s)
27 #define VERBOSE_SERVO_DEBUG_PRINT_HEX(s)
28 #define VERBOSE_SERVO_DEBUG_PRINTLN_HEX(s)
29 #endif
30 
31 //#define SERVO_DEBUG
32 //#define VERBOSE_SERVO_DEBUG
33 //chip registers and default values
34 #define PCA9685_MODE1 0x00
35 #define PCA9685_MODE2 0x01
36 #define PCA9685_SWRST_ADDR 0X00
37 #define PCA9685_SWRST_ACK 0x06
38 #define PCA9685_SWRST_NOACK 0x00
39 #define PCA9685_AI 0x20
40 #define PCA9685_ALLCALL 0x01
41 #define PCA9685_PRESCALE 0xFE
42 #define PCA9685_SLEEP 0x10
43 #define PCA9685_ALLCALLADR 0x70
44 #define PCA9685_ALL_LED_ON_L 0xFA
45 #define PCA9685_ALL_LED_ON_H 0xFB
46 #define PCA9685_ALL_LED_OFF_L 0xFC
47 #define PCA9685_ALL_LED_OFF_H 0xFD
48 #define PCA9685_DEFAULT_PRESCALE_VALUE 0x1A
49 #define LED0_ON_L 0x06
50 #define LED0_ON_H 0x07
51 #define LED0_OFF_L 0x08
52 #define LED0_OFF_H 0x09
53 #define LED_FULL_OFF_L 0x00
54 #define LED_FULL_OFF_H 0x10
55 
56 #define POPULATED_CHANNEL_NUMBER 32
57 #define MIN_PWM_LENGTH 500
58 #define MAX_PWM_LENGTH 2500
59 #define DEFAULT_CHANNEL_STAGGERING false
60 #define CHANNEL_OFFSET_STEP 50 //in us. This value should not extend the last channel off timing to exceed the 4095 limit.
61 #define NOMINATED_ROOM_TEMPERATURE 25
62 #define DEFAULT_TEMPERATURE_CORRECTION 40 //per 30 degrees change in temperature
63 #define DEFAULT_SERVO_PWM_LENGTH 1500
64 #define NOMINAL_CLOCK_FREQUENCY 25000000
65 #define DEFAULT_UPDATE_FREQUENCY 50
66 #define TEMPERATURE_CORRECTION_COEFFICIENT 0.00020
67 #define TEMPERATURE_CORRECTION_STEP 128
68 #define TEMPERATURE_CORRECTION_POINTS ((MAX_PWM_LENGTH-MIN_PWM_LENGTH)/TEMPERATURE_CORRECTION_STEP)
69 
82 template <uint16_t numServos, byte defaultOEValue = HIGH>
84 {
85 private:
86  struct ServoState;
87 public:
91  ServoDispatchPCA9685(TwoWire* i2c, uint8_t startAddress = 0x40) :
92  fI2C(i2c),
93  fOutputEnablePin(-1),
94  fOutputAutoOff(true),
95  fOutputEnabled(false),
96  fOutputExpireMillis(0),
97  fLastTime(0)
98  {
99  for (byte chip = 0; chip < numberOfPCA9685Chips(); chip++)
100  {
101  fI2CAddress[chip] = startAddress + chip;
102  fClocks[chip] = NOMINAL_CLOCK_FREQUENCY;
103  fTargetUpdateFrequency[chip] = DEFAULT_UPDATE_FREQUENCY;
104  }
105  memset(fServos, '\0', sizeof(fServos));
106  for (uint8_t servoChannel = 0; servoChannel < SizeOfArray(fLastLength); servoChannel++)
107  {
108  fLastLength[servoChannel] = DEFAULT_SERVO_PWM_LENGTH;
109  }
110  }
111 
115  ServoDispatchPCA9685(TwoWire* i2c, const ServoSettings* settings, uint8_t startAddress = 0x40) :
116  fI2C(i2c),
117  fOutputEnablePin(-1),
118  fOutputAutoOff(true),
119  fOutputEnabled(false),
120  fOutputExpireMillis(0),
121  fLastTime(0)
122  {
123  for (byte chip = 0; chip < numberOfPCA9685Chips(); chip++)
124  {
125  fI2CAddress[chip] = startAddress + chip;
126  fClocks[chip] = NOMINAL_CLOCK_FREQUENCY;
127  fTargetUpdateFrequency[chip] = DEFAULT_UPDATE_FREQUENCY;
128  }
129  memset(fServos, '\0', sizeof(fServos));
130  for (uint8_t servoChannel = 0; servoChannel < SizeOfArray(fLastLength); servoChannel++)
131  {
132  fLastLength[servoChannel] = DEFAULT_SERVO_PWM_LENGTH;
133  }
134  for (uint16_t i = 0; i < numServos; i++)
135  {
136  ServoState* state = &fServos[i];
137  state->channel = pgm_read_word(&settings[i].pinNum);
138  state->group = pgm_read_dword(&settings[i].group);
139  state->startPulse = pgm_read_word(&settings[i].startPulse);
140  /* netural defaults to start position */
141  state->neutralPulse = state->startPulse;
142  state->endPulse = pgm_read_word(&settings[i].endPulse);
143  fLastLength[state->channel - 1] = state->startPulse;
144  state->posNow = state->startPulse;
145  state->init();
146  }
147  }
148 
152  ServoDispatchPCA9685(const ServoSettings* settings, uint8_t startAddress = 0x40) :
153  #ifdef ARDUINO_SAM_DUE
154  ServoDispatchPCA9685(&Wire1, settings, startAddress)
155  #else
156  ServoDispatchPCA9685(&Wire, settings, startAddress)
157  #endif
158  {
159  }
160 
164  ServoDispatchPCA9685(uint8_t startAddress = 0x40) :
165  #ifdef ARDUINO_SAM_DUE
166  ServoDispatchPCA9685(&Wire1, startAddress)
167  #else
168  ServoDispatchPCA9685(&Wire, startAddress)
169  #endif
170  {
171  }
172 
173  inline byte numberOfPCA9685Chips()
174  {
175  return numServos / 16 + 1;
176  }
177 
178  virtual uint16_t getNumServos() override
179  {
180  return numServos;
181  }
182 
184  {
185  if (fOutputEnabled)
186  {
187  setOutputAll(false);
188  if (fOutputEnablePin != -1)
189  {
190  digitalWrite(fOutputEnablePin, defaultOEValue);
191  }
192  fOutputEnabled = false;
193  }
194  }
195 
197  {
198  if (!fOutputEnabled)
199  {
200  #ifdef SERVO_DEBUG
201  DEBUG_PRINTLN("OUTPUT ENABLED");
202  #endif
203  setOutputAll(false);
204  if (fOutputEnablePin != -1)
205  {
206  digitalWrite(fOutputEnablePin, !defaultOEValue);
207  }
208  fOutputEnabled = true;
209  }
210  }
211 
212  void setOutputEnablePin(const byte outputEnablePin, bool outputAutoOff = true)
213  {
214  // If we enable the OE pin then we default to OFF state (HIGH)
215  fOutputEnablePin = outputEnablePin;
216  fOutputAutoOff = outputAutoOff;
217  pinMode(fOutputEnablePin, OUTPUT);
218  digitalWrite(fOutputEnablePin, defaultOEValue);
219  }
220 
221  void setClockCalibration(const uint32_t clock[(numServos/16)+1])
222  {
223  for (byte i = 0; i < numberOfPCA9685Chips(); i++)
224  {
225  fClocks[i] = clock[i];
226  }
227  }
228 
229  virtual uint8_t getPin(uint16_t num) override
230  {
231  return (num < numServos) ? fServos[num].channel : 0;
232  }
233 
234  virtual uint16_t getStart(uint16_t num) override
235  {
236  return (num < numServos) ? fServos[num].startPulse : 0;
237  }
238 
239  virtual uint16_t getEnd(uint16_t num) override
240  {
241  return (num < numServos) ? fServos[num].endPulse : 0;
242  }
243 
244  virtual uint16_t getMinimum(uint16_t num) override
245  {
246  return (num < numServos) ? fServos[num].getMinimum() : 0;
247  }
248 
249  virtual uint16_t getNeutral(uint16_t num) override
250  {
251  return (num < numServos) ? fServos[num].getNeutral() : 0;
252  }
253 
254  virtual uint16_t getMaximum(uint16_t num) override
255  {
256  return (num < numServos) ? fServos[num].getMaximum() : 0;
257  }
258 
259  virtual uint32_t getGroup(uint16_t num) override
260  {
261  return (num < numServos) ? fServos[num].group : 0;
262  }
263 
264  virtual uint16_t currentPos(uint16_t num) override
265  {
266  return (num < numServos) ? fServos[num].currentPos() : 0;
267  }
268 
269  virtual void setPin(uint16_t num, uint16_t pin) override
270  {
271  if (num < numServos) {
272  ServoState* state = &fServos[num];
273  state->channel = pin;
274  state->init();
275  }
276  }
277 
278  virtual void setNeutral(uint16_t num, uint16_t neutralPulse) override
279  {
280  if (num < numServos)
281  fServos[num].neutralPulse = neutralPulse;
282  }
283 
284  virtual void setStart(uint16_t num, uint16_t startPulse) override
285  {
286  if (num < numServos) {
287  ServoState* state = &fServos[num];
288  state->startPulse = startPulse;
289  if (state->channel != 0)
290  fLastLength[state->channel - 1] = state->startPulse;
291  }
292  }
293 
294  virtual void setEnd(uint16_t num, uint16_t endPulse) override
295  {
296  if (num < numServos)
297  fServos[num].endPulse = endPulse;
298  }
299 
300  virtual void setServo(uint16_t num, uint8_t pin, uint16_t startPulse, uint16_t endPulse, uint16_t neutralPulse, uint32_t group) override
301  {
302  if (num < numServos)
303  {
304  ServoState* state = &fServos[num];
305  state->channel = pin;
306  state->group = group;
307  state->startPulse = startPulse;
308  state->neutralPulse = neutralPulse;
309  state->endPulse = endPulse;
310  if (state->channel != 0)
311  fLastLength[state->channel - 1] = state->startPulse;
312  state->posNow = state->startPulse;
313  state->init();
314  }
315  }
316 
317  virtual void stop() override
318  {
319  // Stop all servo movement
320  for (uint16_t i = 0; i < numServos; i++)
321  {
322  disable(i);
323  }
324  }
325 
326  virtual uint16_t scaleToPos(uint16_t num, float scale) override
327  {
328  uint16_t pos = 0;
329  if (num < numServos)
330  {
331  scale = min(max(0.0f, scale), 1.0f);
332  uint16_t startPulse = fServos[num].startPulse;
333  uint16_t endPulse = fServos[num].endPulse;
334  if (startPulse < endPulse)
335  {
336  pos = startPulse + (endPulse - startPulse) * scale;
337  }
338  else
339  {
340  pos = startPulse - (startPulse - endPulse) * scale;
341  }
342  }
343  return pos;
344  }
345 
346  virtual void setup() override
347  {
348  reset();
349 
350  //Enable Auto-Increment and all call.
351  for (byte i = 0; i < numberOfPCA9685Chips(); i++)
352  {
353  writeRegister(i, PCA9685_MODE1, PCA9685_AI | PCA9685_ALLCALL);
354  }
355 
357  //Initialize temperature correction array
358  for (uint8_t i = 0; i < SizeOfArray(fTemperatureCorrectionArray); i++)
359  {
360  fTemperatureCorrectionArray[i] = 0;
361  }
362 
363  setUpdateFrequency(fTargetUpdateFrequency);
364 
365  setOutputAll(false);
366 
367  SERVO_DEBUG_PRINTLN("PCA9685 initialization completed.");
368  }
369 
370  virtual bool isActive(uint16_t num) override
371  {
372  return (num < numServos && fOutputEnabled) ? fServos[num].isActive() : false;
373  }
374 
375  virtual void disable(uint16_t num) override
376  {
377  if (num < numServos)
378  {
379  fServos[num].init();
380  }
381  }
382 
383  virtual void animate() override
384  {
385  if (fOutputEnabled)
386  {
387  uint32_t now = millis();
388  if (fLastTime + 1 < now)
389  {
390  for (unsigned i = 0; i < numServos; i++)
391  {
392  if (fServos[i].channel != 0)
393  fServos[i].move(this, now);
394  }
395  fLastTime = now = millis();
396  }
397  if (fOutputAutoOff && now > fOutputExpireMillis)
398  {
399  SERVO_DEBUG_PRINTLN("POWER OFF");
400  ensureDisabled();
401  setOutputAll(false);
402  }
403  }
404  }
405 
406  //Set output signal to on or off. Any PWM input command will turn the signal on.
407  void setOutput(uint16_t servoChannel, bool state)
408  {
409  if (servoChannel > SizeOfArray(fLastLength))
410  return;
411  if (state)
412  {
413  setPWM(servoChannel, fLastLength[servoChannel - 1]);
414  SERVO_DEBUG_PRINT("Set servo channel ");
415  SERVO_DEBUG_PRINT(servoChannel);
416  SERVO_DEBUG_PRINTLN(" output on");
417  }
418  else
419  {
420  SERVO_DEBUG_PRINT("Set servo channel ");
421  SERVO_DEBUG_PRINT(servoChannel);
422  SERVO_DEBUG_PRINTLN(" output off");
423 
424  uint8_t chip = (servoChannel - 1) / 16;
425  uint8_t channel = (servoChannel - 1) % 16;
426  fI2C->beginTransmission(fI2CAddress[chip]);
427  fI2C->write(LED0_OFF_L + 4 * channel);
428  fI2C->write(LED_FULL_OFF_L);
429  fI2C->write(LED_FULL_OFF_H);
430  fI2C->endTransmission();
431  }
432  }
433 
434  void setPrescale(uint8_t prescale)
435  {
436  for (byte chip = 0; chip < numberOfPCA9685Chips(); chip++)
437  {
438  uint8_t currentMode = readRegister(chip, PCA9685_MODE1); //read current MODE1 register
439  uint8_t sleepMode = (currentMode & 0x7F) | PCA9685_SLEEP;
440  writeRegister(chip, PCA9685_MODE1, sleepMode);
441  writeRegister(chip, PCA9685_PRESCALE, prescale); //change the prescaler register
442  writeRegister(chip, PCA9685_MODE1, currentMode);
443  }
444  delay(5);
445  }
446 
447  // Return the prescale.
448  uint8_t getPrescale(uint8_t chipNumber)
449  {
450  return readRegister(chipNumber, PCA9685_PRESCALE);
451  }
452 
453  //set ambient temperature for temperature correction
454  void setEnvironmentTemperatureCelsius(int8_t degreesInCelsius)
455  {
456  fDeltaTemperature = degreesInCelsius - NOMINATED_ROOM_TEMPERATURE;
457  SERVO_DEBUG_PRINTLN("Temperature correction at each checkpoint:");
458  //Initialize temperature correction array
459  for (uint8_t i = 0; i < TEMPERATURE_CORRECTION_POINTS; i++)
460  {
461  uint16_t targetPWMLength = MIN_PWM_LENGTH + i * TEMPERATURE_CORRECTION_STEP;
462  fTemperatureCorrectionArray[i] = (float)fDeltaTemperature * TEMPERATURE_CORRECTION_COEFFICIENT* (float)targetPWMLength;
463  VERBOSE_SERVO_DEBUG_PRINT(targetPWMLength);
465  VERBOSE_SERVO_DEBUG_PRINTLN(fTemperatureCorrectionArray[i]);
466  }
467  }
468 
469  //if set true, output channels will stagger (phase shift) by the amout of time (us) defined in CHANNEL_OFFSET_STEP
470  void setChannelStaggering(bool value)
471  {
472  for (uint16_t index = 0; index < SizeOfArray(fChannelOffset); index++)
473  {
474  fChannelOffset[index] = (value) ? CHANNEL_OFFSET_STEP * (index % 16) : 0;
475  }
476  }
477 
478  float getNominalUpdateFrequency(uint32_t clockFrequency, uint8_t prescale)
479  {
480  float nominalUpdateFrequency;
481  nominalUpdateFrequency = (float)clockFrequency / (float)(((uint32_t)(prescale+1)) << 12);
482  return nominalUpdateFrequency;
483  }
484 
485  void setClockFrequency(const uint32_t clocks[(numServos/16)+1])
486  {
487  for (byte chip = 0; chip < numberOfPCA9685Chips(); chip++)
488  {
489  fClocks[chip] = clocks[chip];
490  }
491  }
492 
493  void setUpdateFrequency(const float targetUpdateFrequency[(numServos/16)+1])
494  {
495  for (byte chip = 0; chip < numberOfPCA9685Chips(); chip++)
496  {
497  fTargetUpdateFrequency[chip] = targetUpdateFrequency[chip];
498  SERVO_DEBUG_PRINT("Set target update frequency[");
499  SERVO_DEBUG_PRINT(chip);
500  SERVO_DEBUG_PRINT("] ");
501  SERVO_DEBUG_PRINT(targetUpdateFrequency[chip]);
503 
504  uint8_t prescale = getCalculatedPrescale(fClocks[chip], fTargetUpdateFrequency[chip]);
505 
506  uint8_t currentMode;
507  uint8_t sleepMode;
508 
509  currentMode = readRegister(chip, PCA9685_MODE1); //read current MODE1 register
510  sleepMode = (currentMode & 0x7F) | PCA9685_SLEEP;
511  writeRegister(chip, PCA9685_MODE1, sleepMode);
512  writeRegister(chip, PCA9685_PRESCALE, prescale); //change the prescaler register
513  writeRegister(chip, PCA9685_MODE1, currentMode);
514 
515  delay(1);
516 
517  SERVO_DEBUG_PRINT("Set prescale[");
518  SERVO_DEBUG_PRINT(chip);
519  SERVO_DEBUG_PRINT("] : ");
520  SERVO_DEBUG_PRINTLN(prescale);
521 
522  prescale = getPrescale(chip);
523  fCalculatedUpdateFrequency[chip] = fClocks[chip] / (float)(((uint32_t)prescale + 1) << 12);
524  fCalculatedResolution[chip] = 1000000.0 / (fCalculatedUpdateFrequency[chip] * 4096);
525 
526  SERVO_DEBUG_PRINT("Calculated update frequency = ");
527  SERVO_DEBUG_PRINTLN(fCalculatedUpdateFrequency[chip]);
528  }
529  }
530 
531  uint8_t getCalculatedPrescale(uint32_t calculatedClockFrequency, float targetUpdateFrequency)
532  {
533  //rounding method from here: https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library/issues/40
534  uint32_t calculatedPrescale;
535  calculatedPrescale = (float)calculatedClockFrequency * 100.0 / (4096.0 * targetUpdateFrequency);
536  if ((calculatedPrescale % 100) >= 50)
537  calculatedPrescale += 100;
538  calculatedPrescale = (calculatedPrescale / 100) - 1;
539  return (uint8_t)calculatedPrescale;
540  }
541 
542  uint16_t getCalibratedSteps(uint8_t chip, uint16_t targetLength)
543  {
544  return (chip < numberOfPCA9685Chips()) ? (targetLength / fCalculatedResolution[chip]) + 0.5 : 0;
545  }
546 
547  float getCalculatedResolution(uint8_t chip)
548  {
549  return (chip < numberOfPCA9685Chips()) ? fCalculatedResolution[chip] : 0;
550  }
551 
552 private:
553  TwoWire *fI2C;
554  uint8_t fI2CAddress[(numServos/16)+1];
555  float fCalculatedUpdateFrequency[(numServos/16)+1];
556  uint32_t fClocks[(numServos/16)+1];
557  float fTargetUpdateFrequency[(numServos/16)+1];
558  float fCalculatedResolution[(numServos/16)+1];
559  int8_t fDeltaTemperature = 0;
560  int8_t fTemperatureCorrection = DEFAULT_TEMPERATURE_CORRECTION;
561  int8_t fTemperatureCorrectionArray[TEMPERATURE_CORRECTION_POINTS];
562  uint16_t fChannelOffset[((numServos/16)+1)*16]; //array starts from index 0, servo channel starts from index 1
563  uint16_t fLastLength[((numServos/16)+1)*16];
564 
565  int fOutputEnablePin;
566  bool fOutputAutoOff;
567  bool fOutputEnabled;
568  uint32_t fOutputExpireMillis;
569  uint32_t fLastTime;
570 
571  struct ServoState
572  {
573  uint16_t currentPos()
574  {
575  return posNow;
576  }
577 
578  uint16_t getMinimum()
579  {
580  return min(startPulse, endPulse);
581  }
582 
583  uint16_t getMaximum()
584  {
585  return max(startPulse, endPulse);
586  }
587 
588  uint16_t getNeutral()
589  {
590  return neutralPulse;
591  }
592 
593  void move(ServoDispatchPCA9685<numServos,defaultOEValue>* dispatch, uint32_t timeNow)
594  {
595  float (*useMethod)(float) = easingMethod;
596  if (useMethod == NULL)
597  useMethod = Easing::LinearInterpolation;
598  if (finishTime != 0)
599  {
600  if (timeNow < startTime)
601  {
602  /* wait */
603  }
604  else if (timeNow >= finishTime)
605  {
606  posNow = finishPos;
607  if (useMethod == Easing::Continuous || timeNow >= offTime)
608  {
609  // printf("SET PWM OFF\n");
610  dispatch->setPWMOff(channel);
611  offTime = 0;
612  }
613  else
614  {
615  doMove(dispatch, timeNow);
616  }
617  uint32_t savedOffTime = offTime;
618  init();
619  offTime = savedOffTime;
620  }
621  else if (lastMoveTime != timeNow)
622  {
623  uint32_t timeSinceLastMove = timeNow - startTime;
624  uint32_t denominator = finishTime - startTime;
625  if (useMethod != Easing::Continuous)
626  {
627  float fractionChange = useMethod(float(timeSinceLastMove)/float(denominator));
628  int distanceToMove = float(deltaPos) * fractionChange;
629  uint16_t newPos = startPosition + distanceToMove;
630  if (newPos != posNow)
631  {
632  posNow = startPosition + distanceToMove;
633  doMove(dispatch, timeNow);
634  }
635  }
636  else
637  {
638  posNow = finishPos;
639  doMove(dispatch, timeNow);
640  }
641  }
642  }
643  else if (offTime != 0 && timeNow >= offTime)
644  {
645  dispatch->setPWMOff(channel);
646  offTime = 0;
647  }
648  }
649 
650  void moveToPulse(ServoDispatchPCA9685<numServos,defaultOEValue>* dispatch, uint32_t startDelay, uint32_t moveTime, uint16_t startPos, uint16_t pos)
651  {
652  uint32_t timeNow = millis();
653 
654  startTime = startDelay + timeNow;
655  finishTime = moveTime + startTime;
656  offTime = finishTime;
657  if (moveTime == 0)
658  offTime += 200;
659  finishPos = min(getMaximum(), max(getMinimum(), pos));
660  posNow = startPosition = startPos;
661  deltaPos = finishPos - posNow;
662  doMove(dispatch, timeNow);
663  }
664 
665  uint8_t channel;
666  uint32_t group;
667  uint16_t startPulse;
668  uint16_t endPulse;
669  uint16_t neutralPulse;
670  uint32_t startTime;
671  uint32_t finishTime;
672  uint32_t lastMoveTime;
673  uint32_t offTime;
674  uint16_t finishPos;
675  uint16_t startPosition;
676  uint16_t posNow;
677  int deltaPos;
678  float (*easingMethod)(float completion) = NULL;
679 
680  void doMove(ServoDispatchPCA9685<numServos,defaultOEValue>* dispatch, uint32_t timeNow)
681  {
682  SERVO_DEBUG_PRINT("PWM ");
683  SERVO_DEBUG_PRINT(channel);
684  SERVO_DEBUG_PRINT(" ");
685  SERVO_DEBUG_PRINTLN(posNow);
686 
687  dispatch->setPWM(channel, posNow);
688  #if 0//def USE_SMQ
689  if (SMQ::sendTopic("PWM"))
690  {
691  SMQ::send_uint8(F("num"), channel);
692  SMQ::send_float(F("len"), posNow);
693  SMQ::send_end();
694  }
695  #endif
696  lastMoveTime = timeNow;
697  }
698 
699  bool isActive()
700  {
701  return (finishTime != 0 || lastMoveTime != 0 || finishPos != 0);
702  }
703 
704  void init()
705  {
706  finishTime = 0;
707  lastMoveTime = 0;
708  finishPos = 0;
709  offTime = 0;
710  }
711  };
712 
713  ServoState fServos[numServos];
714 
716 
717  virtual void _moveServoToPulse(uint16_t num, uint32_t startDelay, uint32_t moveTime, uint16_t startPos, uint16_t pos) override
718  {
719  if (num < numServos && fServos[num].channel != 0)
720  {
721  ensureEnabled();
722  fServos[num].moveToPulse(this, startDelay, moveTime, startPos, pos);
723  fOutputExpireMillis = max(fOutputExpireMillis, uint32_t(millis() + startDelay + moveTime + 500));
724  fLastTime = 0;
725  }
726  }
727 
729 
730  // Move all servos matching servoGroupMask starting at startDelay in moveTimeMin-moveTimeMax to position pos
731  virtual void _moveServosToPulse(uint32_t servoGroupMask, uint32_t startDelay, uint32_t moveTimeMin, uint32_t moveTimeMax, uint16_t pos) override
732  {
733  for (uint16_t i = 0; i < numServos; i++)
734  {
735  uint32_t moveTime = (moveTimeMin != moveTimeMax) ? random(moveTimeMin, moveTimeMax) : moveTimeMax;
736  if ((fServos[i].group & servoGroupMask) != 0)
737  {
738  moveToPulse(i, startDelay, moveTime, fServos[i].currentPos(), pos);
739  }
740  }
741  }
742 
743  virtual void _moveServosByPulse(uint32_t servoGroupMask, uint32_t startDelay, uint32_t moveTimeMin, uint32_t moveTimeMax, int16_t pos) override
744  {
745  for (uint16_t i = 0; i < numServos; i++)
746  {
747  uint32_t moveTime = (moveTimeMin != moveTimeMax) ? random(moveTimeMin, moveTimeMax) : moveTimeMax;
748  if ((fServos[i].group & servoGroupMask) != 0)
749  {
750  int16_t curpos = fServos[i].currentPos();
751  moveToPulse(i, startDelay, moveTime, curpos, curpos + pos);
752  }
753  }
754  }
755 
757 
758  virtual void _moveServoSetToPulse(uint32_t servoGroupMask, uint32_t servoSetMask, uint32_t startDelay, uint32_t moveTimeMin, uint32_t moveTimeMax, uint16_t onPos, uint16_t offPos) override
759  {
760  byte bitShift = 31;
761  for (uint16_t i = 0; i < numServos; i++)
762  {
763  if ((fServos[i].group & servoGroupMask) == 0)
764  continue;
765  uint32_t moveTime = (moveTimeMin != moveTimeMax) ? random(moveTimeMin, moveTimeMax) : moveTimeMax;
766  bool on = ((servoSetMask & (1L<<bitShift)) != 0);
767  moveToPulse(i, startDelay, moveTime, fServos[i].currentPos(), (on) ? onPos : offPos);
768  if (bitShift-- == 0)
769  break;
770  }
771  }
772 
773  virtual void _moveServoSetByPulse(uint32_t servoGroupMask, uint32_t servoSetMask, uint32_t startDelay, uint32_t moveTimeMin, uint32_t moveTimeMax, int16_t onPos, int16_t offPos) override
774  {
775  byte bitShift = 31;
776  for (uint16_t i = 0; i < numServos; i++)
777  {
778  if ((fServos[i].group & servoGroupMask) == 0)
779  continue;
780  uint32_t moveTime = (moveTimeMin != moveTimeMax) ? random(moveTimeMin, moveTimeMax) : moveTimeMax;
781  bool on = ((servoSetMask & (1L<<bitShift)) != 0);
782  int16_t curpos = fServos[i].currentPos();
783  moveToPulse(i, startDelay, moveTime, curpos, curpos + ((on) ? onPos : offPos));
784  if (bitShift-- == 0)
785  break;
786  }
787  }
788 
790 
791  virtual void _moveServosTo(uint32_t servoGroupMask, uint32_t startDelay, uint32_t moveTimeMin, uint32_t moveTimeMax, float pos) override
792  {
793  for (uint16_t i = 0; i < numServos; i++)
794  {
795  uint32_t moveTime = (moveTimeMin != moveTimeMax) ? random(moveTimeMin, moveTimeMax) : moveTimeMax;
796  if ((fServos[i].group & servoGroupMask) != 0)
797  {
798  moveToPulse(i, startDelay, moveTime, fServos[i].currentPos(), scaleToPos(i, pos));
799  }
800  }
801  }
802 
803  virtual void _moveServoSetTo(uint32_t servoGroupMask, uint32_t servoSetMask, uint32_t startDelay, uint32_t moveTimeMin, uint32_t moveTimeMax, float onPos, float offPos, float (*onEasingMethod)(float), float (*offEasingMethod)(float)) override
804  {
805  byte bitShift = 31;
806  for (uint16_t i = 0; i < numServos; i++)
807  {
808  if ((fServos[i].group & servoGroupMask) == 0)
809  continue;
810  uint32_t moveTime = (moveTimeMin != moveTimeMax) ? random(moveTimeMin, moveTimeMax) : moveTimeMax;
811  bool on = ((servoSetMask & (1L<<bitShift)) != 0);
812  VERBOSE_SERVO_DEBUG_PRINT("moveToPulse on=");
814  VERBOSE_SERVO_DEBUG_PRINT(" onPos=");
816  VERBOSE_SERVO_DEBUG_PRINT(" offPos=");
818  VERBOSE_SERVO_DEBUG_PRINT(" pos=");
819  VERBOSE_SERVO_DEBUG_PRINTLN(scaleToPos(i, (on) ? onPos : offPos));
820  if (on)
821  {
822  if (onEasingMethod != NULL)
823  setServoEasingMethod(i, onEasingMethod);
824  }
825  else if (offEasingMethod != NULL)
826  {
827  setServoEasingMethod(i, offEasingMethod);
828  }
829  moveToPulse(i, startDelay, moveTime, fServos[i].currentPos(), scaleToPos(i, (on) ? onPos : offPos));
830  if (bitShift-- == 0)
831  break;
832  }
833  }
834 
836 
837  virtual void _setServoEasingMethod(uint16_t num, float (*easingMethod)(float completion))
838  {
839  if (num < numServos && fServos[num].channel != 0)
840  {
841  fServos[num].easingMethod = easingMethod;
842  }
843  }
844 
845  virtual void _setServosEasingMethod(uint32_t servoGroupMask, float (*easingMethod)(float completion))
846  {
847  for (uint16_t i = 0; i < numServos; i++)
848  {
849  if ((fServos[i].group & servoGroupMask) != 0)
850  {
851  fServos[i].easingMethod = easingMethod;
852  }
853  }
854  }
855 
856  virtual void _setEasingMethod(float (*easingMethod)(float completion))
857  {
858  for (uint16_t i = 0; i < numServos; i++)
859  {
860  fServos[i].easingMethod = easingMethod;
861  }
862  }
863 
865 
866  uint8_t readRegister(uint8_t chipNumber, uint8_t registerAddress)
867  {
868  fI2C->beginTransmission(fI2CAddress[chipNumber]);
869  fI2C->write(registerAddress);
870  fI2C->endTransmission();
871  fI2C->requestFrom(fI2CAddress[chipNumber], (uint8_t)1);
872  return fI2C->read();
873  }
874 
875  void writeRegister(uint8_t chipNumber, uint8_t registerAddress, uint8_t value)
876  {
877  fI2C->beginTransmission(fI2CAddress[chipNumber]);
878  fI2C->write(registerAddress);
879  fI2C->write(value);
880  fI2C->endTransmission();
881  }
882 
883  void reset()
884  {
885  //perform a software reset to both chips with reserved address PCA9685_SWRST_ADDR
886  fI2C->beginTransmission(PCA9685_SWRST_ADDR);
887  fI2C->write(PCA9685_SWRST_ACK);
888  fI2C->endTransmission();
889  }
890 
891 public:
892  void setPWMFull(uint16_t servoChannel)
893  {
894  if (servoChannel > SizeOfArray(fLastLength))
895  return;
896  // Special value for signal fully on.
897  setPWM(servoChannel, 4096, 0);
898  }
899 
900  void setPWMOff(uint16_t servoChannel)
901  {
902  if (servoChannel <= SizeOfArray(fLastLength))
903  {
904  // Special value for signal fully off.
905  // printf("SET PWM OFF: %u\n", servoChannel);
906  setPWM(servoChannel, 0, 4096);
907  }
908  }
909 
910  void setPWM(uint16_t servoChannel, uint16_t on, uint16_t off)
911  {
912  if (servoChannel < SizeOfArray(fLastLength))
913  {
914  uint8_t chip = (servoChannel - 1) / 16;
915  uint8_t channel = (servoChannel - 1) % 16;
916 
917  VERBOSE_SERVO_DEBUG_PRINT_HEX((long)&Wire);
919  VERBOSE_SERVO_DEBUG_PRINT_HEX((long)fI2C);
920  VERBOSE_SERVO_DEBUG_PRINT(" I2C: 0x");
921  VERBOSE_SERVO_DEBUG_PRINT_HEX(fI2CAddress[chip]);
922  VERBOSE_SERVO_DEBUG_PRINT(" channel: ");
923  VERBOSE_SERVO_DEBUG_PRINT(channel);
924 
925  fI2C->beginTransmission(fI2CAddress[chip]);
926  fI2C->write(LED0_ON_L + 4 * channel);
927  fI2C->write(on);
928  fI2C->write(on >> 8);
929  fI2C->write(off);
930  fI2C->write(off >> 8);
931  fI2C->endTransmission();
932 
933  VERBOSE_SERVO_DEBUG_PRINT(" Channel ");
934  VERBOSE_SERVO_DEBUG_PRINT(servoChannel);
937  VERBOSE_SERVO_DEBUG_PRINT(" off ");
939  }
940  }
941 
942  //Command a servo position.
943  void setPWM(uint16_t servoChannel, uint16_t targetLength)
944  {
945  if (servoChannel > SizeOfArray(fLastLength))
946  return;
947  VERBOSE_SERVO_DEBUG_PRINT("Target ");
948  VERBOSE_SERVO_DEBUG_PRINT(targetLength);
949 
950  //perform frequency adjustment
951 
952  if (targetLength < MIN_PWM_LENGTH)
953  targetLength = MIN_PWM_LENGTH;
954  if (targetLength > MAX_PWM_LENGTH)
955  targetLength = MAX_PWM_LENGTH;
956  fLastLength[servoChannel - 1] = targetLength;
957 
958  //Perform temperature correction
959  uint8_t chip = (servoChannel - 1) / 16;
960  uint16_t temperatureCorrectedTargetLength = targetLength +
961  fTemperatureCorrectionArray[(targetLength - MIN_PWM_LENGTH) >>7];
962  uint16_t calibratedSteps = getCalibratedSteps(chip, temperatureCorrectedTargetLength);
963  // uint16_t calculatedLength = (float)calibratedSteps * fCalculatedResolution[chip] + 0.5;
964  uint16_t on = fChannelOffset[servoChannel - 1];
965  uint16_t off = on + calibratedSteps;
966 
967  setPWM(servoChannel, on, off);
968  }
969 
970  // Set all channels to the command target PWM position.
971  void setPWMAll(uint16_t targetLength)
972  {
973  if (targetLength < MIN_PWM_LENGTH)
974  targetLength = MIN_PWM_LENGTH;
975  if (targetLength > MAX_PWM_LENGTH)
976  targetLength = MAX_PWM_LENGTH;
977 
978  uint16_t on = 0;
979  uint16_t off = targetLength +
980  fTemperatureCorrectionArray[(targetLength - MIN_PWM_LENGTH) >> 7];
981  #if 1
982  uint8_t servoChannel = 1;
983  /*sequenced writing method*/
984  VERBOSE_SERVO_DEBUG_PRINT("Set PWM all ");
988  for (byte chip = 0; chip < numberOfPCA9685Chips(); chip++)
989  {
990  for (uint8_t i = 0; i < 16; i++, servoChannel++)
991  {
992  uint16_t channelOn = on;
993  uint16_t channelOff = getCalibratedSteps(chip, off);
994  fI2C->beginTransmission(fI2CAddress[chip]);
995  fI2C->write(LED0_ON_L + 4 * i);
996  fI2C->write(channelOn);
997  fI2C->write(channelOn >> 8);
998  fI2C->write(channelOff);
999  fI2C->write(channelOff >> 8);
1000  fI2C->endTransmission();
1001  fLastLength[i] = off - on;
1002 
1003  VERBOSE_SERVO_DEBUG_PRINT("Set channel ");
1004  VERBOSE_SERVO_DEBUG_PRINT(servoChannel);
1006  VERBOSE_SERVO_DEBUG_PRINT(channelOn);
1008  VERBOSE_SERVO_DEBUG_PRINTLN(channelOff);
1009  }
1010  }
1011  #else
1012  /* all call method */
1013  fI2C->beginTransmission(PCA9685_ALLCALLADR);
1014  fI2C->write(PCA9685_ALL_LED_ON_L);
1015  fI2C->write(on);
1016  fI2C->write(on >> 8);
1017  fI2C->write(off);
1018  fI2C->write(off >> 8);
1019  fI2C->endTransmission();
1020  #endif
1021  }
1022 
1023  void setOutputAll(bool state)
1024  {
1025  if (state)
1026  {
1027  for (uint16_t servoChannel = 1; servoChannel <= numServos; servoChannel++)
1028  {
1029  setPWM(servoChannel, fLastLength[servoChannel - 1]);
1030  }
1031  SERVO_DEBUG_PRINTLN("Set all channels on");
1032  return;
1033  }
1034  fI2C->beginTransmission(PCA9685_ALLCALLADR);
1035  fI2C->write(PCA9685_ALL_LED_OFF_L);
1036  fI2C->write(LED_FULL_OFF_L);
1037  fI2C->write(LED_FULL_OFF_H);
1038  fI2C->endTransmission();
1039  SERVO_DEBUG_PRINTLN("Set all channels off");
1040  }
1041 
1042  int mapPulselength(double microseconds)
1043  {
1044  // The Adafruit PWM Driver library overshoots the frequency by a factor of 1/0.9
1045  // therefore we must multiply the frequency value of 60 by 0.9 to correct for this
1046  // resulting in a more actuate map
1047  double pulselength = 4.521; // (1000000/(60.00*0.9))/4096
1048  int pulse;
1049  pulse = microseconds/pulselength;
1050  return pulse;
1051  }
1052 };
1053 
1063 template <uint16_t numServos>
1065 
1066 #endif
PCA9685_SWRST_ADDR
#define PCA9685_SWRST_ADDR
Definition: ServoDispatchPCA9685.h:36
ServoDispatchPCA9685::setPin
virtual void setPin(uint16_t num, uint16_t pin) override
Definition: ServoDispatchPCA9685.h:269
ServoDispatchPCA9685::setStart
virtual void setStart(uint16_t num, uint16_t startPulse) override
Definition: ServoDispatchPCA9685.h:284
NOMINATED_ROOM_TEMPERATURE
#define NOMINATED_ROOM_TEMPERATURE
Definition: ServoDispatchPCA9685.h:61
ServoDispatch.h
PCA9685_SLEEP
#define PCA9685_SLEEP
Definition: ServoDispatchPCA9685.h:42
ServoDispatchPCA9685::setUpdateFrequency
void setUpdateFrequency(const float targetUpdateFrequency[(numServos/16)+1])
Definition: ServoDispatchPCA9685.h:493
DEFAULT_CHANNEL_STAGGERING
#define DEFAULT_CHANNEL_STAGGERING
Definition: ServoDispatchPCA9685.h:59
ServoDispatchPCA9685::ServoDispatchPCA9685
ServoDispatchPCA9685(TwoWire *i2c, const ServoSettings *settings, uint8_t startAddress=0x40)
Constructor.
Definition: ServoDispatchPCA9685.h:115
PCA9685_ALL_LED_OFF_L
#define PCA9685_ALL_LED_OFF_L
Definition: ServoDispatchPCA9685.h:46
PCA9685_SWRST_ACK
#define PCA9685_SWRST_ACK
Definition: ServoDispatchPCA9685.h:37
ServoDispatchPCA9685::isActive
virtual bool isActive(uint16_t num) override
Definition: ServoDispatchPCA9685.h:370
ServoDispatchPCA9685::setClockCalibration
void setClockCalibration(const uint32_t clock[(numServos/16)+1])
Definition: ServoDispatchPCA9685.h:221
AnimatedEvent
Base class for all animated devices. AnimatedEvent::animate() is called for each device once through ...
Definition: AnimatedEvent.h:18
SMQ::send_end
static void send_end()
Definition: ReelTwoSMQ.h:463
ServoDispatchPCA9685::setClockFrequency
void setClockFrequency(const uint32_t clocks[(numServos/16)+1])
Definition: ServoDispatchPCA9685.h:485
ServoDispatchPCA9685::scaleToPos
virtual uint16_t scaleToPos(uint16_t num, float scale) override
Definition: ServoDispatchPCA9685.h:326
SetupEvent
Base class for all devices that require setup that cannot happen in the constructor....
Definition: SetupEvent.h:15
SMQ::sendTopic
static bool sendTopic(const smq_id id)
Definition: ReelTwoSMQ.h:155
ServoDispatchPCA9685::setPWM
void setPWM(uint16_t servoChannel, uint16_t on, uint16_t off)
Definition: ServoDispatchPCA9685.h:910
ServoDispatchPCA9685::getCalibratedSteps
uint16_t getCalibratedSteps(uint8_t chip, uint16_t targetLength)
Definition: ServoDispatchPCA9685.h:542
ServoDispatchPCA9685::getMaximum
virtual uint16_t getMaximum(uint16_t num) override
Definition: ServoDispatchPCA9685.h:254
ServoDispatchPCA9685::setPWMAll
void setPWMAll(uint16_t targetLength)
Definition: ServoDispatchPCA9685.h:971
TEMPERATURE_CORRECTION_STEP
#define TEMPERATURE_CORRECTION_STEP
Definition: ServoDispatchPCA9685.h:67
ServoDispatchPCA9685::setOutput
void setOutput(uint16_t servoChannel, bool state)
Definition: ServoDispatchPCA9685.h:407
DEFAULT_TEMPERATURE_CORRECTION
#define DEFAULT_TEMPERATURE_CORRECTION
Definition: ServoDispatchPCA9685.h:62
LED_FULL_OFF_H
#define LED_FULL_OFF_H
Definition: ServoDispatchPCA9685.h:54
DEBUG_PRINTLN
#define DEBUG_PRINTLN(s)
Definition: ReelTwo.h:188
ServoDispatchPCA9685::setPWMFull
void setPWMFull(uint16_t servoChannel)
Definition: ServoDispatchPCA9685.h:892
ServoDispatchPCA9685::getGroup
virtual uint32_t getGroup(uint16_t num) override
Definition: ServoDispatchPCA9685.h:259
VERBOSE_SERVO_DEBUG_PRINTLN
#define VERBOSE_SERVO_DEBUG_PRINTLN(s)
Definition: ServoDispatchPCA9685.h:26
LED0_OFF_L
#define LED0_OFF_L
Definition: ServoDispatchPCA9685.h:51
TEMPERATURE_CORRECTION_POINTS
#define TEMPERATURE_CORRECTION_POINTS
Definition: ServoDispatchPCA9685.h:68
PCA9685_ALLCALL
#define PCA9685_ALLCALL
Definition: ServoDispatchPCA9685.h:40
ServoDispatchPCA9685::setNeutral
virtual void setNeutral(uint16_t num, uint16_t neutralPulse) override
Definition: ServoDispatchPCA9685.h:278
ServoDispatchPCA9685::ServoDispatchPCA9685
ServoDispatchPCA9685(TwoWire *i2c, uint8_t startAddress=0x40)
Constructor.
Definition: ServoDispatchPCA9685.h:91
ServoDispatchPCA9685::setOutputAll
void setOutputAll(bool state)
Definition: ServoDispatchPCA9685.h:1023
ServoDispatchPCA9685::mapPulselength
int mapPulselength(double microseconds)
Definition: ServoDispatchPCA9685.h:1042
ServoDispatchPCA9685::setChannelStaggering
void setChannelStaggering(bool value)
Definition: ServoDispatchPCA9685.h:470
ServoDispatchPCA9685::getMinimum
virtual uint16_t getMinimum(uint16_t num) override
Definition: ServoDispatchPCA9685.h:244
ServoDispatchPCA9685::ServoDispatchPCA9685
ServoDispatchPCA9685(uint8_t startAddress=0x40)
Constructor.
Definition: ServoDispatchPCA9685.h:164
ServoDispatchPCA9685::stop
virtual void stop() override
Definition: ServoDispatchPCA9685.h:317
ServoDispatchPCA9685::getEnd
virtual uint16_t getEnd(uint16_t num) override
Definition: ServoDispatchPCA9685.h:239
NOMINAL_CLOCK_FREQUENCY
#define NOMINAL_CLOCK_FREQUENCY
Definition: ServoDispatchPCA9685.h:64
MAX_PWM_LENGTH
#define MAX_PWM_LENGTH
Definition: ServoDispatchPCA9685.h:58
DEFAULT_UPDATE_FREQUENCY
#define DEFAULT_UPDATE_FREQUENCY
Definition: ServoDispatchPCA9685.h:65
ServoDispatchPCA9685::animate
virtual void animate() override
Subclasses must implement this function to run through a single frame of animation/activity.
Definition: ServoDispatchPCA9685.h:383
ServoDispatchPCA9685::ServoDispatchPCA9685
ServoDispatchPCA9685(const ServoSettings *settings, uint8_t startAddress=0x40)
Constructor.
Definition: ServoDispatchPCA9685.h:152
ServoDispatchPCA9685::setPWM
void setPWM(uint16_t servoChannel, uint16_t targetLength)
Definition: ServoDispatchPCA9685.h:943
CHANNEL_OFFSET_STEP
#define CHANNEL_OFFSET_STEP
Definition: ServoDispatchPCA9685.h:60
ServoDispatchPCA9685::ensureDisabled
void ensureDisabled()
Definition: ServoDispatchPCA9685.h:183
ServoDispatchPCA9685::getStart
virtual uint16_t getStart(uint16_t num) override
Definition: ServoDispatchPCA9685.h:234
MIN_PWM_LENGTH
#define MIN_PWM_LENGTH
Definition: ServoDispatchPCA9685.h:57
PCA9685_MODE1
#define PCA9685_MODE1
Definition: ServoDispatchPCA9685.h:34
ServoDispatchPCA9685
Implements ServoDispatch over i2c to PCA9685.
Definition: ServoDispatchPCA9685.h:83
ServoDispatchPCA9685::getNumServos
virtual uint16_t getNumServos() override
Definition: ServoDispatchPCA9685.h:178
ServoDispatchPCA9685::getCalculatedPrescale
uint8_t getCalculatedPrescale(uint32_t calculatedClockFrequency, float targetUpdateFrequency)
Definition: ServoDispatchPCA9685.h:531
PCA9685_AI
#define PCA9685_AI
Definition: ServoDispatchPCA9685.h:39
ServoDispatchFuzzyNoodlePCA9685
Implements ServoDispatch over i2c for 32-channel PCA9685.
LED0_ON_L
#define LED0_ON_L
Definition: ServoDispatchPCA9685.h:49
ServoSettings
Settings for individual servos.
Definition: ServoDispatch.h:55
ServoDispatchPCA9685::getPin
virtual uint8_t getPin(uint16_t num) override
Definition: ServoDispatchPCA9685.h:229
ServoDispatchPCA9685::getNeutral
virtual uint16_t getNeutral(uint16_t num) override
Definition: ServoDispatchPCA9685.h:249
SMQ::send_float
static void send_float(const msg_id id, float val)
Definition: ReelTwoSMQ.h:364
ServoDispatchPCA9685::setPWMOff
void setPWMOff(uint16_t servoChannel)
Definition: ServoDispatchPCA9685.h:900
PCA9685_ALLCALLADR
#define PCA9685_ALLCALLADR
Definition: ServoDispatchPCA9685.h:43
ServoDispatch
Servo interace implemented eitehr by ServoDispatchPCA9685 or ServoDispatchDirect.
Definition: ServoDispatch.h:83
DEFAULT_SERVO_PWM_LENGTH
#define DEFAULT_SERVO_PWM_LENGTH
Definition: ServoDispatchPCA9685.h:63
TEMPERATURE_CORRECTION_COEFFICIENT
#define TEMPERATURE_CORRECTION_COEFFICIENT
Definition: ServoDispatchPCA9685.h:66
PCA9685_PRESCALE
#define PCA9685_PRESCALE
Definition: ServoDispatchPCA9685.h:41
ServoDispatchPCA9685::getCalculatedResolution
float getCalculatedResolution(uint8_t chip)
Definition: ServoDispatchPCA9685.h:547
ServoDispatchPCA9685::setOutputEnablePin
void setOutputEnablePin(const byte outputEnablePin, bool outputAutoOff=true)
Definition: ServoDispatchPCA9685.h:212
LED_FULL_OFF_L
#define LED_FULL_OFF_L
Definition: ServoDispatchPCA9685.h:53
SMQ::send_uint8
static void send_uint8(const msg_id id, uint8_t val)
Definition: ReelTwoSMQ.h:292
ServoDispatchPCA9685::setEnd
virtual void setEnd(uint16_t num, uint16_t endPulse) override
Definition: ServoDispatchPCA9685.h:294
ServoDispatch::moveToPulse
void moveToPulse(uint16_t num, uint32_t startDelay, uint32_t moveTime, uint16_t pos)
Definition: ServoDispatch.h:198
ServoDispatchPCA9685::setEnvironmentTemperatureCelsius
void setEnvironmentTemperatureCelsius(int8_t degreesInCelsius)
Definition: ServoDispatchPCA9685.h:454
ServoDispatchPCA9685::disable
virtual void disable(uint16_t num) override
Definition: ServoDispatchPCA9685.h:375
VERBOSE_SERVO_DEBUG_PRINT_HEX
#define VERBOSE_SERVO_DEBUG_PRINT_HEX(s)
Definition: ServoDispatchPCA9685.h:27
Easing::Continuous
static float Continuous(float p)
Definition: ServoEasing.h:53
VERBOSE_SERVO_DEBUG_PRINT
#define VERBOSE_SERVO_DEBUG_PRINT(s)
Definition: ServoDispatchPCA9685.h:25
ServoDispatchPCA9685::currentPos
virtual uint16_t currentPos(uint16_t num) override
Definition: ServoDispatchPCA9685.h:264
ServoDispatchPCA9685::getPrescale
uint8_t getPrescale(uint8_t chipNumber)
Definition: ServoDispatchPCA9685.h:448
ServoDispatchPCA9685::numberOfPCA9685Chips
byte numberOfPCA9685Chips()
Definition: ServoDispatchPCA9685.h:173
SizeOfArray
#define SizeOfArray(arr)
Definition: ReelTwo.h:213
ServoDispatchPCA9685::getNominalUpdateFrequency
float getNominalUpdateFrequency(uint32_t clockFrequency, uint8_t prescale)
Definition: ServoDispatchPCA9685.h:478
PCA9685_ALL_LED_ON_L
#define PCA9685_ALL_LED_ON_L
Definition: ServoDispatchPCA9685.h:44
ServoDispatch::setServoEasingMethod
void setServoEasingMethod(uint16_t num, float(*easingMethod)(float completion))
Definition: ServoDispatch.h:312
SERVO_DEBUG_PRINT
#define SERVO_DEBUG_PRINT(s)
Definition: ServoDispatchPCA9685.h:13
SERVO_DEBUG_PRINTLN
#define SERVO_DEBUG_PRINTLN(s)
Definition: ServoDispatchPCA9685.h:14
ServoDispatchPCA9685::ensureEnabled
void ensureEnabled()
Definition: ServoDispatchPCA9685.h:196
Easing::LinearInterpolation
static float LinearInterpolation(float p)
Definition: ServoEasing.h:48
ServoDispatchPCA9685::setup
virtual void setup() override
Subclasses must implement this function to perform any necessary setup that cannot happen in the cons...
Definition: ServoDispatchPCA9685.h:346
ServoDispatchPCA9685::setPrescale
void setPrescale(uint8_t prescale)
Definition: ServoDispatchPCA9685.h:434
ServoDispatchPCA9685::setServo
virtual void setServo(uint16_t num, uint8_t pin, uint16_t startPulse, uint16_t endPulse, uint16_t neutralPulse, uint32_t group) override
Definition: ServoDispatchPCA9685.h:300