AC Track Powered Trolley

Revised 11-13-08

A trolley will operate on a point-to-point layout using track power.  This track power will be a continuous AC voltage that will power the motor, on-board electronics and lights.

The constant voltage that will be available to the trolley through the track will help to insure that its lights will remain on at all times.  In addition the relatively high AC track voltage should help keep the train running even as the track becomes dirty.

The on-board electronic controller will accelerate the motor, sense when the train enters a section of cut track and bring the train to a stop.  After pausing the motor will reverse and the operation will repeat.

Programming of the microcontroller will be via a standard TV remote control using Sony codes.  Program changes include setting the maximum motor speed, the length of delay at each end of the point-to-point and the acceleration / deceleration rate.  Once set these changes will be remembered even after power is removed.

At the end of each "lap" the controller will flash out, by means of three LEDs, the number of "laps" that have been completed.  The time that it takes to flash out this information will be automatically deducted from the pause time.

Other options will include sounding a bell each time the trolley stops and activating an audio track as the trolley stops.

Update for 2008

The two trolleys that were built using the AC track power system worked very well for the 2007 Christmas season.  This year the circuit has been revised to make use of an inexpensive MRC AD322 DCC controller with sound capability.

This microcontroller chip that normally detects and acts upon DCC commands has been removed and replaced by a PIC 16F88 that runs the same program that was used in 2007.  The reason for using the new board is to make the system more compact by using AD322 board which contains the bridge rectifier, relay, power transistor, sound circuit, and audio amplifier.

All that needs to be added is the PIC microcontroller and the optoisolator.  This is done without a circuit board utilizing what is commonly called "dead bug" wiring.  The reason for this is sure to be clear from the photos below.

Full Schematic

The schematic shows the parts of the system. 

2007

2008

Track preparation

In order for the on-board microcontroller to sense when it gets to the end of the track diodes are inserted in cut rails as in the drawing below.  Note that the diodes are oriented differently from those that are used with DC operated point-to-point reversing systems.  Both diodes have their banded (cathode) ends pointing towards the end of the track.

The power for the system is 12-24 volts AC which is connected to the center section of track, between the cuts.

Converting AC to DC - these items are on the AD322 board that is used on the 2008 version

The trolley's motor and the electronics that operate it run on direct current.  The parts of the circuit below take the AC from the track and deliver it to the bridge rectifier made up of four diodes.  This device converts the AC to DC which is filtered and smoothed by capacitor C2.  The LM78L05 voltage regulator supplies a constant 5 volt power output that is used by the microcontroller.  If you have a particularly "noisy" motor in your trolley you can use a larger value capacitor for C2.

Input / Output / Control - the relay and power transistor are on the AD322 board on the 2008 version

Microcontroller PIC16F88 is connected to Q1 and Q2 which operate the relay and control the motor's speed with PWM pulses.  The controller uses 4 LEDs (D1 through D4) to flash out information including delay time and laps completed.

Part number PNA4602M is an infrared receiver which allows the program's operation to be modified with a standard TV remote control.

 

On-board controller - Relay section (not used in 2008 version as the relay is on the AD322)

The motor (M) is connected to a double-pole double-throw relay.  When the relay is off the motor runs in one direction.  When the relay is on the polarity of the voltage is reversed and the motor runs in the other direction.  Transistor Q2 is used to switch the relay on or off.

Mosfet Q1 uses PWM (Pulse Width Modulation) to control the speed of the motor.

Sensing cut track

The last connection to the microcontroller is from an optoisolator.  This device, composed of an encased LED and light sensor, is used to determine when the engine has entered one of the cut sections of track.  When the train is in the non-cut area the LED in the optoisolator is lit sees full-wave AC and the emitter is "on".  When a cut section is encountered the AC becomes half-wave, the LED goes out and the microcontroller knows to decelerate the motor stopping the trolley.  Capacitor C1 is used to smooth out the pulse from the optoisolator that is created when the diode cut section is encountered.  The connections MUST be made as shown here or the optoisolator will not successfully note entry into the diode block at each end of the track!

 

 

 

Operation

Place the trolley in the center area of the track and apply AC power to the track.

The default speed, pause time and acceleration / deceleration rate are in effect when the unit is first operated.  The engine will proceed in one direction until it encounters a cut section of track where it will smoothly decelerate, pause, flash out the number of laps completed, reverse direction and accelerate back onto the main track.

During the train's cruising phase, that is when it is not accelerating, decelerating or pausing, the TV remote can be used to change settings.  Aim the remote at the engine and press the ENTER button.  The train should stop awaiting commands. 

