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
Motor starts running(+), a scale will detect any change of pressure, if it happens, then the motor stop. (got this part done)
I press a button, the stepper motor continues running in + direction for 5 seconds, then stop
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
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
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. )
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, **
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
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
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.
/ 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 ?
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.
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".
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 ?
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
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
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.
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.