Saturday, December 14, 2024

A Robot Race Car Timing System


Prototyping the system

This project concept came from a YouTube subscriber.  Todd, who is a 6th grade computer science teacher, has a section of each semester where his students build, and then race, small robot cars.  In the past, he filmed the students, ran a stopwatch and recorded each race's final times... all while trying to help and teach the students.

He wondered if an automated timing system could be created with a visible time display.  Adding LED lighting would be a bonus.  What follows is the system that we eventually created.

Introduction

TL;DR:
  • A timing system using an ESP32, two ToF sensors and a matrix display was created.
  • Optional LED accent lighting was added to indicate the current race stage.
  • Modular design allows the system to easily be disassembled and stored when not is use
  • The Arduino/C++ firmware is provided and includes a web interface for controlling the system and making temporary or permanent settings changes.

Now, you may not need a 'robot car' timing system, but the concepts presented could be applied to many different types of projects.  Once unique approach for this project is that distance sensors were used instead of motion sensors and this concept has all sorts of potential other uses.

As always, there is a YouTube video that shows the system in use, along with some overall review of parts and the controller build.  This document contains additional details not covered in the video but focuses primarily on the build of the system.  The Github repo contains a full wiki with information on installing the firmware and using the system, so that will only be touched upon in this article.  Additional links can be found at the end of this article as well.

General Concepts


For this project, the students must build a wire-controlled robot race car and navigate it down a 10' x 16" track.  Points are earned based on completing the course in the shortest time.

Click to enlarge

The project will use a single ESP32 and a sensor at the start and finish lines.  Elapsed time (and other system messages) will be shown on an external display.  LED strip lighting will parallel each side of the track and change colors based on the mode or stage of the race.  Along the way, a few other features will be added.

Parts List

As always, I like to include the complete parts list of the items used in the build covered here and in the YouTube video.  Some parts are optional and substitutions may work for others.  This is noted, where practical, in the list below and in the build details that follow.  For other parts, it may be necessary to modify the source code to work with other components.

Part or Item

Notes

Main Controller Board

 

ESP32 Dev Board

Standard 30-pin version

ElectroCookie 1/2 Size Protoboard

 

2.54mm Pitch 15-Pin Headers

Use 19-pin for ESP32 38 pin/narrow

Logic Level Shifter

Can omit if not using LED strips

5V 10A* Power Supply

*Size dependent on number of LEDs

 

 

Timer Display

 

MAX7219 Dot Matrix Display

 

Normally-Open Push Buttons

Minimum of two needed

3-Position Toggle Switch

 

 

 

Start/Finish Line Sensors

 

VL53L0x ToF Sensors

Minimum of two needed

 

 

LED Strip Lighting

Optional – omit these parts and logic level shifter above if not using LED strips

WS2812b 5V RGBIC LED strip(s)

Length as needed for your track/design

Aluminum LED Channel w/Diffusers

Optional but includes diffusers

Double-sided 3M Tape

Optional but recommended

 

 

Other Components, Connectors and Wiring

 

18-gauge Stranded Wire

 

20-gauge Stranded Wire

 

20-gauge Solid Core Wire

 

22-gauge Stranded Wire

 

2.54mm JST Connector Kit

 

2mm JST Connector Kit

 

2.54mm Dupont Connector Kit

 

2.8 mm Female Spade Connectors

 

 Various Wago Lever Nuts

 

Optional Items (cabling / wiring)

 

1/4" Expandable Braided Sleeve

 

Heat Shrink Tubing

 

3D Printed Enclosure Design Files (.stl)

From the Github Repo

M2 x 6mm Screws

For mounting board in controller enclosure

 

 

Additional Parts used for Breadboard/Bench Testing

 

Prototyping Breadboard

Standard breadboard can also be used.

Breadboard Jumper Kit

 

Dupont Jumpers

 

 

 

Some of these links may be Amazon affiliate links.  Use of these links will not affect your pricing, but as an affiliate this blog may earn a small commission if you make a purchase.

A few additional notes on some of the major components used.

ESP32
I used a standard 30-pin ESP32 Dev board.  The firmware should work with most ESP32 boards, but different pinouts, GPIO pins and wiring may be required.  Because of the width of the standard ESP32, pin headers are required for mounting on the ElectroCookie board to allow connections to the GPIO pins on one side of the board.  A 38-pin "narrow" version of the ESP32 could theoretically be used and not require the pin headers, but the pinout on these boards are significantly different, which would require wiring changes from what is shown here.  Pin headers are recommended regardless, as it allow easy removal/replacement of the ESP32 without modifying the rest of the controller.