To set speed press the "1" key on the remote - the unit flashes the white LED once - next enter the maximum speed between 0 and 255.  If a number above 255 is entered it will be ignored.  Note that a number must be 3 digits.  Enter 090 for 90,  

To set pause time press the "2" key on the remote -  the unit flashes the white LED twice - next enter the pause time in seconds between 0 and 255.  Note that a number must be 3 digits.  Enter 005 for 5 seconds.  Enter 090 for 90 seconds and so on.

To set the acceleration / deceleration rate press the "3" key on the remote - the unit flashes the white LED three times - enter a 3 digit number that determines the rate of acceleration.  1 gives the slowest acceleration while a higher number (anything over 20 or 30) gives almost instant speed changes.

 

Software - 2007 version

 

'11-22-07 based on 16F684 code - revised for 16F88
'To use - right arrow (vol+) to set speed then
'hit ENTER - all will stop - 3 digit time (roughly 1/10 seconds)

DEFINE DEBUG_REG PORTA
DEFINE DEBUG_BIT 2 ' PIN 1 on 16f88
DEFINE DEBUG_BAUD 9600
DEFINE DEBUG_MODE 1 ' Set Debug mode: 0 = true, 1 = inverted

'define PULSIN_MAX 555
' @ DEVICE PIC16F88, INTRC_OSC_NOCLKOUT, WDT_OFF, LVP_OFF, PWRT_ON, PROTECT_OFF, BOD_ON, MCLR_OFF
DEFINE OSC 8
OSCCON = $70 'dec 112 binary 11100000 = 8mhz

'NOTE - at $70 (8mhz) must double ms on GETIR routines to 400 & 200

'OSCCON = %01100111 '=103 dec / 67 hex 'MUST BE USED to set clock speed=4mhz
cmcon=7 'allows you to use pins as digital rather than analog
ansel=0 'allows you to use pins as digital rather than analog

Include "modedefs.bas"
relay var portb.3 'relay to control direction pin 9
loop var byte
temp var word
temp1 var word
temp2 var word
LEDTemp1 var byte
LEDTemp2 var byte
LEDTemp3 var byte
laps var byte
TempByte var byte
digit var byte
rndYN var byte
PauseByte var byte 'pause at end of run in seconds
SavePause var byte 'temp variable to store value while working
SaveADRate var byte 'temp variable to store value while working
SaveSpeed var byte 'temp variable to store value while working
PauseByte2 var byte
DigitsByte var byte 'temp for getting digit input
DigitType var byte '1 =speed, 2=pause, 3=ADRate
ADRate var byte 'accel / decel rate - large # is fast rate
TempWord var word
TempWord2 var word
TempWord3 var word
value var byte
TIP101 con 2 'pin 6 for PWM
ForwardFlag var bit
InBlockFlag var bit '0 if on mainline / 1 if in block
LEDGreen var portb.6 'pin 12
LEDYellow var portb.7 'pin 13
LEDRed var portb.5 'pin 11
LEDWhite var portb.4 'pin 10
BlockSense var porta.3 'pin 2 high when on mainline/low with diode
zero con 136
one con 128
two con 129
three con 130
four con 131
five con 132
six con 133
seven con 134
eight con 135
nine con 136
channelUP con 144
channelDOWN con 145
volumeUP con 146
volumeDOWN con 147
OK con 148
Menu con 224
ENTER con 139
Power con 149
TVVCR con 165
Speed var byte
IRpulse_length var word(13)
xx var Byte
Command Var Byte
IRin var porta.1 'pin 18
ansel = 0
'cmcon0 = 7

serial_out var porta.2
trisa.1=1 'IR sensor
trisa.2=0 'debug an output
trisb.3=0 'make relay pin an output
trisb.4=0 'make led output
trisb.5=0
trisb.6=0
trisb.7=0
trisb.0=0 'pwm pin 6 an output
trisa.3=1 'block sense input
laps=0

data @0,150,005, 1 '150 speed, 005 pause, 001 adrate (1 is slow rate)

read 0, speed
read 1, pausebyte
read 2, ADRate

debug 13,10,13,10,"(C) 2007 - d. bodnar - ver 1.5",13,10,"TrainElectronics.com",13,10
debug 13,10,"speed, pausebyte, adrate ",#speed, " ", #pausebyte," ",#adrate
pause 2000
VeryTop:
hpwm TIP101, 0, 0 'all stop
low relay:low LEDGreen:Low LEDYellow:low LEDWhite:low ledred
start:
tempword=0
command=0
forwardflag=0
InBlockFlag=0

