Go Down

Topic: Trying to use time variable to calculate entry within a sensor (Read 581 times) previous topic - next topic

nobodylikeswasps

Hey everyone. This is my first post here, and I am very new to Arduino. I'm trying to create a game, where i have an lcd screen, a push button, and an ultrasonic sensor hooked up to my arduino leonardo.

The goal of the game is, if button is pushed, a random number between 1-30 will be displayed. You then have 2 seconds to move a piece of paper to the number shown (there is a ruler in place in front of the sensor).

Now, the sensor has a typical range of ~80cm sometimes higher. The way i am calculating if you got it in two seconds is, if cm < 70 (meaning your hand or piece of paper passed this threshold), start set time1. Once cm = randNumber, set time2. If time2-time1 < 2000 (milliseconds), score++;

I've create a boolean of isInZone to false in my declaration. This boolean serves to shut off the time1 set and time2 set once they have been reached, so that only one instance of the two will be calculated.
But this time thing is what has been causing me issues. If anyone could offer advice, maybe I need a library, or I'm using the wrong variable, thank you.

Code: [Select]
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <TimeLib.h>

LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display

const int trigPin = 5; // Trigger Pin of Ultrasonic Sensor
const int echoPin = 4; // Echo Pin of Ultrasonic Sensor
unsigned long time1 = 0;
unsigned long time2 = 0;
unsigned long time = 0;
int button =6;
int score =0;
bool isInZone=false;
// float current_time = 0;
// float thousand = 1000;

long randNumber;

void setup()
{
  Serial.begin(9600); // Starting Serial Terminal
  randomSeed(analogRead(0));
  lcd.init();                      // initialize the lcd
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(1,0);
  lcd.print("Distance:");
  delay(50);
  lcd.setCursor(12,0);
  lcd.print("cm");
  delay(50);
}


void loop()
{
  // The sensor is triggered by a HIGH pulse of 10 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  long duration, inches, cm;
  pinMode(trigPin, OUTPUT);
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  // Read the signal from the sensor: a HIGH pulse whose
  // duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off of an object.
  pinMode(echoPin, INPUT);
  duration = pulseIn(echoPin, HIGH);
  // current_time = millis();
  // the code above is taken from
  // https://www.instructables.com/id/Measuring-Distance-Over-Time-With-Arduino-HC-SR04-/^^
 

    if(digitalRead(button)==HIGH){
    lcd.setCursor(10,0);
    randNumber = random(1, 30);
    lcd.print(randNumber);
    delay(50);
  }
 
  // Serial.println(current_time/thousand);
  cm = microsecondsToCentimeters(duration);
  Serial.print(cm);
  Serial.print("cm");
  Serial.println();
  Serial.println(randNumber);
  delay(100);
 

 

 
  // get distance
  if ((cm < 70) && (isInZone == false)) {
    time1 = millis();
    delay(50);
    Serial.println("time1");
    Serial.println(time1);
    Serial.println();
    isInZone=true;
  }
 
  if ((cm == 22) && (isInZone == true)) {
    time2 = millis();
    Serial.println("time2");
    Serial.println(time2);
    Serial.println();
  }
 
  if (time2-time1 <= 2000 && isInZone == true) {
    score++;
    isInZone=false;
  } else if (time2 - time1 > 2000 && isInZone == true){
    score--;
    isInZone=false;
  }
 
  lcd.setCursor(1,1);
  lcd.print("Score:");
  lcd.print(score);
  delay(100);
 
  // lcd.setCursor(1,1);
  // lcd.print("Time:");
  // lcd.setCursor(7,1);
  // lcd.print(time+"s");
  // delay(50);
}

long microsecondsToCentimeters(long microseconds) {
  // The speed of sound is 340 m/s or 29 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the
  // object we take half of the distance travelled.
  // this code is also taken from https://www.instructables.com/id/Measuring-Distance-Over-Time-With-Arduino-HC-SR04-/
   return microseconds / 29 / 2;
}

PickyBiker

