Stepper motor not reversing properly

Hello,
I am currently trying to build a laser PCB etcher. The idea is that my Arduino Mega 2560 will read information from an SD card, and then control 2 stepper motors (X and Y axis) and eventually, a laser. What I’ve done is converted a CAD drawing to a JPG (not to scale, yet), then checked the colour of each pixel, left to right, up to down. I’ve set it so that if the pixel is black (no copper on PCB) a 0 is written to the output. If it’s red (copper on PCB) it outputs a 1. When it reaches the end of each line, a new output file is made.

What I’m trying to do is read each output file, 1 by 1 for now. If a 0 is read, it turns the laser (LED) off, if a 1 is read, it turns on, this works as it should. However at the end of each output file, the Y axis should move a bit, and the X axis should return to it’s normal position, here is where the problem lies.
Here is my code:

  #include <SD.h>
  #include <Servo.h> //Servo temporarily used instead of second stepper motor for Y axis
  int x,y,filecount,index,rewind,servpos;
  File file;
  String fileindex,info;
  Servo serv;   
  const int dirpin=2; //Direction and step pins used by the driver
  const int steppin=3;
  const int servpin=4; //Y axis servo
  const int ledpin=5; //LED used instead of laser
  
  /*
  SD pin connections:
  MISO - 50
  Clock - 52
  MOSI - 51
  Chip select - 53
  /*/
  
  void setup(){
    Serial.begin(9600);
    if (!SD.begin(53)){
      Serial.println("Error");
      return;
    }
    serv.attach(servpin);
    pinMode(ledpin,OUTPUT);
    pinMode(dirpin,OUTPUT);
    pinMode(steppin,OUTPUT);
    Serial.println("Initilization complete");
    
    readSize();  //Gets the number of output files on SD card
    
    Serial.println(filecount);
    
    for (index=1;index<filecount;index++){   //Loop for filecount number of files
      
      fileindex = "out"+String(index)+".txt";   //Assign a value to the filename value  out[fileindex].txt
      char filename[fileindex.length()+1];              //For example out23.txt 
      fileindex.toCharArray(filename, sizeof(filename));
      
      file = SD.open(filename);
      if (file){
        digitalWrite(dirpin,LOW);  //Set the direction to clockwise
        while (file.available()){
        digitalWrite(steppin,LOW);
        digitalWrite(steppin,HIGH);
        delayMicroseconds(70); //Let the motor turn
        x = file.read();
        switch (x){
          case 48:  // X reads as 0 (laser off)
            digitalWrite(ledpin,LOW);
            break;
          case 49:  // X reads as 1 (laser on)
            digitalWrite(ledpin,HIGH);
            break;
        }
      }
      //Output file (number) has been read, move on to the next
      file.close();     
    }
    nextLine(); //Rewind the X axis and move the Y axis
  }
  }
  
  void loop(){} //Nothing happens after setup
  
  void nextLine()
  {
     delay(100);
     digitalWrite(2,HIGH); //Set the direction to counter-clockwise
     for (rewind=0;rewind<6500;rewind++){  //Make a full revolution
       digitalWrite(steppin,LOW);
       digitalWrite(steppin,HIGH);
       delayMicroseconds(70);
     }
     servpos+=1;          //Move the Y axis
     serv.write(servpos);
     delay(100);
  }

  void readSize()
  {
    file = SD.open("count.txt");   //Text file containing the number of output files
    if (file){
      while (file.available()){
        x = file.read();
        switch (x){
          case 48:
            info += "0";
            break;
          case 49:
            info += "1";
            break;
          case 50:
            info += "2";
            break;
          case 51:
            info += "3";
            break;
          case 52:
            info += "4";
            break;
          case 53:
            info += "5";
            break;
          case 54:
            info += "6";
            break;
          case 55:
            info += "7";
            break;
          case 56:
            info += "8";
            break;
          case 57:
            info += "9";
            break;
        }
      }
      file.close();
      filecount = info.toInt();  //Converts the string to int filecount
    }
    info="";
    return;
  }

The error I’m getting is that when the program reads the output file, the motor spins clockwise as it should. However when it reaches the end, and it’s supposed to ‘rewind’ the stepper motor, the motor just jumps slightly and continues in the clockwise direction. The Y axis servo moves as it should, but not the stepper motor. I’ve tried using the code in the nextline function inside the setup, but that didn’t work either. The motor, driver and voltages are fine, turning it either direction works with different code.

Stepper motor datasheet: http://www.electrokit.com/productFile/download/2610
Stepper motor driver: http://www.electrokit.com/productFile/download/2981
Attached is a load of example output files along with the original test image if anyone is interested.

