Untitled

mail@pastecode.io avatar
unknown
plain_text
a year ago
51 kB
2
Indexable
Never
//CAMTRACK

#include <SPI.h>                                                                //Import libraries to control the OLED display
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <math.h>

#define SCREEN_WIDTH 128                                                        
#define SCREEN_HEIGHT 64                                                        // OLED Dimension in pixels
#define OLED_RESET -1                                                           // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);       // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)

const unsigned char logo [] PROGMEM = {    

  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x55, 0x55, 0x55, 0x55, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xe3, 0x80, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x01, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xe7, 0x80, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x01, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xe3, 0x80, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x01, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xe3, 0x80, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xb3, 0xff, 0xff, 0xff, 0xff, 0xeb, 0x08, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x0d, 0x77, 0xff, 0xff, 0xff, 0xff, 0xee, 0xb0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x07, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xe0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x07, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xf0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x07, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xe0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x07, 0x87, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xe0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x03, 0x13, 0xff, 0xff, 0xff, 0xff, 0xe4, 0xe0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x01, 0xb7, 0xff, 0xff, 0xff, 0xff, 0xed, 0x80, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x1d, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xb8, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x0e, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xe7, 0x70, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x0f, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xf0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x0f, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xf0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x07, 0xcb, 0xff, 0xff, 0xff, 0xff, 0xeb, 0xe0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x03, 0x33, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xe0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xb3, 0xff, 0xff, 0xff, 0xff, 0xce, 0x80, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x01, 0x71, 0xff, 0xff, 0xff, 0xff, 0xce, 0x80, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x0d, 0xf1, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xb0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x07, 0x71, 0xff, 0xff, 0xff, 0xff, 0x8e, 0xf0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x87, 0xe0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x03, 0xec, 0xff, 0xff, 0xff, 0xff, 0x37, 0xc0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x03, 0xec, 0x7f, 0xff, 0xff, 0xff, 0x37, 0xc0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7f, 0xff, 0xff, 0xfe, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x3f, 0xff, 0xff, 0xfe, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x03, 0xdc, 0x3f, 0xff, 0xff, 0xfc, 0x3b, 0xc0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x9f, 0xff, 0xff, 0xf9, 0xbf, 0xc0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0x8f, 0xff, 0xff, 0xf9, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x8f, 0xff, 0xff, 0xf1, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0xc7, 0xff, 0xff, 0xe3, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc3, 0xff, 0xff, 0xc1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0xc9, 0xff, 0xff, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xd8, 0xff, 0xff, 0x19, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x9c, 0x7f, 0xfe, 0x39, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0xfc, 0x3f, 0xfc, 0x3f, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x01, 0xc3, 0xfe, 0x0f, 0xf8, 0x3f, 0xc3, 0x80, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x1e, 0x07, 0xf0, 0x38, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x0f, 0xe1, 0xfc, 0x03, 0xc0, 0x3f, 0x87, 0xf0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0xfc, 0x00, 0x80, 0x3f, 0x9f, 0xe0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x07, 0xfc, 0x7d, 0x00, 0x00, 0xbe, 0x3f, 0xe0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0x3f, 0x00, 0x00, 0x7d, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x17, 0xff, 0x84, 0x80, 0x01, 0x53, 0xff, 0xd0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xc0, 0x54, 0x15, 0x03, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xc0, 0x0a, 0xa8, 0x03, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x80, 0x03, 0xc0, 0x01, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x06, 0x60, 0x01, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x07, 0xfe, 0x00, 0x0c, 0x30, 0x00, 0x7f, 0xe0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x18, 0x18, 0x00, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x80, 0x10, 0x08, 0x03, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xe0, 0x00, 0x00, 0x07, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf8, 0x00, 0x00, 0x3f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x80, 0x02, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xfa, 0xbf, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};   // 'LPU LOGO', 128x64px

#define MAX_DATA_SIZE 12
#define minTravDist 25                      //Define travel distance initial setting, minimum, maximum and increment
#define maxTravDist 475
#define travDistInc 25
#define initialDur 120                      //Define duration initial setting, minimum, maximum and increment
#define minDur 10
#define maxDur 1800
#define durInc 5
#define initialRotAng 180                   //Define rotation initial setting, minimum, maximum and increment
#define minRotAng 20
#define maxRotAng 360
#define rotAngInc 10
#define initialObjDist 200                  //Define object distance initial setting, minimum, maximum and increment
#define minObjDist 150
#define maxObjDist 5000
#define objInc 50
#define minInterval 400                     //Minimum interval time between pulses in microseconds

static int pinA = 2;                        //Hardware interrupt digital pin 2
static int pinB = 3;                        //Hardware interrupt digital pin 3
volatile byte aFlag = 0;                    //Rising edge on pinA to signal that the encoder has arrived at a detent
volatile byte bFlag = 0;                    //Rising edge on pinB to signal that the encoder has arrived at a detent (opposite direction to when aFlag is set)
volatile int encoderPos = 0;                //Current value of encoder position, contained between limits below
volatile int prevEncoderPos = 0;            //To track whether the encoder has been turned and the display needs to update
volatile byte reading = 0;                  //Stores direct value from interrupt pin
#define encButton 4                         //Define encoder pushbutton pin
byte oldButtonState = HIGH;                 //First button state is open because of pull-up resistor
const unsigned long debounceTime = 10;      //Debounce delay time
unsigned long buttonPressTime;              //Time button has been pressed for debounce

