Lunar Lander for 1.0.6

nickcinquino: I've started looking up the essential equations needed to write a new version from scratch...this could take a while!

In former times I'veplayed a acouple of lunar lander simulations and when "Turbo Pascal" was a leading compiler for hobbyist programmers I think I played around with some lunar lander source codes in Turbo Pascal for myself.

I think most of the lander programs were not very realistic in their simulation. They simply assumed that the lander appears suddenly in a given height above the moon and starts free-falling down, while the player has to brake the free-fall until he reaches height=0 at a descent rate of 0.

More realistic simulations would consider the real descent: The lander starts from a lunar orbit with a relatively high horizontal speed and a very small or zero vertical(falling) speed. Like shown in this NASA document, which provides a detailed description of the Apollo-17 "lunar module powered descent" from the moon orbit to landing: http://www.braeunig.us/apollo/LM-descent.htm

Two more interesting documents might be these:

NASA quick reference with data about lunar lander module (weight of module and propellent

Wikipedia page about the lunar module: Wikipedia page about the lunar module

I hope the links and the information provided there can help in writing a new and better simulation.

nickcinquino: Hi Tom, Jurs, JRemington and PaulRB, Thanks for the continued research, and posting code! The new one does verify but does the same thing on my system (allows the fuel burn rate setting to be entered but then goes no further, no update of speed, weight,etc). Is the IDE critical? Which IDE is best to use?

Would it greatly simplify things to remove all of the serial.Write data inputs and input an integer from a pot at A5 instead? I've started looking up the essential equations needed to write a new version from scratch...this could take a while!

-Nick

Hi, did you.

Try this, you will need to select "Carriage Returrn" as well as 115200baud. It has a error message on the monitor when you run the monitor but it doesn't stop the code.

In the monitor, otherwise it appears to be swallowing your entry. Select Carriage Return in the monitor. Tom..... :) IDE 1.6.7

I think most of the lander programs were not very realistic in their simulation.

I don't know about "most", but after some study, I determined that the ancient BASIC (translated to C) code posted by Tom does a proper numerical integration of the rocket equation, and is reasonably accurate to the extent that the time step is 10 seconds (which is probably fine for something like the lunar lander). The numbers assumed for mass, fuel, etc. are in fact realistic values, although the choice of non-SI units is unfortunate. For example, the total mass of the Apollo lander capsule was 33,500 lbs (15,200 kg).

In other words, this is Rocket Science!

Earlier I wondered about an unfamiliar series approximation, but that turns out to just be the analytical integral of the fifth order approximation used for log(1-dM/M).

