Filter Wheel Automation (Astronomy)
A solution to automate an otherwise manual filter wheel, to slide the needed filter into the light train.
Components and supplies
1
Generic 4x4 keyboard
1
i2c eeprom module
1
Arduino Nano R3
1
Dual H-Bridge motor drivers L298
1
LCD 1602 on I2C
Tools and machines
1
Soldering iron (generic)
Project description
Code
The code
c_cpp
The source code of the hand controller
1#define FILTERWHEEL_WELCOME_SCREEN_FIRST_LINE "FilterWheel v0.4" 2#define FILTERWHEEL_WELCOME_SCREEN_SECOND_LINE " csillagtura.ro " 3 4 5//#define FILTERWHEEL_PROJECT_DEBUG_MODE 6 7 8 9 10 11#include <AT24Cxx.h> 12 13#include <Wire.h> 14#include <LiquidCrystal_I2C.h> 15 16#define EEPROM_I2C_ADDRESS 0x50 17 18AT24Cxx eep(EEPROM_I2C_ADDRESS, 32); 19 20 21LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display 22 23//=================== PINS ====================== 24 25#define PIN_MOTOR_RIGHT A0 26#define PIN_MOTOR_LEFT A1 27 28 29#define PIN_ROW_0 12 30#define PIN_ROW_1 11 31#define PIN_ROW_2 10 32#define PIN_ROW_3 9 33 34#define PIN_COL_0 8 35#define PIN_COL_1 7 36#define PIN_COL_2 6 37#define PIN_COL_3 5 38 39#define PIN_OPTO_ENABLE 4 40 41#define PIN_OPTO_INPUT A2 42 43#define PIN_MYSERIAL_TX 3 44#define PIN_MYSERIAL_RX 2 45 46 47 48 49 50 51//====================== KEYBOARD ========================== 52#define KEYBOARD_INPUT_LEN 10 53char keyboardInput[KEYBOARD_INPUT_LEN]; 54int keyboardCursorRead = 0; 55int keyboardCursorWrite = 0; 56int keyboardCurrentColumn = 0; 57const char keyboardKeys[16] = {'1','2','3','A','4','5','6','B','7','8','9','C','*','0','#','D'}; 58 59char currentKey = 0; 60 61 62 63char keyboardCandidate = 0; 64char keyboardPreviousCandidate = 0; 65int keyboardCandidateObservedCount = 0; 66 67 68 69 70void keyboardInsert(char c){ 71 int prev = keyboardCursorWrite - 1; 72 if (prev == -1){ 73 prev = KEYBOARD_INPUT_LEN - 1; 74 } 75 if (keyboardInput[prev] == c){ 76 return ; 77 } 78 keyboardInput[keyboardCursorWrite] = c; 79 keyboardCursorWrite++; 80 if (keyboardCursorWrite >= KEYBOARD_INPUT_LEN ){ 81 keyboardCursorWrite = 0; 82 } 83} 84 85void keyboardInit(){ 86 pinMode(PIN_ROW_0, INPUT_PULLUP); 87 pinMode(PIN_ROW_1, INPUT_PULLUP); 88 pinMode(PIN_ROW_2, INPUT_PULLUP); 89 pinMode(PIN_ROW_3, INPUT_PULLUP); 90 91 pinMode(PIN_COL_0, OUTPUT); 92 pinMode(PIN_COL_1, OUTPUT); 93 pinMode(PIN_COL_2, OUTPUT); 94 pinMode(PIN_COL_3, OUTPUT); 95 96 digitalWrite(PIN_COL_0, HIGH); 97 digitalWrite(PIN_COL_1, HIGH); 98 digitalWrite(PIN_COL_2, HIGH); 99 digitalWrite(PIN_COL_3, HIGH); 100} 101 102void keyboardProcess(){ 103 digitalWrite(PIN_COL_0, keyboardCurrentColumn == 0 ? LOW: HIGH); 104 digitalWrite(PIN_COL_1, keyboardCurrentColumn == 1 ? LOW: HIGH); 105 digitalWrite(PIN_COL_2, keyboardCurrentColumn == 2 ? LOW: HIGH); 106 digitalWrite(PIN_COL_3, keyboardCurrentColumn == 3 ? LOW: HIGH); 107 if (keyboardCurrentColumn == 0){ 108 //full cycle, reset 109 keyboardCandidate = 0; 110 } 111 if (digitalRead(PIN_ROW_0) == LOW){ 112 keyboardCandidate = keyboardKeys[ 0*4 + keyboardCurrentColumn ]; 113 } 114 if (digitalRead(PIN_ROW_1) == LOW){ 115 keyboardCandidate = keyboardKeys[ 1*4 + keyboardCurrentColumn ]; 116 } 117 if (digitalRead(PIN_ROW_2) == LOW){ 118 keyboardCandidate = keyboardKeys[ 2*4 + keyboardCurrentColumn ]; 119 } 120 if (digitalRead(PIN_ROW_3) == LOW){ 121 keyboardCandidate = keyboardKeys[ 3*4 + keyboardCurrentColumn ]; 122 } 123 124 keyboardCurrentColumn++; 125 if (keyboardCurrentColumn > 3){ 126 keyboardCurrentColumn = 0; 127 } 128 129 if (0 == keyboardCurrentColumn){ 130 //a full cycle has been done 131 if (keyboardCandidate == keyboardPreviousCandidate){ 132 if (keyboardCandidateObservedCount > 100){ 133 //we have a keypress 134 keyboardInsert(keyboardCandidate); 135 keyboardCandidateObservedCount = 0; 136 }else{ 137 keyboardCandidateObservedCount++; 138 } 139 }else{ 140 keyboardCandidateObservedCount = 0; 141 keyboardPreviousCandidate = keyboardCandidate; 142 } 143 } 144 145 146 //Serial.print(candidate); 147} 148 149char keyboardGetCurrentKey(){ 150 char r = 0; 151 if (keyboardCursorRead != keyboardCursorWrite){ 152 r = keyboardInput[keyboardCursorRead]; 153 keyboardCursorRead = keyboardCursorWrite; 154 }; 155 return r; 156} 157 158 159 160#define OPTO_CHANGE_OBSERVED 1 161#define OPTO_NO_CHANGE_OBSERVED 0 162 163typedef struct OptoObserver { 164 unsigned int changes; 165 unsigned int observingSameStateCounter; 166 byte observingState; 167 byte observingPreviousState; 168 byte currentState; 169 byte optoIsObserving; 170} OptoObserver; 171 172OptoObserver optoObserver; 173 174 175void optoStart(){ 176 digitalWrite(PIN_OPTO_ENABLE, HIGH); 177 optoObserver.observingState = (digitalRead(PIN_OPTO_INPUT) == HIGH) ? 1 : 0; 178 optoObserver.observingPreviousState = optoObserver.observingState; 179 optoObserver.optoIsObserving = 1; 180} 181 182void optoStop(){ 183 optoObserver.optoIsObserving = 0; 184 digitalWrite(PIN_OPTO_ENABLE, LOW); 185} 186 187void optoInit(){ 188 pinMode(PIN_OPTO_INPUT, INPUT_PULLUP); 189 pinMode(PIN_OPTO_ENABLE, OUTPUT); 190 digitalWrite(PIN_OPTO_ENABLE, LOW); 191 optoObserver.optoIsObserving = 0; 192} 193 194byte optoObserverProcess(){ 195 byte rez = OPTO_NO_CHANGE_OBSERVED; 196 if (1 == optoObserver.optoIsObserving){ 197 optoObserver.observingState = (digitalRead(PIN_OPTO_INPUT) == HIGH) ? 1 : 0; 198 if (optoObserver.observingState == optoObserver.observingPreviousState){ 199 optoObserver.observingSameStateCounter++; 200 if (optoObserver.observingSameStateCounter > 200){ 201 optoObserver.observingSameStateCounter = 200; 202 } 203 if (optoObserver.observingSameStateCounter > 100){ 204 if (optoObserver.currentState != optoObserver.observingState){ 205 optoObserver.currentState = optoObserver.observingState; 206 //we have an event here 207 optoObserver.changes++; 208 rez = OPTO_CHANGE_OBSERVED; 209 /* 210 lcd.setCursor(0,1); 211 char n[10]; 212 itoa(changes, n, 10); 213 lcd.print(n); 214 lcd.print(" "); 215 */ 216 } 217 } 218 }else{ 219 optoObserver.observingSameStateCounter = 0; 220 } 221 optoObserver.observingPreviousState = optoObserver.observingState; 222 }else{ 223 // the opto is turned off 224 } 225 return rez; 226} 227 228 229 230 231 232inline int chrToDir(char dir){ 233 if (dir == 'L'){ 234 return 1; 235 }else{ 236 return -1; 237 }; 238} 239 240void(* resetFunc) (void) = 0; //declare reset function @ address 0 241 242 243 244#define NUMBER_1_FILTER_INDEX_CHARACTER '\\1' 245#define NUMBER_2_FILTER_INDEX_CHARACTER '\\2' 246#define NUMBER_3_FILTER_INDEX_CHARACTER '\\3' 247#define NUMBER_4_FILTER_INDEX_CHARACTER '\\4' 248#define NUMBER_5_FILTER_INDEX_CHARACTER '\\5' 249#define MOTOR_IS_STATIONARY_CHARACTER '\\6' 250#define MOTOR_BACKSLASH_CHARACTER '\\7' 251 252 253byte customBackslash[8] = { 254 0b00000, 255 0b10000, 256 0b01000, 257 0b00100, 258 0b00010, 259 0b00001, 260 0b00000, 261 0b00000 262}; 263byte customDot[8] = { 264 0b00000, 265 0b00000, 266 0b00100, 267 0b00000, 268 0b00000, 269 0b00000, 270 0b00000, 271 0b00000 272}; 273/* 274byte customOneFilterIndex[8] = { 275 0b01000, 276 0b11000, 277 0b01001, 278 0b01000, 279 0b01001, 280 0b11100, 281 0b00000, 282 0b00000 283}; 284 285byte customTwoFilterIndex[8] = { 286 0b01100, 287 0b10100, 288 0b00101, 289 0b01000, 290 0b10001, 291 0b11100, 292 0b00000, 293 0b00000 294}; 295*/ 296 297byte customOneFilterIndex[8] = { 298 0b01000, 299 0b11000, 300 0b01000, 301 0b01000, 302 0b11100, 303 0b00000, 304 0b00000, 305 0b00000 306}; 307 308byte customTwoFilterIndex[8] = { 309 0b01000, 310 0b10100, 311 0b00100, 312 0b01000, 313 0b11100, 314 0b00000, 315 0b00000, 316 0b00000 317}; 318 319byte customThreeFilterIndex[8] = { 320 0b11000, 321 0b00100, 322 0b01000, 323 0b00100, 324 0b11000, 325 0b00000, 326 0b00000, 327 0b00000 328}; 329 330byte customFourFilterIndex[8] = { 331 0b00100, 332 0b01100, 333 0b10100, 334 0b11110, 335 0b00100, 336 0b00000, 337 0b00000, 338 0b00000 339}; 340 341byte customFiveFilterIndex[8] = { 342 0b11100, 343 0b10000, 344 0b11100, 345 0b00100, 346 0b11000, 347 0b00000, 348 0b00000, 349 0b00000 350}; 351 352inline void customCharsInit(){ 353 lcd.createChar((byte) MOTOR_BACKSLASH_CHARACTER, customBackslash); 354 lcd.createChar((byte) MOTOR_IS_STATIONARY_CHARACTER, customDot); 355 lcd.createChar((byte) NUMBER_1_FILTER_INDEX_CHARACTER, customOneFilterIndex); 356 lcd.createChar((byte) NUMBER_2_FILTER_INDEX_CHARACTER, customTwoFilterIndex); 357 lcd.createChar((byte) NUMBER_3_FILTER_INDEX_CHARACTER, customThreeFilterIndex); 358 lcd.createChar((byte) NUMBER_4_FILTER_INDEX_CHARACTER, customFourFilterIndex); 359 lcd.createChar((byte) NUMBER_5_FILTER_INDEX_CHARACTER, customFiveFilterIndex); 360 361} 362 363 364//=================== MOTOR ===================== 365const char motorMovingCharacters[4] = { 366 '/', '-', MOTOR_BACKSLASH_CHARACTER, '|' 367}; 368int motorMovingCharactersCursor = 0; 369int motorIsMoving = 0; 370unsigned long int motorOldMillis = 0; 371 372 373 374 375byte motorStoppedFlag = 0; 376 377void motorStop(byte updateScreen){ 378 optoStop(); 379 motorIsMoving = 0; 380 motorSetDirectionPinsStateByDir(motorIsMoving); 381 if (1 == updateScreen){ 382 motorDrawMovementStatus(); 383 } 384 motorStoppedFlag = 1; 385} 386 387 388void motorInit(){ 389 pinMode(PIN_MOTOR_LEFT, OUTPUT); 390 pinMode(PIN_MOTOR_RIGHT, OUTPUT); 391 motorStop(0); 392 customCharsInit(); 393} 394 395 396 397 398#include <SoftwareSerial.h> 399SoftwareSerial mySerial(PIN_MYSERIAL_RX, PIN_MYSERIAL_TX); 400 401 402const int READ_BUFFER_LEN = 96; 403char filterWheelSerialReadBuffer[READ_BUFFER_LEN]; 404char mySerialReadBuffer[READ_BUFFER_LEN]; 405 406 407 408 409 410inline void mySerial_process(){ 411 while (mySerial.available() > 0){ 412 char c = mySerial.read(); 413 if (c == '#'){ 414 mySerialReadBuffer[0] = 0; 415 }else{ 416 if (c == '/'){ 417 Serial.println("message from upstairs"); 418 Serial.println(mySerialReadBuffer); 419 command_process(mySerialReadBuffer, 1); 420 }else{ 421 //continue to concat 422 int n = strlen(mySerialReadBuffer); 423 if (n < READ_BUFFER_LEN - 2) { 424 mySerialReadBuffer[n] = c; 425 mySerialReadBuffer[n + 1] = 0; 426 } 427 } 428 } 429 } 430} 431 432 433inline void process_Serial(){ 434 while (Serial.available() > 0) { 435 char c = Serial.read(); 436 if (c == '#') { 437 filterWheelSerialReadBuffer[0] = 0; 438 } else { 439 if (c == '/') { 440 command_process(filterWheelSerialReadBuffer, 0); 441 //mySerial.write(filterWheelSerialReadBuffer); 442 } else { 443 //continue to concat 444 int n = strlen(filterWheelSerialReadBuffer); 445 if (n < READ_BUFFER_LEN - 2) { 446 filterWheelSerialReadBuffer[n] = c; 447 filterWheelSerialReadBuffer[n + 1] = 0; 448 } 449 } 450 } 451 }; 452} 453 454 455inline void serialInit(){ 456 Serial.begin(9600); 457 mySerial.begin(4800); 458} 459 460inline void serialProcess(){ 461 process_Serial(); 462 mySerial_process(); 463} 464 465 466 467 468void motorProcess(){ 469 if (0 != motorIsMoving){ 470 unsigned long int m = millis(); 471 if (m > motorOldMillis+500){ 472 motorOldMillis = m; 473 motorMovingCharactersCursor++; 474 if (motorMovingCharactersCursor >= 4){ 475 motorMovingCharactersCursor = 0; 476 } 477 motorDrawMovementStatus(); 478 } 479 } 480 if (1 == motorStoppedFlag){ 481 motorStoppedFlag = 0; 482 mySerial.println("#?fw:motstopd?/"); 483 } 484} 485void motorStart(int dir){ 486 if (dir == 0){ 487 motorIsMoving = 0; 488 }else{ 489 optoStart(); 490 491 if (dir > 0){ 492 motorIsMoving = 1; 493 }else{ 494 motorIsMoving = -1; 495 }; 496 } 497 motorDrawMovementStatus(); 498 motorSetDirectionPinsStateByDir(motorIsMoving); 499 if (dir == 0){ 500 motorStop(1); 501 } 502} 503 504inline void motorStartChrDir(char dir){ 505 motorStart(chrToDir(dir)); 506} 507 508void motorSetDirectionPinsStateByDir(int dir){ 509 digitalWrite(PIN_MOTOR_RIGHT, dir > 0 ? HIGH : LOW); 510 digitalWrite(PIN_MOTOR_LEFT, dir < 0 ? HIGH : LOW); 511}; 512 513inline void motorPause(byte doPause){ 514 motorSetDirectionPinsStateByDir((doPause == 0) ? motorIsMoving : 0); 515} 516 517void motorDrawMovementStatus(){ 518 motorPause(1); 519 lcd.setCursor(3,0); 520 lcd.print( 521 (0 != motorIsMoving ) ? 522 motorMovingCharacters[motorMovingCharactersCursor] : 523 MOTOR_IS_STATIONARY_CHARACTER 524 ); 525 motorPause(0); 526} 527 528 529 530 531// ================ WHEEL ==================== 532 533#define WHEEL_FILTERCOUNT 5 534// N position: the number visible on the side, 535// F position: the filter actually loaded 536// F(N) = N % 5 + 1 537#define COUNT_OF_CHANGES_BETWEEN_POSITIONS 123 538 539#define WHEEL_FILTER_NAMES_ITEMSIZE 5 540#define WHEEL_FILTER_NAMES_CHAR_ARRAY_SIZE ( WHEEL_FILTERCOUNT * WHEEL_FILTER_NAMES_ITEMSIZE ) 541#define WHEEL_FILTER_POSITION_ADDRESS 14 542#define WHEEL_FILTER_NAMES_CHAR_ARRAY_ADDR (WHEEL_FILTER_POSITION_ADDRESS+2) 543char wheelFilterNamesCharArray[WHEEL_FILTER_NAMES_CHAR_ARRAY_SIZE]; 544byte wheelNamesReadFromEEPROM = 0; 545 546void wheelSaveNPosition(byte p){ 547 eep.write(WHEEL_FILTER_POSITION_ADDRESS, p); 548}; 549 550byte wheelReadNPosition(){ 551 signed char p = eep.read(WHEEL_FILTER_POSITION_ADDRESS); 552 if (p < 1){ 553 return 1; 554 } 555 if (p > WHEEL_FILTERCOUNT){ 556 return 1; 557 } 558 return p; 559}; 560 561 562void wheelNamesToSerial(int destinationSerial){ 563 #define FILTERNAMES_HEAD "?filtrNs=" 564 #define FILTERNAMES_TAIL "?" 565 if (0 == destinationSerial){ 566 Serial.print('#'); 567 Serial.print(FILTERNAMES_HEAD); 568 for (uint16_t i=0; i<WHEEL_FILTER_NAMES_CHAR_ARRAY_SIZE; i++){ 569 Serial.print(wheelFilterNamesCharArray[i]); 570 } 571 Serial.print(FILTERNAMES_TAIL); 572 Serial.println('/'); 573 } 574 if (1 == destinationSerial){ 575 //this guy may be slower, so just enqueue some 576 Serial.println("destination is 1"); 577 mySerial.print('#'); 578 mySerial.print(FILTERNAMES_HEAD); 579 for (uint16_t i=0; i<WHEEL_FILTER_NAMES_CHAR_ARRAY_SIZE; i++){ 580 mySerial.print(wheelFilterNamesCharArray[i]); 581 } 582 mySerial.print(FILTERNAMES_TAIL); 583 mySerial.println('/'); 584 } 585} 586 587void wheelNamesWrite(){ 588 Serial.println("writing to eeprom"); 589 wheelNamesToSerial(0); 590 for (uint16_t i=0; i<WHEEL_FILTER_NAMES_CHAR_ARRAY_SIZE; i++){ 591 eep.write(WHEEL_FILTER_NAMES_CHAR_ARRAY_ADDR + i, wheelFilterNamesCharArray[i]); 592 } 593 wheelNamesReadFromEEPROM = 0; 594} 595 596void wheelNamesRead(int destinationSerial){ 597 for (uint16_t i=0; i<WHEEL_FILTER_NAMES_CHAR_ARRAY_SIZE; i++){ 598 wheelFilterNamesCharArray[i] = eep.read(WHEEL_FILTER_NAMES_CHAR_ARRAY_ADDR + i); 599 } 600 wheelNamesToSerial(destinationSerial); 601} 602 603void wheelNamesCachedRead(){ 604 if (0 == wheelNamesReadFromEEPROM){ 605 wheelNamesReadFromEEPROM = 1; 606 wheelNamesRead(-1); 607 } 608} 609 610 611 612byte wheelNamesToggleStatus = 1; 613void wheelNamesToggle(){ 614 if (1 == wheelNamesToggleStatus){ 615 wheelNamesToggleStatus = 0; 616 wheelDisplayNPosition(0); 617 lcd.setCursor(0,1); 618 lcd.print("ABCD:move #d:set"); 619 }else{ 620 wheelNamesToggleStatus = 1; 621 wheelDisplayNPosition(0); 622 wheelNamesCachedRead(); 623 lcd.setCursor(4,0); 624 int i = 0; 625 i+= 2; 626 lcd.print(' '); 627 lcd.print(' '); 628 lcd.print(' '); 629 lcd.print(NUMBER_1_FILTER_INDEX_CHARACTER); 630 lcd.print(wheelFilterNamesCharArray[i++]); 631 lcd.print(wheelFilterNamesCharArray[i++]); 632 lcd.print(wheelFilterNamesCharArray[i++]); 633 lcd.print(' '); 634 i+= 2; 635 lcd.print(NUMBER_2_FILTER_INDEX_CHARACTER); 636 lcd.print(wheelFilterNamesCharArray[i++]); 637 lcd.print(wheelFilterNamesCharArray[i++]); 638 lcd.print(wheelFilterNamesCharArray[i++]); 639 lcd.print(' '); 640 lcd.setCursor(0,1); 641 lcd.print(' '); 642 lcd.print(' '); 643 i += 2; 644 lcd.print(NUMBER_3_FILTER_INDEX_CHARACTER); 645 lcd.print(wheelFilterNamesCharArray[i++]); 646 lcd.print(wheelFilterNamesCharArray[i++]); 647 lcd.print(wheelFilterNamesCharArray[i++]); 648 lcd.print(' '); 649 i+= 2; 650 lcd.print(NUMBER_4_FILTER_INDEX_CHARACTER); 651 lcd.print(wheelFilterNamesCharArray[i++]); 652 lcd.print(wheelFilterNamesCharArray[i++]); 653 lcd.print(wheelFilterNamesCharArray[i++]); 654 lcd.print(' '); 655 i+= 2; 656 lcd.print(NUMBER_5_FILTER_INDEX_CHARACTER); 657 lcd.print(wheelFilterNamesCharArray[i++]); 658 lcd.print(wheelFilterNamesCharArray[i++]); 659 lcd.print(wheelFilterNamesCharArray[i++]); 660 lcd.print(' '); 661 } 662}; 663 664 665 666 667int wheelPosition = 1; 668int wheelStopAfter = 0; 669 670void wheelReportNPositionToSerialPorts(int isSetting){ 671 Serial.print("#?wheel"); 672 if (1 == isSetting){ 673 Serial.print("Set"); 674 }; 675 Serial.print("Position="); 676 Serial.print(wheelPosition); 677 Serial.print("?/"); 678 mySerial.print("#?wheelPosition="); 679 mySerial.print(wheelPosition); 680 mySerial.print("?/"); 681}; 682 683void wheelDisplayNPosition(int isSetting){ 684 lcd.setCursor(0,0); 685 lcd.print("N="); 686 lcd.print(wheelPosition); 687 lcd.print(" d:goto"); 688 motorDrawMovementStatus(); 689 wheelReportNPositionToSerialPorts(isSetting); 690} 691 692void wheelConsiderWeAreAtNPosition(int n){ 693 wheelPosition = n; 694 wheelSaveNPosition(n); 695 wheelDisplayNPosition(1); 696}; 697 698 699void wheelMove(int dir, int count){ 700 optoObserver.changes = 0; 701 wheelStopAfter = abs(count) * COUNT_OF_CHANGES_BETWEEN_POSITIONS - 1; 702 if (wheelStopAfter < 0){ 703 wheelStopAfter = 0; 704 } 705 motorStart(dir); 706 wheelPosition = wheelPosition + count*dir; 707 while (wheelPosition > WHEEL_FILTERCOUNT){ 708 wheelPosition -= WHEEL_FILTERCOUNT; 709 } 710 while (wheelPosition < 1){ 711 wheelPosition += WHEEL_FILTERCOUNT; 712 } 713 wheelDisplayNPosition(0); 714} 715 716void wheelMoveFullCircleChrDir(char dir){ 717 wheelMove(chrToDir(dir), WHEEL_FILTERCOUNT); 718}; 719 720 721inline void wheelMoveChrDir(char dir, int count){ 722 wheelMove(chrToDir(dir), count); 723}; 724 725 726void wheelMarkInputStateChange(){ 727 if (wheelStopAfter > 0){ 728 wheelStopAfter--; 729 if (wheelStopAfter == 0){ 730 motorStop(1); 731 } 732 } 733} 734 735void wheelGotoNPosition(int n){ 736 int zeroBasedCurrentPosition = wheelPosition - 1; 737 int zeroBasedDestination = n - 1; 738 739 int delta = zeroBasedDestination - zeroBasedCurrentPosition; 740 if (abs(delta) > WHEEL_FILTERCOUNT / 2){ 741 int s = delta < 0 ? -1 : 1; 742 delta = (WHEEL_FILTERCOUNT - abs(delta))*(s*-1); 743 } 744 /* 745 lcd.setCursor(0,1); 746 lcd.print("delta="); 747 lcd.print(delta); 748 lcd.print(" "); 749 */ 750 wheelSaveNPosition(zeroBasedDestination + 1); 751 wheelMove(-delta, -delta); 752 wheelPosition = zeroBasedDestination + 1; 753 wheelDisplayNPosition(1); 754} 755 756int wheelNextKeyIsNSetter = 0; 757 758void wheelMoveALittle(char dir, int steps){ 759 wheelStopAfter = steps; 760 motorStartChrDir(dir); 761} 762 763void wheelNamesSetIndexZ(int zi, char * subname, int doWrite){ 764 if (zi < 0){ 765 return ;//invalid index 766 } 767 if (zi >= WHEEL_FILTERCOUNT){ 768 return ; // invalid index 769 } 770 #ifdef FILTERWHEEL_PROJECT_DEBUG_MODE 771 Serial.print("Setting name "); 772 Serial.print(zi); 773 Serial.print(" to "); 774 Serial.println(subname); 775 #endif 776 int i = zi*WHEEL_FILTER_NAMES_ITEMSIZE; 777 wheelFilterNamesCharArray[i++] = zi+48+1; 778 wheelFilterNamesCharArray[i++] = '='; 779 byte j=0; 780 for (byte k=0; k<WHEEL_FILTER_NAMES_ITEMSIZE-2;k++){ 781 wheelFilterNamesCharArray[i+k] = (j<strlen(subname)) ? subname[j++] : ' '; 782 } 783 if (1 == doWrite){ 784 wheelNamesWrite(); 785 }; 786} 787 788 789 790 791int command_process(const char * filterWheelSerialReadBuffer, int destinationSerial){ 792 if (strncmp(filterWheelSerialReadBuffer, "filter", 6) == 0){ 793 wheelMoveChrDir(filterWheelSerialReadBuffer[6], 1); 794 return 1; 795 } 796 if (strncmp(filterWheelSerialReadBuffer, "jump", 4) == 0){ 797 wheelMoveALittle(filterWheelSerialReadBuffer[4], 10); 798 return 1; 799 } 800 if (strncmp(filterWheelSerialReadBuffer, "move", 4) == 0){ 801 wheelMoveALittle(filterWheelSerialReadBuffer[4], 4); 802 return 1; 803 } 804 if (strncmp(filterWheelSerialReadBuffer, "step", 4) == 0){ 805 wheelMoveALittle(filterWheelSerialReadBuffer[4], 1); 806 return 1; 807 } 808 809 if (strncmp(filterWheelSerialReadBuffer, "atn,", 4) == 0){ 810 wheelConsiderWeAreAtNPosition(filterWheelSerialReadBuffer[4] - 48); 811 wheelStopAfter = 0; 812 motorStop(1); 813 return 1; 814 } 815 if (strncmp(filterWheelSerialReadBuffer, "goton,", 6) == 0){ 816 wheelGotoNPosition(filterWheelSerialReadBuffer[6] - 48); 817 return 1; 818 } 819 if (strncmp(filterWheelSerialReadBuffer, "goton=", 6) == 0){ 820 wheelGotoNPosition(filterWheelSerialReadBuffer[6] - 48); 821 return 1; 822 } 823 if (strncmp(filterWheelSerialReadBuffer, "wheren", 6) == 0){ 824 wheelReportNPositionToSerialPorts(0); 825 return 1; 826 } 827 if (strncmp(filterWheelSerialReadBuffer, "eepnames?", 9) == 0){ 828 wheelNamesRead(destinationSerial); 829 return 1; 830 } 831 if (strncmp(filterWheelSerialReadBuffer, "name",4)==0){ 832 #ifdef DEBUG_MODE 833 Serial.println(filterWheelSerialReadBuffer); 834 #endif 835 if (filterWheelSerialReadBuffer[4] == 's'){ 836 // names=a,b,c,d,e,f,g,h 837 char subname[16]; 838 subname[0] = 0; 839 int subnameIndex = 0; 840 for (int i=6; i<64; i++){ 841 if ((filterWheelSerialReadBuffer[i] == ',') || (filterWheelSerialReadBuffer[i] == 0)){ 842 wheelNamesSetIndexZ(subnameIndex, subname, 0); 843 if (filterWheelSerialReadBuffer[i] == 0){ 844 wheelNamesWrite(); 845 return ; 846 } 847 subname[0] = 0; 848 subnameIndex++; 849 }else{ 850 int l = strlen(subname); 851 if (l >= WHEEL_FILTER_NAMES_ITEMSIZE-1){ 852 l = WHEEL_FILTER_NAMES_ITEMSIZE-2; 853 } 854 subname[l] = filterWheelSerialReadBuffer[i]; 855 subname[l+1] = 0; 856 } 857 } 858 //wheelNamesWrite(); 859 }else{ 860 // nameN=xyzqw 861 strcat(filterWheelSerialReadBuffer, " "); 862 int n = filterWheelSerialReadBuffer[4] - 48; 863 wheelNamesSetIndexZ(n-1, filterWheelSerialReadBuffer+6, 1); 864 } 865 return 1; 866 } 867 return 0; 868} 869 870 871 872 873 874void setup(){ 875 lcd.init(); 876 lcd.backlight(); 877 lcd.setCursor(0,0); 878 lcd.print(FILTERWHEEL_WELCOME_SCREEN_FIRST_LINE); 879 lcd.setCursor(0,1); 880 lcd.print(FILTERWHEEL_WELCOME_SCREEN_SECOND_LINE); 881 optoInit(); 882 883 motorInit(); 884 885 serialInit(); 886 887 #ifndef FILTERWHEEL_PROJECT_DEBUG_MODE 888 wheelNamesCachedRead(); 889 wheelPosition = wheelReadNPosition(); 890 delay(1000); 891 #endif 892 keyboardInit(); 893 lcd.setCursor(0,0); 894 lcd.print("Set the cur. N "); 895 wheelNamesToggle(); 896 #ifdef FILTERWHEEL_PROJECT_DEBUG_MODE 897 Serial.println("debug mode"); 898 wheelNamesRead(0); 899 #endif 900} 901 902 903 904 905void loop() { 906 if (OPTO_CHANGE_OBSERVED == optoObserverProcess()){ 907 wheelMarkInputStateChange(); 908 } 909 serialProcess(); 910 keyboardProcess(); 911 motorProcess(); 912 913 currentKey = keyboardGetCurrentKey(); 914 if (currentKey != 0){ 915 if (currentKey == '*'){ 916 wheelNamesToggle(); 917 } 918 if (currentKey == '0'){ 919 resetFunc(); 920 } 921 if (0 != motorIsMoving){ 922 // do not execute keyboard commands 923 }else{ 924 if ((currentKey >= 49) && (currentKey <= 57)){ 925 //if (currentKey == '8'){ wheelMoveFullCircleChrDir('R'); } 926 if ((currentKey - 48) > WHEEL_FILTERCOUNT){ 927 //invalid filter N position, zero already handled 928 return ; 929 } 930 if (1 == wheelNamesToggleStatus){ 931 wheelNamesToggle(); 932 } 933 if (1 == wheelNextKeyIsNSetter){ 934 wheelConsiderWeAreAtNPosition(currentKey - 48); 935 wheelStopAfter = 0; 936 motorStop(1); 937 }else{ 938 wheelGotoNPosition(currentKey - 48); 939 } 940 } 941 if (currentKey == '#'){ 942 if (1 == wheelNextKeyIsNSetter){ 943 wheelNextKeyIsNSetter = 0; 944 wheelDisplayNPosition(0); 945 }else{ 946 wheelNextKeyIsNSetter = 1; 947 lcd.setCursor(2,0); 948 lcd.print('?'); 949 } 950 }else{ 951 wheelNextKeyIsNSetter = 0; 952 } 953 if (currentKey == 'A'){ 954 wheelMoveALittle('L', 4); 955 } 956 if (currentKey == 'D'){ 957 wheelMoveALittle('R', 4); 958 } 959 if (currentKey == 'B'){ 960 wheelMoveALittle('L', 2); 961 } 962 if (currentKey == 'C'){ 963 wheelMoveALittle('R', 2); 964 } 965 } 966 } 967 968}
The code
c_cpp
The source code of the hand controller
1#define FILTERWHEEL_WELCOME_SCREEN_FIRST_LINE "FilterWheel v0.4" 2#define FILTERWHEEL_WELCOME_SCREEN_SECOND_LINE " csillagtura.ro " 3 4 5//#define FILTERWHEEL_PROJECT_DEBUG_MODE 6 7 8 9 10 11#include <AT24Cxx.h> 12 13#include <Wire.h> 14#include <LiquidCrystal_I2C.h> 15 16#define EEPROM_I2C_ADDRESS 0x50 17 18AT24Cxx eep(EEPROM_I2C_ADDRESS, 32); 19 20 21LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display 22 23//=================== PINS ====================== 24 25#define PIN_MOTOR_RIGHT A0 26#define PIN_MOTOR_LEFT A1 27 28 29#define PIN_ROW_0 12 30#define PIN_ROW_1 11 31#define PIN_ROW_2 10 32#define PIN_ROW_3 9 33 34#define PIN_COL_0 8 35#define PIN_COL_1 7 36#define PIN_COL_2 6 37#define PIN_COL_3 5 38 39#define PIN_OPTO_ENABLE 4 40 41#define PIN_OPTO_INPUT A2 42 43#define PIN_MYSERIAL_TX 3 44#define PIN_MYSERIAL_RX 2 45 46 47 48 49 50 51//====================== KEYBOARD ========================== 52#define KEYBOARD_INPUT_LEN 10 53char keyboardInput[KEYBOARD_INPUT_LEN]; 54int keyboardCursorRead = 0; 55int keyboardCursorWrite = 0; 56int keyboardCurrentColumn = 0; 57const char keyboardKeys[16] = {'1','2','3','A','4','5','6','B','7','8','9','C','*','0','#','D'}; 58 59char currentKey = 0; 60 61 62 63char keyboardCandidate = 0; 64char keyboardPreviousCandidate = 0; 65int keyboardCandidateObservedCount = 0; 66 67 68 69 70void keyboardInsert(char c){ 71 int prev = keyboardCursorWrite - 1; 72 if (prev == -1){ 73 prev = KEYBOARD_INPUT_LEN - 1; 74 } 75 if (keyboardInput[prev] == c){ 76 return ; 77 } 78 keyboardInput[keyboardCursorWrite] = c; 79 keyboardCursorWrite++; 80 if (keyboardCursorWrite >= KEYBOARD_INPUT_LEN ){ 81 keyboardCursorWrite = 0; 82 } 83} 84 85void keyboardInit(){ 86 pinMode(PIN_ROW_0, INPUT_PULLUP); 87 pinMode(PIN_ROW_1, INPUT_PULLUP); 88 pinMode(PIN_ROW_2, INPUT_PULLUP); 89 pinMode(PIN_ROW_3, INPUT_PULLUP); 90 91 pinMode(PIN_COL_0, OUTPUT); 92 pinMode(PIN_COL_1, OUTPUT); 93 pinMode(PIN_COL_2, OUTPUT); 94 pinMode(PIN_COL_3, OUTPUT); 95 96 digitalWrite(PIN_COL_0, HIGH); 97 digitalWrite(PIN_COL_1, HIGH); 98 digitalWrite(PIN_COL_2, HIGH); 99 digitalWrite(PIN_COL_3, HIGH); 100} 101 102void keyboardProcess(){ 103 digitalWrite(PIN_COL_0, keyboardCurrentColumn == 0 ? LOW: HIGH); 104 digitalWrite(PIN_COL_1, keyboardCurrentColumn == 1 ? LOW: HIGH); 105 digitalWrite(PIN_COL_2, keyboardCurrentColumn == 2 ? LOW: HIGH); 106 digitalWrite(PIN_COL_3, keyboardCurrentColumn == 3 ? LOW: HIGH); 107 if (keyboardCurrentColumn == 0){ 108 //full cycle, reset 109 keyboardCandidate = 0; 110 } 111 if (digitalRead(PIN_ROW_0) == LOW){ 112 keyboardCandidate = keyboardKeys[ 0*4 + keyboardCurrentColumn ]; 113 } 114 if (digitalRead(PIN_ROW_1) == LOW){ 115 keyboardCandidate = keyboardKeys[ 1*4 + keyboardCurrentColumn ]; 116 } 117 if (digitalRead(PIN_ROW_2) == LOW){ 118 keyboardCandidate = keyboardKeys[ 2*4 + keyboardCurrentColumn ]; 119 } 120 if (digitalRead(PIN_ROW_3) == LOW){ 121 keyboardCandidate = keyboardKeys[ 3*4 + keyboardCurrentColumn ]; 122 } 123 124 keyboardCurrentColumn++; 125 if (keyboardCurrentColumn > 3){ 126 keyboardCurrentColumn = 0; 127 } 128 129 if (0 == keyboardCurrentColumn){ 130 //a full cycle has been done 131 if (keyboardCandidate == keyboardPreviousCandidate){ 132 if (keyboardCandidateObservedCount > 100){ 133 //we have a keypress 134 keyboardInsert(keyboardCandidate); 135 keyboardCandidateObservedCount = 0; 136 }else{ 137 keyboardCandidateObservedCount++; 138 } 139 }else{ 140 keyboardCandidateObservedCount = 0; 141 keyboardPreviousCandidate = keyboardCandidate; 142 } 143 } 144 145 146 //Serial.print(candidate); 147} 148 149char keyboardGetCurrentKey(){ 150 char r = 0; 151 if (keyboardCursorRead != keyboardCursorWrite){ 152 r = keyboardInput[keyboardCursorRead]; 153 keyboardCursorRead = keyboardCursorWrite; 154 }; 155 return r; 156} 157 158 159 160#define OPTO_CHANGE_OBSERVED 1 161#define OPTO_NO_CHANGE_OBSERVED 0 162 163typedef struct OptoObserver { 164 unsigned int changes; 165 unsigned int observingSameStateCounter; 166 byte observingState; 167 byte observingPreviousState; 168 byte currentState; 169 byte optoIsObserving; 170} OptoObserver; 171 172OptoObserver optoObserver; 173 174 175void optoStart(){ 176 digitalWrite(PIN_OPTO_ENABLE, HIGH); 177 optoObserver.observingState = (digitalRead(PIN_OPTO_INPUT) == HIGH) ? 1 : 0; 178 optoObserver.observingPreviousState = optoObserver.observingState; 179 optoObserver.optoIsObserving = 1; 180} 181 182void optoStop(){ 183 optoObserver.optoIsObserving = 0; 184 digitalWrite(PIN_OPTO_ENABLE, LOW); 185} 186 187void optoInit(){ 188 pinMode(PIN_OPTO_INPUT, INPUT_PULLUP); 189 pinMode(PIN_OPTO_ENABLE, OUTPUT); 190 digitalWrite(PIN_OPTO_ENABLE, LOW); 191 optoObserver.optoIsObserving = 0; 192} 193 194byte optoObserverProcess(){ 195 byte rez = OPTO_NO_CHANGE_OBSERVED; 196 if (1 == optoObserver.optoIsObserving){ 197 optoObserver.observingState = (digitalRead(PIN_OPTO_INPUT) == HIGH) ? 1 : 0; 198 if (optoObserver.observingState == optoObserver.observingPreviousState){ 199 optoObserver.observingSameStateCounter++; 200 if (optoObserver.observingSameStateCounter > 200){ 201 optoObserver.observingSameStateCounter = 200; 202 } 203 if (optoObserver.observingSameStateCounter > 100){ 204 if (optoObserver.currentState != optoObserver.observingState){ 205 optoObserver.currentState = optoObserver.observingState; 206 //we have an event here 207 optoObserver.changes++; 208 rez = OPTO_CHANGE_OBSERVED; 209 /* 210 lcd.setCursor(0,1); 211 char n[10]; 212 itoa(changes, n, 10); 213 lcd.print(n); 214 lcd.print(" "); 215 */ 216 } 217 } 218 }else{ 219 optoObserver.observingSameStateCounter = 0; 220 } 221 optoObserver.observingPreviousState = optoObserver.observingState; 222 }else{ 223 // the opto is turned off 224 } 225 return rez; 226} 227 228 229 230 231 232inline int chrToDir(char dir){ 233 if (dir == 'L'){ 234 return 1; 235 }else{ 236 return -1; 237 }; 238} 239 240void(* resetFunc) (void) = 0; //declare reset function @ address 0 241 242 243 244#define NUMBER_1_FILTER_INDEX_CHARACTER '\\1' 245#define NUMBER_2_FILTER_INDEX_CHARACTER '\\2' 246#define NUMBER_3_FILTER_INDEX_CHARACTER '\\3' 247#define NUMBER_4_FILTER_INDEX_CHARACTER '\\4' 248#define NUMBER_5_FILTER_INDEX_CHARACTER '\\5' 249#define MOTOR_IS_STATIONARY_CHARACTER '\\6' 250#define MOTOR_BACKSLASH_CHARACTER '\\7' 251 252 253byte customBackslash[8] = { 254 0b00000, 255 0b10000, 256 0b01000, 257 0b00100, 258 0b00010, 259 0b00001, 260 0b00000, 261 0b00000 262}; 263byte customDot[8] = { 264 0b00000, 265 0b00000, 266 0b00100, 267 0b00000, 268 0b00000, 269 0b00000, 270 0b00000, 271 0b00000 272}; 273/* 274byte customOneFilterIndex[8] = { 275 0b01000, 276 0b11000, 277 0b01001, 278 0b01000, 279 0b01001, 280 0b11100, 281 0b00000, 282 0b00000 283}; 284 285byte customTwoFilterIndex[8] = { 286 0b01100, 287 0b10100, 288 0b00101, 289 0b01000, 290 0b10001, 291 0b11100, 292 0b00000, 293 0b00000 294}; 295*/ 296 297byte customOneFilterIndex[8] = { 298 0b01000, 299 0b11000, 300 0b01000, 301 0b01000, 302 0b11100, 303 0b00000, 304 0b00000, 305 0b00000 306}; 307 308byte customTwoFilterIndex[8] = { 309 0b01000, 310 0b10100, 311 0b00100, 312 0b01000, 313 0b11100, 314 0b00000, 315 0b00000, 316 0b00000 317}; 318 319byte customThreeFilterIndex[8] = { 320 0b11000, 321 0b00100, 322 0b01000, 323 0b00100, 324 0b11000, 325 0b00000, 326 0b00000, 327 0b00000 328}; 329 330byte customFourFilterIndex[8] = { 331 0b00100, 332 0b01100, 333 0b10100, 334 0b11110, 335 0b00100, 336 0b00000, 337 0b00000, 338 0b00000 339}; 340 341byte customFiveFilterIndex[8] = { 342 0b11100, 343 0b10000, 344 0b11100, 345 0b00100, 346 0b11000, 347 0b00000, 348 0b00000, 349 0b00000 350}; 351 352inline void customCharsInit(){ 353 lcd.createChar((byte) MOTOR_BACKSLASH_CHARACTER, customBackslash); 354 lcd.createChar((byte) MOTOR_IS_STATIONARY_CHARACTER, customDot); 355 lcd.createChar((byte) NUMBER_1_FILTER_INDEX_CHARACTER, customOneFilterIndex); 356 lcd.createChar((byte) NUMBER_2_FILTER_INDEX_CHARACTER, customTwoFilterIndex); 357 lcd.createChar((byte) NUMBER_3_FILTER_INDEX_CHARACTER, customThreeFilterIndex); 358 lcd.createChar((byte) NUMBER_4_FILTER_INDEX_CHARACTER, customFourFilterIndex); 359 lcd.createChar((byte) NUMBER_5_FILTER_INDEX_CHARACTER, customFiveFilterIndex); 360 361} 362 363 364//=================== MOTOR ===================== 365const char motorMovingCharacters[4] = { 366 '/', '-', MOTOR_BACKSLASH_CHARACTER, '|' 367}; 368int motorMovingCharactersCursor = 0; 369int motorIsMoving = 0; 370unsigned long int motorOldMillis = 0; 371 372 373 374 375byte motorStoppedFlag = 0; 376 377void motorStop(byte updateScreen){ 378 optoStop(); 379 motorIsMoving = 0; 380 motorSetDirectionPinsStateByDir(motorIsMoving); 381 if (1 == updateScreen){ 382 motorDrawMovementStatus(); 383 } 384 motorStoppedFlag = 1; 385} 386 387 388void motorInit(){ 389 pinMode(PIN_MOTOR_LEFT, OUTPUT); 390 pinMode(PIN_MOTOR_RIGHT, OUTPUT); 391 motorStop(0); 392 customCharsInit(); 393} 394 395 396 397 398#include <SoftwareSerial.h> 399SoftwareSerial mySerial(PIN_MYSERIAL_RX, PIN_MYSERIAL_TX); 400 401 402const int READ_BUFFER_LEN = 96; 403char filterWheelSerialReadBuffer[READ_BUFFER_LEN]; 404char mySerialReadBuffer[READ_BUFFER_LEN]; 405 406 407 408 409 410inline void mySerial_process(){ 411 while (mySerial.available() > 0){ 412 char c = mySerial.read(); 413 if (c == '#'){ 414 mySerialReadBuffer[0] = 0; 415 }else{ 416 if (c == '/'){ 417 Serial.println("message from upstairs"); 418 Serial.println(mySerialReadBuffer); 419 command_process(mySerialReadBuffer, 1); 420 }else{ 421 //continue to concat 422 int n = strlen(mySerialReadBuffer); 423 if (n < READ_BUFFER_LEN - 2) { 424 mySerialReadBuffer[n] = c; 425 mySerialReadBuffer[n + 1] = 0; 426 } 427 } 428 } 429 } 430} 431 432 433inline void process_Serial(){ 434 while (Serial.available() > 0) { 435 char c = Serial.read(); 436 if (c == '#') { 437 filterWheelSerialReadBuffer[0] = 0; 438 } else { 439 if (c == '/') { 440 command_process(filterWheelSerialReadBuffer, 0); 441 //mySerial.write(filterWheelSerialReadBuffer); 442 } else { 443 //continue to concat 444 int n = strlen(filterWheelSerialReadBuffer); 445 if (n < READ_BUFFER_LEN - 2) { 446 filterWheelSerialReadBuffer[n] = c; 447 filterWheelSerialReadBuffer[n + 1] = 0; 448 } 449 } 450 } 451 }; 452} 453 454 455inline void serialInit(){ 456 Serial.begin(9600); 457 mySerial.begin(4800); 458} 459 460inline void serialProcess(){ 461 process_Serial(); 462 mySerial_process(); 463} 464 465 466 467 468void motorProcess(){ 469 if (0 != motorIsMoving){ 470 unsigned long int m = millis(); 471 if (m > motorOldMillis+500){ 472 motorOldMillis = m; 473 motorMovingCharactersCursor++; 474 if (motorMovingCharactersCursor >= 4){ 475 motorMovingCharactersCursor = 0; 476 } 477 motorDrawMovementStatus(); 478 } 479 } 480 if (1 == motorStoppedFlag){ 481 motorStoppedFlag = 0; 482 mySerial.println("#?fw:motstopd?/"); 483 } 484} 485void motorStart(int dir){ 486 if (dir == 0){ 487 motorIsMoving = 0; 488 }else{ 489 optoStart(); 490 491 if (dir > 0){ 492 motorIsMoving = 1; 493 }else{ 494 motorIsMoving = -1; 495 }; 496 } 497 motorDrawMovementStatus(); 498 motorSetDirectionPinsStateByDir(motorIsMoving); 499 if (dir == 0){ 500 motorStop(1); 501 } 502} 503 504inline void motorStartChrDir(char dir){ 505 motorStart(chrToDir(dir)); 506} 507 508void motorSetDirectionPinsStateByDir(int dir){ 509 digitalWrite(PIN_MOTOR_RIGHT, dir > 0 ? HIGH : LOW); 510 digitalWrite(PIN_MOTOR_LEFT, dir < 0 ? HIGH : LOW); 511}; 512 513inline void motorPause(byte doPause){ 514 motorSetDirectionPinsStateByDir((doPause == 0) ? motorIsMoving : 0); 515} 516 517void motorDrawMovementStatus(){ 518 motorPause(1); 519 lcd.setCursor(3,0); 520 lcd.print( 521 (0 != motorIsMoving ) ? 522 motorMovingCharacters[motorMovingCharactersCursor] : 523 MOTOR_IS_STATIONARY_CHARACTER 524 ); 525 motorPause(0); 526} 527 528 529 530 531// ================ WHEEL ==================== 532 533#define WHEEL_FILTERCOUNT 5 534// N position: the number visible on the side, 535// F position: the filter actually loaded 536// F(N) = N % 5 + 1 537#define COUNT_OF_CHANGES_BETWEEN_POSITIONS 123 538 539#define WHEEL_FILTER_NAMES_ITEMSIZE 5 540#define WHEEL_FILTER_NAMES_CHAR_ARRAY_SIZE ( WHEEL_FILTERCOUNT * WHEEL_FILTER_NAMES_ITEMSIZE ) 541#define WHEEL_FILTER_POSITION_ADDRESS 14 542#define WHEEL_FILTER_NAMES_CHAR_ARRAY_ADDR (WHEEL_FILTER_POSITION_ADDRESS+2) 543char wheelFilterNamesCharArray[WHEEL_FILTER_NAMES_CHAR_ARRAY_SIZE]; 544byte wheelNamesReadFromEEPROM = 0; 545 546void wheelSaveNPosition(byte p){ 547 eep.write(WHEEL_FILTER_POSITION_ADDRESS, p); 548}; 549 550byte wheelReadNPosition(){ 551 signed char p = eep.read(WHEEL_FILTER_POSITION_ADDRESS); 552 if (p < 1){ 553 return 1; 554 } 555 if (p > WHEEL_FILTERCOUNT){ 556 return 1; 557 } 558 return p; 559}; 560 561 562void wheelNamesToSerial(int destinationSerial){ 563 #define FILTERNAMES_HEAD "?filtrNs=" 564 #define FILTERNAMES_TAIL "?" 565 if (0 == destinationSerial){ 566 Serial.print('#'); 567 Serial.print(FILTERNAMES_HEAD); 568 for (uint16_t i=0; i<WHEEL_FILTER_NAMES_CHAR_ARRAY_SIZE; i++){ 569 Serial.print(wheelFilterNamesCharArray[i]); 570 } 571 Serial.print(FILTERNAMES_TAIL); 572 Serial.println('/'); 573 } 574 if (1 == destinationSerial){ 575 //this guy may be slower, so just enqueue some 576 Serial.println("destination is 1"); 577 mySerial.print('#'); 578 mySerial.print(FILTERNAMES_HEAD); 579 for (uint16_t i=0; i<WHEEL_FILTER_NAMES_CHAR_ARRAY_SIZE; i++){ 580 mySerial.print(wheelFilterNamesCharArray[i]); 581 } 582 mySerial.print(FILTERNAMES_TAIL); 583 mySerial.println('/'); 584 } 585} 586 587void wheelNamesWrite(){ 588 Serial.println("writing to eeprom"); 589 wheelNamesToSerial(0); 590 for (uint16_t i=0; i<WHEEL_FILTER_NAMES_CHAR_ARRAY_SIZE; i++){ 591 eep.write(WHEEL_FILTER_NAMES_CHAR_ARRAY_ADDR + i, wheelFilterNamesCharArray[i]); 592 } 593 wheelNamesReadFromEEPROM = 0; 594} 595 596void wheelNamesRead(int destinationSerial){ 597 for (uint16_t i=0; i<WHEEL_FILTER_NAMES_CHAR_ARRAY_SIZE; i++){ 598 wheelFilterNamesCharArray[i] = eep.read(WHEEL_FILTER_NAMES_CHAR_ARRAY_ADDR + i); 599 } 600 wheelNamesToSerial(destinationSerial); 601} 602 603void wheelNamesCachedRead(){ 604 if (0 == wheelNamesReadFromEEPROM){ 605 wheelNamesReadFromEEPROM = 1; 606 wheelNamesRead(-1); 607 } 608} 609 610 611 612byte wheelNamesToggleStatus = 1; 613void wheelNamesToggle(){ 614 if (1 == wheelNamesToggleStatus){ 615 wheelNamesToggleStatus = 0; 616 wheelDisplayNPosition(0); 617 lcd.setCursor(0,1); 618 lcd.print("ABCD:move #d:set"); 619 }else{ 620 wheelNamesToggleStatus = 1; 621 wheelDisplayNPosition(0); 622 wheelNamesCachedRead(); 623 lcd.setCursor(4,0); 624 int i = 0; 625 i+= 2; 626 lcd.print(' '); 627 lcd.print(' '); 628 lcd.print(' '); 629 lcd.print(NUMBER_1_FILTER_INDEX_CHARACTER); 630 lcd.print(wheelFilterNamesCharArray[i++]); 631 lcd.print(wheelFilterNamesCharArray[i++]); 632 lcd.print(wheelFilterNamesCharArray[i++]); 633 lcd.print(' '); 634 i+= 2; 635 lcd.print(NUMBER_2_FILTER_INDEX_CHARACTER); 636 lcd.print(wheelFilterNamesCharArray[i++]); 637 lcd.print(wheelFilterNamesCharArray[i++]); 638 lcd.print(wheelFilterNamesCharArray[i++]); 639 lcd.print(' '); 640 lcd.setCursor(0,1); 641 lcd.print(' '); 642 lcd.print(' '); 643 i += 2; 644 lcd.print(NUMBER_3_FILTER_INDEX_CHARACTER); 645 lcd.print(wheelFilterNamesCharArray[i++]); 646 lcd.print(wheelFilterNamesCharArray[i++]); 647 lcd.print(wheelFilterNamesCharArray[i++]); 648 lcd.print(' '); 649 i+= 2; 650 lcd.print(NUMBER_4_FILTER_INDEX_CHARACTER); 651 lcd.print(wheelFilterNamesCharArray[i++]); 652 lcd.print(wheelFilterNamesCharArray[i++]); 653 lcd.print(wheelFilterNamesCharArray[i++]); 654 lcd.print(' '); 655 i+= 2; 656 lcd.print(NUMBER_5_FILTER_INDEX_CHARACTER); 657 lcd.print(wheelFilterNamesCharArray[i++]); 658 lcd.print(wheelFilterNamesCharArray[i++]); 659 lcd.print(wheelFilterNamesCharArray[i++]); 660 lcd.print(' '); 661 } 662}; 663 664 665 666 667int wheelPosition = 1; 668int wheelStopAfter = 0; 669 670void wheelReportNPositionToSerialPorts(int isSetting){ 671 Serial.print("#?wheel"); 672 if (1 == isSetting){ 673 Serial.print("Set"); 674 }; 675 Serial.print("Position="); 676 Serial.print(wheelPosition); 677 Serial.print("?/"); 678 mySerial.print("#?wheelPosition="); 679 mySerial.print(wheelPosition); 680 mySerial.print("?/"); 681}; 682 683void wheelDisplayNPosition(int isSetting){ 684 lcd.setCursor(0,0); 685 lcd.print("N="); 686 lcd.print(wheelPosition); 687 lcd.print(" d:goto"); 688 motorDrawMovementStatus(); 689 wheelReportNPositionToSerialPorts(isSetting); 690} 691 692void wheelConsiderWeAreAtNPosition(int n){ 693 wheelPosition = n; 694 wheelSaveNPosition(n); 695 wheelDisplayNPosition(1); 696}; 697 698 699void wheelMove(int dir, int count){ 700 optoObserver.changes = 0; 701 wheelStopAfter = abs(count) * COUNT_OF_CHANGES_BETWEEN_POSITIONS - 1; 702 if (wheelStopAfter < 0){ 703 wheelStopAfter = 0; 704 } 705 motorStart(dir); 706 wheelPosition = wheelPosition + count*dir; 707 while (wheelPosition > WHEEL_FILTERCOUNT){ 708 wheelPosition -= WHEEL_FILTERCOUNT; 709 } 710 while (wheelPosition < 1){ 711 wheelPosition += WHEEL_FILTERCOUNT; 712 } 713 wheelDisplayNPosition(0); 714} 715 716void wheelMoveFullCircleChrDir(char dir){ 717 wheelMove(chrToDir(dir), WHEEL_FILTERCOUNT); 718}; 719 720 721inline void wheelMoveChrDir(char dir, int count){ 722 wheelMove(chrToDir(dir), count); 723}; 724 725 726void wheelMarkInputStateChange(){ 727 if (wheelStopAfter > 0){ 728 wheelStopAfter--; 729 if (wheelStopAfter == 0){ 730 motorStop(1); 731 } 732 } 733} 734 735void wheelGotoNPosition(int n){ 736 int zeroBasedCurrentPosition = wheelPosition - 1; 737 int zeroBasedDestination = n - 1; 738 739 int delta = zeroBasedDestination - zeroBasedCurrentPosition; 740 if (abs(delta) > WHEEL_FILTERCOUNT / 2){ 741 int s = delta < 0 ? -1 : 1; 742 delta = (WHEEL_FILTERCOUNT - abs(delta))*(s*-1); 743 } 744 /* 745 lcd.setCursor(0,1); 746 lcd.print("delta="); 747 lcd.print(delta); 748 lcd.print(" "); 749 */ 750 wheelSaveNPosition(zeroBasedDestination + 1); 751 wheelMove(-delta, -delta); 752 wheelPosition = zeroBasedDestination + 1; 753 wheelDisplayNPosition(1); 754} 755 756int wheelNextKeyIsNSetter = 0; 757 758void wheelMoveALittle(char dir, int steps){ 759 wheelStopAfter = steps; 760 motorStartChrDir(dir); 761} 762 763void wheelNamesSetIndexZ(int zi, char * subname, int doWrite){ 764 if (zi < 0){ 765 return ;//invalid index 766 } 767 if (zi >= WHEEL_FILTERCOUNT){ 768 return ; // invalid index 769 } 770 #ifdef FILTERWHEEL_PROJECT_DEBUG_MODE 771 Serial.print("Setting name "); 772 Serial.print(zi); 773 Serial.print(" to "); 774 Serial.println(subname); 775 #endif 776 int i = zi*WHEEL_FILTER_NAMES_ITEMSIZE; 777 wheelFilterNamesCharArray[i++] = zi+48+1; 778 wheelFilterNamesCharArray[i++] = '='; 779 byte j=0; 780 for (byte k=0; k<WHEEL_FILTER_NAMES_ITEMSIZE-2;k++){ 781 wheelFilterNamesCharArray[i+k] = (j<strlen(subname)) ? subname[j++] : ' '; 782 } 783 if (1 == doWrite){ 784 wheelNamesWrite(); 785 }; 786} 787 788 789 790 791int command_process(const char * filterWheelSerialReadBuffer, int destinationSerial){ 792 if (strncmp(filterWheelSerialReadBuffer, "filter", 6) == 0){ 793 wheelMoveChrDir(filterWheelSerialReadBuffer[6], 1); 794 return 1; 795 } 796 if (strncmp(filterWheelSerialReadBuffer, "jump", 4) == 0){ 797 wheelMoveALittle(filterWheelSerialReadBuffer[4], 10); 798 return 1; 799 } 800 if (strncmp(filterWheelSerialReadBuffer, "move", 4) == 0){ 801 wheelMoveALittle(filterWheelSerialReadBuffer[4], 4); 802 return 1; 803 } 804 if (strncmp(filterWheelSerialReadBuffer, "step", 4) == 0){ 805 wheelMoveALittle(filterWheelSerialReadBuffer[4], 1); 806 return 1; 807 } 808 809 if (strncmp(filterWheelSerialReadBuffer, "atn,", 4) == 0){ 810 wheelConsiderWeAreAtNPosition(filterWheelSerialReadBuffer[4] - 48); 811 wheelStopAfter = 0; 812 motorStop(1); 813 return 1; 814 } 815 if (strncmp(filterWheelSerialReadBuffer, "goton,", 6) == 0){ 816 wheelGotoNPosition(filterWheelSerialReadBuffer[6] - 48); 817 return 1; 818 } 819 if (strncmp(filterWheelSerialReadBuffer, "goton=", 6) == 0){ 820 wheelGotoNPosition(filterWheelSerialReadBuffer[6] - 48); 821 return 1; 822 } 823 if (strncmp(filterWheelSerialReadBuffer, "wheren", 6) == 0){ 824 wheelReportNPositionToSerialPorts(0); 825 return 1; 826 } 827 if (strncmp(filterWheelSerialReadBuffer, "eepnames?", 9) == 0){ 828 wheelNamesRead(destinationSerial); 829 return 1; 830 } 831 if (strncmp(filterWheelSerialReadBuffer, "name",4)==0){ 832 #ifdef DEBUG_MODE 833 Serial.println(filterWheelSerialReadBuffer); 834 #endif 835 if (filterWheelSerialReadBuffer[4] == 's'){ 836 // names=a,b,c,d,e,f,g,h 837 char subname[16]; 838 subname[0] = 0; 839 int subnameIndex = 0; 840 for (int i=6; i<64; i++){ 841 if ((filterWheelSerialReadBuffer[i] == ',') || (filterWheelSerialReadBuffer[i] == 0)){ 842 wheelNamesSetIndexZ(subnameIndex, subname, 0); 843 if (filterWheelSerialReadBuffer[i] == 0){ 844 wheelNamesWrite(); 845 return ; 846 } 847 subname[0] = 0; 848 subnameIndex++; 849 }else{ 850 int l = strlen(subname); 851 if (l >= WHEEL_FILTER_NAMES_ITEMSIZE-1){ 852 l = WHEEL_FILTER_NAMES_ITEMSIZE-2; 853 } 854 subname[l] = filterWheelSerialReadBuffer[i]; 855 subname[l+1] = 0; 856 } 857 } 858 //wheelNamesWrite(); 859 }else{ 860 // nameN=xyzqw 861 strcat(filterWheelSerialReadBuffer, " "); 862 int n = filterWheelSerialReadBuffer[4] - 48; 863 wheelNamesSetIndexZ(n-1, filterWheelSerialReadBuffer+6, 1); 864 } 865 return 1; 866 } 867 return 0; 868} 869 870 871 872 873 874void setup(){ 875 lcd.init(); 876 lcd.backlight(); 877 lcd.setCursor(0,0); 878 lcd.print(FILTERWHEEL_WELCOME_SCREEN_FIRST_LINE); 879 lcd.setCursor(0,1); 880 lcd.print(FILTERWHEEL_WELCOME_SCREEN_SECOND_LINE); 881 optoInit(); 882 883 motorInit(); 884 885 serialInit(); 886 887 #ifndef FILTERWHEEL_PROJECT_DEBUG_MODE 888 wheelNamesCachedRead(); 889 wheelPosition = wheelReadNPosition(); 890 delay(1000); 891 #endif 892 keyboardInit(); 893 lcd.setCursor(0,0); 894 lcd.print("Set the cur. N "); 895 wheelNamesToggle(); 896 #ifdef FILTERWHEEL_PROJECT_DEBUG_MODE 897 Serial.println("debug mode"); 898 wheelNamesRead(0); 899 #endif 900} 901 902 903 904 905void loop() { 906 if (OPTO_CHANGE_OBSERVED == optoObserverProcess()){ 907 wheelMarkInputStateChange(); 908 } 909 serialProcess(); 910 keyboardProcess(); 911 motorProcess(); 912 913 currentKey = keyboardGetCurrentKey(); 914 if (currentKey != 0){ 915 if (currentKey == '*'){ 916 wheelNamesToggle(); 917 } 918 if (currentKey == '0'){ 919 resetFunc(); 920 } 921 if (0 != motorIsMoving){ 922 // do not execute keyboard commands 923 }else{ 924 if ((currentKey >= 49) && (currentKey <= 57)){ 925 //if (currentKey == '8'){ wheelMoveFullCircleChrDir('R'); } 926 if ((currentKey - 48) > WHEEL_FILTERCOUNT){ 927 //invalid filter N position, zero already handled 928 return ; 929 } 930 if (1 == wheelNamesToggleStatus){ 931 wheelNamesToggle(); 932 } 933 if (1 == wheelNextKeyIsNSetter){ 934 wheelConsiderWeAreAtNPosition(currentKey - 48); 935 wheelStopAfter = 0; 936 motorStop(1); 937 }else{ 938 wheelGotoNPosition(currentKey - 48); 939 } 940 } 941 if (currentKey == '#'){ 942 if (1 == wheelNextKeyIsNSetter){ 943 wheelNextKeyIsNSetter = 0; 944 wheelDisplayNPosition(0); 945 }else{ 946 wheelNextKeyIsNSetter = 1; 947 lcd.setCursor(2,0); 948 lcd.print('?'); 949 } 950 }else{ 951 wheelNextKeyIsNSetter = 0; 952 } 953 if (currentKey == 'A'){ 954 wheelMoveALittle('L', 4); 955 } 956 if (currentKey == 'D'){ 957 wheelMoveALittle('R', 4); 958 } 959 if (currentKey == 'B'){ 960 wheelMoveALittle('L', 2); 961 } 962 if (currentKey == 'C'){ 963 wheelMoveALittle('R', 2); 964 } 965 } 966 } 967 968}
Downloadable files
Hand Controller Schematic
It's all modules, no discrete elements.
Hand Controller Schematic
Comments
Only logged in users can leave comments