Layout Design

Electrical Design/Connections/Testing

Layout Design, Electrical Design/Connections/Testing

Introduction to Design - Track Plan

...shoulda done this much earlier. You can't really decide such detailed things as how many expansion boards and relays and detectors and other electronics and mechanical details you should order, let alone how to lay them out and mount them, until you have an overall design in mind. It should be good enough that you can write it down and revise it and tweak it until it's workable. Even then, it needs to be flexible enough that you can revise it "on the fly" if necessary. ...and you know how pesky flies can be, right!

So start off with a good track plan, one that you feel like will serve your model railroading desires and ye be expandable. Model railroading tends to be a lifelong hobby, so you want to be able to modify it and add to it from time to time. Otherwise, interest may wane. Consider all sorts of things, beginning with how much space you can negotiate with your spouse for the layout. Worry about such things as what minimum curve radius and maximum vertical incline you can tolerate. Think about such things as what's gone wrong on past layouts. Do you have problems with, for example, "splitting frogs" on turnouts causing derailments, meaning the "frog" (moveable, or "point") portion of the turnout doesn't align properly, so you try to minimize the number of "leading point" turnouts and instead favor "trailing point" installations. "Trailing point" installation is much more forgiving because the locomotives and cars tend to barge on through, forcing the alignment, rather than the wheel-sets dropping onto the ties.

Don't forget to think about how you will access your rolling stock when the inevitable happens and there's a derailment. My wrists still bear the scars of reaching through tunnel portals to retrieve derailed equipment and snagging on stray scenery supporting screen wire, ad yes, I've collapsed layout benchwork while climbing onto it to reach a remote corner. Save yourself lots of headaches (and puncture wounds) by thinking through your track plan first. Buy books and magazines. Cruise the internet. Make friends with locals. Visit club layouts and model train swap meets, then think about how you would downsize what you saw. These folks, too, suffer just as badly from from delusions of grandeur as you do.

Draw your layout first, then build benchwork, then install roadbed and track. (...sounds quick-and-easy, right? Yeah. Right.) Hook it up with as simple electrical wiring as possible, then run a few trains to make sure the trackwork is smooth and correct and everything works properly.

It won't, of course. Work on the inevitable rough spots and derailment causes. Correct inclines if you have 'em- - inevitably they're too steep and the transitions into and out of them are too sudden.

Make sure you have well-reasoned block gaps. I've tried installing plastic rail joiners as I lay track, but with mixed success. Nowadays, I solder all my rail joints and file or grind the joints level. Then, I cut gaps between blocks with a razor saw and fill the gap with epoxy or, yes, even wood glue. I lay all my track on cork roadbed glued to the sub-roadbed. Instead of using track nails, which invariably split the plastic ties on my N-scale layout, I lay a minimal seam of wood glue down the cork roadbed beneath the track. This can be done before or after the track is in place, so for example, if you have to saw out a section of bad track and replace it, you can install it, solder it in place, then run a seam down the center of the track. Needless to say, keep it small so you don't get any on the rails themselves, and don't do it within turnouts, but otherwise, go ahead. You can install granular ballast later. You'll be doing that with diluted glue, anyway, so what's the big deal? There'll be less noise because the track will be tied to the cork, not the sub-roadbed, so you won't have a sounding board for a layout.

IO Pi Plus 2.1 Electrical Design, Connections & Testing

Please realize that I’ve jumped the gun just a bit on this writeup. I had a layout in mind, and drew it up. I planned out the track electrical blocks. I built the benchwork, installed the track, and got a minimal electrical system running. Then, I "noodled" what I wanted in a control system.

The Raspberry Pi hardware and AB Electronics expansion boards were obvious choices for what I wanted to do, so I bought ‘em! Right away, though, I needed some C code. Once my two IO Pi Plus 2.1 32-channel digital expansion HATs for Raspberry Pi were assembled, visually checked out, and fired up, it was time to wire up the relay boards and test them. First, though, I needed a formalized plan. I hope to present it to you here as well as on the AB Electronics website, as long as I don’t wear out my welcome with Andrew & friends. Let’s cover, at least:

      • Overall Plan

      • Power Management (Relay Wiring)

      • RasPi Graphical Interface

      • Position Detection (hopefully with interrupts)

      • Smart Power Management System (AI Expert System)

      • Speed/Power Indication

      • Motor Regulation

      • Turnout Position Indication/Operation (manual vs. motorized)