start0:
gosub accel
start01:
if blocksense=0 and inblockflag=0 then
high ledwhite
gosub decel
inblockflag=1
debug 10,13,"pausing =",#pausebyte
pause (pausebyte*1000)
laps=laps+1: debug 13,10,"Laps= ",#laps
gosub ReportLaps:
toggle relay
gosub accel
'pause 1500 'to get out of block - change to sense or out-of-block?
endif
command=0
gosub getir

if speed >= 10 then
if speed <100 then high ledred:low ledgreen
if speed >=100 and speed <200 then high ledred:high ledgreen
if speed >=200 then high ledgreen:low ledred
endif
if command = OK then
speed=0
goto VeryTop:
endif

if command = volumeDOWN then relayoff:
if command = volumeUP then relayon:
if command = ChannelUp then speedup:
if command = channelDown then speeddown:
if command = Enter then GetDigits:
if command = Power then speedup: 'go to max speed

if blocksense=1 and inblockflag=1 then
inblockflag=0
low ledwhite
endif

goto start01

relayon:
if forwardflag =1 then start01: 'if already going backward skip
goto dorelay:

relayoff:
if forwardflag=0 then start01: 'if already going forward skip

dorelay:
Gosub Decel
toggle relay
gosub Accel:
forwardflag=not(forwardflag)
goto start01:

speedup:
if speed > 250 then start0:
speed=speed+2
goto dospeed:

speeddown:
if speed < 5 then start0:
speed=speed -2

dospeed:
hpwm tip101, speed, 2000
debug 13,10,"Speed= ",#speed
goto start01:

Decel:
debug 13,10,"D-Speed= ",#temp, " "
for Temp=speed to 0 step -adrate
hpwm tip101, Temp, 2000
debug #temp," "
toggle ledred:toggle ledgreen:toggle ledyellow
temp1=255-speed: temp1=temp/20 'adjusts ad rate for low top speed
pause temp1
toggle ledred:toggle ledgreen:toggle ledyellow
next Temp
return

Accel:
debug 13,10,"A-Speed= ",#speed," "
for Tempword3=10 to speed step adrate
hpwm tip101, tempword3,1000
debug #tempword3, " "
toggle ledred:toggle ledgreen:toggle ledyellow
temp1=255-speed: temp1=temp1/10 'adjusts ad rate for low top speed
pause temp1
next Tempword3
return


GetIR:
Getstartbits:
Pulsin IRin ,0,IRpulse_length(0)
if IRpulse_length(0) < 400 then
'goto getstartbits
return
Endif

for xx=1 to 12
pulsin IRin,0,IRpulse_length(xx)
next xx

displaybits:
if IRpulse_length(1) < 200 then
Command.bit0 = 0
Else
Command.bit0 = 1
endif
if IRpulse_length(2) < 200 then
Command.bit1 = 0
Else
Command.bit1 = 1
endif
if IRpulse_length(3) < 200 then
Command.bit2 = 0
Else
Command.bit2 = 1
endif
if IRpulse_length(4) < 200 then
Command.bit3 = 0
Else
Command.bit3 = 1
endif
if IRpulse_length(5) < 200 then
Command.bit4 = 0
Else
Command.bit4 = 1
endif
if IRpulse_length(6) < 200 then
Command.bit5 = 0
Else
Command.bit5 = 1
endif
if IRpulse_length(7) < 200 then
Command.bit6 = 0
Else
Command.bit6 = 1
endif
if IRpulse_length(8) < 200 then
Command.bit7 = 0
Else
Command.bit7 = 1
Endif
If Command.bit7 = 0 then 'Bit 7 is one of the device bits
Command = Command + 1
Endif
If Command = 10 then
Command = 0
Endif
debug "code= ", #command ,13,10
'serout serial_out,n9600,[13,10,"command", #command," speed ", #speed," PauseByte ", #PauseByte, 13,10]
return

ShowSpeedLEDs:
temp2=tempword2*10 'using 8 for only 8 numbers with 3 leds (7 actually!)
temp1=temp2/PauseByte
low ledred:low ledgreen:low ledyellow:low ledwhite
'debug 13,10,"TEMP1 ",#temp1 ," "
if (temp1 & %00000001)=1 then high ledred
if (temp1 & %00000010)=2 then high ledyellow
if (temp1 & %00000100)=4 then high ledgreen
if (temp1 & %00001000)=8 then high ledwhite
return

ReportLaps:
high ledwhite:high ledred:high ledgreen:high ledyellow
pause 1000
low ledwhite:low ledred:low ledgreen:low ledyellow
pause 500
if laps> 99 then
temp2=laps dig 2
for temp=1 to temp2
high ledred
pause 300
low ledred
pause 300
next temp
pause 500
endif
if laps > 9 then
temp2=laps dig 1
for temp=1 to temp2
high ledyellow
pause 300
low ledyellow
pause 300
next temp
pause 500
endif
temp2=laps dig 0
for temp=1 to temp2
high ledgreen
pause 300
low ledgreen
pause 300
next temp
pause 500
return

