Go Down

Topic: 4 stepper motors control: max3 running simlutaneously, start stop independently (Read 754 times) previous topic - next topic

patrickgoh1993

I'm designing this carousel style cocktail machine and I have:
1. motor i to turn alcohols (rotatory table)
2. motor ii to dispense alcohol (push to release)
3. motor iii and iv dispense mixer (peristaltic pumps)

The machine:
a. As button is pressed, depending on the drink, C and/or D will start dispensing the mixer.
b. At the same time as button is pressed, i turns the table to a specific alcohol(by controlling steps), then stop.
c. ii starts the dispensing mechanism, drink poured, ii then needs to clear out(reverse steps) the way before i can move again to the next alcohol.

I have codes for controlling the lcd display for drinks. User can switching between drinks using potentiometer:
Code: [Select]

#include <Wire.h> //
#include <LiquidCrystal_I2C.h>//
#include <avr/pgmspace.h>
const char string_0[] PROGMEM = "Welcome!";
const char string_1[] PROGMEM = "Manhattan";
const char string_2[] PROGMEM = "Cosmo";
const char string_3[] PROGMEM = "Mojito";
const char string_4[] PROGMEM = "BlackRussian";
const char string_5[] PROGMEM = "LongIslandIceTea";
const char string_6[] PROGMEM = "DRINK#6";
const char string_7[] PROGMEM = "DRINK#7";
const char string_8[] PROGMEM = "DRINK#8";
const char string_9[] PROGMEM = "DRINK#9";
const char string_10[] PROGMEM = "DRINK#10";



const char* const string_table[] PROGMEM = {string_0, string_1, string_2, string_3, string_4, string_5, string_6, string_7, string_8, string_9, string_10};

char buffer[50];    // make sure this is large enough for the largest string it must hold
int analogPin = 0;
int result = 0;
int oldResult = 0;
int i = 0;
LiquidCrystal_I2C lcd(0x3F,16,2);//

void setup()
{
  Serial.begin(9600);
  while (!Serial);
  Serial.println("OK");
  lcd.init();//

  // Turn on the backlight
  lcd.backlight();//
  delay(100);
}


void loop()
{
  result = analogRead(analogPin);
  i = result / 100; //more drinks --> try result / 50

  if (i != oldResult)
  {
    lcd.clear();//
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i]))); // Necessary casts and dereferencing, just copy.
    lcd.home();//

    lcd.print(buffer);//
    delay(200);


  }
  oldResult = i;
}



I still need to incorporate a button for user to select the chosen drink and to run motors.

The code to run 2 motors in sequence:
Code: [Select]

// (1) Pin Setup
int pulsePinA = 12;
int dirPinA = 11;
int pulsePinB = 5;
int dirPinB = 4;

// (2) Timing Setup
int PWMicros = 1000;
int millisbetweenSteps =  1;
int del = 2000;

void setup() {
  Serial.begin(9600);
  pinMode(pulsePinA, OUTPUT);
  pinMode(pulsePinB, OUTPUT);

  pinMode(dirPinA, OUTPUT);
  pinMode(dirPinB, OUTPUT);

// (3) Running motor sequences---------need to save (3) (as cases?) for different mix of cocktail, and be able to call each case by controlling potentiometer, and select button.
  motorA(200,0);  //motorfucntion(steps, direction) //I need motor C and/or motor D to start together with motor A, and able to call a stop independently.
  motorB(400,0);
  delay(del);     //delay to pour drinks-------If i want to have motor C and/or motor D running but need motor B to pause for a while, I shouldn't use delay?
  motorB(400,1);       
}

// (4) motor A function
void motorA(int stepsA,int dirA) {
  for(int n = 0; n <= stepsA; n++)  {   //------code from Robin2 on Arduino forum(Thank you!)
  digitalWrite(dirPinA, dirA);
  digitalWrite(pulsePinA, HIGH);
  delayMicroseconds(PWMicros);
  digitalWrite(pulsePinA, LOW);
 
  delay(millisbetweenSteps);
  }
}

// (5) motor B function
void motorB(int stepsB, int dirB) {
for(int n = 0; n <= stepsB; n++)  {
 digitalWrite(dirPinB, dirB);
  digitalWrite(pulsePinB, HIGH);
  delayMicroseconds(PWMicros);
  digitalWrite(pulsePinB, LOW);

  delay(millisbetweenSteps);
  }
}

// (6) motor C function

//(7) motor D function