Delboy

Output files.zip (9.46 KB)

Looking at some of the delays you have makes me think you are trying to make the stepper accelerate instantly to a high speed (70us delay is 14kHz step rate, ignoring the other code).

Motors cannot suddenly jump to high speed, the acceleration is limited by the MoI of the rotor and load, and if you exceed it the motor will mis-step (which may be the issue here).

Try first just making the speed a lot slower, then think about adding acceleration (perhaps the AccelStepper library is more appropriate?)

       digitalWrite(steppin,LOW);
       digitalWrite(steppin,HIGH);

This code creates a stepper pulse that is virtually zero length. You need a short (50 microseconds?) delay between the low and the high

and delayMicroseconds(70);

70 usecs is much too short a time between stepper motor steps. 70 usecs would imply 14,286 steps per second or 71 rps or 4200 rpm. 700 usecs would still be fast. I would try 70 millisecs to start with.

...R

This code creates a stepper pulse that is virtually zero length. You need a short (50 microseconds?) delay between the low and the high

No that will be fine.

70 usecs is much too short a time between stepper motor steps. 70 usecs would imply 14,286 steps per second or 71 rps or 4200 rpm. 700 usecs would still be fast. I would try 70 millisecs to start with.

Yes that is the problem, you are trying to drive the motor faster than it will go.

A bit out with your 71 revs/sec gentlemen. According to the linked datasheets a 70uS step delay with that motor and driver equates to roughly 4.5 revs/sec. Still probably too fast though given no accel curve. Partcularly as the motor is probably being current starved by that driver and definitely “voltage starved” for “max performance”.

The reason it goes “forward” but not in “reverse” is probably down to the (I suspect substantial) added delay of the file.read() included in the “forward” step code. A really bad idea BTW to include that in the step delay OP.

Grumpy_Mike:

This code creates a stepper pulse that is virtually zero length. You need a short (50 microseconds?) delay between the low and the high

No that will be fine.

I fully concede that 50 usecs is overkill, but the datasheet for the Allegro stepper drivers says that the high and low of the pulses must be at least 1 usec.

...R

Robin2: I fully concede that 50 usecs is overkill, but the datasheet for the Allegro stepper drivers says that the high and low of the pulses must be at least 1 usec.

And what pulse width do you think:-

  digitalWrite(pin,HIGH);
  digitalWrite(pin,LOW);

Will give you?

Let me tell you, 4uS

Interesting. I didn't think it would be that slow.

...R

Look at the code for digitalWrite it does a lot of work.

Hello again,
after “some” tweaking I’ve finally achieved not a perfect code, but a code heading in the right direction.

MarkT:
Try first just making the speed a lot slower, then think about adding
acceleration (perhaps the AccelStepper library is more appropriate?)

This library proved very helpful, thank you for the suggestion.

I changed the delay in the loop to 50ms instead, which proved to be seemingly best for now.
I also changed the format of the output file that lies on the SD card. Instead of being many files, one for each line on the X axis, it is now one big file, with the number 2 symbolising the end of each line. This helped to remove some loops, which made things a lot easier.
The “runToNewPosition(int)” function in the AccelStepper library proved to be exactly what I needed, since it “stops” the code until the specified position has been reached by the stepper motor.
My current code which is far from done:

#include <SD.h>
  #include <AccelStepper.h>
  AccelStepper stepper(1,9,8);
  const int ledpin=5;
  File file;
  int x,pos;
  
  void setup()
  {
    Serial.begin(9600);
    pinMode(ledpin,OUTPUT);
    if (!SD.begin(53))
    {
      Serial.println("Error");
      return;
    }
    stepper.setMaxSpeed(10000);
    stepper.setSpeed(4000);
    stepper.setAcceleration(6000);
    file=SD.open("output.txt");
    pos=1000;
    stepper.runToNewPosition(pos);
    if (file)
    {
      while (file.available())
      {
        pos+=100;
        x=file.read();
        stepper.runToNewPosition(pos);
        
        switch (x)
        {
          case 48:// 0
            digitalWrite(ledpin,LOW); // Laser off
            break;
          case 49: // 1
            digitalWrite(ledpin,HIGH); // Laser on
            break;
          case 50: // 2
            Serial.println(-pos);
            stepper.runToNewPosition(0);
            pos=0;
            // Insert Y axis stepper motor here
            break;
        }
        Serial.println(char(x));
        delay(50);
      }
      file.close();
      digitalWrite(ledpin,LOW);
    }
    
    stepper.runToNewPosition(0);
  }
  
  
  void loop(){}

Delboy