Erratic boolean or millis behavior?

Dear all,

I have been designing a ultrasonic sensor and use a motor as an proximity alarm.

With the help from the community, I put the codes together so that:

1.) When distance is far enough (>triggerDistance), stops motor, and add a delay;
2) When distance is close enough (<triggerDistance), starts the motor, but stops after a few seconds)

While my codes seems to be working on Arduino Uno, it behaves erratically when I transferred the code to Arduion nano V3.0

Condition 1 have no problems, while condition 2 does not always work.

I guess something wrong with the boolean tripped function or millis function?

#define echoPin 2 // Echo Pin
#define trigPin 3 // Trigger Pin
#define LEDPin 13 // Onboard LED
#define motorPin 19
#define powerPin 4
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int motorState = 0;             // motorState used to set the LED
unsigned long previousMillis;        // will store last time LED was updated
unsigned long startTime;
long interval = 1000;
boolean lastTrip;
boolean lastTrip2;
//
int maximumRange = 200; // Maximum range needed
int minimumRange = 10; // Minimum range needed
int triggerDistance = 10;
int crashDistance = 5;
//long duration, distance; // Duration used to calculate distance
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() 
{
  pinMode(powerPin, OUTPUT);
  pinMode(motorPin, OUTPUT);
  Serial.begin (9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(LEDPin, OUTPUT); // Use LED indicator (if required)
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
long getDistance()
{
  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2); 
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10); 
  digitalWrite(trigPin, LOW);
  long duration = pulseIn(echoPin, HIGH);
  long dist = duration/58.2;
  return dist;
}
//////////////////////////////////////////////////////////////////////////////////
void runMotor()
{
  if( millis() - startTime < 3000) // Three Second Interval
  {
    analogWrite(motorPin, 200);
    //or digitalWrite(motorPin, HIGH);
 
  }
  else
  {
    analogWrite(motorPin, 0);
    //or digitalWrite(motorPin, LOW);
    motorState = 0;
  }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
void runMotor2()
{
  if( millis() - startTime < 3000) // Three Second Interval
  {
    analogWrite(motorPin, 200);
    //or digitalWrite(motorPin, HIGH);
 
  }
  else
  {
    analogWrite(motorPin, 0);
    //or digitalWrite(motorPin, LOW);
    motorState = 0;
  }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() 
{
  digitalWrite(powerPin, HIGH);
  long distance = getDistance();
  if (distance > minimumRange)
  {
    Serial.println(distance);
    digitalWrite(LEDPin, LOW); 
  }
  if (distance < minimumRange)
  {
    Serial.println(distance);
    digitalWrite(LEDPin, HIGH); 
  }
  ////////////////////////////////////////////////////////////////////////////////////////////////////////
  boolean tripped = (distance <= triggerDistance ? 1 : 0); // flag if triggered
  if (tripped)
  {
    if (tripped != lastTrip)
    {
      startTime = millis();
      motorState = 1;
    }
  }
  lastTrip = tripped;
  if (motorState == 1)
  {
    runMotor();
  }
  
  ////////////////////////////////////////////////////////////////////////////////////////////////////////
  boolean tripped2 = (distance <= crashDistance ? 1 : 0); // flag if triggered
  if (tripped2)
  {
    if (tripped2 != lastTrip2)
    {
      startTime = millis();
      motorState = 2;
    }
  }
  lastTrip = tripped;
  if (motorState == 2)
  {
    runMotor2();
  }
  
  //////////////////////////////////////////////////////////////////////////////////////////////////////////
if (distance > triggerDistance)
{analogWrite(motorPin, 0);
motorState = 0;
delay (500);
}

}

Please have a look on my codes, many thanks in advance!

also, look at these two blocks of code:

possibly a cut/paste error

 ////////////////////////////////////////////////////////////////////////////////////////////////////////
  boolean tripped = (distance <= triggerDistance ? 1 : 0); // flag if triggered
  if (tripped)
  {
    if (tripped != lastTrip)
    {
      startTime = millis();
      motorState = 1;
    }
  }
  lastTrip = tripped;// <<<<<<<<<<<<<<<<<<<< here
  if (motorState == 1)
  {
    runMotor();
  }

  ////////////////////////////////////////////////////////////////////////////////////////////////////////
  boolean tripped2 = (distance <= crashDistance ? 1 : 0); // flag if triggered
  if (tripped2)
  {
    if (tripped2 != lastTrip2)
    {
      startTime = millis();
      motorState = 2;
    }
  }
  lastTrip = tripped;//  <<<<<<<<<<<you are using same variable as above
  if (motorState == 2)
  {
    runMotor2();
  }

Thanks for your help!

I updated the codes, but it doesn't know how to stop.

I think something wrong with the millis function?

post where you are now, please

#define echoPin 2 // Echo Pin
#define trigPin 3 // Trigger Pin
#define LEDPin 13 // Onboard LED
#define motorPin 19
#define powerPin 4
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int motorState = 0;             // motorState used to set the LED
unsigned long previousMillis;        // will store last time LED was updated
unsigned long startTime;
[color=red]unsigned long startTime2; //<<<<<<<<<<New variable added[/color]
long interval = 1000;
boolean lastTrip;
boolean lastTrip2;
//
int maximumRange = 200; // Maximum range needed
int minimumRange = 10; // Minimum range needed
int triggerDistance = 10;
int crashDistance = 5;
//long duration, distance; // Duration used to calculate distance
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() 
{
  pinMode(powerPin, OUTPUT);
  pinMode(motorPin, OUTPUT);
  Serial.begin (9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(LEDPin, OUTPUT); // Use LED indicator (if required)
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
long getDistance()
{
  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2); 
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10); 
  digitalWrite(trigPin, LOW);
  long duration = pulseIn(echoPin, HIGH);
  long dist = duration/58.2;
  return dist;
}
//////////////////////////////////////////////////////////////////////////////////
void runMotor()
{
  if( millis() - startTime < 500) // Three Second Interval
  {
    analogWrite(motorPin, 200);
    //or digitalWrite(motorPin, HIGH);
 
  }
  else
  {
    analogWrite(motorPin, 0);
    //or digitalWrite(motorPin, LOW);
    motorState = 0;
  }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
void runMotor2()
{
  if( millis() - startTime2 < 3000) // Three Second Interval
  {
    analogWrite(motorPin, 200);
    //or digitalWrite(motorPin, HIGH);
 
  }
  else
  {
    analogWrite(motorPin, 0);
    //or digitalWrite(motorPin, LOW);
    motorState = 0;
  }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() 
{
  digitalWrite(powerPin, HIGH);
  long distance = getDistance();
  if (distance > minimumRange)
  {
    Serial.println(distance);
    digitalWrite(LEDPin, LOW); 
  }
  if (distance < minimumRange)
  {
    Serial.println(distance);
    digitalWrite(LEDPin, HIGH); 
  }
  ////////////////////////////////////////////////////////////////////////////////////////////////////////
  boolean tripped = (distance <= triggerDistance ? 1 : 0); // flag if triggered
  if (tripped)
  {
    if (tripped != lastTrip)
    {
      startTime = millis();
      motorState = 1;
    }
  }
  lastTrip = tripped;
  if (motorState == 1)
  {
    runMotor();
  }
  
  ////////////////////////////////////////////////////////////////////////////////////////////////////////
  boolean tripped2 = (distance <= crashDistance ? 1 : 0); // flag if triggered
  if (tripped2)
  {
    if (tripped2 != lastTrip2)
    {
      [color=red]startTime2 = millis(); //<<<<<<< In addition, I found that I am using the same starttime function, did correction here[/color]
      motorState = 2;
    }
  }
  [color=red]lastTrip = tripped2; // <<<<<<<<<Updated[/color]
  if (motorState == 2)
  {
    runMotor2();
  }
  
  //////////////////////////////////////////////////////////////////////////////////////////////////////////
if (distance > triggerDistance)
{analogWrite(motorPin, 0);
motorState = 0;
delay (500);
}

}

Please kindly refer to my codes, I highlighted the changes.

As for now:

  1. Motor shakes when an object near the ultrasonic sensor
  2. Motor stops when the object is removed
  3. Motor WILL NOT stop when the object is placed more than predetermined time.

you are still using the old variable here:

if (tripped2)
  {
    if (tripped2 != lastTrip2)
    {
      startTime2 = millis(); //<<<<<
      motorState = 2;
    }
  }
  lastTrip = tripped2; // <<<<<<<<< Right Here
  if (motorState == 2)
  {
    runMotor2();
  }

you want this I believe:

if (tripped2)
  {
    if (tripped2 != lastTrip2)
    {
      startTime2 = millis(); //<
      motorState = 2;
    }
  }
  lastTrip2 = tripped2; // <<<<<<<<< Updated
  if (motorState == 2)
  {
    runMotor2();
  }

let me look it over while you look int that...

BulldogLowell:
you are still using the old variable here:

if (tripped2)

{
    if (tripped2 != lastTrip2)
    {
      startTime2 = millis(); //<<<<<
      motorState = 2;
    }
  }
  lastTrip = tripped2; // <<<<<<<<< Right Here
  if (motorState == 2)
  {
    runMotor2();
  }




you want this I believe:



if (tripped2)
  {
    if (tripped2 != lastTrip2)
    {
      startTime2 = millis(); //<
      motorState = 2;
    }
  }
  lastTrip2 = tripped2; // <<<<<<<<< Updated
  if (motorState == 2)
  {
    runMotor2();
  }




let me look it over while you look int that...

After I corrected all silly mistakes and put a nice "2" in corresponding places, it worked!! XD

Here's my new code, many thanks Lowell!!!
And, let me express my thanks on behalf for my sister, she will not crash her leg when driving her wheelchair (hopefully :open_mouth:)

#define echoPin 2 // Echo Pin
#define trigPin 3 // Trigger Pin
#define LEDPin 13 // Onboard LED
#define motorPin 19
#define powerPin 4
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int motorState = 0;             // motorState used to set the LED
unsigned long previousMillis;        // will store last time LED was updated
unsigned long startTime;
unsigned long startTime2;
long interval = 1000;
boolean lastTrip;
boolean lastTrip2;
//
int maximumRange = 200; // Maximum range needed
int minimumRange = 10; // Minimum range needed
int triggerDistance = 15;
int crashDistance = 8;
//long duration, distance; // Duration used to calculate distance
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() 
{
  pinMode(powerPin, OUTPUT);
  pinMode(motorPin, OUTPUT);
  Serial.begin (9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(LEDPin, OUTPUT); // Use LED indicator (if required)
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
long getDistance()
{
  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2); 
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10); 
  digitalWrite(trigPin, LOW);
  long duration = pulseIn(echoPin, HIGH);
  long dist = duration/58.2;
  return dist;
}
//////////////////////////////////////////////////////////////////////////////////
void runMotor()
{
  if( millis() - startTime < 500) // Three Second Interval
  {
    analogWrite(motorPin, 200);
    //or digitalWrite(motorPin, HIGH);
 
  }
  else
  {
    analogWrite(motorPin, 0);
    //or digitalWrite(motorPin, LOW);
    motorState = 0;
  }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
void runMotor2()
{
  if( millis() - startTime2 < 3000) // Three Second Interval
  {
    analogWrite(motorPin, 200);
    //or digitalWrite(motorPin, HIGH);
 
  }
  else
  {
    analogWrite(motorPin, 0);
    //or digitalWrite(motorPin, LOW);
    motorState = 0;
  }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() 
{
  digitalWrite(powerPin, HIGH);
  long distance = getDistance();
  if (distance > minimumRange)
  {
    Serial.println(distance);
    digitalWrite(LEDPin, LOW); 
  }
  if (distance < minimumRange)
  {
    Serial.println(distance);
    digitalWrite(LEDPin, HIGH); 
  }
  ////////////////////////////////////////////////////////////////////////////////////////////////////////
  boolean tripped = (distance <= triggerDistance ? 1 : 0); // flag if triggered
  if (tripped)
  {
    if (tripped != lastTrip)
    {
      startTime = millis();
      motorState = 1;
    }
  }
  lastTrip = tripped;
  if (motorState == 1)
  {
    runMotor();
  }
  
  ////////////////////////////////////////////////////////////////////////////////////////////////////////
  boolean tripped2 = (distance <= crashDistance ? 1 : 0); // flag if triggered
  if (tripped2)
  {
    if (tripped2 != lastTrip2)
    {
      startTime2 = millis();
      motorState = 2;
    }
  }
  lastTrip2 = tripped2;
  if (motorState == 2)
  {
    runMotor2();
  }
  
  //////////////////////////////////////////////////////////////////////////////////////////////////////////
if (distance > triggerDistance)
{analogWrite(motorPin, 0);
motorState = 0;
delay (500);
}

}

A quick question, I have heard millis will overflow if arduino was left running for several days.
Will this disable my program?
Do I need to add some codes to prevent this?

I have heard millis will overflow if arduino was left running for several days.

It will. So does your watch, and that's not a problem, is it?

Will this disable my program?

Not if handled properly.

Do I need to add some codes to prevent this?

That depends on what you are trying to prevent. You can't prevent rollover.

henryvii99:
A quick question, I have heard millis will overflow if arduino was left running for several days.
Will this disable my program?
Do I need to add some codes to prevent this?

there is a very technical explanation here which if you read it, will tell you the way you have structured your millis() timers (using unsigned long subtraction) that you will avoid any issues regarding rollover of the millis() timer. :slight_smile:

UL_CurrentTime - UL_StartTime >= UL_Interval;

Personally, I like to force my constants into the desired form so that later, when I make a change to a sketch, I immediately recognise what kind of math I'm doing; for example:

instead of this:

  if( millis() - startTime < 500) // Three Second Interval

I'd do this:

  if( millis() - startTime < 500UL) // fix this note too...

I'm just wandering in the forum...
but int the following condition

if( millis() - startTime < 500UL)

the subtraction, shouldn't be casted?

Something like

if( (int) (millis() - startTime) < 500UL)

the subtraction, shouldn't be casted?

No. Subtracting an unsigned long from an unsigned long results in an unsigned long value. Casting that to an int, and then comparing the int to an unsigned long does not make sense.

henryvii99:
A quick question, I have heard millis will overflow if arduino was left running for several days.
Will this disable my program?
Do I need to add some codes to prevent this?

EngineerWithTheGear:
I'm just wandering in the forum...
but int the following condition

if( millis() - startTime < 500UL)

the subtraction, shouldn't be casted?

Something like

if( (int) (millis() - startTime) < 500UL)

Absolutely not. Casting is throwing away information in this case. Why would you want to do that?

That was intended to (mis)handling the millis rollover. The link you shared (Gammon Forum : Electronics : Microprocessors : millis() overflow ... a bad thing?) has clarified the question to me. Thank you.