Arduino Forum

Using Arduino => Programming Questions => Topic started by: nobodylikeswasps on Dec 07, 2019, 05:59 pm

Title: Trying to use time variable to calculate entry within a sensor
Post by: nobodylikeswasps on Dec 07, 2019, 05:59 pm
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;
}
Title: Re: Trying to use time variable to calculate entry within a sensor
Post by: PickyBiker on Dec 07, 2019, 06:24 pm
At the end of your time comparisons, should't you make time2 = time1?  Right now, time2 is always zero.
Title: Re: Trying to use time variable to calculate entry within a sensor
Post by: nobodylikeswasps on Dec 07, 2019, 07:15 pm
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
Title: Re: Trying to use time variable to calculate entry within a sensor
Post by: PickyBiker on Dec 07, 2019, 08:25 pm
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.
Title: Re: Trying to use time variable to calculate entry within a sensor
Post by: nobodylikeswasps on Dec 07, 2019, 08:41 pm
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
Title: Re: Trying to use time variable to calculate entry within a sensor
Post by: PickyBiker on Dec 07, 2019, 09:41 pm
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
  }
}
Title: Re: Trying to use time variable to calculate entry within a sensor
Post by: nobodylikeswasps on Dec 08, 2019, 12:32 am
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.
Title: Re: Trying to use time variable to calculate entry within a sensor
Post by: PickyBiker on Dec 08, 2019, 12:43 am
Please post the code for how you tried it.
Title: Re: Trying to use time variable to calculate entry within a sensor
Post by: nobodylikeswasps on Dec 08, 2019, 01:01 am
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;
}
Title: I'm trying to only grab two separate timestamps instead of the actual millis()
Post by: nobodylikeswasps on Dec 08, 2019, 03:04 am
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;
}
Title: Re: I'm trying to only grab two separate timestamps instead of the actual millis()
Post by: Power_Broker on Dec 08, 2019, 03:37 am
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()".
Title: Re: I'm trying to only grab two separate timestamps instead of the actual millis()
Post by: nobodylikeswasps on Dec 08, 2019, 04:10 am
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 :)
Title: Re: I'm trying to only grab two separate timestamps instead of the actual millis()
Post by: nobodylikeswasps on Dec 08, 2019, 04:16 am
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
Title: Re: I'm trying to only grab two separate timestamps instead of the actual millis()
Post by: 12Stepper on Dec 08, 2019, 05:21 am
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 (https://www.arduino.cc/reference/en/language/structure/control-structure/switchcase/), with theState as the case variable.



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

Title: Re: Trying to use time variable to calculate entry within a sensor
Post by: PickyBiker on Dec 08, 2019, 05:30 am

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.
Title: Re: I'm trying to only grab two separate timestamps instead of the actual millis()
Post by: 12Stepper on Dec 08, 2019, 06:08 am
Bit off the top of my head, but hey, it's 0615 on sunday and howMuchCoffeeIHaveHad=1 right now.
And subsequently with howMuchCoffeeIHaveHad>1, written and tested if you want it.

Title: Re: Trying to use time variable to calculate entry within a sensor
Post by: UKHeliBob on Dec 08, 2019, 08:19 am
Topics merged
Title: Re: Trying to use time variable to calculate entry within a sensor
Post by: nobodylikeswasps on Dec 08, 2019, 05:02 pm
so i have updated the code. what happens is, i push button, a random number between 1 - 30 is displayed after lcd.print Distance

so the screen reads: Distance: xxcm

in my serial monitor, i have it set so when i go below 70cm, i see time1. when i reach target cm, time2 is display and either success or failure is shown. score goes up by 1 or down by 1 based on this.

my issue now is that even if i hold it past time1 for 8 seconds, it still doesnt go down by 1 UNTIL i hit cm (time2), and if i move my hand in the slightest and it hits time2 again it clocks it as a win, so the -1 score is nullified.

its not very accurate in the time and maybe i need to include margin of error calculations.

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 timeStart;
int button =6;
int score =0;
bool isInZone=false;
// float current_time = 0;
// float thousand = 1000;

long randNumber=0;

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(1000);
  }
 
  // Serial.println(current_time/thousand);
  cm = microsecondsToCentimeters(duration);
 
  Serial.print(cm);
  Serial.print(" cm");
  Serial.println();
  Serial.println(randNumber);
  Serial.println();
  delay(100);
 
 if (cm <=70 && time1==0 && isInZone==false)
 {
    time1 = millis();
    time2 = time1;
    isInZone=true;
    Serial.println("time1 : ");
    Serial.println(time1);
    Serial.println();
    delay(100);
 }
 
  if ((cm == randNumber) && (isInZone == true))
  {
    time2 = millis();
    Serial.println("time2  : ");
    Serial.println(time2);
    Serial.println();

    if ((time2-time1 <= 2000) && (time2-time1 > 0) &&  (isInZone == true))
    {
      score++;
      isInZone=false;
      time1 = time2 =0;
      Serial.println("*************");
      Serial.println("Sucess");
      Serial.println("*************");
      Serial.println();
    }
    else if ((time2 - time1 > 2000) && (isInZone == true))
    {
      score--;
      isInZone=false;
      time1 = time2 =0;
      Serial.println("*************");
      Serial.println("Failure");
      Serial.println("*************");
      Serial.println();
    }
   
  }
 
  else if ((cm != randNumber) && (time2 - time1 == 10) && (isInZone == true))
  {
      score=0;
      isInZone=false;
      time1 = time2 =0;
      Serial.println("*************");
      Serial.println("Failure");
      Serial.println("*************");
      Serial.println();
    }

    lcd.setCursor(1,1);
    lcd.print("Score:");
    lcd.print(score);
    lcd.print("   "); 
    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;
}
Title: Re: Trying to use time variable to calculate entry within a sensor
Post by: nobodylikeswasps on Dec 08, 2019, 05:09 pm
And subsequently with howMuchCoffeeIHaveHad>1, written and tested if you want it.