Overall Plan:

For the overall plan, I hope to operate and regulate as much of the model railroad as makes sense, whatever that is. There will be compromises, so don’t expect the complete thing described above to actually come to fruition. I was involved my entire working career with chemical plant automation, though, so I like to think I can scale things to the proper level. (…to be seen!)

Here’s a layout diagram. (I’ve since added some additional sidings.) There are two power packs, #1 and #2, supplying power to all blocks via two power busses and a common return buss. The current from each of them is switched off or on with a single pole double throw (SPDT) relay. The layout trackage is divided into eight main electrical blocks numbered 00 through 07, each of which needs its own power controls. These controls consist of, for each block, an SPDT relay connection to either one of two power supply packs, an SPDT off/on relay switch, and a double pole, double throw (DPDT) forward/reverse directional control relay. In addition there are three sidings, numbered 08 through 10. These sidings need only be connected to their adjacent blocks via an SPDT relay, which simplifies wiring considerably. (One rail is soldered to the main block, and the other is connected to its corresponding rail via a single SPDT relay.)

Power Management (Relay Wiring):

Photos of the output relay boards were shown above.. There are four 8-relay boards and two 4-relay DPDT boards.

The wiring diagrams for a single example of each block, and each siding, are shown below.

I wired up the power control relays, which is to say, the output relays, as described in my earlier post. Next, it was time to wire up the power side of the relays, the part that hooks to the model railroad. To do so, I needed a block diagram of the layout, plus electrical diagrams of the necessary wiring (see above).

A side note, here: the last fifteen years or so have seen a shift from old-fashioned track electrical blocks operating DC motors to so-called Digi-Trax equipment supplying voltage to the whole layout

Electronic modules in each locomotive convert the power to the desired DC polarity and voltage as controlled by a digitally encoded signal superimposed on the power. These things cost $200 plus for the layout, plus an electronic decoder module ($50 ?) in each locomotive. This gets pricey, fast. Add in the fact that I’m getting older and reluctant to change, and oh yeah, cheap, I decided to stick with what I knew. Yeah, laugh if you will. I’d rather spend my time and money on the computer control end of the hobby, anyway.

So, without further ado, let’s lay out the design and then take a plunge into power system. Below is a shot of the power management section of the system, with the RasPi on the right, standing on its end. The double-decker SPST relays are center, the DPDT relays are on the left, and a double-decker pair of SPDT relay boards for the main power pack off/on relays and siding power connections are at the rear.

Note the heavy use of color-coded wiring. (Sorry- - it’s a bit hard to see, here.) I can’t stress color coding enough. I learned the hard way that everything electrical must be triple-checked or you risk burning out components or entire boards. This is especially important with today’s integrated circuits.

You can run through the test program from my previous post, just to make sure that the relays all work via the RasPi. However, to test the power side of the circuitry, you’ll need a bit more elaborate programming. This time, you’ll impose a voltage across one or both power pack supply wiring. This is easily done, at this stage, with wired alligator test clips and a battery holder. Put in a temporary jumper to supply voltage to both power Pack supply leads.

Then, for the testing regimen, you’ll need to, first,

  • turn on main power pack supply #1 and make sure you can detect the voltage on the power pack buss. Then, turn on #2 and check it.

  • Next, check the outlet voltage from the block power pack selection relay, which should default to pack #1. Activate it to check that pack #2 can be selected.

  • Then turn on the block power off/on relay, which defaulted off, and make sure that it passes current.

  • Then check the voltage on the DPDT forward/reverse relay, to make sure the polarity is correct. Then, activate that relay and check that the polarity reverses.

I’ve mentioned before that the folks at AB Electronics have provided some great code for testing. I’ve cobbled together some code based on theirs that allows you to test the power side of the relays as described above. It’s fairly flexible, allowing you to turn on the relays as described, working your way block-by-block. My modified code follows, with apologies to the AB-E folks. As before, make sure you have copied files ABE_IoPi.c and ABE_IoPi.h into the same directory as your test code, which I’ve named IO_Pi_test2.c which follows below.

