stepper motor and calculating time in while loop

I have a stepper motor (1 step = 0.0125 mm) that will have:

  • Rotate at a speed set between 0.00028 mm / s and 1.25 mm / s
  • And make a certain number of turns, a distance (between 0 and 500 mm).

The adjustment is made on an LCD screen and using 3 potentiometers:

  • 2 for the speed setting broad and finer to adjust. The display will be in mm / s.
  • 1 for the distance, the display will be in mm.

When the switch is OFF, you can adjust the speed and distance.
When the switch is ON, the motor rotates in the previous settings.
During engine operation, it must be able to stop without waiting for the end of the delay by returning the switch to OFF.

I have a problem for calculating the rotation time.
Can you help me?

#include <Stepper.h>
#include <LiquidCrystal.h>
const int stepsPerRevolution = 200;  // the number of steps per revolution                                 
// initialize the stepper library on pins 8 through 11:
Stepper myStepper(stepsPerRevolution, 8,9,10,11); 
// initialize the LCD pin
LiquidCrystal lcd(13,12,5,4,3,2);

// this constant won't change:
const int  buttonPin = 7;    // the pin that the pushbutton is attached to
const int ledPin = 13;       // the pin that the LED is attached to

// Variables will change:
unsigned long t1, t2, time;
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button
unsigned long turnTime; // temporisation rotation moteur
unsigned long stepTime;   // temporisation pas moteur
float speedMoteurScreen;

void setup() {
  // LCD sizes. We're using one that's 2 lines of 16 characters,
  lcd.begin(16, 2);
  // Let's clear the LCD
  lcd.clear();
  // contrast for LCD screen
  analogWrite(6, 120);
  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  // initialize the LED as an output:
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);
  // read the sensorSpeedLarge value:
  int sensorSpeedLarge = analogRead(A0);
  // map it to a range from 0 to 1000:
  double speedMoteurLarge = map(sensorSpeedLarge, 0, 1023, 28, 125000);
  // read the sensorSpeedLarge value:
  int sensorSpeedFine = analogRead(A1);
  // map it to a range from 0 to 1000:
  int speedMoteurFine = map(sensorSpeedFine, 0, 1023, -50, 50);
  // read the sensorShortening value:
  int sensorShortening = analogRead(A2);
  // map it to a range from 0 to 1000:
  int disTance = map(sensorShortening, 0, 1023, 0, 500);
  
  double speedMoteur = speedMoteurLarge + speedMoteurFine;
  speedMoteurScreen=speedMoteur/100000;  //100000 pour affichage en mm/s
  stepTime = (0.0125/speedMoteurScreen)*1000; //*1000 car secondes en entree
  turnTime = (disTance/speedMoteurScreen)*1000; //*1000 car secondes en entree

  lcd.setCursor(0,0);
  lcd.print("v = " );
  lcd.print(speedMoteurScreen);
  lcd.print (" mm/s");
  lcd.setCursor(0,1);
  lcd.print("d = " );
  lcd.print(disTance);
  lcd.print (" mm");
  delay(100);
  lcd.clear();
  
  t1= millis();
  // compare the buttonState to its previous state
  if ((buttonState != lastButtonState) && (buttonState == HIGH))
  {  
     digitalWrite(ledPin, HIGH);
     while ((buttonState == HIGH) && (time < turnTime))
     {
       t2 = millis();
       myStepper.step(-1); 
       delay(stepTime);
       buttonState = digitalRead(buttonPin);
       time = t2-t1;
     }
  }
   digitalWrite(ledPin, LOW);
   lastButtonState = buttonState;       
   time=0;
}

Define "rotation time". Do you mean RPM?

I might be misunderstanding the question here. But why are we measuring rotational speed in mm/s?

mm/s is fine for linear distance, but is meaningless in rotation, as the distance covered is dependant on the radius of whatever you have attached to your shaft?

I'd go with rad/s, degrees/sec or rps?

Sorry it’s a time during the motor turn

My movement is not continuous.
I make 1 step, delay (stepTime), an another step, delay (stepTime) etc…
1 step = 0.0125 mm
speed = step / stepTime with stepTime is the delay between steps in sec => speed is in mm/s
distance = speed * turnTime

I want to calculating exactly time in my while loop for the condition time < turnTime

Do not use the delay() function. Do not use a WHILE loop - or certainly not one on which the timing depends.

