how to safe millis at certain time after running a program

All the examples i found online are how to repetitively do certain things with millis right after the program began, and i understand it.

in my task, I want to rotate the motor in the reverse direction after the motor run in + direction for 5 seconds.

  • Start a program
  1. Motor starts running(+), a scale will detect any change of pressure, if it happens, then the motor stop. (got this part done)
  2. I press a button, the stepper motor continues running in + direction for 5 seconds, then stop
  3. then run in the reverse direction

The time the scale detects force can be any milliseconds,
then how do i save a millis() right after i press the button?
So i can use that value to set up a
"currentMillis - savedMillis > 5000", which indicate it to run 5 seconds.

if i use delay function, the scale won't detect pressure during the delay time, which is not what i want

Any of the following tutorials should help you:

BlinkWithoutDelay
Arduino Multiple Things
Several Things at a Time

ToddL1962:
Any of the following tutorials should help you:

BlinkWithoutDelay
Arduino Multiple Things
Several Things at a Time

i have read these posts planty of time, but all they show are how to run repetitively right after the program starts,
non of them show how to save millis() after certain time.
or maybe i miss any posts

unsigned long savedMillis;  // Somewhere near the top.
savedMillis = millis(); // Where you detect that the button is pressed (or released).

f129luke:
2. I press a button, the stepper motor continues running in + direction for 5 seconds, then stop
3. then run in the reverse direction

I suspect your thought process is making the problem seem more complicated than it really is.

When the button changes from not-pressed to pressed save the value of millis() and start the motor.

Then have a piece of code in loop() (or in a function called from loop) like this pseudo code

if (millis() - buttonPressedTime >= motorRunTime) {
  // code to stop motor
}

...R

Robin2:
I suspect your thought process is making the problem seem more complicated than it really is.

When the button changes from not-pressed to pressed save the value of millis() and start the motor.

Then have a piece of code in loop() (or in a function called from loop) like this pseudo code

if (millis() - buttonPressedTime >= motorRunTime) {

// code to stop motor
}




...R

Thank you, It might be my problem. I'll try it

  if (buttonstate == HIGH){
  currentTime_motor = millis(); 
  motor.setModeRunContinuous(); //Tell the motor to run at the given speed... forever
  motor.setSpeed(800); // give the motor a speed
  if (currentTime_motor - previousTime2 >= Interval_further){ // After 5 seconds
  motor.setSpeed(-800); 
  }
  }
  }

i'll explain a bit more where i got confused about

So above this code, i have another code that a load cell will detect the force change
And when the load cell detect any force applied on it, it will stop the motor for 2 seconds
(So the motor can stop at any milliseconds, lets say at 5 sec after the program starts, or 12 sec after the program starts)

Then I'll press a button again, the motor will continue running (Above code)
And i want the motor to run only 5 seconds (So the total process time can be 5+5 seconds, or 12+5 seconds when it reverse)

