Jump to content
  • entries
  • comments
  • views

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:


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):


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:


That was a fun one :)

  • Like 8


Recommended Comments

Oh yes, I totally enjoyed your video and blog entry. In fact I never remember enjoying one more than this.


I hope you take another video at the Chicago get-together of this in head to head matches with other TI'ers. I'm betting the TI will win most matches. Sorry guys.


Pulse modulation, was an elegant solution to the problem. I bet some model railroaders will be looking into this with keen interest as well.


So far, how many digital inputs is the TI capable of tracking in total? Could the software be modified (at a future point) to accept strength values (high / low) to double the amount of input capability?


Great job Walid!

  • Like 1

Share this comment

Link to comment

Oh yes, I totally enjoyed your video and blog entry. In fact I never remember enjoying one more than this.


I hope you take another video at the Chicago get-together of this in head to head matches with other TI'ers. I'm betting the TI will win most matches. Sorry guys.


Pulse modulation, was an elegant solution to the problem. I bet some model railroaders will be looking into this with keen interest as well.


So far, how many digital inputs is the TI capable of tracking in total? Could the software be modified (at a future point) to accept strength values (high / low) to double the amount of input capability?


Great job Walid!


Thanks :) It was really fun to develop, but I have to say that the project would not have come to fruition were it not for your initial suggestion to use the cassette motor port to power a relay for the rocket engine igniter test. I had never thought of that previously!


There are only 8 inputs on the PIO port, although we could add a couple more if we use the handshake in and the spare in lines as well. So 10 total. That said however, if you wire external inputs to trigger more than one pin on the PIO port, you could differentiate these kinds of input discreetly through masking in software, so theoretically several 2^8 inputs could be accommodated...

  • Like 1

Share this comment

Link to comment

Nicely done. I got to try making my own PCBs.


Here's where I learned how to do it. I think making one's own PCB really makes a project truly homebrew :) Back in the early 90's, I used an etching pen and hand drawn circuits, which worked but only for the crudest of circuits!


Share this comment

Link to comment

When I did my slot car racing controller some years ago, I had a speed control consisting of a few outputs, driving relays which bridged a resistor each in a resistor ladder. This kind of gave me a functionality corresponding to different gears in a car.

I also had a photo cell at the start of each track segment, after which I first ran one "gear" for a certain time, then another "gear" forever. The last gear was slow enough to allow the car to run around the track without de-railing. This allowed putting the car back on track anywhere. It would just run at medium speed until it was picked up by some photo cell, then continued at optimized speed from there.

Share this comment

Link to comment
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Create New...