Help with moving steppers at different speeds

Hi everyone,
I've built a labeling machine which puts one label on another,
The project is built using arduino nano, two optical sensors, two steppers driven by big easy driver.

currently the motors work simultaneously at the same speed. I want motor A to work a little faster than motor B. how can I do that?
When I try to play with delay times for individual motors it affects the whole process, so I understand that delay() command is not suitable for what i'm looking for.

Here's the code, the part I wish to modify is under TTI() process:

int const potPin1 = A6; // analog pin used to connect to sensor1
int potVal;
int const potPin2 = A7; // analog pin used to connect to sensor2
int potVal2;
const int stepPin = 5;
const int dirPin = 4;
const int enable1 = 12;
const int stepPin2 = 2;
const int dirPin2 = 3;
const int enable2 = 6;
int const buttonPin = A0; // digital pin used to connect to button(request TTI)
int button;
 
int potValLow = 400; 
int Speed = 180; //delay between actions
int button_VAL = 400; // button_VAL active val
 
 void setup() {
 // set the two pins as outputs
 Serial.begin(9600);
  pinMode(stepPin,OUTPUT);
  pinMode(dirPin,OUTPUT);
  pinMode(stepPin2,OUTPUT);
  pinMode(dirPin2,OUTPUT);
  pinMode(buttonPin,INPUT);
  pinMode(enable1,OUTPUT);
  pinMode(enable2,OUTPUT);
  pinMode(potPin1, INPUT);
  pinMode(potPin2, INPUT);
  button=0;
}

void loop() 
{
  calibrate();
  TTI();
}

void calibrate()
{
  potVal = analogRead(potPin1); 		// read the value of the sensor
  potVal2 = analogRead(potPin2); 	// read the value of the sensor
  while((potVal < potValLow) || (potVal2 < potValLow))
  { 
	digitalWrite(enable1,LOW);
	digitalWrite(enable2,LOW); 
    potVal = analogRead(potPin1); 	// read the value of the sensor
    potVal2 = analogRead(potPin2); 	// read the value of the sensor
    if(potVal < potValLow)			// calibrate position of Active labels. bring space between labels into sensor
	  {
        digitalWrite(stepPin2,HIGH);
    }
    if(potVal2 < potValLow)
	  {
        digitalWrite(stepPin,HIGH);        
    }
    digitalWrite(stepPin2,LOW);
    digitalWrite(stepPin,LOW);
    delayMicroseconds(Speed);
 }
}
void TTI()
{
  button = analogRead(buttonPin);
  if(button > button_VAL)
  {
    digitalWrite(enable1,LOW);
    digitalWrite(enable2,LOW);
	potVal = analogRead(potPin1); 		// read the value of the sensor
	potVal2 = analogRead(potPin2); 	// read the value of the sensor
	digitalWrite(stepPin,LOW);
	digitalWrite(stepPin2,LOW);
    while((potVal > potValLow) || (potVal2 > potValLow))
    {
      potVal = analogRead(potPin1); // read the value of the sensor
      potVal2 = analogRead(potPin2); // read the value of the sensor
          if(potVal > potValLow)// calibrate position of Active labels. bring start of label into sensor
          {
            digitalWrite(stepPin2,HIGH);
          }
          if(potVal2 > potValLow)// calibrate position of Base labels. bring start of label into sensor
          {
            digitalWrite(stepPin,HIGH);

          }
		digitalWrite(stepPin2,LOW);
		digitalWrite(stepPin,LOW);
		delayMicroseconds(Speed);
    }
  }  
}

the accelStepper library could help you do that

1 Like

The AccelStepper is an excellent stepper library, but I find the MobaTools stepper library comparable and, in my opinion, a bit easier to learn.

Both AccelStepper and MobaTools are available via the iDE library manager.

If you do not want to use a library and write your own stepper code, this Robin2 simple stepper code tutorial may be of interest.

1 Like

Thanks,
I tried to test the AccelStepper commands, with a simplified version of the program i'm using, and it doesn't seem to turn the motors.
Is there anything obvious that i'm missing?

#include <AccelStepper.h>
int const potPin1 = A6; // analog pin used to connect to sensor1
int potVal;
int const potPin2 = A7; // analog pin used to connect to sensor2
int potVal2;
int const buttonPin = A0; // digital pin used to connect to button(request TTI)
int button_VAL = 400; // button_VAL active val
int button;
int potValLow = 400; 
// Define two steppers and the pins they will use
AccelStepper stepper1(AccelStepper::DRIVER, 5, 4);
AccelStepper stepper2(AccelStepper::DRIVER, 2, 3);

void setup()
{ 
  Serial.begin(9600);
  stepper1.setMaxSpeed(1000);
  stepper1.setAcceleration(1000);
  stepper2.setMaxSpeed(1000);
  stepper2.setAcceleration(1000);
  pinMode(buttonPin,INPUT);
  pinMode(potPin1, INPUT);
  pinMode(potPin2, INPUT);
  button=0;
}