my friend i have tried the switch cases method i would love to see how u incorporated it D:

the thing is i dont want it to break after hte first case (cm < 70) because i want to catch time2 when cm == randNumber

currently on coffee=1 today on my sunday morning
Title: Re: Trying to use time variable to calculate entry within a sensor
Post by: 12Stepper on Dec 08, 2019, 05:25 pm
Try this....

Code: [Select]
//  https://forum.arduino.cc/index.php?topic=652553
//  https://forum.arduino.cc/index.php?topic=652479

//states
enum {ST_idle, ST_primed, ST_timing} theState = ST_idle;
//   this is just a quick way of giving numbers human names
//   starts at 0 on the left, so ST_idle is 0, ST_primed is 1
//   which makes it more readable later in the switch...case

//variables
long duration;
long inches;
long cm;
unsigned long timeStart;
unsigned long timeEnd;
unsigned long elapsedTime;
byte targetDistance;

//pins
const byte theButton = 6;
const int trigPin = 5; // Trigger Pin of Ultrasonic Sensor
const int echoPin = 4; // Echo Pin of Ultrasonic Sensor

void setup()
{
  // initialize serial communication:
  Serial.begin(9600);
  Serial.println("setup() ... ");
  Serial.println("652553 652479 ultrasonic game");
  Serial.print("Compiler: ");
  Serial.print(__VERSION__);
  Serial.print(", Arduino IDE: ");
  Serial.println(ARDUINO);
  Serial.print("Created: ");
  Serial.print(__TIME__);
  Serial.print(", ");
  Serial.println(__DATE__);
  Serial.println(__FILE__);

  pinMode(theButton, INPUT_PULLUP); //wired from pin to ground
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  randomSeed(analogRead(0));

  Serial.println("setup() done");
  Serial.println(" ");
  Serial.println("Press the button to start");
}

void loop()
{
  playGame();
} //loop