VL53L0x ToF Sensors
This project uses distance instead of motion for the start and finish line sensors.  The YouTube video goes into more detail why distance is used instead of motion, but the gist is that a distance sensor allows the creation of a "break beam" for the starting and finishing line, ignoring any motion or objects beyond the immediate track surface. Use of other sensors (motion or distance) would likely require modification of the source code and included libraries.

MAX7219 Matrix Display
Many types of displays could be used, but the MAX7219 matrix was selected for its cost, size, brightness level and ability to better display text over something like a 7-segment display.  Use of other displays is possible but would require code/library changes, along with wiring changes.

WS2812b LED Strips
The use of LED accent strips is optional and can be disabled in the settings.  WS2812b LEDs were selected for their addressability, low-cost, high availability and the 5V operating range.  Long runs (approx. >200 LEDs) may require power injection... which is covered below.  Use of other LED types or voltages is possible, but will require code and wiring changes.

Building the System

This section will cover the build and wiring of the system.  It is recommended that you begin with a breadboard version for testing then move to a soldered version.  The build of the breadboard and soldered versions are very similar, but a few significant differences will be noted.

Before building the controller, you may wish to go ahead and flash the firmware onto the ESP32 and complete the initial onboarding.  Full details of the steps to complete this can be found in the Github Wiki, but is also briefly covered in a following section in this article. 

Breadboard version


Click to enlarge

This is the overall wiring diagram for the entire system.  Obviously when creating a breadboard/temp version, you don't want to create permanent soldered connections, so make all the connections with breadboard and Dupont jumpers, alligator clips, Wago lever nuts, etc.

If not using LED strip lighting, you can eliminate both the LED strips and the level shifter, along with all related wiring.  Be sure to eventually disable the LEDs in the system settings (more on this under the section on web settings).

But if you are using a standard 30-pin ESP32, you may have noticed an issue.  The ESP32 is just wide enough that it won't leave a row of holes on each side of the ESP32 for connecting to the GPIO pins.  


This is where the pin headers come into play.


By elevating the ESP32 onto pin headers, it allows access to make connections to the ESP32 pin underneath the board as well as on one side.  This same concept will be used with the soldered version.

Of course there are alternatives.   You could use a 38-pin "narrow" version of the ESP32, but the pinout for those boards are generally quite a bit different than the 30-pin version, so you'd need to adapt the above diagram for your particular board's GPIO and power pins.

The other alternative is to use a different style of proto/breadboard that will accept the ESP32 and still provide connection points on each side of the board.


In fact, you'll see me using a protoboard here and in the video for my bench testing.

An early version with only one push button and LED strip and no toggle switch

Regardless of the type of ESP32 and breadboard used, you will want to use temporary connection methods to make all the wiring connections as shown in the above diagram.  The only real items of note is that you will want to temporarily place your VL35L0x ToF sensors in a position so that there are no objects, walls, floor, etc. within the field of view for at least a couple of feet in front of the sensor.

While my diagram above shows a 5V 10A power supply, the size of the power supply is primarily dependent upon the quantity of LEDs used (if any).

Selecting a Power Supply and making Power Connections


Before powering on the system, let's discuss selection of the proper power supply size and the recommended method of making power connections.  The size of the power supply is going to be directly dependent upon the type and number of LED strips used.  For standard WS2812b LEDs, each LED pixel can theoretically draw up to 60mA with white on full 100% bright.  That means if you are using a total of 200 LEDs, they could technically pull up to 12A.  But if you are going to be primarily using various colors and/or operate at less than 100% brightness, you won't consistently be pulling the maximum. 

In addition, the firmware has a setting called Max. Milliamps that you will first enter during initial onboarding:


The firmware will use this value to attempt to limit the amount of current the LEDs will draw to no more than this maximum.  You should specify around 80% of the max peak rating on your power supply.  For example, if you are using a 10A power supply, you want to specify about 80% of this value, 8,000 milliamps (8A) for this setting.  This is primarily a safety feature but you should also assure you are using a large enough power supply to adequately support the number of LEDs in use.

In addition, this higher amount of current should not be run through the controller board (and definitely not off the 5V pin of the ESP32) as it is not rated to handle those sort of amps.  Instead, higher current draw devices such as the LED strips should be wired in parallel to the controller.




But what if you aren't using LED strips?  The rest of the system shouldn't require more than 1-2A.  In fact, while this approach is not recommended, if you are omitting the LED strips, you can likely get by with powering the system with a 2-3A power supply and the USB port on the ESP32.