GetDigits:
debug 10,13, "At Get Digits", 10,13
savespeed=speed
saveadrate=adrate
savepause=pausebyte
hpwm tip101, 0, 0 'all stop
GetType: high ledwhite
command=0
gosub GetIR: 'one for speed, two for pause, three for ADRate
if command=0 then GetType
low ledwhite
if command <> one and command <> two and command <> three then
goto Gettype: 'repeat on abort on non number 1, 2, 3
endif
DigitType= command-127 'speed=1, pause =2, ADRate=3
low ledwhite:pause 500
if digittype=1 then
for temp1=1 to 2
toggle ledwhite
pause 600
next temp1
endif
if digittype=2 then
for temp1=1 to 4
toggle ledwhite
pause 600
next temp1
endif

if digittype=3 then
for temp1=1 to 6
toggle ledwhite
pause 600
next temp1
endif



debug 10,13, "DigitType= ", #digittype
digit=3
command=0
DigitsByte=0
high LEDYellow:high LEDGreen:pause 1000:low LEDYellow:low LEDGreen:low LEDWhite
GetDigits0:
gosub GetIR:
if command=0 then GetDigits0
if command > 137 or command < 128 and command <>139 and command <> 0 then
goto VeryTop: 'abort on non number 0-9
endif
if command=139 then GetDigits0:
Value=command-127
if Value = 10 then value=0
if digit<4 then skiprnd:
digit=3
for tempbyte=1 to 50:toggle LEDYellow:pause 30:next tempbyte
goto GetDigits0:
skiprnd:
if value=0 then high ledwhite:pause 500:low ledwhite
for tempbyte=1 to value:High LEDwhite:pause 200:low LEDwhite:pause 200:next tempbyte
DigitsByte=DigitsByte*10+Value
digit=digit-1
pause 200:command=0
if digitsbyte > 255 then digitsbyte=255
if digit=0 then
if DigitType=1 then
speed=digitsbyte
write 0, speed
endif
if Digittype=2 then
pausebyte=digitsbyte
write 1, pausebyte
endif
if digittype=3 then
adrate=digitsbyte
write 2, ADRate
endif
debug 13,10,"Wrote speed, pause, adrate ", #speed, " ", #pausebyte, " ", #adrate
' speed=DigitsByte
goto Start0: 'StartReverse:
endif
goto GetDigits0:
 

 

Software - 2008 version
'11-12-08 revised for MRC AD322 DCC controller board with 16F88 on it
'WORKING on AD322 board - ready to install in trolley & test on diode track
'11-22-07 based on 16F684 code - revised for 16F88
'To use - right arrow (vol+) to set speed then 
'hit ENTER - all will stop - 3 digit time (roughly 1/10 seconds)
'Delay adjusted for length of time needed to report laps
'modifeid to flash speed (1), delay (2), ad rate (3) three times fast on ENTER
' and to allow IR ENTER command during pause at end of track
DEFINE DEBUG_REG PORTA  
DEFINE DEBUG_BIT 2         ' PIN 1 on 16f88
DEFINE DEBUG_BAUD 9600 
DEFINE DEBUG_MODE 1 ' Set Debug mode: 0 = true, 1 = inverted

'define PULSIN_MAX 555
'  @ DEVICE  PIC16F88, INTRC_OSC_NOCLKOUT, WDT_OFF, LVP_OFF, PWRT_ON, PROTECT_OFF, BOD_ON, MCLR_OFF
DEFINE OSC 8
OSCCON = $70      'dec 112 binary 11100000   = 8mhz

'NOTE - at $70 (8mhz) must double ms on GETIR routines to 400 & 200

'OSCCON = %01100111     '=103 dec / 67 hex 'MUST BE USED to set clock speed=4mhz
cmcon=7                 'allows you to use pins as digital rather than analog
ansel=0                 'allows you to use pins as digital rather than analog

