Train Speedometer — Implementation

Background

This page is a follow-up to the Train Speedometer – Basics page and goes into more detail on the hardware and software I actually set up and tested.

Hardware

The hardware items I used for my train speedometer testbed are:

Four-conductor I2C cables (called “Qwiic” by SparkFun, “STEMMA” by Adafruit) are used to connect the Qwiic Shield connectors to the two sensors and the pair of displays. Each of the sensors also has an additional pair of wires connected to GPIO (general-purpose input/output) pins on the Arduino. These are explained in more detail below.

Setup

Figure 1 below shows the pair of ToF sensors mounted at each end of the prototyping board. They are centered on holes that are 5.0 inches (50 holes apart at 0.1 inch spacing), or 127 millimeters. This determines the sensor spacing which is used to calculate the measured scale speed. The four-conductor twisted cables going to the sensors are the I2C bus connections to the Arduino through the Qwiic shield.

Figure 1: Sensor unit alongside KATO Unitrack setup

Connecting to the upper edge of the prototyping board are four more wires connected to four Arduino GPIO pins. Two of the wires are used to disable or enable the sensor boards, which are needed to set each sensor to its own I2C address. The other pair of wires bring a logic signal from each sensor back to the Arduino to indicate that each sensor has taken a range measurement..

The pair of sensors are placed about 33 millimeters from the nearest edge of the track; 33 millimeters is also the center-to-center spacing between the two KATO tracks. The sensor-to-track distance can be adjusted in the Arduino code, as can be the spacing between the sensors. Because the sensors don’t need to be right up near the track being monitored, they could be hidden on a model railroad layout inside trackside buildings, with each sensor looking through a small hole in one wall of the building. It’s important that the two sensors be placed as close as possible to the same distance from the track.

Video 1 below shows one of the sensors powering up when the power adapter to the Arduino is plugged in. After the green power-on LEDs light up, you can see the laser emitter in the center of the sensor board flickering on. The laser’s light is actually infrared so invisible to the eye, but digital cameras such as in mobile devices can see the infrared laser beam, as long as the camera is close enough to being directly in front of the sensor.

Video 1: Powering up the sensors

Videos 2 and 3 below show early testing of the two sensors, to verify that they can indeed detect trains passing on the two tracks, giving an approximate (and very twitchy) measure of the range, measured in millimeters. The sensors are set to measure only out to about 200 mm (about 8 inches). If a sensor does not get a reflected light pulse from a surface within that distance, it returns a measure of 255 mm (which happens to be the highest number that can be represented with an 8-bit binary value). So a reading of 255 will definitely be treated as a NO-DETECT condition.

(And I apologize in advance for the two displays being swapped left and right relative to the pair of sensors. Didn’t catch that when I was recording the videos.)

Video 2: Testing ToF distance sensors, test 1
Video 3: Testing ToF distance sensors, test 2

As you can see in the two videos, the tram on the inner loop is measured at about 33 mm from the sensors, while the train on the outer loop is about 66 mm away. Being able to identify on which track a train is passing allows the speedometer to measure only those trains passing on one specific track.

Operating the speedometer

To convert the sensor testing setup shown above, the actual speedometer code was written to:

  1. Create DETECT and NO-DETECT states from the measured ranges received from the sensors.
  2. Compute the scale speed of a passing train from the relative timing of DETECT conditions on the two sensors.
  3. Display the computed scale speed.

Detect a train

As you probably noticed in videos 2 and 3 above, the range measurements coming from each sensor are very noisy, partly because the train is not a smooth stationary surface. The measurement noise is also partly due to the sensor trying to measure time intervals on the order of a billionth of a second (nanoseconds) because of the speed of light and the short distances being measured. So the series of range measurements needs some cleaning up.

To convert a rapid series of range measurements into DETECT/NO-DETECT states, several signal processing steps are applied to the incoming data for each sensor.

  1. Each measured range value is averaged with a fixed number of the measurements immediately before. In my test code, I average each sample with the 4 values before to create a running average. This smooths the stream of measurements quite a bit, reducing the noise in the data stream.
  2. The smoothed range measurements are compared against a minimum range and a maximum range, which roughly bracket the track being monitored. A hysteresis algorithm is used when comparing with the range limits to reduce switching between DETECT and NO-DETECT when the range is near either limit for too long.
  3. Once a range measurement has been cleaned up, a DETECT is declared when the range is greater than the minimum range, but less than the maximum. Any range outside the minimum-to-maximum window is considered a NO-DETECT.

By using this process, the speedometer will only detect passing trains on the one track that falls between the range limits.

Compute the train’s speed

Each time the speedometer’s code sees one of the sensors go from NO-DETECT to DETECT, it reads the Arduino’s millisecond-clock. If one sensor goes to DETECT while the other is still NO-DETECT, this marks the beginning of a timing interval. When the other sensor goes to DETECT (even if the first sensor has returned to NO-DETECT), this marks the end of the timing interval. The difference between these two clock readings is the number of milliseconds which the passing train took to get from one sensor to the other. From this the speed is computed. (See this section on the Train Speedometer – Basics page.)

Display the speed

Once the speed has been calculated, it is written to the 8-character digital display in either miles-per-hour or kilometers-per-hour, depending on whether one of the Arduino’s GPIO pins is tied to 0 volts or not. Another GPIO pin also allows the scale factor to be switched between two values. In my test setup, the scale factors are either 150 for Japanese non-shinkansen models, or 160 for shinkansen models and US models.

Testing the speedometer

Here are videos of the train speedometer being tested. In the videos, you will see a red LED on the Arduino turn on when one sensor has detected the passing train, and the speedometer is waiting for the other sensor to detect the train. Once the train has been detected by both sensors (which was first doesn’t matter), the speed is displayed.

Video 4: Testing at scale speed of about 40 km/hr
Video 5: Testing at scale speed of about 60 km/hr

As a bit of trivia about the two videos above, 40 and 60 km/hr happen to be the actual speeds of the real trams which run on the Toyama Light Rail system (also called PORTRAM) in Toyama, Japan; the tram in the videos is an N-scale model of a PORTRAM. The trams in Toyama run at a top speed of 40 km/hr on parts of their track which are built on the city roads. On the portion that goes north to the port by Toyama Bay, the tracks are not on city roads, so the trams can run at up to 60 km/hr.

In the next video, you will see that only the track closer to the sensors is being monitored by the speedometer. A locomotive on the outer loop is outside the preset range of distances the speedometer is watching, so the locomotive’s speed is NOT measured.

Video 6: Speedometer watching only inner loop

Finally, the video below starts with a pair of jumper wires tying two GPIO pins to 0 volts. In this mode, (a) the displayed speed will be in miles-per-hour rather than kilometers-per-hour, and (b) the speed scale factor is 160 as would be used for US N-scale train models. When the wires are removed partway through, the speedometer switches to kilometers-per-hour and a scale factor of 150 (Japanese N-scale).

Video 7: Switching speedometer modes

つづく