capeMirror v. 2 – a prototype

So, some holiday madness from Spain. The [first] prototype for an arduino-driven GoTo bincoular mirror mount.

The pictures speak for themselves:

below is the prototype arduino code that worked after a few amends and tests.

/* 
 * capeMirror v2.0 (prototype)
 * ---------------------------------------
 *
 * Start-up
 * The Arduino is wired as follows:
 * 1 x Bluesmirf Bluetooth chip which will receive instructions from 
 * a Windows program (Skymap Pro).
 * 4 x Buttons which denote up, down, left, right.
 * 2 x Stepper motors (4 wires for each).
 * 
 * NB1: The key structural point about the code below is that the 
 * mount needs to be able to receive instructions from two different
 * sources: (i) from the laptop via bluetooth and (ii) from the 
 * 4 buttons 'on-board' the mount itself.
 * 
 * NB2: One trick that will be obvious reading the code but is easiest
 * to point out at the outset is that for a mirror mount the altitude
 * and azimuth have to be reversed - ie if the altitude of the point
 * in the sky looked at RISES, then the mirror has to tilt DOWN (same for azimuth).  
 * I decided to 'hard-wire' this reversal into the code below.  Look 
 * for the "Alt = Alt * -1" in the code.
 * 
 * Now, the structure of the sketch:
 * Part 1: Bluetooth data.
 * The chip here receives instructions via bluetooth.  The 2 steppers 
 * move according to those instructions.  The format of the instructions 
 * is as follows "[5;-10;]".  The first number carries the instructions
 * for the movements in Azimuth, the second number carries instructions
 * for Altitude.  If the chip received the following "[-5;10;]", then Az would 
 * rotate left 5 times (positive Azimuth values rotate the mount right, negative
 * value rotate it left), and then the Alt stepper would step 10 times up.  
 * 
 * If the chip receives X for the Az value (ie "[X;;]", then the mount
 * knows to change to Mount control (ie not bluetooth).
 * There is in fact a third number (between the second semi-colon and 
 * the right end square bracket) this is for future development.
 *
 * Also, during this 'bluetooth' phase, the chip also checks whether the
 * UP button is pressed, if it is, then the bluetooth control ends.
 * 
 * Part 2: On-board instructions
 * The chip begins by polling the 4 buttons (up, down, left, right).
 * These feed into 4 analog inputs.  The rate at which the stepper 
 * steps is (in part) determined by how long a delay there is between 
 * the polling of the buttons.  This is set in the variable
 * ButtonPollDelay.
 * 
 * Part 3: Hand-over to bluetooth instructions.  If the user wants to 
 * handover control to the laptop, then the user has to press the 
 * 'left' and 'right' buttons at the same time.  When that happens, 
 * the chip sends a brief message via bluetooth to the laptop.  
 * The chip then stops polling the buttons and instead
 * starts to read any serial data received via bluetooth.
 * 
 * Acknowledgements 
 * The difficult serial parsing bit was came from Nition
 * see forum post at:
 * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1203538464/2#2
 *
 * The AFSoftwareSerial library came from ladyada.  It adds the
 * serial.available functionality.
 * download it here: http://www.ladyada.net/make/eshield/download.html
 *
 * The button wiring came from the standard arduino tutorial on 
 * digital inputs.
 *
 * created 21 August 2008
 * by Ben 
 */

// include the AFSoftSerial library
#include <AFSoftSerial.h>
#include <Stepper.h>

// define the button pins
#define switchPinUp 0     // analog pin 0 wired to the Up button
#define switchPinLeft 1   // analog pin 1 wired to the Left button
#define switchPinDown 2   // analog pin 2 wired to the Down button
#define switchPinRight 3  // analog pin 3 wired to the Right button

// define the bluetooth pins 
#define rxPin 4           // pin 4 (receive) wired to tx-0 (transmit) on bluesmirf
#define txPin 5           // pin 5 (transmit) wired to rx-1 (receive) on bluesmirf

// define the polling delay for the buttons
#define ButtonPollDelay 250

// define the stepper motor constants
#define STEPS 200         // how many steps for the stepper motor(s)
#define AzStepSpeed 5     // speed for the az stepper motor (per min)
#define AltStepSpeed 10   // speed for the alt stepper motor (per min)
#define AzSteps 1         // how many steps per button press
#define AltSteps 1        // how many steps per button press

// create the steppers on pins 6-9 (az) and 10-13 (alt)
Stepper AzStepper(STEPS, 6, 8, 7, 9);
Stepper AltStepper(STEPS, 10, 12, 11, 13);

// define the LED pin which is used to read the alt and az scales on the mount 
// it's normally on when laptop controlled and off when on-board controls are 
// used, but the user can toggle it by pressing UP and DOWN together.
#define LEDPin 3        // Pin 3 is an LED.  
boolean LEDOn = false;  // Turn it off at the start. 

