4th Axis - PS8 Steam

PS8 Steam
Title
Go to content
Projects
4th Axis for the Mill

Partly as an excuse to play with stepper motors, I would like to build an Arduino controlled indexing head for use on my Mill.  Having never used a stepper motor before, so playing is required.  Alongside is the stepper/mount/vice combination I plan to use.  At present this is driven from a micro-stepper which is driven from the Arduino, but that might not be the best plan.  I don't need the fine control between steppers that the micro-stepper can provide and there is a risk of it missing steps.  A simple bridge driver for this 4 wire stepper may be a better bet.  Still, it works and the torque is huge.

Project completed!  Rare to actually say that, but this is done.

Code was originally from Gary Liming's website : http://www.liming.org/millindex

Code:

#define Version "StepIndexer V1.3"

#include <Arduino.h>
#include <LiquidCrystal_I2C.h>

// Define your parameters about your motor and gearing

#define StepsPerRevolution 200  // Change this to represent the number of steps
                               //   it takes the motor to do one full revolution
                               //   200 is the result of a 1.8 degree per step motor
#define Microsteps 2

#define AngleIncrement 5        // Set how much a keypress changes the angle setting

#define CW LOW                 // Define direction of rotation -
#define CCW HIGH               // If rotation needs to be reversed, swap HIGH and LOW here

#define DefaultMotorSpeed 0     // zero here means fast, as in no delay

// define menu screen ids
#define mainmenu  0
#define stepmode  1
#define anglemode 2
#define runmode   3
#define jogmode   4

#define numModes  4     // number of above menu items to choose, not counting main menu

#define moveangle 10
#define movesteps 11

// Define the pins that the driver is attached to.
// Once set, this are normally not changed since they correspond to the wiring.

#define motorSTEPpin   32    // output signal to step the motor
#define motorDIRpin    28    // output siagnal to set direction
#define motorENABLEpin 22    // output pin to power up the motor

#define en1 26  // Enable -
#define cw1 30  // CW -
#define clk1 34 // Clock -

#define button1 43
#define button2 45
#define button3 47
#define button4 49
#define button5 51
#define button6 53

#define SinkTempPin    1    // temp sensor for heatsink is pin A1
#define MotorTempPin   2    // temp sensor for motor is pin A2

#define pulsewidth     10    // length of time for one step pulse (microseconds)
#define ScreenPause    800  // pause after screen completion
#define ADSettleTime   10   // ms delay to let AD converter "settle" i.e., discharge

#define SpeedDelayIncrement 5  // change value of motor speed steps (delay amount)
#define JogStepsIncrement 1    // initial value of number of steps per keypress in test mode
#define TSampleSize 7          // size of temperature sampling to average

// create lcd display construct
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

// define LCD/Keypad buttons
#define NO_KEY 0
#define SELECT_KEY 1
#define LEFT_KEY 2
#define UP_KEY 3
#define DOWN_KEY 4
#define RIGHT_KEY 5

// create global variables

int    cur_mode = mainmenu;
int    mode_select = stepmode;
int    current_menu;
float  cur_angle = 0;
int    cur_key;
int    num_divisions = 0;
int    numjogsteps = JogStepsIncrement;
unsigned long stepsperdiv;
int    cur_pos = 0;
int    cur_dir = CW;
int    motorspeeddelay = DefaultMotorSpeed;
unsigned long motorSteps;

void setup()
{
 pinMode(button1, INPUT_PULLUP);
 pinMode(button2, INPUT_PULLUP);
 pinMode(button3, INPUT_PULLUP);
 pinMode(button4, INPUT_PULLUP);
 pinMode(button5, INPUT_PULLUP);
 pinMode(button6, INPUT_PULLUP);

 // begin program

 #define gearRatio 32
 motorSteps = Microsteps * StepsPerRevolution * gearRatio;
 lcd.begin(16, 2);
 lcd.clear();
 lcd.setCursor(0,0);                 // display flash screen
 lcd.print(Version);
 lcd.setCursor(0,1);

 delay(1500);                        // wait a few secs
 lcd.clear();
 pinMode(motorSTEPpin, OUTPUT);
 pinMode(motorDIRpin, OUTPUT);
 pinMode(motorENABLEpin, OUTPUT);

 // These three -ve inputs to the stepper driver could all be wired high
 // rather than using Arduino pins
 pinMode(en1, OUTPUT);
 pinMode(cw1, OUTPUT);
 pinMode(clk1, OUTPUT);

 digitalWrite(en1, HIGH);
 digitalWrite(cw1, HIGH);
 digitalWrite(clk1, HIGH);
 digitalWrite(motorENABLEpin,HIGH); // power up the motor and leave it on
 displayscreen(cur_mode);           // put up initial menu screen
}

