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