Rocket Challenge 1

This competition is now closed, but we still welcome all attempts at this challenge!
Please send your code to greg@bodekerscientific.com and we'd be delighted to run and test your code, and let you know how you fared compared with others.

Competition Details

Prizes up for grabs:

Winner: $300 (plus job interview at Bodeker Scientific if you are interested)

Second: $150

Third: $50

Deadline for submissions: 31 August 2020

Send your solution to Greg Bodeker (greg@bodekerscientific.com) by this date.

The Challenge

Consider a spacecraft 100 km above the surface of some planet. It has just been released from the mother-ship and needs to descend to the surface carrying two astronauts. The spacecraft weighs 2000 kg and has 1000 kg of fuel onboard. The gravitational acceleration of the planet is 6 m.s-2 (on Earth it is 9.8 m.s-2). Burning 1 kg of fuel in one second generates 6000 N of upward thrust. Your job is to write some python code that decides how much fuel to burn, every second, so that the spacecraft lands on the surface under the following constraints:

    • The upward acceleration must never be more than 3g otherwise the astronauts will pass out.

    • The vertical velocity must be less than 2 m.s-1 when the spacecraft lands otherwise you destroy it.

The goal is to land on the surface, under these constraints, with as much fuel in the tank as possible. Most of the job has already been done for you. Here is some sample code:

# You will need this external library if you want to make plots

import matplotlib.pyplot as plt

thrust_per_kg = 6000

g = 6.0

mass_of_fuel = 1000

time = [0]

alt = [100000.0]

actual_speed = [0.0]

acc = [g]

fuel_to_burn = [0.0]

def get_fuel_to_burn(time, alt, speed, fuelmass):

# Students should implement their solution between here

if alt < 50000:

ftb = 5.0

else:

ftb = 0.0

if alt < 5000:

ftb = 6.0

# and here

# The line below prevents more fuel being burnt than is available

ftb = ftb if ftb < fuelmass else fuelmass

return ftb

print('Time, Altitude, Speed, Accel., G-force, Fuel left')

print('{:4d}, {:8.1f}, {:6.2f}, {:6.2f}, {:6.2f}, {:6.2f}'.format(time[-1],

alt[-1], actual_speed[-1], acc[-1], (6.0 - acc[-1]) / 9.8, mass_of_fuel))

while alt[-1] > 0:

# Find out how much fuel we will burn in the next second.

fuel_to_burn.append(get_fuel_to_burn(time[-1], alt[-1], actual_speed[-1], mass_of_fuel))

# Calculate the acceleration from the fuel burnt in the previous time step

acc_from_burn = (thrust_per_kg * fuel_to_burn[-1]) / (2000 + mass_of_fuel)

# Update the mass of fuel

mass_of_fuel = mass_of_fuel - fuel_to_burn[-1]

# Work out the acceleration at the end of the 1 second period.

acc.append(g - acc_from_burn)

# Work out new speed: v = u + a*t

actual_speed.append(actual_speed[-1] + acc[-1])

# Work out new altitude: s = ut + 0.5*a*t^2

alt.append(alt[-1] - (actual_speed[-2] + 0.5 * acc[-1]))

# Update the time

time.append(time[-1] + 1)

# Print the diagnostics

print('{:4d}, {:8.1f}, {:6.2f}, {:6.2f}, {:6.2f}, {:6.2f}'.format(time[-1],

alt[-1], actual_speed[-1], acc[-1], (6.0-acc[-1])/9.8, mass_of_fuel))

print('Final fuel left in tank={}kg'.format(mass_of_fuel))

# Make plot of altitude and speed

fig, ax = plt.subplots()

ax.plot(time, alt, color='red')

ax.set_xlabel('Time (seconds)', fontsize=12)

ax.set_ylabel('Altitude (m)', color='red', fontsize=12)

ax2=ax.twinx()

ax2.plot(time, actual_speed, color='blue')

ax2.set_ylabel('Speed (m/s)', color='blue', fontsize=12)

plt.show()

plt.close()

# Make plot of acceleration and fuel burnt

fig, ax = plt.subplots()

ax.plot(time, acc, color='red')

ax.set_xlabel('Time (seconds)', fontsize=12)

ax.set_ylabel('Acceleration (m/s^2)', color='red', fontsize=12)

ax2=ax.twinx()

ax2.plot(time, fuel_to_burn, color='blue')

ax2.set_ylabel('Fuel burnt (kg)', color='blue', fontsize=12)

plt.show()

plt.close()

print('Done')

The code repeats a loop in 1 second steps until the altitude goes negative (i.e. you have landed). At the beginning of each 1-second interval it calls the get_fuel_to_burn function which must return the mass of fuel to burn over the coming second. The parameters passed to the function are the time, altitude, speed, and mass of fuel remaining in the tank. As it stands, you can see that the algorithm for how much fuel to burn specifies 5 kg/s when the altitude is less than 50,000 m and 6 kg/s when the altitude is less than 5,000 m. As the program runs it prints out, for every second of the simulation, the time, altitude, speed, acceleration, G-force and fuel left. For this simulation, the last few lines look like:

207, 2456.0, 407.19, -7.76, 1.40, 610.00

208, 2052.7, 399.39, -7.79, 1.41, 604.00

209, 1657.2, 391.57, -7.82, 1.41, 598.00

210, 1269.6, 383.71, -7.86, 1.41, 592.00

211, 889.8, 375.82, -7.89, 1.42, 586.00

212, 518.0, 367.90, -7.92, 1.42, 580.00

213, 154.1, 359.95, -7.95, 1.42, 574.00

214, -201.9, 351.96, -7.99, 1.43, 568.00

Final fuel left in tank=568.0kg

Clearly it is not a successful algorithm - the spacecraft hits the surface at 351.96 m.s-1 with the result that the astronauts need to be scraped off the floor with a spatula. Your job is to modify the algorithm between the lines indicated in the code above so that the landing occurs within the constraints detailed above. The winner will be the person whose algorithm lands with the most fuel left in the tank, within the constraints.

The code also generates two plots which, using the algorithm above, look like this:

These figures may help with understanding the behaviour of your spacecraft. Try all sorts of different plans for burning the fuel. Notice what happens when you run out of fuel!