nungeste@hpspkla.spk.hp.com (Dick L. Nungester) (10/11/89)
This moon lander program for the HP-28S features simultaneous numeric and
overranging bar graph displays of height, velocity, fuel, and fuel flow
(thrust) all calibrated in MKS units. It also has blinking low- and no-
fuel indicators, a success or failure tune upon landing, and a "black doom"
instrument panel display if you crash.
The display during run-time looks like this:
hgt 1184 m |XXXXXXXXX
vel -14 m/s XXX|
fuel 500 l |XXXXXXXXX
flow 3 l/s |XXX
and updates every 1.1 seconds (on my HP-28S). The 13 programs will take a
while to key in. Once all exist in the same directory, run MOON. The
first time it runs, "Stand by..." will be seen for about 90 seconds while
variable initializations take place. On future runs this won't happen.
The program starts as the lunar lander's main retrorocket has cut off,
leaving it about 1300 meters above the lunar surface with 0 velocity and
manual thrusters off (free fall). Once the program is running, push keys 0
through 9 as fuel flow (thrust) values. 0 means free-fall, 5 means hold
current velocity constant, and 9 means hit the jets as hard as you can. A
displayed impact speed of 0 or 1 m/sec is a successful landing.
Once you get proficient, try to land with height, velocity, fuel, and flow
all at "0". The initial conditions were picked so that an optimum landing
takes about 300 liters of fuel, and you have 500 to start with. Can you
land with over 200 liters left? I have landed with 201 still available.
Comments are welcome. Send to:
Dick Nungester
[72257,2501] (CompuServe)
nungeste@hpspkla (UNIX mail)
(509) 921-3560 (work phone: Hewlett-Packard, Spokane, WA)
(509) 926-9048 (home phone, Spokane, WA)
----------------------------------------------------------------------------
Variable definitions:
=====================
Variables initialized by INIT that change value during run time and are
purged at the end of a program run by CLOSE:
H = Height above the lunar surface (meters, >0 is upward)
V = Velocity (meter/sec, >0 is moving upward)
F = Fuel remaining (liters -- arbitrary units)
R = fuel Rate (liter/sec, >0 is spending fuel)
RP = fuel Rate at Previous display update (liter/sec)
A = Acceleration (meter/sec^2, >0 is accelerating upward)
DT = Delta Time per execution loop (sec, 1.1 for my 28S)
Variables created by MVRS that stay from run to run of the program and
never change value. (Doing MVRS's one-time setup speeds execution.)
FST1 = Fuel STring #1 -- used to blink "fuel" when < 100 liter remain
FST2 = Fuel STring #2 -- used to blink "fuel 0" when fuel is gone
ISTR = Inversion STRing -- used to invert whole display when you crash
GBL = General Bar List (all height, fuel, and flow bar displays)
VBL = Velocity Bar List (all velocity bar displays)
Important equations:
Given H, V, F, and constant A and R for period DT, new values of H, V,
and F after time DT are:
H = H + V*DT + A*SQ(DT)/2
V = V + A*DT
F = F - R*DT
Fuel flow ("R", 0-9 l/s), and acceleration ("A", m/s^2) are linearly
related, with the following 2 points defining the relationship:
R A Notes
====== ============ =================
0 -1.62 free fall, 0 fuel flow
5 0 constant velocity, arbitrary fuel flow of 5
This means that upon sensing key 0 through 9 ("R"):
A = 1.62*(R/5 - 1)
--------------------------------------------------------------------------
Here are the programs. They are listed from "high-level" to low. Entering
them into the 28S in the reverse order given leaves MOON on the leftmost
key of the USER menu (most accessable position). The following strings
represent single characters in the 28S character set: "<=", ">=", "->",
"<-", "<<", ">>", "`root`" (square root).
MOON MOON main program.
<< INIT
DO VIEW KSCN EQS
UNTIL H 0 <=
END CLOSE
>>
INIT INITialize all variables. To make every
program run slightly different, height is +/- 50
meters about 1296. Existence of 'FST1' is used to
determine if all permanent varibles need creation.
<< RAND .5 - 100 *
1296 + 'H' STO 0 'V'
STO 500 'F' STO 0
'R' STO 1 'RP' STO
-1.62 'A' STO 1.1
'DT' STO 49 CF 50 CF STD display mode
CLLCD
IFERR 'FST1' RCL
THEN MVRS
END DROP
>>
MVRS Make permanent VaRiableS.
<< "Stand by..." 1
DISP 274 0 SBLD DUP
24 255 SBLD + 250 0
SBLD + 'FST1' STO 48 FST1 = 274 CHR(0)'s + 24 CHR(255)'s + 250 CHR(0)'s
255 SBLD + 226 0
SBLD + 'FST2' STO FST2 = 274 CHR(0)'s + 48 CHR(255)'s + 226 CHR(0)'s
548 255 SBLD 'ISTR' ISTR = 548 CHR(255)'s
STO 10 1 MBL 'GBL' GBL = 10 char bar graph with "0" in char #1
STO 10 9 MBL 'VBL' VBL = 10 char bar graph with "0" in char #9
STO
>>
SBLD String BuiLD. Return a string made up of n
CHR(chr) characters.
<< -> n chr
<< "" 1 n
START chr CHR +
NEXT
>>
>>
MBL Make Bar List. Accept the 's'ize of the bar list
in chararters and the location within the string of
the 'z'ero axis. Return a list of s+2 bar strings,
one for each possible value position plus overrange
and underrange.
<< -> s z
<< 0 s 1 +
FOR v "" 1 s v = 'v'alue represented by each bar string
FOR t t = 't'his char within each bar string
IF 't==1
AND v==0' EVAL
THEN "<<" + underrange; ("<<" is a single character)
ELSE
IF 't==s
AND v==s+1' EVAL
THEN ">>" + overrange; (">>" is a single character)
ELSE
IF 't==z
' EVAL
THEN 124 "|" character (to indicate zero location)
CHR +
ELSE
IF 't<
z AND t>=v OR t>z
AND t<=v' EVAL
THEN
127 CHR + "dark" part of bar
ELSE
" " + "light" part of bar
END
END
END
END
NEXT
NEXT s 2 + ->LIST
>>
>>
VIEW VIEW current status.
<<
IF F 100 < Low or no fuel?
THEN LCD->
IF F 0 >
THEN FST1 Low fuel. Invert "fuel".
ELSE FST2 No fuel. Invert "fuel 0"
END XOR ->LCD Invert display pixels.
END "hgt " H 4 FMT
+ " m " + H 0 1296
'GBL' 10 BAR + 1
DISP "vel " V 4 FMT
+ " m/s " + V -40 5
'VBL' 10 BAR + 2
DISP "fuel " F 3 FMT
+ " l " + F 0 500
'GBL' 10 BAR + 3
DISP If inverted above, this restores normal look.
IF R RP # Only update "flow..." if needed. "#" = "not equal".
THEN R 'RP' STO
"flow " R 1 FMT +
" l/s " + R 0 9
'GBL' 10 BAR + 4
DISP
END
>>
FMT ForMaT a number for display. Round to the nearest
integer value and return a string padded with
blanks to total 'n' characters. Assumes STD
display mode (as set in INIT).
<< -> n
<< .5 + FLOOR ->STR
WHILE DUP SIZE n
<
REPEAT " " SWAP
+
END
>>
>>
BAR select a BAR graph string. Accept a 'val'ue, the
'lo'w bar limit (number representing the center of
the leftmost character), the 'hi'gh bar limit
(number representing the middle of the rightmost
character), which 'blist' (bar list) to select
from, and the size of the strings in 'blist'.
Return the appropriate bar string from within
'blist'.
<< -> val lo hi blist
size
<< '2+(size-1)*((
val-lo)/(hi-lo))'
EVAL
IF DUP 1 <
THEN DROP 1
ELSE
IF DUP size 2
+ >
THEN DROP size
2 +
END
END .5 + FLOOR
blist SWAP GET
>>
>>
KSCN Keyboard SCaN.
<<
IF KEY
THEN
IF F 0 == If fuel is gone, ignore keyboard input.
THEN DROP
ELSE STR-> DUP
'R' STO 5 / 1 - 1.62 else store new Rate and Acceleration.
* 'A' STO
END
END
>>
EQS old status to new status EQuationS.
<< 'H' 'V*DT+A*SQ(DT)
/2' EVAL STO+ 'V' 'A
*DT' EVAL STO+ 'F' '
R*DT' EVAL STO-
IF F 0 < Clip fuel at 0 (can't go negative).
THEN 0 'F' STO 0
'R' STO -1.62 'A' If out of fuel, free-fall until impact.
STO
END
>>
CLOSE CLOSE the display and the program.
<< '-`root`(V^2-2*A*H)' Find impact velocity. "`root`" = "square root".
EVAL 'V' STO 0 'H' End with height = 0 always.
STO VIEW View final status.
IF V -1.5 >= If display is "0" or "-1" m/s,
THEN SBP success! Sound the victory charge.
ELSE LCD-> ISTR XOR else failure (blacken display and embarass user).
->LCD FBP
END { H V F R RP A Purge all temporary variables.
DT } PURGE
WHILE KEY Purge any queued-up before-landing keystrokes.
REPEAT DROP
END
>> End.
SBP Success BeeP. (The "victory charge")
<< 523 .1 BEEP 659 .1
BEEP 784 .1 BEEP
1047 .1 BEEP .1 WAIT
784 .1 BEEP 1047 .8
BEEP
>>
FBP Failure BeeP. (The "death dirge".)
<< 1 3
START 220 .1 BEEP
.1 WAIT
NEXT 175 .8 BEEP
>>