Abstract/Summary:This project tracks a model train using four sensors - displays status on serial port and controls signals - uses ESP8266 microcontroller. With limited number of microcontroller pins the input and output are via the serial ports.
Possible Audience: Model train enthusiasts wishing to monitor the status of a model train. Some hardware and software is assumed.
Keywords: ESP8266, Arduino IDE Program Manager, LDR Light Detecting Resistors, enum type, state machine, watchdog timer
Components Required: ESP8266 Microcontroller, 74HC164, 74HC165 and 74HC02 chips. 4 LDR plus resistors. 4 sets of RED,AMBER,GREEN Leds for laboratory testing.
Required Software: Arduino IDE with ESP8266 Add on. Libraries from previous projects: Signals3_Serial_Class and LDR_Serial_Sensor_Class
This project is concerned with tracking the locaton of a model train as it moves along a section of track. The position of the train will be detected using LDR (Light Detecting Resistors). As the train passes each sensor the signals will go through a RED-AMBER-GREEN sequence. Four states, {coming,arriving,departing,going} are defined when the train is over a sensor and three states, approaching,station,leaving when the train is between the sensors. The other state is waiting when there are no trains present.
Long term it is proposed to send the train status to external devices via WiFi hence the ESP8266 is the chosen micro-controller although the Arduino UNO or NANO could be used.
Since this design will require 16 signals and the ESP8266 has only 11 free the design will use a parallel to serial chip on the input plus a serial to parallel chip plus a "glue" chip on the output.
My design is shown above. Note I am using 4k7 pull up resistors on the LDRs and 1k current limiting resistors on the LEDs. These work well in my environment but may need to be adjusted in other situations.
I have constructed the prototype using two wire-wrapped boards.
The "final" setup on my layout is shown across. As everything is still in prototype form I have continued to use LEDs rather that the expense of actual true to scale signals.
Note I am using 4k7 pull up resistors on the LDRs and 1k current limiting resistors on the LEDs. These work well in my environment but may need to be adjusted in other situations.
The project will use the Arduino IDE with the ESP8266 Add-ons.
This will allow the Arduino IDE editor to be used but the results are then compiled for the ESP8266. The advantage is that applications can be developed for the ESP8266 without the developer having to learn more complex and/or different tools. The disadvantage is that some of the features/attributes of theESP8266 may be hidden in the simplification. It may also lead to the impression that the ESP8266 is similar to the ATMega828 in the Arduino when it is not.
If required Install the drivers: (I was using a WiFi Mini product code XC3802 from Jaycar) and found my PC recognized the XC3802 I was using so this step was not necessary)
If the library is not found the WiFi Mini uses a CH340G USB-Serial IC. The drivers for this can be downloaded from the IC manufacturer’s website: http://www.wch.cn/download/CH341SER_ZIP.html
To add board support for tjhe ESP8266 it is recommended to use Arduino IDE version 1.6.4 or later so that the Boards Manager can handle the installation.
1. To install board support for ESP8266, in File-->Preferences-->Additional Board Manager URLS add: http://arduino.esp8266.com/stable/package_esp8266com_index.json separating from existing entries with a comma.
2: Go to Tools-->Boards-->Boards Manager and type 'esp' in the search box
3. Install ESP8266 by ESP8266 Community. (Button on lower right) This is about 150MB download and can take a while.
4. Select the desired ESP6266 board. My board was identical to the 'WeMos D1 Mini Lite’
The Arduino IDE will now start creating, compiling and running programs with the ESP8266.
If readers have implemented the projects they will have the two libraries Signals3_Serial_Class and LDR_Serial_Sensor_Class. If not, it is recommended that readers complete these projects and generate the libraries.
As a starting point the following code should be entered in the IDE. I have given the file the name/label Track_Train_ESP.ino.
Notes:
1. Use Sketch-->Include Library--> to select libraries Signals3_Serial_Class and LDR_Serial_Sensor_Class.
2. Create an instance/object of each of the types Signals3_Serial_Class and LDR_Serial_Sensor_Class. Use the arguments to define how the parallel to serial and serial to parallel converters are wired to the ESP8266.**
3. In the setup( ) routine add the begin( ) for both the signal and sensor object. Note signal.begin( ) defaults to external gate used (the NOR gate), positive polarity signals (signals are pulled high to activate) and 4 output signals. See Signals3_Serial_Class page.
4. In the loop( ) function s0..s3 are defined as shorthand for sensor.train_over_sensor( ) where train over sensor is a public method from LDR_Serial_Sensor_Class.
5. Also in the loop( ) the method signal.signal_control( ) is used where the first argument is the signal to control and the second the status of the signal.
6. Users will need match all parameters to how the circuit is actually wired. In my case my wiring was a bit random.
The code should compile and run. (Ensure ESP board is selected and correct COM port). Covering an LDR should cause the corresponding signal to go through the RED-AMBER-GREEN sequence.
** The code as given will turn the red LED on immediate a train is detected. When the train is no longer present the red LED will remain on for 5 seconds, the signal will go AMBER for 5 seconds also before returning to GREEN. By digging into the libraries inherited by Signals3_Serial_Class these time can be modified. In the case of my club layout 5 seconds seems appropriate but in the case of my very modest home layout I'm considering reducing these times.
The LEDs are basically just for show. The real object is to capture and display the train state.
Add the following code:
Notes:
1. An enum type where_is_train is defined that includes all the possible train states. A state variable the_train of the type where_is_train is created.
2. In the setup( ) method the train state the_train is initialised to the state waiting. To display the results the serial port is set to 115200 baud.
3. A method train(int s0, int s1, int s2, int s3) of type where_is_train is created. This method tests for the next state only. If the state is waiting then if the train passes over sensor s0 the next state will be coming etc.
4. The program loop calls the method train(int s0, int s1, int s2, int s3) using the current sensor readings.
5. The Serial.write will print out the current state. The +'0' is used to make the states printable. Note the delay is just for convenience while displaying the results.
The serial output will become with the train moving from the state waiting (==0) coming (==1) before returning to the waiting state.:
The program can be upgraded to display the results in the form of text messages. Possible code will be:
Notes:
1. The code basically uses the current state and displays a message.
2. The code will only display changes in the state. The varable save_loc saves the last state displayed. Only if the next state is different is the display updated.
3. The routine includes a watchdog timer to reset the state machine if ever the program gets "stuck" in the same state. It is anticipated that the critical situation might be a spectator shading the "coming" sensor putting the state machine in the first state where it will remain until a train actually comes. For testing the critical time is set to 20 seconds but in practice it could be made much longer. If trains where actually stopping at the state "station" the time needs to be longer than the longest time at the station.
Possible results are shown below:
An example of the watchdog timer in action is shown across. First the "train" is in the approaching state from 19 to 39 seconds so the state is reset to waiting. In the next snippet the "train" is in the state "station" for 20 seconds before being timed out..
The sample code is for trains only going in one direction. The code could be enhanced for trains approaching from both directions**. In the waiting state the design would test for the first and last sensors. Depending upon which sensor is detected the train will move to a state coming0 or coming1 or comingNS/comingSN where NS refer to north/south. Or in railway terminology UP and DOWN where UP refers to trains going to the main city. The messages would need to be enhanced.
Possible code is given in the folder Track_Train_ESP_code. See directive BOTH_WAYS. Possible results for a train going in one direction followed by a second going the other way are:
The print out gives possible results for a train going in one direction followed by a second going the other way,
**In my layout the signals (LEDs) are flat on the layout so there is no issue with them facing in the wrong direction.
The two begin methods in this program have no arguments, they use default values.
sensor.begin( ) has inherited LDR_Sensor_Class where there is a 1 second filter to avoid false exits when the train couplings are above the sensor.
signal.begin( ) assumes the design uses an external gate to generate the AMBER signal (arg0 = 1), the signals are positive polarity (arg1= 1) and there are 4 sets of signals (arg2 = 4).
Also signal instance/object has inherited the Signals3_Class where the default delays are 5 seconds. That is the LEDs remain RED for 5 seconds, then go AMBER for 5 seconds before returning to GREEN.
Programming enthusiasts may wish to delve into the inherited libraries and change these times.
For railway and hardware enthusiasts what might be immediately more useful is to use different arguments with the sensor.begin( ) method^^.
sensor.begin(1,1,4): Default values- the design will operate as given.
sensor.begin(0,1,4): The design does not include external logic to generate the AMBER. Previously the GREEN output was every second pin. It will now be every third pin. Testing using the original circuit will now give GREEN,RED,AMBER,GREEN... Since every signal requires 3 pins two 74HC164s would be required**.
sensor.begin(1,0,4): The design uses negative polarity signals. Testing with the original design the GREEN becomes RED and the RED becomes GREEN. The NOR gate would need to be changed to a NAND to generate an AMBER signal.**++
sensor.begin(1,1,3): The final sensor was ignored.**
^^ Modifying the sensor.begin( ) method will only change the signalling. It will have no impact on the train state or the serial display.
** These were the results observed on the test circuit used in this project.
++The impact on the AMBER LED is not easy to test as the NOR and NAND gate have different wirings so a 1:1 switch is not possible.