Due Date: | 2/21/13 |
---|
The lander program is a simulation of the following:
You're the pilot of the first mission to Titan, Saturn's largest moon. One kilometer above the surface and descending at a rate of 50 meters per second with 100 thrust units of fuel left, your on-board computer fails and you have to perform the descent manually. This means deciding how much thrust to provide second-by-second to land at a speed (velocity magnitude) of under 2 meters per second. Any faster than that and you will crash. If you run out of fuel, you will fall to the surface (although you might survive). Titan's surface gravity is 1.352 meters per second per second (on the Earth, it's 9.8) and your engines can deliver a maximum thrust of 5 meters per second per second upward. (No fair flying away!)
Your part of the problem has been broken down into three functions in addition to main(), which is given:
getThrust(): input a valid thrust value from the user step(): compute the result of a single burn increment land(): perform the simulation itself
Here's a template for the overall program:
/* * Titan Lander * * Adapted from Dave Ahl and Joe Morrison's classic "Lunar Lander". */ #include <stdio.h> #include <math.h> /* * insert getThrust() here */ /* * insert step() here */ /* * insert land() here */ int main(void) { double elapsedTime[1]; double finalVelocity[1]; double fuel[1] = { 100 }; land(fuel, finalVelocity, elapsedTime); printf("final velocity: %.1f m/s\n", finalVelocity[0]); if (fabs(finalVelocity[0]) > 2.0) printf("you crashed!\n"); else printf("safe landing\n"); printf(" elapsed time: %.2f s\n", elapsedTime[0]); return 0; }
Put everything in one file lander.c and submit through Angel.
In what follows, you are given the prototype and pseudocode for the functions you are to implement. You are not allowed to change the prototypes or to add additional global variables. (If you don't know what those are, that's fine for now.)
Here's the prototype and pseudocode:
#define MAX_THRUST 5.0 double getThrust(double fuel) /* * Prompt the user to enter a legal thrust value. Engines cannot * proved more than MAX_THRUST (a constant) thrust. Allow for errors. * * input: * fuel: available fuel * * returns: * a legal thrust value */ { /* * pseudocode: * * let maxBurn be the smaller of MAX_THRUST and fuel * prompt the user to enter a thrust value between 0 and maxBurn * if the thrust is less than 0, * print a message that a negative thrust is not permitted * and that you're assuming zero thrust * set thrust to 0.0 * else if the thrust is greater than maxBurn * print a message that thrust is too large * and that you're assuming the maximum * set thrust to maxBurn * return thrust */ }
This function will require you to recall a little physics. The the product of the acceleration of an object with its mass being the sum of forces acting on it. This is the familiar F = m a, only to make things simple we assume m = 1.
The two forces acting on the lander are gravity (pulling it down) and thrust (lifting it up). The net acceleration a is their difference:
where T is the thrust (an input controlled by the user) and g is the gravitational acceleration (a constant 1.352 m/s**2 in the case of Titan). The thrust is always positive. The acceleration can be positive or negative. Negative acceleration is downward, so if the thrust is zero, the lander is in "free fall" and the acceleration is negative.
If we start with a velocity v from a height h, after time dT, the new velocity will be
and the new height will be
step() then, will compute these new values for a single step (one "burn") lasting one second (dT = 1). Height and velocity will be both input to and output from the function. Negative velocity is towards the ground.
step() will also keep track of the fuel (deducting the thrust from the fuel value, which is also input/output) and of the elapsed time (adding dT to it every time it's called).
Here's the prototype and pseudocode:
void step(double thrust, double height[1], double velocity[1], double fuel[1], double elapsedTime[1]) /* * Compute the change in height, velocity, fuel, and elapsed time for * a single time step. (In order to both input and output these * values, each of them is a one-element array.) * * Optional: If the lander crashes, allow for the fact that it does * not sink into the ground. * * input: * * thrust: amount of thrust to apply (this will be deducted from * fuel[1]) * * inputs/outputs: * * height[0]: height above the ground (in m.) before/after step * * velocity[0]: velocity (in m.) (negative is downward) * * fuel[0]: amount of fuel available/remaining * * elapsedTime[0]: clock time before/after step (in s.) */ { /* * pseudocode: * * declare dT, accel, newVelocity, gravAccel, and newHeight as doubles * set gravAccel to 1.352 (m/s**2 on Titan) * set dT (the time step) to 1.0 * compute accel ("a" in the writeup) * compute newVelocity ("v'" in the writeup) * compute newHeight ("h'" in the writeup) * decrease fuel[0] by thrust * if newHeight is positive (the lander hasn't landed), * increase elapsedTime[0] by dT * set velocity[0] to newVelocity * set height[0] to newHeight * otherwise, * revise dT to get an accurate crash time and velocity * (this is optional -- see writeup) * increase elapsedTime[0] by dT * increment velocity[0] by accel times dT * set height[0] to 0 */ }
The lander reaches the ground when the height is zero, but your calculations may actually end up with a negative height. It's okay to stop there, but for 10 points of extra credit, figure out the actual dT on the last time step (it will be between 0 and 1) by solving
for dT and using that value to update the velocity and elapsed time. (Set the height to 0, of course.) Allow for the possibility that a = 0.
Here's the prototype and pseudocode:
void land(double fuel[1], double finalVelocity[1], double elapsedTime[1]) /* * Simulate the landing. * * input: * * fuel: the initial amount of fuel in thrust units * * outputs: * * finalVelocity[0]: the velocity of the lander upon landing (in * meters per second) * * elapsedTime[0]: the total time required to land (in seconds) * */ { /* * pseudocode: * * declare height as a 1-element double array * declare velocity as a 1-element double array * declare thrust as a double * initialize height[0] to 1000 * initialize velocity[0] to -50 * initialize elapsedTime[0] to 0 * as long as height[0] is greater than 0, * print out elapsedTime[0] * print out height[0] * print out velocity[0] * print out fuel[0] (the remaining fuel) * if there's any fuel left, * assign the return of getThrust() to thrust * otherwise * print a message that the lander is out of fuel and free falling * set thrust to 0 * call step() to apply thrust to compute the new values of height, * velocity, fuel, and elapsedTime * set finalVelocity to the velocity upon landing (or crashing) */ return; }