// define the variables that will store the data from the buttons
// if 0 then not pressed, if 1 then pressed.
int UpBtnVal = 0;
int DownBtnVal = 0;
int LeftBtnVal = 0;
int RightBtnVal = 0;

// create the variables that will hold the Alt and Az sums (ie the total moves 
// made by the mount while controlled by the user.  These are stored and then
// sent back to the PC.
int AltTotal = 0;
int AzTotal = 0;

// create the variable that will record whether under 'onboard control'
boolean MountControl = false;  // start with 'bluetooth control'

// Serial parsing variables and set up
#define tagLength 6	    // each 'tag' or instructions will contains 6 bytes
#define semicolon 0x3b      // create a shorthand reference to a semicolon
#define dataRate 9600       // create a shorthand reference to 9600kbps serial baud rate
#define leftbracket 0x5b    // create a shorthand reference to a left squarebracket "[" 
#define rightbracket 0x5d   // create a shorthand reference to a right squarebracket "]" 
int tagIndex = 0;           // counter for number of bytes read
int allComplete = false;    // whether all tags have been read
char AzVal[tagLength];      // create the variable that will hold the Az instructions
char AltVal[tagLength];     // create the variable that will hold the Alt instructions
char rVal[tagLength];       // create the spare (unused) variable for future instructions
int AzComplete = false;     // variable to indicate whether the Az instructions are complete
int AltComplete = false;    // variable to indicate whether the Alt instructions are complete
int rComplete = false;      // variable to indicate whether the sprare (r) instructions are complete
AFSoftSerial mySerial =  AFSoftSerial(rxPin, txPin); // create a new serial connection using the AFSoftSerial library

//*****************
// Setup Procedure 
//*****************
void setup()  
{
  // define the pins
  pinMode(rxPin, INPUT);          // sets the digital pin as input to rx serial data
  pinMode(txPin, OUTPUT);         // sets the digital pin as output to tx serial data
  pinMode(LEDPin, OUTPUT);        // LED to communicate

  // set the speeds (different) for the stepper motors.
  AzStepper.setSpeed(AzStepSpeed);
  AltStepper.setSpeed(AltStepSpeed);

  // set the data rate for the serial port
  mySerial.begin(dataRate);

  // turn on LED 3 times to show mount working
   for (int i=0;i<3;i++){
   digitalWrite(LEDPin, LOW);
   delay(125);
   digitalWrite(LEDPin, HIGH);  // LED left on
   delay(250);
   }  // end: for
} // end: setup