void loop()
{
 int exitflag;
 int numjogsteps;
 displayscreen(cur_mode);            // display the screen
 cur_key = get_real_key();           // grab a keypress
 switch(cur_mode)                    // execute the keystroke
 {
   case mainmenu:                    // main menu
     switch(cur_key)
     {
       case UP_KEY:
         mode_select++;
         if (mode_select > numModes)  // wrap around menu
           mode_select = 1;
         break;
       case DOWN_KEY:
         mode_select--;
         if (mode_select < 1)         // wrap around menu
           mode_select = numModes;
         break;
       case LEFT_KEY:           // left and right keys do nothing in main menu
         break;
       case RIGHT_KEY:
         break;
       case SELECT_KEY:         // user has picked a menu item
         cur_mode = mode_select;
         break;
     }
     break;
//    case tempmode:                    // call temps
//      dotempmode(cur_key);
//      cur_mode = mainmenu;
//      break;
   case stepmode:                    // call steps
     dostepmode(cur_key);
     cur_mode = mainmenu;
     break;
   case anglemode:                   // call angles
     doanglemode(cur_key);
     cur_mode = mainmenu;
     break;
   case runmode:                     // call run  
     dorunmode(cur_key);
     cur_mode = mainmenu;
     break;
   case jogmode:                    // call jog
     dojogmode(cur_key);
     cur_mode = mainmenu;
     break;
//    case ratiomode:                 // call ratio
//      doratiomode(cur_key);
//      cur_mode = mainmenu;
//      break;  
 }                                           // end of mode switch
}                                               // end of main loop
void dostepmode(int tmp_key)
{
 int breakflag = 0;
 displayscreen(stepmode);
 while (breakflag == 0)
 {
   switch(tmp_key)
   {
     case UP_KEY:
       num_divisions++;
       break;
     case DOWN_KEY:
       if (num_divisions > 0)
         num_divisions--;
       break;  
     case LEFT_KEY:
       cur_dir = CCW;
       stepsperdiv = (motorSteps / num_divisions);
       move_motor(stepsperdiv, cur_dir, movesteps);
       delay(ScreenPause);   //pause to inspect the screen
       cur_pos--;
       if (cur_pos == (-num_divisions))
         cur_pos = 0;
       break;
     case RIGHT_KEY:
       cur_dir = CW;
       stepsperdiv = (motorSteps / num_divisions);
       move_motor(stepsperdiv, cur_dir, movesteps);
       delay(ScreenPause);   // pause to inspect the screen
       cur_pos++;
       if (cur_pos == num_divisions)
         cur_pos = 0;
       break;
     case SELECT_KEY:
       cur_pos = 0;                       // reset position
       num_divisions = 0;                 // reset number of divisions
       return;
       break;  
   }   
   displayscreen(stepmode);
   tmp_key = get_real_key();
 }  
 return;
}
void doanglemode(int tmp_key)
{
 int breakflag = 0;
 displayscreen(anglemode);
 while (breakflag == 0)
 {
   switch(tmp_key)
   {
     case UP_KEY:
       if ((cur_angle+AngleIncrement) < 361)
         cur_angle += AngleIncrement;
       break;
     case DOWN_KEY:
       if ((cur_angle-AngleIncrement) > -1)
         cur_angle -= AngleIncrement;
       break;  
     case LEFT_KEY:
       cur_dir = CCW;
       stepsperdiv = ((motorSteps * cur_angle) / 360);
       move_motor(stepsperdiv, cur_dir,moveangle);
       delay(ScreenPause);   //pause to inspect the screen
       break;
     case RIGHT_KEY:
       cur_dir = CW;
       stepsperdiv = ((motorSteps * cur_angle) / 360);
       move_motor(stepsperdiv, cur_dir,moveangle);
       delay(ScreenPause);   //pause to inspect the screen
       break;
     case SELECT_KEY:
       cur_angle = 0;                       // reset angle to default of zero
       return;
       break;  
   }
   displayscreen(anglemode);
   tmp_key = get_real_key();    
 }  
 return;
}