Be sure you have made the change in ABE_IoPi.c described in my previous post. Assume your code is named IO_Pi_test2.c in which case you’ll need to build your code with the following line:

gcc ABE_IoPi.c IO_Pi_test2.c -o test2

then run with


My approach deals with the fact that we have eight sets of four relays in series, and that testing them one-by-one would involve an inordinate amount of repetitive work. The code I’ve provided works its way through each set of relays, allowing you to logically find short circuits or open circuits. This cuts the amount of work considerably.

Here’s a recent version of the C test code, IO_Pi_test2.c. A few quirks should be mentioned, as discussed in comments below. You’ll need to do some code modifications to adapt the code to your own needs, of course. I include it here only as an example of what to do for similar applications.

/* Use this in testing the model railroad wiring */#include "ABE_IoPi.h"#include "ABE_I2CSwitch.h"typedef struct block_structure // pin nmbrs are octal{ int block_no[11]; //except this one char pwr_select_pin[11]; char block_on_off_pin[11]; char block_fwd_rev_pin[11]; char siding_on_off_pin[11];} block_structure; block_structure block_relay = // pin nmbrs are octal{ .block_no ={0,1,2,3,4,5,6,7,8,9,10}, //except this one .pwr_select_pin = {01,03,05,07,011,013,015,017,00,00,00}, .block_on_off_pin = {00,02,04,06,010,012,014,016,00,00,00}, .block_fwd_rev_pin = {07,06,05,04,03,02,01,00,010,010,010}, .siding_on_off_pin = {017,017,017,017,017,017,017,017,015,014,013}}; // Specify which i2c addresses to use.// For two IO PI Plus 2.1 cards, the following four addresses are hard-wired.// They can be char (octal) numbers, although specified as hexadecimal.// For two IO PI Plus 2.1 cards, the following four addresses are// hard-wired.char ADDRESS20=0x20; // right (aux) two relay cards 17 - 0char ADDRESS21=0x21; // left (main block) two relay cards 17 - 0char ADDRESS22=0x22; // fwd/rev relays 7 thru 0 (invert required)char ADDRESS23=0x23; // detectors char on=0;char off=1; // global pin on/off zero or onechar on_invert=1;char off_invert=0; // global pin on/off one, zero // setup for kbd inputchar *buffer;size_t bufsize = 32;size_t characters; // SPECIFY BLOCK (RELAYS) TO TEST (pin nmbrs are octal)char main_pwr_pin=017; // main pwr pack #1 off/onchar pwr_select_pin; // block pwr pack select (#1 or #2)char block_on_off_pin; // block select off/onchar block_fwd_rev_pin; // block select fwd/rev void turn_off_all_test_relays(){// turn test relays off: PROGRAM END// all main power packs off, all block power packs= 1,// all blocks on/off = off, all block directions fwd// all detectors???// right (aux) two relay cards 17 – 0 (main power packs off/on, sidings) write_pin(ADDRESS20,016,off); write_pin(ADDRESS20,017,off);// left (main blocks) two relay cards 17 – 0 (block pack selection, off/on) write_pin(ADDRESS21,pwr_select_pin,off); write_pin(ADDRESS21,block_on_off_pin,off);// mid left (main blocks) fwd/rev relays 7 thru 0 (fwd/rev direction, invert required) write_pin(ADDRESS22,block_fwd_rev_pin,off_invert);// far left (main block gaps) detectors SHOULD THE FOLLOWING BE INVERTED???// write_pin(ADDRESS23,detect_pin,off_invert);} int turn_on_one_relay_set(){ printf("Turning ON designated relays one at a time.\n Activates next pin after keypress.\n"); // Print which pin function, output the print line to // stdout (display) buffer, flush it to display on-screen, // write to pin, then wait for key before next pin. // LOW level triggers SPDT relays on; HIGH triggers DPDT relays on. int index; char dummy[2]; dummy[0]=0;if(dummy[0]==0)dummy[0]=0; // so compiler won't complain // // Note that all pin numbers are octal (preceding 0 character). // Select block to test printf("Enter block number to test (block 0 - 11),\n"); printf("\r -1 to toggle main power, 99 or c to quit "); // main_pwr_pin defaulted to pwr pack #1 above index=000; // default block characters = getline(&buffer,&bufsize,stdin); index=atoi(buffer); if(index==-1) { write_pin(ADDRESS20,main_pwr_pin,off); if(main_pwr_pin==017) {main_pwr_pin=016;} else {main_pwr_pin=017;} printf("main power toggled to pin %o\n",main_pwr_pin); return(0); } // block_relay.pwr_select_pin[index]; // main pwr pack #1 off/on selected above pwr_select_pin=block_relay.pwr_select_pin[index]; // block pwr pack select (#1 or #2) block_on_off_pin=block_relay.block_on_off_pin[index]; // block select off/on block_fwd_rev_pin=block_relay.block_fwd_rev_pin[index]; // block select fwd/rev if((index<0)||(index>11)) {printf("Exiting %i\n",index); return(1); }// turn on power supply main switch// right (aux) two relay cards 17 – 0 (main power packs off/on, sidings) write_pin(ADDRESS20,main_pwr_pin,off); printf("\rMain pwr ");fflush(stdout);write_pin(ADDRESS20,main_pwr_pin,on); dummy[0]=getchar(); // write_pin(ADDRESS,i,off);// turn on block power pack selection switch// left (main blocks) two relay cards 17 – 0 (block pack selection, off/on) write_pin(ADDRESS22,pwr_select_pin,off_invert); printf("\rPwr select");fflush(stdout);write_pin(ADDRESS21,pwr_select_pin,on); dummy[0]=getchar(); // write_pin(ADDRESS,i,off);// turn on block off/on switch// left (main blocks) two relay cards 17 – 0 (block pack selection, off/on) write_pin(ADDRESS22,block_on_off_pin,off_invert); printf("\rBlock off/on");fflush(stdout);write_pin(ADDRESS21,block_on_off_pin,on); dummy[0]=getchar(); // write_pin(ADDRESS,i,off);// turn on block fwd/rev switch// mid left (main blocks) fwd/rev relays 7 thru 0 (fwd/rev direction, invert required) write_pin(ADDRESS22,block_fwd_rev_pin,off_invert); printf("\rBlock fwd/rev"); fflush(stdout);write_pin(ADDRESS22,block_fwd_rev_pin,on_invert); dummy[0]=getchar(); // write_pin(ADDRESS,i,off); printf("ON test complete. Turning relays off.\n"); turn_off_all_test_relays(); return(0);} void turn_all_relays_off(){ for(char i=017;((i>=000)&&(i<=017));i--)write_pin(ADDRESS20,i,off); for(char i=017;((i>=000)&&(i<=017));i--)write_pin(ADDRESS21,i,off); for(char i=007;((i>=000)&&(i<=007));i--)write_pin(ADDRESS22,i,off_invert);// for(char i=017;((i>=000)&&(i<=017));i--)write_pin(ADDRESS23,i,off);} void map_pins_to_blocks(){ // initialize pin-block mapping//#define ADDRESS20 0x20 // right (aux) two relay cards 17 – 0// (main power packs off/on, sidings) IOPi_init(ADDRESS20); // initialize io pi channel on i2c set_port_direction(ADDRESS20, 0, 000); // set bus 0 to be outputs set_port_direction(ADDRESS20, 1, 000); // set bus 1 to be outputs//#define ADDRESS21 0x21 // left (main blocks) two relay cards 17 – 0// (block pack selection, off/on) IOPi_init(ADDRESS21); // initialize io pi channel on i2c set_port_direction(ADDRESS21, 0, 000); // set bus 0 to be outputs set_port_direction(ADDRESS21, 1, 000); // set bus 1 to be outputs//#define ADDRESS22 0x22 // mid left (main blocks) fwd/rev relays 7 thru 0// (fwd/rev direction, invert required) IOPi_init(ADDRESS22); // initialize io pi channel on i2c set_port_direction(ADDRESS22, 0, 000); // set bus 0 to be outputs set_port_direction(ADDRESS22, 1, 000); // set bus 1 to be outputs//#define ADDRESS23 0x23 // far left (main block gaps) detectors IOPi_init(ADDRESS23); // initialize io pi channel on i2c set_port_direction(ADDRESS23, 0, 001); // set bus 0 to be INputs set_port_direction(ADDRESS23, 1, 001); // set bus 1 to be INputs} // Callback handler. Shut down test if CTRL-C signal is detectedvoid my_handler(int s){ printf("\nDetected CTRL-C signal. Exiting. \n"); turn_all_relays_off(); // reset to OFF. exit(0);} int main(int argc, char **argv){ // Register callback function for CTRL-C signal(SIGINT, my_handler); // set up stdin for kbd input buffer = (char *)malloc(bufsize * sizeof(char)); if( buffer == NULL) {printf("Unable to allocate kbd buffer\n");exit(1);} printf("Initializing i2c addresses.\n");// ADDRESS is defined in the following map_pins_to_blocks(); printf("Press Ctrl-C to exit.\n"); turn_all_relays_off(); // initialize while(turn_on_one_relay_set()==0); // run until user signals exit return (0);}

