Legal Removal Request This form is for reporting content posted on the AB Electronics UK forums that you believe violates your personal legal rights or applicable local laws for your country. Post: IO Pi Plus 2.1 Connections & Testing Part 2 - Design, Electrical Diagram Please realize that I’ve jumped the gun just a bit on this write-up. 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 long as I don’t wear out my welcome with Andrew & friends. Let’s cover: 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) [b]Overall Plan:[/b] 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. There are two power packs, #1 and #2, supplying power to all blocks via two power busses and a common return bus. 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.) [img]/docs/forumpost/20200318a.webp[/img] [b]Power Management (Relay Wiring):[/b] Here are some photos of the output relay boards. There are four 8-relay boards and two 4-relay DPDT boards. [img]/docs/forumpost/20200318b.webp[/img] The wiring diagrams for a single example of each block, and each siding, are shown below. [img]/docs/forumpost/20200318c.webp[/img] [img]/docs/forumpost/20200318d.webp[/img] 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, with electronic modules in each locomotive which 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 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. Here’s a shot of the power management section of the system, with the RasPi on the right. 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. [img]/docs/forumpost/20200318e.webp[/img] Note the heavy use of color-coded wiring. I can’t stress this 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 in this day of 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 ./test2 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 the 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. [pre][code]/* Use this in testing the model railroad wiring */ #include #include #include #include #include #include #include #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 - 0 char ADDRESS21=0x21; // left (main block) two relay cards 17 - 0 char 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 one char on_invert=1;char off_invert=0; // global pin on/off one, zero // setup for kbd input char *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/on char pwr_select_pin; // block pwr pack select (#1 or #2) char block_on_off_pin; // block select off/on char 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 detected void 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); } [/code][/pre] 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 "[pre][code]typedef struct block_structure[/code][/pre]" 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 bus to use, an off/on relay for its track block, and a forward/reverse relay to control polarity. In addition, there are three electrically-controlled sidings which require only one relay to connect to an adjacent track block. 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 bus 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, and 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). NEXT TOPIC: RasPi Graphical Interface Select the country where you are claiming legal rights. Albania Algeria American Samoa Andorra Angola Anguilla Antarctica Antigua and Barbuda Argentina Aruba Australia Austria Bahamas Bahrain Bangladesh Barbados Belarus Belgium Belize Benin Bermuda Bhutan Bolivia Bosnia And Herzegovina Botswana Bouvet Island Brazil British Indian Ocean Territory British Virgin Islands Brunei Bulgaria Burkina Faso Burundi Cambodia Cameroon Canada Canary Islands Cape Verde Cayman Islands Central African Republic Chad Channel Islands Chile Christmas Island Cocos (Keeling) Islands Colombia Comoros Congo Cook Islands Costa Rica Croatia Cuba Cyprus Czech Republic Denmark Djibouti Dominica Dominican Republic East Timor Ecuador Egypt El Salvador Equatorial Guinea Estonia Ethiopia Falkland Islands (Malvinas) Faroe Islands Federated States of Micronesia Fiji Finland France French Guiana French Polynesia French Southern Territories Gabon Gambia Georgia Germany Ghana Gibraltar Greece Greenland Grenada Guadeloupe Guam Guatemala Guyana Haiti Heard Island and McDonald Islands Honduras Hong Kong Hungary Iceland India Indonesia Ireland Israel Italy Jamaica Japan Jordan Kazakhstan Kenya Kiribati Kuwait Kyrgyzstan Laos Latvia Lesotho Liechtenstein Lithuania Luxembourg Macau Macedonia Madagascar Malawi Malaysia Maldives Mali Malta Marshall Islands Martinique Mauritania Mauritius Mayotte Mexico Micronesia, Federated States Of Moldova, Republic Of Monaco Mongolia Montenegro Montserrat Morocco Mozambique Myanmar Namibia Nauru Nepal Netherlands Netherlands Antilles New Caledonia New Zealand Nicaragua Niue Norfolk Island Northern Mariana Islands Norway Oman Palau Panama Papua New Guinea Paraguay Peru Philippines Pitcairn Poland Portugal Puerto Rico Qatar Reunion Romania Russia Rwanda Samoa San Marino Sao Tome and Principe Saudi Arabia Serbia Seychelles Singapore Slovakia Slovenia Solomon Islands South Africa South Georgia and the South Sandwich Islands South Korea Spain Sri Lanka St. Helena St. Kitts and Nevis St. Lucia St. Pierre and Miquelon St. Vincent and the Grenadines Suriname Svalbard and Jan Mayen Islands Swaziland Sweden Switzerland Syria Taiwan Tajikistan Tanzania Thailand Togo Tokelau Tonga Trinidad and Tobago Tunisia Turkey Turkmenistan Turks and Caicos Islands Tuvalu U.S. Virgin Islands Uganda Ukraine United Arab Emirates United Kingdom United States United States Minor Outlying Islands Uruguay Uzbekistan Vanuatu Vatican City Venezuela Vietnam Wallis and Futuna Islands Western Sahara Yemen Yugoslavia Zambia What legal issue or problem do you wish to report? Please select Privacy / Erasure under GDPR Defamation Intellectual Property Hate Speech Other Please enter the following information so we can process your report. Contact Name: Contact Email: Details of complaint: Submit Complaint