Now you are the flight controller. A small drone flies a hidden 30-second mission, and fifty times a second (every dt = 0.02 s) the simulator calls your function
altitude_hold(altitude, target, t) -> thrust
with the altitude sensor's reading (metres), the altitude the mission wants now (metres), and the time since take-off (seconds; t is exactly 0 on the first call of every flight, so reset anything you remember then). Return the total thrust of the four motors in newtons.
What you are up against:
- the drone weighs 0.8 kg plus an unknown payload of up to 0.2 kg, so hovering needs between about 7.85 and 9.81 N; air resistance takes
0.3 * speednewtons; - the motors give between
0and16N (anything outside is limited), and they lag: the thrust follows your command with a time constant of 0.06 s; - the mission starts on the ground, asks for 2 m, and changes the target every 7.5 s (to 3.5 to 5 m, then 1.5 to 2.5 m, then 3 or 3.5 m);
- three gusts push the drone up or down by 1 to 3 N for 0.5 to 2 s each;
- the sensor is noisy: each reading is the true altitude plus a random error with a typical size of 2 cm, rounded to the millimetre. A raw derivative of that is a vertical speed that jumps by about 1.4 m/s from one sample to the next.
Each test calls fly(altitude_hold, seed) (it is defined for you, so you can try it with Run), which returns a summary such as
{"rms_error": 0.207717, "effort": 5.48521, "lowest": 1.4235, "highest": 4.0197, "final_error": 0.075628}
for a plain PID controller with a raw derivative on seed 1.
rms_error is the root-mean-square altitude error (m) over the last 5 s of each 7.5 s stage (the first 2.5 s after each target change are for getting there); effort is the average change of your thrust command from one step to the next (N); lowest is the lowest altitude after the first 3 s, highest the highest altitude; final_error is the mean distance from the target over the last 3 s. Your function may keep values between calls in global variables.
How this problem is scored
- A test passes when the drone never comes within 30 cm of the ground after the first 3 s (
lowest >= 0.3), never flies above the 7 m ceiling, and holds its last target to within 0.3 m on average over the last 3 s. - Its quality is
100 - 100 * rms_error - 5 * effort(between 0 and 100): every centimetre of typical error costs a point, and every newton of step-to-step thrust change costs 5, for the heat and wear that buzzing motors suffer. - A plain PID with a raw derivative on the measurement passes but scores only about 50: the noise makes its thrust buzz. Higher gains track better but buzz more; the lessons of this topic show how to have both.
Constraints
- return a number (
Noneor a value that is not a finite number counts as 0 N) - the result must not depend on the clock; each call should take well under a millisecond
Goals
- Write a PID controller that a simulator calls once per time step
- Hold altitude through payload changes, gusts and sensor noise with limited thrust
- Balance tight tracking against the motor effort that noise and a raw derivative cause