int encLowLim = 0;                          //Variables to store the encoder limits and increment
int encHighLim = 4;                         //PB Encoder limit raised to enable extra menu item
int encIncrement = 1;
int dataInputNo = 0;
int modeSelected = 0;                       //Current operating mode (Pan, Rotate, Pan & Rotate, Track Object)

#define enablePin 5                         //Define motor enable pin
#define travDirPin 6                        //Define travel & rotation stepper motor pins
#define travStepPin 7
#define rotDirPin 8
#define rotStepPin 9
#define leftlimit 10                        //Define left limit switches
#define rightlimit 11                       //Define right  limit switches

float travDist = maxTravDist;               //Distance to travel in mm
float travTime = initialDur;                //Travel time to cover the distance
float objDist = initialObjDist;             //Distance of tracked object from slider in millimeters
int travelDir = 0;                          //Deifne initial travel and rotation directions
int rotDir = 0;
int rotAngle = 180;                         //Angle to rotate camera around axis

float pulsesPerMM = 50;                     //Number of motor pulses for 1mm travel
float pulsesPerDeg = 4.4444;                //Number of motor pulses for 1 degree of rotation
float currentDist = 0;
float currentAngle = 0;

int camLeft;
int camRight;
int gantryLeft;
int gantryRight; 
int mode;
int AtravDist;
int AtravDir;
int AtravDur;
int ArotDeg;
int ArotDir;
int ArotDur;

int dataArray[11];
int dataIndex = 0;

void setup() 
{
                             //Start serial communication for debugging
  
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C))          //Connect to the OLED display
  {
    for(;;);                                              //Don't proceed, loop forever
  }
  pinMode(pinA, INPUT_PULLUP);                            //Set pinA as an input, pulled HIGH to the logic voltage
  pinMode(pinB, INPUT_PULLUP);                            //Set pinB as an input, pulled HIGH to the logic voltage
  pinMode(leftlimit, INPUT_PULLUP);
  pinMode(rightlimit, INPUT_PULLUP);                      
  attachInterrupt(0,PinA,RISING);                         //Set an interrupt on PinA
  attachInterrupt(1,PinB,RISING);                         //Set an interrupt on PinB
  pinMode (encButton, INPUT_PULLUP);                      //Set the encoder button as an input, pulled HIGH to the logic voltage
  pinMode(enablePin, INPUT);                              //Open circuit enable pin, disables motors
  pinMode(travDirPin, OUTPUT);                            //Define the travel stepper motor pins
  pinMode(travStepPin, OUTPUT);
  pinMode(rotDirPin, OUTPUT);                             //Define the rotation stepper motor pins
  pinMode(rotStepPin, OUTPUT);
  digitalWrite(travDirPin, HIGH);                         //Set the initial direction of motion for both motors
  digitalWrite(rotDirPin, HIGH);

  display.clearDisplay();                                 //Clear the display
  display.setTextColor(SSD1306_WHITE);                    //Set the text colour to white
  display.drawBitmap(0, 0, logo, 128, 64, WHITE);         //Display bitmap from array
  display.display();                                      
  delay(2000);
  display.clearDisplay();                                 //Clear display

  if(!digitalRead(leftlimit))            
  if(!digitalRead(rightlimit))
  {

  }
  
 
}