void playGame()
{
  switch (theState)
  {
    case ST_idle:

      if (!digitalRead(theButton)) theState = ST_primed; //button active low, ! means "not"
      break;

    case ST_primed:
      Serial.print("Come within 70cm to start, currently at ");
      digitalWrite(trigPin, LOW);
      delayMicroseconds(2);
      digitalWrite(trigPin, HIGH);
      delayMicroseconds(10);
      digitalWrite(trigPin, LOW);
      duration = pulseIn(echoPin, HIGH);
      cm = microsecondsToCentimeters(duration);
      Serial.print(cm);
      Serial.print("cm");
      Serial.println();

      if (cm < 70)
      {
        targetDistance = random(5, 31);
        theState = ST_timing;
        timeStart = millis();
      }
      break;

    case ST_timing:
      Serial.print("Come to ");
      Serial.print(targetDistance);
      Serial.print("cm to end, currently at ");
      digitalWrite(trigPin, LOW);
      delayMicroseconds(2);
      digitalWrite(trigPin, HIGH);
      delayMicroseconds(10);
      digitalWrite(trigPin, LOW);
      duration = pulseIn(echoPin, HIGH);
      cm = microsecondsToCentimeters(duration);
      Serial.print(cm);
      Serial.print("cm");
      Serial.println();

      if (cm == targetDistance)
      {
        timeEnd = millis();
        elapsedTime = timeEnd - timeStart;
        Serial.print("You took ");
        Serial.print(elapsedTime); Serial.println("ms");
        theState = ST_idle;
        Serial.println("Press the button to start");
      }
      break;
  }//switch
}//playGame

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;
}//microsecondsToCentimeters
Title: Re: Trying to use time variable to calculate entry within a sensor
Post by: 12Stepper on Dec 08, 2019, 05:31 pm
ps... My lcd is deployed elsewhere (https://forum.arduino.cc/index.php?topic=651844), so everything's in the monitor.




Title: Re: Trying to use time variable to calculate entry within a sensor
Post by: nobodylikeswasps on Dec 08, 2019, 06:55 pm
i loved the layout of your code... the layout is so much cleaner on the serial monitor. i definitely need to input my lcd components, and maybe shorten the time between when the code restarts, and also include that the button controls the random number (because it outputs it as soon as cm == randomnumber and so the button becomes obsolete) ... thank you so much for the time you took and i appreciate your help you are a true maestro
Title: Re: Trying to use time variable to calculate entry within a sensor
Post by: PickyBiker on Dec 08, 2019, 08:20 pm
nobodylikeswasps,

I could not see the logic you described actually implemented in the code so I decided to demonstrate one possible way this game can be implemented. I don't have the LCD, the sonic sensor, or the button, so I just fake a button press and arbitrarily set the desired distance to target and actual distance to target.

Wherever you see "only for testing **************************" these are the places where you can add data for testing the code. With a "closeness" setting of 1, the actual distance difference must be +- 1 to the target distance. With a closeness of 0, they must match.

Everything that is printed on the Serial Monitor must be converted to LCD prints, the button must be connected to the button pin and ground.

I commented everything in this model to try to help describe what it is doing and how it works. As a newbie myself, I found it very useful to see examples of what I was trying to do. I hope this helps you.

Code: [Select]

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

// This code will wait for a button press and then start a 2 second loop that continuously
// sends pings to get the current distance while setting a winner or running out of time.

#include <Wire.h>             // include the wire library

#define BUTTONPIN 6           // Button is connected to pin 6 and ground
#define TRIGPIN 5             // Trigger Pin of Ultrasonic Sensor
#define ECHOPIN 4             // Echo Pin of Ultrasonic Sensor

int closness = 1;             // how close +/- must the winner be to the target
int period = 4000;            // this is a 4 second loop time
int duration;                 // duration = pulse length in microsecs
long targetDistance;          // desired distance to target
int actualDistance;           // actual distance to target
long score = 0;               // a place to keep score

unsigned long startTime;      // the time of the loop start
boolean winner;               // indicates a winner

void setup()
{
  Serial.begin(115200);                 // Starting Serial Terminal
  randomSeed(analogRead(0));            // randomize the randon number generator
  // using INPUT_PULLUP guarantees the pin will be high until the button pulls low.
  pinMode(BUTTONPIN, INPUT_PULLUP);     // when the button is pressed the pin goes low
  pinMode(ECHOPIN, INPUT);              // the sonic sensor echo pin is an imput
  pinMode(TRIGPIN, OUTPUT);             // the sonic sensor trigger pin is an output
  digitalWrite(TRIGPIN, LOW);           // make certain the trigger pin starts out LOW
}

void loop()
{
  //while (!getButton());               // wait here for a button press

  // ******************** start timing after button press **********************
  targetDistance = random(1, 31);       // returns target distance 0f 1-30 cm
  targetDistance = 30;                  // only for testing **************************
  Serial.print(targetDistance); Serial.print(" ");

  startTime = millis();
  winner = false;                       // must win to change this to true

  // *********************** begin <period> sec loop *********************************
  while (startTime + period > millis())
  {
    actualDistance = getDistance();     // return the actual distance to the target
    actualDistance = 32;                // only for testing **************************

    // check for actualDistance = target distance +/- closeness
    int win = abs(actualDistance - targetDistance); // determine the absolute difference
    if (win <= closness)                            // is it close enough?
    {
      // YES! this is a win
      winner = true;                                // set the winner status
      score++;                                      // increase the score
     
      // display tge winner information
      Serial.print(" *** WINNER *** ");             
      Serial.print("Score:");
      Serial.println(score);
    }

    if (winner)
      // use up the rest of the <period> sec loop time
      // this prevents a button repeat on long presses & fast wins
      while (startTime + period > millis());    // stay here intil 2 sec has passed
  }
  // ********************** end of <period> second loop  *****************************

  if (!winner)
  {
    // <period> time has expired so display the loss information
    Serial.print("Sorry, try again!, ");
    score--;                                        // decrease the score
    Serial.print("Score:");
    Serial.println(score);
  }
}

boolean getButton()     // return true if the button is pressed
{
  if (digitalRead(BUTTONPIN) == LOW)      // is the buttin pressed?
    return true;                          // yes, retutrn true
  else
    return false;                         // no, return false
}

int getDistance()
{
  // The sensor is triggered by a HIGH pulse of 10 or more microseconds.
  digitalWrite(TRIGPIN, HIGH);          // we know the pin is low, so start the pulse
  delayMicroseconds(10);                // wait 10 microseconds
  digitalWrite(TRIGPIN, LOW);           // end the pulse

  // 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.
  duration = pulseIn(ECHOPIN, HIGH);         // sonic sensor's pulse-return microsecs
  actualDistance = microsecondsToCentimeters(duration);  // Convert the microsecs to distance
  return actualDistance;                                 // return the distance
}

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;
}
Title: Re: Trying to use time variable to calculate entry within a sensor
Post by: nobodylikeswasps on Dec 08, 2019, 11:12 pm
hey thanks for your reply! i have actually finally figured out how to perfectly set it up. it required more booleans. i had set it now so that it does not enter the program if button is not hit, and it exits when cm = random number

