Close

Motor Control Targeting Interface Mega 2560 V3.02

A project log for DAV5 V3.01 Raman Spectrometer

The only thing worth doing, is the thing worth doing right!

david-h-haffner-srDavid H Haffner Sr 11/06/2017 at 14:570 Comments

*UPDATED Turret Control Program:

/*When you turn the rotary encoder clockwise, the angular displacement is increased;

  when you turn it counterclockwise, the displacement is decreased.  If you press the switch on the rotary encoder, the readings will return to zero  Original code can be found here://Email: support@sunfounder.com  //Website: www.sunfounder.com  //2015.5.7/
  **Although this is in the Public Domain, I have created a "Creative Commons License" for this work,  the reason is, I made enough mod's and put in many hours of work to make this program accurate and  efficient as part of a much larger project @ Hackaday.com, the DAV5 3D Printable Raman Spectrometer.
  There are individuals there that have engaged in "intellectual theft" and not bothered to give credit  where credit was certainly due, so I believe I have no choice but to go this route since I have put in  2 years of very hard work on this.**
  The creative commons license can be viewed here: http://thequantumhub.blog/
  I have modified this code to accomodate my diffraction grating turret for  the DAV5 Raman 3D printable Spectrometer (http://hackaday.io/project/18126-dav5-v301-raman-spectrometer)
  Written and modified by David H Haffner SR 10/18/2017
  Full project details can be found here @ https://hackaday.io/project/18126-dav5-v301-raman-spectrometer
  This program is also in the public domain @ https://playground.arduino.cc/Main/KY-040EncodeUsedToControlAHolographicDiffractionGratingForARamanSpectrometer
  It utilizes a KY-040 encoder to control the holographic diffraction grating  at steps of 1 & -1, each pin (SW,DT and CLK) has a 0.1uf ceramic cap for decoupling,  this is more effective for rise time spike removal. There are 2 LED indicators, a red for encoder step movements and  a yellow for home position indication that will light when the shaft docks back to a pre-determined home position,(I'm still  working on it,)This is accomplished by adjusting both "StepsToTake and RotoryPosition," they are in direct relation to steps per revolution  of the internal shaft according to the type of stepper motor you are using (mine is a 28-YBJ-48).Fine tuning can be done by playing between  STEPS (per revolution of shaft) and Speed, this will ensure smoother transitions when turning the encoder for fewer misses.  If you press the switch on the rotary encoder, the readings will return to approx zero 0.21 percent error.  a 0.1uf ceramic Cap is placed @ PinSW (4) to + (the reason for the pin pullup).
  The formula in this sketch is derived from the specifications of the 28-YBJ-48 stepper MTR  which has a step angle of 5.62deg, to convert degrees into nanometers you 1st have to convert  degrees into radians {RAD}, we do this for the 1st specification which is 5.625deg = 0.09817474 {RAD}  this # is then divided by the equitorial radius of the Earth which is 3,963.2 miles.
  Our new value would then be, 0.000024772 miles (NM), convert this into centimeters, (3.986667)
  Now with this #, we multiply it by the constant of 1 (NM) = 1609344e+012 miles *(Variable)/ 7  gives us our converting factor from encoder position count to nanometer counts.
  Sketch uses 9202 bytes (3%) of program storage space. Maximum is 253952 bytes.  Global variables use 519 bytes (6%) of dynamic memory, leaving 7673 bytes for local variables. Maximum is 8192 bytes.
  1. include <digitalWriteFast.h>
  2. include <math.h>
  3. include <Wire.h>
  4. include <LiquidCrystal_I2C.h>
  5. include "Stepper.h"
  6. define STEPS 64 // Number of steps for one revolution of Internal shaft

// 2048 steps for one revolution of External shaft LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address

double double_x = 3.986667 * 1.609344e+012 * 0 / 7;

volatile boolean TurnDetected; // need volatile for Interrupts volatile boolean rotationdirection; // CW or CCW rotation

  1. define PinNum 2 // Generating interrupts using CLK signal
  2. define PinNum 3 // Reading DT signal
  3. define PinNum 4 // Reading Push Button switch

int RotaryPosition = 0; // To store Stepper Motor Position

int PrevPosition; // Previous Rotary position Value to check accuracy int StepsToTake; // How much to move Stepper

// Setup of proper sequencing for Motor Driver Pins // In1, In2, In3, In4 in the sequence 1-3-2-4 Stepper small_stepper(STEPS, 8, 10, 9, 11);

// Interrupt routine runs if CLK goes from HIGH to LOW void isr () {

  static unsigned long                lastInterruptTime = 0;
  unsigned long                       interruptTime = millis();
  //If interrupts come faster than 5ms, assume it's a bounce and ignore  if (interruptTime - lastInterruptTime > 5) {    if (!digitalReadFast(3))      rotationdirection = digitalReadFast(2);    else      rotationdirection = !digitalReadFast(2);  }  lastInterruptTime = interruptTime;  // ISR  digitalWriteFast(12, HIGH); // Tracks the detents of the encoder  delay(1);  digitalWriteFast(12, LOW);  delay(1);  TurnDetected = true;

}

void setup () {

  lcd.begin(20, 4);        // initialize the lcd for 20 chars 4 lines, turn on backlight  // ------- Quick 3 blinks of backlight  -------------  for (int i = 0; i < 3; i++)  {    lcd.backlight();    delay(250);    lcd.noBacklight();    delay(250);  }  lcd.backlight(); // finish with backlight on  // set up the LCD's number of columns and rows:  lcd.begin(20, 4);  // Print a message to the LCD.  lcd.print("SYSTEM RDY");  lcd.setCursor(10, 0);  lcd.print(" Mega 2560");// system ready wired to Pin#13 built-in LED (blinks twice to indicate "system ready.")  lcd.setCursor(0, 1);  lcd.print("POS:");//CCW or CC  lcd.setCursor(0, 2);  lcd.print("Nanomtrs");// Float Position corrected  lcd.setCursor(0, 3);  lcd.print("Correctd");  Serial.begin(115200);  delay(1000);
  pinModeFast(12, OUTPUT);// tracks the detent pins of the KY_040 encoder/turns off when button is pressed  pinModeFast(2, INPUT);  pinModeFast(3, INPUT);  pinModeFast(4, INPUT_PULLUP);// pullup resistor needed for switch stability  digitalWriteFast(4, HIGH); // Pull-Up resistor for switch  attachInterrupt (0, isr, FALLING); // interrupt 0 always connected to pin 2 on Arduino UNO

}

void loop () {

  small_stepper.setSpeed(10); //Max seems to be 700  if (!(digitalReadFast(4))) {   // check if button is pressed    if (RotaryPosition == 0) {  // check if button was already pressed    } else {      small_stepper.step(RotaryPosition * 0);      RotaryPosition = 0; // Reset position to ZERO ("home" position)      lcd.setCursor(9, 3);      lcd.print(fabs ( 3.986667 * 1.609344 * (PrevPosition) / 7) ); // absolute value of a float    }    bool reading = digitalReadFast(4);
    if (reading == ERROR_SEQUENCE) { //ERROR_SEQUENCE  defined as 0b10101010      // pinNum is not a const and will always return as HIGH    }  }  // Runs if rotation was detected  if (TurnDetected)  {    PrevPosition = RotaryPosition; // Save previous position in variable    if (rotationdirection) {      RotaryPosition = RotaryPosition - 1;      lcd.setCursor(8, 1);      lcd.print(RotaryPosition);    } // decrase Position by 1    else {      RotaryPosition = RotaryPosition + 1;      lcd.setCursor(13, 1);      lcd.print(RotaryPosition);
    } // increase Position by 1
    TurnDetected = false;  // do NOT repeat IF loop until new rotation detected
    // Which direction to move Stepper motor    if ((PrevPosition + 1) == RotaryPosition) { // Move motor CW      StepsToTake = 1;      small_stepper.step(StepsToTake);      lcd.setCursor(15, 2);      lcd.print(fabs(+(PrevPosition) * 0.965)); // absolute value of a float, steps in + direction      delay(1);    }
    if ((RotaryPosition + 1) == PrevPosition) { // Move motor CCW      StepsToTake = -1;      small_stepper.step(StepsToTake);      lcd.setCursor(9, 2);      lcd.print(fabs(-(PrevPosition) * 0.965)); // absolute value of a float, steps in - direction      delay(1);    }  }

}

Discussions