void loop() 
{  
   Wire.begin(8);  // Arduino address
  Wire.onReceive(receiveEvent);    
  encLowLim = 0;                                            //Mode selection menu, 4 modes
  encHighLim = 3;
  encIncrement = 1;
  updateMainMenu();
  
  boolean confirmed = false;                                //Both used to confirm button push to select mode
  boolean pressed = false;
  encoderPos = 0;                                           //Encoder starts from 0, first menu option
  while(!confirmed)                                         //While the user has not confirmed the selection
  {
    byte buttonState = digitalRead (encButton); 
    if (buttonState != oldButtonState)
    {
      if (millis () - buttonPressTime >= debounceTime)      //Debounce button
      {
        buttonPressTime = millis ();                        //Time when button was pushed
        oldButtonState =  buttonState;                      //Remember button state for next time
        if (buttonState == LOW)
        {
          modeSelected = encoderPos;                        //If the button is pressed, accept the current digit into the guessed code
          pressed = true;
        }
        else 
        {
          if (pressed == true)                              //Confirm the input once the button is released again
          {
            confirmed = true;
          }
        }  
      }
    }
    if(encoderPos!=prevEncoderPos)                          //Update the display if the encoder position has changed
    {
      updateMainMenu();
      prevEncoderPos=encoderPos;
    }
  }
  if (modeSelected == 0)                                    //Run required mode function depending on selection
    runPan();
  else if (modeSelected == 1)
    runRotate ();
  else if (modeSelected == 2)
    runPanAndRotate ();
  else
    homeslider ();


switch (mode)
  {
      case 0:                                    //manual control of the gantry and rotation of camera
      if (gantryLeft == 1){                 //moves the gantry to the LEFT 
         digitalWrite(travDirPin, LOW);
            for (int j=1; j<100; j++)  
                  {
                  digitalWrite(travStepPin, HIGH);
                  delayMicroseconds(1000);
                  digitalWrite(travStepPin, LOW);
                  delayMicroseconds(1000);
                 } 
         }
      if (gantryRight == 1){                   //moves the gantry to the RIGHT   
          digitalWrite(travDirPin, HIGH);
            for (int j=1; j<100; j++)  
              {
              digitalWrite(travStepPin, HIGH);
              delayMicroseconds(1000);
              digitalWrite(travStepPin, LOW);
              delayMicroseconds(1000); 
              }
         }
      if (camLeft == 1){                      //rotate camera 10 degrees to the left
          digitalWrite(rotDirPin, LOW);
          for (int i=1; i<=444.44; i++)                 
                  {
                  digitalWrite(rotStepPin, HIGH);
                  delay(1000);
                  digitalWrite(rotStepPin, LOW);
                  delay(1000);
                  }
      }

      if (camRight == 1){                   //rotate camera 10 degrees to the right
          digitalWrite(rotDirPin, HIGH);
          for (int i=1; i<=444.44; i++)                 
                  {
                  digitalWrite(rotStepPin, HIGH);
                  delay(1000);
                  digitalWrite(rotStepPin, LOW);
                  delay(1000);
                  }
      }
      break;

    case 1:
    displayStart (); 
    display.setCursor(55,30);
    display.print(F("Pan"));
    display.display();
    if (AtravDir == 1)                                   //Set motor travel direction
        digitalWrite(travDirPin, LOW);
      else
        digitalWrite(travDirPin, HIGH);
    int travelP = AtravDist*pulsesPerMM;
    float interA = AtravDur*1000000/travelP;

    for (int i=1; i<=travelP; i++)                   //Pulse the motor to move the required distance in the required time
  {
      if (digitalRead(leftlimit) == true && digitalRead(rightlimit) == true ){   //limit switches not reached
        digitalWrite(travStepPin, HIGH);
        delayMicroseconds(interA/2);
        digitalWrite(travStepPin, LOW);
        delayMicroseconds(interA/2);
      }
      else {
        display.setCursor(28,4);
        display.print(F("Limit Reached"));
        display.display();
        if (travelDir == 0)                                   //Set motor travel direction
          digitalWrite(travDirPin, HIGH);
        else
          digitalWrite(travDirPin, LOW);
        for (int j=1; j<100; j++)  
        {
         digitalWrite(travStepPin, HIGH);
         delayMicroseconds(interA/2);
         digitalWrite(travStepPin, LOW);
         delayMicroseconds(interA/2); 
        }
        }
        }  
    displayEnd();
    break;

  case 2:
      displayStart ();                                      //Display startup sequence and enable motors
      display.setCursor(49,30);
      display.print(F("Rotate"));
      display.display();

      if (ArotDir == 0)                                      //Set motor travel direction
        digitalWrite(rotDirPin, HIGH);
      else
        digitalWrite(rotDirPin, LOW);
      int rotationP = ArotDeg*pulsesPerDeg;           //Calculate the number of motor pulses required to rotate the required angle
    float interv = ArotDur*1000/rotationP;
    for (int i=1; i<=rotationP; i++)            //Pulse the motor to rotate the required angle in the required time
  {
      digitalWrite(rotStepPin, HIGH);
      delay(interv/2);
      digitalWrite(rotStepPin, LOW);
      delay(interv/2);
  }
  displayEnd();    

    case 3:
      displayStart ();                                            //Display startup sequence and enable motors
      display.setCursor(30,30);
      display.print(F("Pan & Rotate"));
      display.display();

      if (AtravDir == 0)                                           //Set motor travel direction
            digitalWrite(travDirPin, LOW);          else
            digitalWrite(travDirPin, HIGH);
      if (ArotDir == 0)                                            //Set motor travel direction
            digitalWrite(rotDirPin, HIGH);
          else
            digitalWrite(rotDirPin, LOW);

      int travelPs = AtravDist*pulsesPerMM;
      float interc = AtravDur*1000000/travelP;
      int rotationPs = ArotDeg*pulsesPerDeg;           //Calculate the number of motor pulses required to rotate the required angle
      int travelPerRotation = travelPs/rotationPs;


      for (int i=1; i<=travelP; i++)
      {
        if (digitalRead(leftlimit) == true && digitalRead(rightlimit) == true )
        {                                                                           //limit switches not reached
            digitalWrite(travStepPin, HIGH);
            int checkRotate = i % travelPerRotation;                                //Check if a rotation step must be made
          if (checkRotate == 0)
            digitalWrite(rotStepPin, HIGH);
            delayMicroseconds(interc/2);
            digitalWrite(travStepPin, LOW);

      if (checkRotate == 0)
            digitalWrite(rotStepPin, LOW);
            delayMicroseconds(interc/2);
      }

      else {
        display.setCursor(28,4);
        display.print(F("Limit Reached"));
        display.display();
        if (travelDir == 0)                                   //Set motor travel direction
          digitalWrite(travDirPin, HIGH);
        else
          digitalWrite(travDirPin, LOW);
        for (int j=1; j<100; j++)  
        {
         digitalWrite(travStepPin, HIGH);
         delayMicroseconds(interc/2);
         digitalWrite(travStepPin, LOW);
         delayMicroseconds(interc/2); 
        }

  }
  }
  break;
  }
  
  

  

}