The potential issue with this approach is that the MAX7219 LED dot-matrix display can pull up to one amp with all LEDs on at full brightness.  But when using as a timer, no more than about 20-30% of the LEDs will be lit at any given time.  If using this method, it is also strongly suggested that you limit the display brightness to a setting of 3 or less (scaled from 0-10). In this configuration note that the 5V power rail, and therefore the MAX7219 are being powered directly off the 5V pin of the ESP32.  Attempting to draw too many milliamps through the VIN/5V pin of the ESP32 could damage or even destroy the ESP32.  The above wiring method is probably OK for some initial breadboard testing as long as you keep the display at lower brightness levels.

But this breadboard/Dupont-wired system probably isn't ideal for transportation,  routine use and storage.  For that, let's create a soldered version of the controller and design the rest of the system to facilitate easy assembly and disassembly.

Creating a soldered, modular system


Let's start with the primary controller itself.

ElectroCookie Soldered Version: Note that connections to GPIO pins on the
bottom edge of the ESP32 are made using the through-holes under the ESP32.


As you can see, the ElectroCookie soldered version is very similar to the breadboard version.  There are just a few differences to note:
  • The two ground rails are joined together with a short piece of wire/solder bridge.
  • The MAX7219 is powered off the 5V rail.  This is possible because the 5V rail is being powered via the main power supply and not the 5V pin of the ESP32.  (In addition, I added some 20 gauge wire as a bridge for the 5V rail on the underside of the board... although this is probably overkill).
  • The push buttons and toggle switch have been moved up to be part of the timer display assembly (covered below).
Otherwise, all the GPIO pin and power connections are the same.  The order that you solder components is somewhat arbitrary and based on trying to make soldering easier!  But here is the general order I used:

1. Solder the pin headers to the ElectroCookie board


Using pin headers, like with the breadboard version, elevates the ESP32 and allows use of the through holes under the ESP32 for wiring connections. It also allows easy removal of the ESP32 if needed for USB flashing or in the unlikely event the ESP32 fails and needs replacement.

2. Make all 'point-to-point' wiring connections


Next, I like to make all my point-to-point wiring connections on the ElectroCookie board.  This includes joining the ground rails (but not the + rails!) as highlighted above.  For point-to-point connections, I prefer to use 20 gauge solid core wire as it holds its shape/position and allows me to run the wiring and avoid blocking other through holes that I will need for later connections.  I've gone ahead and added the logic level shifter at this point.

3. Make all external wiring connections with lead wires


I'm using a combination of the through holes under the ESP32 and also along the top row just outside of the pin header.  And since my enclosure has mounting posts that accept M2 screws, it also elevates the ElectroCookie board allowing me to may these wiring connections from both the top and bottom of the board.



FYI:  Design files (.stl) for all my enclosures can be found in the /stl folder of the Github repo.

But note that I said 'wiring leads'.  That is because at this point, the each wire is just a 12-16" lead.  I'm going to come back and add JST connectors to these leads.  But for now, I've just bundled and labeled the wires involved in external connections.


But before we get into wiring connections, let's take a look at the timer display assembly.

Timer Display


In addition to the matrix display, the timer enclosure/assembly will also house the two push buttons and timing mode toggle switch.


The timing display will actually have two independent wire "bundles"... one for the MAX7219 display and other for the two buttons/toggle switch.


Each of the buttons and the toggle switch require a ground connection but we can daisy-chain the ground connections so that we only need one ground wire back to the controller. 


