Issue using millis for step count

Hi,

I have the below code that i have been working on that will count the steps of each motor and stop when they all return back to zero, based on a raito of their speed.

I can get this working quite fine when the millis between steps are set to like 200ms+ all motor stop when they all are at zero again, but when they are down towards 10,20& 30ms it never works and it appers that the millis between steps time are wrong, when i print the steps count of all motors they are the same except motor 3 it is 2 steps out, therefore making the motors contiunally run and never stop.

unsigned long curMillis1;
unsigned long prevStepMillis1 = 0;
unsigned long millisBetweenSteps1 = 20; // milliseconds
int stepperMotor1StepCount = 0;
int stepperMotor1Rotation = 0;

unsigned long curMillis2;
unsigned long prevStepMillis2 = 0;
unsigned long millisBetweenSteps2 = 10; // milliseconds
int stepperMotor2StepCount = 0;
int stepperMotor2Rotation = 0;

unsigned long curMillis3;
unsigned long prevStepMillis3 = 0;
unsigned long millisBetweenSteps3 = 40; // milliseconds
int stepperMotor3StepCount = 0;
int stepperMotor3Rotation = 0;
int  startToDraw =0 ;

void setup() {

     Serial.begin(9600);
      
}

void loop() {
   
    curMillis1 = millis();
    curMillis2 = millis();
    curMillis3 = millis();
    stopAllAtZero(); 

    // stops motors Once all hit zero
   if(startToDraw == 0){
    StepperMotorControl();
   }
   
   
}
   void stopAllAtZero() {
  // when all motors return back to step 0 at the same time print the below message
  if (stepperMotor1StepCount == 0 && stepperMotor2StepCount == 0 && stepperMotor3StepCount == 0 && curMillis1 > 2000)
  {
    Serial.print("all Axis equal zero");
    startToDraw = 1;
}
   }

void StepperMotorControl() {
    if (curMillis1 - prevStepMillis1 >= millisBetweenSteps1) {
        prevStepMillis1 = curMillis1;
        //Serial.print("steps1:");
        //Serial.println(stepperMotor1StepCount);
        Serial.println("stepperMotor1Rotation");
        Serial.println(stepperMotor1Rotation);
        stepperMotor1StepCount++;
        
        
    }
    if (stepperMotor1StepCount == 199)  {
    stepperMotor1StepCount = 0;
    stepperMotor1Rotation++;
  }

  if (curMillis2 - prevStepMillis2 >= millisBetweenSteps2) {
        prevStepMillis2 = curMillis2;
        //Serial.print("steps2:");
        //Serial.println(stepperMotor2StepCount);
        Serial.println("stepperMotor2Rotation");
        Serial.println(stepperMotor2Rotation);
        stepperMotor2StepCount++;
        
        
    }
    if (stepperMotor2StepCount == 199)  {
    stepperMotor2StepCount = 0;
    stepperMotor2Rotation++;
  }

  if (curMillis3 - prevStepMillis3 >= millisBetweenSteps3) {
        prevStepMillis3 = curMillis3;
        //Serial.print("steps3:");
        //Serial.println(stepperMotor3StepCount);
        Serial.println("stepperMotor3Rotation");
        Serial.println(stepperMotor3Rotation);
        stepperMotor3StepCount++;
        
        
    }
    if (stepperMotor3StepCount == 199)  {
    stepperMotor3StepCount = 0;
    stepperMotor3Rotation++;
  }
}

What am i missing here that's making the millis be incorrect?

curMillis1 = millis();
    curMillis2 = millis();
    curMillis3 = millis();

Why?

Serial.begin(9600)The 1970s called; they want their bitrate back.

TheMemberFormerlyKnownAsAWOL:

curMillis1 = millis();

curMillis2 = millis();
    curMillis3 = millis();



Why?

How would i change this? i assumed i would need one for every millis between steps time?