---- here is what I'm confused about
if I save the millis at the when the button is pressed( The value of millis() suppose to be the time the preceding time the entire process has passed.)

  motor.setModeRunContinuous(); //Tell the motor to run at the given speed... forever
  motor.setSpeed(800); // give the motor a speed
  if (currentTime_motor - previousTime2 >= Interval_further){ // After 5 seconds
  motor.setSpeed(-800);

so by the time it reach this code
currentTime_motor is way larger than 5,
previousTime2 is still 0
( then it will imminently jump to this code without actually running the top two lines. )

So what is your question?

Or describe on normal words what kind of behaviour do you want the program to have?

best regards Stefan

that is on my 1st post

  1. Motor starts runnin, a scale will detect any change of force, if it happens, then the motor stop.
    2.** then I press a button, the stepper motor continues running in + direction for 5 seconds, **
  2. then run in the reverse direction

Black ward is what I'm stuck with
i don't know how to set up a millis to let it run for 5 sec, then reverse

Run forever in reverse or run also for 5 seconds in reverse ?

Hi Luke,

please give an overview of what your project will do if it is finished. Describe the whole thing in normal words.
This will make it much easier to suggest how to solve the problem.

I give an example how it should look like

just some arbitrarily chosen example that came to my mind:
the Arduino shall control a machine that does split wood with a cone with thread

motor shall run forward so the thread wants to drive into the woord (forward-speed)
If the force gets too high the motor shall stop
then I press a button the motor shall run backwards for five seconds (drive thread backwards out of the wood
then stop again.

I guess my example deviates from what you want and you have a different "machine" This example shall only illustrate how write the descrition.

If this description is given the experienced users can make suggestions on how to program this behaviour.
I have in mind that a statemachine could be used. But maybe a statemachine is "oversized" for this.

If a statemachine is oversized can be said if you have posted the behaviour

best regards Stefan

f129luke:

  motor.setModeRunContinuous(); //Tell the motor to run at the given speed... forever

motor.setSpeed(800); // give the motor a speed
  if (currentTime_motor - previousTime2 >= Interval_further){ // After 5 seconds
  motor.setSpeed(-800);



so by the time it reach this code
currentTime_motor is way larger than 5,
previousTime2 is still 0
( **then it will imminently jump to this code without actually running the top two lines.** )

This is a good example of why you should post the complete program and not just snippets. We can't see how the value of previousTime2 was set and we can't see what might be happening so that it takes more than 5000 millisecs to reach this part of the program.

In a well designed program I would expect the time-check to happen every 5 or 10 millisecs so it should be checked maybe 500 times before the 5000 millisecs is reached.

...R

/ Libraries and setup:
#include "SparkFun_Qwiic_Step.h" //Click here to get the library: http://librarymanager/All#Qwiic_Step by SparkFun
#include <Wire.h>
#include "SparkFun_Qwiic_Scale_NAU7802_Arduino_Library.h"
NAU7802 myScale; //Create instance of the NAU7802 class
QwiicStep motor;

// Constants, doesn't change
const int buttonpin = 2;   // where button pins are, can have more than one button
const int buttonpin2 = 3;
const int buttonpin3 = 4;
const int ledblue = 12;

const int Interval = 100;                // time between each load cell data pop out
const int Interval_detectforce = 5000;   // time the actuator pasue when detect force
const int Interval_further = 10000;      // time the actuator move forward after the detection
const int Interval_backward = 20000;     // time the actuator shrink to the original position 
const int buttonInterval = 300;


// Values, change 
int buttonstate = 0;                      // 0 = LOW = off
int buttonstate2 = 0;
int buttonstate3 = 0;
int ledbluestate = LOW;
unsigned long currentTime_load_cell = 0;
unsigned long currentTime_motor = 0;
unsigned long previousTime = 0;
unsigned long previousTime2 = 0;
unsigned long previousButtonMillis =0; 




int bendingForce = 0;

void setup() {
  Serial.begin(115200);                                                  // data speed
  Wire.begin();      
  if (motor.begin() == false)                                           //Check if Qwiic Step is correctly connected to I2C
  {
   Serial.println("Device did not acknowledge! Freezing.");
    while (1);
  }
  Serial.println("Motor acknowledged.");
  pinMode(buttonpin, INPUT);                                            // assign buttonpin as input_pullup
  pinMode(buttonpin2, INPUT);
  pinMode(buttonpin3, INPUT);
  pinMode(ledblue, OUTPUT);
  
  if (myScale.begin() == false)                                        // check if scale is correctly connected to I2C
  {
Serial.println("Scale not detected. Please check wiring. Freezing...");
    while (1);
  }
Serial.println("Scale detected!");




}
  void loop()
{
    
  buttonstate2 = digitalRead(buttonpin2);
  if (buttonstate2 == HIGH){   // Emergency stop
  motor.stop();
  }
  
  STmotor();
//  loadcell();
  switchbutton();
}

// the relasionship of the button and its state
void switchbutton(){
  buttonstate = digitalRead(buttonpin);
  }

//==  Load cell: reading nonstop
  void loadcell() {     
    
  currentTime_load_cell = millis();
                          
  if (currentTime_load_cell - previousTime >= Interval){
  if(myScale.available() == true)
  {
   float currentReading = (myScale.getReading()-26000)/8181.8; // assume 1 pound = 8181.8 value
   float forceCalculated = currentReading*32.17;  // convert mass to force
   Serial.println(forceCalculated);
   bendingForce = forceCalculated;
  }
  previousTime = currentTime_load_cell;
  }
  }


//=== Acutator: initial process
  void STmotor(){
  if (buttonstate == HIGH){
  currentTime_motor = millis();
  motor.setModeRunContinuous(); //Tell the motor to run at the given speed... forever
  motor.setSpeed(800); // give the motor a speed
  if (currentTime_motor - previousTime2 >= Interval_further){ // After 5 seconds
  motor.setSpeed(-800);  // reverse
  }
  }

Thank you for spending time answering my question.
This is the entire code, i have for now.
I'll describe the whole thing in normal words in the way you typed.
An Arduino board controls the linear actuator, which is operated by a motor.
A load cell is attached at the tip of the linear actuator, which will detect force change as the actuator extends or shrinks.

When I press a button, the entire process began:
The load cell shall read the force, the motor shall run forward
If the force is high, the motor stops completely. [the load cell touch the specimen]
I press the same button again the actuator continues to extend for 5 seconds. [assume 5 seconds is enough to break the specimen]
Then the motor shall run backward until the actuator is back to its original position.

The above process continues again if I press the button again.

There is a way to make a "do-this-then-do-that-then-do-something-else-and-so-on" sketch.
It is called a Finite State Machine. The name is fancy, but the code is simple. Tutorial: The Finite State Machine | Majenko Technologies.
It that something you like ?

Combining a Finite State Machine with millis() is for advanced programmers. Maybe this example will help (you can try it): Fun_with_millis/millis_and_finite_state_machine.ino at master · Koepel/Fun_with_millis · GitHub.

It you don't like it, then you still have to rewrite your sketch. It is not possible to replace delay() with millis(). You have to split everything into parts and let a millis-timer decide which part should be executed.

Here is a sample of a possible set of states.

Unknown - We just fired up the machine. Who knows where things are? (Also good for crash recovery)
Initializing - Going from Unknown to Ready.
Ready - ready to run. In retracted position.
RunningToSample - As it says, running to sample looking for a touch.
Smashing - Breaking the sample.
Retracting - returning to state "Ready".

-jim lee

If you are using one button to do two jobs then you need a variable to keep track of the state of the system. Maybe something like

char systemState = 'W'; //  waiting - later it will be A for active, P for paused B for breaking or F for finishing

The logic of the system then works like this

if the button is pressed and systemState == 'W'
start the actuator
set systemState = 'A'

if the systemState == 'A' and the sensor detects something
stop the actuator
set systemState = 'P'

if the button is pressed and systemState == 'P'
start the actuator
save the value of millis() to breakingStartTime
set systemState = 'B'

if the systemState == 'B' and millis() - breakingStartTime >= 5000
stop the actuator
set the actuator to return to 0
set systemState = 'F'

if the systemState == 'F' and the actuator is at 0
stop the actuator
set systemState = 'W' - ready to start again

...R

Koepel:
There is a way to make a "do-this-then-do-that-then-do-something-else-and-so-on" sketch.
It is called a Finite State Machine. The name is fancy, but the code is simple. Tutorial: https://majenko.co.uk/blog/finite-state-machine.
It that something you like ?

Combining a Finite State Machine with millis() is for advanced programmers. Maybe this example will help (you can try it): Fun_with_millis/millis_and_finite_state_machine.ino at master · Koepel/Fun_with_millis · GitHub.

It you don't like it, then you still have to rewrite your sketch. It is not possible to replace delay() with millis(). You have to split everything into parts and let a millis-timer decide which part should be executed.

Thx i read a little bit, and it seems like exactly what i need.
I'll work on it and see if it works

  1. I try out the method of state switch, and for some reason. The example code for LED light works fine, but when i add the code for the motor (simply replace LEDstate = HIGH by motor.setSpeed(800)) then Arduino IDE keeps saying
    avrdude: stk500_recv(): programmer is not responding
    the selected serial port avrdude: stk500_recv(): programmer is not responding
    ** does not exist or your board is not connected**
    So I continue working on the original code I posted (2)
    but I'll also work on the state switch to see if I can make it work

  2. So what i find the problem is when i

if (buttonstate == HIGH) {
  dostuff = 1;
}
if (dostuff == 1){
  previousTime2= millis();
  motor.setModeRunContinuous(); //Tell the motor to run at the given speed... forever
  motor.setSpeed(-800); // give the motor a speed
//  Serial.println(millis() - previousTime2);
  if (millis() - previousTime2 >= Interval_further){ // After 5 seconds
  motor.stop(); 
  }
  dostuff = 0 ;
  } 
}

So what I notice is. Whenever I press the button. Arduino read through the whole code, but it only takes a few milliseconds, therefore it will never reach the 5 seconds interval, so it will never run the if statement to stop the motor.

I don't know if there is anyway to fix this.

What happens when you try to upload a simple, known sketch like Blink?

Blink does work,

void setup() {
    pinMode(13, OUTPUT);
      Serial.begin(115200);
}

void loop() {
    static int state = 2; // initial state is 1, the "idle" state.
    static unsigned long ts;  // To store the "current" time in for delays.

    switch (state)   {
        case 1:
            // We don't need to do anything here, waiting for a forced state change.
            break;

        case 2:
            digitalWrite(13, HIGH); // Turn on the light
            ts = millis();  // Remember the current time
            Serial.println(ts);
            state = 3;  // Move to the next state
            break;

        case 3:

            // If one second has passed, then move on to the next state.
            if (millis() - ts > 1000) {
                state = 4;
            }

            break;

        case 4:
            digitalWrite(13, LOW); // Turn off the light
            ts = millis();  // Remember the current time
            state = 5;
            break;

        case 5:

            // If one second has passed, then go back to state 2.
            if (millis() - ts > 1000) {
                state = 2;
            }

            break;

        case 6:
            // We only get here when forced from outside.
            digitalWrite(13, LOW); // Turn off the light
            state = 1;  // Return to the "idle" state.
            break;

        default:
            state = 1;
            break;
    }
}

This is the exact same code from the tutorial page:

And this one work on my board.

But them i add some libraries for my parts on the top, and a motor line to test if it can run then i get the error message.

#include "SparkFun_Qwiic_Step.h" //Click here to get the library: http://librarymanager/All#Qwiic_Step by SparkFun
#include <Wire.h>
#include "SparkFun_Qwiic_Scale_NAU7802_Arduino_Library.h"
NAU7802 myScale; //Create instance of the NAU7802 class
QwiicStep motor;

void setup() {
    pinMode(13, OUTPUT);
      Serial.begin(115200);
}

void loop() {
    static int state = 2; // initial state is 1, the "idle" state.
    static unsigned long ts;  // To store the "current" time in for delays.

    switch (state)   {
        case 1:
            // We don't need to do anything here, waiting for a forced state change.
            break;

        case 2:
            motor.setModeRunContinuous();               // only line i add
            motor.setSpeed(800);                        // and this one     --- basically tell the motor to run
            digitalWrite(13, HIGH); // Turn on the light
            ts = millis();  // Remember the current time
            Serial.println(ts);
            state = 3;  // Move to the next state
            break;

        case 3:

            // If one second has passed, then move on to the next state.
            if (millis() - ts > 1000) {
                state = 4;
            }

            break;

        case 4:
            digitalWrite(13, LOW); // Turn off the light
            ts = millis();  // Remember the current time
            state = 5;
            break;

        case 5:

            // If one second has passed, then go back to state 2.
            if (millis() - ts > 1000) {
                state = 2;
            }

            break;

        case 6:
            // We only get here when forced from outside.
            digitalWrite(13, LOW); // Turn off the light
            state = 1;  // Return to the "idle" state.
            break;

        default:
            state = 1;
            break;
    }
}

I test those lines one at a time to see what line causes the problem.

            motor.setModeRunContinuous();  
            motor.setSpeed(800);

end up these two lines cause the error.

I'm trying to rewrite a switch statement to see if i can fix it