Need an AND condition with a 1 sec delay before and after the &&

I would like to know how to write a conditional statement using AND “&&” that includes a 1 second delay between the statements before and after the &&. (or maybe such code is not using AND “&&”) Let me explain to be clear.

Right now I have the following which works well to active the onboard LED light if I tilt my IMU sensor more than say 40 degrees.

if (accelerometer_x < -5000) {
    digitalWrite(LED_BUILTIN, HIGH);

I would like the LED to come on only when I tilt the board past the 40 degs AND with 1 sec back to under say 5 degs but with the AND condition the LED obviously will never light up because this condition can never be physically satisfied if I am asking it to be done simultaneously as such:

} else if (accelerometer_x > 5000 && (accelerometer_x < 1000) ) {

So how do I add the following condition to my code?

Assuming we are starting at 0000 which is level;
When the X axis sensor is tilted to more than 5000 and within 1 sec it goes back to under 1000 execute the event.

Thanks in advance for your help.

Below is the entire code:

#include <Wire.h>

const int MPU_ADDR=0x68;

int16_t accelerometer_x, accelerometer_y, accelerometer_z;
int16_t gyro_x, gyro_y, gyro_z;
int16_t temperature;

char tmp_str[7];

char* convert_int16_to_str(int16_t i) {
  sprintf(tmp_str, "%6d", i);
  return tmp_str; 
}

void setup() {
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);
  Wire.begin();
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x6B);
  Wire.write(0x00); // Wake up MPU
  Wire.endTransmission(true);
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x1B); // Gyro set to 500deg/s
  Wire.write(0b00001000);
  Wire.endTransmission(true);
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x1C); // Accel set to 4g
  Wire.write(0b00001000);
  Wire.endTransmission(true);
  
}
void loop() {
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x3B);
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_ADDR, 7*2, true);
  
  accelerometer_x = Wire.read()<<8 | Wire.read();
  accelerometer_y = Wire.read()<<8 | Wire.read();
  accelerometer_z = Wire.read()<<8 | Wire.read();
  temperature = Wire.read()<<8 | Wire.read();
  gyro_x = Wire.read()<<8 | Wire.read();
  gyro_y = Wire.read()<<8 | Wire.read();
  gyro_z = Wire.read()<<8 | Wire.read();

  Serial.print("aX = "); Serial.print(convert_int16_to_str(accelerometer_x));
  Serial.print(" | aY = "); Serial.print(convert_int16_to_str(accelerometer_y));
  Serial.print(" | aZ = "); Serial.print(convert_int16_to_str(accelerometer_z));
  Serial.print(" | tmp = "); Serial.print(temperature/340.00+36.53);
  Serial.print(" | gX = "); Serial.print(convert_int16_to_str(gyro_x));
  Serial.print(" | gY = "); Serial.print(convert_int16_to_str(gyro_y));
  Serial.print(" | gZ = "); Serial.print(convert_int16_to_str(gyro_z));
  Serial.println();

  if (accelerometer_x < -5000) {
    digitalWrite(LED_BUILTIN, HIGH);
    
  } else if (accelerometer_x > 5000) {
    digitalWrite(LED_BUILTIN, HIGH);
    
  } else {
    digitalWrite(LED_BUILTIN, LOW);
  
  }
  
    delay(100);
    
}

You have to capture the time when the first condition was met and then on a future pass through loop(), compare the current position to elapsed time and if you are back within spec and under 1 second, execute the event. If more than 1 second has elapsed, you can abandon the time the first condition was met.

Think of it like a state machine.

State 1: waiting for angle to be greater than 5000 (or whatever)
State 2: angle was achieved, waiting for 1 second to elapse or angle return to 0

Search the forum for "How to do multiple things at the same time" for a good example.

I am new to coding but verbally that makes sense.

I am looking for the actual code that will execute this!

In the meantime I will search with the title you suggested ""How to do multiple things at the same time"

Vertical757:
In the meantime I will search with the title you suggested ""How to do multiple things at the same time"

The correct search term is 'several things at the same time'. :wink:

Several Things at a Time

...R

I had been reading the arduino tutorials including “using millis instead of delay” also the “blink without delay”, “several things at the same time” and it seems I have titled the topic in this thread with the wrong title.

Seems I will never accomplish what I want with the && “AND” conditional, it is all about using Millis for timing, I just don’t know how to place and contain the millis in the conditional AND statements before the next 'if" or “if else” conditional take affect.