int isKeyPressed()
{
 int retval = 0;
 if (digitalRead(button1) == LOW)
   retval = 1;
 if (digitalRead(button2) == LOW)
   retval = 1;
 if (digitalRead(button3) == LOW)
   retval = 1;
 if (digitalRead(button4) == LOW)
   retval = 1;
 if (digitalRead(button5) == LOW)
   retval = 1;
 if (digitalRead(button6) == LOW)
   retval = 1;

 return retval;
}

void dorunmode(int tmp_key)
{
 int breakflag = 0;
 delay(100);                              // wait for keybounce from user's selection
 cur_dir = CW;                            // initially, clockwise
 displayscreen(runmode);                  // show the screen
 while (breakflag == 0)                   // cycle until Select Key sets flag
 {        
   move_motor(1,cur_dir,0);               // move motor 1 step
   if (isKeyPressed() == 1)                    // if a keypress is present       {
   {                          
     cur_key = get_real_key();            // then get it
     switch(cur_key)                       // and honor it
     {
     case UP_KEY:                        // bump up the speed
       if (motorspeeddelay >= SpeedDelayIncrement) {
         motorspeeddelay -= SpeedDelayIncrement;
         displayscreen(runmode);
       }  
       break;
     case DOWN_KEY:                      // bump down the speed
       motorspeeddelay += SpeedDelayIncrement;
       displayscreen(runmode);
       break;
     case LEFT_KEY:                      // set direction
       cur_dir = CCW;
       displayscreen(runmode);
       break;
     case RIGHT_KEY:                     // set other direction
       cur_dir = CW;
       displayscreen(runmode);
       break;
     case SELECT_KEY:                   // user wants to stop
       motorspeeddelay = DefaultMotorSpeed;   // reset speed   
       breakflag = 1;                   // fall through to exit
     }
   }  
 }     
}  
void dotempmode(int test_key)
{
 while (1)
 {
   if (test_key == SELECT_KEY) return;     // all we do here is wait for a select key
   test_key = get_real_key();
 }
 return;                                   // to exit
}

void dojogmode(int tmp_key)
{
 int breakflag = 0;
 numjogsteps = JogStepsIncrement;
 for (;breakflag==0;)
 {
   switch(tmp_key)
   {
     case UP_KEY:                          // bump the number of steps
       numjogsteps += JogStepsIncrement;
       break;
     case DOWN_KEY:                        // reduce the number of steps
       if (numjogsteps > JogStepsIncrement)
         numjogsteps -= JogStepsIncrement;
         break;
     case LEFT_KEY:                        // step the motor CCW
         move_motor(numjogsteps,CCW,0);  
         break;
     case RIGHT_KEY:                       // step the motor CW
         move_motor(numjogsteps,CW,0);  
         break;
     case SELECT_KEY:                      // user want to quit
         breakflag = 1;
         break;
   }
   if (breakflag == 0)
   {
     displayscreen(jogmode);
     tmp_key = get_real_key();
   }  
 }  
 numjogsteps = JogStepsIncrement;
 cur_mode = mainmenu;                 // go back to main menu
 return;
}