void loop()
{
  potVal = analogRead(potPin1);     // read the value of the sensor
  potVal2 = analogRead(potPin2);  // read the value of the sensor
  while((potVal < potValLow) || (potVal2 < potValLow))
  { 
    stepper1.run();
    stepper2.run();
    potVal = analogRead(potPin1);   // read the value of the sensor
    potVal2 = analogRead(potPin2);  // read the value of the sensor
}
}

Try runSpeed() instead. Or give them a place to run to with move() or moveTo().

Please post a schematic.

1 Like

I tried the runSpeed() instead run(), still the same, it sounds like the motors are stuck in place.
the move commands are less appropriate because the number of steps is not constant, I need to pull the motor until a label gets into the optical sensor.

Here's a schematic:

I do not understand what you are doing with the Vdd lines to the motor drivers. Those terminals should be connected to 5V logic power. What is the purpose of switching them?

Opto-interrupters are usually digital devices.

you can ignore that, it's drawn incorrectly to indicate a momentary switch for "give me next label"
The motors are connected to 12v from the input power, VDD connected to 5v from the arduino

regarding opto interrupters, i'm working with labels of different density and can identify that level through the value I put in the program ("potValLow")

If you use runSpeed(), you must also use setSpeed() to make the motors turn. With runSpeed() you don't get acceleration and deceleration, but that won't work with your approach anyway.

Here are 2 ways to do what (I think) that you want. The first uses your AccelStepper code but modified to use runSpeed (with setSpeed as @MicroBahner mentions). I use an if structure instead of while so it does not block. The other uses the MobaTools steppers. I use a CNC shield with an Uno for testing so the pin numbers must be changed to suit your setup.

AccelStepper:

#include <AccelStepper.h>
int const potPin1 = A0; // analog pin used to connect to sensor1
int potVal;
int const potPin2 = A1; // analog pin used to connect to sensor2
int potVal2;
int const buttonPin = A2; // digital pin used to connect to button(request TTI)
int button_VAL = 400; // button_VAL active val
int button;
const byte enablePin = 8;  // for CNC shield

int potValLow = 400;

// Define two steppers and the pins they will use
AccelStepper stepper1(AccelStepper::DRIVER, 2, 5);
AccelStepper stepper2(AccelStepper::DRIVER, 3, 6);

void setup()
{
   Serial.begin(9600);
   stepper1.setMaxSpeed(1000);
   stepper1.setAcceleration(1000);
   stepper2.setMaxSpeed(1000);
   stepper2.setAcceleration(1000);
   pinMode(buttonPin, INPUT);
   pinMode(potPin1, INPUT);
   pinMode(potPin2, INPUT);
   pinMode(enablePin, OUTPUT);
   digitalWrite(enablePin, LOW);
   button = 0;
}

void loop()
{
   potVal = analogRead(potPin1);     // read the value of the sensor
   potVal2 = analogRead(potPin2);  // read the value of the sensor
   if ((potVal < potValLow) || (potVal2 < potValLow))
   {
      stepper1.setSpeed(800);
      stepper1.runSpeed();
      stepper2.setSpeed(800);
      stepper2.runSpeed();
   }
   else
   {
      stepper1.stop();
      stepper2.stop();
   }
}

MobaTools:

#include <MobaTools.h>

const byte stepPin1 = 2;
const byte dirPin1 = 5;
const byte stepPin2 = 3;
const byte dirPin2 = 6;
const byte enablePin = 8;  // for CNC shield
const byte potPin1 = A0;
const byte potPin2 = A1;
const byte buttonPin = A2;

const int stepsPerRev = 400;

MoToStepper stepper1( stepsPerRev, STEPDIR );
MoToStepper stepper2( stepsPerRev, STEPDIR );

int potValLow = 400;

void setup()
{
   Serial.begin(115200);
   
   stepper1.attach( stepPin1, dirPin1 );
   stepper1.setSpeed( 800 );
   stepper1.setRampLen( stepsPerRev / 3);

   stepper2.attach( stepPin2, dirPin2 );
   stepper2.setSpeed( 800 );
   stepper2.setRampLen( stepsPerRev / 3);

   pinMode(enablePin, OUTPUT); // for CNC shield
   digitalWrite(enablePin, LOW);  // for CNC shield
   pinMode(buttonPin, INPUT_PULLUP);
}

void loop()
{
   int potVal1 = analogRead(potPin1);
   int potVal2 = analogRead(potPin2);
   
   if ((potVal1 < potValLow) || (potVal2 < potValLow))
   {
      stepper1.rotate(1);
      stepper2.rotate(1);      
   }
   else
   {
      stepper1.rotate(0);
      stepper2.rotate(0);
   }
}

To tell the truth, I like MobaTools better and I have been using AccelStepper for years.

Do you know that the mega 328 processor has a watchdog timer built-in?

If you do not want acceleration with the MobaTools steppers, use

stepperX.setRampLen( 0 );

Thanks very much!
thanks to your AccelStepper variation, I see progress in the project,
I used the code below, it works for bringing each label into the optical sensor and stopping, but the motors sound like they are stuck in place and not off, I filmed a video to demonstrate:

https://youtu.be/xSQYqIlRkPA

#include <AccelStepper.h>
int const potPin1 = A6; // analog pin used to connect to sensor1
int potVal;
int const potPin2 = A7; // analog pin used to connect to sensor2
int potVal2;
int const buttonPin = A0; // digital pin used to connect to button(request TTI)
int button_VAL = 400; // button_VAL active val
int button;
const int enable1 = 12;
const int enable2 = 6;


int potValLow = 400;

// Define two steppers and the pins they will use
AccelStepper stepper1(AccelStepper::DRIVER, 2, 3);
AccelStepper stepper2(AccelStepper::DRIVER, 5, 4);

void setup()
{
   Serial.begin(9600);
   stepper1.setMaxSpeed(-10000);
   stepper1.setAcceleration(-1000);
   stepper2.setMaxSpeed(-10000);
   stepper2.setAcceleration(-1000);
   pinMode(buttonPin, INPUT);
   pinMode(potPin1, INPUT);
   pinMode(potPin2, INPUT);
   pinMode(enable1, OUTPUT);
   pinMode(enable2, OUTPUT);
   //digitalWrite(enable1, HIGH);
   button = 0;
}

void loop()
{
   potVal = analogRead(potPin1);     // read the value of the sensor
   potVal2 = analogRead(potPin2);  // read the value of the sensor
   if (potVal < potValLow)
   {
      stepper1.setSpeed(-2000);
      stepper1.runSpeed();
   }
   else if (potVal2 < potValLow)
   {
      stepper2.setSpeed(-2000);
      stepper2.runSpeed();
   }
   if ((potVal < potValLow) && (potVal2 < potValLow))
   {
      stepper1.stop();
      stepper2.stop();
   }

You can disable the driver outputs by setting the enable pin(s) of the drivers to HIGH and setting them to LOW to move the steppers.

Maybe like so:

if (potVal < potValLow)
{
   digitalWrite(enablePin, LOW);
   stepper1.setSpeed(-2000);
   stepper1.runSpeed();
}
else if (potVal2 < potValLow)
{
   digitalWrite(enablePin, LOW);
   stepper2.setSpeed(-2000);
   stepper2.runSpeed();
}
if ((potVal < potValLow) && (potVal2 < potValLow))
{
   stepper1.stop();
   stepper2.stop();
   digitalWrite(enablePin, HIGH);
}

This way nothing moves and there's a high pitch noise

Post the code as you ran it.

#include <AccelStepper.h>
int const potPin1 = A6; // analog pin used to connect to sensor1
int potVal;
int const potPin2 = A7; // analog pin used to connect to sensor2
int potVal2;
int const buttonPin = A0; // digital pin used to connect to button(request TTI)
int button_VAL = 400; // button_VAL active val
int button;
const int enable1 = 12;
const int enable2 = 6;


int potValLow = 400;

// Define two steppers and the pins they will use
AccelStepper stepper1(AccelStepper::DRIVER, 2, 3);
AccelStepper stepper2(AccelStepper::DRIVER, 5, 4);

void setup()
{
   Serial.begin(9600);
   stepper1.setMaxSpeed(-10000);
   stepper1.setAcceleration(-1000);
   stepper2.setMaxSpeed(-10000);
   stepper2.setAcceleration(-1000);
   pinMode(buttonPin, INPUT);
   pinMode(potPin1, INPUT);
   pinMode(potPin2, INPUT);
   pinMode(enable1, OUTPUT);
   pinMode(enable2, OUTPUT);
   button = 0;
}

void loop()
{
   potVal = analogRead(potPin1);     // read the value of the sensor
   potVal2 = analogRead(potPin2);  // read the value of the sensor
   if (potVal < potValLow)
   {
      digitalWrite(enable1, LOW);
      stepper1.setSpeed(-2000);
      stepper1.runSpeed();
   }
   else if (potVal2 < potValLow)
   {
      digitalWrite(enable2, LOW);
      stepper2.setSpeed(-2000);
      stepper2.runSpeed();
   }
   if ((potVal < potValLow) && (potVal2 < potValLow))
   {
      stepper1.stop();
      stepper2.stop();
      digitalWrite(enable1, HIGH);
      digitalWrite(enable2, HIGH);
   }

Well, that's got me. I do not know what is wrong.

is there a command I can use to break out of this loop of reading sensors and moving the motors?
I mean something like "break", or to go to another sub program that waits for a push of the button to start running the motors again.

because as it is right now, it seems that perhaps it doesn't get into the last if() that turns the motors off. maybe I need to read the input of the sensors somehow differently?

why the negative values???

the doc states

Parameters
[in] speed The desired maximum speed in steps per second. Must be > 0. Caution: Speeds that exceed the maximum speed supported by the processor may Result in non-linear accelerations and decelerations.

start writing a very basic code that makes both motor spins to make sure you got the wiring and power right

Negative for the motors to turn counter clockwise.
The writing is correct because my original program(first message) is working well