void PinA()                                             //Rotary encoder interrupt service routine for one encoder pin
{
  cli();                                                //Stop interrupts happening before we read pin values
  reading = PIND & 0xC;                                 //Read all eight pin values then strip away all but pinA and pinB's values
  if(reading == B00001100 && aFlag)                     //Check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
  {     
    if(encoderPos<=(encHighLim-encIncrement))
      encoderPos = encoderPos+encIncrement;             //Increment the encoder's position count , only when below upper limit
    else
      encoderPos = encHighLim;                          //Stop at maximum, being upper limit
    bFlag = 0;                                          //Reset flags for the next turn
    aFlag = 0;                                          //Reset flags for the next turn
  }
  else if (reading == B00000100)                        //Signal that we're expecting pinB to signal the transition to detent from free rotation
    bFlag = 1;
  sei();                                                //Restart interrupts
}

void PinB()                                             //Rotary encoder interrupt service routine for the other encoder pin
{
  cli();                                                //Stop interrupts happening before we read pin values
  reading = PIND & 0xC;                                 //Read all eight pin values then strip away all but pinA and pinB's values
  if (reading == B00001100 && bFlag)                    //Check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
  {
    if(encoderPos>=(encLowLim+encIncrement))
      encoderPos = encoderPos-encIncrement;             //Decrement the encoder's position count, only when above lower limit
    else
      encoderPos = encLowLim;                           //Stop at minimum, being lower limit
    bFlag = 0;                                          //Reset flags for the next turn
    aFlag = 0;                                          //Reset flags for the next turn
  }
  else if (reading == B00001000)                        //Signal that we're expecting pinA to signal the transition to detent from free rotation
    aFlag = 1;
  sei();                                                //Restart interrupts
}

void updateMainMenu()                                   //Updates the display data for the main menu
{
  display.clearDisplay();                               //Clear display
  display.setTextSize(1);                               //Set the text size
  display.setCursor(28,4);
  display.print(F("Camera Slider"));
  display.setCursor(25,15);                             //Set the display cursor position
  display.print(F("Pan"));                              //Set the display text
  display.setCursor(25,25);
  display.print(F("Rotate"));
  display.setCursor(25,35);
  display.print(F("Pan & Rotate"));
  display.setCursor(25,45);
  display.print(F("Home Slider"));
  int selected = 0;                                     //Stores cursor vertical position to show selected item
  if (encoderPos == 0)
    selected = 15;
  else if (encoderPos == 1)
    selected = 25;
  else if (encoderPos == 2)
    selected = 35;
  else if (encoderPos == 3)
    selected = 45;

  display.setCursor(14,selected);                       //Set the display cursor position
  display.print(F(">"));
  display.display();                                    //Output the display text
}

void homeslider ()                                      //Runs the pan mode sequence
{
 
  displayStart ();                                      //Display startup sequence and enable motors
  display.setCursor(35,30);
  display.print(F("Homing Slider"));
  display.display();
                                                        //Set motor travel direction
                                                        // digitalWrite(travDirPin, LOW);
  
  digitalWrite(travDirPin, HIGH);
  int travelPulses = 25000;               
  float interval = 380;         
   
  for (int i=1; i<=travelPulses; i++)                   //Pulse the motor to move the required distance in the required time
  {
      if (digitalRead(leftlimit) == true && digitalRead(rightlimit) == true ){   //limit switches not reached
      digitalWrite(travStepPin, HIGH);
      delayMicroseconds(interval/2);
      digitalWrite(travStepPin, LOW);
      delayMicroseconds(interval/2);
      }
      else {
        display.setCursor(28,4);
        display.print(F("Limit Reached"));
        display.display();
          digitalWrite(travDirPin, LOW);
        for (int j=1; j<100; j++)  
        {
         digitalWrite(travStepPin, HIGH);
         delayMicroseconds(interval/2);
         digitalWrite(travStepPin, LOW);
         delayMicroseconds(interval/2); 
        }
        break;
      }
  }  
  displayEnd();  
                                         //Display the end sequence and disable motors
}


void runPan ()                                          //Runs the pan mode sequence
{
  inputPanData ();                                      //Get user inputs for pan movement
  displayStart ();                                      //Display startup sequence and enable motors
  display.setCursor(55,30);
  display.print(F("Pan"));
  display.display();
  if (travelDir == 0)                                   //Set motor travel direction
    digitalWrite(travDirPin, LOW);
  else
    digitalWrite(travDirPin, HIGH);
  int travelPulses = calcTravelPulses ();               //Calculate the number of motor pulses required to move the travel distance
  float interval = calcInterval (travelPulses);         //Calculate the pulse interval required to move the required distance in the required time

  
  
  for (int i=1; i<=travelPulses; i++)                   //Pulse the motor to move the required distance in the required time
  {
      if (digitalRead(leftlimit) == true && digitalRead(rightlimit) == true ){   //limit switches not reached
      digitalWrite(travStepPin, HIGH);
      delayMicroseconds(interval/2);
      digitalWrite(travStepPin, LOW);
      delayMicroseconds(interval/2);
      }
      else {
        display.setCursor(28,4);
        display.print(F("Limit Reached"));
        display.display();
        //delay(2000);
        if (travelDir == 0)                                   //Set motor travel direction
          digitalWrite(travDirPin, HIGH);
        else
          digitalWrite(travDirPin, LOW);
        for (int j=1; j<100; j++)  
        {
         digitalWrite(travStepPin, HIGH);
         delayMicroseconds(interval/2);
         digitalWrite(travStepPin, LOW);
         delayMicroseconds(interval/2); 
        }
        break;
      }
  }  
  displayEnd();  
                                         //Display the end sequence and disable motors
}