heres the code below

Code: [Select]
// Jad Seaidoun - 200340278
// must be in webeditor

#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; // time for entry within range
unsigned long time2 = 0; // time for reaching randomNumber
int button = 6; // button pin
int score = 0; // default score value
bool isInZone = false; // condition to see if in range
bool buttonReset = false; // condition to see if button was pressed to start new level
long randNumber = 0; // random number generator later on

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


void loop()
{
  // code for pin taken from:
  // https://www.instructables.com/id/Measuring-Distance-Over-Time-With-Arduino-HC-SR04-/
  // 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, 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);
 
 
  // if button is pushed down, print random number between 5 and 30 on lcd screen
  // and set value for button reset to true
  if (digitalRead(button) == HIGH) {
    lcd.setCursor(10, 0);
    lcd.print("    ");
    randNumber = random(5, 30);
    buttonReset = true;
    lcd.setCursor(10, 0);
    lcd.print(randNumber);
    lcd.setCursor(12, 0);
    lcd.print("cm");
    delay(20);
  }

  // maxTime is the number of milliseconds to beat for win, or if you pass, to lose
  long maxTime = 000;
 
  // microsecondsToCentimers is defined at the bottom, uses speed of sound to determine distance in cm
  cm = microsecondsToCentimeters(duration);
  printCM(cm);
  delay(100);

  // set time2 to millis() when button is pressed
  if (buttonReset) {
    time2 = millis();
  }

  // sets time1 when object moved inZone of <=70cm
  if (cm <= 70 && time1 == 0 && isInZone == false && buttonReset == true)
  {
    time1 = millis();
    time2 = time1;
    isInZone = true;
    printTime(time1);
    delay(100);
  }
 
 
  // gives a point if object reaches desired random number [cm == randNumber]
  else if ((cm == randNumber) && (isInZone == true) && buttonReset && abs(time2 - time1) <= maxTime && (time2 - time1 > 0))
  {
    printSuccess();
    score++;
    isInZone = false;
    time1 = 0;
    time2 = 0;
    buttonReset = false;
  }

  // reset score if you do not reach desired randNumber and you have gone over allowed maxTime
  else if ((cm != randNumber) && (abs(time2 - time1) > maxTime) && isInZone)
  {
    printFailure();
    score = 0;
    isInZone = false;
    time1 = time2 = 0;
    buttonReset = false;
  }

  // display score
  lcd.setCursor(1, 1);
  lcd.print("Score:");
  lcd.print(score);
  lcd.print("   ");
  delay(100);
}

// function to print when you have failed in serial monitor
void printFailure() {
  Serial.println("*************");
  Serial.println("Failure");
  Serial.println("Your time was: ");
  Serial.println(time2 - time1);
  Serial.println("*************");
  Serial.println();
}

// function to print when you have scored in serial monitor
void printSuccess() {
  printTime(time2);
  delay(100);
  Serial.println("*************");
  Serial.println("Sucess");
  Serial.println("Your time was: ");
  Serial.println(time2 - time1);
  Serial.println("*************");
  Serial.println();
}

// function to print current cm from sensor AND desired randNumber on next line in serial monitor
void printCM(long cm) {
  Serial.print(cm);
  Serial.print(" cm");
  Serial.println();
  Serial.println(randNumber);
  Serial.println();
}

// print time in serial monitor to show for ac
void printTime(long t) {
  Serial.println("time  : ");
  Serial.println(t);
  Serial.println();
}

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;
}
Title: Re: Trying to use time variable to calculate entry within a sensor
Post by: PickyBiker on Dec 08, 2019, 11:46 pm
Great, glad you got it working.

FYI:  randNumber = random(5, 30);  will return a number between 5 and 29.

If you want a number between 5 and 30 then us  randNumber = random(5, 31);
Title: Re: Trying to use time variable to calculate entry within a sensor
Post by: nobodylikeswasps on Dec 11, 2019, 01:15 am
wow thank you for letting me know! I actually did not pick up on that xD that would have made my comment //brings a random number between 5 and 30 // incorrect haha. i appreciate you catching that, and for you and @12stepper for all your help. both of you helped me look at it differently!