For this and the other component wiring, they will once again just be "leads" at this point.  The primary difference is that you will want to make these leads long enough that when combined with the lead from the controller will result in a total cable length to allow you to place the timer in the approximate final position.  Alternatively, you can keep these leads shorter (~12-18") and build various lengths of extension cables.  This is covered below under the Wiring and Connectors section.

For the MAX7219 display, the first thing I needed to do, based on my enclosure design, is to remove the pre-installed 90° pins and replace with straight pins that extend out the rear of the display.


Luckily, each 8x8 "grid" of the display is independent and just mounted on its own pin headers.  This means that the LED matrix portion can be gently removed to access the header pins.  Naturally de-soldering and replacing the pins is optional and you could just design a different enclosure (or not use one at all).  But in my case, I wanted all wiring to extend out of the back of the enclosure.


For the two sensors, use a similar method to create appropriate length wiring lead bundles.  For the VL53L0x sensors and the MAX7219, I opted to create my own JST connectors using a small kit.


There are a couple of reasons I built my own JST connectors (instead of cutting the lead off of one end of an existing connector):
  • I can create 'headers' with just the right number of pins and using the exact colors of wire that I desired.
  • Most importantly, it allowed me to use 20/22 gauge wire instead of the much smaller gauge wire that is generally used with pre-bought jumpers.  For the longer leads of the sensors, the larger gauge wire will help with voltage drop and the signal itself.
At this point, all components should have wiring "bundles" that correspond to the "bundles" from the controller itself.  Now we just need to create convenient connectors for these bundles and clean up the wiring just a bit.

Wiring and Connectors


The type of connector used (and optional sheathing with a little heat shrink) is really up to you.  I opted to use two different sizes of JST connectors in different pin counts:


By using different JST connector sizes, pin numbers and orientation (male-female vs. female-male), I could design all the connections so that everything only fits one way.  This means that it is impossible to connect the wrong component's wiring to the wrong leads from the controller.  In addition, since JST connectors only fit together in one manner, it is impossible to connect something "backwards" and reverse the polarity of the power connections, possibly damaging or destroying a component.

Again, you can substitute other types of connectors if desired.  The following shows the choices and methods I used.

Timer Display Connections


Recall that there are two separate wiring bundles from the timer display... one for the display itself and the other for the buttons/toggle.  I opted for the smaller 2.0 mm JST connectors here.  But both bundles use 5 wires, so to assure that the connections don't get swapped, one connection uses a male connector from the display and the other uses a female connector. 

Even though it isn't possible to inadvertently swap or reverse these cables due to the orientation of the JST connectors, I added some color coded tape and the wiring colors on each side of the JST connector match.  This certainly isn't required, but I implemented these as an extra visual reference that the connections are correct.

Sensor Connections


I opted for the larger 2.54 JST connectors here.  This is primarily to differentiate the sensor connectors from the timer connectors, but also because the larger JST connectors will accept 20 gauge wire and the larger gauge could be important as the sensors are likely to be located some distance away from the central controller.

I used the same male-female orientation on both connectors since the sensors themselves are interchangeable.   What isn't interchangeable is the start vs. finish connections from the controller... and that's why you see the labeled "start" on the lead from the controller in the above photo.


Since the leads from the controller are actually wired to specific GPIO pins on the controller, the two controller connections are not interchangeable.  I designed mine so that the connection for the start line sensor connects to the wiring exiting from the end of the enclosure where the ESP32's USB port is located.

Of course you can reverse this in your build if desired by just channeling the wire bundles in the opposite direction.  Alternatively, if you need to reverse the connections after the controller is built, you can make a simple code change in the firmware to swap the GPIO pins that each connector is using:

Original values with start line sensor cable on USB end

Swapped values with finish line sensor cable on USB end

This will effectively "swap" the controller's start sensor and the finish sensor connections.  Naturally, you will need to compile and flash your changes to the controller.  A little more information on making code and firmware changes can be found in the Github wiki, but details on modifying/creating Arduino code is beyond the scope of this project.

If you've never used the Arduino IDE with an ESP32 (or ESP8266), this video should provide you with the information needed to get started:

Arduino IDE: ESP32/ESP8266 Basics for Non-Coders

LED Strip Wiring


If you are implementing the optional LED strip lighting, recall from the discussion above that due to the current draw from anything more than just a few LEDs, it is necessary to provide power for the LEDs directly from the power supply.

Click to enlarge

Note that there is only a single LED data line coming from the controller.  If using two LED strips, you simply split this signal and run it to each LED's data in (DI) line.  Both LED strips will always receive the same data signal and always remain in sync.  Note that with the current wiring/firmware, it isn't possible to have each LED strips display a different color or pattern.  If using only one LED strip, you can run the LED data line directly from the controller to the data in (DI) on the LED strip.

For the connectors, LED strips generally come with a 2.54mm 3-pin female JST connector soldered to the start of the strip (note that the end of the strip will have a male connector). Recall that with addressable strips, the data only flows one direction, so assure you are connecting the LED data line to the start of the strip and not the end.  This is always indicated by small arrows on the LED strip itself that indicates data direction.


Since the LED strip came pre-installed with a JST 3-pin female connector at the start, I simply created a male JST pin with wire leads for power and data that will connect to the Wago lever nuts.


How and where you install the LED strips is also at your discretion.  I wanted LED lighting down both sides of the entire length of the 10' track.  But you could do something like a short single strip mounted somewhere to indicate the race stages.

I placed my LEDs in an aluminum channel specifically designed for LED strips.


These come with diffusers and mounting clips and you can get them in a variety of configurations.  The above shows the "flat" channel and one with a 45° angle.  You can use whatever configuration fits your mounting location.

I also like to add a little 3M double-sided tape between the channel and the LED strip.  This just assures the LEDs do not work loose over time, as they will generate a little heat and the adhesive that comes on the back of the LED strips isn't that fantastic.  But using the double-sided tape is optional.  Simply cut your LED strips to desired length.  The aluminum channel can easily be cut with a hacksaw or similar.  Lay down the double-sided tape (if using) and remove the protective tape.  Then remove the protective tape from the back of the LED strip and adhere either to the double-sided tape or directly to the aluminum channel.  Again, you can put the LED strips anywhere you like... or omit altogether.

The only potential issue I needed to avoid was installing the LED strips where they could potentially interfere with the cars.  In the case of the 6th grade projects, one of the challenges is to simply keep the car on the track from start to finish.  So the LED strips and/or channel should not act as "bumpers" or prevent the car from exiting the sides of the track or course.


Since the 'track' or 'course' in this case will consist of 1/2" plywood or particle board, the LED channel can lay along side the track and not interfere with cars veering off either side of the course.  Again, your particular install may vary.

With that, all components can now easily be disassembled and stored when not in use.


When it is time to use the system again, it only requires making a few JST connections... and since everything is keyed/oriented differently, components cannot be connected to the wrong leads from the controller nor can connections be 'reversed'.

Power Wiring and Connections


While the power connections are included in the overall wiring diagrams above, let's take a look at just the power-related connections.

Click to enlarge

As described, 5V power is run in parallel to the controller and LED strips.  5V from the power supply is connected to a power rail on one side of the ElectroCookie.  This 5V rail will power the ESP32 via its VIN and GND pins.  Unlike the breadboard version, the MAX7219 display will also be powered from this 5V rail.  As mentioned, the MAX7219 can potentially draw up to 1A at full brightness with all LEDs lit.  But since less than 30% of the LEDs will ever bit lit simultaneously when used as a timer, the draw should be less than 500mA so I'm using the 5V rail.  Since the traces are a bit small on the ElectroCookie, as an extra precaution I run a 20-gauge "bridge wire" between the incoming 5V and the MAX7219 connections.  But this is probably overkill.

On the opposite power rail, the ESP32's 3V3 pin is connected to provide a 3.3V rail.  This will be used to power the two VL53L0x sensors.  These draw very little current, so no bridging or alternate power source is needed.

Powering via the ESP32 USB Port


If not using LED strips and you disable them via the initial onboarding (see below), then it is possible to power the system via the 5V USB port on the ESP32.  

Click to enlarge
Any 5V 2.5-3A power source should work... like a wall wort or even a cell phone charger. When using this method you must exercise a bit of care regarding the MAX7219 display.  When powering via the USB port, then the 5V power rail for powering the display is generated through the ESP32's VIN pin.... and this has limits on maximum current.  It is advised to use lower brightness levels on the display when powering via the USB port.

While this method will likely work without issue, it is still recommended to power the controller directly from a power source of at least 3A (with no LEDs) wired directly to the 5V rail of the ElectroCookie board and then powering the ESP32 from this power rail.

Do not attempt to use the USB port as the power source when powering LED strips!  This will almost surely attempt to draw too much current through the ESP32 and will likely lead to damage or destruction of the ESP32.

Power Injection (for LED strips only)


This last power-related section only applies if using LED strip(s).  If using lengthier strips with a lot of LEDs (> ~150-200 per strip or side), you may notice LEDs towards the end of the strip that are fading or shifting colors.  In some instances, the LEDs may even flicker or misbehave.  This is generally due to voltage drop along the strip, resulting in LEDs towards the end not receiving enough voltage to fully light properly.  This can almost always be resolved by implementing power injection.


Power injection involves running new power leads from the power source to the opposite end of the LED strip and connecting to the +5V and GND on the LED strip.  


How you make these connections is up to you.  You could solder the power injection leads directly to the LEDs, but this sort of defeats the purpose of making the system modular and easy to disassemble and store.  But we can also use JST connectors here as well.


Most LED strips will have a male 3-pin JST connector pre-attached to the end of the LED strip, similar to the start of the strip (except the start of the strip uses a female connector).  In addition, these pre-attached connectors generally have a couple of extra free wires.  These wires are connected to the +5V and GND of the LED strip and are meant specifically for power injection.

If you've cut the strip to fit your installation, then the end JST connector is probably missing.  But many LED strips also provide an extra male JST connector in the packaging just for this purpose.  You could solder the extra JST connector to the end of the LED strip.

Then you could add a 3-pin JST connector to the power injection leads. If you use this method only the two outer pins would be used as the center pin is for the LED data line and that is only connected at the start of these strip.  Alternatively, you could create your own 2-pin JST connector to solder to the LED strip's +5V/GND pads and then add the opposite 2-pin JST connector. Or you could just use bare wire and connect the leads to the wires from the LED strip using Wago lever nuts or any other type of appropriately rated connectors.  If using two LED strips, just repeat for the other strip.

Of course, this now results in a couple of long wire runs that need to be cleaned up or hidden.  For my particular project, the race "track" will be a long, narrow strip of plywood, with the LEDs mounted along each side.


I was able to simply tuck the power injection wires between the plywood "track" and the LED strip aluminum channel.  Sometimes you just need to be a bit creative with the best method of running power injection wires.  For this project, it was important that the wires do not interfere with the track or robot cars and that they do not create a tripping hazard for students moving around the track area.

If needed, adding power injection at the end of the LED strips should allow you to adequately power 400-500 LEDs per strip/side.  If you do note some slight fading, this can often be address by just slightly lowering the brightness levels of the LEDs.

Note:  The firmware has a hardcoded max of 500 LEDs (per side/strip).

Extension cables


In the build above, short 12-18" leads were created from the controller, but the leads from the individual external components (sensors, timer, LEDs, etc.) were built to "planned lengths".  But you may be planning on using the system in multiple locations or for multiple occasions and may not know the final setup or lengths of cabling needed.  In this case, you can make the leads from the various components shorter (again maybe 12-24") and create a series of extension cables in various configurations and lengths.