void loop() {
  }



Questions:
How do you compile everything together?
How to make motors running simultaneously while another motor needs to pause for a while?
What is the approach here?
I'm using a Arduino Mega 2560, 3 easy drivers, and a HY-DIV268N-5A stepper motor drive. Not too worried about the wiring but I'm really struggles with the programming.


Thank you

Robin2

How do you compile everything together?
Without seeing what you have tried I don't know what to say without writing a long essay (and I'm lazy)

Quote
How to make motors running simultaneously while another motor needs to pause for a while?
The version of my examples that you have chosen is not suitable for that. Have a look at the second example in this Simple Stepper Code - it uses millis() rather than delay().

To make motors move simultaneously you must interleave the steps - so quite a bit of change will be needed for the code.

Another option is to use the AccelStepper library. Then you can set up the speed and number of steps and call motorA.run() and motorB.run() to have the library take care of the interleaving.

I am assuming that it is NOT necessary to synchronize the movement so that (say) motorA does 133 steps in exactly the same time as motorB does 731 steps. If you do need that then you need the MultiStepper version of the library. And you can also do it without any library by calculating the appropriate interval between steps for each motor.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

patrickgoh1993

Without seeing what you have tried I don't know what to say without writing a long essay (and I'm lazy)
The version of my examples that you have chosen is not suitable for that. Have a look at the second example in this Simple Stepper Code - it uses millis() rather than delay().

To make motors move simultaneously you must interleave the steps - so quite a bit of change will be needed for the code.

Another option is to use the AccelStepper library. Then you can set up the speed and number of steps and call motorA.run() and motorB.run() to have the library take care of the interleaving.

I am assuming that it is NOT necessary to synchronize the movement so that (say) motorA does 133 steps in exactly the same time as motorB does 731 steps. If you do need that then you need the MultiStepper version of the library. And you can also do it without any library by calculating the appropriate interval between steps for each motor.

...R
I have motor A, B running in sequence:
Aforward - Astop - Bforward - Bstop - Breverse - Aforward - Astop-..., while motor C, D running at the same time. There is not need to synchronise as the motors just need to complete their respective input steps.

What do you mean by interleave?

Robin2

What do you mean by interleave?
Move motorA by one step, move motorB by one step, move motorA by one step etc

In reality it may be a little more complex because motorB might be running faster and may need to make 5 steps for every 3 that A makes. The simple solution is to use millis() to manage the timing and get each motor to make a step at the time that is correct for it. That is the concept used in the AccelStepper library.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

MarkT

If it was 3 motors you could use GRBL and program it in GCODE, which would be rather a cool
use of GCODE in my view!
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

patrickgoh1993

Without seeing what you have tried I don't know what to say without writing a long essay (and I'm lazy)
The version of my examples that you have chosen is not suitable for that. Have a look at the second example in this Simple Stepper Code - it uses millis() rather than delay().

To make motors move simultaneously you must interleave the steps - so quite a bit of change will be needed for the code.

Another option is to use the AccelStepper library. Then you can set up the speed and number of steps and call motorA.run() and motorB.run() to have the library take care of the interleaving.

I am assuming that it is NOT necessary to synchronize the movement so that (say) motorA does 133 steps in exactly the same time as motorB does 731 steps. If you do need that then you need the MultiStepper version of the library. And you can also do it without any library by calculating the appropriate interval between steps for each motor.

...R
In AccelStepper library it requires loop function to call run().

Code: [Select]
  //carousel
    stepper1.setSpeed(50.0);
    stepper1.setAcceleration(5000.0);
    stepper1.moveTo(56);

    //for leadscrew drive
    stepper2.setMaxSpeed(2000.0);
    stepper2.setAcceleration(5000.0);
    stepper2.moveTo(10400);
   
   //pump motor C
    stepper3.setMaxSpeed(800.0);
    stepper3.setAcceleration(5000.0);
    stepper3.moveTo(400);

    //pump motor D
    stepper4.setMaxSpeed(800.0);
    stepper4.setAcceleration(5000.0);
    stepper4.moveTo(400);

}

 void loop()
{   
    stepper1.run();
    stepper2.run();
    stepper3.run();
    stepper4.run();
    stepper4.run();
}


I need something that doesn't require loop function so that I can create functions for each motor.

Robin2

I need something that doesn't require loop function so that I can create functions for each motor.
No you don't. You just need to organize your program properly. You can have
Code: [Select]
motorA.run();
motorB.run();
motorC.run();

