Millis() not working

I have a very simple sketch that runs a stepper motor.
I am using millis(); to time how long the stepper motor runs to a given position.
But, this just returns 0 in the Serial Monitor and I cannot understand why?

#include <AccelStepper.h>

#define enable23 13
#define STEP_PIN_23 11
#define DIR_PIN_23 10

#define enable17 12
#define STEP_PIN_17 4
#define DIR_PIN_17 5

AccelStepper stepper23(1, STEP_PIN_23, DIR_PIN_23);
AccelStepper stepper17(1, STEP_PIN_17, DIR_PIN_17);

unsigned long timeEnd;
unsigned long timeBegin;

void setup() {
  Serial.begin(115200);
  pinMode(enable23, OUTPUT);
  digitalWrite(enable23, LOW);
  stepper17.setMaxSpeed(3000);
  stepper23.setMaxSpeed(3000);
}

void loop() {
  
  stepper17.setCurrentPosition(0);
  stepper17.moveTo(3520);
  stepper17.setMaxSpeed(2000);
  stepper17.setSpeed(-1750);
  timeBegin = millis();
  do {
    stepper17.runSpeedToPosition();
  } while (stepper17.distanceToGo() != 3520);
  timeEnd = millis();

  // stepper23.setCurrentPosition(0);
  // stepper23.moveTo(10536);
  // stepper23.setMaxSpeed(2000);
  // stepper23.setSpeed(-1200);
  // // stepper23.runSpeed();
  // do {
  //   stepper23.runSpeedToPosition();
  // } while (stepper23.distanceToGo() != 10536);

  Serial.print("Start: ");
  Serial.println(timeBegin);
  Serial.print("End: ");
  Serial.println(timeEnd);

  unsigned long duration = timeEnd - timeBegin;
  Serial.print("Duration: ");
  Serial.println(duration);
}

Serial Monitor:

Start: 0

End: 0

Duration: 0

What do you see when you print timeBegin and timeEnd ?

Off the top of my head, I'll wager that if you create a counter that counts the number of times your code executes that while loop, you'll find it does it once.

while (stepper17.distanceToGo() != 3520);

I have doubts that this does what you think it does.

distanceToGo()

long AccelStepper::distanceToGo ( )

The distance from the current position to the target position.

This is initialization of local variable and it is performed just once.
Variables timeEnd, timeBegin are global, zeroed by default.
Try this:

unsigned long duration;
  duration = timeEnd - timeBegin;

You tell the stepper to move from 0 to 3520. How many times will distanceToGo not equal 3250 during that move ?

It looks like you should be testing whether distanceToGo is not equal to 0 rather than 3520

Start: 0

End: 0

Duration: 0

The steppers run perfectly

Which has nothing at all to do with what I wrote.

I don't see any obvious reason why it is not updating.
Try the sketch just for millis().

Same result, just zeroes

Have you tried counting how many times that do/while loop executes as previously suggested ?

the doc for runToPosition()states

Moves the motor (with acceleration/deceleration) to the target position and blocks until it is at position. Dont use this in event loops, since it blocks

distanceToGo() will be 0 at the end...

Only once

  int toGoDistanceCounter = 0;

  timeBegin = millis();
  do 
  {
    stepper17.runSpeedToPosition();
    toGoDistanceCounter++:
  } 
  while (toGoDistanceCounter != 3520);
  timeEnd = millis();
  Serial.print(timeEnd - timeBegin); //should show non-zero value

The stepper17.runSpeedToPosition(); function must be executing for 3520 times for stepper to arrive at its final postion. So, you need a counter to count how many times the function has been exected as said in #3.

will exit the loop immediately, because the motor hasn’t moved yet when this is first tested(i.e. distanceToGo is still 3520).

Suggest you try this, with your original code otherwise as posted.

What Arduino is this running on?

There’s something fishy about those zero returns from millis(). Never seen that on my Nanos. The variables are globals, are written once each when you call millis(), and should have valid non-zero values when you do the initialization of duration. My comment before was with regards to the likelihood that they are the same, thus returning zero for a delta value, but the two timestamps should not be zero.

Try this code and you will see the problem.

  do {
    stepper17.runSpeedToPosition();
    Serial.println(stepper17.distanceToGo());
  } while (stepper17.distanceToGo() != 3520);

The do..while executes once, presumably because the accelstepper library had not yet updated the value of distanceToGo, so that it is still equal to 3520.
After that, the loop starts over, and the stepper moves until distanceToGo() is zero, at which point the do..while loop will never exit.

