Help! installation involving four nema 34 stepper motors and accelstepper.h

Hello Guys and Girls,

I am building an installation that has two X,Y moving carriages on either side of a room (so up/down - side/side). I have built a chassis/ frame using the coreXY method: http://corexy.com and have used this example to test the movement of the system and see if it works, which it does, phew! :

This code is in the public domain...

You can: copy it, use it, modify it, share it or just plain ignore it!
Thx!

*/

#include "AccelStepper.h" 
// Library created by Mike McCauley at http://www.airspayce.com/mikem/arduino/AccelStepper/

// AccelStepper Setup
AccelStepper stepperX(1, 2, 3);   // 1 = Easy Driver interface
                                  // UNO Pin 2 connected to STEP pin of Easy Driver
                                  // UNO Pin 3 connected to DIR pin of Easy Driver
                                  
AccelStepper stepperZ(1, 5, 6);   // 1 = Easy Driver interface
                                  // UNO Pin 5 connected to STEP pin of Easy Driver
                                  // UNO Pin 6 connected to DIR pin of Easy Driver

// Stepper Travel Variables
long TravelX;  // Used to store the X value entered in the Serial Monitor
long TravelZ;  // Used to store the Z value entered in the Serial Monitor

int move_finished=1;  // Used to check if move is completed


void setup() {
  
  Serial.begin(9600);  // Start the Serial monitor with speed of 9600 Bauds
  
// Print out Instructions on the Serial Monitor at Start
  Serial.println("Enter Travel distance seperated by a comma: X,Z ");
  Serial.print("Enter Move Values Now: ");

//  Set Max Speed and Acceleration of each Steppers
  stepperX.setMaxSpeed(400.0);      // Set Max Speed of X axis
  stepperX.setAcceleration(500.0);  // Acceleration of X axis

  stepperZ.setMaxSpeed(400.0);      // Set Max Speed of Y axis slower for rotation
  stepperZ.setAcceleration(500.0);  // Acceleration of Y axis

}


void loop() {

while (Serial.available()>0)  { // Check if values are available in the Serial Buffer

  move_finished=0;  // Set variable for checking move of the Steppers
  
  TravelX= Serial.parseInt();  // Put First numeric value from buffer in TravelX variable
  Serial.print(TravelX);
  Serial.print(" X Travel , ");
  
  TravelZ= Serial.parseInt();  // Put Second numeric value from buffer in TravelZ variable
  Serial.print(TravelZ);  
  Serial.println(" Y Travel ");
  
  stepperX.moveTo(TravelX);  // Set new move position for X Stepper
  stepperZ.moveTo(TravelZ);  // Set new move position for Z Stepper
  
  delay(1000);  // Wait 1 seconds before moving the Steppers
  Serial.print("Moving Steppers into position...");
  }

// Check if the Steppers have reached desired position
  if ((stepperX.distanceToGo() != 0) || (stepperZ.distanceToGo() !=0)) {
    
    stepperX.run();  // Move Stepper X into position
    stepperZ.run();  // Move Stepper Z into position
    
  }

// If move is completed display message on Serial Monitor
  if ((move_finished == 0) && (stepperX.distanceToGo() == 0) && (stepperZ.distanceToGo() == 0)) {
    Serial.println("COMPLETED!");
    Serial.println("");
    Serial.println("Enter Next Move Values (0,0 for reset): ");  // Get ready for new Serial monitor values
    move_finished=1;  // Reset move variable
  }
}

the trouble is that i want to have this thing running constantly without me having to type inputs each time!

a feasible option for this is the random stepper function:

#include <AccelStepper.h>

// Define a stepper and the pins it will use
AccelStepper stepper; // Defaults to AccelStepper::FULL4WIRE (4 pins) on 2, 3, 4, 5

void setup()
{  
}

void loop()
{
    if (stepper.distanceToGo() == 0)
    {
 // Random change to speed, position and acceleration
 // Make sure we dont get 0 speed or accelerations
 delay(1000);
 stepper.moveTo(rand() % 200);
 stepper.setMaxSpeed((rand() % 200) + 1);
 stepper.setAcceleration((rand() % 200) + 1);
    }
    stepper.run();
}

this would be better because it would look great! but as is it might break off the wall if the trolly was randomly pulled to far left/right/up/down

It would be awesome if someone could shed some light onto how to stop this random movement from going to far out of the sides of my frame; since this is a 2 by 2 meter metal structure .

sorry for being such a noob, i wanna learn this stuff

Cheers, in advance :slight_smile:

Add some physical limit switches at the ends of the travel. When you hit the switch, reverse the motion.