in loop()

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

patrickgoh1993

No you don't. You just need to organize your program properly. You can have
Code: [Select]
motorA.run();
motorB.run();
motorC.run();

in loop()

...R
Hi I will give it a go. Another question is how to write button bit. I have push to break button and a switch case that read will the potentiometer. I'm struggling to write up the button part so that when it's pressed it will run certain function based on the analogRead from potentiometer.

Code: [Select]

int butPin = 22;
pinMode (butPin, INPUT);

//check if button is pressed
 if (digitalRead(butPin) == 0){
   switch(i){
     case 1: function1();
     break;
     case 2:  function2();
     break;
     case 3: function3();
     break;
     case 4: function4();
     break;
     case 5: function5();
     break;
     case 6: function6();
     break;
     case 7: function7();
     break;
     case 8: function8();
     break;
     case 9: function9();
     break;
     case 10: function10();
     break;
     default: ;
   }




Pretty sure it's wrong and I still need debouncing. Any guidance is much appreciated.

Robin2

and a switch case that read will the potentiometer.
Shouldn't that be "Peter the potentiometer" ?

I recommend that you read the switch state into a variable and use that in the IF test. It means you can print the value to see if it is what you think it should be.

Quote
Pretty sure it's wrong
What happens when you try it?

If it does not work please post the whole program.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

patrickgoh1993

Whole program (1/2):

Code: [Select]
#include <Wire.h> //
#include <LiquidCrystal_I2C.h>//
#include <avr/pgmspace.h>
#include <AccelStepper.h>
#include <MultiStepper.h>

//Back view//A Top//B Down//C Left//D Right
AccelStepper stepperA(AccelStepper::DRIVER, 12, 11);
AccelStepper stepperB(AccelStepper::DRIVER, 10, 9);
AccelStepper stepperC(AccelStepper::DRIVER, 7, 6);
AccelStepper stepperD(AccelStepper::DRIVER, 4, 3);

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

const char string_0[] PROGMEM = "Welcome!";
const char string_1[] PROGMEM = "Sex On The Beach";
const char string_2[] PROGMEM = "Screwdriver";
const char string_3[] PROGMEM = "Rum Sunset";
const char string_4[] PROGMEM = "Orange Crush";
const char string_5[] PROGMEM = "Cosmo";
const char string_6[] PROGMEM = "Vodka C'berry";
const char string_7[] PROGMEM = "Vodka Metro";
const char string_8[] PROGMEM = "Gimlet";
const char string_9[] PROGMEM = "Gin Sunset";
const char string_10[] PROGMEM = "Caipirinha";

const char* const string_table[] PROGMEM = {string_0, string_1, string_2, string_3, string_4, string_5, string_6, string_7, string_8, string_9, string_10};
char buffer[50];    // make sure this is large enough for the largest string it must hold
int analogPin = 0;
int result = 0;
int oldResult = 0;
int i = 0;

const int buttonPin = 2;     // the number of the pushbutton pin
int buttonState;      // the current reading from the input pin
int lastButtonState = LOW;
// the following variables are unsigned long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers


LiquidCrystal_I2C lcd(0x3F,16,2);//

void setup()
{
  Serial.begin(9600);
  while (!Serial);
  Serial.println("OK");
  lcd.init();//

  // Turn on the backlight
  lcd.backlight();//
  delay(100);

//Configure button
pinMode(buttonPin, INPUT);

// Configure each stepper
stepperA.setMaxSpeed(29); //steps per sec
stepperB.setMaxSpeed(1400);
stepperC.setMaxSpeed(400); //set this to match eul ratio of sms to position
stepperD.setMaxSpeed(400); //This ensure that under the same 1 second, motor C and D will complete 3 turns while motor A turns (say) 20 steps in the same 1 second.
 
// Then give them to MultiStepper to manage
  steppers.addStepper(stepperA);
  steppers.addStepper(stepperB);
  steppers.addStepper(stepperC);
  steppers.addStepper(stepperD);
}

////////////////////////DRINKS///////////////////////DRINKS/////////////////////////////////////DRINKS////////////////////////////////////
void function1(){ //Sex On The Beach
   Serial.println("Case 1");
motorA(50);
  }

void function2(){ //Screwdriver
   Serial.println("Case 2");
motorCD(2);
  }

void function3(){ //Rum Sunset
 Serial.println("Case 3");
 motorB(1);
  }

void function4(){ //Orange Crush
   Serial.println("Case 4");
   motorCD(4);
   motorA(3);
  
  }

void function5(){  //Cosmo
motorC(5);
motorCD(6);
  }

void function6(){ // Vodka C'berry
motorCD(6);
delay(500);
motorACD(3);
  }

void function7(){  //Vodka Metro
motorCD(7);
  }

void function8(){  //Gimlet
motorCD(8);
  }

void function9(){  //Gin Sunset
motorCD(9);
  }

void function10(){  //Caipirinha
motorCD(10);
  }




patrickgoh1993

Whole program (2/2):

Code: [Select]

///////////////////FUNCTIONS//////////////////////////////////////////////FUNCTIONS//////////////////////////////FUNCTIONS////////////////////////////
///Open MultiStepper3 to verify each function///
///////////////////////////////////////////////
//Motor function A//x from -3 to +3 but not 0//to call Carousel to move only
void motorA(int a) {
  long positions[4];            // Array of desired stepper positions. 4 for 4 steppers
  positions[0] = 29*a;            //number on steps based on stp per rev (don't forget microstepping settings)
  positions[1] = 0;
  positions[2] = 0;
  positions[3] = 0;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); // Blocks until all are in position
  }