void runRotate ()                                       //Runs the rotate mode sequence
{
  inputRotateData ();                                   //Get user inputs for pan movement
  displayStart ();                                      //Display startup sequence and enable motors
  display.setCursor(49,30);
  display.print(F("Rotate"));
  display.display();
  if (rotDir == 0)                                      //Set motor travel direction
    digitalWrite(rotDirPin, HIGH);
  else
    digitalWrite(rotDirPin, LOW);
  int rotationPulses = calcRotationPulses ();           //Calculate the number of motor pulses required to rotate the required angle
  float interval = calcRotInterval (rotationPulses);       //Calculate the pulse interval required to rotate in the required time

  for (int i=1; i<=rotationPulses; i++)                 //Pulse the motor to rotate the required angle in the required time
  {
      digitalWrite(rotStepPin, HIGH);
      delay(interval/2);
      digitalWrite(rotStepPin, LOW);
      delay(interval/2);
  }
  displayEnd();                                         //Display the end sequence and disable motors
}

void runPanAndRotate ()                                       //Runs the pan and rotate mode sequence
{
  inputPanAndRotateData ();                                   //Get user inputs for pan movement
  displayStart ();                                            //Display startup sequence and enable motors
  display.setCursor(30,30);
  display.print(F("Pan & Rotate"));
  display.display();
  if (travelDir == 0)                                         //Set motor travel direction
    digitalWrite(travDirPin, LOW);
  else
    digitalWrite(travDirPin, HIGH);
  if (rotDir == 0)                                            //Set motor travel direction
    digitalWrite(rotDirPin, HIGH);
  else
    digitalWrite(rotDirPin, LOW);
  int travelPulses = calcTravelPulses ();                     //Calculate the number of motor pulses required to move the travel distance

  float interval = calcInterval (travelPulses);               //Calculate the pulse interval required to move the required distance in the required time

  int rotationPulses = calcRotationPulses ();                 //Calculate the number of motor pulses required to rotate the required angle
  int travelPerRotation = travelPulses/rotationPulses;        //Calculate how much the camera should pan for each rotation step
  
  
  for (int i=1; i<=travelPulses; i++)
  {
     if (digitalRead(leftlimit) == true && digitalRead(rightlimit) == true ){   //limit switches not reached
     
      digitalWrite(travStepPin, HIGH);
      int checkRotate = i % travelPerRotation;                //Check if a rotation step must be made
      if (checkRotate == 0)
        digitalWrite(rotStepPin, HIGH);
      delayMicroseconds(interval/2);
      digitalWrite(travStepPin, LOW);
      if (checkRotate == 0)
        digitalWrite(rotStepPin, LOW);
      delayMicroseconds(interval/2);
      }else {
        display.setCursor(28,4);
        display.print(F("Limit Reached"));
        display.display();
        //delay(2000);
        if (travelDir == 0)                                   //Set motor travel direction
          digitalWrite(travDirPin, HIGH);
        else
          digitalWrite(travDirPin, LOW);
        for (int j=1; j<100; j++)  
        {
         digitalWrite(travStepPin, HIGH);
         delayMicroseconds(interval/2);
         digitalWrite(travStepPin, LOW);
         delayMicroseconds(interval/2); 
        }
        break;
      /*currentDist = i/pulsesPerMM;
      currentAngle = i/pulsesPerDeg;
      Serial.print("Dist: ");
      Serial.println(currentDist);
      Serial.print("Angle: ");
      Serial.println(currentAngle);*/
      }
  }
   displayEnd();                                                 //Display the end sequence and disable motors
}


void displayStart()
{
  display.clearDisplay();                                   //Clear display
  display.setTextSize(1);                                   //Set the text size
  display.setCursor(45,20);                                 //Set the display cursor position
  display.print(F("Push To"));                              //Set the display text
  display.setCursor(50,32);
  display.print(F("Start"));
  display.display();                                        //Output the display text
  boolean confirmed = false;                                //Both used to confirm button push to select mode
  boolean pressed = false;
  while(!confirmed)                                         //While the user has not started the panning routine
  {
    byte buttonState = digitalRead (encButton); 
    if (buttonState != oldButtonState)
    {
      if (millis () - buttonPressTime >= debounceTime)      //Debounce button
      {
        buttonPressTime = millis ();                        //Time when button was pushed
        oldButtonState =  buttonState;                      //Remember button state for next time
        if (buttonState == LOW)
        {
          pressed = true;
        }
        else 
        {
          if (pressed == true)                              //Confirm the input once the button is released again
          {
            confirmed = true;
          }
        }  
      }
    }
  }
  pinMode(enablePin, OUTPUT);                               //Enable the motors
  for(int i=3 ; i> 0 ; i--)                                 //Countdown to start
  {
    display.clearDisplay();                                 //Clear display
    display.setTextSize(2);                                 //Set the text size
    display.setCursor(60,20);                               //Set the display cursor position
    display.print(i);                                       //Set the display text
    display.display(); 
    delay(1000);
  }
  display.clearDisplay();                                   //Clear display
  display.setTextSize(1);                                   //Set the text size
  display.setCursor(45,15);                                 //Set the display cursor position
  display.print(F("Running"));                              //Set the display text
  display.display();
}