Have a look at the second example in this simple stepper code that uses millis() and micros() to manage the timing.

...R Stepper Motor Basics

Thank you I will studied it! Can you just explain this "+=" in your singleStep function please?

valA += 3; is the same as valA = valA + 3;

...R

Very big thanks Robin2.
I am greatly inspired by your example but I have not actually tested. I’ll do that monday.

#include <Stepper.h>
#include <LiquidCrystal.h>
const int stepsPerRevolution = 200;  // the number of steps per revolution
Stepper myStepper(stepsPerRevolution, 8,9,10,11); 
LiquidCrystal lcd(13,12,5,4,3,2);

const int buttonPin = 7;          // pin bouton
const int ledPin = 13;            // pin led
boolean buttonOFF = false;
boolean buttonON = false;

unsigned long curMillis;
unsigned long prevStepMillis = 0;
unsigned long stepTime;
int numberOfSteps;
double motorSpeed;
double motorSpeedLarge;
int motorSpeedFine;
int disTance;

void setup() {
  lcd.begin(16, 2);
  lcd.clear();
  analogWrite(6, 120);  // contrast for LCD screen
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
}

void loop() {
 curMillis = millis();
 readButtons();
 actOnButtons();
} 

void readButtons() {
  buttonOFF = false;
  buttonON = false;  
  if (digitalRead(buttonPin)==LOW) {
    digitalWrite(ledPin, LOW);
    buttonOFF = true; 
  }
  if (digitalRead(buttonPin)==HIGH) {
    digitalWrite(ledPin, HIGH);
    buttonON = true;  
  }
}

void actOnButtons() {
  if (buttonOFF == true) {
    int potSpeedLarge = analogRead(A0);
    motorSpeedLarge = map(potSpeedLarge, 0, 1023, 28, 100000);
    int potSpeedFine = analogRead(A1);
    motorSpeedFine = map(potSpeedLarge, 0, 1023, -50, 50);
    int potDistance = analogRead(A2);
    disTance = map(potDistance, 0, 1023, 0, 500);
    motorSpeed = motorSpeedLarge+motorSpeedFine;
    stepTime = (0.0125/motorSpeed)*1000; 
    numberOfSteps = (disTance/0.0125);
    screenLCD();
  }
  if (buttonON == true) {
    singleStep();
  }
}

void singleStep() {
  for(int n = 0; n < numberOfSteps; n++) {
    if (curMillis - prevStepMillis >= stepTime) {
      prevStepMillis += stepTime;
      myStepper.step(-1);
    }
  }
}

void screenLCD() {
  lcd.setCursor(0,0);
  lcd.print("v = " );
  lcd.print(motorSpeed/100000,5);
  lcd.print (" mm/s");
  lcd.setCursor(0,1);
  lcd.print("d = " );
  lcd.print(disTance);
  lcd.print (" mm");
  delay(100);
  lcd.clear();
}

Ok I've tested... The screenLCD function doesn't work... The screen blink. I see values but it's dissapear after 1 sec. I think it's because I used "if" loop.

The button on Pin 7 is very slow (About 1 sec) to detect if it's on ON or OFF.

And the motor turn but it's very strange. If I choise a speed, It turn in clockwise. If I changed speed with potentiometer, It turn in counter clockwise or it changed the speed ...

I don' understand why.

Someone can help me?

This won't work as you expect

stepTime = (0.0125/motorSpeed)*1000;

because you are mixing floating point maths and integer maths - it will probably always give 0 What you have is the equivalent of 125 / motorSpeed - but you should express it like that. However if motor speed is bigger than 125 the answer will be 0.

You could simplify the code in readButtons() to this

void readButtons() {
  buttonON = false;
  if (digitalRead(buttonPin)==HIGH) {
    digitalWrite(ledPin, LOW);
    buttonON = true;
  }
}

there is no need for a buttonOFF variable as well as buttonON.

By the way I am assuming your button registers HIGH when pressed. It is better practice to use INPUT_PULLUP and wire the switch between buttonPin and GND - which gives a LOW when pressed. It is "better" because there is no need to have a 5v wire that could cause a short circuit.

...R

Thank you for your answer of steptime.

For my button, it is not a button that I press. In fact it's a switch button with 3 pins (5V/Pin7/Ground) and 2 positions ON/OFF.

goodsayan:
In fact it’s a switch button with 3 pins (5V/Pin7/Ground) and 2 positions ON/OFF.

