Millis() when condition is met....issue..

Hi

I'm having a real battle with millis at the moment and for the life of me I can't figure out what to tell the Arduino to do. I have written down exatly what I want but as soon as I start coding it I seem to just start confusing myself.

What I'm after is using an ultrasonic sensor to detect if an object is there for a period of time, say >5sec. If the condition is met then the green LED blinks. If an object is detected but doesn't meet the period of 5sec then the LED continues to just blink red.

I have followed UKHelibob's & BWD tutorials and I'm slowly starting to get to grips with it, but I feel there is something I'm missing or the penny hasn't quite dropped with something yet.

The code I've writted and amended several times just doens't quite work yet. I can get it blinking red without issue, I can get it to sense there is an object there for more than 5 secs. I can't seem to get the red LED to stop or the green LED to flash (it just goes solid on) or switch off once the object has been removed.

(Once I get the initial problem solved, I'd like to have the green LED flash once the object has been detected for >5sec, for a period of say 30sec before flashing an LED blue until the object has been removed. Then the whole thing reset once the object has been removed and the cycle starts again....but that is for later down the line once I get the first bit nailed.)

Any guidance or pointers in the right direction would be greatly appreciated.

Thank you in advance.

I'm using a Micro (clone) and the HC-SR04 ultrasonic sensor.

I've limited the range of the object detection so I can control the detection and it's not just picking up my wall.

This is the code in it's current form...it's been through many itteration that have been superseded (and deleted)

const int redLED = 6; //Red LED pin
const int greenLED = 7; //Green LED pin
const int blueLED = 8; //Blue LED pin
const int echoPin = 11; //sets ultrasonic sensor echopin
const int trigPin = 12; //sets ultrasonic sensor triggerpin

int ledState = LOW;
int distance; //distance from US sensor

const long blinkLED = 500; //LED blink time (ms)
unsigned long startTime = 0;
unsigned long currentTime;
const unsigned long objectCheck = 5000; //Checks for object (ms)

void setup() {
  //LEDs
  pinMode(redLED, OUTPUT);
  pinMode(greenLED, OUTPUT);
  pinMode(blueLED, OUTPUT);

  //US sensor
  pinMode(echoPin, INPUT);
  pinMode(trigPin, OUTPUT);
  Serial.begin(9600);

  startTime = millis(); //initial start time

}

void loop() {
  sendPing();
  int duration = pulseIn(echoPin, HIGH);
  distance = 0.034 * duration / 2;
  printToScreen(distance);


  currentTime = millis();

  //If object detected but for less than 5sec then continue blinking red
  if (distance >= 30 && distance <= 500 && currentTime - startTime <= objectCheck) {

    if (currentTime - startTime >= blinkLED) {
      if (ledState == LOW) {
        ledState = HIGH;
      } else {
        ledState = LOW;
      }

      // set the LED with the ledState of the variable:
      digitalWrite(redLED, ledState);

      startTime = currentTime;

    }
  }


  // If object deteceted then for more than 5sec then blink green
  else if (distance >= 10 && distance <= 500 && currentTime - startTime >= objectCheck) {

  if (currentTime - startTime >= blinkLED) {
      if (ledState == LOW) {
        ledState = HIGH;
      } else {
        ledState = LOW;
      }

      // set the LED with the ledState of the variable:
      digitalWrite(greenLED, ledState);

      startTime = currentTime;
    }
  }
}


void sendPing() {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(5);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
}

void printToScreen(int TARGET) {
  Serial.print(TARGET);
  Serial.println(" cm");
}

You need to use a different startTime to time your LEDs. What is happening is that as long as the object is within distance you continue blinking the RED LED and resetting startTime causing currentTime - startTime to never be greater than objectCheck.

Once the object has been within range for 5 seconds you need to set the Red LED off before blinking the green LED.

Also, when the object is out of range you need to reset the Green and Red LEDs to make sure they are off and also reset startTime so that when it is within range it can start timing from the correct start time.

Thanks for the reply @ToddL1962. Ah ok! I see what you're saying, I'll give it another go and report back (probably tomorrow as it's been a long day) :slight_smile:

Thank you

I donno' if this will work. It does compile but I have no distance sensor to test it with.

But, for a different approach..

#include <blinker.h>

const int redLED = 6; //Red LED pin
const int greenLED = 7; //Green LED pin
const int blueLED = 8; //Blue LED pin?
const int echoPin = 11; //sets ultrasonic sensor echopin
const int trigPin = 12; //sets ultrasonic sensor triggerpin

int distance; //distance from US sensor

blinker  redBlinker(redLED);        //A background blinker for red.
blinker  greenBlinker(greenLED);    // And another one for green
timeObj  theTimer(5000);            // A five second timer, starting NOW.

void setup(void) {

   redBlinker.setOnOff(true);       // Initial condition red is on.
   greenBlinker.setOnOff(false);    // And green will be off.

   pinMode(echoPin, INPUT);         // Do the stuff for the echo thing.
   pinMode(trigPin, OUTPUT);
   digitalWrite(trigPin, LOW);      // Make sure its set to low.
}


// Do what we need to do to get the distance.
float getDistance(void) {
   
   int   duration;
   float distance;
   
   digitalWrite(trigPin, HIGH);
   delayMicroseconds(10);
   digitalWrite(trigPin, LOW);
   duration = pulseIn(echoPin, HIGH);
   distance = 0.034 * duration / 2; 
   return distance;
}


void loop(void) {

   float distance;
   
   idle();                                   // Let the backgorund things like LED blinkers run.
   distance = getDistance();                 // Do the echo thing and get the distance.
   if (distance < 30 && distance > 500) {    // If the object is NOT in the correct location..
      theTimer.start();                      // We restart the timer from now.
      redBlinker.setOnOff(true);             // Make sure the red LED is on.
      greenBlinker.setOnOff(false);          // And the Green LED is off.
   } else if (theTimer.ding()) {             // Else, if the timer has expired.. (Been seeing it for > 5 sec.)
      redBlinker.setOnOff(false);            // We turn off the red LED.
      greenBlinker.setOnOff(true);           // And turn on the green LED
   }
}

This uses the LC-baseTools library to simplify the user code. You can grab it off the library manager if you would like to try it this way.

Enjoy!

-jim lee

Thanks JimLee. I'll give it a go later on! I would still like to crack the problem using a method similar to my original post as I won't learn otherwise :smiley:

I will definitely give your code a go though!! Thank you :slight_smile:

GaryRH:
What I'm after is using an ultrasonic sensor to detect if an object is there for a period of time, say >5sec.

The solution to that may appear as "upside-down logic" as in this pseudo code

if (object is not detected) {
   lastTimeThereWasNoObject = millis();
}
if (millis() - lastTimeThereWasNoObject >= 5000) {
  // object has been detected continuously for 5 secs
  // do something
}

...R

This timer example, Delay execution until condition has been true for X secs
from my How to Write Timers and Delays in Arduino tutorial is what you need

I would write it as a state machine. It looks like you have three states:
Blinking Red until an object has been present for 5 seconds
Then
Blinking Green until 30 seconds have passed
Then
Blinking Blue until the object is not detected
Then
Back to Blinking Red

// Example Finite State Machine


const int RedLEDPin = 6; //Red LED pin
const int GreenLEDPin = 7; //Green LED pin
const int BlueLEDPin = 8; //Blue LED pin
const int EchoPin = 11; //sets ultrasonic sensor echopin
const int TriggerPin = 12; //sets ultrasonic sensor triggerpin


// The states we can be in:
enum States {BLINK_RED, BLINK_GREEN, BLINK_BLUE} State = BLINK_RED;


const unsigned long BLINK_INTERVAL = 500;
const unsigned long OBJECT_PRESENT_INTERVAL = 5000;
const unsigned long BLINKING_GREEN_INTERVAL = 30000;


unsigned long StateStartTime;  // The time in millis() when the current state was entered.


void setup()
{
  Serial.begin(115200);


  pinMode(EchoPin, INPUT);
  pinMode(TriggerPin, OUTPUT);


  // Starting in BLINK_RED state
  State = BLINK_RED;


  StateStartTime = millis();
}


boolean ObjectIsAbsent()
{
  digitalWrite(TriggerPin, LOW);
  delayMicroseconds(5);
  digitalWrite(TriggerPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(TriggerPin, LOW);
  unsigned long duration = pulseIn(EchoPin, HIGH, (600 / 0.034) * 2UL);
  int distance = 0.034 * duration / 2;
  Serial.print(distance);
  Serial.println(" cm");
  return distance < 10;
}


void loop()
{
  unsigned long currentTime = millis();
  static unsigned long lastObjectAbsentTime = 0;
  boolean absent = ObjectIsAbsent();
  if (absent)
    lastObjectAbsentTime = currentTime;


  switch (State)
  {
    case BLINK_RED:
      // Blink the Red LED
      digitalWrite(RedLEDPin, (millis() / BLINK_INTERVAL) & 1);


      // Has an object been present long enough?
      if (currentTime - lastObjectAbsentTime >= OBJECT_PRESENT_INTERVAL)
      {
        digitalWrite(RedLEDPin, LOW); // Stop blinking red
        State = BLINK_GREEN;
        StateStartTime = currentTime;
      }
      break;


    case BLINK_GREEN:
      // Blink the Green LED
      digitalWrite(GreenLEDPin, (millis() / BLINK_INTERVAL) & 1);


      // Has the Green been blinking long enough?
      if (currentTime - StateStartTime >= BLINKING_GREEN_INTERVAL)
      {
        digitalWrite(GreenLEDPin, LOW); // Stop blinking green
        State = BLINK_BLUE;
      }
      break;


    case BLINK_BLUE:
      // Blink the Blue LED
      digitalWrite(BlueLEDPin, (millis() / BLINK_INTERVAL) & 1);


      // Has the object been removed?
      if (absent)
      {
        digitalWrite(BlueLEDPin, LOW); // Stop blinking blue
        State = BLINK_RED;
      }
      break;


  } // End switch(State)
}

johnwasser:
I would write it as a state machine. It looks like you have three states:
Blinking Red until an object has been present for 5 seconds
Then
Blinking Green until 30 seconds have passed
Then
Blinking Blue until the object is not detected
Then
Back to Blinking Red

This is very cool. I've not come across a state machine before but after some youtubes and googles it makes the most sense to approach it like this. Much cleaner. Thank you.
I think state machines are my new favourite thing.

drmpf:
This timer example, Delay execution until condition has been true for X secs
from my How to Write Timers and Delays in Arduino tutorial is what you need

This is great, thank you for the links! Although I'll probably look going down the state machine route, I still want to make what I started work. Just so the concept sticks.

Using Delay execution until condition has been true for X secs will save you a couple of states / flags,
but you can do it all with states if you want.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.