You need some switches anyway to define a "home" position for the steppers. Otherwise there's no feedback for the Arduino to know where they are at any time.

As MorganS said you need some limit switches to tell where it's at there east to get for free most times out of old printers great place to find parts because most have lots of limit switches.

That would have been a great idea but i have already engineered the parts with no room for limit switches, i was hoping that i could calibrate it so that; when I go to start it up I can move the stage to bottom left and call that 0,0 and then move the stage to top right and call that 1000, 1000 (working out the amount of rotations needed to get there, or something like that ? and then have code that will move around randomly within those constraints? it doesn't need to go to the absolute corners, i just want something that will move around on its own accord for now. After my deadline I will try and add some limiting switches.

would there be a way of editing the random movement code or other code so that it had a definable boundary?

thanks

sharkie:
i was hoping that i could calibrate it so that; when I go to start it up I can move the stage to bottom left and call that 0,0 and then move the stage to top right and call that 1000,

If no damage will be caused by trying to drive the motor beyond the end of the carriage’s travel so that it misses steps then you could establish the zero by simply running the motor towards that position for a number of steps that is greater than could ever be needed to move it the full length of the track. When that “movement” has been completed the Arduino can then know that the motor is at the ZERO position. That would have to be done every time the Arduino is reset or switched on.

If damage would be caused then there is no option but to fit some sort of limit switch. A slotted optical switch would not take much space.

It should be possible to count the number of steps needed to get from the ZERO position to the other end of the travel and build that into your program.

…R
Stepper Motor Basics
Simple Stepper Code

Well you always should keep track of the total steps taken. Add forwards and subtra t backwards. Then you can write your code to have travel limits.

If damage would be caused then there is no option but to fit some sort of limit switch. A slotted optical switch would not take much space.

yea the frame is all made of steel and wouldn’t mind a bash, also the travel of the stage will be well inside the outer limits of possible movements.

The thing is I’m not sure how to make the code run a sequence of movements with the accelerate function?

could i use this code?

// MultiStepper.pde
// -*- mode: C++ -*-
// Use MultiStepper class to manage multiple steppers and make them all move to 
// the same position at the same time for linear 2d (or 3d) motion.

#include <AccelStepper.h>
#include <MultiStepper.h>

// EG X-Y position bed driven by 2 steppers
// Alas its not possible to build an array of these with different pins for each :-(
AccelStepper stepper1(AccelStepper::FULL4WIRE, 2, 3, 4, 5);
AccelStepper stepper2(AccelStepper::FULL4WIRE, 8, 9, 10, 11);

// Up to 10 steppers can be handled as a group by MultiStepper
MultiStepper steppers;

void setup() {
  Serial.begin(9600);

  // Configure each stepper
  stepper1.setMaxSpeed(100);
  stepper2.setMaxSpeed(100);

  // Then give them to MultiStepper to manage
  steppers.addStepper(stepper1);
  steppers.addStepper(stepper2);
}

void loop() {
  long positions[2]; // Array of desired stepper positions
  
  positions[0] = 1000;
  positions[1] = 50;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); // Blocks until all are in position
  delay(1000);
  
  // Move to a different coordinate
  positions[0] = -100;
  positions[1] = 100;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); // Blocks until all are in position
  delay(1000);
}

I have tried this code but it doesn’t seem to use the accelerate function ?

Also is there a line of code that will stop the random function from going further than say -100 to +100?

thanks

I would generate a random number, then check if that is going to exceed the limit. If it is OK, then send that to the motors. If not then you could simply reverse the direction or run to the limit and stop early.

What is this supposed to look like? Real random numbers will just make it wobble. To make it look like a drunk staggering around the room, you need some strategies to make it less random.

okay maybe it would be easier to just make a sequence of coordinates that the motors follow?

if so would it be a simple string of commands with the accel stepper library?

sharkie:
I have tried this code but it doesn't seem to use the accelerate function ?

It looks like the multiStepper version of the library does not support acceleration.

I'm not sure, from your description so far, if you actually need the multiStepper feature. Its purpose is to ensure that all the motors complete all their steps in the exact same time - as would be needed for a CNC machine or 3D printer when it is following an exact diagonal path.

However if it is OK for your different axes to move at the same time but perhaps one will finish its move before the other, then the regular AccelStepper will be suitable. It can manage several stepper motors with acceleration and deceleration.

...R

However if it is OK for your different axes to move at the same time but perhaps one will finish its move before the other, then the regular AccelStepper will be suitable

Thanks for your help so far Robin2, so with your advice I have written this little piece of code. Does this look okay to you? or is there an easier way of doing what i want.

And yes it is true that I do not need all the motors complete all their steps in the exact same time