Whether using 2.0mm or 2.54mm JST connectors, 3-pin, 4-pin or 5-pin, you can just create a cable with a male connector on one end and a female connector on the other.  These can be used to extend the distance of any cable connection and the extras can be stored along with the system.

Note: Do not make cables any longer than absolutely necessary, especially the sensor cables.  Longer cables (and thinner gauge wire) are more susceptible to voltage drop and/or EM interference which can introduce noise and cause false triggers. Only use the length of cable needed for a particular event or install.  


Setting Up the System Hardware

OK... the system is built and ready to be connected.  Let's cover how to setup and position the hardware for the best results.

General Component Positioning



This is my overall setup and layout for the 6th grade "races" but your setup is likely to be different, so adapt as needed.  In my case the "race course" is 10 feet from start to finish.  If I place the primary controller in the center of the course, I'll need around 5' cable lengths for each of the sensors.  The timer position can really be about anywhere, but I'll probably place it near the finish line somewhere, so 4-5' cables will be needed here.  The longest run will be the LED data line.  But that's why the logic level shifter was used.  This gives the ability to have a much longer wire run from the controller to the start of the LED strip.

While placement of the controller, timer and even the LED strips are somewhat arbitrary, the sensor placements certainly aren't and will take some trial and error to get just right.

Positioning and Aligning the Start and Finish Sensors


