Installing the Detector Boards
Buying the Boards - Summary
I bought some detector boards that, typical of model railroading electrical practice, operate at 12 volts. RasPi takes 5 volt input signals, so it was necessary to buy voltage converter boards. I'm not very good at electronics, so I bought them instead of designing and building them from scratch. The voltage converters weren't that expensive, and gave the advantage of providing optical isolation (en lieu of direct connections). I got some programming advice from Andrew at AB-Electronics, and on his advice, added some 10-k ohm current-limiting resistors. Please read on for details.
Details
I bought the detectors from Rob Paisley, who shipped them promptly. He provided several pages of schematics and advice via his website, http://www.circuitous.ca/8PhotoInverting.html , which is highly detailed and offers quite a few installation and operating tips. A total of 16 positions were needed, one at the end of each electrical (track) block plus a few for crossovers and sidings and such. I thought that just using these boards and tying them to two of the 8-bit i2C channels via the Raspberry Pi expansion board would be sufficient. I mounted them on my plastic mounting board. Then, it dawned on me that the detector boards work on 12 volts DC and the Raspberry Pi runs on 5 volts DC. Having fried a couple of printed circuit boards already, I wanted to take no chances.
So I bought two voltage converters on Amazon. They are "ICStation 12V to 5V 8 channel Optocoupler Isolation Board Voltage Level Translator Modules, part # 11590." They sold for $10.59 USD. I bought another small food-grade plastic kitchen cutting board, mounted the detectors on one side and the voltage converters on the other, wired it all up, and mounted it on its end. (Real estate is always tight, despite planning otherwise. A link to a picture follows, below.)
Please bear with me while I cut-and-paste a bit of writing from the introductory page. Having hooked the detector boards all up, I plugged the 12 volt power supply in to activate them and tested one of the circuits. It didn't work, until I realized that the opto-transistors had to be mounted properly. Seeing as how they detect infrared light, covering them with fingers made them keep on conducting. Duh! So I went ahead and installed the opto-transistors, drilling 3/16" holes through the roadbed at block boundaries, and wired 'em up. I tested a couple of them by wiring up a resistor and a spare LED. ...good so far.
Next, I powered up the voltage converter boards. The little green LEDs lit, signifying power. Of course, not all of the detectors worked at first. There were a number of loose wires and poor connections, the curse of having screw terminal hardware connections. Once I got them straightened out, no problem. I hand-pushed a railroad car about the layout, obscuring the opto-transistors one at a time, and test-lit the LEDs on the voltage converters, showing that I was finally good to go. The sun set about that time, it got dark in my train room/workshop, and Wow! ...impressive! They ALL came on, both the detector side and the output side. I powered down, plugged up the 20-pin connector to the RasPi expansion board, and powered it back on.
..."crickets," as the show biz people say. The output LEDs stayed dark. "WTF?" as my grand-kids say when the grownups aren't around. I fiddled with 'em for a few days, ran out of ideas, and posted my trials, tribulations, and a few code snippets on AB-Electronics community board. Good ol' Andrew responded next morning. As it turns out, the i2C activation is done bit-wise. For my setup, I needed the following initialization code. (NOTE that the 3rd argument is a one-byte value which turns on all 8 detector circuits, and of course I have 16):
IOPi_init(ADDRESS23); // initialize IO Pi channel 23 on i2C
set_port_direction(ADDRESS23, 0, 0xFF); // set bus 0 to be all INputs
set_port_direction(ADDRESS23, 1, 0xFF); // set bus 1 to be all INputs
Andrew of AB-Electronics advised that I insert current-limiting resistors between converter boards and the IO PI Expansion Boards. The local electronic parts store was out of the recommended 10 k-ohm resistors, so I substituted 8.2 k-ohm ones and installed mechanical connectors to tie down the little guys. I was nearly out of mounting board "real estate," but got it all to fit.
Now for the detector system electrical diagram. Also, here's a picture of what the board installation looks like.
You'll need a program to test that the signals get through to RasPi. Here's mine.
/* Position Detector Test Program */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <wiringPi.h>
#include <signal.h>
#include <linux/i2c-dev.h>
#include "ABE_IoPi.h"
#include "ABE_I2CSwitch.h"
// MAX_DETECTORS is the number of detectors, 8/card x 2 cards
#define MAX_DETECTORS 16
int counter;
typedef struct block_structure // pin nmbrs are octal
{ int pos_no[MAX_DETECTORS+1]; //except this one
char occupied_pin_no[MAX_DETECTORS+1];
} block_structure;
block_structure block_relay = // pin nmbrs are octal
{ .pos_no ={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}, //except this one
.occupied_pin_no = {00,01,02,03,04,05,06,07,010,011,012,013,014,015,016,017}
};
// 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
int turn_on_all_detectors()
{ printf("Reading all positions.\n");
// Print which pin function, output the print line to
char occ_value[MAX_DETECTORS];
int i;
counter+=1; // increment
for(i=0;i<=9;i++){printf(" %i",i);};
for(i=10;i<MAX_DETECTORS;i++){printf(" %i",i);}
printf("\n");
for(i=0;i<MAX_DETECTORS;i++)
{ occ_value[i]=read_pin(ADDRESS23,block_relay.occupied_pin_no[i]);
printf(" %i",occ_value[i]);
}
printf(" %i\n",counter);
printf("Test pass complete.\n");
delay(2000);
return(0);
}
void map_pins_to_blocks()
{ // initialize pin-block mapping
// The third parameter for set_port_direction() needs a single byte
// number between 0 and 255 or 0x00 and 0xFF. Each pin can be set as
// an input or output based on the value of the corresponding bit
// within the byte so for example to set pins 3 and 5 as inputs and
// the other pins as outputs you would use a value of 0b00010100 in
// binary, 20 in decimal or 0x14 in hexadecimal.
IOPi_init(ADDRESS23); // initialize io pi channel on i2c
set_port_direction(ADDRESS23, 0, 0xFF); // set bus 0 to be all INputs
set_port_direction(ADDRESS23, 1, 0xFF); // set bus 1 to be all 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_off_all_detectors(); // reset to OFF.
exit(0);
}
int main(int argc, char *argv[])
{ // Register callback function for CTRL-C
signal(SIGINT, my_handler);
printf("Initializing i2c addresses.\n");
counter=1;
printf("Press Ctrl-C to exit.\n");
// ADDRESS is defined in the following
map_pins_to_blocks();
printf("Press Ctrl-C to exit.\n");
while(turn_on_all_detectors()==0); // run until user signals exit
return (0);
}
The code above initializes the IO Pi input card i2C channels, then loops to print out either a "0" for no input or a "1" for signal detected. I suggest you run it and obscure each photo-transistor in turn, verifying that the selected detector and its associated input signal works successfully. Then comes a fun test- - darken the room (after sunset with the lights off is a great way to do this) and see if everything turns on, all together. (Sometimes you gotta show off! The LEDs are impressive.)
What Could Possibly Go Wrong?
Fortunately, if you've gotten this far, you've blundered into enough problems and fixed them that what you'll find here isn't new. ...mostly. "Trust me." Here are a few symptoms and solutions, however.
It just won't go! Make sure that you are supplying the correct voltage and polarity to the boards. You need 12 volts for the detectors and 5 volts for the voltage converters. Don't hook the polarities up wrong, or you'll fry the boards. (My track record is not great. Be careful.)
Opto-transistors don't detect. Rob Paisley's writeups on his website are quite good. Review them to make sure everything is installed and powered correctly. The boards should work as supplied (mine did). If they don't, try hooking up an LED to read detector output, and fiddle with the opto-transistor position until it works correctly. Rob suggests installing the things in 3/16" holes below the roadbed, where a model freight car or the like will reduce light level enough to activate the circuit. You may have to adjust the position of the thing up or down a little. Heed my caution about trying to block light with your fingers. They give off infrared light, and will interfere with opto operation.
The expected LED doesn't turn on. Chances are good that there's an open circuit. Check your wiring. Places prone to error include a bad wire connection to the layout, a bad connection in one that pesky screw terminal hardware, and if nothing turns on, a wiring fault in the power supply to the cards. Dn't forget to turn the power on! (How many times have I done that?) A suggestion: using a power strip for the "whole shootin' match" really helps.
Unexpected LEDs turn on. Carefully document what's hooked up to what. It is easy to expect one detector to fire and actually fire a different one. I recommend drawing a diagram, similar to what I attached, to keep track of it all. Libre Office provides excellent tools.
One or more voltage converter output LEDs remain(s) dark. This may well be a programming error. Be sure to specify that the signal is input, and that all 8 signals in the channel are activated (0xFF for you hexadecimal fans).