egoShield
egoShieldTimeLapse.cpp
1 /********************************************************************************************
2 * File: egoShieldTimeLapse.cpp *
3 * Version: 1.1.0 *
4 * Date: March 17th, 2018 *
5 * Author: Mogens Groth Nicolaisen *
6 * *
7 *********************************************************************************************
8 * egoShield class *
9 * *
10 * This file contains the implementation of the class methods, incorporated in the *
11 * egoShield Arduino library. The library is used by instantiating an egoShield object *
12 * by calling of the overloaded constructor: *
13 * *
14 * example: *
15 * *
16 * egoShield ego; *
17 * *
18 * The instantiation above creates an egoShield object *
19 * after instantiation of the object, the object setup function should be called within *
20 * Arduino's setup function, and the object loop function should be run within the Arduino's *
21 * loop function: *
22 * *
23 * example: *
24 * *
25 * egoShieldTimeLapse ego; *
26 * *
27 * void setup() *
28 * { *
29 * ego.setup(); *
30 * } *
31 * *
32 * void loop() *
33 * { *
34 * ego.loop(); *
35 * } *
36 * *
37 * *
38 *********************************************************************************************
39 * (C) 2018 *
40 * *
41 * uStepper ApS *
42 * www.ustepper.com *
43 * administration@ustepper.com *
44 * *
45 * The code contained in this file is released under the following open source license: *
46 * *
47 * Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International *
48 * *
49 * The code in this file is provided without warranty of any kind - use at own risk! *
50 * neither uStepper ApS nor the author, can be held responsible for any damage *
51 * caused by the use of the code contained in this file ! *
52 * *
53 ********************************************************************************************/
64 #include "egoShieldTimeLapse.h"
65 
66 egoShield *egoPointer;
67 
68 extern "C" {
69  void WDT_vect(void)
70  {
71  //sei();
72  egoPointer->inputs();
73  WDTCSR |= (1<<WDIE);
74  }
75 }
76 
78 {
79  u8g2 = new U8G2_SSD1306_128X64_NONAME_1_4W_SW_SPI(U8G2_R0, /* clock=*/ 11, /* data=*/ 9, /* cs=*/ U8X8_PIN_NONE, /* dc=*/ 2, /* reset=*/ 10);
80 }
81 
82 void egoShield::setup(uint16_t acc, uint16_t vel, uint8_t uStep, uint16_t fTol, uint16_t fHys, float P, float I, float D, float res, uint16_t shutterDelay)//brake mode?
83 {
84  egoPointer = this;
85 
86  cli();
87  RESETWDT;
88  WDTCSR = (1 << WDCE) | (1 << WDE);
89  WDTCSR |= (1 << WDIE) | (1 << WDE);
90 
91 
92  this->acceleration = acc;
93  this->velocity = vel;
94  this->microStepping = uStep;
95  this->faultTolerance = fTol;
96  this->faultHysteresis = fHys;
97  this->pTerm = P;
98  this->iTerm = I;
99  this->dTerm = D;
100  this->resolution = res;
101  this->stepSize = 2;
102  this->interval = 2000;
103  this->shutterDelay = shutterDelay;
104 
105  brakeFlag = 1;
106 
107  stepper.setup(PID,this->microStepping,this->faultTolerance,this->faultHysteresis,this->pTerm,this->iTerm,this->dTerm,1);
108 
109  u8g2->begin();//start display
110 
111  // Check whether the uStepper is mounted on a motor with a magnet attached. If not, show an error message untill mounted correctly
112  do
113  {
114  u8g2->firstPage();
115  do
116  {
117  u8g2->setFontMode(1);
118  u8g2->setDrawColor(1);
119  u8g2->setFontDirection(0);
120  u8g2->setFont(u8g2_font_6x10_tf);
121 
122  u8g2->drawStr(2,10,"Magnet not present !");
123  } while ( u8g2->nextPage() );
124  }
125  while(stepper.encoder.detectMagnet() == 2 || stepper.encoder.detectMagnet() == 1);
126 
127  stepper.encoder.setHome();
128  stepper.setMaxVelocity(this->velocity);
129  stepper.setMaxAcceleration(this->acceleration);
130 
131  //Serial.begin(9600);
132  pinMode(FWBT ,INPUT);
133  pinMode(PLBT ,INPUT);
134  pinMode(RECBT ,INPUT);
135  pinMode(BWBT ,INPUT);
136  pinMode(OPTO,OUTPUT);
137  digitalWrite(OPTO ,HIGH);
138  digitalWrite(FWBT ,HIGH);//pull-up
139  digitalWrite(PLBT ,HIGH);//pull-up
140  digitalWrite(RECBT ,HIGH);//pull-up
141  digitalWrite(BWBT ,HIGH);//pull-up
142 
143  this->startPage();//show startpage
144  delay(2000);//for 2 seconds
145  this->resetAllButton();
146  state = 'a';//start in idle
147  stepper.moveToEnd(1);
148  stepper.moveToAngle(30,HARD);
149  while(stepper.getMotorState());
150  stepper.encoder.setHome();
151  pidFlag = 1;//enable PID
152  setPoint = stepper.encoder.getAngleMoved();//set manual move setpoint to current position
153 }
154 
155 void egoShield::loop(void)
156 {
157  setPoint = stepper.encoder.getAngleMoved();
158  switch (state)
159  {
160  case 'a'://if we are in idle
161  idleMode();
162  break;
163 
164  case 'b'://if we are in play
165  state = 'a';
166  break;
167 
168  case 'c'://if we are in record
169  timeMode();
170  break;
171 
172  case 'd'://in pause
173  pauseMode();
174  break;
175  }
176 }
177 
179 {
180  static bool continousForward = 0;
181  static bool continousBackwards = 0;
182 
183  this->idlePage(pidFlag,setPoint);
184 
185  if(continousForward)
186  {
187  if(this->forwardBtn.state != HOLD)
188  {
189  stepper.hardStop(HARD);
190  continousForward = 0;
191  }
192  }
193  else if(continousBackwards)
194  {
195  if(this->backwardsBtn.state != HOLD)
196  {
197  stepper.hardStop(HARD);
198  continousBackwards = 0;
199  }
200  }
201  if(this->playBtn.btn)//if play/stop/pause is pressed for long time, invert the pid mode
202  {
203  while(this->playBtn.state == PRESSED);
204  if(this->playBtn.state == DEPRESSED)//we want to play sequence when doing a short press
205  {
206  state = 'b';
207  continousForward = 0;
208  continousBackwards = 0;
209  this->resetAllButton();
210  }
211  else
212  {
213  if(pidFlag == 0)
214  {
215  pidFlag = 1;
216  stepper.setup(PID,this->microStepping,this->faultTolerance,this->faultHysteresis,this->pTerm,this->iTerm,this->dTerm,0);//pause PID to allow manual movement
217  }
218  else
219  {
220  pidFlag = 0;
221  stepper.setup(NORMAL,this->microStepping,this->faultTolerance,this->faultHysteresis,this->pTerm,this->iTerm,this->dTerm,0);//pause PID to allow manual movement
222  stepper.hardStop(SOFT);
223  }
224  this->idlePage(pidFlag,setPoint);
225  while(this->playBtn.state == HOLD);
226  }
227  this->resetButton(&playBtn);
228  }
229  else if(this->forwardBtn.btn)//if manual forward signal
230  {
231  if(this->forwardBtn.state == HOLD)
232  {
233  if(!continousForward)
234  {
235  stepper.runContinous(CCW);
236  continousForward = 1;
237  }
238  this->forwardBtn.btn = 0;
239  }
240  else
241  {
242  stepper.moveAngle(-5.0,0);//move 5deg
243  this->forwardBtn.btn = 0;
244  }
245  }
246  else if(this->backwardsBtn.btn)//if manual backward signal
247  {
248  if(this->backwardsBtn.state == HOLD)
249  {
250  if(!continousBackwards)
251  {
252  stepper.runContinous(CW);
253  continousBackwards = 1;
254  }
255  this->backwardsBtn.btn = 0;
256  }
257  else
258  {
259  stepper.moveAngle(5.0,0);//move 5deg
260  this->backwardsBtn.btn = 0;
261  }
262  }
263  else if(this->recordBtn.btn == 1)
264  {
265  this->resetAllButton();
266  continousForward = 0;
267  continousBackwards = 0;
268  state = 'c';
269  }
270 }
271 
273 {
274  static uint8_t started = 0;
275 
276  this->playPage(loopMode,pidFlag,place,0);
277 
278  if(this->recordBtn.btn)//play/stop/pause
279  {
280  while(this->recordBtn.state == PRESSED);
281  if(this->recordBtn.state == DEPRESSED)//we want to play sequence when doing a short press
282  {
283  state = 'd';
284  this->resetAllButton();
285  return;
286  }
287  else //Long press = stop
288  {
289  this->resetAllButton();
290  this->changeVelocity();
291  }
292  }
293  else if(this->playBtn.btn)//play/stop/pause
294  {
295  while(this->playBtn.state == PRESSED);
296  if(this->playBtn.state == DEPRESSED)//we want to play sequence when doing a short press
297  {
298  started = 1;
299  }
300  else //Long press = stop
301  {
302  place = 0;//reset array counter
303  loopMode = 0;
304  started = 0;
305  state = 'a';//idle
306  this->idlePage(pidFlag,setPoint);
307  while(this->playBtn.state == HOLD);
308  }
309  this->resetAllButton();
310  return;
311  }
312  else if(started || loopMode)
313  {
314  if(!stepper.getMotorState())
315  {
316  place++;//increment array counter
317  if(loopMode && place > endmove)
318  {
319  place = 0;
320  }
321  else if(place > endmove)//If we are at the end move
322  {
323  place = 0;//reset array counter
324  started = 0;
325  state = 'a';
326  this->resetAllButton();
327  return;
328  }
329  stepper.moveToAngle(pos[place],brakeFlag);
330  }
331  }
332 
333  if(this->forwardBtn.state == HOLD)//loop mode start
334  {
335  this->resetButton(&forwardBtn);
336  loopMode = 1;
337  }
338  else if(this->backwardsBtn.state == HOLD)//loop mode stop
339  {
340  this->resetButton(&backwardsBtn);
341  loopMode = 0;
342  }
343 }
344 
346 {
347  for(;;)
348  {
349  this->playPage(loopMode,pidFlag,place,1);
350  if(this->forwardBtn.btn == 1 && this->velocity <= 9900 && this->acceleration <= 19900)//increase speed
351  {
352  this->forwardBtn.btn = 0;
353  this->velocity+=100;
354  this->acceleration+=100;
355  }
356  else if(this->backwardsBtn.btn == 1 && this->velocity >= 200 && this->acceleration >= 200)//decrease speed
357  {
358  this->backwardsBtn.btn = 0;
359  this->velocity-=100;
360  this->acceleration-=100;
361  }
362  else if(this->playBtn.btn == 1)
363  {
364  stepper.setMaxVelocity(this->velocity);
365  stepper.setMaxAcceleration(this->acceleration);
366  this->resetAllButton();
367  return;
368  }
369  }
370 }
371 
373 {
375  if(this->playBtn.btn)//play/stop/pause
376  {
377  while(this->playBtn.state == PRESSED);
378  if(this->playBtn.state == DEPRESSED) //Short press = unpause
379  {
380  state = 'b';
381  }
382  else //Long press = stop
383  {
384  state = 'a';
385  this->idlePage(pidFlag,setPoint);
386  while(this->playBtn.state == HOLD);
387  this->resetAllButton();
388  }
389  this->resetButton(&playBtn);
390  }
391 }
392 
394 {
395  static uint8_t step = 0;
396  static uint32_t i = 0, j = 0;
397  static uint8_t runState = 0;
398 
399  this->timePage(step,pidFlag);
400  if(step == 0)//first put in how long to move at every step in mm
401  {
402  digitalWrite(OPTO, HIGH);
403  if(this->forwardBtn.btn == 1 && stepSize < 100)
404  {
405  this->forwardBtn.btn = 0;
406  stepSize=stepSize+0.25;
407  }
408  else if(this->backwardsBtn.btn == 1 && stepSize >= 0.25)
409  {
410  this->backwardsBtn.btn = 0;
411  stepSize=stepSize-0.25;
412  }
413  else if(this->recordBtn.btn == 1)
414  {
415  delay(200);
416  this->recordBtn.btn = 0;
417  step = 1;
418  }
419  }
420  else if(step == 1)//next put in how long the intervals between moves are in milliseconds
421  {
422  if(this->forwardBtn.btn == 1 && interval < 65000)
423  {
424  this->forwardBtn.btn = 0;
425  interval=interval+250;
426  }
427  else if(this->backwardsBtn.btn == 1 && interval >= (500 + this->shutterDelay))
428  {
429  this->backwardsBtn.btn = 0;
430  interval=interval-250;
431  }
432  else if(this->recordBtn.btn == 1)
433  {
434  delay(200);
435  this->recordBtn.btn = 0;
436  step = 2;
437  }
438  }
439  else if(step == 2)//ready to play
440  {
441  if(this->playBtn.btn)//play/stop/pause
442  {
443  while(this->playBtn.state == PRESSED);
444  if(this->playBtn.state == DEPRESSED) //Short press = unpause
445  {
446  step = 3;
447  i = millis();
448  }
449  else //Long press = stop
450  {
451  state = 'a';
452  step = 0;
453  this->resetAllButton();
454  }
455  this->resetButton(&playBtn);
456  }
457  }
458  else if(step == 3)//playing until the end
459  {
460  if(runState == 0) //start new movement
461  {
463  stepper.moveAngle((stepSize*resolution),brakeFlag);
464  this->timePage(step,pidFlag);
465  i = millis();
466  runState = 1;
467  return;
468  }
469  else if(runState == 1) //Waiting for movement to finish
470  {
471  if(!stepper.getMotorState())
472  {
473  j = millis();
474  runState = 2;
475  return;
476  }
477  }
478  else if(runState == 2) //Waiting 250ms before firing trigger. (to stabilize rail and avoid vibrations)
479  {
480  if(((millis() - j) > this->shutterDelay))
481  {
482  digitalWrite(OPTO, LOW); // sets the LED in the opto on triggering the camera
483  runState = 3;
484  j = millis();
485  return;
486  }
487  }
488  else if(runState == 3) //Waiting to release trigger
489  {
490  if(((millis() - j) > 200))
491  {
492  digitalWrite(OPTO, HIGH); // sets the LED in the opto off releases the camera trigger
493  runState = 4;
494  return;
495  }
496  }
497  else if(runState == 4) //Waiting The remaining period
498  {
499  if((millis() - i) > interval)
500  {
501  runState = 0;
502  return;
503  }
504  }
505  if(this->playBtn.btn == 1)
506  {
507  state = 'a';
508  step = 0;
509  this->resetAllButton();
510  return;
511  }
512  if(stepper.isStalled())
513  {
514  stepper.moveToEnd(1);
515  stepper.moveToAngle(30,HARD);
516  while(stepper.getMotorState());
517  stepper.encoder.setHome();
518  state = 'a';//idle state
519  step = 0;
520  this->resetAllButton();
521  return;
522  }
523  }
524 }
525 
527 {
528  this->debounce(&forwardBtn,(PINC >> 3) & 0x01);
529  this->debounce(&playBtn,(PINC >> 1) & 0x01);
530  this->debounce(&recordBtn,(PINC >> 2) & 0x01);
531  this->debounce(&backwardsBtn,(PINC >> 0) & 0x01);
532 }
533 
535 {
536  u8g2->firstPage();
537  do {
538  u8g2->drawXBM(19, 20, logo_width, logo_height, logo_bits);
539  } while ( u8g2->nextPage() );
540 }
541 
542 void egoShield::idlePage(bool pidMode, float pos)
543 {
544  char buf[20];
545  String sBuf;
546 
547  sBuf = "Position: ";
548  sBuf += (int32_t)(pos/this->resolution);
549  sBuf += " mm";
550  sBuf.toCharArray(buf, 20);
551 
552  u8g2->firstPage();
553  do {
554  u8g2->drawBox(1, 1, 128, 12);
555  u8g2->drawBox(1, 48, 128, 68);
556  u8g2->setFontMode(0);
557  u8g2->setDrawColor(0);
558  u8g2->setFontDirection(0);
559  u8g2->setFont(u8g2_font_6x10_tf);
560 
561  //Bottom bar
562  u8g2->drawXBM(5, 51, en_width, en_height, bw_bits);
563  u8g2->drawXBM(112, 51, en_width, en_height, fw_bits);
564  u8g2->drawXBM(32, 50, play_width, play_height, play_bits);
565  u8g2->drawXBM(43, 51, tt_width, tt_height, stop_bits);
566  u8g2->drawXBM(71, 51, tt_width, tt_height, rec_bits);
567  u8g2->drawXBM(85, 51, tt_width, tt_height, pse_bits);
568 
569  //Mode
570  u8g2->drawStr(2,10,"Idle");
571  if(pidMode)
572  {
573  u8g2->drawStr(45,10,"PID ON");
574  }
575  else
576  {
577  u8g2->drawStr(45,10,"PID OFF");
578  }
579  u8g2->setFontMode(1);
580  u8g2->setDrawColor(1);
581  u8g2->drawStr(2,35,buf);
582  } while ( u8g2->nextPage() );
583 }
584 
585 void egoShield::recordPage(bool pidMode, bool recorded, uint8_t index, float pos)
586 {
587  char buf[22];//char array buffer
588  String sBuf;
589 
590  u8g2->firstPage();
591  do
592  {
593  u8g2->drawBox(1, 1, 128, 12);
594  u8g2->drawBox(1, 48, 128, 68);
595  u8g2->setFontMode(0);
596  u8g2->setDrawColor(0);
597  u8g2->setFontDirection(0);
598  u8g2->setFont(u8g2_font_6x10_tf);
599 
600  u8g2->drawXBM(5, 51, en_width, en_height, bw_bits);
601  u8g2->drawXBM(112, 51, en_width, en_height, fw_bits);
602  u8g2->drawXBM(38, 51, tt_width, tt_height, stop_bits);
603  u8g2->drawXBM(76, 51, tt_width, tt_height, rec_bits);
604 
605  //Mode
606  u8g2->drawStr(2,10,"Record");
607  if(pidMode)
608  {
609  u8g2->drawStr(45,10,"PID ON");
610  }
611  else
612  {
613  u8g2->drawStr(45,10,"PID OFF");
614  }
615  u8g2->setFontMode(1);
616  u8g2->setDrawColor(1);
617  if(recorded)
618  {
619  sBuf = "Position ";
620  sBuf += index;
621  sBuf += " recorded";
622  sBuf.toCharArray(buf, 22);
623  u8g2->drawStr(2,35,buf);
624  }
625  else
626  {
627  sBuf = "Position: ";
628  sBuf += (int32_t)pos;
629  sBuf += (char)176;
630  sBuf.toCharArray(buf, 22);
631  u8g2->drawStr(2,35,buf);
632  }
633  } while ( u8g2->nextPage() );
634 }
635 
636 void egoShield::playPage(bool loopMode, bool pidMode, uint8_t index, bool mode)
637 {
638  char buf[5];//char array buffer
639 
640  u8g2->firstPage();
641  do
642  {
643  u8g2->drawBox(1, 1, 128, 12);
644  u8g2->drawBox(1, 48, 128, 68);
645  u8g2->setFontMode(0);
646  u8g2->setDrawColor(0);
647  u8g2->setFontDirection(0);
648  u8g2->setFont(u8g2_font_6x10_tf);
649 
650  if(loopMode)
651  {
652  u8g2->drawXBM(110, 2, loop_width, loop_height, loop_bits);
653  }
654 
655  //Bottom bar
656  u8g2->drawXBM(5, 51, en_width, en_height, bw_bits);
657  u8g2->drawXBM(112, 51, en_width, en_height, fw_bits);
658  u8g2->drawXBM(32, 50, play_width, play_height, play_bits);
659  u8g2->drawXBM(43, 51, tt_width, tt_height, stop_bits);
660  u8g2->drawXBM(77, 51, tt_width, tt_height, pse_bits);
661 
662  //Mode
663  u8g2->drawStr(2,10,"Play");
664  if(pidMode)
665  {
666  u8g2->drawStr(45,10,"PID ON");
667  }
668  else
669  {
670  u8g2->drawStr(45,10,"PID OFF");
671  }
672  u8g2->setFontMode(1);
673  u8g2->setDrawColor(1);
674  if(mode)
675  {
676  u8g2->drawStr(2,25,"Adjust velocity");
677  }
678  else
679  {
680  u8g2->drawStr(2,25,"Moving to pos");
681  String(index).toCharArray(buf, 5);
682  u8g2->drawStr(90,25,buf);
683  }
684  u8g2->drawStr(2,40,"Speed:");
685  String(this->velocity).toCharArray(buf, 5);
686  u8g2->drawStr(60,40,buf);
687  } while ( u8g2->nextPage() );
688 }
689 
690 void egoShield::pausePage(bool loopMode, bool pidMode, uint8_t index)
691 {
692  char buf[3];//char array buffer
693 
694  u8g2->firstPage();
695  do
696  {
697  u8g2->drawBox(1, 1, 128, 12);
698  u8g2->drawBox(1, 48, 128, 68);
699  u8g2->setFontMode(0);
700  u8g2->setDrawColor(0);
701  u8g2->setFontDirection(0);
702  u8g2->setFont(u8g2_font_6x10_tf);
703 
704  if(loopMode)
705  {
706  u8g2->drawXBM(110, 2, loop_width, loop_height, loop_bits);
707  }
708 
709  //Bottom bar
710  u8g2->drawXBM(32, 50, play_width, play_height, play_bits);
711  u8g2->drawXBM(43, 51, tt_width, tt_height, stop_bits);
712 
713  //Mode
714  u8g2->drawStr(2,10,"Pause");
715  if(pidMode)
716  {
717  u8g2->drawStr(45,10,"PID ON");
718  }
719  else
720  {
721  u8g2->drawStr(45,10,"PID OFF");
722  }
723  u8g2->setFontMode(1);
724  u8g2->setDrawColor(1);
725  u8g2->drawStr(2,35,"Paused at pos");
726  String(index).toCharArray(buf, 3);
727  u8g2->drawStr(90,35,buf);
728  } while ( u8g2->nextPage() );
729 }
730 
731 
732 void egoShield::timePage(uint8_t step, bool pidMode)
733 {
734  char buf[22];//char array buffer
735  String sBuf;
736 
737  u8g2->firstPage();
738  do
739  {
740  u8g2->drawBox(1, 1, 128, 12);
741  u8g2->drawBox(1, 48, 128, 68);
742  u8g2->setFontMode(0);
743  u8g2->setDrawColor(0);
744  u8g2->setFontDirection(0);
745  u8g2->setFont(u8g2_font_6x10_tf);
746  if(step == 0)//we are waiting for the distance interval to be put in
747  {
748  u8g2->drawXBM(5, 51, en_width, en_height, bw_bits);
749  u8g2->drawXBM(112, 51, en_width, en_height, fw_bits);
750  u8g2->drawXBM(76, 51, tt_width, tt_height, rec_bits);
751  u8g2->setFontMode(1);
752  u8g2->setDrawColor(1);
753  u8g2->drawStr(115,24,"<-");
754  u8g2->setFontMode(0);
755  u8g2->setDrawColor(0);
756  }
757  else if(step == 1)//we are waiting for the time interval to be put in
758  {
759  u8g2->drawXBM(5, 51, en_width, en_height, bw_bits);
760  u8g2->drawXBM(112, 51, en_width, en_height, fw_bits);
761  u8g2->drawXBM(76, 51, tt_width, tt_height, rec_bits);
762  u8g2->setFontMode(1);
763  u8g2->setDrawColor(1);
764  u8g2->drawStr(115,34,"<-");
765  u8g2->setFontMode(0);
766  u8g2->setDrawColor(0);
767  }
768  else if(step == 2)//we are waiting for play to be issued
769  {
770  u8g2->drawXBM(32, 50, play_width, play_height, play_bits);
771  u8g2->drawXBM(38, 51, tt_width, tt_height, stop_bits);
772  }
773  else if(step == 3)//we are playing sequence until end of rail
774  {
775  u8g2->drawXBM(38, 51, tt_width, tt_height, stop_bits);
776  }
777 
778  u8g2->drawStr(2,10,"Time");
779  if(pidMode)
780  {
781  u8g2->drawStr(45,10,"PID ON");
782  }
783  else
784  {
785  u8g2->drawStr(45,10,"PID OFF");
786  }
787  u8g2->setFontMode(1);
788  u8g2->setDrawColor(1);
789  sBuf = "Stepsize: ";
790  sBuf += stepSize;
791  sBuf += " mm";
792  sBuf.toCharArray(buf, 22);
793  u8g2->drawStr(2,24,buf);
794  sBuf = "Interval: ";
795  sBuf += interval*0.001;
796  sBuf += " s";
797  sBuf.toCharArray(buf, 22);
798  u8g2->drawStr(2,34,buf);
799  sBuf = "Encoder: ";
800  sBuf += (int32_t)(stepper.encoder.getAngleMoved()/resolution);
801  sBuf += " mm";
802  sBuf.toCharArray(buf, 22);
803  u8g2->drawStr(2,44,buf);
804  } while ( u8g2->nextPage() );
805 }
806 
807 void egoShield::debounce(buttons *btn, uint8_t sample)
808 {
809  if(btn->state == DEPRESSED)
810  {
811  btn->debounce &= (0xFE + sample);
812 
813  if( (btn->debounce & 0x1F) == 0x00)
814  {
815  btn->state = PRESSED;
816  btn->btn = 1;
817  return;
818  }
819 
820  btn->debounce <<= 1;
821  btn->debounce |= 0x01;
822  }
823 
824  else if((btn->state == PRESSED) || (btn->state == HOLD))
825  {
826  btn->debounce |= sample;
827 
828  if(btn->state != HOLD)
829  {
830  if((btn->debounce & 0x1F) == 0x00)
831  {
832  if(btn->holdCnt >= HOLDTIME)
833  {
834  btn->state = HOLD;
835  }
836  btn->holdCnt++;
837  }
838  }
839 
840  if( (btn->debounce & 0x1F) == 0x1F)
841  {
842  btn->state = DEPRESSED;
843  btn->holdCnt = 0;
844  return;
845  }
846 
847  btn->debounce <<= 1;
848  btn->debounce &= 0xFE;
849  }
850 
851  if(btn->state == HOLD)
852  {
853  if(btn->time == HOLDTICK)
854  {
855  btn->btn = 1;
856  btn->time = 0;
857  }
858 
859  else
860  {
861  btn->time++;
862  }
863  }
864 }
865 
867 {
868  btn->time = 0;
869  btn->state = DEPRESSED;
870  btn->debounce = 0x1F;
871  btn->holdCnt = 0;
872  btn->btn = 0;
873 }
875 {
876  this->resetButton(&playBtn);
877  this->resetButton(&forwardBtn);
878  this->resetButton(&backwardsBtn);
879  this->resetButton(&recordBtn);
880 }
#define FWBT
void loop(void)
Contains the main logic of the shield functionality, e.g. transition between states (idle...
void playPage(bool loopMode, bool pidMode, uint8_t index, bool mode)
Holds the code for the play page of the OLED.
uStepper stepper
Creates an uStepper instance.
void WDT_vect(void) __attribute__((signal
Watchdog timer interrupt handler, for examining the buttons periodically.
void idleMode(void)
Holds the idle logic; page to show, what buttons to enable etc.
void debounce(buttons *btn, uint8_t sample)
This function handles the debouncing and tracking of whether buttons are pressed, released or held...
void resetAllButton()
Resets the state of all 4 buttons at once.
#define RESETWDT
uint8_t debounce
void recordPage(bool pidMode, bool recorded, uint8_t index, float pos)
Holds the code for the record page of the OLED.
uint16_t acceleration
void idlePage(bool pidMode, float pos)
Holds the code for the idle page of the OLED.
void timeMode(void)
Holds the timelapse logic, showing the timelapse page.
uint16_t shutterDelay
#define OPTO
U8G2_SSD1306_128X64_NONAME_1_4W_SW_SPI * u8g2
void playMode(void)
Holds the play logic, showing play page and running the recorded sequence.
uint8_t microStepping
float pos[CNT]
void pauseMode(void)
Holds the pause logic, showing the pause page and pausing the playing of a sequence.
void setup(uint16_t acc=1500, uint16_t vel=1000, uint8_t uStep=SIXTEEN, uint16_t fTol=10, uint16_t fHys=5, float P=1.0, float I=0.02, float D=0.006, float res=1, uint16_t shutterDelay=250)
Initializes buttons, OLED, uStepper and BT-module.
void resetButton(buttons *btn)
Function for resetting the state of a button seperately.
struct to hold information required to debounce button.
uint16_t time
uint16_t velocity
#define PLBT
Function prototypes and definitions for the egoShield library.
void inputs(void)
Reads the four buttons and writes their value; no push, short push or long push, to global variables...
uint16_t faultTolerance
void startPage(void)
Holds the code for the start page of the OLED.
void pausePage(bool loopMode, bool pidMode, uint8_t index)
Holds the code for the pause page of the OLED.
void changeVelocity(void)
Holds the code for the changing velocity during sequence play.
uint16_t faultHysteresis
void timePage(uint8_t step, bool pidMode)
Holds the code for the timelapse page of the OLED.
#define RECBT
egoShield(void)
Constructor of egoShield class.
#define BWBT
uint16_t interval
uint8_t holdCnt