The two key lines in the numerical integration, updating the velocity and altitude are the following (where I've added comments) and they appear to be correct:

 J = V + G * S + Z * (-q - (q2 / 2.0) - (q3 / 3.0) - (q4 / 4.0) - (q5 / 5.0)); 
  // new V = V0 + g*t + Z*log(1-deltaM/M), fifth order approx., Z = exhaust velocity, q = dM/M
  I = A - G * S * S / 2.0 - V * S + Z * S * (q / 2.0 + q2 / 6.0 + q3 / 12.0 + q4 / 20.0 + q5 / 30.0);
   // new Altitude = A - g*t^2/2 - v*t + (integrated burn term = integral[f(q)dq]*(dt/dq)

A fun Sunday morning puzzle!

Hi Arduino Forum,
You’re right, I failed to change the serial window setting to carriage return…
now it functions great on 1.0.6, and I’m sorry to say I punched a very nasty hole in the moon on the first try. Too much fun! Here’s the code as of now. Next I plan to input fuel use from a pot.

void setup()
{
   Serial.begin(115200);
   delay(1000);
   Serial.println("\t\t\t\t LUNAR");
   Serial.println("\t       CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
   Serial.println("\n\n");
   Serial.println("THIS IS A COMPUTER SIMULATION OF AN APOLLO LUNAR");
   Serial.println("LANDING CAPSULE.\n\n");
   Serial.println("THE ON-BOARD COMPUTER HAS FAILED (IT WAS MADE BY");
   Serial.println("XEROX) SO YOU HAVE TO LAND THE CAPSULE MANUALLY.");
}

float L, A, V, M, N, G, Z, K, T, S, W, I, J;

float input(char *p)
{
   int ans;
   byte n;

restart:
   ans = 0;
   if (p == NULL)
       Serial.print("? ");
   else
       Serial.print(p);
   
   for (;;) {
       if (Serial.available()) {
           n = Serial.read();
           Serial.write (n);  //and all Serial.print(xxxx, BYTE) by Serial.write(xxxx). 
           if ((n == '\r') || (n == '\n')) {
               Serial.println();
               break;
           }
           else if (n == '\010') {     // backspace
              Serial.print(" \010");
              ans /= 10;
           }
           else if (isdigit(n)) {
               ans = ans*10 + (n - '0');
           }
           else {
               Serial.println("\n\rERROR: BAD INPUT.  TRY AGAIN");
               goto restart;
           }
       }
   }
   return (float)ans;
}


void landing()
{
   W = 3600.0 * V;
   Serial.print("ON MOON AT ");
   Serial.print(L);
   Serial.print(" SECONDS - IMPACT VELOCITY ");
   Serial.print(W);
   Serial.println(" MPH");
   
   if (W <= 1.2)
       Serial.println("PERFECT LANDING!");
   else if (W <= 10.0)
       Serial.println("GOOD LANDING (COULD BE BETTER)");
   else if (W <= 60.0) {
       Serial.println("CRAFT DAMAGE... YOU'RE STRANDED HERE UNTIL A RESCUE");
       Serial.println("PARTY ARRIVES.  HOPE YOU HAVE ENOUGH OXYGEN!");
   } else {
       Serial.println("SORRY THERE WERE NO SURVIVORS. YOU BLEW IT!");
       Serial.print("IN FACT, YOU BLASTED A NEW LUNAR CRATER ");
       Serial.print(W*0.277);
       Serial.println(" FEET DEEP!");
   }
   
   Serial.println("\n\n\nTRY AGAIN?");
}

void sub420()
{
   float q, q2, q3, q4, q5;
   
   q  = S * K/M;
   q2 = q * q;
   q3 = q * q2;
   q4 = q * q3;
   q5 = q * q4;
   
   J=V+G*S+Z*(-q - (q2/2.0) - (q3/3.0) - (q4/4.0) - (q5/5.0));
   I=A-G*S*S/2.0-V*S+Z*S*(q/2.0 + q2/6.0 + q3/12.0 + q4/20.0 + q5/30.0);
}

void sub330()
{
   L += S;
   T -= S;
   M -= S*K;
   A = I;
   V = J;
}

void sub340() {
   float D;
   for ( ;S >= 5.0e-3; ) { // line 340
       D = V + sqrt(V*V+2.0*A*(G-Z*K/M));
       S = 2.0 * A / D;
       sub420();
       sub330();
   }
}

void loop()
{
   char line[80];

   Serial.println("\nSET BURN RATE OF RETRO ROCKETS TO ANY VALUE BETWEEN");
   Serial.println("0 (FREE FALL) AND 200 (MAXIMUM BURN) POUNDS PER SECOND.");
   Serial.println("SET NEW BURN RATE EVERY 10 SECONDS.\n");
   Serial.println("CAPSULE WEIGHT 32,500 LBS; FUEL WEIGHT 16,500 LBS.");
   Serial.println("\n\n\nGOOD LUCK");
   L=0;
   Serial.println("\nSEC\tMI + FT \tMPH\tLB FUEL\t\tBURN RATE\n");
   A=120.0; V=1.0; M=33000.0; N=16500.0; G=1.0e-3; Z=1.8;

   for (;;) {                        // line 150
       sprintf(line, " %-d\t %d  %-4d\t %d\t %d\t\t",
                        (int)L, (int)floor(A),
                         (int)floor(5280.0*(A-floor(A))),
                     (int)(3600.0*V), (int)(M-N));
       Serial.print(line);
       K = input(NULL);
       T = 10.0;

       for (;;) {                    // line 160
           if ((M-N) < 1.0e-3) {
               Serial.print("FUEL OUT AT ");
               Serial.print(L);
               Serial.println(" SECONDS");
               S = (-V + sqrt(V*V + 2*A*G))/G;
               V += G*S;
               L += S;
               landing();
               return;      // Game over, Man!
           }
   
           if (T < 1.0e-3)  // line 170
               break;
               
           S = T;
           if (M < (N+S*K))
               S = (M-N)/K;

           sub420();
           if (I <= 0.0) {
               sub340();
               landing();
               return;
           }
           
           if ((V <= 0.0) || (J >= 0.0)) {
               sub330();
               continue;     // back to line 160
           }
       
           // line 370
           do {
               W = (1.0 - M*G/(Z*K))/2.0;
               S = M*V/(Z*K*(W+sqrt(W*W+V/Z))) + 0.05;
               sub420();
               
               if (I <= 0.0) {
                   sub340();
                   landing();
                   return;
               }

               sub330();
               if (J > 0.0)
                   break;
           } while (V > 0.0);
       }
   }
}

So far I’m punching lots of holes in the moon…so, to practice with some cheating,
I set starting speed to 500 here:

(int)(500.0*V), (int)(M-N)); //change speed 3600 orig

and starting altitude to 50 miles here:

A=50.0; V=1.0; M=33000.0; N=16500.0; G=1.0e-3; Z=1.8; //change altitude 120mi orig

Now you can manage a landing without too much “ballooning”!

If you change the "mystery" constant 3600 to 500, you are changing the force of gravity on the Moon to something much smaller (from 1.6 meters/second^2 to 0.22 meters/second^2).

It is no longer a realistic simulation of the Apollo landing. But then, the astronauts had a computer and radar ranging to calculate the burn rate.

Oh, drat, no wonder it was so much easier!! Thanks for that info, back to 3600.