Slot car computer control with a TI 99/4A computer
Slot car racing sets have always fascinated me, and I have owned a few over the years. Unfortunately, it was always difficult to find opponents to race against beyond just a few runs. I have dabbled many times with the idea of a computer controlled opponent over the years, and finally decided to tackle it as a demo project for the 2016 Chicago International TI Faire in October 2016.
I have a lot of experience under my belt interfacing the TI computer to the real world, using the PIO, joystick and cassette port as interfaces, and therefore it was only natural for me to attempt doing this using my good old TI 99/4A computer.
The first idea I came up with was outfitting one of the slot cars with a centrifugal force sensor that could send a wireless signal to the TI equipped with a compatible wireless receiver, and thus allow the computer to adjust the speed of the car in order to keep the centrifugal force under a certain limit that would keep the car on the track. The obvious advantage here is that this would be track independent regardless of how tough and twisted the track was. I may still do that at some point, but it required a fairly large scale car and track in order to be able to accommodate the needed electronics and power supply, and I did not want to invest in a large slot car race track at this time.
The alternative idea required a different approach, with 2 problems to solve:
- How to sense the location of the car on the track
- How to control the speed of the car
The sensing part was solved by strategically positioning photoresistors on the track which will sense when the car is over them and thus report back a location to the computer. One only needs to know where a particular type of track starts, whether a curve or a straight, and adjust the speed of the car accordingly. These track sections will be labeled as sectors with a fixed car speed for each optimized by trial and error.
Here's the basic circuit diagram:
When the photoresistor is fully lit, i.e. there is no overlying car, then its resistance is very low and the PIO line is connected to the positive pole of the battery, and so is in a high state or 1. When the car is on top of the photoresistor, then the latter's resistance becomes very high, therefore the PIO line goes to ground or 0. From there, it's just a matter of masking in software the appropriate bit in the PIO data lines (there are 8 of them) to find out whether it is high or low and thus figure out which photoresistor got triggered. Since there are 8 available PIO lines, it's possible to detect up to 8 sectors on the track.
As for speed control, I decided to use the cassette port motor control plug for the purpose. Earlier on, I had experimented with that method to ignite a rocket motor igniter at the request of a fellow TIer (Omega) as seen in the video below:
https://youtu.be/4FHgEjmP8C4
Here, I replace the igniter with the connection to the track hand controller which is nothing but a variable resistor. The problem here is that when the relay is activated, then the slot car will get full power and will very likely fly off the track in an instant. One way I came up with to mitigate that problem was to use what I call Pulse Frequency Modulation, where full power is applied for a very brief amount of time, but then repeated frequently. The frequency of the on/off cycles will then determine the speed of the car. The frequency can be easily controlled in software and again I relied on a previous project where I control a robotic arm with the TI as detailed below (skip to 14:11 for the relevant part):
https://youtu.be/HrDUJUfcD2k
And here's the basic control circuit. I will be using a solid state relay instead of a mechanical one for durability, speed of actuation and lack of bounce.
So now we have solved both problems, and it's just a matter of experimentation and putting it all together. I created a small PCB which incorporates both the sensing and motor components as discussed above. The slot car racing set I'm using is a cheap small one which only requires 5 photoresistors. The PCB layout was designed using Circuit Wizard and the PCB was produced using a homebrew process.
And the finished product. It won't win any design awards, but hey it's functional
Here's the source code for the control program:
** SLOT CAR CONTROL PROGRAM **** SEPTEMBER 2016 **** BY WALID MAALOULI ** DEF START REF VSBW,VMBW,VWTR,KSCAN,GPLLNKKEY EQU >8375 ADDRESS OF KEY PRESSED VALUEGPLSTS EQU >837C GPL STATUS BYTEPIO EQU >5000 PARALLEL PORT DATA BYTE ADDRESSBUFFER EQU >1000 VDP RAM SOUND BUFFERSUBRT1 BSS 2 SUBROUTINE RETURN ADDRESSSEC1FL BSS 2 SECTOR 1 FLAGPLYFLG BSS 2 PLAYER LAP FLAGNUMANS BSS 10 STORAGE SPACE FOR NUMBERSONE DATA 1ANYKEY BYTE >20BONE BYTE >01SLIST BYTE >03,>89,>3F,>91,>1E,>01,>9F,>00ASCDIG TEXT '0123456789'TITLE TEXT 'TI SLOT CAR CONTROL PROGRAM'LAP TEXT 'LAP # 'SECTOR TEXT 'SECTOR: 'CNTMSG TEXT 'PRESS ANY KEY TO START COUNTDOWN'CNTSTR TEXT 'COUNTDOWN IN PROGRESS!'COMPTR TEXT 'COMPUTER'PLAYER TEXT 'PLAYER'PLYWIN TEXT 'YOU WIN!!!!'COMWIN TEXT 'YOU LOSE!!!'BLANK TEXT ' ' EVEN ** INITIALIZE TEXT MODE **START LWPI >8300 LI R0,>0731 GREEN LETTERS ON BLACK BACKGROUND BLWP @VWTR LI R0,>F000 VALUE TO BE LOADED IN VR1 MOVB R0,@>83D4 SAVE VALUE LI R0,>01F0 START TEXT MODE BLWP @VWTR ** INITIALIZE RS232 CARD PIO PORT AND CASSETTE MOTOR ** LI R12,>1300 SELECT DSR ADDRESS OF CARD SBO 0 ACTIVATE CARD SBO 7 TURN CARD LED ON CLR @PIO CLEAR DATA LINES SBO 1 SET PORT TO INPUT CLR R12 SELECT DSR ADDRESS OF TMS9901 SBZ 22 DEACTIVATE MOTOR ** SPLASH SCREEN BL @CLRTXT CLEAR THE SCREEN LI R0,7 LI R1,TITLE LI R2,27 BLWP @VMBW DISPLAY TITLE LI R0,404 LI R1,CNTMSG LI R2,32 BLWP @VMBW DISPLAY KEY PRESS REQUEST BL @KINPT BL @CLRTXT CLEAR THE SCREEN ** INITIALIZE SOUND BUFFER LI R0,BUFFER LI R1,SLIST LI R2,8 BLWP @VMBW ** COUNTDOWN LI R0,409 LI R1,CNTSTR LI R2,22 BLWP @VMBW DISPLAY START OF COUNTDOWN MESSAGE LI R1,>0035 ASCII NUMBER 5 LI R0,500CNTDN SWPB R1 BLWP @VSBW DISPLAY NUMBER BL @PLYSND PLAY SOUND BL @DELAY SWPB R1 DEC R1 CI R1,>002F JNE CNTDN BL @CLRTXT LI R5,6000 DEFAULT PFM DELAY ** SET UP RACE SCREEN ** LI R0,122 LI R1,COMPTR LI R2,8 BLWP @VMBW LI R0,142 LI R1,PLAYER LI R2,6 BLWP @VMBW LI R0,202 LI R1,LAP LI R2,5 BLWP @VMBW LI R0,222 LI R1,LAP LI R2,5 BLWP @VMBW LI R0,282 LI R1,SECTOR LI R2,8 BLWP @VMBW ** CAR SECTOR LOCATION LI R8,-1 INITIALIZE COMPUTER LAP NUMBER LI R9,-1 INITIALIZE PLAYER LAP NUMBER CLR @SEC1FL CLEAR SECTOR FLAG CLR @PLYFLG CLEAR PLAYER LAP FLAG* CHECK SECTOR 1 *SECCHK CLR R0 MOVB @PIO,R0 ANDI R0,>0100 JEQ S1* CHECK SECTOR 2 * MOVB @PIO,R0 ANDI R0,>0200 JEQ S2* CHECK SECTOR 3 * MOVB @PIO,R0 ANDI R0,>0400 JEQ S3* CHECK SECTOR 4 * MOVB @PIO,R0 ANDI R0,>0800 JEQ S4* CHECK PLAYER CAR * MOVB @PIO,R0 ANDI R0,>1000 JEQ PCAR JMP MOTORS1 C @SEC1FL,@ONE CHECK IF STILL IN SECTOR 1 JEQ MOTOR IF YES THEN SKIP SECTOR LI R5,6000 SET PFM FREQUENCY INC R8 INCREMENT COMPUTER LAP COUNTER LI R0,290 LI R1,>3100 BLWP @VSBW DISPLAY SECTOR NUMBER MOV R8,R1 LI R7,207 BL @DISNUM DISPLAY LAP NUMBER CI R8,20 JNE CCONT BL @CWINCCONT MOV @ONE,@SEC1FL SET SECTOR 1 FLAG CLR @PLYFLG CLEAR PLAYER LAP FLAG JMP MOTORS2 LI R5,10500 LI R0,290 LI R1,>3200 BLWP @VSBW CLR @SEC1FL CLEAR SECTOR 1 FLAG CLR @PLYFLG JMP MOTORS3 LI R5,8500 LI R0,290 LI R1,>3300 BLWP @VSBW CLR @PLYFLG JMP MOTORS4 LI R5,6500 LI R0,290 LI R1,>3400 BLWP @VSBW CLR @PLYFLG JMP MOTORPCAR C @PLYFLG,@ONE CHECK IF PLAYER CAR STILL ON LAP SENSOR JEQ MOTOR IF YES THEN SKIP TO MOTOR SECTION INC R9 INCREMENT PLAYER LAP COUNTER LI R7,227 MOV R9,R1 BL @DISNUM CI R9,20 JNE PCONT BL @PWINPCONT MOV @ONE,@PLYFLG SET THE PLAYER CAR LAP FLAG ** MOTOR CONTROL **MOTOR BL @PFM B @SECCHK ********************************************************************************** CLEAR TEXT SCREEN ROUTINE **CLRTXT CLR R0 POINT TO SIT CLR R1 LI R2,960 LENGTH OF SITREDO BLWP @VSBW CLEAR SIT BYTE INC R0 POINT TO NEXT SIT BYTE DEC R2 JNE REDO REPEAT UNTIL ALL SIT BYTES ARE CLEARED RT********************************************************************************** TEXT MODE KEY INPUT ROUTINE **KINPT CLR @GPLSTS BLWP @KSCAN READ KEYBOARD CB @ANYKEY,@GPLSTS BIT 2 OF GPLSTS IS SET WHEN DIFFERENT KEY PRESSED JNE KINPT RESCAN IF SAME KEY PRESENT IN BUFFER RT********************************************************************************** MOTOR PULSE FREQUENCY MODULATION** R5 WILL CONTAIN THE COUNTDOWN TIMER BETWEEN MOTOR ACTIVATION PULSESPFM MOV R5,R7 LI R1,50 SBO 22 ACTIVATE MOTORRUN DEC R1 START COUNTDOWN TIMER JNE RUN SBZ 22 DEACTIVATE MOTORSTOP DEC R7 START COUNTDOWN TIMER JNE STOP RT********************************************************************************** TEXT BLANKING ROUTINE **** R0 WILL CONTAIN TEXT LOCATION ON SCREEN **TXTBLK LI R1,BLANK LI R2,27 BLWP @VMBW RT********************************************************************************** DISPLAY NUMBER ON SCREEN ROUTINE **** R1 WILL CONTAIN THE NUMBER TO DISPLAY **** R7 CONTAINS THE SCREEN ADDRESS **DISNUM LI R2,100 CLR R0 DIV R2,R0 DIVIDE R0+R1 BY 100. R0=QUOTIENT R1=REMAINDER MOV R0,@NUMANS STORE ASCII QUOTIENT LI R2,10 CLR R0 DIV R2,R0 DIVIDE R0+R1 BY 10 MOV R0,@NUMANS+2 STORE ASCII QUOTIENT MOV R1,@NUMANS+4 STORE ASCII REMAINDER MOV @NUMANS,R1 PLACE FIRST DIGIT IN R1 LI R6,ASCDIG POINT TO THE ASCII DIGIT TABLE A R6,R1 OFFSET TO PROPER DIGIT IN STRING MOV R7,R0 SCREEN ADDRESS IN R0 LI R2,1 DIGIT LENGTH IS ONE BLWP @VMBW WRITE DIGIT TO SCREEN MOV @NUMANS+2,R1 FETCH NEXT DIGIT A R6,R1 INC R0 NEXT SCREEN ADDRESS BLWP @VMBW MOV @NUMANS+4,R1 FETCH LAST DIGIT A R6,R1 INC R0 BLWP @VMBW RT********************************************************************************** TIME DELAY ROUTINE **DELAY LI R9,>FFFFDLOOP DEC R9 JNE DLOOP RT********************************************************************************** BEEP SOUND ROUTINE **PLYSND LIMI 0 LI R10,BUFFER LOAD SOUND TABLE ADDRESS MOV R10,@>83CC POINT TO THE TABLE SOCB @BONE,@>83FD SET VDP FLAG MOVB @BONE,@>83CE TRIGGER SOUND PROCESSING LIMI 2 RT********************************************************************************** COMPUTER WINS ROUTINE **CWIN SBZ 22 STOP THE COMPUTER CONTROLLED CAR LI R0,814 LI R1,COMWIN LI R2,11 BLWP @VMBWILOOP JMP ILOOP RT********************************************************************************** PLAYER WINS ROUTINE **PWIN SBZ 22 STOP THE PLAYER CONTROLLED CAR LI R0,814 LI R1,PLYWIN LI R2,11 BLWP @VMBWILOOP1 JMP ILOOP1 RT******************************************************************************** END START
Below is the video of the experimentation and the completed project:
https://youtu.be/TNhTnfGklIg
That was a fun one
- 10
8 Comments
Recommended Comments