4-Lane Race Car Timing - Build Log

I am designing a 4 lane race track. The cars will be built from Lego. Overall the final product will be very similar to a pinewood derby track. My goal for this thread is to log my progress and hope that others may be able to learn from my progress and mistakes. If you see something that you could improve, please chime in!
Major design features:

  • Touch Screen Display
  • Manual or Automatic Car Release
  • Individual Christmas tree for each lane
  • MP3 Audio with built in SD Card reader for cues and sound effects

The brains of the operation will be an Arduino Mega. I chose a Mega because I will also be using a 2.4 inch TFT LCD Touch Screen Shield.
The touch screen will be where the users select automatic or manual car release. Races can be run on any combination of 1, 2, 3, or 4 lanes. Elapsed Time, Reaction Time, Disqualified, Race Rankings will be displayed here.
Each lane will have indicator lights like a real drag strip. Prestage (lane active), Stage (racer ready), 3, 2, 1, Go! and Disqualified. LEDs will be run using a shift register.
After the lanes have been setup on the touch screen, "Prestage" will light on the active lanes. When the car is placed and the racer has pushed their control button, "Stage" will light. After all active lanes have been staged, the 3,2,1,Go! lights will sequence. The MP3 module will play an audible countdown. If the racer has selected manual release, s/he must hit the control button to release the car. If the car is released prior to Go!, the car will be DQ'd. In automatic release mode, the car will be released after a short (~5mS) delay.
Each lane will have a solenoid controlled gate. Solenoids will be driven through a shift register and transistor/MOSFET.
Each lane will have an IR emitter/detector pair for finish timing. If a detector pair is not triggered after a anticipated finish time, that lane will be logged as DNF. I plan to use a Schmitt trigger to set the output of the IR detector to a hard On/Off so the Mega can read it properly.
Final times and rankings will be displayed on the TFT screen. The MP3 module will play a "Lane X wins". The track can then be reset to start a new race.
I anticipate using a lot of interrupts from button pushes and IR detectors for setting flags. The main loop will probably be several switch cases depending on the stage of the race and taking action on the flags set in the interrupts. Parts are on the way and the track construction is starting soon. As I make progress, I'll post updates and my code.

Interrupts rule of thumb: you don't need interrupts.

Interrupts and buttons are a very bad combination (by the time you understand why this is, you may start using interrupts).

You MAY need interrupts for the break beam sensors (depending on how fast your cars are) but with proper programming you can check them easily a couple hundred times a second so you very likely don't need interrupts.

Why using shift registers when you have a Mega?

wvmarle:
Interrupts rule of thumb: you don't need interrupts.

Interrupts and buttons are a very bad combination (by the time you understand why this is, you may start using interrupts).

I understand the importance of debouncing the buttons to eliminate multiple triggers. That will be taken care of in hardware. The interrupt will set a flag and return to the loop. Am l missing something else?

Why use shift registers when you have a Mega?

I have several on hand and it would be an easy way to manage all the lights in software. I plan to use a register to release the gates at the same time.Stringing in a couple more for the lights will be no big deal.

Thanks for the interest and comments!

tblake3:
I understand the importance of debouncing the buttons to eliminate multiple triggers. That will be taken care of in hardware. The interrupt will set a flag and return to the loop. Am l missing something else?

So instead of polling a button you're polling a flag set by an interrupt routine, same overall reaction time. That's not an improvement, on the contrary as your code has become more complex.

A bit of software debounce and you don't need the hardware debounce.

I have several on hand and it would be an easy way to manage all the lights in software. I plan to use a register to release the gates at the same time.Stringing in a couple more for the lights will be no big deal.

A series of digitalWrite() calls set pins just microseconds apart, the variance in reaction time of your solenoids (magnetic field collapsing, spring starting to move back the pin, etc) will be more than this. Or if you really want your pins to change at even more the same time, make sure all pins are on the same PORT and use a PORTx register call to set the pins all at the exact same time.

tblake3:
I anticipate using a lot of interrupts from button pushes

Why do you think you need debounce?

I just don’t understand how subsequent bounces would change anything in this type of application.

Press button, trigger state variable, ignore button until next race start turns state variable back.

wvmarle:
So instead of polling a button you're polling a flag set by an interrupt routine, same overall reaction time. That's not an improvement, on the contrary as your code has become more complex.

Good point.

A bit of software debounce and you don't need the hardware debounce.

Since I was stuck on using interrupts, I didn't think putting software debounce in an interrupt was a good idea, therefore hardware.

A series of digitalWrite() calls set pins just microseconds apart, the variance in reaction time of your solenoids (magnetic field collapsing, spring starting to move back the pin, etc) will be more than this. Or if you really want your pins to change at even more the same time, make sure all pins are on the same PORT and use a PORTx register call to set the pins all at the exact same time.

I should mention that if some racers are using manual release, the pins shouldn't release at the same time. As more racers hit their buttons, that bit would be added to the shift queue and release to the register at the end of the loop.

My mentality was also stuck in the Uno world. Counting up all the individual LEDs, IR sensors, etc., my Uno design influence automatically set to using shift registers.

Slumpert:
Why do you think you need debounce?

I didn't think software debounce within an interrupt call was a good idea. I haven't used them before and all my reading suggested that you should interrupt, set a flag and get back to the main loop.

I just don’t understand how subsequent bounces would change anything in this type of application.
Press button, trigger state variable, ignore button until next race start turns state variable back.

For most of the race sequence, extra button pushes wouldn't matter. In the case where you are the last racer to "Stage", the race mode immediately switches to countdown mode. An extra button push would seem to be a false start and DQ that racer.
As others have suggested, interrupts may be an unnecessary complication allowing software debounce. That would reduce the component BOM.
I admit that I have probably overthought and unnecessarily complicated my design. Sub-milllisecond timing on a kids Lego racetrack is not going to be that critical. It's a toy for kids to have fun with not a defense system catching flying neutrons.