void displayEnd()
{
  display.clearDisplay();                                   //Clear display
  display.setTextSize(1);                                   //Set the text size
  display.setCursor(40,15);                                 //Set the display cursor position
  display.print(F("Complete"));                             //Set the display text
  display.setCursor(44,35);
  display.print(F("Push To"));
  display.setCursor(27,47);
  display.print(F("Release Motors"));
  display.display();                                        //Output the display text
  boolean confirmed = false;                                //Both used to confirm button push to select mode
  boolean pressed = false;
  while(!confirmed)                                         //While the user has not started the routine
  {
    byte buttonState = digitalRead (encButton); 
    if (buttonState != oldButtonState)
    {
      if (millis () - buttonPressTime >= debounceTime)      //Debounce button
      {
        buttonPressTime = millis ();                        //Time when button was pushed
        oldButtonState =  buttonState;                      //Remember button state for next time
        if (buttonState == LOW)
        {
          pressed = true;
        }
        else 
        {
          if (pressed == true)                              //Confirm the input once the button is released again
          {
            confirmed = true;
          }
        }  
      }
    }
  }
  pinMode(enablePin, INPUT);                                //Open circuit enable pin, disables motors
  resetVariables ();
}

void inputPanData ()                                                              //Input required data for pan mode
{
  dataInputNo = 0;                                                                //Input travel distance
  inputField (maxTravDist, minTravDist, maxTravDist, travDistInc);
  dataInputNo = 1;                                                                //Input travel direction
  inputField (0, 0, 1, 1);
  dataInputNo = 2;                                                                //Input travel duration
  inputField (initialDur, minDur, maxDur, durInc);
}

void inputRotateData ()                                                           //Input required data for rotate mode
{
  dataInputNo = 0;                                                                //Input rotation angle
  inputField (initialRotAng, minRotAng, maxRotAng, rotAngInc);
  dataInputNo = 1;                                                                //Input rotation direction
  inputField (0, 0, 1, 1);
  dataInputNo = 2;                                                                //Input rotation duration
  inputField (initialDur, minDur, maxDur, durInc);
}

void inputPanAndRotateData ()                                                     //Input required data for pan and rotate mode
{
  dataInputNo = 0;                                                                //Input pan distance
  inputField (maxTravDist, minTravDist, maxTravDist, travDistInc);
  dataInputNo = 1;                                                                //Input pan direction
  inputField (0, 0, 1, 1);
  dataInputNo = 2;                                                                //Input rotation angle
  inputField (initialRotAng, minRotAng, maxRotAng, rotAngInc);
  dataInputNo = 3;                                                                //Input rotation direction
  inputField (0, 0, 1, 1);
  dataInputNo = 4;                                                                //Input total duration
  inputField (initialDur, minDur, maxDur, durInc);
}

void inputTrackData ()                                                            //Input required data for object tracking mode
{
  dataInputNo = 0;                                                                //Input pan distance
  inputField (maxTravDist, minTravDist, maxTravDist, travDistInc);
  dataInputNo = 1;                                                                //Input pan direction
  inputField (0, 0, 1, 1);
  dataInputNo = 2;                                                                //Input rotation angle
  inputField (initialObjDist, minObjDist, maxObjDist, objInc);
  dataInputNo = 3;                                                                //Input total duration
  inputField (initialDur, minDur, maxDur, durInc);
}

void updatePanDataDisplay ()
{
  display.clearDisplay();                                   //Clear display
  display.setTextSize(1);                                   //Set the text size
  display.setCursor(2,10);                                  //Set the display cursor position
  display.print(F("Distance: "));                           //Set the display text
  display.setCursor(2,20);
  display.print(F("Direction: "));
  display.setCursor(2,30);
  display.print(F("Duration: "));
  int selected = 0;
  if (dataInputNo == 0)                                     //Get the cursor position & update changing variable
  {
    selected = 10;
    travDist = encoderPos;
  }
  else if (dataInputNo == 1)
  {
    selected = 20;
    travelDir = encoderPos;
  }
  else
  {
    selected = 30;
    travTime = encoderPos;
    if(calcInterval (calcTravelPulses ()) < minInterval)    //Flags movement too fast
    {
      display.setCursor(40,55);                             //Set the display cursor position
      display.print(F("Too Fast"));                         //Set the display text
    }
  }
  display.setCursor(65,selected);                           //Set the display cursor position
  display.print(F(">"));
  display.setCursor(75,10);                                 //Display the field data
  display.print(travDist);
  display.print(F("mm"));
  display.setCursor(75,20);
  if (travelDir == 0)
    display.print(F("Forward"));
  else
    display.print(F("Reverse"));
  display.setCursor(75,30);
  display.print(travTime);
  display.print(F("s"));
  display.display();                                        //Output the display text
}