#include <AccelStepper.h>


AccelStepper stepperX(AccelStepper::DRIVER, 2, 3);
AccelStepper stepperY(AccelStepper::DRIVER, 5, 6);



void setup()
{
  stepperX.setMaxSpeed(200.0);
  stepperX.setAcceleration(100.0);


  stepperY.setMaxSpeed(300.0);
  stepperY.setAcceleration(300.0);


}

void loop()
{
  stepperX.moveTo(-300);

  stepperY.moveTo(-900);

  if (stepperX.distanceToGo() == 0)
    stepperX.moveTo(-stepperX.currentPosition());

  if (stepperY.distanceToGo() == 0)
    stepperY.moveTo(-stepperY.currentPosition());

  stepperX.run();
  stepperY.run();

  stepperX.moveTo(300);

  stepperY.moveTo(900);

  if (stepperX.distanceToGo() == 0)
    stepperX.moveTo(-stepperX.currentPosition());

  if (stepperY.distanceToGo() == 0)
    stepperY.moveTo(-stepperY.currentPosition());

  stepperX.run();
  stepperY.run();

  // more comands to follow?

I would try something like this as it avoids repetitive code and allows for more easily changing the destination values. Note that I have not tested it.

#include <AccelStepper.h>


AccelStepper stepperX(AccelStepper::DRIVER, 2, 3);
AccelStepper stepperY(AccelStepper::DRIVER, 5, 6);

boolean nextMove = true;
byte moveNum = 1;
int xPos = -300;
int yPos = -900;

void setup()
{
    stepperX.setMaxSpeed(200.0);
    stepperX.setAcceleration(100.0);

    stepperY.setMaxSpeed(300.0);
    stepperY.setAcceleration(300.0);


}

void loop() {
    
    if (nextMove == true) {
        nextMove = false;
        stepperX.moveTo(xPos);
        stepperY.moveTo(yPos);
    }


    if (stepperX.distanceToGo() == 0 && stepperY.distanceToGo == 0) {
        nextMove = true;
        if (moveNum == 0) {
            xPos = -300;
            yPos = -900;
            moveNum = 1;
        }
        else {
            xPos = 300;
            yPos = 900;
            moveNum = 0;
        }
    }

    stepperX.run();
    stepperY.run();

}

…R

Thankyou Robin2! that helped me understand neatening things up a little :slight_smile:

I managed to find some pretty great code (i think) from an american university website. Basically it follows a table type thing of coordinates and allocates those numbers to different motors, then read the next line of numbers in the table and move to those coordinates, over and over again. Perfect for what I wanted!

the trouble is that the fourth motor defined as stepper2R doesn’t seem to move at all?

i would be really grateful if you could shed some light on this.

//code from   http://dm.risd.edu/pbadger/PhysComp/index.php?n=Devices.DRV8825StepperDriverBoard    


#include <AccelStepper.h>



// Define some steppers and the pins the will use
//AccelStepper stepper1(AccelStepper::DRIVER, stepPin, dirPin);
AccelStepper stepper1L(AccelStepper::DRIVER, 2, 3);
AccelStepper stepper2L(AccelStepper::DRIVER, 5, 6);
AccelStepper stepper1R(AccelStepper::DRIVER, 8, 9); 
AccelStepper stepper2R(AccelStepper::DRIVER, 11, 12);

int holdTime;

int moves[] {
  // stepper1 position, stepper2 position,  stepper right1, stepper right2,  hold time (mS)
  // stepper positions are absolute coordinates not steps to move
   300, 300, 300, 300,  500,
   300, 300, 300, 300,  500,
   -300, -300, -300, -300,  500,
   -500, -500, -500, -300,  2000,  // 2 second delay after move
   0,   0,    0,   0,   0
}; 
// add more moves at will, nothing will break 
// you must use three entries for every move.

int maxIndex = (sizeof(moves) / sizeof(moves[0])) - 1;
// get max index
// sizeof(moves) reports in total bytes
// divide by first element ( sizeof(moves[0]) ) to get total
// entries in the array. Subtract 1 to shift entry counting from
// zero as the first element, instead of one as first element.

int indexCount = 0; //counter for the array

void setup()
{//could sack this top bit off?
  //Serial.begin(57600);  // don't forget to set Serial Monitor for 57600 baud
  //Serial.println("start");
  // set speeds and accel's in pulses per second
  // I was using divide by 4 microstepping (shunt on M1)
  // you will need to adjust these number for other divisors
  // (shunt settings) experiment!

  stepper1L.setMaxSpeed(200.0);
  stepper1L.setAcceleration(160.0);

  stepper2L.setMaxSpeed(200.0);
  stepper2L.setAcceleration(160.0);

  stepper1R.setMaxSpeed(200.0);
  stepper1R.setAcceleration(160.0);

  stepper2R.setMaxSpeed(200.0);
  stepper2R.setAcceleration(160.0);
}
void loop()
{
  if (millis() % 100 == 0) { // for debugging don't print too often
    // Serial.println(stepper2.currentPosition());
  }
  // If both steppers have completed move, choose next position
  if   (stepper1L.distanceToGo() == 0 && stepper2L.distanceToGo() == 0 
     && stepper1R.distanceToGo() == 0 && stepper2R.distanceToGo() == 0 ) {
    if (holdTime > 0){
      delay(holdTime);
    }
    stepper1L.moveTo(moves[indexCount]);
    stepper2L.moveTo(moves[indexCount + 1]);  // next entry in moves array is stepper 2
    stepper1R.moveTo(moves[indexCount + 1]);
    stepper2R.moveTo(moves[indexCount + 1]);
    holdTime = moves[indexCount + 2];

    // print entries for debugging - feel free to comment out
    //Serial.print(moves[indexCount]);
    //Serial.print("\t"); // prints a tab character
    //Serial.print(moves[indexCount + 1]); // stepper 2
    //Serial.print("\t"); // prints a tab character
    //Serial.println(moves[indexCount + 2]); // hold time

    // choose next postion - won't run til the current position finishes
    indexCount = indexCount + 5; // index by 3's, 2 steppers + hold time
    if (indexCount > maxIndex) indexCount = 0; // at end, wrap around to beginning
  }

  stepper1L.run();  // run() makes all the magic happen behind the scenes
  stepper2L.run();
  stepper1R.run();  // run() makes all the magic happen behind the scenes
  stepper2R.run();
}
    stepper1L.moveTo(moves[indexCount]);

stepper2L.moveTo(moves[indexCount + 1]);  // next entry in moves array is stepper 2
    stepper1R.moveTo(moves[indexCount + 1]);
    stepper2R.moveTo(moves[indexCount + 1]);


[/qquote]
So the 3rd and 4th steppers always follow the 2nd and those other numbers you entered are useless?



> the trouble is that the fourth motor defined as stepper2R doesn't seem to move at all?


Check your wiring. Can you make it move by itself?

You have not provided a diagram to illustrate your machine. I wonder if motors 1R and 1L are connected to the same piece of metal - one on each side? If so you could drive both of them with the same set of pulses to ensure they stay exactly in step.

...R

yes sorry, it is quite a complicated thing and i was trying to keep it simple.

I wonder if motors 1R and 1L are connected to the same piece of metal

Yes. All of the motors are connected to the same piece of metal 1L And 2L moving the left side and 1R and 2R moving the right side. Here are some pictures of the set up.

thank you for your patience

Images from Reply #15 so we don’t have to download them. See this Image Guide

a74693c707f5e45f1d8cb2f0f3b20a1f8bd4fa00.jpg

f00e98f21b0b45ef80d02d64222aeae75ec5e5e5.jpg

…R

sharkie:
All of the motors are connected to the same piece of metal

Thanks for the pics.

I had a COMPLETELY different idea in my mind when I envisaged connection to the same piece of metal. I was thinking of something like a bar moving along a table with a motor at each end of the bar.

I can't say that I understand how your system is intended to work. It looks a bit like a Polargraph drawing machine - but they seem only to have one motor for each side.

(Sorry could not find a simple image of those things)

...R

So the 3rd and 4th steppers always follow the 2nd and those other numbers you entered are useless?

could you explain this a bit more please? is it not possible to control four motors from this sketch ?

I can’t say that I understand how your system is intended to work. It looks a bit like a Polargraph drawing machine - but they seem only to have one motor for each side.

a polargraph drawing machine would have been a better option probably, I had looked into this but i went for a corexy model basically.

sharkie:
could you explain this a bit more please? is it not possible to control four motors from this sketch ?

he just meant that you are using

stepper1R.moveTo(moves[indexCount + 1]);

for 3 motors when you should probably be using +2 and +3 for two of them.

Actually, now that I focus on that I suspect indexCount +1 (etc) may not be correct. I wonder if you need a 2 dimensioned array so that the line of code would be something like

stepper1R.moveTo(moves[motorNum][indexCount]);

a polargraph drawing machine would have been a better option probably, I had looked into this but i went for a corexy model basically.

I had not realized what CoreXY implied and I was not trying to suggest a preference.

Is it the case that the two motors on one side must move in exact step with each other? or are there circumstances in which you need completely separate movements for 1R and 1L?

...R