Go Down

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

12Stepper

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.


UKHeliBob

Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

nobodylikeswasps

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;
}

nobodylikeswasps

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

12Stepper

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

12Stepper

ps... My lcd is deployed elsewhere, so everything's in the monitor.





nobodylikeswasps

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

PickyBiker

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;
}

nobodylikeswasps

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;
}

PickyBiker

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);

nobodylikeswasps

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!

Go Up