INCLUDE "modedefs.bas"
loop                VAR BYTE
temp                VAR WORD
temp1               VAR WORD
temp2               VAR WORD
LEDTemp1            VAR BYTE
LEDTemp2            VAR BYTE
LEDTemp3            VAR BYTE
Laps                VAR WORD 
ReportLapsTime      VAR WORD
TempByte            VAR BYTE
digit               VAR BYTE
rndYN               VAR BYTE
PauseByte           VAR BYTE        'pause at end of run in seconds
PauseWord           VAR WORD        'used in lap report correction of pause
SavePause           VAR BYTE        'temp variable to store value while working
SaveADRate          VAR BYTE        'temp variable to store value while working
SaveSpeed           VAR BYTE        'temp variable to store value while working
PauseByte2          VAR BYTE
DigitsByte          VAR BYTE        'temp for getting digit input
DigitType           VAR BYTE         '1 =speed, 2=pause, 3=ADRate
ADRate              VAR BYTE        'accel / decel rate - large # is fast rate
TempWord            VAR WORD
TempWord2           VAR WORD
TempWord3           VAR WORD
value               VAR BYTE
TIP101              CON 2          'pin 6 for PWM
ForwardFlag         VAR BIT
InBlockFlag         VAR BIT         '0 if on mainline / 1 if in block
LEDGreen            VAR portb.6    'pin 12 
LEDYellow           VAR portb.7    'pin 13 
LEDRed              VAR portb.5    'pin 11 
LEDWhite            VAR portb.4    'pin 10 
BlockSense          VAR porta.3    'pin 2  high when on mainline/low with diode
LongHorn            VAR portb.1    'AD322 pin 4  PIC  pin 7
BellSound           VAR portb.2    'AD322 pin 2  PIC  pin 8
ShortHorn           VAR porta.0    'another sound pin 17
relay               VAR portb.3     'relay to control direction pin 9
zero                CON 136
one                 CON 128
two                 CON 129
three               CON 130
four                CON 131
five                CON 132
six                 CON 133
seven               CON 134
eight               CON 135
nine                CON 136
channelUP           CON 144
channelDOWN         CON 145
volumeUP            CON 146
volumeDOWN          CON 147
OK                  CON 148
Menu                CON 224
ENTER               CON 139
Power               CON 149
TVVCR               CON 165
Speed               VAR BYTE
IRpulse_length      VAR WORD(13)
xx VAR BYTE
Command VAR BYTE
IRin                VAR porta.1 'pin 18
ansel = 0
'cmcon0 = 7

serial_out           VAR porta.2   'pin 1
trisa.1=1           'IR sensor
trisa.2=0           'debug an output           
trisb.3=0           'make relay pin an output
trisb.4=0           'make led output
trisb.5=0
trisb.6=0
trisb.7=0
trisb.0=0           'pwm pin 6 an output
trisa.3=1           'block sense input   pin 2
portb.1=0
portb.2=0
Laps=0
trisa.6=0:trisa.7=0:trisa.0=0'sounds
DEBUG 13,10,13,10,"(C) 2008 - d. bodnar - ver 1-0",13,10,"TrainElectronics.com",13,10
LOW LongHorn:LOW BellSound:LOW ShortHorn
DATA @0,150,005, 1   '150 speed, 005 pause, 001 adrate (1 is slow rate)

READ 0, speed
READ 1, pausebyte
READ 2, ADRate
again:

HPWM TIP101, 0, 0			'all stop
'for temp=1 to 3
'high relay:pause 500:low relay:pause 500
'next temp

'debug 10,13,"Long Horn 1 test"
'high LongHorn:pause 2000:low LongHorn:pause 1000
'debug 10,13,"Bell test"
'high BellSound:pause 2000:low BellSound:pause 1000
DEBUG 10,13,"Short Horn test"
HIGH ShortHorn:PAUSE 2000:LOW ShortHorn:PAUSE 1000
'high LongHorn:high BellSound' turn both sounds off
DEBUG 13,10,13,10,"(C) 2008 - d. bodnar - ver 1-2",13,10,"TrainElectronics.com",13,10
DEBUG 13,10,"speed, pausebyte, adrate ",#speed, " ", #pausebyte," ",#adrate
PAUSE 2000
VeryTop:
'low BellSound::toggle ledwhite:pause 100:high BellSound:pause 3000:low LongHorn:pause 100:high LongHorn:toggle ledwhite:pause 3000

LOW relay:LOW LEDGreen:LOW LEDYellow:LOW LEDWhite:LOW ledred
start:
tempword=0
Command=0
forwardflag=0
InBlockFlag=0