I don’t see why it needs three connections to show ON/OFF. Why is there a need for a 5V connection ?

…R

It’s a schematic model of my switch

On Pin 1, I connected +5V of arduino board.
On Pin 2, the pin 7
On Pin 3, the ground of arduino board.

I will look tomorrow the exact reference

goodsayan: It's a schematic model of my switch

Just connect the centre pin to a Digital pin and one of the side pins to GND. Don't connect the 3rd pin to anything. Then set the digital pin for

pinMode(ppp, INPUT_PULLUP);

...R

I'm a little desperate to properly operate this motor.

My unipolar motor is http://www.tedmotors.com/Archive/_eng/DST86.pdf My driver is EASY STEP 1000 http://www.gotronic.fr/art-commande-es1000-12028.htm

I tried your changes but the switch reacts very slowly. The LDC screen show values but only for 1 sec and off. The motor running smoothly and the torque is not enough strong.

Here is my wiring. I removed the LCD screen.

I'm not good, sorry.

goodsayan: I tried your changes but the switch reacts very slowly.

That is a code problem, not a switch problem.

Post the latest (simplest ?) version of your code.

...R

The latest is

#include <Stepper.h>
#include <LiquidCrystal.h>
const int stepsPerRevolution = 200;  // the number of steps per revolution
Stepper myStepper(stepsPerRevolution, 8,9,10,11); 
LiquidCrystal lcd(13,12,5,4,3,2);

const int buttonPin = 7;          // pin bouton
const int ledPin = 13;            // pin led
boolean buttonON = false;

unsigned long curMillis;
unsigned long prevStepMillis = 0;
unsigned long stepTime;
int numberOfSteps;
double motorSpeed;
int disTance;

void setup() {
  lcd.begin(16, 2);
  lcd.clear();
  analogWrite(6, 120);  // contrast for LCD screen
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
}

void loop() {
 curMillis = millis();
 readButtons();
 actOnButtons();
} 

void readButtons() {
  buttonON = false;  
  if (digitalRead(buttonPin)==HIGH) {
    digitalWrite(ledPin, LOW);
    buttonON = true;  
  }
}

void actOnButtons() {
  if (buttonON == false) {
    digitalWrite(ledPin, HIGH);
    int potSpeed = analogRead(A0);
    motorSpeed = map(potSpeed, 0, 1023, 28, 100000);
    int potDistance = analogRead(A2);
    disTance = map(potDistance, 0, 1023, 0, 500);
    stepTime = (0.0125/(motorSpeed/100000))*1000; 
    numberOfSteps = (disTance/0.0125);
    screenLCD();
  }
  if (buttonON == true) {
    singleStep();
  }
}

void singleStep() {
  for(int n = 0; n < numberOfSteps; n++) {
    if (curMillis - prevStepMillis >= stepTime) {
      prevStepMillis += stepTime;
      myStepper.step(-1);
    }
  }
}

void screenLCD() {
  lcd.setCursor(0,0);
  lcd.print("v = " );
  lcd.print(motorSpeed/100000,5);
  lcd.print (" mm/s");
  lcd.setCursor(0,1);
  lcd.print("d = " );
  lcd.print(disTance);
  lcd.print (" mm");
  delay(1000);
  lcd.clear();
}

Thank you for your time.

The switch reacting slowly is probably due to the delay(1000) during which the Arduino does not check the switch.

Don’t use delay() in any serious program. Use millis() to manage timing everywhere.

…R

Ok, I replace delay(1000) in my function screenLCD() by this function?

void timeDelay() {
    if (curMillis - prevScreenMillis >= 1000) {
      prevScreenMillis += 1000;
    }
  }

with unsigned long prevScreenMillis = 0 in the declaration of variable.

goodsayan: Ok, I replace delay(1000) in my function screenLCD() by this function?

Not quite.

Something like this

void screenLCD() {
  if (curMillis - startScreenMillis >= 1000) {
    lcd.clear();
    displayNewScreen = true;
  }
  if (displayNewScreen == true) {
    displayNewScreen = false;
    startScreenMillis = curMillis;
    lcd.setCursor(0,0);
    lcd.print("v = " );
    lcd.print(motorSpeed/100000,5);
    lcd.print (" mm/s");
    lcd.setCursor(0,1);
    lcd.print("d = " );
    lcd.print(disTance);
    lcd.print (" mm");
  }
}

...R