For this step, you will want to connect everything and power on the system.  You should have completed the initial onboarding and should be able to access the web settings page for the controller before moving forward.  At a minimum, you'll want the timer module connected.  LEDs aren't needed but you can certainly go ahead and connect them as they serve as another visual notification for the various stages of a race.  

Next, it will be helpful if you have the sensors mounted in an enclosure or otherwise mounted so that small adjustments to the horizontal and vertical position can be made.


In my case, the sensor is in a 3D printed enclosure (design files for all my enclosures can be found in the Github repo).  The enclosure is attached to a small wood platform with a screw and washer.  The screw is tightened just enough to hold the sensor in position, but loose enough to allow the sensor to be turned left and right for horizontal alignment.  The enclosure itself consists of mounting pins that allow vertical adjustment but will hold its position.

Vertical alignment is important here, especially if the sensor is to mounted on the ground or near track level.  Why? Well, the sensor has a field-of-view of approximately 25°... and this is vertically as well as horizontally.


If the sensor is placed level and perpendicular to the track, the surface of the track will be within the F.O.V. of the sensor and it will continuously report back the distance from the sensor to the track surface and not an object on the track that is crossing the start/finish line.  If the timer starts immediately as soon as the system is placed in ready mode and there aren't any objects on the track, you likely need to adjust the vertical alignment.  For the initial adjustment, just aim it high enough that the timer does not automatically start as soon as placed in ready mode.  You'll fine-tune this later.

Horizontally, the alignment is similar.

Click to enlarge

