16 August 2010

Code for an arduino plotterhead

Space is needed, and we will be dismantling the junkrecycledplotter to go on with other projects. It certainly helped us in the learning curve, but for long term use we would be having issues with the tiny motors losing steps. More "real" CNC things in the pipeline...
This plotter head gave good results, however.


We used a spring to regulate the pen's pressure on the surface (it pulls the pen down), while the stepper pulls the pen up with a wire cable. The position is kept even when the head loses power.
The controller knows two positions: pen down and pen up. We re-used the CD-Rom's proximity switch as the up position sensor.

The head is driven by an Arduino duemilanove and a custom-made shield for the L298D inspired by this good implementation (capacitors and all that). The controller reacts to the Z-axis enable and direction change signals sent by EMC2, and ignores the rest. Also there is a manual pen-up/pen-down switch on the shield, that came of good use.

Here is the code used for the plotter head. Heavily indebted to the many tutorials and examples at the Arduino site and in various places.


/* a sketch to use a an arduino or derivative and a L293D as a stepper motor controller
with an additional homing button (pen up/pen down for example)
Uses optionally John Zandbergen's enhancement to the stepper library to do half-stepping
http://code.google.com/p/arduino/issues/detail?id=139
the arduino responds to standard STEP, DIR and ENABLE signals
we have only an upper limit stop sensor, the lower limit is done in software
Koroviev, july 2010
*/

#define IN_DIR_PIN 12
#define IN_STEP_PIN 13
#define IN_ENABLE_PIN 8
#define STEPPER_ENABLE_PIN 7
#define STEPPER_PIN_A1 11
#define STEPPER_PIN_A2 10
#define STEPPER_PIN_B1 6
#define STEPPER_PIN_B2 5
#define IN_Z_LIM_PROX_PIN 3
#define OUT_Z_LIM_PROX_PIN 14
#define OUT_Z_LIM_DIST_PIN 1
#define IN_HOME_SWITCH_PIN 4
#define UP 1
#define DOWN -1
#define ZLENGTH 54
#define USE_HALF_STEP 0
#define ENABLED 1
#define DISABLED 0

// change this to your motor's number of steps per turn
#define STEPS 48
 
#include

int zButtonState = 0 ;  // current z button state
int zLastButtonState = 0 ; // previous state of the z button
int zButtonPushCounter = 1 ; // push counter for the z button
int zProxLimState = LOW ; // z prox limit sensor state 
int zpos = 0 ; // keeps the current z position. 0 is all the way up.
int ztarget = 0 ; // target position
int direction = 0 ;
int enableState = DISABLED ;
int doStep = 0 ;

// create an instance of the stepper class, specifying
// the number of steps of the motor and the pins it's
// attached to
Stepper stepper(STEPS, STEPPER_PIN_A1, STEPPER_PIN_A2, STEPPER_PIN_B1, STEPPER_PIN_B2, USE_HALF_STEP);


void setup()
{
 pinMode(IN_DIR_PIN, INPUT) ; 
 pinMode(IN_STEP_PIN, INPUT) ;
 pinMode(IN_ENABLE_PIN, INPUT) ;
 pinMode(IN_HOME_SWITCH_PIN, INPUT);
 pinMode(IN_Z_LIM_PROX_PIN, INPUT);
 pinMode(OUT_Z_LIM_PROX_PIN, OUTPUT);
 pinMode(STEPPER_ENABLE_PIN, OUTPUT) ;  
 pinMode(STEPPER_PIN_A1, OUTPUT) ;
 pinMode(STEPPER_PIN_A2, OUTPUT) ;
 pinMode(STEPPER_PIN_B1, OUTPUT) ;
 pinMode(STEPPER_PIN_B2, OUTPUT) ; 
   
  // set the speed of the motor to  RPMs. Use something adapted to your particular stepper
  stepper.setSpeed(200)
}

void readButton() {
  zButtonState = digitalRead(IN_HOME_SWITCH_PIN); 
}

void homePen() {
   if (zButtonState != zLastButtonState) {
   if (zButtonState == LOW) {
    zButtonPushCounter++ ;
  if (zButtonPushCounter % 2 == 0) {
      homeUp();
  } else {
      homeDown();
      }
     }
    }
 zLastButtonState = zButtonState;
}

void homeUp() {
    digitalWrite(STEPPER_ENABLE_PIN, HIGH);         // enable the L293D output
  while (true) {
  zProxLimState = digitalRead(IN_Z_LIM_PROX_PIN) ;  // check if we have activated the upper limit sensor
 
  if (zProxLimState == HIGH) {
    zpos = 0 ;                                      // we are at the top. Let this position be 0
    digitalWrite(OUT_Z_LIM_PROX_PIN, HIGH);         // Notify the hierarchy we reached the limit
    break ;     // get outta here
   }
    stepper.step(UP) ;                 
  }
  digitalWrite(STEPPER_ENABLE_PIN, LOW); // disable the L293D output
}

void homeDown() {
  digitalWrite(STEPPER_ENABLE_PIN, HIGH); // enable the L293D output
  ztarget = ZLENGTH - zpos ;
  for(int i = 0; i <= ztarget; i++) {
     stepper.step(DOWN) ;
     zpos = zpos + 1 ; // update position counter
     if (zpos > 0) {
             digitalWrite(OUT_Z_LIM_PROX_PIN, LOW);  //
     }
     if (zpos == ZLENGTH) {
            digitalWrite(OUT_Z_LIM_DIST_PIN, HIGH) ;         // Advertise we have reached the lower limit
     } else if (zpos < 100) {
            digitalWrite(OUT_Z_LIM_DIST_PIN, LOW) ;          // all OK
     }
  }
 digitalWrite(STEPPER_ENABLE_PIN, LOW); // disable the l293D output
}

void listenCommands(){
direction = digitalRead(IN_DIR_PIN);
enableState = digitalRead(IN_ENABLE_PIN);
doStep = digitalRead(IN_STEP_PIN);
}

void doStuff(){
  if (enableState == ENABLED) {
         if (direction == 1) {
              homeUp();
         }
         if (direction == 0) {
               homeDown();
         }
  }
 
 
  if (enableState == DISABLED) {
       digitalWrite(STEPPER_ENABLE_PIN, LOW); // disable the L293D output
  }
}

void loop()
{
  readButton() ;      // check manual button
  homePen() ;         // do manual pen up / pen down
  listenCommands();   // check for signals
  doStuff();          // take the actual actions
}



Cheers,

K.