Ignore a sensor being passed the 1st time and start recording millis the 2nd

I am building a timing system that has a start, split and finish beams with this I am using a start gate that will drop when the race starts.

when the gate drops it will trip the 1st sensor and will take note of the millis for the"start" then the person will go through the second sensor and that will take note of the millis for the "reaction" and then a final sensor will be passed through and the millis will be noted for the "push" then it will serialPrint them all. After that I will do the math in an excel form (reaction - start will give me the 1st time) then (finish - reaction will give me the 2nd time)

So where I am running into issues is that after the person goes through the 3 timer sensors I have to close the start gate which ends up tripping the first sensor and seems when it gets to the serialPrint section it will use that as the first entry. at first it is hard to notice because I am using very short time frames but when I test it out and go quick through the 1st and 2nd sensors and then take time breaking the last one.... this should give me a small 1st time and large 2nd time but it gives me the opposite so I am assuming that it is because the millis that is being printed in the serial monitor is from when I lift the gate up and break the beam.

so long story short I need to have some sort of way to reset things after the the sensor is tripped when lifting the gate up or a way to use the second millis entry when the sensor is. When the gate is up and locked it is in a HIGH state then when it drops it breaks hte sensor beam and goes in a LOW state (this is when the millis needs to be recorded.... then it stays in a HIGH state until the rider breaks the other 2 beams....... then when you lift the gate it goes from HIGH to LOW (this is millis I want to ignore) then back to HIGH waiting for hte race to start.

I am thinking that the easiest way is to use some sort of switch for the start gate instead of the IR sensor I am using now then it will either be HIGH or LOW and not transfer between the two before it needs to be active.... I am actually waiting on a reed switch but wanted to see if I can get this fixed in the meantime.

//timer
unsigned long start, reaction, push, elapsed;


void setup()
{
  Serial.begin(115200);
  pinMode(2, INPUT); // start switch
  pinMode(3, INPUT); // split sensor
  pinMode(4, INPUT); // finish sensor
}


void loop() {

  if (digitalRead(2) == LOW )
  {

    start = millis();

  }

  if (digitalRead(3) == HIGH)
  {

    reaction = millis();
    //   delay(200); // for debounce


  }

  if (digitalRead(4) == HIGH)
  {

    push = millis();
    delay(500); // for debounce

    Serial.print(start);
    Serial.print(",");
    Serial.print(reaction);
    Serial.print(",");
    Serial.print(push);
    Serial.println();



  }


}

Hi cnak,

your functionality of

1: record timing-system is ready to start
2: gate drops make first snapshot of millis()
3: person triggers second sensor second snapshot of millis()
4: person triggers push-button make third snapshot of millis()
send snapshots to serial

needs an additional state
5: wait for system to be made ready again through lifting the gate to "closed" position
in this state any changes of any sensor shall be ignored

This is a fixed pattern. Triggering sensor 1 always occurs before triggering sensor 2 which always occurs before triggering sensor 3

This functionality can be programmed with a programming-technique called "state-machine"

I was gearching for a good introduction to state-machines and of course google found a lot of hits.
Most of these tutorials are IMHO opinion not best suited to explain the concept of state-machine because they include more functionality than it would need to explain the basic concept.

I read a couple of them and came to the conclusion: none of them is best suited to explain the concept.
What comes closest to it IMHO is this one

Arduino tutorial about state machine

The beginning of this document is very good but it leaves the reader without haven given an example how to use if-conditions to change from one state to the next

This example adds some value to it but I'm still not satisfied with it
very simple state-machine with an if-condition

best regards Stefan

Thanks Stephan

This makes sense and gives me a starting point to be able to sort this out.

I am thinking that life will be a lot easier if I am able to swap out the first IR sensor for a actual switch that will go from HIGH when the gate is closed to LOW when it opens. then when closed it will go to HIGH again

I have forgotten to mention something
1: record timing-system is ready to start
2: gate drops make first snapshot of millis()
3: person triggers second sensor second snapshot of millis()
4: person triggers push-button make third snapshot of millis()
send snapshots to serial

needs an additional state
5: wait for system to be made ready again through lifting the gate to "closed" position
in this state any changes of any sensor shall be ignored

change from state 5 to state 1 through pressing a button.

so here is a code with a statemachine that compiles but is not really tested

[color=#222222]unsigned long start, reaction, push, elapsed;[/color]

[color=#222222]
[/color]

[color=#222222]const byte StartSwitch_Pin  = 2;[/color]

[color=#222222]const byte SplitSensor_Pin  = 3;[/color]

[color=#222222]const byte PushButton_Pin = 4;[/color]

[color=#222222]const byte StartCycleButton_Pin = 5;[/color]

[color=#222222]
[/color]

[color=#222222]
[/color]

[color=#222222]void setup()[/color]

[color=#222222]{[/color]

[color=#222222]  Serial.begin(115200);[/color]

[color=#222222]  Serial.println("Setup Start");[/color]

[color=#222222]  pinMode(StartSwitch_Pin, INPUT); // start switch[/color]

[color=#222222]  pinMode(SplitSensor_Pin, INPUT); // split sensor[/color]

[color=#222222]  pinMode(PushButton_Pin, INPUT); // finish sensor[/color]

[color=#222222]  pinMode(StartCycleButton_Pin, INPUT); // finish sensor[/color]

[color=#222222]}[/color]

[color=#222222]
[/color]

[color=#222222]
[/color]

[color=#222222]const byte CloseGate = 1;[/color]

[color=#222222]const byte WaitForGateDropped = 2;[/color]

[color=#222222]const byte WaitForSplitSensorTriggered  = 3;[/color]

[color=#222222]const byte WaitForPushButtonPressed     = 4;[/color]

[color=#222222]
[/color]

[color=#222222]int MyStateVar = CloseGate;[/color]

[color=#222222]
[/color]

[color=#222222]void loop() {[/color]

[color=#222222]
[/color]

[color=#222222]  switch (MyStateVar) { // start of switch case[/color]

[color=#222222]
[/color]

[color=#222222]    case CloseGate:[/color]

[color=#222222]      if (StartCycleButton_Pin == LOW) { // only if button is pressed start watching IO-pin StartSwitch[/color]

[color=#222222]        MyStateVar = WaitForGateDropped;[/color]

[color=#222222]      }[/color]

[color=#222222]      break;[/color]

[color=#222222] [/color]

[color=#222222]    case WaitForGateDropped:[/color]

[color=#222222]      if (digitalRead(StartSwitch_Pin) == LOW ) {[/color]

[color=#222222]        start = millis();[/color]

[color=#222222]        MyStateVar = WaitForSplitSensorTriggered;[/color]

[color=#222222]      }[/color]

[color=#222222]      break;[/color]

[color=#222222]
[/color]

[color=#222222]    case WaitForSplitSensorTriggered:[/color]

[color=#222222]      if (digitalRead(SplitSensor_Pin) == HIGH) {[/color]

[color=#222222]        reaction = millis();[/color]

[color=#222222]        MyStateVar = WaitForPushButtonPressed;[/color]

[color=#222222]        //   delay(200); // for debounce[/color]

[color=#222222]      }[/color]

[color=#222222]      break;[/color]

[color=#222222]      [/color]

[color=#222222]    case WaitForPushButtonPressed:[/color]

[color=#222222]
[/color]

[color=#222222]      if (digitalRead(PushButton_Pin) == HIGH) {[/color]

[color=#222222]        push = millis();[/color]

[color=#222222]        delay(500); // for debounce[/color]

[color=#222222]
[/color]

[color=#222222]        Serial.print(start);[/color]

[color=#222222]        Serial.print(",");[/color]

[color=#222222]        Serial.print(reaction);[/color]

[color=#222222]        Serial.print(",");[/color]

[color=#222222]        Serial.print(push);[/color]

[color=#222222]        Serial.println();[/color]

[color=#222222]        MyStateVar = CloseGate;[/color]

[color=#222222]      }[/color]

[color=#222222]      break;[/color]

[color=#222222]  } // end of switch[/color]

[color=#222222]
[/color]

[color=#222222]}  [/color]

[color=#222222]

best regards Stefan

Wow thanks for all that it will definitely save me some headaches trying to sort it out myself but something I am definitely going to read up on to be able to understand it more.
I will be making the adjustments in the next day or two and let you on the results

thanks again

Hi Stephan

so I tried adding a switch and tried the code but it doesn’t seem to be working it prints the “Setup Start” and then that is it.
I am thinking that it may be the type of switch I am using? I am using a momentary ON ON switch. the one thing in the code that makes me wonder if it is the wrong switch is the comment at the end of the code “// end of switch” so if it is a momentary switch it wouldn’t stay in the state it needs to for long enough?
should it be a OFF ON switch? and then we would have to turn it off and then back on after we lift the gate?

any suggestions?

Do you know how to change the code that the switch works with opposite logic?

code with debug-output

unsigned long MyTimer;

boolean TimePeriodIsOver (unsigned long &expireTime, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - expireTime >= TimePeriod )
  {
    expireTime = currentMillis; // set new expireTime
    return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
  } 
  else return false;            // not expired
}


unsigned long start, reaction, push, elapsed;

const byte StartSwitch_Pin  = 2;
const byte SplitSensor_Pin  = 3;
const byte PushButton_Pin = 4;
const byte StartCycleButton_Pin = 5;

void setup()
{
  Serial.begin(115200);
  Serial.println("Setup Start");
  pinMode(StartSwitch_Pin, INPUT); // start switch
  pinMode(SplitSensor_Pin, INPUT); // split sensor
  pinMode(PushButton_Pin, INPUT); // finish sensor
  pinMode(StartCycleButton_Pin, INPUT); // finish sensor
}


const byte CloseGate = 1;
const byte WaitForGateDropped = 2;
const byte WaitForSplitSensorTriggered  = 3;
const byte WaitForPushButtonPressed     = 4;

int MyStateVar = CloseGate;



void Print_IO_Pin_Status() {

  if (StartSwitch_Pin == LOW) {
    Serial.print("Start LOW");
  }
  else {
    Serial.print("Start HIGH");
  }


  if (SplitSensor_Pin == LOW) {
    Serial.print("  Split LOW");
  }
  else {
    Serial.print("  Split HIGH");
  }


  if (PushButton_Pin == LOW) {
    Serial.print("  Push LOW");
  }
  else {
    Serial.print("  Push HIGH");
  }


  if (StartCycleButton_Pin == LOW) {
    Serial.print("  Cycle LOW");
  }
  else {
    Serial.print("  Cycle HIGH");
  }

  Serial.println();
}


void loop() {

  if (TimePeriodIsOver(MyTimer, 1000) ) { // print IO-pin-status only once per second
    Print_IO_Pin_Status();
  }

  switch (MyStateVar) { // start of switch case

    case CloseGate:
      if (StartCycleButton_Pin == LOW) { // only if button is pressed start watching IO-pin StartSwitch
        MyStateVar = WaitForGateDropped;
        Serial.println("StartCycleButton_Pin == LOW ==> change to state WaitForGateDropped" );
      }
      break;
 
    case WaitForGateDropped:
      if (digitalRead(StartSwitch_Pin) == LOW ) {
        start = millis();
        Serial.println("StartSwitch_Pin) == LOW  ==> change to state WaitForSplitSensorTriggered" );
        MyStateVar = WaitForSplitSensorTriggered;
      }
      break;

    case WaitForSplitSensorTriggered:
      if (digitalRead(SplitSensor_Pin) == HIGH) {
        reaction = millis();
        Serial.println("SplitSensor_Pin) == HIGH  ==> change to state WaitForPushButtonPressed" );
        MyStateVar = WaitForPushButtonPressed;
        //   delay(200); // for debounce
      }
      break;
      
    case WaitForPushButtonPressed:

      if (digitalRead(PushButton_Pin) == HIGH) {
        push = millis();
        delay(500); // for debounce

        Serial.print(start);
        Serial.print(",");
        Serial.print(reaction);
        Serial.print(",");
        Serial.print(push);
        Serial.println();
        MyStateVar = CloseGate;
      }
      break;
  } // end of switch

}

best regards Stefan

so trying to answer your questions Stefan.... the hardware set up I am using when I ran the program is.

StartSwitch - Is a IR distance sensor 0-10cm (that is for the start gate)
SplitSensor - Is a IR distance sensor 20 - 150cm
PushButton - Is a IR distance sensor 20 - 150cm
StartCycleButton - I switched this to a OFF - ON push button switch
I dont yet have the pull up resistor attached to it.

and then I am running it on a Arduino Uno with everything running on 3.3v

I am running it on a Arduino Uno with everything running on 3.3v

I was astonished about the Arduino running on 3.3V. So I did a realworld-hardware-test immediately.
I tested with an Arduino clone. This clone has a MEGA328P SMD-chip soldered on the PCB.

I turned down the supply-voltage to 3.3V feeding in the 3.3V to the 5V-pin and the board was
still running an I2C 20x4 display.

Seems the clones are the better and cheaper Arduinos.

Can you post a hand drawn schematic how you wired the button?

If you trigger your IR-sensors does the voltage-level on the IO-pins change?
Do you have a digital multimeter so you can measure the voltages?

If you start tinkering with microcontrollers and do more than using the USB-serial interface a digital multimeter is a must.

best regards Stefan

I may not have given you all the info in my previous post... the arduino is power through my computer via the USB.... all the sensors are run through the 3.3V on the Arduino.

here is a drawing of the hook up that I originally had..... hopefully it is clear. I just have one line going from the pin to the button but will be adding the resistor in there based on the post you sent me.

I don't have a functioning multimeter handy and have been meaning to replace it.

Screen Shot 2020-09-25 at 12.37.36 PM.png

Screen Shot 2020-09-25 at 12.37.36 PM.png

OK. any button has to be connected with two wires.

I beg you from the bottom of my heart to read this tutorial about buttons and switches

I couldn't explain it any better. It would just need additional time to re-write this tutorial as a response to you

Tutorial about using buttons and switches

If you don't understand any detail in this tuotrial I will answer these questions.

Depending on where you are living I would recommend buying this digital multimeter
True RMS Bluetooth with flashlight digital multimeter 30 Euros

If shipping cost too much of course the price / perfomance-ration drops down
It has the best price / perfomance ratio I have ever seen.
The features combined in this DMM usually is about 50 to 100 Euros

measuring-digits 5.999 instead of 3.999 or 1.999
TRUE RMS,
contactless detecting of 110/230V AC
Measuring
of course voltage, current, resistance

Frequency
Dutycycle
Capacitance
20 A current
temperature
bluetooth connection to an android app
androidapp with record-function of measured values

best regards Stefan

Thanks

I do understand that there are 2 wires for buttons I only drew in one. I basically just drew what I had currently set up on my board (didn't have the resistor yet). and yes I did read the link a few times as well as done some searches online for more examples and I believe I do understand it.

BUT I am running into other issues now that I am going to have to try to sort out. for some reason I am getting a "problem uploading to the board" error

avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 10 of 10: not in sync: resp=0x00

I have no idea how this happened and I even tried on a different Uno and it does the same thing even for the simple Blink sample sketch

so this I assume will take me some time to sort out....

hopefully I can get back to sorting out my original question soon.

thanks for all the help

Are you using an Arduino uno original or clone with a USB-cable directly plugged into the board?

The setup described above does not need an avrdude or something like that. There is an extra subforum about avrdude stk500
I'm not familiar with this I guess some options hoe to upload the code of the arduino-ide is disadjusted. But i have no experience which option this is.

Try a google-search switching from avrdude stk500 to usb virtual comport
Best regards Stefan

OK I am back on track.... well slightly. I got my computer situation sorted out and everything is uploading properly now. I have the switch wired in the following way

1st side goes to ground
2nd side goes to one side of a 10k resistor as well as one wire to pin #5 as in the sketch (StartCycleButton_Pin) then the power goes to the other side of the resistor.

this is how I understood it in the link you sent.

the sketch still doesn't show the times. I used the debug code that you sent and I still get

Start HIGH Split HIGH Push HIGH Cycle HIGH

this is regardless of the button position.

so I am wondering... did I mess up the switch instal? wrong resistor?...... or need to finally get the multi meter and actually test the connections?

the arduino is power through my computer via the USB.... all the sensors are run through the 3.3V on the Arduino.

That is not really acceptable. You must have 5V-3.3V logic level translation for a circuit like that to work reliably. Most 3.3V sensors can be easily damaged by 5V levels on the I/O pins.

so adding a logic level converter could be a solution to the problem I am having?

doing a little research on this... so the IR sensors I am using are powered to the 3.3V pin and that worked before I had the button hooked up.... but this is still not the ideal situation from what I am understanding but it can work.
so the bigger issue is with the button and that would need the converter to work properly?

I am a little confused with this

Hi cnak,

as you can see from the problems that occur. A basic knowledge about electronics is a big advantage for tinkering with microcontrollers.

To narrow down the problem I suggest to go back to very basic tests and I information about your setup.
Did I understand right: You are supplying your Arduino from the USB-cable?
Your sensors are supplied from the 3.3V pin of the Arduino-Uno-Board?

Disconnect everything from your Arduino. Then reconnect only connect the button and the pullup-resistor .

One end of pullup-resistor is connected to 5V the other end of pullup-resistor is connected to IO-pin 5.
Switch one pin of the switch is connected to IO-pin 5 the other pin is conected to ground.

Upload this code

const byte switchPin = 5;

void setup ()
  {
  Serial.begin (115200);
  pinMode (switchPin, INPUT);
  }  // end of setup

void loop ()
  {
  if (digitalRead (switchPin) == HIGH) {
     Serial.println ("Button unpressed");
  } 
     
  else {
    Serial.println ("Button PRESSED");
  }
  delay (1000);  
}  // end of loop

if you have things connected take a picture of it and post it here.
This picture or multiple pictures should clearly show how everything is connected.
The IO-pin-numbers must be seen clearly. Best way to dothis is taking the pictures from exact vertically above

The small testcode should write "Button PRESSED" if buton is pressed and should write "Button unpressed" to the serial monitor if unpressed.

Can you provide datasheets of the sensors that you are using? or at least a link to the onlineshop where you bought them

best regards Stefan

cnak:
so adding a logic level converter could be a solution to the problem I am having?

doing a little research on this… so the IR sensors I am using are powered to the 3.3V pin and that worked before I had the button hooked up… but this is still not the ideal situation from what I am understanding but it can work.
so the bigger issue is with the button and that would need the converter to work properly?

I am a little confused with this

My answer - if everything was working perfectly, knowing that there is a potential problem with the logic levels would only be a future concern. Maybe you could say, “ah, it only does something for entertainment, I don’t depend on the operation for anything important”.

But the fact is, it is not working perfectly, and you actually don’t know what is wrong. In such cases, if you already know about something that is wrong, it makes sense to deal with it before you move on to guessing or performing lengthy troubleshooting.

Sometimes it is the case that you don’t have the ability to fix the known problem (for example, you would have to order level shifters and wait several weeks for delivery). But you can still use the information to troubleshoot. For example Stefan’s suggestion above does this in a very neutral way - without judgement or guesswork about the components of the circuit, instead simply divide them and test them separately. This method is standard troubleshooting procedure, so much that it has a meme, “divide and conquer methodology”. I highly recommend that you follow it.

In parallel with that, or if the system works without the sensors connected, you can still do tests on the hardware to see what’s going on. For example, you could possibly detect one problem with the voltage level translation by measuring the 3.3V line with a DMM. If the protection diodes in the 3.3V devices are violated (which can happen if you apply 5V to an I/O pin), you might measure a voltage greater than 3.3V at the 3.3V power pin, with the I/O lines connected. If you disconnect them (but not the power wire!) and the voltage becomes normal, you know you have a big problem, because the sensors are operating way outside their specifications. So you don’t have to act completely blindly in this situation.

If I were standing over your shoulder, I could show you some “black arts” stuff that I’ve learned, like feeling the parts with your fingers to feel any heat that shouldn’t be there…

HI Stephan

so I did what you suggested and it worked as planned with the test code.

so the obvious difference with the button hook up from before is the voltage pin I was using.... originally everything went to 3.3v and this hook up for just the button was 5v

here are the links to the sensors and buttons I am using.

Button
https://www.rpelectronics.com/r1400a-push-button-switch-spst-2a-off-on-low-profile-metal.html

start gate sensor (distance IR sensor 0-10cm)

Split sensor and Finish sensor (distance IR sensor 20-150cm)

It sound like you had your switch pull up resistor connected to 3.3V instead of 5V. But that may be a complete "red herring" which has nothing to do with the problem. I can say that because you disconnected major parts of the circuit at the same time. If you want to really resolve that more finely, you should now try the same setup but connecting the pull up resistor to 3.3V as you did originally. But for the final circuit, you should use 5V, or just use the INPUT_PULLUP option of pinMode() to select the internal pull up resistor.

I looked at this sensor of yours

Split sensor and Finish sensor (distance IR sensor 20-150cm)
https://leeselectronic.com/en/product/7396.html

Here is the data sheet: https://www.sparkfun.com/datasheets/Sensors/Infrared/gp2y0a02yk_e.pdf
It is specified to run on 5V. Why then are you trying to run it on 3.3V? That is not cool.

I looked at your other sensor

start gate sensor (distance IR sensor 0-10cm)
https://leeselectronic.com/en/product/7393.html

It is specified to run on 2.7 – 6.2 V. Why then are you trying to run it on 3.3V?

What compelled you to use 3.3V at all?