//Motor function B//y either +1 or -1 only//to call Pusher up OR down only
void motorB(int b) {
  long positions[4];           
  positions[0] = 0;             //number on steps based on spr
  positions[1] = b*800;
  positions[2] = 0;
  positions[3] = 0;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); // Blocks until all are in position
  }

//Motor function C//
void motorC(int c) {
  long positions[4];           
  positions[0] = 0;             //number on steps based on spr
  positions[1] = 0;
  positions[2] = c*200;
  positions[3] = 0;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); // Blocks until all are in position
  }

//Motor function D//
void motorD(int d) {
  long positions[4];           
  positions[0] = 0;             //number on steps based on spr
  positions[1] = 0;
  positions[2] = 0;
  positions[3] = d*200;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); // Blocks until all are in position
  }
 
//Motor function AC//to call Carousel to move and C starts pumping//Every alcohol gap(29steps) C/D pumps 2 revs
void motorAC(int e) {
  long positions[4];           //Array of desired stepper positions
  positions[0] = 29*e;         //number on steps based on spr
  positions[1] = 0;
  positions[2] = 200*e;
  positions[3] = 0;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); // Blocks until all are in position
  }

void motorAD(int f) {
  long positions[4];           //Array of desired stepper positions
  positions[0] = 29*f;         //number on steps based on spr
  positions[1] = 0;
  positions[2] = 0;
  positions[3] = 400*f;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); // Blocks until all are in position
  }

//Motor functionBC//fixed//Every up one way OR down (29steps), C/D pumps 9 rev.
void motorBC() {

 long positions[4];            // Array of desired stepper positions
  positions[0] = 0;            //number on steps based on spr
  positions[1] = 8000;
  positions[2] = 2000;
  positions[3] = 0;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); // Blocks until all are in position
  }
 
//Motor function-BC//fixed
void motornBC() {
 long positions[4];            // Array of desired stepper positions
  positions[0] = 0;            //number on steps based on spr
  positions[1] = -8000;
  positions[2] = 2000;
  positions[3] = 0;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); // Blocks until all are in position
  }

//Motor functionBD//fixed
void motorBD() {
 long positions[4];            // Array of desired stepper positions
  positions[0] = 0;            //number on steps based on spr
  positions[1] = 8000;
  positions[2] = 2000;
  positions[3] = 0;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); // Blocks until all are in position
  }
 
//Motor function-BD//fixed
void motornBD() {
 long positions[4];            // Array of desired stepper positions
  positions[0] = 0;            //number on steps based on spr
  positions[1] = -8000;
  positions[2] = 2000;
  positions[3] = 0;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); // Blocks until all are in position
  }
 
//Motor function ACD//Every alcohol gap(29steps) C/D pumps 2 revs.
void motorACD(int g) {
  long positions[4];
  positions[0] = 29*g;
  positions[1] = 0;
  positions[2] =400*g;
  positions[3] = 400*g;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); // Blocks until all are in position
  }

//Motor function BCD//fixed//Every up one way OR down (29steps), C/D pumps 9 revs.
void motorBCD() {
  long positions[4];
  positions[0] = 8000;
  positions[1] = 0;
  positions[2] =2000;
  positions[3] = 2000;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); // Blocks until all are in position
  }