There's a lot to digest in that diagram, so let's start with the horizontal distance between the sensor and near edge of the track.  The VL53L0x sensor has a minimum distance range of 5 cm (~2").  Inside of this range, it may not detect objects or give inaccurate readings.  So first position the sensors approximately 2-6" from the edge of the track or detection area.

Next, similar to vertical alignment, turn the sensors left or right to align the edge of the F.O.V. cone to be parallel and as closely aligned as possible to the leading edges of the start and finish lines.  This will take a little trial-and-error.  Initially, just shoot for something close.  You want the start sensor to start the timer as soon as an object touches or crosses the start line and the time to stop as soon as the object touches/crosses the finish line.

While the minimum range of the VL53L0x is 5 cm, the maximum range is around 1.2M (almost 4 feet!).  This means that it will detect/return measurement values for objects well beyond the 16" width of my track.  This means that people or other objects could enter the area near the opposite side of the track and trigger the sensors to start or stop the time.  Not good!

If your course is wider than about 1M (3.25 feet), then you may not be able to use the VL53L0x sensor.  You might be able to use an ultrasonic sensor or something like a TF-Mini LIDAR sensor (a much better choice, but also much more expensive).  Changing sensor types will also require firmware code changes to work with a different sensor.  That is beyond the scope of this project, but the source code is available on Github if you wish to give it a shot.

To fix the range issue issue for narrower courses, we'll use the web settings for the controller.  The web settings has a sensor distance setting for each sensor:


This will limit the maximum distance (always entered in millimeters) that the sensor will use for triggering the timer.  In my example, I have these distances set to 395mm and 405mm for the start and finish sensors, respectively.  With these values set, objects, motion or movement outside the track area (as indicated by the green dashed box) will no longer be detected.


In effect, we are creating 'break beams' across the start and finish lines.  Anytime an object approaches and touches/crosses the start or finish line from the 'race direction', the timer will be automatically started or stopped accordingly.

Due to the cone-shaped field-of-view, it is not possible to run the course "backwards" or in the reverse direction.  This is because the object will enter the field-of-view cone from the opposite direction before reaching the line.

You will likely need to continue making small adjustments to the vertical and horizontal alignment, along with max sensor distances until the sensors are precisely positioned so that the timer starts/stops just as an object touches the start/finish lines and isn't triggered by objects or movement outside of the track area.  In my testing, it took about 10 minutes to align the sensors and from that point forward, the system worked perfectly every time with no further adjustments.

Settings, Options and Using the System

Full details for installing, initializing and using the firmware, along with all the various setting and options are detailed in full in both the Github wiki and in a User Setup and User Guide document, also found in the Github repo (docs folder).

Future firmware enhancements or updates may also render some of information in this article obsolete.  For this reason, the following sections will only briefly cover firmware or system use topics.

IMPORTANT: Always check the Github wiki for the most complete and latest information for anything related to firmware or use of the system!

The following are highlights only and does not include all the pertinent details that are needed to setup and use the system.  See the wiki!
 

Installing (flashing) the Firmware


Before the system can be used, the firmware must be installed, or flashed, onto the ESP32.  For the initial installation only, this will require connecting the ESP32 to a computer via USB data cable.  To do this, you will temporarily need to use a desktop utility like NodeMCU PyFlasher or ESPHome Flasher (no... you do not need to have/use ESPHome).  Links to both are provided below.  Follow the info in the wiki for more details.

The USB cable and physical connection to a computer will only be needed once for the initial flash/installation.  After the firmware is installed, it contains utilities for installing future firmware updates wirelessly over-the-air (OTA).

Onboarding and Initial Configuration of the System


After the firmware is flashed, you must onboard the system to your WiFi.  The firmware will temporarily broadcast a local hotspot, RaceTimer_AP, that you will connect to with your mobile device, laptop or other device that can connect to an ad-hoc wireless network.  


Once connected, use the device's browser to navigate to http://192.168.4.1


You will enter your wifi information, along with a few default system settings on this form.  The wiki has complete details, but in short, these are the additional fields you will need to complete:
  • Device Name:  Give your project a unique name.  This not only allows multiple versions to co-exist and be identified on a single network, but the device name is also used as the WiFi hostname and as part of the Arduino IDE OTA name.  You should only use up to 16 alphanumeric characters, with no symbols or spaces.  Examples might be names like 'Timer01', 'RobotTimerProd', 'RobetTimerTest', etc. This can only be changed later by resetting the controller and onboarding again.
  • Number of LEDs:  Enter the number of LEDs used.  If using two LED strips, this should be the number of just one strip.  If one strip has more LEDs than the other, enter the larger of the two numbers.  If you are not using LED strips, enter 0 to disable LED use.  This can be changed later via the web settings.
  • LED Brightness: Enter the starting brightness level for the LED strips, from 1-10.  Lower values will use less power and can reduce fading LEDs at the end of the strip.  Ignored if number of LEDs is 0.  Can be changed later via settings page.
  • Maximum Milliamps: If using LEDs, enter the maximum milliamps that the LEDs should be permitted to draw.  It is recommended that you use 80% of the peak max rating of your power supply.  For example, if using a 10A (10,000mA), then use a value of 8,000 mA as the max.  Permissible range is 2,000-15,000 mA.  Ignored if not using LEDs.   Can be change later via settings page.
When you save these settings, the controller will reboot and attempt to join your WiFi.  See the Github Wiki for more information, including identifying whether the device is on WiFi or not.  If the controller does successfully join WiFi, the timer display will show the assigned IP address (one segment at a time) during the boot process. 

Timer showing an IP address of 192.168.1.229 during boot up

You will then use this IP address in a browser of a device on the same WiFi network to reach the system settings page.

System Settings (temp vs. boot settings) 

Once the controller is joined to your WiFi, a settings page can be accessed by going to the IP address of the controller (e.g. http://192.168.1.237) from any device on the same WiFi network.  The settings page is responsive, so you can use a phone, tablet, laptop or desktop PC/Mac to connect.


This page allows you to set and control most settings and options related to the system, including setting final sensor distances, brightness levels of both the LEDs (if used) and the timer display.

You can change and test different settings, LED colors, etc. just temporarily and the changes will remain in effect until changed again or until the controller reboots, at which point it will reload all the default settings from a configuration file.  If you make changes and want to save them as the new default(s), you can check a box and save your settings as the new boot defaults.


The web settings page also has a number of command that can be issued to the controller, everything from a simple reboot to a full system reset.  The web app also allows you to easily apply future firmware updates over-the-air (OTA) wirelessly right from the web app itself.

See the Github Wiki for full information on all the various settings and commands.

Typical System Use and Options


Designed use is for a sensor at the start and finish line of a race track or course.  A race car (or other object), crosses the start line and the time will automatically start and the LEDs (if used) will change from the ready color to the active race color(s).  As soon as the car/object reaches the finish line, the timer automatically stops and the LEDs change to the completed race color.

Timing resolution can be seconds or tenths of a second.  In seconds resolution, the maximum permissible race time is 99 minutes, 59 seconds (99:59).  The timer will "timeout" when this limit is reached and the LEDs will change to the 'time expired' color. When timing resolution is set to tenths of a second, then the maximum race time is 9 minutes, 59 seconds (9:59.9).


This is when the system is set to 'auto' mode.  But it also has a manual mode option.


A 3-position toggle switch on the timer display allow you to set the system to manual mode.  When operating manually, the start and finish line sensors are completely ignored and time is started/stopped manually using the start/stop button on the timer itself.  Basically, the system works like a stopwatch.  The LEDs (if used) will respond just the same as in auto mode, changing colors based on current race stage.

This toggle can also be set to the center standby position.  When in standby mode, the LEDs and timer display are shut off, but the controller remains powered on and running, maintain all current settings and system state.  The system can be restored by simply moving the toggle to either auto or manual timing mode.

Once again, see the Github Wiki for full details on using the system.

Other Potential Uses and Ideas


This certainly is not the only configuration or the only components that could be used to create a timing system.  In addition, the components and concepts that I used to create a very specific system for a local 6th grade computer science class can be adapted to other project types.

For example, I use two VL53L0x sensors in a very similar "break beam" configuration at the top and bottom of my stairs to trigger and control LED stair lighting.  This replaced the original PIR sensors that were susceptible to false triggers when someone just walked near the stairs.  And naturally there are many other uses for timers, clocks or displays that could be implemented in a manner similar to this project.

Let me know down in the comments if you have any thoughts or questions.  And as always, thanks for reading!

ResinChem Tech





Links and Additional Information

Github Project Repository (firmware, source, docs, wiki and more)
NodeMCU PyFlasher (firmware flashing utility)
ESPHome Flasher (another flashing utility)

Additional videos that may be of interest or are referenced above:
A Beginner's Guide to DIY LED Projects (common questions and answers)

Supporting this blog and related YouTube channel


It takes significant time and effort (and occasionally expense) to create these articles and videos.  If you'd like to support future content on this blog and the related YouTube channel, or just say thanks for something that helped you out, you can consider buying me a one-off cup of coffee or two at:

No comments:

Post a Comment

To help eliminate spam and to keep all conversations civil, submitted comments are moderated. Therefore your post may not show up immediately. Please be patient as most reviews are completed within a few hours.