Abstract: The Delta Layout project develops the code that takes the inputs from 4 relays that are part of model train points and controls 8 signals that indicate to the model train the status of the track.
Possible Audience: Model railway enthusiasts with some knowledge of C programming who are interested in using the status of points to control signals. The major challenge is probably determining the ouput logic for the signals from the 4 inputs.
Required Hardware: Nano Microcontroller, 4 on-off sensors attached to points and eight 3 phase model railway signals. Three serial to parallel 74HC164chips. (Note switches and leds could be used to simulate the input-output so an actual model train is not essential.). While not essential the test system was expanded to include a 1602 LCD
Software Tools: Arduino IDE
Required Libraries: LCD_1602 if display is to be used.
--------------------------------------
A Model Train Club where I am a member has a "Delta" or "Y" section of tracks as illustrated below.
It is proposed to include signals to indicate the status of the points on the track. Thus, for example signal "A" would indicate to an approaching train, shown by the arrow the status of points 61 and 60. Signal "A" would be RED if point 61 is against the train, it would be GREEN for straight through and AMBER if point 60 is set to turn.
------------------------------------------------------------
The complete layout contains of many sets of points that can be set/cleared from the master controller. In the section of interest, the points are numbered '60', '61' and '63'. (Note point 60 is pysically two points that are electrically linked.) Each point contains a relay with two contracts: one will be closed for the point in the Normal position and Open when in the Reverse or Turn position. These relays will be monitored and used to control the train signals 'A'..'H'.
There are two tracks entering from the right passing an area where there are wheat silos. The tracks then merge before again separating with the top (normal) track going to Hardware Lane while the turn or reverse sends the train to another point where the train goes to either the Ashland Steel Mill or Pommy Land Terminus. With the points numbered '60' linked there will not be any issues with the lower point being incorrectly set. If the train is sent into the curve the second point will let it out.
Trains from Ashland or Pommy Land are able to travel to the Silos or the lower Hardware Lane Track while trains on the lower Hardware Lane track (Also known as the Hardware Lane Sidings) may travel to Ashland or Pommy Land.
The basic operation of the signals will be
GREEN The points ahead are in the straight or normal position.
AMBER The points ahead are in the reverse or turn position.
RED The points ahead are against the train. The train must STOP
There is one complication for signals 'A' and 'B' and that is that there are actually 4 options. At point 63 trains can diverge to go to either Ashland or Pommy Land. To allow for this 4th option an additional signal 'C' is included in the layout. By the same reasoning signal 'H' is necessary to indicate the status of point 61 for trains coming from either Ashland or Pommy Land. **
The layout also contains a broad-gauge track (5'3" full scale) that crosses the standard gauge track as shown. There will be a switch included to give priority to the Broad Gauge trains.
** (i) As given signals 'C' and 'H' would be inside the length of track defined at each end by points 60.
(ii) Not shown on the diagram but well to the left there is a scissor cross over at Hardware Lane. If signals 'F' and 'G' were moved prior to the crossover there would be four options so signals 'C' and 'H' would need to be located outside the track defined by points 60.
------------------------------------------------------------------
As a first pass the signals can be described with the following equations (not verified):
Ag = 61n.60n./BG Aa = 61n.60t./BG Ar = 61t+BG
Bg = 61t.60n./BG Ba = 61t.60t./BG Br = 61n+BG
Cg = 63n Ca = 63t
Dg = 63t.60t./BG Da = 63t.60n./DG Dr = 63n
Eg = 63n.60t./BG Ea = 63n.60n Er = 63t
Fg = 61n.60n./BG Fa = 61t.60n . /BG Fr = 60t+BG
Gg = 60n.63n Ga = 60n.63t Gr = 60t
Hg = 61n./BG Ha = 61t./BG Hr = BG
where signal A is green when point 61 is normal AND point 60 is normal AND not broad gauge. Signal A will be amber when point 61 is normal AND point 60 is turn AND not broad gauge. Signal A is red when point 61 is in the turn position OR the broad gauge is selected
The above equations could be implemented using a truth table or when coding a switch statement. That is:
Sensors Active Signals - only signal "A" shown**
BG 63 61 60
0 0 0 0 = 0 Ar........Bg.........Cr ... etc
0 0 0 1 = 1 Ar
0 0 1 0 = 2 Aa
0 0 1 1 = 3 Ag
0 1 0 0 = 4 Ar
0 1 0 1 = 5 Ar
0 1 1 0 = 6 Aa
0 1 1 1 = 7 Ag
1 0 0 0 = 8 Ar
1 0 0 1 = 9 Ar
1 0 1 0 = 10 Ar
1 0 1 1 = 11 Ar
1 1 0 0 = 12 Ar
1 1 0 1 = 13 Ar
1 1 1 0 = 14 Ar
1 1 1 1 = 15 Ar
As shown whenever the Broad Gauge (BG) sensor is active the A signal will be in the RED state. (States 8 through 15). It will also be RED if point 61 is in the turn position (States 0, 1, 4 & 5). Signal A will be GREEN for. points 60 and 61 in the normal state. (States 3 & 7) while it is AMBER for point 60 normal but 60 in the turn position (States 2 and 6).
** The table defines "1" as the point being in the normal or straight position. However, in retrofitting the wiring under the base board the definitions could be different.
It was proposed that the design proceed in an incremental fashion with the table completed in the field.
-----------------------------------------------------------------
The Basic Micro-controller Hardware
Inspection of the equations gives:
(i) Four inputs wired to the relay on the points 60, 61, 63 and the broad-gauge switch.
(ii) Twenty-three outputs wired to Ag through Hr. This suggests 3 8-bit serial shift registers for the signal interface. **
** There are 23 outputs required (there is no red for signal C) with six outputs that may be wired directly to an input (e.g. Cgreen = 63t ) This leaves 17 outputs to be programmed via computer logic. This is one more line than is available with two shift registers.
----------------------------------------------------------
Having undertaken several previous projects that used the DCC from the tracks as a power supply I felt confident of going straight to a PCB. The basic circuit is shown below where I have used Net Symbols to describe the start/end points of all the tracks. The design package would generate the rat lines.
Using the rat lines as a guide the components were laid out as illustrated with 4 sets of signals on each of the top and bottom edges, the 4 inputs along another edge and the DCC input on the final edge.
-----------------------------------------------
The Starting Code: Reading the sensors.
To develop the actual code the Nano Hardware with 4 inputs will be required**. These 4 inputs are physically wired to a micro-switch that is part of the mechanism that operates the points. In the actual train layout these points are labled 60, 61 and 63. There is a fourth input that will come from a manually controlled switch with label BG.
The first step is to open a new file. Delta_Layout. Note the Arduino IDE will give it the extension *.ino
Initially the code will only read the 4 inputs and display the results using the serial monitor.
Possible code will be:
int points;The code will basically read the 4 inputs and if debugging is enabled write these to the serial monitor++.
A possible response will be:
[ Sensor State =5 Point60 normal Point61 turn Point63 normal BG Inactive.]
If real inputs are available for testing these should be used otherwise it will be necessary to simulate the inputs with switches or jumpers.
The objective here is to make sure the messages are appropriate for the activated signal.
** At this point the NANO will be powered over the USB cable. Except for the four pull up resistors and the 4 two-pin screw terminals there is no need to populate the PCB
++For convenience #define statements are used to define where the sensors are wired - eg the sensor on point P60 is wired to pin A0 etc
An XOR_Mask is included to change the ploarity of selected input bits if required.
-------------------------------------
Once the input signals/patterns are known the next steps are to (i) determine the required outputs and (ii) to use this information to drive the various signals.
Rather than drive the physical signals the serial monitor may be used to develop the circuit logic. The program loop( ) is enhanced with the function work_signals(points);
void loop() {
points = read_points( ); //continuously read
if (points != previous_points) {
previous_points = points;
#if DEBUG
dump_sig(points);
#endif
work_signals(points);
}
}
The full implementation of the function long work_signals(int sig) is given below. work_signals( ) will use the state of all the points and return an unsigned long that represents the status of all signals. There are 8 signals with three options each giving a 24 bit result.
The code should be entered incrementally, and the results tested to see if the code matches the required logic.
One possibility is to enter the code for just the A signal and check for all input combinations.
Thus signal A will be RED when point 61 is in the turn position or the Broad Gauge switch is active. This is represented by ARL - A Red and L for active Low. A is red for 12 combinations. For the remaining 4 states A will be GREEN when point 60 is 1 indicating the train will continue normally (straight). When point 60 is "0" indicating a turn A should be AMBER.
Alternatively all combinations for all the points in the turn state (case 0) can be entered and the logic confirmed.**
unsigned long work_signals(int sig) {
unsigned long the_signals;
//********************************Program Here**************************
switch ( sig) {
case 0 : the_signals = ARL+BAL+CRL+DRL+EGL+FRL+GRL+HGL; break; //BG*,63*,61*,60*
case 1 : the_signals = ARL+BGL+CRL+DRL+EAL+FAL+GGL+HRL; break; //BG*,63*,61*,60
case 2 : the_signals = AAL+BRL+CRL+DRL+EGL+FRL+GRL+HAL; break; //BG*,63*,61,60*
case 3 : the_signals = AGL+BRL+CRL+DRL+EAL+FAL+GAL+HRL; break; //BG*,63*,61,60
//-----------------------------------------------------------------------
case 4 : the_signals = ARL+BAL+CGL+DGL+ERL+FRL+GRL+HGL; break; //BG*,63,61*,60*
case 5 : the_signals = ARL+BGL+CGL+DAL+ERL+FGL+GGL+HRL; break; //BG*,63,61*,60
case 6 : the_signals = AAL+BRL+CGL+DGL+ERL+FRL+GRL+HAL; break; //BG*,63,61,60*
case 7 : the_signals = AGL+BRL+CGL+DAL+ERL+FGL+GAL+HRL;break; //BG*,63,61,60
//------------------------------------------------------------------------------
case 8 : the_signals = ARL+BRL+CRL+DRL+ERL+FRL+GRL+HRL;break; //BG,63*,61*,60*
case 9 : the_signals = ARL+BRL+CRL+DRL+EAL+FAL+GRL+HRL;break; //BG,63*,61*,60
case 10 : the_signals = ARL+BRL+CRL+DRL+ERL+FRL+GRL+HRL; break; //BG,63*,61,60*
case 11 : the_signals = ARL+BRL+CRL+DRL+EAL+FAL+GRL+HRL;break; //BG,63*,61*,60
//--------------------------------------------------------------------------
case 12 : the_signals = ARL+BRL+CRL+DRL+ERL+FRL+GRL+HRL;break; //BG,63,61*,60*
case 13 : the_signals = ARL+BRL+CRL+DAL+ERL+FGL+GRL+HRL; break; //BG,63,61,60
case 14 : the_signals = ARL+BRL+CRL+DRL+ERL+FRL+GRL+HRL; break; //BG,63,61*,60*
case 15 : the_signals = ARL+BRL+CRL+DAL+ERL+FGL+GRL+HRL; ;break; //BG,63,61,60
}
//******************End Program Here Code*************************
return the_signals;
}
All the constants AGL through HRL will need to be defined:
const long HRL = 0x000001;
const long HAL = 0x000002;
const long HGL = 0x000004;
const long GRL = 0x000008;
const long GAL = 0x000010;
const long GGL = 0x000020;
const long FRL = 0x000040;
const long FAL = 0x000080;
const long FGL = 0x000100;
const long ERL = 0x000200;
const long EAL = 0x000400;
const long EGL = 0x000800;
const long DRL = 0x001000;
const long DAL = 0x002000;
const long DGL = 0x004000;
const long CRL = 0x008000;
const long CAL = 0x010000;
const long CGL = 0x020000;
const long BRL = 0x040000;
const long BAL = 0x080000;
const long BGL = 0x100000;
const long ARL = 0x200000;
const long AAL = 0x400000;
const long AGL = 0x800000;
As given AGL is represented by the bit pattern 100,0000,0000,0000,0000,0000, AAL by the pattern 010,0000,0000,0000,0000,0000, ARL 001,0000,0000,0000,0000,0000 etc down to HRL =000,0000,0000,0000,0000,0001.
** Two options - draw up a table with 16 rows but for starters only one column representing the A signal. When verified add the B signal. Alternatively draw up a table with all columns but only one row representing one input combination. When verified add the next row.
------------------------------------
To display the results the following code should be added to the work_signals( ) method.
#if DEBUGThe print_signals( ) function will be:
void print_signals(long int sig){With the previous outputs for the points state a typical serial output will be:
Sensor State = 0 Point60 turn. Point61 turn. Point63 turn. BG Inactive.
Signals State = 2660428 HG GR FR EG DR CR BA AR
---------------------------------------
Once the simulation is operational the code can be enhanced to control the actual signals**
The design consists of 3 74HC164 shifr registers as shown. The steps will be:
1. Pin D2 will be the data and D3 the clock. These must be initialized as outputs as part of the set up routine.
void setup() {2. The desired parameter the_signals as found earlier is passed to a function ripple_out.
void loop() {3. Eash bit is rippled to pin D2 and clocked into the shift registers.
void ripple_out(unsigned long sig) {The final code that includes formatting the debug data to write to the serial monitor will be++
void ripple_out(unsigned long sig) {--------------------------------------------
During the prototyping phase the Broad-Gauge control was set and the output waveforms observed.
As shown as expected there are 24 clock pulses with the third output corresponding to signal A-RED being low.
Note the code only changes the signals when the input state changes. In micro-controller terms this is very infrequent so the 440uS spike when the new values are rippled across will not be noticed.
-----------------------------------------------------------------------
For on the bench testing the value of the points variable may be set and the output status verified with a multimeter.
void loop() {Working through every combination of points (16) a working system may be verified**.
One problem that was found with the final product was that while all the signals were in view of the approaching locos many were not visible to the engineering controlling the train. It was decided to add 2 LCD to facilitate reading the signal status.
** During the testing phase became lazy and added Serial.println( ) statements to every state. This resulted in a compiler warning that I only had 44 bytes left for local variables. Running the program it did not run correctly so the Serial.println( ) s were removed.
-------------------------------------------------
To facilitate reading the status of the track by the engine drivers who were not physically in the locos it was decided to add two LCD displays near signals A/B and F/G. These would give messages such as "GO: Mainline to Pommyland"**
To use the LCD Library, it will be necessary to wire the LCD to pins A4 and A5 and if the messages at A/B and F/G are to be different the LCDs must have different addresses++.
To include two objects of the class LCD_1602 the following three lines should be added to the *.ino code..
#include <LCD_1602.h>The setup( ) function must include code to initialise the lcds and if desired provide some output message
void setup() {One issue is compacting the message in to one line on the lcd display.
Also, while lcd1 and lcd2 could display the same message it was considered to match the display to where the lcds were located. Hence on the top line of the LCD near signals A/B the message is "GO: Main to Pom." where as for lcd2 located near signals F/G the message becomes "GO: Pom. to Main"
Readers should look at the final code for the remaining messages&&.
** Including a LCD at the start of the project may have assisted in the debugging. Also adding a LCD as an afterthought implied a small prototyping board with some wire wrapping needed to be added to the PCB.
++ Many LCDs have the default address 0x27. It will be necessary to use a second LCD where the address can be changed - usually by adding a link across two solder pads. (Adresses in the range 0x20 through 0x27 available)
&& Due to circumstances the Broad Gauge switch was not used. The opportunity was taken to replace it with an input from controller for a scissor cross over approaching Hardware Lane. This did not impact on any of the signalling but it did allow the messages regarding Hardware Land to be broken into two - either the actual Hardware Lane station, known as HW or the Hardware Lane Siding known as Side. However when the scissors were in the cross over position there was the potential for two trains to cross so rather than "GO: Silos to Side" the message became "??: Silos to Side" telling the loco drivers they would need to check before proceeding.
--------------------------------------------