//Motor function nBCD (fixed)
void motornBCD() {
  long positions[4];
  positions[0] = -8000;
  positions[1] = 0;
  positions[2] =2000;
  positions[3] = 2000;
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); // Blocks until all are in position
  }

//Motor function CD ()
void motorCD(int h) {
  long positions[4];
  positions[0] = 0;
  positions[1] = 0;
  positions[2] = 200*h;
  positions[3] = 200*h;
 steppers.moveTo(positions);
  steppers.runSpeedToPosition(); // Blocks until all are in position
}

///////////////////////////////   RUNNING CODE   /////////////////////////////////////////////
void loop(){
  result = analogRead(analogPin);
  i = result / 100; //more drinks --> try result / 50
  //Serial.println(i); //To check what potentiometer reads: uncomment this
  if (i != oldResult){
    lcd.clear();//
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i]))); // Necessary casts and dereferencing, just copy.
    lcd.home();//
    lcd.print(buffer);//
    delay(200);
  }
  oldResult = i;
///////////////////////////////////   BUTTON   //////////////////////////////////////////////
// read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;
     
      // only toggle the LED if the new button state is HIGH
     if (buttonState == LOW) {
      Serial.println(i);
        switch(i){
          case 0:;
          break;
          //case 1: function1();
          Serial.println("Case 1");
          case 1: function1();
          break;
          //case 2:  function2();
          Serial.println("Case 2");
          case 2: function2();
          break;
         // case 3: function3();
          Serial.println("Case 3");
          case 3: function3();
          break;
          //case 4: function4();
          Serial.println("Case 4");
          case 4: function4();
          break;
          //case 5: function5();
          Serial.println("Case 5");
          case 5: function5();
          break;
         // case 6: function6();
          Serial.println("Case 6");
          case 6: function6();
          break;
          //case 7: function7();
          Serial.println("Case 7");
          case 7: function7();
          break;
          //case 8: function8();
          Serial.println("Case 8");
          case 8: function8();
          break;
          //case 9: function9();
          Serial.println("Case 9");
          case 9: function9();
          break;
          //case 10: function10();
          Serial.println("Case 10");
          case 10: function10();
          break;
          default: ;
 }
}
}
  }
  lastButtonState = reading;
  }

Robin2

Sorry, but for a long program just add the .ino file as an attachment. When joining two fragments it is very easy to introduce an error.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

patrickgoh1993

Program attached. To summarise my stepper motors (A,B,C,D)problem:
i. A start(turning)-A stop-B start(goes up)-B stop(very short interval)-B start(goes down)-A start(turning)- A stop-B start...

ii. C and/or D start-(for a period of time)-C and/or D stop.

I want to have i and ii running together but independent of each other.

In my program(it didn't work but that's my logic), I call C and D in each function in order for C and D to continue running. Sort of making C and D running continuously. Assumed the image attached is a drink recipe, motor ACD works well when jump to next line everything went wrong: all motors start to move.

I have now gave up(time constraint) and running A-B-C-D in order. :-(

Robin2

You are using runSpeedToPosition() which blocks everything until the move is complete. Remove all those lines.
Then, as the last thing in loop() add the line steppers.run();

You will also need to remove all delay()s from loop() and anything else that might reduce the repeat rate.

You don't actually need the MultiStepper library. You could just as easily put
Code: [Select]
stepperA.run();
stepperB.run();
etc

as the last thing in loop()

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

patrickgoh1993

Thank you. I will try it out tomorrow. Another question on the Accelstepper library. Here is a rough sketch of what I want to find out using a push to break button:

Code: [Select]

void setup() {
  Serial.begin(9600);
  stepperC.setMaxSpeed(800);
  stepperC.setAcceleration(1000);
}

void motorC() {
  stepperC.runToNewPosition(400);
  delay(50);
}

void function1(){
  motorC();
  delay(50);
  motorC();

void loop(){
  if (digitalRead(pin) ==LOW){
    function1();
  }
}



If I pressed once, will it move 800 steps or it will only move 400 because the second time I call function motorC() it's already at 400?

I read the library reference it says something about moving in relative OR treating steps as coordinates.

What will happen if I pressed second time?

If I want it to run it in a way that when I call motorC() once, it moves 400 steps, call it again, it moves ANOTHER 400 steps(which means it's 800 steps from power-on position), what should I write in the program?

Go Up