At the end of your time comparisons, should't you make time2 = time1?  Right now, time2 is always zero.

nobodylikeswasps

hey thanks for your reply.

im not sure i can spot that. i have time1 = millis if cm < 70 and time2 = millis if cm == 22 (as a test. what i have originally is cm == randNumber)

then time2-time1 should give the difference in how long it took to reach the target cm

PickyBiker

Time1 = millis() returns a continuously increasing number and time2 is always zero

So
2000-0  = 2000
4000-=0 = 4000
456732-0=456732

you can see this for yourself if you print time1 and time 2 on each pass.


Try putting  time2=time1;   at the end of your loop before the closing brace.

nobodylikeswasps

Time1 = millis() returns a continuously increasing number and time2 is always zero

So
2000-0  = 2000
4000-=0 = 4000
456732-0=456732

you can see this for yourself if you print time1 and time 2 on each pass.


Try putting  time2=time1;   at the end of your loop before the closing brace.
hey so i do have serial printing time2 and time1. as soon as i move a paper below 70cm, i can see time1 getting clocked at whatever the time is since the program started. and when i reach the destination of randNumber in cm, time2 gets clocked that one time and i can make score go up +1. the issue is that because it is constantly grabbing time1, it is always going -1 unless i reach time2. how can i get it to clock time1 only once??

thank you very much @pickybiker

PickyBiker

millis() always counts increasingly from the start of the program that is why the times need to be synchronized when the time difference is greater than what you want.

Try this to see what I mean

Code: [Select]

unsigned long timeNow;    // much more descriptuve than time1
unsigned long timeLast;   // much more descriptuve than time2
unsigned int period = 2000;

void setup()
{
  Serial.begin(9600);
  timeNow = millis();
  timeLast = timeNow;   // this synchronizes the times regardless of the millis count
}

void loop()
{
  timeNow = millis();    // this is actually where the millis timer start
  if (timeNow - timeLast >= period)
  {
    Serial.println(timeNow - timeLast);  // show the millis DIFFERENCE
    timeLast = timeNow; // "IMPORTANT" synchronize the times for the next loop
  }
}

nobodylikeswasps

i understand what you mean. however i tried that, and it didnt work. it only made the score go score++ now. im hardstuck and ive been ltrying to manipulate it in every way.

PickyBiker


nobodylikeswasps

it isnt perfect because this is probably the 5th rearrangement i had and i did not save the others, but here it is:

Code: [Select]
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <TimeLib.h>

LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display

const int trigPin = 5; // Trigger Pin of Ultrasonic Sensor
const int echoPin = 4; // Echo Pin of Ultrasonic Sensor
unsigned long timeNow;
unsigned long timeLast;
unsigned int period = 2000;
int button =6;
int score =0;
long randNumber;
// bool isInZone=false;
// float current_time = 0;
// float thousand = 1000;

void setup()
{
  Serial.begin(9600); // Starting Serial Terminal
  randomSeed(analogRead(0));
  timeNow = millis();
  timeLast = timeNow;   // this synchronizes the times regardless of the millis count
  lcd.init();                      // initialize the lcd
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(1,0);
  lcd.print("Distance:");
  delay(50);
  lcd.setCursor(12,0);
  lcd.print("cm");
  delay(50);
}