void updateRotDataDisplay ()
{
  display.clearDisplay();                                   //Clear display
  display.setTextSize(1);                                   //Set the text size
  display.setCursor(2,10);                                  //Set the display cursor position
  display.print(F("Rot. Ang.: "));                          //Set the display text
  display.setCursor(2,20);
  display.print(F("Direction: "));
  display.setCursor(2,30);
  display.print(F("Duration: "));
  int selected = 0;
  if (dataInputNo == 0)                                     //Get the cursor position & update changing variable
  {
    selected = 10;
    rotAngle = encoderPos;
  }
  else if (dataInputNo == 1)
  {
    selected = 20;
    rotDir = encoderPos;
  }
  else
  {
    selected = 30;
    travTime = encoderPos;
    if(calcRotInterval (calcRotationPulses ()) < minInterval)  //Flags movement too fast
    {
      display.setCursor(40,55);                             //Set the display cursor position
      display.print(F("Too Fast"));                         //Set the display text
    }
  }
  display.setCursor(65,selected);                           //Set the display cursor position
  display.print(F(">"));
  display.setCursor(75,10);                                 //Display the field data
  display.print(rotAngle);
  display.print(F("deg"));
  display.setCursor(75,20);
  if (rotDir == 0)
    display.print(F("Forward"));
  else
    display.print(F("Reverse"));
  display.setCursor(75,30);
  display.print(travTime);
  display.print(F("s"));
  display.display();                                        //Output the display text
}

void updatePanAndRotateDataDisplay ()
{
  display.clearDisplay();                                   //Clear display
  display.setTextSize(1);                                   //Set the text size
  display.setCursor(2,2);                                   //Set the display cursor position
  display.print(F("Distance: "));                           //Set the display text
  display.setCursor(2,12);
  display.print(F("Trav. Dir: "));
  display.setCursor(2,22);
  display.print(F("Rot. Ang: "));
  display.setCursor(2,32);
  display.print(F("Rot. Dir: "));
  display.setCursor(2,42);
  display.print(F("Duration: "));
  int selected = 0;
  if (dataInputNo == 0)                                     //Get the cursor position & update changing variable
  {
    selected = 2;
    travDist = encoderPos;
  }
  else if (dataInputNo == 1)
  {
    selected = 12;
    travelDir = encoderPos;
  }
  else if (dataInputNo == 2)
  {
    selected = 22;
    rotAngle = encoderPos;
  }
  else if (dataInputNo == 3)
  {
    selected = 32;
    rotDir = encoderPos;
  }
  else
  {
    selected = 42;
    travTime = encoderPos;
    if(calcInterval (calcTravelPulses ()) < minInterval)    //Flags movement too fast
    {
      display.setCursor(40,55);                             //Set the display cursor position
      display.print(F("Too Fast"));                         //Set the display text
    }
  }
  display.setCursor(65,selected);                           //Set the display cursor position
  display.print(F(">"));
  display.setCursor(75,2);                                  //Display the field data
  display.print(travDist);
  display.print(F("mm"));
  display.setCursor(75,12);
  if (travelDir == 0)
    display.print(F("Forward"));
  else
    display.print(F("Reverse"));
  display.setCursor(75,22);
  display.print(rotAngle);
  display.print(F("deg"));
  display.setCursor(75,32);
  if (rotDir == 0)
    display.print(F("Forward"));
  else
    display.print(F("Reverse"));
  display.setCursor(75,42);
  display.print(travTime);
  display.print(F("s"));
  display.display();                                        //Output the display text
}

void updateTrackDataDisplay ()
{
  display.clearDisplay();                                   //Clear display
  display.setTextSize(1);                                   //Set the text size
  display.setCursor(2,10);                                  //Set the display cursor position
  display.print(F("Distance: "));                           //Set the display text
  display.setCursor(2,20);
  display.print(F("Trav. Dir: "));
  display.setCursor(2,30);
  display.print(F("Obj. Dist: "));
  display.setCursor(2,40);
  display.print(F("Duration: "));
  int selected = 0;
  if (dataInputNo == 0)                                     //Get the cursor position & update changing variable
  {
    selected = 10;
    travDist = encoderPos;
  }
  else if (dataInputNo == 1)
  {
    selected = 20;
    travelDir = encoderPos;
  }
  else if (dataInputNo == 2)
  {
    selected = 30;
    objDist = encoderPos;
  }
  else
  {
    selected = 40;
    travTime = encoderPos;
    if(calcInterval (calcTravelPulses ()) < minInterval)    //Flags movement too fast
    {
      display.setCursor(40,55);                             //Set the display cursor position
      display.print(F("Too Fast"));                         //Set the display text
    }
  }
  display.setCursor(65,selected);                           //Set the display cursor position
  display.print(F(">"));
  display.setCursor(75,10);                                 //Display the field data
  display.print(travDist);
  display.print(F("mm"));
  display.setCursor(75,20);
  if (travelDir == 0)
    display.print(F("Forward"));
  else
    display.print(F("Reverse"));
  display.setCursor(75,30);
  display.print(objDist);
  display.print(F("mm"));
  display.setCursor(75,40);
  display.print(travTime);
  display.print(F("s"));
  display.display();                                        //Output the display text
}

