A simple approach to a stepper controller, which got a little complicated.

Here’s the story, I’m working on a cnc machine with simple circuitry and software. I’m at the home stretch really. It’s built out of an old scanner(most of which is gone except the base of the body, and the 3 motors it had). The machine isn’t quite finished but the motor driver is right at the edge of being done as a prototype. Basically the arduino takes input from the lpt port and moves the motor according to step and direction pulses. Currently the code works great for one motor. However, as soon as I step a second motor in the main loop, both motors will start glitching out when you step them. If I reset the Arduino, I can start with the second motor just fine. I can move it back forth, wait a second, then move it some more, but as soon as I step the first motor again, they both glitch out whenever I step one or the other. I’m using the stepper library that came with the arduino, simply because it is simple, and works astonishingly well with one motor. So I’m wondering then if the library is at fault for not being able to handle more than one stepper motor, or is it the micro-controller not being able to keep up. I do have three atmega8s that I can use, which are cheaper than some controllers I’ve seen, but I’m also wondering if there is a way to keep all three motors on one chip, since there are enough pins for both input and output, with out sacrificing the serial port for programming.

At any rate here is the code, any Ideas?

//Make sure this is in your library
//It probably is, but I'm just suggesting.
#include <Stepper.h>

//Stepper pin setup
Stepper stX(200, 2,3,4,5);
Stepper stY(200, 6,7,8,9);

//input pins
int stXstppin = A0;
int stXdirpin = A1;

int stYstppin = A2;
int stYdirpin = A3;


//pin state variables
int stXstate = 0;
int stXlstate = 0;
int stXdirstate = 0;
boolean stXstp = false;

int stYstate = 0;
int stYlstate = 0;
int stYdirstate = 0;
boolean stYstp = false;

// Switch case Variable
int stTurn = 1;

//--------------------------------------

void setup() {
  //Set up input pins.
  pinMode(stXstppin, INPUT);
  pinMode(stXdirpin, INPUT);
  pinMode(stYstppin, INPUT);
  pinMode(stYdirpin, INPUT);
  stX.setSpeed(150);
  stY.setSpeed(150);

}

//--------------------------------------

void loop() {
  // Switch between the x and y stepper every loop.

  switch (stTurn) {
  case 1:
  //check for state of stepper 1 step pin and set wether or not to step
  //steps on rising edge
    stXstate = digitalRead(stXstppin);
    if (stXstate != stXlstate){
      if (stXstate == HIGH){
        stXdirstate = digitalRead(stXdirpin);
        if(stXdirstate == HIGH) {
          stX.step(-1);  
        }
        else{
          stX.step(1);  
        }
      }
    }
    stXlstate = stXstate;
    //comment out the next line to just use the x stepper
    //uncomment so the loop switches between both, but this
    //will glitch it out.
  //  stTurn = 2;
    break;

  case 2:
    stYstate = digitalRead(stYstppin);
    if (stYstate != stYlstate){
      if (stYstate == HIGH){
        stYdirstate = digitalRead(stYdirpin);
        if(stYdirstate == HIGH) {
          stY.step(-1);  
        }
        else{
          stY.step(1);  
        }
      }
    }
    stYlstate = stYstate;
    stTurn = 1;
    break;
  }
}

Do both steppers behave the same i.e. if you move stX first then stY do you get the same behaviour as when you move stY first and then stX?

How fast is the PC writing to the LPT port? Is it possible that it's so fast that the delay waiting for the first motor to complete its step is causing the second stepper to miss its input? You might be able to test for that by slowing down the PC controlling application so that both steppers are moving at a crawl. Alternatively, write a test sketch that just moves both steppers in a hard-coded pattern and confirm they both do work - this would confirm the problem is to do with your control logic not the steppers.

Do both steppers behave the same i.e. if you move stX first then stY do you get the same behaviour as when you move stY first and then stX?

Exactly. After a reset, whichever motor I move first works fine until I step the other motor. After that, stepping one motor makes it rotate real hard and loud, like the timing is off, while the other motor jitters around back and fourth.

I Haven't had a go at hard coding the two motors in the same program yet. I was thinkng I'd hear that the Stepper Library doesn't do multiple motors ha ha. I'll work it out and see what happens.

The timing is set down as low as possible at 970hz. No change from 8Khz, I still get the same result.

Thanks!

neato3000:
The timing is set down as low as possible at 970hz. No change from 8Khz, I still get the same result.

That's still only allowing 1ms for the motor to complete a step. If you can't get your link to run any slower than that then I'd say it was time to take the link out of the equation and just run a hard-coded sequence of both motors so you can establish whether the problem is reading your interface, or moving the motors on command.

//Make sure this is in your library
//It probably is, but this program won’t run without it.
#include <Stepper.h>

//Stepper pin setup
Stepper stX(200, 2,3,4,5);
Stepper stY(200, 6,7,8,9);

//--------------------------------------

void setup() {

  stX.setSpeed(100);
  stY.setSpeed(100);

}
void loop() {
  
  stX.step(100);
  stY.step(100);
  delay(100);
  stX.step(-100);
  stY.step(-100);
  delay(100);  
  
}

This works just fine, they each take a turn moving 100 steps in one direction wait, then take turns going back 100 steps. No problems.

//Make sure this is in your library
//It probably is, but this program won't run without it.
#include <Stepper.h>

//Stepper pin setup
Stepper stX(200, 2,3,4,5);
Stepper stY(200, 6,7,8,9);

//--------------------------------------

