/* * The Multiple servo controller with Serial controll * This code allows you to controll multiple servos at the same time adressing them by an integer number( 1 between 6), * and tell them to switch state (1 or 0) for open or closed, * using the Serial interface. * The serailEvent handling is borrowed and modified from Tom Igoe serial event example http://www.arduino.cc/en/Tutorial/SerialEvent * * http://fab.academany.org/2019/labs/waag/students/josephus-vanderbie//week17.html * made by Joey van der Bie * 2019-05-13 * * This code is based on the Sweep example by BARRAGAN This example code is in the public domain. modified 8 Nov 2013 by Scott Fitzgerald http://www.arduino.cc/en/Tutorial/Sweep */ //CHECK OR UPDATE THESE NUMBERS BEFORE UPLOADING!!!! int ARDUINO_NUMBER = 1; //range 1,2,3 or 4 (Arduino position in servo) int NUMBER_OF_SERVOS = 5; //number of servo's per Arduino; //CHECK OR UPDATE THESE NUMBERS BEFORE UPLOADING!!!! byte servoNumber = B0000000; byte servoState = B0000000; byte emptyValue = B1000000; //this is the empty value for our servoNumber and servoState veriables that allows us to check if it is not set. byte serialProcessBitMask = B00011111; byte endByte = B11111111; bool stringComplete = false; // whether the string is complete #include Servo servo1, servo2, servo3, servo4, servo5, servo6; // create servo object to control a servo // twelve servo objects can be created on most boards int pos = 0; // variable to store the servo position int delayTime = 5; // delay between servo steps int degreeSteps = 1; // steps to take between degrees int delayBetweenServos = 200; // delay between the movement of servos int SERVOSTATE_OPEN = 1; //indicator for communication via serial int SERVOSTATE_CLOSED = 0; //indicator for communication via serial //default positions (not normally used) int SERVOSTATE_OPEN_POSITION = 2;//degrees position for open int SERVOSTATE_CLOSED_POSITION = 95;// degrees position for closed //The servo structure struct ServoStruct { unsigned int servoNumber:5; // the number we addres from our serial communication, the :5 is the number of bits used unsigned int pinNumber:4; // the pin it is connected to, the :4 is the number of bits int currentPosition; // current position in degrees Servo servoObject; // the actual object int OPEN_POSITION; // open position (anything between 0 and 180) int CLOSED_POSITION;// closed position (anything between 0 and 180) }; struct ServoStruct ss1, ss2, ss3, ss4, ss5, ss6; void setup() { Serial.begin(9600); ss1.servoNumber = (ARDUINO_NUMBER-1)*NUMBER_OF_SERVOS + 1; ss1.pinNumber = 3; ss1.currentPosition = 0; ss1.OPEN_POSITION = SERVOSTATE_OPEN_POSITION; ss1.CLOSED_POSITION = SERVOSTATE_CLOSED_POSITION; ss1.servoObject = servo1; ss1.servoObject.attach(ss1.pinNumber); ss1.servoObject.write(ss1.OPEN_POSITION); // move the servo to its start position ss2.servoNumber = (ARDUINO_NUMBER-1)*NUMBER_OF_SERVOS + 2; ss2.pinNumber = 5; ss2.currentPosition = 0; ss2.OPEN_POSITION = SERVOSTATE_OPEN_POSITION; ss2.CLOSED_POSITION = SERVOSTATE_CLOSED_POSITION; ss2.servoObject = servo2; ss2.servoObject.attach(ss2.pinNumber); ss2.servoObject.write(ss2.OPEN_POSITION); ss3.servoNumber = (ARDUINO_NUMBER-1)*NUMBER_OF_SERVOS + 3; ss3.pinNumber = 6; ss3.currentPosition = 0; ss3.OPEN_POSITION = SERVOSTATE_OPEN_POSITION; ss3.CLOSED_POSITION = SERVOSTATE_CLOSED_POSITION; ss3.servoObject = servo3; ss3.servoObject.attach(ss3.pinNumber); ss3.servoObject.write(ss3.OPEN_POSITION); ss4.servoNumber = (ARDUINO_NUMBER-1)*NUMBER_OF_SERVOS + 4; ss4.pinNumber = 10; ss4.currentPosition = 0; ss4.OPEN_POSITION = SERVOSTATE_OPEN_POSITION; ss4.CLOSED_POSITION = SERVOSTATE_CLOSED_POSITION; ss4.servoObject = servo4; ss4.servoObject.attach(ss4.pinNumber); ss4.servoObject.write(ss4.OPEN_POSITION); ss5.servoNumber = (ARDUINO_NUMBER-1)*NUMBER_OF_SERVOS + 5; ss5.pinNumber = 9; ss5.currentPosition = 0; ss6.OPEN_POSITION = SERVOSTATE_OPEN_POSITION; ss6.CLOSED_POSITION = SERVOSTATE_CLOSED_POSITION; ss5.servoObject = servo5; ss5.servoObject.attach(ss5.pinNumber); ss5.servoObject.write(ss5.OPEN_POSITION); ss6.servoNumber = (ARDUINO_NUMBER-1)*NUMBER_OF_SERVOS + 6; ss6.pinNumber = 11; ss6.currentPosition = 0; ss6.OPEN_POSITION = SERVOSTATE_OPEN_POSITION; ss6.CLOSED_POSITION = SERVOSTATE_CLOSED_POSITION; ss6.servoObject = servo6; ss6.servoObject.attach(ss6.pinNumber); ss6.servoObject.write(ss6.OPEN_POSITION); } void loop() { // servoToState(1,SERVOSTATE_CLOSED); // print the string when a newline arrives: if (stringComplete) { //Serial.print("number: "); //Serial.write((int)servoNumber); //Serial.println(""); //Serial.print("state: "); //Serial.write((int)servoState); servoToState((int)servoNumber, (int)servoState); resetSerialStorageValues(); } } void servoToState(int servoNr, int state){ if(state == SERVOSTATE_OPEN){ // state = SERVOSTATE_OPEN_POSITION; }else if(state == SERVOSTATE_CLOSED){ // state = SERVOSTATE_CLOSED_POSITION; }else { //invalid state, stop the function //Serial.print("invalid state:"); //Serial.println(state, BIN); //Serial.println(SERVOSTATE_OPEN, BIN); //Serial.println(SERVOSTATE_CLOSED, BIN); return; } if(ss1.servoNumber == servoNr){ moveServo(&ss1, state?ss1.OPEN_POSITION:ss1.CLOSED_POSITION); }else if(ss2.servoNumber == servoNr){ moveServo(&ss2, state?ss2.OPEN_POSITION:ss2.CLOSED_POSITION); }else if(ss3.servoNumber == servoNr){ moveServo(&ss3, state?ss3.OPEN_POSITION:ss3.CLOSED_POSITION); }else if(ss4.servoNumber == servoNr){ moveServo(&ss4, state?ss4.OPEN_POSITION:ss4.CLOSED_POSITION); }else if(ss5.servoNumber == servoNr){ moveServo(&ss5, state?ss5.OPEN_POSITION:ss5.CLOSED_POSITION); }else if(ss6.servoNumber == servoNr){ moveServo(&ss6, state?ss6.OPEN_POSITION:ss6.CLOSED_POSITION); }else{ //Serial.print("No servos found for number:"); //Serial.println(servoNr, BIN); //Serial.println(ss1.servoNumber, BIN); //Serial.println(ss2.servoNumber, BIN); //Serial.println(ss3.servoNumber, BIN); //Serial.println(ss4.servoNumber, BIN); //Serial.println(ss5.servoNumber, BIN); //Serial.println(ss6.servoNumber, BIN); } } void moveServo(struct ServoStruct *servo, int newPosition){ //Serial.print("Moving servo"); //Serial.println(servo->servoNumber); if(servo->currentPosition < newPosition){ for (pos = servo->currentPosition; pos <= newPosition; pos += degreeSteps) { // goes from 0 degrees to 180 degrees servo->servoObject.write(pos); delay(delayTime); // waits 15ms for the servo to reach the position } }else{ for (pos = servo->currentPosition; pos >= newPosition; pos -= degreeSteps) { // goes from 0 degrees to 180 degrees servo->servoObject.write(pos); delay(delayTime); // waits 15ms for the servo to reach the position } } servo->currentPosition = newPosition; } /* SerialEvent occurs whenever a new data comes in the hardware serial RX. This routine is run between each time loop() runs, so using delay inside loop can delay response. Multiple bytes of data may be available. */ void serialEvent() { while (Serial.available()) { byte incommmingByte = Serial.read(); if (incommmingByte == endByte) { if(servoNumber == emptyValue || servoState == emptyValue){ //we have missed a crucial value, reset our ledger. resetSerialStorageValues(); }else{ //everything checks out, lets process the command stringComplete = true; } }else if(servoNumber == emptyValue){ servoNumber = serialProcessBitMask & incommmingByte; }else if(servoState == emptyValue){ //maks the incomming byte and limit it to one bit (0 or 1); servoState = serialProcessBitMask & incommmingByte; }else{ //something went wrong //continue by storing the values, but move them up a place servoNumber = servoState; servoState = incommmingByte; } } } void resetSerialStorageValues(){ stringComplete = false; servoNumber = emptyValue; servoState = emptyValue; }