void inputField (int initialSetting, int lowerLimit, int upperLimit, int increment)
{
  encLowLim = lowerLimit;
  encHighLim = upperLimit;
  encIncrement = increment;
  encoderPos = initialSetting;                              //Encoder starts from initial setting
  prevEncoderPos = encoderPos+1;                            //Set different so that display is updated on first cycle
  boolean confirmed = false;                                //Both used to confirm button push to select mode
  boolean pressed = false;
  while(!confirmed)                                         //While the user has not confirmed the input
  {
    byte buttonState = digitalRead (encButton); 
    if (buttonState != oldButtonState)
    {
      if (millis () - buttonPressTime >= debounceTime)      //Debounce button
      {
        buttonPressTime = millis ();                        //Time when button was pushed
        oldButtonState =  buttonState;                      //Remember button state for next time
        if (buttonState == LOW)
        {
          pressed = true;
        }
        else 
        {
          if (pressed == true)                              //Confirm the input once the button is released again
          {
            confirmed = true;
          }
        }  
      }
    }
    if(encoderPos!=prevEncoderPos)                          //Update the display if the encoder position has changed
    {
      if (modeSelected == 0)
        updatePanDataDisplay ();
      else if (modeSelected == 1)
        updateRotDataDisplay ();
      else if (modeSelected == 2)
        updatePanAndRotateDataDisplay ();
      else
        updateTrackDataDisplay ();
      prevEncoderPos=encoderPos;
    }
  }
}

void resetVariables ()                                       //Reset variables back to initial values after run
{
  travDist = maxTravDist;
  travTime = initialDur;
  objDist = initialObjDist;
  travelDir = 0;
  rotDir = 0;
  rotAngle = initialRotAng;
}

int calcTravelPulses ()                                       //Calculates the number of pulses required to move a certain distance
{
  int travP = travDist*pulsesPerMM;
  return travP;
}

int calcRotationPulses ()                                     //Calculate the number of pulses required to rotate a certain angle
{
  int rotP = rotAngle*pulsesPerDeg;
  return rotP;
}

boolean checkRot (int i)                                      //Used in tracking to calculate the angle required to track object
{
  boolean rotP = false;
  float deltaAngle;
  if(((travDist/2)-(i/pulsesPerMM)) > 0)
  {
    if (currentAngle < 90-(1/pulsesPerDeg))
    {
      float newAngle = atan((objDist)/((travDist/2)-(i/pulsesPerMM)))*180/M_PI;
      deltaAngle = newAngle-currentAngle;
    }
  }
  else if (((travDist/2)-(i/pulsesPerMM)) < 0)
  {
    if (currentAngle > 0)
    {
      float newAngle = atan((objDist)/((i/pulsesPerMM)-(travDist/2)))*180/M_PI;
      deltaAngle = currentAngle-newAngle;
    }
  }
  if(deltaAngle >= (1/pulsesPerDeg))
  {
    rotP = true;
    if ((travDist/2)-(i/pulsesPerMM) > 0)
      currentAngle=currentAngle+(1/pulsesPerDeg);
    else
      currentAngle=currentAngle-(1/pulsesPerDeg);
  }
  return rotP;
}

float calcInterval (int numPulses)                                 //Calculate the interval required between pulses to achieve duration
{
  float inter = travTime*1000000/numPulses;
  return inter;
}

float calcRotInterval (int numPulses)                              //Calculate the interval required between pulses to achieve duration
{
  float inter = travTime*1000/numPulses;
  return inter;
}



void receiveEvent(int bytes) {
  String receivedData = "";
  while (Wire.available()) {
    char c = Wire.read();  // Read received data
    receivedData += c;  // Append received character to the string
  }
  processData(receivedData);  // Process the received data
}

void processData(String dataString) {
  int index = 0;
  
  while (dataString.length() > 0 && index < 11) {
    int separatorIndex = dataString.indexOf(',');

    if (separatorIndex >= 0) {
      String valueString = dataString.substring(0, separatorIndex);
      dataArray[index] = valueString.toInt();
      dataString = dataString.substring(separatorIndex + 1);
    } else {
      dataArray[index] = dataString.toInt();
      dataString = "";
    }

    index++;
  }
    int camLeft = dataArray[0];
    int camRight  = dataArray[1];
    int gantryLeft  = dataArray[2];
    int gantryRight   = dataArray[3];
    int mode  = dataArray[4];
    int AtravDist  = dataArray[5];
    int AtravDir  = dataArray[6];
    int AtravDur  = dataArray[7];
    int ArotDeg  = dataArray[8];
    int ArotDir  = dataArray[9];
    int ArotDur  = dataArray[10];
    delay(3000);

  // Print the received data
  for (int i = 0; i < index; i++) {
    Serial.print(dataArray[i]);
    Serial.print(" ");
  }
  Serial.println();

}