start0:
HIGH bellsound ' ring BellSound
GOSUB accel:PAUSE 2000 'pause to get out of block - may help?
LOW bellsound
start01:
IF blocksense=0 AND inblockflag=0 THEN 
    HIGH shorthorn
    HIGH ledwhite
    GOSUB decel
    LOW shorthorn
    inblockflag=1
    Laps=Laps+1: GOSUB ReportLaps:
    pauseword=pausebyte*1000
    IF ReportLapsTime < pauseword THEN
        pauseword=pauseword-ReportLapsTime
        ELSE 
        pauseword=0
    ENDIF
    TOGGLE relay
    DEBUG 10,13,"pausing = ",#pausebyte ," corrected to ",#pauseword    
    pauseword=pauseword / 200
    DEBUG 10,13,"for / next  = ",#pauseword    
    FOR tempword3= 1 TO pauseword 
    Command=0
    GOSUB getir
    IF Command =ENTER THEN getdigits
    'pause pauseword
'    toggle relay
    TOGGLE ledyellow
    NEXT tempword3
    HIGH BellSound':pause 100:low BellSound ' ring BellSound
    GOSUB accel
    LOW bellsound 
    'pause 1500   'to get out of block - change to sense or out-of-block?
ENDIF
Command=0
GOSUB getir

IF speed >= 10 THEN
     IF speed <100 THEN HIGH ledred:LOW ledgreen
     IF speed >=100 AND speed <200 THEN HIGH ledred:HIGH ledgreen
     IF speed >=200 THEN HIGH ledgreen:LOW ledred
ENDIF
IF Command = OK THEN 
    speed=0
    GOTO VeryTop:
ENDIF

IF Command =	volumeDOWN THEN relayoff:
IF Command =	volumeUP THEN relayon:
IF Command =	channelUP THEN speedup:
IF Command =	channelDOWN THEN speeddown:
IF Command = 	ENTER THEN GetDigits:
IF Command =    Power THEN speedup:           'go to max speed
IF Command = one THEN OneTest
IF Command = two THEN TwoTest
IF Command = three THEN ThreeTest
IF Command = four THEN FourTest
IF blocksense=1 AND inblockflag=1 THEN
    inblockflag=0
    LOW ledwhite
ENDIF

GOTO start01   

OneTest
DEBUG 10,13,"LongHorn Test",10,13
HIGH LongHorn:PAUSE 1000:LOW LongHorn:PAUSE 1000
GOTO Start01
TwoTest
DEBUG 10,13,"BellSound Test",10,13
HIGH BellSound:PAUSE 1000:LOW BellSound:PAUSE 1000
GOTO Start01
ThreeTest
DEBUG 10,13,"ShortHorn (really LongHorn) Test",10,13
HIGH LongHorn:PAUSE 1000:LOW LongHorn:PAUSE 1000
GOTO Start01
FourTest
DEBUG 10,13,"Relay Test",10,13
HIGH relay:PAUSE 1000:LOW relay:PAUSE 1000
GOTO Start01

relayon:
HIGH LongHorn:PAUSE 100:LOW LongHorn
IF forwardflag =1 THEN start01:	'if already going backward skip
GOTO dorelay:

relayoff:
HIGH BellSound:PAUSE 100:LOW BellSound
IF forwardflag=0  THEN start01:	'if already going forward skip

dorelay:
GOSUB Decel
TOGGLE relay
GOSUB Accel:
forwardflag=NOT(forwardflag)
GOTO start01:

speedup:
IF speed > 250 THEN start0:
speed=speed+2
GOTO dospeed:

speeddown:
IF speed < 5 THEN start0:
speed=speed -2

dospeed:
HPWM TIP101, speed, 2000
DEBUG 13,10,"Speed= ",#speed
GOTO start01:

Decel: 
DEBUG 13,10,"D-Speed= ",#temp, "  "
FOR temp=speed TO 0 STEP -adrate
HPWM TIP101, temp, 2000
DEBUG #temp," "
TOGGLE ledred:TOGGLE ledgreen:TOGGLE ledyellow
temp1=255-speed: temp1=temp/20  'adjusts ad rate for low top speed
PAUSE  temp1 
TOGGLE ledred:TOGGLE ledgreen:TOGGLE ledyellow
NEXT temp
RETURN

Accel:
DEBUG 13,10,"A-Speed= ",#speed,"  "
FOR Tempword3=10 TO speed STEP adrate
HPWM TIP101,  tempword3,1000
DEBUG #tempword3, " "
TOGGLE ledred:TOGGLE ledgreen:TOGGLE ledyellow
temp1=255-speed: temp1=temp1/10  'adjusts ad rate for low top speed
PAUSE  temp1 
NEXT Tempword3
RETURN


GetIR:
Getstartbits:
PULSIN IRin ,0,IRpulse_length(0)
IF IRpulse_length(0) < 400 THEN
   'goto getstartbits
   RETURN
ENDIF

FOR xx=1 TO 12
PULSIN IRin,0,IRpulse_length(xx)
NEXT xx