//*****************************************************
// Loop (main) procedure 
//*****************************************************
void loop() {

///////////////////////////////////////////////////////
// Part 1: Obtain the serial data over bluetooth
///////////////////////////////////////////////////////
if (mySerial.available() > 0) {  // wait til some data available
    digitalWrite(LEDPin, LOW);  // LED off to show receiving
    delay(1500); // wait for all data to be in. 1500 works fine.

    // run the readData procedure for data that's been received
    readData(); 

    // check to see if told to hand-over control to the mount 
    if (AzVal[0]== 'X'){
    // if so, then set mount control to True and reset variables
    MountControl = true;
    AzTotal = 0;
    AltTotal = 0;
    for (int i=0;i<5;i++){     // this empties the arrays
    AzVal[i] = 0x00;
    AltVal[i] = 0x00;
    rVal[i] = 0x00;
    }  // end: for
    }  // end: if

   // Move the Azimuth (Az) stepper
   int AzInt = atoi(AzVal); 
   AzInt = (AzInt * -1);    // reverse the direction
   AzStepper.step(AzInt);
   AzInt = (AzInt * -1);    // put back in case report it later

   // Move the Altitude (Alt) stepper
   int AltInt = atoi(AltVal); 
   AltInt = (AltInt * -1);    // reverse the direction
   AltStepper.step(AltInt);
   AltInt = (AltInt * -1);    // put back in case report it later

   // this would be where to use the rVal data

   // run the DataComplete procedure 
   DataComplete();

   digitalWrite(LEDPin, HIGH);  // LED on to show completed   

}  //  End: If Serial.Available > 0


// check to see if Up button pressed, if so stop handover to on-board control
UpBtnVal = analogRead(switchPinUp);  
if (UpBtnVal > 500){        // check the up button
    MountControl = true;        // set the mount control to true
    AzTotal = 0;
    AltTotal = 0;
    for (int i=0;i<5;i++){     // this empties the arrays
    AzVal[i] = 0x00;
    AltVal[i] = 0x00;
    rVal[i] = 0x00;
    }  // end: for  
}  // end: if button pressed

///////////////////////////////////////////////////////
// Parts 2 & 3: Control of the Mount via the 4 buttons
///////////////////////////////////////////////////////
if (MountControl == true) {

  // flash LED 3 times to show mount got control
   for (int i=0;i<3;i++){
   digitalWrite(LEDPin, HIGH);  
   delay(250);
   digitalWrite(LEDPin, LOW);  // Leave off for mount control
   delay(125);   
   }  //  end: for

  // Loop through this section until left and right pressed together
  do {
  // Poll the 4 buttons to see if any pressed
  UpBtnVal = analogRead(switchPinUp);  
  DownBtnVal = analogRead(switchPinDown);
  LeftBtnVal = analogRead(switchPinLeft);
  RightBtnVal = analogRead(switchPinRight);

    // Part 3: check to see if user wanting to 'end mount control'
    if (LeftBtnVal > 500 && RightBtnVal > 500){      // Bail out if both pressed
       MountControl = false;    // reset the MountControl variable
       digitalWrite(LEDPin, HIGH);  
       ReportBack();  // run the ReportBack procedure
       break;
    }  //  end: if

    // Turn LED on/off if user presses up and down together
    if (UpBtnVal > 500 && DownBtnVal > 500){      // Toggle LED if both pressed
       if (LEDOn == false){
       digitalWrite(LEDPin, HIGH);  
       LEDOn = true;
       }  // end: if LEDOn == false 
       else
       {
       digitalWrite(LEDPin, LOW);  
       LEDOn = false;         
       } // end: else
    }  // end: if toggling 

    // Now step the motors according to buttons pressed
    if (LeftBtnVal > 500){         // the left button
    AzStepper.step(-AzSteps);
    AzTotal = AzTotal + 1;  
    }  // end if left
    if (RightBtnVal > 500){        // the right button
    AzStepper.step(AzSteps);
    AzTotal = AzTotal - 1;  
    }  // end if right
    if (UpBtnVal > 500){           // check the up button
    AltStepper.step(-AltSteps);
    AltTotal = AltTotal + 1;       
    }  // end if up
    if (DownBtnVal > 500){         // the down button
    AltStepper.step(AltSteps);
    AltTotal = AltTotal - 1;  
    }  // end if down
  
  // delay before re-reading
  delay(ButtonPollDelay);   
  } while (MountControl == true);  // End: the Do-While loop

}  // End: if (MountControl = true)

}  //  End: Loop

//************************************
// readData procedure - for Bluetooth
//************************************

void readData() {

    // Reset all the variables
    AzComplete = false;
    AltComplete = false;
    rComplete = false;

    for (int i=0;i<5;i++){
    AzVal[i] = 0x00;
    AltVal[i] = 0x00;
    rVal[i] = 0x00;
    }	

// Read the serial data  
char thisChar = mySerial.read();
 
  if (thisChar == leftbracket){ 
   // read all first data section (Az)
  while (AzComplete == false && mySerial.available() > 0){
    	char thisChar = mySerial.read();
	if (thisChar == semicolon){
  	  AzComplete = true;
	  break;
	}
	else {
  	  AzVal[tagIndex] = thisChar;
	  tagIndex++;
	}  
  }
  tagIndex = 0;
  
   // read all second data section (Alt)
  while (AltComplete == false && mySerial.available() > 0){
	char thisChar = mySerial.read();
   //   Serial.println("y-loop");
	
	if (thisChar == semicolon){
	  AltComplete = true;
	  break;  
    }
	else {
	  AltVal[tagIndex] = thisChar;
	  tagIndex++;
	}  
  }
  tagIndex = 0;
 
 // read all r
  while (rComplete == false && mySerial.available() > 0){
	char thisChar = mySerial.read();
   //   Serial.println("r-loop");
	
	if (thisChar == rightbracket){
	  rComplete = true;
	  break;
	}
	else {
	  rVal[tagIndex] = thisChar;
	  tagIndex++;
	}  
  }
  tagIndex = 0;
  
  if (AzComplete == true && AltComplete == true && rComplete == true){
  // For debugging purposes only.  Data now all read.
  }
 }
}

//*****************************************************
// ReportBack procedure - after left and right pressed
//*****************************************************
void ReportBack(){
  
  // send back the total via bluetooth 
  mySerial.print("[");
  mySerial.print(AzTotal);
  mySerial.print(";");
  mySerial.print(AltTotal);
  mySerial.print(";");
  mySerial.print("X");
  mySerial.print("]");
  AzTotal = 0;
  AltTotal = 0;
}

//****************************************
// DataComplete procedure - for Bluetooth
//****************************************
void DataComplete(){
  // Used for debugging purposes only.  
  // mySerial.print("[Arduino;Bluesmirf;Baltaz]");  
}

Ben

post a comment...

you must be logged in to post a comment.