I don’t think you need anything else than

stepper17.runSpeedToPosition();

It will block us you reached the destination

Also it’s a misconception if you think that the stepper would step every time you ask to run. Speed and acceleration come into play and the step is taken only when the step is due.

1 Like

It's ok, because these 'zeros' are only outputted once. And because there is no delay from start, not even 1 millisecond has elapsed when millis() is called the first time.

The main reason, that your code doesn't work, is the incorrect usage of .distanceToGo(). As already stated, you must check for 0, and not for 3520.

What happens with your code is:

  • when stepper17.runSpeedToPosition();is called for the first time after setup, no step is generated, because millis is still 0.
  • because no step is generated, the distanceToGo() is still 3250, and the while loop is exited immediately.
  • Your serial prints are printed with all values of 0
  • loop() is started again. Now millis() is > 0 and a step is generated with the first call of runSpeedToPosition(). Now distanceToGo is < 3250, and your while loop will never end. So no further printing.
  • Because the while loop calls runSpeedToPosition() again and again, your stepper does its 3520 steps, but the while loop will not end after that - it loops endless.

You can prevent the special behaviour of Accelstepper in the first call of loop ( with millis() == 0 ) if you add a short delay at the end of setup ( a delay(1) is sufficent ). Now your while will loop endless from the beginning, and you will never get an output to the serial monitor.

Hope this helps understanding what is happening.

I noticed you moved from an interrupt driven stepper to AccelStepper.h. Have you tried Servo.h? Have you tried making your own step pulses and acceleration?

// slowly accelerate to desired motor speed - no library

const int dirPin = 2,
          stepPin = 3;

// int usDelay,   // oops... made a mistake (see post #22)
long usDelay,   // pause between half-step
     ramp = 50; // rate of acceleration // keeping this type long

unsigned long timer,
         timeout = 1000,
         multiplier = 16; // start value multiplier, maximum = 16

void setup() {
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  digitalWrite(dirPin, HIGH);

  for (usDelay = timeout * multiplier; usDelay > timeout; usDelay -= ramp) { // decrease step delay
    onestep(); // step the motor
  }
}

void loop() {
  if (micros() - timer > timeout) { // use timeout value for constant rotation speed
    timer = micros(); // reset timer to wait for next pulse
    onestep();
  }
}

void onestep() {
  digitalWrite(stepPin, LOW);
  delayMicroseconds(usDelay);
  digitalWrite(stepPin, HIGH);
  delayMicroseconds(usDelay);
}
diagram.json for wokwi
{
  "version": 1,
  "author": "foreignpigdog x",
  "editor": "wokwi",
  "parts": [
    { "type": "wokwi-arduino-nano", "id": "nano", "top": -4.8, "left": -10.1, "attrs": {} },
    {
      "type": "wokwi-stepper-motor",
      "id": "stepper1",
      "top": -172.81,
      "left": 185.82,
      "attrs": { "size": "8", "arrow": "white" }
    },
    { "type": "wokwi-a4988", "id": "drv1", "top": -91.2, "left": 110.4, "attrs": {} },
    { "type": "wokwi-vcc", "id": "vcc1", "top": -133.64, "left": 163.2, "attrs": {} },
    { "type": "wokwi-gnd", "id": "gnd1", "top": -9.6, "left": 172.2, "attrs": {} }
  ],
  "connections": [
    [ "vcc1:VCC", "drv1:VMOT", "red", [ "v0" ] ],
    [ "gnd1:GND", "drv1:GND.2", "black", [ "v0" ] ],
    [ "drv1:GND.2", "drv1:ENABLE", "black", [ "h19.35", "v-19.12", "h-86.4", "v9.6" ] ],
    [ "drv1:2B", "stepper1:A+", "green", [ "h0" ] ],
    [ "drv1:2A", "stepper1:A-", "green", [ "h0" ] ],
    [ "drv1:1A", "stepper1:B-", "green", [ "h0" ] ],
    [ "drv1:1B", "stepper1:B+", "green", [ "h0" ] ],
    [ "gnd1:GND", "drv1:GND.1", "black", [ "v0" ] ],
    [ "vcc1:VCC", "drv1:VDD", "red", [ "v0" ] ],
    [ "nano:2", "drv1:DIR", "orange", [ "v0" ] ],
    [ "nano:3", "drv1:STEP", "white", [ "v0" ] ],
    [ "drv1:RESET", "drv1:SLEEP", "blue", [ "h-19.2", "v9.6" ] ]
  ],
  "dependencies": {}
}