void setup() {

  stX.setSpeed(100);
  stY.setSpeed(100);

}
void loop() {
  for (int i = 0; i < 100; i++){
  stX.step(1);
  stY.step(1);
  }
  delay(100);
  for (int i2 = 0; i2 < 100; i2++){
  stX.step(-1);
  stY.step(-1);
  }
  delay(100);  
  
}

This works just as well. Both motors run 100 steps in each direction at virtually the same time with no hangup.

Must be my code at this point ha ha.

PeterH:
That’s still only allowing 1ms for the motor to complete a step. If you can’t get your link to run any slower than that then I’d say it was time to take the link out of the equation and just run a hard-coded sequence of both motors so you can establish whether the problem is reading your interface, or moving the motors on command.

Well I thought about that, but that would mean that the stepper library is super heavy. 4 conditions, then a function call per loop doesn’t sound like a lot as far as my code goes. Also only running one motor has proven to work from the lowest timing up to the default 8khz. So doubling the number of motors doesn’t seem like it should reduce my time by an 1/8.

I also get the same exact result without the switch case:

//Make sure this is in your library
//It probably is, but this program won't run without it.
#include <Stepper.h>

//Stepper pin setup
Stepper stX(200, 2,3,4,5);
Stepper stY(200, 6,7,8,9);

//input pins
int stXstppin = A0;
int stXdirpin = A1;

int stYstppin = A2;
int stYdirpin = A3;


//pin state variables
int stXstate = 0;
int stXlstate = 0;
int stXdirstate = 0;
boolean stXstp = false;

int stYstate = 0;
int stYlstate = 0;
int stYdirstate = 0;
boolean stYstp = false;

//--------------------------------------

void setup() {
  //Set up input pins.
  pinMode(stXstppin, INPUT);
  pinMode(stXdirpin, INPUT);
  pinMode(stYstppin, INPUT);
  pinMode(stYdirpin, INPUT);
  stX.setSpeed(150);
  stY.setSpeed(150);

}

//--------------------------------------

void loop() {

  //check for state of stepper 1 step pin and set wether or not to step
  //steps on rising edge
    stXstate = digitalRead(stXstppin);
    if (stXstate != stXlstate){
      if (stXstate == HIGH){
        stXdirstate = digitalRead(stXdirpin);
        if(stXdirstate == HIGH) {
          stX.step(-1);  
        }
        else{
          stX.step(1);  
        }
      }
    }
    stXlstate = stXstate;

    stYstate = digitalRead(stYstppin);
    if (stYstate != stYlstate){
      if (stYstate == HIGH){
        stYdirstate = digitalRead(stYdirpin);
        if(stYdirstate == HIGH) {
          stY.step(-1);  
        }
        else{
          stY.step(1);  
        }
      }
    }
    stYlstate = stYstate;
}

That seems to me to point to a timing problem in the way the sketch reads the parallel port. When you change the output baud rate, do you also change the pulse length or do you have the same length pulses just spaced further apart?

0.5ms on, 0.5ms off. I can set either any where from 1-500000 nano seconds. The default is 5000ns. I’m running LinuxCNC if that helps. Are you thinking maybe a shorter pulse width? Using setSpeed does effect the delay inside of the library… So I’m going to play with that as well today.

I changed up the code a bit last night, trying to simplify it with arithmetic instead of conditional statements. Buut still no dice. I still get the same exact results. Is this easier on the controller than the nested conditions?

//Make sure this is in your library
//It probably is, but this program won't run without it.
#include <Stepper.h>

//Stepper pin setup
Stepper stX(200, 2,3,4,5);
Stepper stY(200, 6,7,8,9);

//input pins
const int stXstppin = A0;
const int stXdirpin = A1;

const int stYstppin = A2;
const int stYdirpin = A3;


//pin state variables
int stXstate = 0;
int stXLstate = 0;
int stXdirstate = 0;
int stXstep = 0;

int stYstate = 0;
int stYLstate = 0;
int stYdirstate = 0;
int stYstep = 0;


//--------------------------------------

void setup() {
  //Set up input pins.
  pinMode(stXstppin, INPUT);
  pinMode(stXdirpin, INPUT);
  pinMode(stYstppin, INPUT);
  pinMode(stYdirpin, INPUT);
  stX.setSpeed (200);
  stY.setSpeed (200);
}

//--------------------------------------

void loop() {

  stXstate = digitalRead(stXstppin);
  stXdirstate = digitalRead(stXdirpin);
  stYstate = digitalRead(stYstppin);
  stYdirstate = digitalRead(stYdirpin);

//      0(0-(0*2)) = 0
//      0(0-(1*2)) = 0
//      1(1-(0*2)) = 1 
//      1(1-(1*2)) = -1 

  if (stXstate > stXLstate){
      stXstep = stXstate * (stXstate - (stXdirstate * 2)); 
  }
  stX.step(stXstep);
  stXstep = 0;
  
  if (stYstate > stYLstate){
      stYstep = stYstate * (stYstate - (stYdirstate * 2));
  }
  stY.step(stYstep);
  stYstep = 0;

  stXLstate = stXstate;
  stYLstate = stYstate;

}

Well, I'm just going to use three different microcontrollers for now. I messed with the sestSpeed and was able to keep the loop between 28 and 124 microseconds. They were however still glitchy. I'm not sure why the code can only run one motor, but for now I have come up with several different ways to run one motor on one controller very well ha ha. I'm off to buy another bread board, Thanks for the help. If you think of anything, let me know.