Untitled
unknown
plain_text
2 years ago
53 kB
17
Indexable
//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 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;
void setup()
{
Serial.begin(9600); //Start serial communication for debugging
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) //Connect to the OLED display
{
Serial.println(F("SSD1306 allocation failed")); //If connection fails
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))
{
Serial.println("Left Limit triggered");
}
if(!digitalRead(rightlimit))
{
Serial.println("Right Limit triggered");
}
Serial.println("Setup complete");
//Write to serial monitor to indicate the setup function is complete
}
void loop()
{
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;
Serial.println("Button Pushed");
}
else
{
if (pressed == true) //Confirm the input once the button is released again
{
confirmed = true;
Serial.println("Mode confirmed");
}
}
}
}
if(encoderPos!=prevEncoderPos) //Update the display if the encoder position has changed
{
updateMainMenu();
prevEncoderPos=encoderPos;
}
}
Serial.println("Mode selected");
if (modeSelected == 0) //Run required mode function depending on selection
runPan();
else if (modeSelected == 1)
runRotate ();
else if (modeSelected == 2)
runPanAndRotate ();
else
homeslider ();
if (Serial.available() > 0) {
String data = Serial.readStringUntil('\n'); // Read the incoming data until a newline character is received
char* token; // Pointer to store the extracted tokens
int values[11]; // Array to store the parsed integers
// Parse the data using strtok()
token = strtok(const_cast<char*>(data.c_str()), ",");
int i = 0;
while (token != NULL && i < 6) {
values[i] = atoi(token); // Convert the token to an integer
token = strtok(NULL, ",");
i++;
}
// Process the parsed integers
for (int j = 0; j < 11; j++) {
Serial.print("Value ");
Serial.print(j);
Serial.print(": ");
Serial.println(values[j]);
}
int camLeft = atoi(values[0]);
int camRight = atoi(values[1]);
int gantryLeft = atoi(values[2]);
int gantryRight = atof(values[3]);
int mode = atoi(values[4]);
int AtravDist = atoi(values[5]);
int AtravDir = atoi(values[6]);
int AtravDur = atoi(values[7]);
int ArotDeg = atof(values[8]);
int ArotDir = atoi(values[9]);
int ArotDur = atoi(values[10]);
float interA;
}
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;
Serial.print("Travel pulses: ");
Serial.println(travelP);
float interA = AtravDur*1000000/travelP;
Serial.print("Interval: ");
Serial.println(interA);
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
Serial.print("Rotation pulses: ");
Serial.println(rotationP);
Serial.print("Travel Time: ");
Serial.println(ArotDur);
float interv = ArotDur*1000/rotationP;
Serial.print("Interval: ");
Serial.println(interv);
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;
Serial.print("Travel pulses: ");
Serial.println(travelPs);
float interc = AtravDur*1000000/travelP;
Serial.print("Interval: ");
Serial.println(interc);
int rotationPs = ArotDeg*pulsesPerDeg; //Calculate the number of motor pulses required to rotate the required angle
Serial.print("Rotation pulses: ");
Serial.println(rotationPs);
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
Serial.print("Travel pulses: ");
Serial.println(travelPulses);
float interval = calcInterval (travelPulses); //Calculate the pulse interval required to move the required distance in the required time
Serial.print("Interval: ");
Serial.println(interval);
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
Serial.print("Rotation pulses: ");
Serial.println(rotationPulses);
Serial.print("Travel Time: ");
Serial.println(travTime);
float interval = calcRotInterval (rotationPulses); //Calculate the pulse interval required to rotate in the required time
Serial.print("Interval: ");
Serial.println(interval);
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
Serial.print("Travel pulses: ");
Serial.println(travelPulses);
float interval = calcInterval (travelPulses); //Calculate the pulse interval required to move the required distance in the required time
Serial.print("Interval: ");
Serial.println(interval);
int rotationPulses = calcRotationPulses (); //Calculate the number of motor pulses required to rotate the required angle
Serial.print("Rotation pulses: ");
Serial.println(rotationPulses);
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;
Serial.println("Input Confirmed");
}
}
}
}
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;
}
Editor is loading...