void loop()
{
  // The sensor is triggered by a HIGH pulse of 10 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  long duration, inches, cm;
  pinMode(trigPin, OUTPUT);
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  // Read the signal from the sensor: a HIGH pulse whose
  // duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off of an object.
  pinMode(echoPin, INPUT);
  duration = pulseIn(echoPin, HIGH);
  // current_time = millis();
  // the code above is taken from
  // https://www.instructables.com/id/Measuring-Distance-Over-Time-With-Arduino-HC-SR04-/^^
 
  if(digitalRead(button)==HIGH){
  lcd.setCursor(10,0);
  randNumber = random(1, 30);
  lcd.print(randNumber);
  delay(50);
}
  // Serial.println(current_time/thousand);
  cm = microsecondsToCentimeters(duration);
  Serial.print(cm);
  Serial.print("cm");
  Serial.println();
  Serial.println(randNumber);
  delay(100);
 
  if (cm < 70) {
    timeNow = millis();    // this is actually where the millis timer start
  }
 
  if (cm == randNumber) {
    timeLast = timeNow;
  }
 
  if (timeNow - timeLast <= period) {
    score++;
    Serial.println(timeNow);
    Serial.println(timeLast);
    Serial.println(timeNow - timeLast);
  } else if (timeNow - timeLast > period){
    score--;
    Serial.println(timeNow - timeLast);  // show the millis DIFFERENCE
    timeLast = timeNow; // "IMPORTANT" synchronize the times for the next loop
  }
 
  // get distance
  // if ((cm < 70) && (isInZone == false)) {
  //   time1 = millis();
  //   delay(50);
  //   Serial.println("time1");
  //   Serial.println(time1);
  //   Serial.println();
  //   isInZone=true;
  // }
 
  // if ((cm == randNumber) && (isInZone == true)) {
  //   time2 = millis();
  //   Serial.println("time2");
  //   Serial.println(time2);
  //   Serial.println();
  // }
 
  // if (time2-time1 <= 2000 && isInZone == true) {
  //   score++;
  //   isInZone=false;
  // } else if (time2 - time1 > 2000 && isInZone == true){
  //   score--;
  //   isInZone=false;
  // }
 
  lcd.setCursor(1,1);
  lcd.print("Score:");
  lcd.print(score);
  delay(100);
 
  // lcd.setCursor(1,1);
  // lcd.print("Time:");
  // lcd.setCursor(7,1);
  // lcd.print(time+"s");
  // delay(50);
}

long microsecondsToCentimeters(long microseconds) {
  // The speed of sound is 340 m/s or 29 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the
  // object we take half of the distance travelled.
  // this code is also taken from https://www.instructables.com/id/Measuring-Distance-Over-Time-With-Arduino-HC-SR04-/
   return microseconds / 29 / 2;
}

nobodylikeswasps

hey guys, as the title says, im trying to grab two different instances of millis(), instead of the continuous millis(). any idea whats wrong in my code?

Code: [Select]
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <TimeLib.h>

LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display

const int trigPin = 5; // Trigger Pin of Ultrasonic Sensor
const int echoPin = 4; // Echo Pin of Ultrasonic Sensor
unsigned long time1;
unsigned long time2;
unsigned long timeStart;
int button =6;
int score =0;
bool isInZone=false;
// float current_time = 0;
// float thousand = 1000;

long randNumber;

void setup()
{
  Serial.begin(9600); // Starting Serial Terminal
  randomSeed(analogRead(0));
  timeStart = millis();
  lcd.init();                      // initialize the lcd
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(1,0);
  lcd.print("Distance:");
  delay(50);
  lcd.setCursor(12,0);
  lcd.print("cm");
  delay(50);
}


void loop()
{
  // The sensor is triggered by a HIGH pulse of 10 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  long duration, inches, cm;
  pinMode(trigPin, OUTPUT);
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  // Read the signal from the sensor: a HIGH pulse whose
  // duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off of an object.
  pinMode(echoPin, INPUT);
  duration = pulseIn(echoPin, HIGH);
  // current_time = millis();
  // the code above is taken from
  // https://www.instructables.com/id/Measuring-Distance-Over-Time-With-Arduino-HC-SR04-/^^
 

    if(digitalRead(button)==HIGH){
    lcd.setCursor(10,0);
    randNumber = random(1, 30);
    lcd.print(randNumber);
    delay(50);
  }
 
  // Serial.println(current_time/thousand);
  cm = microsecondsToCentimeters(duration);
  Serial.print(cm);
  Serial.print("cm");
  Serial.println();
  Serial.println(randNumber);
  delay(100);
 
  // get distance
  if ((cm < 70) && (isInZone == false)) {
    time1 = millis();
    delay(50);
    Serial.println("time1");
    Serial.println(time1);
    Serial.println();
    isInZone=true;
  }
 
  if ((cm == randNumber) && time2-time1 != 0 && (isInZone == true)) {
    time2 = millis();
    Serial.println("time2");
    Serial.println(time2);
    Serial.println();
  }
 
  if (time2-time1 <= 2000 && isInZone == true) {
    score++;
    isInZone=false;
  } else if (time2 - time1 > 2000 && isInZone == true){
    score--;
    isInZone=false;
  }
 
  lcd.setCursor(1,1);
  lcd.print("Score:");
  lcd.print(score);
  delay(100);
 
  // lcd.setCursor(1,1);
  // lcd.print("Time:");
  // lcd.setCursor(7,1);
  // lcd.print(time+"s");
  // delay(50);
}