displaybits:
IF IRpulse_length(1) < 200 THEN 
    Command.Bit0 = 0 
    ELSE 
    Command.Bit0 = 1
ENDIF
IF IRpulse_length(2) < 200 THEN
    Command.Bit1 = 0
    ELSE
    Command.Bit1 = 1
ENDIF
IF IRpulse_length(3) < 200 THEN
    Command.Bit2 = 0
    ELSE
    Command.Bit2 = 1
ENDIF
IF IRpulse_length(4) < 200 THEN
    Command.Bit3 = 0
    ELSE
    Command.Bit3 = 1
ENDIF
IF IRpulse_length(5) < 200 THEN
    Command.Bit4 = 0
    ELSE
    Command.Bit4 = 1
ENDIF
IF IRpulse_length(6) < 200 THEN
    Command.Bit5 = 0
    ELSE
    Command.Bit5 = 1
ENDIF
IF IRpulse_length(7) < 200 THEN
    Command.Bit6 = 0
    ELSE
    Command.Bit6 = 1
ENDIF
IF IRpulse_length(8) < 200 THEN
    Command.Bit7 = 0
    ELSE
    Command.Bit7 = 1
ENDIF
IF Command.Bit7 = 0 THEN 'Bit 7 is one of the device bits
    Command = Command + 1
ENDIF
IF Command = 10 THEN
    Command = 0
ENDIF
 DEBUG "code= ", #Command ,13,10
'serout serial_out,n9600,[13,10,"command", #command," speed ", #speed," PauseByte ", #PauseByte, 13,10]
RETURN 

ShowSpeedLEDs:
temp2=tempword2*10     'using 8 for only 8 numbers with 3 leds (7 actually!)
temp1=temp2/PauseByte
LOW ledred:LOW ledgreen:LOW ledyellow:LOW ledwhite 
'debug 13,10,"TEMP1 ",#temp1 ,"  "
  IF (temp1 & %00000001)=1 THEN HIGH ledred
  IF (temp1 & %00000010)=2 THEN HIGH ledyellow
  IF (temp1 & %00000100)=4 THEN HIGH ledgreen
  IF (temp1 & %00001000)=8 THEN HIGH ledwhite
RETURN

ReportLaps:
DEBUG 13,10,"Laps= ",#Laps
HIGH ledwhite:HIGH ledred:HIGH ledgreen:HIGH ledyellow
PAUSE 100 
LOW ledwhite:LOW ledred:LOW ledgreen:LOW ledyellow
PAUSE 500
ReportLapsTime=600
IF Laps> 99 THEN
temp2=Laps DIG 2
FOR temp=1 TO temp2
    HIGH ledred
    PAUSE 300
    LOW ledred
    PAUSE 300
    ReportLapsTime=ReportLapsTime+600
NEXT temp
PAUSE 500
    ReportLapsTime=ReportLapsTime+500
ENDIF
IF Laps > 9 THEN
temp2=Laps DIG 1
FOR temp=1 TO temp2
    HIGH ledyellow
    PAUSE 300
    LOW ledyellow
    PAUSE 300
    ReportLapsTime=ReportLapsTime+600
NEXT temp
PAUSE 500
    ReportLapsTime=ReportLapsTime+500
ENDIF
temp2=Laps DIG 0
FOR temp=1 TO temp2
    HIGH ledgreen
    PAUSE 300
    LOW ledgreen
    PAUSE 300
    ReportLapsTime=ReportLapsTime+600
NEXT temp
PAUSE 500
    ReportLapsTime=ReportLapsTime+500
    DEBUG 10,13,"RLT= ",#ReportLapsTime ,10,13
RETURN

GetDigits:
DEBUG 10,13, "At Get Digits", 10,13
savespeed=speed
saveadrate=adrate
savepause=pausebyte
HPWM TIP101, 0, 0	'all stop
GetType:   HIGH ledwhite
Command=0
GOSUB GetIR:               'one for speed, two for pause, three for ADRate
IF Command=0 THEN GetType
LOW ledwhite
IF Command <> one AND Command <> two AND Command <> three THEN
    GOTO Gettype: 	'repeat on abort on non number 1, 2, 3
ENDIF
DigitType= Command-127 'speed=1, pause =2, ADRate=3
LOW ledwhite:PAUSE 500
IF digittype=1 THEN
    FOR temp2=1 TO 3
    FOR temp1=1 TO 2
        TOGGLE ledwhite
        PAUSE 100
    NEXT temp1
    PAUSE 500
    NEXT temp2
ENDIF
IF digittype=2 THEN
    FOR temp2=1 TO 3
    FOR temp1=1 TO 4
        TOGGLE ledwhite  
        PAUSE 100
    NEXT temp1
    PAUSE 500
    NEXT temp2
