10 REM RECORDER 20 REM Keith Anderson 30 REM (c) CET 1983 Published by BBC Publications 40 REM version 2.0 50 : 60 CLEAR 70 REM PORT SETUP 80 port = &FE60 :REM User port (see manual for details). 90 ?&FE62 = 15 :REM 00001111; 0 = input; 1 = output 100 PROCmotors_on 110 : 120 REM USER AREA 130 Xfactor = 1.175 :REM Adjust slightly on inaccurate TV sets 140 speedcontrol = 1 :REM Higher values make the Buggy slower 150 : 160 REM MAIN PROGRAM 170 REM Detect arrow keys 180 *FX 4,1 190 MODE 7 200 PROCsetup_general 210 PROCsetup_program 220 : 230 ON ERROR IF ERR=17 THEN GOTO 250 ELSE PROCend:REPORT:PRINT " on line"ERL:END 240 PROCintroduction 250 MODE7 260 IF (?port AND 32) THEN PROCnogo : PROCend : END:REM Check if Buggy connected 270 PROCoff :REM Cursor off 280 REPEAT 290 VDU 26 :REM Reset text & graphics windows 300 CLS 310 PROCmenu 320 IF option=1 THEN MODE 4 : PROCrecord : MODE 7 330 IF option=2 THEN MODE 4 : PROCdo : MODE 7 340 IF option=3 THEN MODE 4 : PROCscale : MODE 7 350 UNTIL option=4 360 : 370 MODE 7 380 PROCcomplete 390 END 400 : 410 : 420 REM PROCEDURES SPECIFICALLY FOR "RECORDER" 430 DEF PROCdo 440 PROCoff 450 IF mem%(1)=0 OR NOT enoughspace THEN PROCnomem ELSE PROCdo_again 460 ENDPROC 470 : 480 DEF PROCdo_again 490 LOCAL move,motor 500 VDU 19,1,7;0; :REM White foreground 510 VDU 19,0,1;0; :REM Red background 520 PROCget_ready 530 VDU 19,1,4;0; :REM Blue foreground 540 VDU 19,0,7;0; :REM White background 550 PROCcentre ("Repeating the route in memory.",6) 560 num = 0 570 room = TRUE 580 PROCupdate 590 angle = 0 600 REPEAT 610 IF room THEN PROCinc_pointer 620 move = INSTR(letter$,mem$(num))-1 630 motor = mem%(num) 640 PRINT TAB(1,2) num 650 PRINT TAB(34,2) mem$(num);". " 660 IF move=forwards OR move=backwards THEN PRINT TAB(36,2) INT(mem%(num)*FWD+0.5) 670 IF move=left OR move=right THEN PRINT TAB(36,2) mem%(num) 680 IF move<>3 THEN PROCmove_buggy (move,motor,bumpers) 690 IF hit THEN PROCcrash (hit) 700 UNTIL move=3 710 PROCcentre ("Route completed",4) 720 PROCspace (6) 730 ENDPROC 740 : 750 DEF PROCget_ready 760 VDU 26 :REM Reset text and graphics windows 770 CLS 780 PROCscreen :REM Draw "Instrument panel" 790 VDU 26 :REM Reset text and graphics windows 800 PROCcentre (program_name$,1) 810 VDU 29,640-(horiz DIV 2*Xscale);320;:REM Set Graphics origin 820 PROCboundary (0,0,horiz,vert) 830 VDU 28,0,31,39,24 :REM Text window 840 BGX = horiz DIV 2 850 BGY = 12 860 PROCcalcpos 870 PROCcalcbug (GRX,GRY,0) 880 PROCdrawbug 890 oldX = GRX : oldY = GRY :REM Save screen position 900 PROCspace (6) 910 REPEAT UNTIL INKEY (nokey) 920 ENDPROC 930 : 940 DEF PROCinc_pointer 950 num = num + 1 960 IF num >= size-1 THEN PROCno_space 970 ENDPROC 980 : 990 DEF PROCintroduction 1000 CLS 1010 PROCoff 1020 PROCdouble (CHR$130 +program_name$ +CHR$135,-1,5) 1030 PROCcentre ("Drive the Buggy manually.",12) 1040 PROCcentre ("The route can then be re-run",14) 1050 PROCcentre ("on 'automatic'.",16) 1060 PROCspace ( 21 ) 1070 ENDPROC 1080 : 1090 DEF PROCmanual 1100 I$ = FNwait 1110 IF INKEY (uparrow ) THEN PROCmove (forwards ,uparrow ,bumpers) 1120 IF INKEY (downarrow ) THEN PROCmove (backwards,downarrow ,nosensors) 1130 IF INKEY (leftarrow ) THEN PROCmove (left ,leftarrow ,bumpers) 1140 IF INKEY (rightarrow) THEN PROCmove (right ,rightarrow,bumpers) 1150 ENDPROC 1160 : 1170 DEF PROCmenu 1180 CLS 1190 PROCdouble (CHR$130 +program_name$ +CHR$135,-1,5) 1200 PRINT TAB(0,1) CHR$130 +"BBC Buggy" 1210 PRINT TAB(7,10) "1. Drive and record." 1220 PRINT TAB(7,12) "2. Repeat route in memory." 1230 PRINT TAB(7,14) "3. Reset scale" 1240 PRINT TAB(7,16) "4. Exit program." 1250 PRINT TAB(3,20) "Your choice: "; 1260 option = VAL( FNinput (1,"1234")) 1270 ENDPROC 1280 : 1290 DEF PROCmove (direction,key,sensors) 1300 LOCAL count 1310 SOUND 1,-8,42+direction*4,-1 1320 ?port = direction :PROCdelay(speedcontrol) 1330 IF direction=left THEN PRINT TAB(16,2)box$ box$ 1340 IF direction=right THEN PRINT TAB(23,2)box$ box$ 1350 REPEAT 1360 ?port = direction OR 2 1370 ?port = direction 1380 count = count+1 1390 IF direction = forwards THEN distance = distance + 1 1400 IF direction = backwards THEN distance = distance - 1 1410 IF direction = left THEN turn = turn - 1 1420 IF direction = right THEN turn = turn + 1 1430 IF sensors THEN hit = (?port AND sensors) 1440 IF count MOD 45 = 0 THEN PROCbug:PROCtemp_update 1450 PRINT TAB(19,2) (360+angle+turn) MOD 360 1460 UNTIL (INKEY (key) = FALSE) OR hit 1470 PRINT TAB(16,2)" " TAB(23,2)" " 1480 ?port = 0 1490 REM Flush buffers 1500 *FX 15 1510 IF record_on THEN PROCupdate_mem (direction,count) 1520 PROCbug 1530 PROCupdate 1540 IF hit THEN PROCcrash (hit) 1550 ENDPROC 1560 : 1570 DEF PROCnomem 1580 CLS 1590 VDU 19,0,1,0,0,0 :REM Red background 1600 COLOUR 129 1610 COLOUR 0 1620 PROCedge 1630 PROCcentre ("",5) 1640 PROCcentre (program_name$,6) 1650 PROCcentre ("",7) 1660 PROCcentre ("",14) 1670 PROCcentre ("NO ROUTE IN MEMORY",15) 1680 PROCcentre ("",16) 1690 COLOUR 128 1700 COLOUR 1 1710 PROCspace (24) 1720 ENDPROC 1730 : 1740 DEF PROCno_space 1750 VDU 7 1760 VDU 4 1770 PROCcentre ("No more space for instructions.",6) 1780 room = FALSE 1790 mem$(num) = "S" 1800 mem%(num) = 0 1810 PROCspace (4) 1820 ENDPROC 1830 : 1840 DEF PROCrecord 1850 PROCoff 1860 IF NOT enoughspace THEN PROCscale 1870 VDU 19,1,7;0; :REM White foreground 1880 VDU 19,0,1;0; :REM Red background 1890 PROCget_ready 1900 VDU 19,1,4;0; :REM blue foreground 1910 VDU 19,0,7;0; :REM white background 1920 PROCcentre ("Use the arrow keys to drive the Buggy",4) 1930 PROCcentre ("",6) 1940 num = 0 1950 room = TRUE 1960 angle=0 1970 PROCupdate 1980 *FX 229,1 1990 REM Disable ESCAPE 2000 REPEAT 2010 PROCmanual 2020 PRINT TAB(1,2) num 2030 UNTIL INKEY(escape) 2040 *FX 229 2050 REM Re-enable ESCAPE 2060 num = num + 1 2070 mem$(num) = "S" 2080 mem%(num) = 0 2090 ENDPROC 2100 : 2110 DEF PROCscale 2120 scale = 10 2130 Xscale = scale * Xfactor 2140 VDU 19,1,7;0; :REM white foreground 2150 VDU 19,0,1;0; :REM red background 2160 CLS 2170 PROCcentre ("Place the Buggy in its area as shown,",2) 2180 PROCcentre ("with the wheels 12 cms from the edge.",4) 2190 PROCrectangle (226,288,1054,800) 2200 PRINT TAB(19,8) "N" TAB(9,14) "W" TAB(30,14) "E" 2210 VDU 29,0;288; :REM Reset graphics origin 2220 PROCcalcpos 2230 PROCcalcbug (640,12*scale,0) 2240 PROCdrawbug 2250 VDU 28,1,30,38,24 :REM Make text window 2260 VDU 29,0;0; :REM Reset graphics origin 2270 enoughspace = FALSE 2280 REPEAT 2290 CLS 2300 PROCedge 2310 PRINT TAB(36,1) "cm" 2320 PRINT TAB(0,1) "Enter distance West to East "; 2330 horiz = VAL(FNinput(3,digit$)) 2340 PRINT TAB(36,3) "cm" 2350 PRINT TAB(0,3) "Enter distance North to South "; 2360 vert = VAL(FNinput(3,digit$)) 2370 IF FNmin (horiz,vert)0 THEN MOVE LBX,LBY:PLOT 6,FMX,FMY:hit = -1 3520 IF (bumper AND rightbumper)<>0 THEN MOVE RBX,RBY:PLOT 6,FMX,FMY:hit = 1 3530 SOUND 0,-15,9+hit,4 :REM Different sound for each bumper 3540 VDU 29,0;0; :REM Graphics origin 3550 VDU 24,510;220;800;700; :REM Graphics window 3560 MOVE 510,270 : MOVE 580,270 3570 PLOT 86+hit,580,220 :REM Only the relevant triangle is filled 3580 MOVE 730,270 : MOVE 800,270 3590 PLOT 86-hit,730,220 3600 VDU 29,640-horiz DIV 2 * Xscale;320;:REM Graphics origin 3610 PROCboundary (0,0,horiz,vert) 3620 PROCmove_buggy (backwards,safedistance,nosensors) 3630 VDU 29,0;0; :REM Graphics origin 3640 VDU 24,510;220;800;700; :REM Graphics window 3650 MOVE 510,270 : MOVE 580,270 3660 PLOT 87,580,220 :REM Delete both triangles 3670 MOVE 730,270 : MOVE 800,270 3680 PLOT 87,730,220 3690 VDU 29,640-horiz DIV 2 * Xscale;320;:REM Graphics origin 3700 PROCboundary (0,0,horiz,vert) 3710 ENDPROC 3720 : 3730 DEF PROCdrawbug 3740 REM Ensures good corners at rear 3750 MOVE LBX,LBY 3760 PLOT 6,RBX,RBY 3770 MOVE RLX,RLY 3780 PLOT 30,FLX,FLY 3790 MOVE RLX,RLY 3800 PLOT 30,RRX,RRY 3810 PLOT 30,FRX,FRY 3820 PLOT 70,RLX,RLY 3830 ENDPROC 3840 : 3850 DEF PROCend 3860 REM Switches motors off, resets cursor, EDIT & ESCAPE keys, buffers, and PRINT format 3870 PROCmotors_off 3880 PROCon 3890 *FX 4 3900 *FX 229 3910 *FX 15 3920 @% = 10 3930 ENDPROC 3940 : 3950 DEF PROCmotors_off 3960 ?port = 8 3970 ENDPROC 3980 : 3990 DEF PROCmotors_on 4000 ?port = 0 4010 ENDPROC 4020 : 4030 DEF PROCmove_buggy (direction,move,sensors) 4040 count = 0 4050 hit = 0 4060 REPEAT 4070 count = count + 1 4080 ?port = direction :PROCdelay (speedcontrol) 4090 ?port = direction OR 2:PROCdelay (speedcontrol) 4100 hit = (?port AND sensors) 4110 UNTIL hit OR count>=move 4120 ?port=0 4130 IF direction = left THEN turn = turn - count 4140 IF direction = right THEN turn = turn + count 4150 IF direction = backwards THEN distance = distance - count 4160 IF direction = forwards THEN distance = distance + count 4170 PROCbug 4180 PROCupdate 4190 ENDPROC 4200 : 4210 DEF PROCnogo 4220 PROCcentre ("Buggy not connected, END OF PROGRAM.",21) 4230 PRINT 4240 ENDPROC 4250 : 4260 DEF PROCscreen 4270 REM "Instrument panel" 4280 VDU 28,0,30,39,24 :REM Text window 4290 CLS 4300 RESTORE 4310 FOR index = 1 TO 14 4320 READ M1,M2,D1,D2 4330 MOVE M1,M2 4340 DRAW D1,D2 4350 NEXT index 4360 PRINT TAB(1,0) "No." 4370 PRINT TAB(6,0) "Position" 4380 PRINT TAB(19,0) "Deg" 4390 DATA 6, 280,1270, 280, 6, 210, 500, 210, 590, 210, 720, 210 4400 DATA 810, 210,1010, 210, 6, 140,1270, 140, 1070, 210,1270, 210 4410 DATA 150, 280, 150, 140, 500, 280, 500, 140, 590, 280, 590, 140 4420 DATA 720, 280, 720, 140, 810, 280, 810, 140, 1010, 280,1010, 140 4430 DATA 1070, 280,1070, 140, 1170, 280,1170, 210 4440 PROCedge 4450 ENDPROC 4460 : 4470 DEF PROCsetup_general 4480 REM Buggy dimensions are in centimetres 4490 BF = 3.9 :REM Buggy centre to bumper 4500 BR = 9 :REM Buggy centre to chassis rear 4510 CW = 6 :REM Half chassis width 4520 BW = 9 :REM Bumper width (1 side) 4530 FWD = 0.1431944:REM Travel (cms/pulse) 4540 safedistance = ( INT( SQR( BR*BR + CW*CW ) -BF )) / FWD +14 4550 REM Values to compare with port 4560 bumpers = 192 4570 leftbumper = 128 4580 rightbumper = 64 4590 nosensors = 0 4600 REM Keyboard control words 4610 uparrow = -58 4620 downarrow = -42 4630 leftarrow = -26 4640 rightarrow = -122 4650 space = -99 4660 nokey = -129 4670 escape = -113 4680 REM Port values for Buggy movement 4690 forwards = 0 4700 backwards = 5 4710 left = 4 4720 right = 1 4730 digit$ = "1234567890" :REM Acceptable characters for numeric input 4740 space$ = STRING$(36," ") 4750 @% = &303 :REM Print format 4760 ENVELOPE 3,1,5,-5,5,10,10,10,5,0,-1,-1,126,0 4770 ENDPROC 4780 : 4790 DEF PROCupdate 4800 PRINT TAB(6,2) INT(BGX+0.5) "," INT(BGY+0.5) 4810 angle = (360+angle) MOD 360 4820 PRINT TAB(19,2) angle 4830 ENDPROC 4840 : 4850 DEF PROCwarn (text$) 4860 PROCcentre (text$,4) 4870 SOUND &103,3,100,10 4880 SOUND &102,3,117,10 4890 ENDPROC 4900 : 4910 DEF PROCcentre(text$,line):PRINT TAB(1,line)SPC38:PRINT TAB(FNcentre(text$),line)text$;:ENDPROC 4920 DEF FNcentre(text$)=19-LEN(text$)DIV2 4930 DEF PROCcomplete:CLS:PROCdouble(CHR$131+"Mission completed.",-1,10):PROCend:ENDPROC 4940 DEF PROCdelay(period):LOCAL index:FOR index=1TOperiod:NEXT index:ENDPROC 4950 DEF PROCdouble(text$,X,Y):IF X<0THEN X=FNcentre(text$) 4960 PRINT TAB(X-1,Y)CHR$141;text$:PRINT TAB(X-1,Y+1)CHR$141;text$:ENDPROC 4970 DEF PROCedge:PROCrectangle(6,6,1274,1018):ENDPROC 4980 DEF FNinput(length,allowed$):LOCAL input$,ascii:PRINT STRING$(length,".");STRING$(length,CHR$8);:PROCon:*FX15 4990 REPEAT ascii=ASC FNwait:IF ascii=127ANDLEN(input$)>0THEN input$=LEFT$(input$,LEN(input$)-1):VDU ascii 5000 IF INSTR(allowed$,CHR$ ascii)AND LEN(input$)13ANDascii<>127THEN ascii=7 5010 IF ascii=13ANDLEN(input$)<1THEN ascii=7 5020 IF ascii=127THEN VDU46,8ELSE VDU ascii 5030 UNTIL ascii=13:PRINT:PROCoff 5040 =input$ 5050 DEF FNlimit(X,Y,X1,Y1,X2,Y2):IF X>X1 AND XY1 AND YB THEN =A ELSE =B 5070 DEF FNmin(A,B):IF A"":*FX4 5150 =I$