tripishadow

control servos

Nov 29th, 2021
54
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.   This code runs vixen through the arduino, usining pins 3, 5, and 6 with
  3.   3 seperate servos; pins 9, 10, and 11 are used for 3 LED circuits with PWM;
  4.   pins 12, 13 are extra digital pins.
  5.  
  6.   Adapted from code by GSRVAhiker17, zparticle, victor_pv, Si_champion, and Neil Tapp.
  7. */
  8.  
  9. #include <Servo.h>    // Servos
  10. #include <avr/wdt.h>  // Raw AVR watchdog timer
  11.  
  12. // Testing mode (treat servos as simple PWM)
  13. const bool TESTINGMODE = false;
  14.  
  15. // Vixen header (identifies a light sequence)
  16. const int HEADER_LEN = 2;
  17. const char seqHeader[] = {'~','!'};
  18.  
  19. // Timeout waiting for serial input before going to random mode (in milliseconds).
  20. const int TIME_OUT = 1000;
  21.  
  22. // Channels mapped to pin numbers
  23. const int PUMPKIN1_MOUTH = 9;
  24. const int PUMPKIN2_MOUTH = 10;
  25. const int PUMPKIN3_MOUTH = 11;
  26. const int PUMPKIN1_EYES  = 3;
  27. const int PUMPKIN2_EYES = 5;
  28. const int PUMPKIN3_EYES = 6;
  29. const int LIGHTS1 = 12;  
  30. const int LIGHTS2 = 13;  
  31. const int CHAN9 = 2;
  32. const int CHAN10 = 4;
  33. const int CHAN11 = 5;
  34. const int CHAN12 = 7;
  35. const int CHAN13 = A0;
  36. const int CHAN14 = A1;
  37. const int CHAN15 = A2;
  38. const int CHAN16 = A3;
  39. const int CHAN17 = A4;
  40. const int CHAN18 = A5;
  41.  
  42. // List of active channels
  43. const int channels[] = {PUMPKIN1_MOUTH, PUMPKIN2_MOUTH, PUMPKIN3_MOUTH,
  44.                         PUMPKIN1_EYES, PUMPKIN2_EYES, PUMPKIN3_EYES, LIGHTS1, LIGHTS2,
  45.                         CHAN9, CHAN10, CHAN11, CHAN12, CHAN13, CHAN14, CHAN15, CHAN16,
  46.                         CHAN17, CHAN18
  47.                        };
  48.  
  49. // Number of active channels
  50. const int NUM_ACTIVE_CHANNELS = 8;
  51.  
  52. // PWM map
  53. const int isPWM[] = {true, true, true, true, true, true, false, false, false, false,
  54.                      false, false, false, false, false, false, false, false
  55.                     };
  56.  
  57. // Servos
  58. const int SERVO_DELAY = 15; // delay after servo is activated (allow it to move)
  59. const int NUM_SERVOS = 3;
  60. const int NEUTRAL = 90;  // Neutral position
  61. Servo servos[NUM_SERVOS];
  62.  
  63. // Min servo opening in degrees from neutral position
  64. const int servoMin[] = {0, 0, 0};
  65.  
  66. // Max servo opening in degrees from neutral position
  67. const int servoMax[] = {35, 45, 45};
  68. //const int servoMax[] = {20, 15, 15};
  69.  
  70. // Servo channel map
  71. const int NO_SERVO = -1;
  72. const int servoNumber[] = {0, 1, 2, NO_SERVO, NO_SERVO, NO_SERVO, NO_SERVO, NO_SERVO,
  73.                         NO_SERVO, NO_SERVO, NO_SERVO, NO_SERVO, NO_SERVO, NO_SERVO, NO_SERVO, NO_SERVO,
  74.                         NO_SERVO, NO_SERVO
  75.                        };
  76.                        
  77. // Servo direction
  78. const int CLOCKWISE = 1;
  79. const int COUNTERCLOCKWISE = -1;
  80. const int servoDirection[] = {COUNTERCLOCKWISE, CLOCKWISE, CLOCKWISE};
  81.  
  82. // Serial
  83. const long COM_SPEED = 115200;
  84. int incomingByte[NUM_ACTIVE_CHANNELS];  // array to store the channel values from the serial port
  85.  
  86. // Misc
  87. int i = 0;                              // Loop counter
  88. int j = 0;                              // Loop counter
  89. volatile unsigned long  timer_a = 0;    // Timer
  90.  
  91.  
  92. //setup the pins/ inputs & outputs
  93. void setup()
  94. {
  95.   // enable the watchdog timer with a time of 1 second. If the board freezes, it will reset itself after 1 second.
  96.   wdt_enable(WDTO_1S);
  97.  
  98.   // specifically for the UNO
  99.   sei();
  100.  
  101.   // initalize PWM Channels / Pins
  102.   for (i = 0; i < NUM_ACTIVE_CHANNELS; i++) {
  103.     pinMode(channels[i], OUTPUT);
  104.     if ((servoNumber[i] != NO_SERVO) && !TESTINGMODE) {
  105.       servos[servoNumber[i]].attach(channels[i]);
  106.     }
  107.   }
  108.  
  109.   // set all the channels off to begin
  110.   for (i = 0; i < NUM_ACTIVE_CHANNELS; i++) {
  111.     digitalWrite(channels[i], LOW);
  112.     if ((servoNumber[i] != NO_SERVO) && !TESTINGMODE) {
  113.       servos[servoNumber[i]].write(NEUTRAL);
  114.     }
  115.   }
  116.  
  117.   test_sequence(); // brief test
  118.   Serial.begin(COM_SPEED);   // set up Serial
  119. }
  120.  
  121. void loop()
  122. {
  123.   if (Serial.available() >= NUM_ACTIVE_CHANNELS + HEADER_LEN) {
  124.     wdt_reset(); // resets the watchdog (prevents board lockup)
  125.     timer_a = millis ();  // Mark the time when a message was received
  126.  
  127.     // read the header to verify this is in fact a light sequence
  128.     // probably overkill, but borrowing from the above sources...
  129.     for (int i = 0; i < HEADER_LEN; i++) {
  130.       if (seqHeader[i] != Serial.read()) { return; }
  131.       //Serial.read();
  132.     }
  133.    
  134.     // read the oldest byte in the serial buffer:
  135.     for (int i = 0; i < NUM_ACTIVE_CHANNELS; i++) {
  136.       // read each byte
  137.       incomingByte[i] = Serial.read();
  138.  
  139.       if ((servoNumber[i] != NO_SERVO) && !TESTINGMODE) {
  140.         // SERVOS ------------------------------
  141.         int angle = map(incomingByte[i], 0, 255, servoMin[servoNumber[i]], servoMax[servoNumber[i]]);
  142.         angle *= servoDirection[servoNumber[i]];
  143.         servos[servoNumber[i]].write(NEUTRAL + angle);
  144.         delay(SERVO_DELAY);
  145.       } else if (isPWM[i]) {
  146.         // PWM ---------------------------------
  147.         analogWrite(channels[i], incomingByte[i]);
  148.       } else {
  149.         // DIGITAL (A2D) -----------------------
  150.         if (incomingByte[i] <= 127) {
  151.           digitalWrite(channels[i], LOW);
  152.         } else {
  153.           digitalWrite(channels[i], HIGH);
  154.         }
  155.       }
  156.     }
  157.  
  158.   } else {
  159.     // Random mode starts if no serial input has been received in TIME_OUT milliseconds
  160.     wdt_reset(); // resets the watchdog (prevents board lockup)
  161.     unsigned long diff = millis() - timer_a;
  162.     if (diff >= TIME_OUT) {
  163.       timer_a = millis ();
  164.       int random_a = 0;
  165.       for (i = 0; i < NUM_ACTIVE_CHANNELS; i++) {
  166.         if ((servoNumber[i] != NO_SERVO) && !TESTINGMODE) continue;
  167.         random_a = random(0, 2);
  168.         if (random_a == 0) {
  169.           digitalWrite(channels[i], LOW);
  170.         } else {
  171.           digitalWrite(channels[i], HIGH);
  172.         }
  173.       }
  174.     }
  175.   }
  176. }
  177.  
  178. // Test the setup briefly
  179. void test_sequence() {
  180.   for (i = 0; i < NUM_ACTIVE_CHANNELS; i++) {
  181.     wdt_reset(); // resets the watchdog
  182.     digitalWrite(channels[i], HIGH);
  183.     delay (500);
  184.     digitalWrite(channels[i], LOW);
  185.   }
  186. }
Add Comment
Please, Sign In to add comment