I have been successful to use millis as a substitution for delay (which I really needed) as follows:

 unsigned long time_now = 0;   // placed outside the loop 

           time_now = millis();               // placed inside the loop


            if (accelerometer_x < -5000) {
            while(millis() < time_now + 1000)
            digitalWrite(LED_BUILTIN, HIGH);
            servoL.write(175);
            while(millis() < time_now + 3000){
            }
            
          } else if (accelerometer_x > 5000) {
            while(millis() < time_now + 1000)
            digitalWrite(LED_BUILTIN, HIGH);
            servoR.write(5);
            while(millis() < time_now + 3000){
            }

Now I am trying to use this same principle for the following in this exact sequence:

if (accel_x < -5000) and within 2 secs (accel_x > 5000) and within 1sec (accel_x <1000

then and only then, execute led high.

Could someone give me a code example of how I can do this? Thanks for everyone’s time!

What kind of information does an accelerometer produce?

How about using,

//Roll & Pitch Equations from accelerometers only
      float roll  = (atan2(-_ay, _az)*180.0)/M_PI;
      float pitch = (atan2(_ax, sqrt(_ay*_ay + _az*_az))*180.0)/M_PI;

,to get degrees?

            while(millis() < time_now + 1000)

digitalWrite(LED_BUILTIN, HIGH);

Several things wrong with that.

  1. You didn’t use braces {} for a multi-line while block. It only repeats the line I quoted, not any other line. Always always always use {} with while, do, for or any other construct like that.

  2. You added times instead of subtracting. This code will malfunction after 49 days. The maths you learned in school says that millis() - time_now < 1000 is exactly identical but with unsigned integers and rollover, it is not identical for the Arduino.

  3. You just wrote delay(1000 + time_now-millis()) in a less-perfect way. If you want a delay(1000) then just delay(1000). However I suggest you avoid the use of delay() entirely.

void loop() {
  const int threshold = 5000;             //accelereometer threshold
  const int timePeriodDesired = 1000; //milliseconds
  static bool underThreshold = false;
  static unsigned long firstExceededThreshold = 0;

  getAccelerometer();  //you should take all of the Wire stuff out of the loop and put it into a function

  if(underThreshold) {
    if(acccelerometer_x > threshold) {
      underThreshold = false;
      firstExceededThreshold = millis();
    }
  } else {
    if(acccelerometer_x < threshold) {
      underThreshold = true;
      if(millis() - firstExceededThreshold > timePeriodDesired) {
        doTheActionRequiredWhenLongerThan1Second();
      } else {
        doTheActionForUnder1Second();
      }
    }
  }
}

Idahowalker:
What kind of information does an accelerometer produce?

How about using,

//Roll & Pitch Equations from accelerometers only

float roll  = (atan2(-_ay, _az)180.0)/M_PI;
      float pitch = (atan2(_ax, sqrt(_ay
_ay + _az*_az))*180.0)/M_PI;



,to get degrees?

I am just using raw data from the IMU just to keep the code short and simple to post it here and try to figure out a good working code for:

if (accel_x < -5000) and within 2 secs (accel_x > 5000) and within 1sec (accel_x <1000

To get degrees (and some serious algorithms to filter the x, y, and z axis I use the 6-axis MotionApps 2.0 which is part of the I2Cdev library collection for the MPU6050 I2C IMU device. You can download from the arduino.cc library or just google it, there are a lot of places to download it from.

MorganS:
Several things wrong with that.

  1. You didn’t use braces {} for a multi-line while block. It only repeats the line I quoted, not any other line. Always always always use {} with while, do, for or any other construct like that.

  2. You added times instead of subtracting. This code will malfunction after 49 days. The maths you learned in school says that millis() - time_now < 1000 is exactly identical but with unsigned integers and rollover, it is not identical for the Arduino.

  3. You just wrote delay(1000 + time_now-millis()) in a less-perfect way. If you want a delay(1000) then just delay(1000). However I suggest you avoid the use of delay() entirely.

void loop() {

const int threshold = 5000;            //accelereometer threshold
  const int timePeriodDesired = 1000; //milliseconds
  static bool underThreshold = false;
  static unsigned long firstExceededThreshold = 0;

getAccelerometer();  //you should take all of the Wire stuff out of the loop and put it into a function

if(underThreshold) {
    if(acccelerometer_x > threshold) {
      underThreshold = false;
      firstExceededThreshold = millis();
    }
  } else {
    if(acccelerometer_x < threshold) {
      underThreshold = true;
      if(millis() - firstExceededThreshold > timePeriodDesired) {
        doTheActionRequiredWhenLongerThan1Second();
      } else {
        doTheActionForUnder1Second();
      }
    }
  }
}

I am new to coding so need some time to digest all you wrote, thank you for all the info, however I think there has been a misunderstanding. The “millis” I wrote is working perfectly to what I need it to do even though it expires in 49 days(I will never need it to run that long)
It has nothing to do with the sequential code I need to code:
if (accel_x < -5000) and within 2 secs (accel_x > 5000) and within 1sec (accel_x <1000

It simply adds a delay after the (accel_x < -5000) condition is fulfilled and executed to make the led go high “1 sec after the execution” and kept high for 2secs before going low" It is working great.
Even though it is working great I will indeed make the changes adding the braces and so forth, I want to learn how to code correctly and efficiently.
Yes, I heard about the 49 day (and change) expiration of the “millis” and even tough for this specific application it does not matter, I would like to know how to use millis in a way that when the 49 day expires and roles over, the millis code continues without missing a beat.

Yes, I agree, I want to avoid using “delay” as much as possible and not “pause” the code every time “delay” is used.

As you can see most of my “wire” stuff is outside of the loop but it is my understanding that the ones that are placed inside the loop need to be there because the MPU-6050 register “0x3B”(and subsequent 6 other registers) need to be read consistently (in a loop) to obtain a continuous data stream for the x, y, z readouts.

What I really want to focus on, which I have been pulling hairs for the last 5 days is the code for:

if (accel_x < -5000) and within 2 secs (accel_x > 5000) and within 1sec (accel_x <1000

It is really confusing for me incorporating the “millis” for this (or maybe there is a different way) but I want to understand it.

The following is my working code revised to be more compact and leaving out anything that is not relevant to finding the answer to my dilemma:
The following is a good clean working code to read the IMU’s raw data (MPU-6050) over serial and also adding a conditional statement that if IMU is tilted for than 5000 raw (about 25 degrees of tilt) the on board led goes on.
I just need to find how to incorporate a “if (accel_x < -5000) and within 2 secs (accel_x > 5000) and within 1sec (accel_x <1000” condition to this code.

Here is my working compact code.

#include <Wire.h>

int16_t accel_x, accel_y, accel_z;
int16_t gyro_x, gyro_y, gyro_z;
int16_t temp;

char tmp_str[7];

char* convert_int16_to_str(int16_t i) {
  sprintf(tmp_str, "%6d", i);
  return tmp_str; 
}

void setup() {
  Wire.begin();
  Wire.setClock(200000);
  Serial.begin(38400);
  pinMode(LED_BUILTIN, OUTPUT);
  
  Wire.beginTransmission(0x68);
  Wire.write(0x6B);
  Wire.write(0x00);
  Wire.endTransmission(true);
  
}
void loop() {
   
  Wire.beginTransmission(0x68);
  Wire.write(0x3B);
  Wire.endTransmission(false);
  Wire.requestFrom(0x68, 7*2, true);
  accel_x = Wire.read()<<8 | Wire.read();
  accel_y = Wire.read()<<8 | Wire.read();
  accel_z = Wire.read()<<8 | Wire.read();
  temp = Wire.read()<<8 | Wire.read();
  gyro_x = Wire.read()<<8 | Wire.read();
  gyro_y = Wire.read()<<8 | Wire.read();
  gyro_z = Wire.read()<<8 | Wire.read();

  Serial.print("aX = "); Serial.print(convert_int16_to_str(accel_x));
  Serial.print(" | aY = "); Serial.print(convert_int16_to_str(accel_y));
  Serial.print(" | aZ = "); Serial.print(convert_int16_to_str(accel_z));
  Serial.print(" | tmp = "); Serial.print(temp/340.00+36.53);
  Serial.print(" | gX = "); Serial.print(convert_int16_to_str(gyro_x));
  Serial.print(" | gY = "); Serial.print(convert_int16_to_str(gyro_y));
  Serial.print(" | gZ = "); Serial.print(convert_int16_to_str(gyro_z));
  Serial.println();


// Conditional using && "AND" does not work because it makes the "and" happen simultaneously.

// These are the conditions I would like to add to (accel_x < -5000) in this following order:

// if (accel_x < -5000) and within 2 secs (accel_x > 5000) and after that, if within 1sec (accel_x <1000  led goes high

  if (accel_x < -5000) {
    digitalWrite(LED_BUILTIN, HIGH);
    
  } else {
    digitalWrite(LED_BUILTIN, LOW);
  
  }
  
}

Buried in the code:
if (accel_x < -5000) and within 2 secs (accel_x > 5000) and after that, if within 1sec (accel_x <1000 led goes high

OK, that’s what happens if everything goes right. What happens if you get -5000 but not +5000 within 2 seconds? Do we have to wait for -5000 again?

What happens if you don’t get <1000 within 1 second? Do we go back to waiting for >5000 or <-5000?

MorganS:
OK, that’s what happens if everything goes right. What happens if you get -5000 but not +5000 within 2 seconds? Do we have to wait for -5000 again?

What happens if you don’t get <1000 within 1 second? Do we go back to waiting for >5000 or <-5000?

It is all or nothing. Do all 3 things in the exact sequence and with the given delays or do nothing.
If something happened in the sequence “partially” go back and start all over waiting for the <-5000

So, if I get -5000 but not +5000 within 2 seconds, go back to the -5000 and wait again.

If I do not get 1000 within 1 second of +5000 go back to the -5000 and wait again.

So, basically if this “trifecta” does not happen, do nothing and start monitoring all over again from the beginning.

Ok. Then draw that on paper. Look at the sequence of states it makes. Look at all the arrows between states. Write code for each arrow.

I didn't ask the question because I wanted the answer. I asked to make you think about it.

Hi Vertical; I’ve been facing a similar problem timing a sequence of events.
I use a timer tick interrupt to increment a counter every millisecond.

You dont seem to have a “ground state” so I’m assuming that is the -5000

You can say (pseudocode)

condition 1: A < -5000
start timer T
while T<2000 {read A: if Anew>Aold Aold=Anew: if Aold>+5000 break; )
//condition 2 success
then {condition=2 ; reset timer}
else {condition =1; reset timer};
}
if (condition==2){
while T<1000 {read A: if Anew<Aold Aold=Anew: if Aold<+1000 break; ]
//condition 3 success
then {condition=3 ; reset timer}
else {condition =1; reset timer};
}

my timer is simple.

in setup start a timer tick interrupt
//Timer0 is already used for millis() - we’ll just interrupt somewhere
//in the middle and call the “Compare A” function below
OCR0A = 0xAF; // set compare register to #175, interrupt on match
TIMSK0 |= _BV(OCIE0A);

and the isr:
// Timer tick interrupt is called once a millisecond,
ISR(TIMER0_COMPA_vect)
{
timerCount+=1;
}

ok you could use millis() but I find that confusing.

Hope all that helps

How is millis() confusing? It counts milliseconds too.

You did not show how you imagine "reset" might work.

How can your "solution" be extended to time more than one thing?

MorganS:
Ok. Then draw that on paper. Look at the sequence of states it makes. Look at all the arrows between states. Write code for each arrow.

I didn’t ask the question because I wanted the answer. I asked to make you think about it.

So, you know how to write the code for these 3 timed sequential states? You just want me to think about it and learn?

I want to learn this more then anything but I would not know how to begin to implement the code with a time relationship function.
I think the best way for me to learn is to see and study a working code, which is how I come to know what I know today.
I am only a beginner and have recently learned how to write code for simple stuff like assigning a pin # to turn leds on and off, to send pwm to control a servo, to press a button to bring a pin low to cause a change of state and recently how to use millis with only a few lines to substitute “delay” (to avoid pausing the entire code) This and a few other simple coding is all I know at this point.

The only way I know how to write a “if” sequence of 3 different states is by && “AND”
as such,

if ( accel_x < -5000 && (accel_x > 5000 && (accel_x <1000 )
{

but the && command does not help in my situation because it is looking for all 3 states to be true simultaneously. There is no time delay control between the states.

Morgan, let me ask you this again; You known exactly how to write the code for this time sequence that I need?

Reaearch "state machine". Do not give up if the first result seems unhelpful. One of the tutorials online will switch on the lightbulb for you.

The alternative is to pay. What is it worth to you?

johnerrington:
condition 1: A < -5000
start timer T
if (A > +5000 AND T < 2000) //condition 2 success
then {condition=2 ; reset timer}
else {condition =1; reset timer};
if (condition==2 && A<1000 && T<1000) //condition 3 success
then {condition=3 ; reset timer}
else {condition =1; reset timer};

I like how it reads, this makes sense to me, I am going to try to see if this works with my code to produce the desired effect.

The above code placed in my loop is all I need? (modified with my exact variables, of course)
I do not need to set some Global Constants or anything thing else?

MorganS:
Reaearch "state machine". Do not give up if the first result seems unhelpful. One of the tutorials online will switch on the lightbulb for you.

The alternative is to pay. What is it worth to you?

I did read up on the '"State Machine" and its principles and also I found a lot of examples. It even deals with a count down "timer" but non of it expresses or shows anything close to a multiple "if" conditional statement, sequential in effect, with a timed delay relationship between the different states.
Here is a quote:
"The concept of a State Machine is that your code knows at any moment what state it is in (because it is recorded in some variable) and there are clearly identified processes for changing state either when something happens (like a button being pressed, a temperature being reached, or a time expiring)."

You didn't answer my question, can you please just answer me yes or no?

Do you know how to write the code for the multiple state sequence that I need?

Yes.

Does that answer get you any closer to a solution?