long microsecondsToCentimeters(long microseconds) {
  // The speed of sound is 340 m/s or 29 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the
  // object we take half of the distance travelled.
  // this code is also taken from https://www.instructables.com/id/Measuring-Distance-Over-Time-With-Arduino-HC-SR04-/
   return microseconds / 29 / 2;
}

Power_Broker

any idea whats wrong in my code?
Idk, what is wrong with your code? What happens when you run it? How does it's current output differ from what you expected/wanted?


You can save the current value of millis() to a variable. That's how you "grab a different instance of millis()".
"The desire that guides me in all I do is the desire to harness the forces of nature to the service of mankind."
   - Nikola Tesla

nobodylikeswasps

hey thanks for your reply, how would i save the CURRENT value of the two instances to the variable?

heres my goal:

I'm trying to create a game, where i have an lcd screen, a push button, and an ultrasonic sensor hooked up to my arduino leonardo.

The goal of the game is, if button is pushed, a random number between 1-30 will be displayed. You then have 2 seconds to move a piece of paper to the number shown (there is a ruler in place in front of the sensor).

Now, the sensor has a typical range of ~80cm sometimes higher. The way i am calculating if you got it in two seconds is, if cm < 70 (meaning your hand or piece of paper passed this threshold), set time1. Once cm = randNumber, set time2. If time2-time1 < 2000 (milliseconds), score++;

so pretty much when an object moves into the ultrasonic sensor below 70cm i want to capture one value of millis, and when it reaches my cm value i want to capture another instance of millis and do a comparison to see if it was less than 2 seconds

thank you again for ur advice :)

nobodylikeswasps

actually sorry i worded it wrong. i did set a variable time1 for one instance and a variable time2 for the other. the issue is, because im continuously moving down below 70, it keeps changing time1 since it is equal to millis, and the score keeps going score--;

i am trying to find a way to actually take that value of millis at that moment and freeze it or shut it off, and do the same for the other to find out if it took less than 2 seconds.

thats what the boolean is for but it doesnt seem to be working

12Stepper

thats what the boolean is for but it doesnt seem to be working
... and that's on the right track.

But I'd go for a number, so we can have more than just those two states of in and out of the zone, call it theState say. And rather than a complicated nest of if()'s, look to using switch...case, with theState as the case variable.

  • theState starts as 0, while we wait the button. When the button is pressed, increment theState to 1.
  • In case theState =1, wait for the object to come in range, capture that instant as first timestamp, and increment theState to 2. (In the next state we won't disturb that first timestamp.)
  • In case theState =2, wait for the object to hit the target, capture that instant as second timestamp, compare, change the score, set theState =0....
  • .. rinse and repeat.


Bit off the top of my head, but hey, it's 0615 on sunday and howMuchCoffeeIHaveHad=1 right now.


PickyBiker


Quote
The goal of the game is, if button is pushed, a random number between 1-30 will be displayed. You then have 2 seconds to move a piece of paper to the number shown (there is a ruler in place in front of the sensor).
Given the above, wouldn't you need to wait for a button press and then loop on sending pings repeatedly to get the current distance and then either win or run out of time?

I am still trying to understand what is supposed to happen.

Go Up