[quote
Serial.begin(9600)The 1970s called; they want their bitrate back.
[/quote]

come on! this is not very useful, i'm still new to this, so some reference to the 1970s dosen't mean much to me :wink:

 Serial.println("stepperMotor1Rotation");
Serial.println(stepperMotor1Rotation);

How long to print all that out?

Bails:
How would i change this? i assumed i would need one for every millis between steps time?

How about

curMillis1 = millis();
curMillis2 = curMillis1;
curMillis3 = curMillis1;

or evencurMillis1 = curMillis2 = curMillis3 = millis();

How about using arrays?

#define NUM_STEPPERS 3

unsigned long curMillis[NUM_STEPPERS] = {0};
unsigned long prevStepMillis[NUM_STEPPERS] = {0};
unsigned long millisBetweenSteps[NUM_STEPPERS] = {20, 10, 40}; // milliseconds
int stepperMotorStepCount[NUM_STEPPERS] = {0};
int stepperMotorRotation[NUM_STEPPERS] = {0};

And check them in a for loop instead of repeating code?

Unrelated to your question, but consider this:

class StepperCounter {
  public:
    unsigned long curMillis;
    unsigned long prevStepMillis = 0;
    const unsigned long millisBetweenSteps; // milliseconds
    int stepCount = 9;
    int rotation = 0;

    StepperCounter(long millisBetweenSteps) :
      millisBetweenSteps(millisBetweenSteps)
    {}
};

StepperCounter stepper1(20);
StepperCounter stepper2(10);
StepperCounter stepper3(40);

If your three steppers are, like, a row of three steppers, then you can use an array:

StepperCounter stepper[] = { StepperCounter(20),
                             StepperCounter(10),
                             StepperCounter(40)
                           };

You can then put common code into the class, like so:

class StepperCounter {
  public:
    unsigned long curMillis;
    unsigned long prevStepMillis = 0;
    const unsigned long millisBetweenSteps; // milliseconds
    int stepCount = 0;
    int rotation = 0;

    StepperCounter(long millisBetweenSteps) :
      millisBetweenSteps(millisBetweenSteps)
    {}

    void count(int myName) {
      if (curMillis - prevStepMillis >= millisBetweenSteps) {
        prevStepMillis = curMillis;
        Serial.print("stepper");
        Serial.print(myName);
        Serial.println("Rotation");
        Serial.println(rotation);
        stepCount++;
      }
      if (stepCount == 199)  {
        stepCount = 0;
        rotation++;
      }
    }
};

StepperCounter stepper[] = { StepperCounter(20),
                             StepperCounter(10),
                             StepperCounter(40)
                           };

void countAllSteppers() {
  for (int i = 0; i < 3; i++) {
    stepper[i].count(i);
  }
}

I mean - you'll still have the same problems in the timing code, but all the fixes go into the one code block in the class.

TheMemberFormerlyKnownAsAWOL:
How about

curMillis1 = curMillis2 = curMillis3 = millis();

Or even replace them all with:

  currentMillis = millis();

You only need one copy of the current time.

If you are going to be printing out position information 100 times a second (every 10 milliseconds) you should definitely change your baud rate from 9600 (about 1000 character per second) to 115200 (about 11,000 characters per second). I think that might actually fix your problem.

TheMemberFormerlyKnownAsAWOL:
Serial.begin(9600)The 1970s called; they want their bitrate back.

Nope! I'm still using that bit rate!

Bails:
if (stepperMotor3StepCount == 199) {

Try to get into the habit of using greater-than (or less-than) in these kinds of comparisons. Things like millis() can skip one and then your processor locks up for 49 days waiting for the exact number to come around again. You might change your code in the future to count in steps of 2 and then this comparison will never become true.

This is also an example of a "magic number". You might change one stepper to a different number of steps (maybe through micro-stepping, so there is no change in the hardware) so which ones of the "199" do you change? Can you be sure you got all of them?

Give every number like this a name. Like stepper1StepsPerRev or something that makes sense to you. Then use that name everywhere.

You have not actually explained the purpose of this code. Whenever you have three variables, it suggests that you have two too many. Your initialization failure has already been pointed out; there is no guarantee that all three variables will have different values. On the other hand, a 1ms error is irrelevant. I think you should create one class for each motor, that does whatever it does for that motor, e.g.,

class MyMotor : public WhateverYourStepperMotorClassIs {
     protected:
        long StepTime;
        long Count;
        long Interval;
        bool clockwise = true;
     public:
         bool takeAStep() 
           {
            if(Count <= 0)
              return false;

            if(millis() < StepTime + Interval)
               return false;

            oneStep();

            StepTime = mlllis() + Interval;
            Count--;
            return true;
           } // takeAStep

         void setNext(long c)
           {
            StepTime = millis();
            if(c < 0)
               {
                clockwise = false;
                Count = -c;
               }
            else
               {
                clockwise = true;
                Count = c;
               }
           } // setNext

         MyMotor(long dt)
           {
            StepTime = millis();
            Count = 0;
            Interval = dt;
           }
    protected:
      void oneStep()
         {
          //...call your motor superclass using "clockwise" to determine what the 
          //...direction parameter is.
         }

}; // class Motor

MyMotor motor1(20); // motor1 needs 20ms interstep time
MyMotor motor2(30); // motor2 needs 30ms interstep time
MyMotor motor3(20); // motor3 needs 20ms interstep time

void loop() 
    {
      bool any = false;
      any |= motor1.takeAStep();
      any |= motor2.takeAStep();
      any |= motor3.takeAStep();
      if(!any)
         {
          // ... do things that compute future steps, if any are needed
          // ...for example, the result might be
          // motor1.setNext(-5);  // 5 steps CCW
          // motor2.setNext(14);  // 14 steps CW
          // ...note that motor3 dpes not get a value in this example computation,
          // and will not move
         }
   } // loop

I wrote this off the top of my head, but if it is not the precise truth, it is closer than the overly-complex code you wrote. Never think of using multiple global variables when class instances can solve the problem trivially. In fact, try to ignore the concept of global variables, except in a few rare cases, such as for class variables that represent the objects you are controlling. In this example, the only three global variables are for the three motors. There are no other global variables to maintain state.

Also, learn to indent better.

flounder:
I wrote this off the top of my head,

This is not a reliable way to use millis()

if(millis() < StepTime + Interval)

Always use subtraction to avoid the risk of errors when millis() overflows

if(millis() - PrevStepTime < Interval)

...R

Wow, thanks for the suggestion and advice.

I need to learn a bit more about classes to fully understand these and to utilise in my code.

Besides my formatting issues, would the Baud rate and the amount of information i want to print actually effect the rest of the code with regards to the millis between steps?

Bails:
Besides my formatting issues, would the Baud rate and the amount of information i want to print actually effect the rest of the code with regards to the millis between steps?

Absolutely.