Jump to content
  • entries
    11
  • comments
    44
  • views
    13,289

Heathkit Hero Jr Robot Wireless Communication and Control with a TI 99/4A computer

Sign in to follow this  
Vorticon

229 views

The Heathkit Hero Jr robot came out in 1984 as a more home friendly version of the original Hero 1 robot, but was still equipped with multiple sensors, speech and programming capabilities albeit without a robotic arm attachment. I bought my robot on Ebay and upgraded it with extra memory (24K), an updated ROM, serial communication and a multi-cartridge which combined all of the cartridges produced for the Hero Jr into one master cart, as well as a beefy 10Ah battery and full documentation. The Robot Workshop (https://www.robotworkshop.com/robotweb/) still has most parts, upgrades and documentation for the Hero Jr at very reasonable prices.

 

Heathkit HERO Jr.jpg

 

Manufacturer Heathkit
Type robot
Release date 1984
Introductory price Kit US$599.95,
Assembled US$1000[3]
Discontinued Before October 1987 (Assembled)[15]
1995 (Kit)
Units sold 4000 (across 8 years)
CPU Motorola 6808 1 MHz
Memory RAM: 2 kB, expandable to 24 kB
Monitor ROM: 32 kB
Display 9 LEDs
Sound Votrax SC-01 speech synthesizer[5]
Input Hex keypad with 17 keys
Power Batteries:6 V 3.8 A·h x2, x4 optional
Dimensions 19 inches high[16]
Mass 21.5 pounds[16]

 

The interesting thing is that all the electronics are located in the "head" of the robot and under the front panel, while the drive mechanism and battery are in the bottom part, leaving most of the mid-section open, which was very inviting for modifications and modern upgrades. And while I dabbled with this idea for a while, I ended up deciding not to modify the robot from its original condition and opting to experiment with using the serial port as the only means of communication with it. The Hero Jr is capable of baud rates from 300 to 9600 with Even parity and 7 data bits.

 

An early experiment I did involved a wired serial connection to a Raspberry Pi Model B where I had a Pi camera recognize a ball using the OpenCV framework running on the Rpi, and the result was communicated to the Hero Jr who in turn verbalized it using its on-board speech synthesizer:

 

 

This served as a proof of concept, but I really wanted to ditch the serial tether and go completely wireless. I also wanted to use the TI 99/4A computer, and I already had quite a bit of experience with wireless serial communication on it from my previous wireless weather station project:

 

 

The main problem I ran into was the the Xbee transceiver I used for that project did not support 7 data bits, only 8, and it turned out that almost all available modern transceivers had the same issue!. Luckily, I finally was able to find a very cheap Chinese transceiver called the HC-12 which costs less than $5 per module and supports a wide range of communication parameters. 

 

Image result for hc-12 wireless serial communication module

 

It's really designed for use with an Arduino, but with the addition of a GPIO to serial converter, one can connect it to a standard computer terminal.

 

Image result for serial to gpio

 

From there, I went through a couple of experimental tests as shown below. The main difficulty encountered was the very short range of the coil antenna that comes stock with the HC-12 module, and so this required upgrading it to beefier coax antenna.

 

 

 

From there I was finally ready to put the project together using the TI 99/4A computer. I opted to use RXB on the TI side because it allowed low-level access to the serial card using the CALL IO command, something not available on other Basics. This was necessary because the HC-12 was not very reliable in its wireless transmissions and communication was frequently dropped, thus requiring a form of communication time-out feature in order to resend dropped data packets. 

Here's the code for the TI. You might note that there are a lot of repetitive routines which could not be consolidated into subroutines because the ON ERROR command in Extended Basic does not work within subroutines.

 

// HERO Jr remote exploration program
// November 2019

// INITIALIZATION
CALL CLEAR
OPTION BASE 1
DIM MAP(23,32)
HOMEX=16
HOMEY=12
PRANGE=0
TCOUNT=0
DIR=1 !1=N 2=E 3=S 4=W
OPEN #1:"RS232.BA=9600.DA=7.PA=E.EC",UPDATE
CRU=2464 !CRU ADDRESS OF TMS9902 (>1340) DIVIDED BY 2

// CHECK IF ROBOT IS READY  
PRINT "CHECKING ROBOT STATUS"
CheckStatus:
CALL IO(3,1,CRU+18,0)
PRINT #1:65
GOSUB BytePresent
IF FLAG=0 THEN
	CheckStatus
Status:
ON ERROR Status
INPUT #1:ANS$
ON ERROR STOP
IF VAL(ANS$)<> 1 THEN CheckStatus 
ELSE PRINT "ROBOT IS READY!": :
PRINT "PRESS ANY KEY TO START"
GetKey:
CALL KEY(0,K,S)
IF S=0 THEN GetKey

// SET UP DISPLAY
CALL CLEAR
// CHARACTER DEFINITIONS
CALL CHAR(104,"FFFFFFFFFFFFFFFF") !BLACK LEVEL 0-20
CALL CHAR(112,"FFFFFFFFFFFFFFFF") !GRAY LEVEL 21-100
CALL CHAR(120,"FFFFFFFFFFFFFFFF") !WHITE LEVEL 101-255
CALL CHAR(105,"FFC3A59999A5C3FF") !OBSTACLE
CALL CHAR(106,"183C5A9918181818") !UP ARROW
CALL CHAR(107,"080402FFFF020408") !RIGHT ARROW
CALL CHAR(108,"18181818995A3C18") !DOWN ARROW
CALL CHAR(109,"102040FFFF402010") !LEFT ARROW

DIRSPR=106

CALL COLOR(10,2,16,11,15,16,12,16,16)
CALL SPRITE(#1,DIRSPR,9,(HOMEY-1)*8+1,(HOMEX-1)*8+1)

// START EXPLORATION
RX=HOMEX
RY=HOMEY

Explore:
TCOUNT=TCOUNT+1
IF TCOUNT>10 THEN 
	Home
// GET LIGHT LEVEL
LightInput:
CALL IO(3,1,CRU+18,0) !CLEAR RECEIVE BUFFER
PRINT #1:6 !Read light sensor
GOSUB BytePresent !WAIT FOR BYTE TO COME IN
IF FLAG=0 THEN
	LightInput
Status1:
ON ERROR Status1
INPUT #1:LIGHT$
ON ERROR STOP
IF VAL(LIGHT$)<21 THEN CALL HCHAR(RY,RX,104) 
	ELSE IF VAL(LIGHT$)<101 THEN CALL HCHAR(RY,RX,112)
		ELSE CALL HCHAR(RY,RX,120)
CALL DELAY(1)

// Check for movement in front of robot
MotionCheck:
CALL IO(3,1,CRU+18,0) ! CLEAR RECEIVE BUFFER
PRINT #1:8 !Read infrared sensor
GOSUB BytePresent
IF FLAG=0 THEN
	MotionCheck
Status7:
ON ERROR Status7
INPUT #1:HEAT$
ON ERROR STOP
IF VAL(HEAT$)=0 THEN 
	RangeInput
DISPLAY AT(24,1)BEEP:"MOTION DETECTED!"
Speak1:
CALL IO(3,1,CRU+18,0) !CLEAR RECEIVE BUFFER
PRINT #1:9 !Speak 
CALL DELAY(1)
PRINT #1:1 !PLEASE MOVE CLEAR OF ME
GOSUB BytePresent
IF FLAG=0 THEN
	Speak1
Status8:
ON ERROR Status8
INPUT #1:ANS$
ON ERROR STOP
IF VAL(ANS$)<>89 THEN 
	Speak1
DISPLAY AT(24,1):"                         "
GOTO MotionCheck

// Check for obstacles
RangeInput:
CALL IO(3,1,CRU+18,0) !CLEAR RECEIVE BUFFER
PRINT #1:7	!Read sonar
GOSUB BytePresent
IF FLAG=0 THEN
	RangeInput
Status2:
ON ERROR Status2
INPUT #1:RANGE$
ON ERROR STOP
IF VAL(RANGE$)>40 AND ((DIR=1 AND RY>2) OR (DIR=2 AND RX<31) OR (DIR=3 AND RY<22) OR (DIR=4 AND RX>2)) THEN
	GOTO PathClear
IF DIR=1 THEN 
	CALL HCHAR(RY-1,RX,105)::
	MAP(RY-1,RX)=1
IF DIR=2 THEN 
	CALL HCHAR(RY,RX+1,105)::
	MAP(RY,RX+1)=1
IF DIR=3 THEN 
	CALL HCHAR(RY+1,RX,105)::
	MAP(RY+1,RX)=1
IF DIR=4 THEN 
	CALL HCHAR(RY,RX-1,105)::
	MAP(RY,RX-1)=1
Speak2:
CALL IO(3,1,CRU+18,0) !CLEAR RECEIVE BUFFER
PRINT #1:9 !Speak
CALL DELAY(1)
PRINT #1:2 !OBSTACLE DETECTED
GOSUB BytePresent
IF FLAG=0 THEN
	Speak2
StatusObs:
ON ERROR StatusObs
INPUT #1:ANS$
ON ERROR STOP
IF VAL(ANS$)<>89 THEN 
	Speak2

//Back up
Reverse:
CALL IO(3,1,CRU+18,0) !CLEAR RECEIVE BUFFER
PRINT #1:2
GOSUB BytePresent
IF FLAG=0 THEN
	Reverse
Status3:
ON ERROR Status3
INPUT #1:ANS$
ON ERROR STOP
IF ANS$<>"89" THEN Reverse
IF DIR=1 THEN RY=RY+1
IF DIR=2 THEN RX=RX-1
IF DIR=3 THEN RY=RY-1
IF DIR=4 THEN RX=RX+1
CALL LOCATE(#1,(RY-1)*8+1,(RX-1)*8+1)
CALL DELAY(2)

//Check for surrounding blocked path
IF DIR=1 THEN
	CALL GCHAR(RY,RX+1,BLOCK)::
	GOTO Turn
IF DIR=2 THEN
	CALL GCHAR(RY+1,RX,BLOCK)::
	GOTO Turn
IF DIR=3 THEN 
	CALL GCHAR(RY,RX-1,BLOCK)::
	GOTO Turn
CALL GCHAR(RY-1,RX,BLOCK)

Turn:
IF BLOCK<>105 THEN
		Go_Right
	ELSE
		Go_Left

//Turn right	
Go_Right:
CALL IO(3,1,CRU+18,0) !CLEAR RECEIVE BUFFER
PRINT #1:4
GOSUB BytePresent
IF FLAG=0 THEN
	Go_Right
Status4:
ON ERROR Status4
INPUT #1:ANS$
ON ERROR STOP
IF ANS$<>"89" THEN Go_Right
DIR=DIR+1
DIRSPR=DIRSPR+1
IF DIR>4 THEN DIR=1::DIRSPR=106
CALL PATTERN(#1,DIRSPR)
CALL DELAY(2)
IF HFLAG=1 THEN
	Home
GOTO Explore	

//Turn left
Go_Left:
CALL IO(3,1,CRU+18,0) !CLEAR RECEIVE BUFFER
PRINT #1:5	
GOSUB BytePresent
IF FLAG=0 THEN
	Go_Left
Status6:
ON ERROR Status6
INPUT #1:ANS$
ON ERROR STOP
IF ANS$<>"89" THEN Go_Left
DIR=DIR-1
DIRSPR=DIRSPR-1
IF DIR<1 THEN DIR=4::DIRSPR=109
CALL PATTERN(#1,DIRSPR)
CALL DELAY(2)
IF HFLAG=1 THEN
	Home
GOTO Explore

//Move forward
PathClear:
CALL DELAY(1)
Forward:
CALL IO(3,1,CRU+18,0) !CLEAR RECEIVE BUFFER
PRINT #1:3
GOSUB BytePresent
IF FLAG=0 THEN
	Forward
Status5:
ON ERROR Status5
INPUT #1:ANS$
ON ERROR STOP
IF ANS$<>"89" THEN Forward
IF DIR=1 THEN RY=RY-1
IF DIR=2 THEN RX=RX+1
IF DIR=3 THEN RY=RY+1
IF DIR=4 THEN RX=RX-1
CALL LOCATE(#1,(RY-1)*8+1,(RX-1)*8+1)
CALL DELAY(2)
IF HFLAG=1 THEN
	Home
GOTO Explore

// Go home routine
Home:
HFLAG=1
IF RX=HOMEX AND RY=HOMEY THEN
	DISPLAY AT(24,1)BEEP:"AT HOME!"::
	GOTO GetKey1
ELSE
	DISPLAY AT(24,1)BEEP:"GOING HOME..."
	
Speak3:
CALL IO(3,1,CRU+18,0) !CLEAR RECEIVE BUFFER
PRINT #1:9 !Speak
CALL DELAY(1)
PRINT #1:3 !GOING HOME
GOSUB BytePresent
IF FLAG=0 THEN
	Speak3
StatusHome:
ON ERROR StatusHome
INPUT #1:ANS$
ON ERROR STOP
IF VAL(ANS$)<>89 THEN 
	Speak3
	
IF RY>HOMEY AND MAP(RY-1,RX)=0 THEN
	TDIR=1::
	GOTO CheckFacing
IF RY<HOMEY AND MAP(RY+1,RX)=0 THEN
	TDIR=3::
	GOTO CheckFacing
IF RX>HOMEX AND MAP(RY,RX-1)=0 THEN
	TDIR=4::
	GOTO CheckFacing
IF RX<HOMEX AND MAP(RY,RX+1)=0 THEN
	TDIR=2::
	GOTO CheckFacing
GOTO Explore

CheckFacing:
IF DIR<>TDIR THEN
	FacingTurn

ForwardH:
CALL IO(3,1,CRU+18,0) !CLEAR RECEIVE BUFFER
PRINT #1:3
GOSUB BytePresent
IF FLAG=0 THEN
	ForwardH
StatusHF:
ON ERROR StatusHF
INPUT #1:ANS$
ON ERROR STOP
IF ANS$<>"89" THEN ForwardH
IF DIR=1 THEN RY=RY-1
IF DIR=2 THEN RX=RX+1
IF DIR=3 THEN RY=RY+1
IF DIR=4 THEN RX=RX-1
CALL LOCATE(#1,(RY-1)*8+1,(RX-1)*8+1)
CALL DELAY(2)
GOTO Home

FacingTurn:
IF ABS(TDIR-DIR)>2 AND TDIR<DIR THEN
	TurnRightH
IF ABS(TDIR-DIR)>2 AND TDIR>DIR THEN
	TurnLeftH
IF TDIR<DIR THEN 
	TurnLeftH

TurnRightH:
CALL IO(3,1,CRU+18,0) !CLEAR RECEIVE BUFFER
PRINT #1:4
GOSUB BytePresent
IF FLAG=0 THEN
	TurnRightH
StatusHR:
ON ERROR StatusHR
INPUT #1:ANS$
ON ERROR STOP
IF ANS$<>"89" THEN TurnRightH
DIR=DIR+1
DIRSPR=DIRSPR+1
IF DIR>4 THEN DIR=1::DIRSPR=106
CALL PATTERN(#1,DIRSPR)
CALL DELAY(2)
GOTO CheckFacing

TurnLeftH:
CALL IO(3,1,CRU+18,0) !CLEAR RECEIVE BUFFER
PRINT #1:5	
GOSUB BytePresent
IF FLAG=0 THEN
	TurnLeftH
StatusHL:
ON ERROR StatusHL
INPUT #1:ANS$
ON ERROR STOP
IF ANS$<>"89" THEN TurnLeftH
DIR=DIR-1
DIRSPR=DIRSPR-1
IF DIR<1 THEN DIR=4::DIRSPR=109
CALL PATTERN(#1,DIRSPR)
CALL DELAY(2)
GOTO CheckFacing
	
// Resume exploration
GetKey1:
CALL KEY(0,K,S)
IF S=0 THEN GetKey1
DISPLAY AT(24,1):"                       "
HFLAG=0
GOTO Explore

// Check for incoming byte over serial line
BytePresent:
COUNTER=0
CheckByte:
CALL IO(2,1,CRU+21,BYTEIN)
IF BYTEIN=0 THEN 
	COUNTER=COUNTER+1
ELSE
	FLAG=1::
	RETURN
IF COUNTER>50 THEN 
	FLAG=0::
	DISPLAY AT(24,1)BEEP:"TIME OUT! RETRYING..."::
	CALL DELAY(1)::
	DISPLAY AT(24,1):"                     "::
	RETURN
ELSE
	GOTO CheckByte

// Delay routine
SUB DELAY(DUR)
FOR I=1 TO DUR*100
NEXT I
SUBEND

 

 

On the Hero Jr side, I ran a very simple Basic program which accepted coded commands mapped to specific robot functions and executed them, and also sent back sensor data and communication acknowledgments. All actual control and decision making was made by the TI.

 

1 REM HERO ROAM PROGRAM
10 INPUT C
20 IF C<>65 THEN GOTO 10
21 FOR I=1 TO 100:NEXT I
22 PRINT 1
30 INPUT C
35 IF C<1 THEN GOTO 30
36 IF C>9 THEN GOTO 30
40 ON C GOSUB 500,600,700,800,900,1000,1100,1200,1300
50 GOTO 30
500 REM FORWARD 5 UNITS
510 FWD 5
511 GOSUB 1510
515 PRINT 89
520 RETURN
600 REM BACKWARD 5 UNITS
610 BWD 5
611 GOSUB 1510
615 PRINT 89
620 RETURN
700 REM FORWARD 10 UNITS
710 FWD 10
711 GOSUB 1510
715 PRINT 89
720 RETURN
800 REM RIGHT ROTATION
810 RIGHT 90
811 GOSUB 1510
815 PRINT 89
820 RETURN
900 REM LEFT ROTATION
910 LEFT 90
911 GOSUB 1510
915 PRINT 89
920 RETURN
1000 REM LIGHT LEVEL DETECTION
1010 L=EYE
1011 GOSUB 1510
1015 PRINT L
1020 RETURN
1100 REM RANGE MEASUREMENT
1105 R=SONAR
1110 GOSUB 1510
1115 PRINT R
1120 RETURN
1200 REM INFRARED HEAT DETECTION
1210 I=MOTION
1211 GOSUB 1510
1215 PRINT I
1220 RETURN
1300 REM SPEAK FUNCTION
1305 INPUT C
1306 IF C<1 THEN GOTO 1305
1307 IF C>3 THEN GOTO 1305
1308 ON C GOTO 1310,1340,1370
1309 REM PLEASE MOVE CLEAR OF ME
1310 SPEAK "PLEZHPA1MOO1VPA1KLEERPA1OVPA1MEE"
1315 GOSUB 1510
1320 PRINT 89
1330 RETURN
1335 REM OBSTACLE DETECTED
1340 SPEAK "OBSTAEKLPA1DE1TEH3KTEHD"
1345 GOSUB 1510
1350 PRINT 89
1360 RETURN
1365 REM GOING HOME
1370 SPEAK "GOWINGPA1HO1O1MM"
1375 GOSUB 1510
1380 PRINT 89
1390 RETURN
1500 REM DELAY SUBROUTINE
1510 FOR T=1 TO 200:NEXT T
1520 RETURN
>


 

And here's the final result:

 

 

Another fun one :)

  • Like 2
Sign in to follow this  


0 Comments


Recommended Comments

There are no comments to display.

Guest
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.

Loading...
  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...