As to adaptations, specifically, the electrical needs of my model railroad dictated that I build in data describing how the relays are grouped, so-called track blocks, for testing purposes. This is done with the "typedef struct block_struct" statements. Each of the eight track block groupings needs access to both main power pack off/on switches, to provide current to the two power busses. Then, each grouping requires a relay for selecting which power pack buss to use, an off/on relay for its track block, and a forward/reverse relay to control polarity. In addition, there were three electrically-controlled sidings which require only one relay to connect to an adjacent track block. (I've since added three more.)

You’ll have to completely re-think this data portion of the code, grouping relays so as to fit your needs and expedite testing. To be honest, this code will not be needed once testing is complete, but it sure is handy when you have a network of interacting relays that need to be checked.

As you work your way through testing your equipment, take a multimeter and check that voltages and polarities are correct, one relay at a time. You’ll need to cycle through all blocks 00 through 07, to make sure there are no short circuits or open circuits, then check sidings 08, 09, and 10. My apologies for using decimal numbering for the blocks here, seeing as how the IO Pi equipment selects data buss addresses in hexadecimal but pin numbers in octal. Be very careful as you adapt the code to your needs. If things don’t work the way you expect, check to see that you specified your numbers in the correct notation, 0x1234 (leading 0x) for hexadecimal, 01234 (leading zero) for octal, nothing special for decimal. Most numerical values are passed as type char, which in the Raspberry Pi Linux world can range from 0 to 255, and are very forgiving (not strictly type-checked, it seems).

Click here to see details of the power wiring for both the main track blocks and the sidings.


19/03/2020 Posted by: el Ducko Location: Texas, USA

Here's a quick word about polarity. You'd like to have your railroad configured such that trains run forward when the relays are in default (off) mode. What you should do is decide whether you prefer left-hand running or right-hand running (assuming parallel double tracks), then hook up the power wires such that the locomotive defaults to running that way. If it doesn't, swap the two power leads, either at the track or at the DPDT fwd/rev relay terminals. Check this constantly as you connect up your wiring, so that your trains will smoothly go from one track electrical block to the next without interruption. If you don't have it wired correctly, the power pickups on the locomotive will form a short circuit when the locomotive goes from one electrical block to the next, and the train will, at best, stop. At worst, if there's no circuit breaker in your power pack, you can have a fire. (Voice of experience: usually what happens with no circuit breaker is that the insulation melts off the wiring and ruins it.)

I'll mention in passing that there are nasty things called "reversing loops" which complicate wiring. Having a loop of track double back on itself forms a short circuit through the rails, unless you take some special precautions (such as rail electrical gaps and a strategically-positioned isolated track power block.) It's simple to handle, but I'll avoid discussing that for the moment. If you are interested, please read on. There's a description of the problem and its operating solution much later, and the track block in question is named "BLOCK_07" as it connects back to block 05 through a crossover pair of turnouts. ...but you'll see.

Color Coded Wiring

As to color coding, I'm fortunate in that, being a pack rat, I've collected wiring over the years. Thirty-some-odd years ago, I cleaned a bunch of 50-conductor color-coded cable out of my wife's new offices during a relocation. It lives on in my model railroading! Things are much easier to troubleshoot when your wiring is color coded.

Computer geek since 1964. Upgraded to FORTRAN66 back in the day. Downhill ever since.

NEXT TOPIC: RasPi Graphical Interface