ENDIF

IF digittype=3 THEN
    FOR temp2=1 TO 3
    FOR temp1=1 TO 6
        TOGGLE ledwhite
        PAUSE 100
    NEXT temp1
    PAUSE 500
    NEXT temp2
    
ENDIF



DEBUG 10,13, "DigitType= ", #digittype
digit=3
Command=0
DigitsByte=0
HIGH LEDYellow:HIGH LEDGreen:PAUSE 1000:LOW LEDYellow:LOW LEDGreen:LOW LEDWhite
GetDigits0:
GOSUB GetIR:
IF Command=0 THEN GetDigits0
IF Command > 137 OR Command < 128 AND Command <>139 AND Command <> 0 THEN 
    GOTO VeryTop:	'abort on non number 0-9
ENDIF
IF Command=139 THEN GetDigits0:
Value=Command-127
IF Value = 10 THEN value=0
IF digit<4 THEN skiprnd:
digit=3
FOR tempbyte=1 TO 50:TOGGLE LEDYellow:PAUSE 30:NEXT tempbyte
GOTO GetDigits0:
skiprnd:
IF value=0 THEN HIGH ledwhite:PAUSE 500:LOW ledwhite
FOR tempbyte=1 TO value:HIGH LEDwhite:PAUSE 200:LOW LEDwhite:PAUSE 200:NEXT tempbyte
DigitsByte=DigitsByte*10+Value
digit=digit-1
PAUSE 200:Command=0
IF digitsbyte > 255 THEN digitsbyte=255
IF digit=0 THEN 
    IF DigitType=1 THEN
        speed=digitsbyte
        WRITE 0, speed
    ENDIF
    IF Digittype=2 THEN
        pausebyte=digitsbyte
        WRITE 1, pausebyte
    ENDIF
    IF digittype=3 THEN
        adrate=digitsbyte
        WRITE 2, ADRate
    ENDIF
    DEBUG 13,10,"Wrote speed, pause, adrate ", #speed, " ", #pausebyte, " ", #adrate
    ' speed=DigitsByte
     GOTO Start0: 'StartReverse:
ENDIF
GOTO GetDigits0:
Trolley Photos - 2007 version

The devices at the top of the photos are the bridge rectifier (black unit) and a 1000 mfd capacitor.  The circuit board is to the right.  The other wires in the photo connect to the motor, track power pickups and head lights.  (Note - the bridge rectifier is on the AD322 board)

Here is a close up of the bridge rectifier and filter cap.

The standard Bachmann power units on both trolleys were replaced with ones from Bachmann Spectrum 45 Ton Center Cab Switchers.  The stock power units are poor at best.

Lights are also installed in the clearstory

The headlights are 5mm bright white LEDs.  They are VERY visible.

... especially when viewed straight on!

 

Circuit Board Photos - 2007 version

The 16F88 is the IC in the upper right.  The small device above the 4 LEDs is the IR receiver.  The relay is the white device bottom, center.  The 6 pin IC in the bottom left is the optoisolator.  The power transistor that controls the trolley's speed is just to the right of the relay.

 

Construction for 2008

The parts that were used in the new version are shown below.  The AD322 board is on the left.  It will be modified and its 4 diodes (top of board), relay (blue object), power transistor (right center), power supply (lower right), amplifier (bottom center), and sound unit (lower left) will be used.  The large capacitor on the right will help the trolley to navigate dirty or wet track.

The microcontroller that had been on the AD322 has been removed.  Connections will be made to the solder pads that it was once fastened to.

Pre-wiring these three modules speeds construction.  The unit at the left is the optoisolator.  It is used to sense when the train enters a diode protected section of track.  The unit in the center holds four signaling LEDs and their 470 ohm current limiting resistors.  The socket at the right will hold the 16F88.  A capacitor and a resistor have been fit inside of the socket to save space.  The plug all the way to the right is used to program the PIC.

Some close-ups

The PIC's socket has been glued to the top of the relay and its wires connected.  The optoisolator has been glued to the side of the relay (front center).

The wires that control the sound are soldered to the pads where the other processor once resided.  A sharply pointed soldering iron and some care are needed to prevent solder bridges and short circuits.

This close-up shows the 4 pin connector that allows you to program the PIC while it is installed in the circuit.  The header to the right with the green and white wires connects the optoisolator's input to the track power so that it can detect when a diode protected area in the track has been entered.

Here is the bottom of the AD322 where the green and white wires are connected.  The black and red wires connect to the DC output from the four diodes on the AD322 board and go to the large capacitor.