void displayscreen(int menunum)        // screen displays are here
{
lcd.clear();
lcd.setCursor(0,0);
switch (menunum)
{
 case mainmenu:
   lcd.print("Select Mode");
   lcd.setCursor(0,1);
   lcd.print("Mode = ");
   lcd.setCursor(7,1);
   switch(mode_select)
   {
     case(stepmode):
       lcd.print("Step");
       break;
//      case(tempmode):
//        lcd.print("Temp");
//        break;
     case(anglemode):
       lcd.print("Angle");
       break;
     case(runmode):
       lcd.print("Run");
       break;   
     case(jogmode):
       lcd.print("Jog");
       break;  
   }  
   break;
 case stepmode:
   lcd.print("Divisions:");
   lcd.setCursor(10,0);
   lcd.print(num_divisions);
   lcd.setCursor(0,1);
   lcd.print(" Position:");
   lcd.setCursor(10,1);
   lcd.print(cur_pos);
   break;
 case movesteps:
   lcd.print("Steps/Div:");
   lcd.setCursor(10,0);
   lcd.print(stepsperdiv);
   lcd.setCursor(0,1);
   lcd.print("Move ");
   lcd.setCursor(5,1);
   if (cur_dir == CW)
     lcd.write(">");
   else
     lcd.write("<");
   lcd.setCursor(7,1);
   lcd.print("to:");
   lcd.setCursor(10,1);
   lcd.print(cur_pos);
   break;  
 case anglemode:
   lcd.print("Move ");
   lcd.setCursor(5,0);
   lcd.print((int)cur_angle);
   lcd.setCursor(8,0);
   lcd.print(" degrees");
   break;
 case moveangle:
   lcd.print("Move ");
   lcd.setCursor(5,0);
   if (cur_dir == CW)
     lcd.write(">");
   else
     lcd.write("<");
   lcd.setCursor(12,0);
   lcd.print("steps");  
   lcd.setCursor(0,1);
   lcd.print("to ");
   lcd.setCursor(3,1);
   lcd.print((int)cur_angle);
   lcd.setCursor(7,1);
   lcd.print("degrees");
   break;
 case runmode:
   lcd.print("Continuous");
   lcd.setCursor(11,0);
   if (cur_dir == CW)
     lcd.write(">");
   else
     lcd.write("<");
   lcd.setCursor(0,1);
   lcd.print("Speed = ");
   lcd.setCursor(8,1);
   lcd.print((int)motorspeeddelay);
   break;
 case jogmode:
   lcd.print("Jog ");
   lcd.setCursor(0,1);
   lcd.print("Steps/jog: ");
   lcd.setCursor(11,1);
   lcd.print(numjogsteps);
   break;
 }
 return;
}  

void move_motor(unsigned long steps, int dir, int type)
{
 unsigned long i;

 //steps = steps * 16;
 if (type == movesteps)
   displayscreen(movesteps);

 if (type == moveangle)
   displayscreen(moveangle);    
 for (i=0; i < steps; i++)
 {
   digitalWrite(motorDIRpin,dir);
   digitalWrite(motorSTEPpin,HIGH);   //pulse the motor
   delayMicroseconds(pulsewidth);
   digitalWrite(motorSTEPpin,LOW);
   if (type == movesteps)             // in this mode display progress
   {
     lcd.setCursor(10,1);
     lcd.print(i);
   }
   if (type == moveangle)             // in this mode display progress
   {
     lcd.setCursor(7,0);
     lcd.print(i);
   }   
   delayMicroseconds(motorspeeddelay * 128);            // wait betweeen pulses
 }  
 return;
}  

int gettemp(int device)
{
 float temperature=0.0;
 float tCelsius=0.0;
 int i;
 analogRead(device);                      // first time to let adc settle down
 delay(50);                               // throw first reading away
 for (i=0; i<TSampleSize; ++i)              // take several readings
 {
   tCelsius = ((tCelsius-32.0)/1.8) ;  // just use different formula for celsius
   temperature += tCelsius;
   delay(ADSettleTime);
 }
 return (int)(temperature/TSampleSize);   // return the average
}

int get_real_key(void)    // routine to return a valid keystroke
{
 int trial_key = 0;
 while (trial_key < 1)
 {
   trial_key = read_LCD_button();
 }
 delay(200);             // 200 millisec delay between user keys
 return trial_key;
}  

int read_LCD_button()     // routine to read the LCD's buttons
{
 if (digitalRead(button1) == LOW)
 {
   return SELECT_KEY;
 }
 if (digitalRead(button2) == LOW)
 {
   return RIGHT_KEY;
 }
 if (digitalRead(button3) == LOW)
 {
   return UP_KEY;
 }
 if (digitalRead(button4) == LOW)
 {
   return DOWN_KEY;
 }
 if (digitalRead(button5) == LOW)
 {
   return LEFT_KEY;
 }
 if (digitalRead(button6) == LOW)
 {
   return NO_KEY;
 }
}
 
 
 
 
 
 
   
 
 
 
   
   
 
   
First attempts with a stepper motor
(C) 2018 Kevin Murrell
Back to content