"""EL01 lab: why a drone hovers. YOU WRITE THIS FILE (EL01 lab, steps 1-3).Each docstring is a contract, and labs/el01_hover/tests check exactly thesecontracts. The @quantities line above each function is part of the contract too:it rejects bare numbers and wrong units before your code runs, and it checks theunit of whatever you return. Work through the lab steps in EL01, section 3, andrun `python labs/el01_hover/check.py N` after finishing step N.Conventions for this whole file- Up is positive. A thrust pushing up is positive; weight points down, so it enters every sum with a minus sign.- Thrusts are forces. A thrust table's "grams" are gram-force (gf), and pint converts them for you: Q_(1500, "gf").to("N") is about 14.7 N.- g defaults to standard gravity G0 = 9.80665 m/s^2 from hwe.units.- Never strip units inside these functions (no .magnitude, no .m): let pint carry them to the end, so a slip shows up as an error instead of a wrong number."""fromhwe.unitsimportG0,Q_,quantities# ----------------------------------------------------------------------# STEP 1: mass is not weight (worked example; type it from EL01, step 1).# ----------------------------------------------------------------------@quantities(mass="[mass]",g="[acceleration]",returns="[force]")defweight(mass,g=G0):"""The weight of a mass: W = m g, the force gravity exerts on it. mass any mass unit (g, kg). g gravitational acceleration; standard gravity unless told otherwise. Returns the weight in newtons. """raiseNotImplementedError("Step 1: weight")# ----------------------------------------------------------------------# STEP 2: Newton's second law along the vertical (partly filled in EL01).# ----------------------------------------------------------------------@quantities(thrusts="[force]",mass="[mass]",g="[acceleration]",returns="[force]")defnet_force(thrusts,mass,g=G0):"""The net vertical force on the drone: the sum of all thrusts minus its weight. thrusts a list of thrust forces, one per motor, each pointing up. mass the drone's total mass. Returns the net force in newtons: positive means it accelerates upward. Ignore drag (the drone is still or moving slowly). """# TODO(human): Step 2. Sum the thrusts from a start value that carries a unit, then subtract the weight.raiseNotImplementedError("Step 2: net_force")@quantities(thrusts="[force]",mass="[mass]",g="[acceleration]",returns="[acceleration]")defacceleration(thrusts,mass,g=G0):"""The drone's vertical acceleration from Newton's second law, a = F_net / m. Same inputs as net_force. Returns the acceleration in m/s^2 (up positive): zero in a hover, positive while speeding up upward (or slowing a descent). """raiseNotImplementedError("Step 2: acceleration")@quantities(accel="[acceleration]",g="[acceleration]",returns="[acceleration]")defaccelerometer_reading(accel,g=G0):"""What an up-pointing accelerometer reads for a body with vertical acceleration accel. An accelerometer cannot feel gravity (gravity pulls its test mass and its case equally). It measures every OTHER force per unit mass, called the specific force: reading = accel + g, up positive (EL01, section 2.6). Examples: resting on a table, accel = 0, so it reads +g; in free fall, accel = -g, so it reads 0. Returns m/s^2. """raiseNotImplementedError("Step 2: accelerometer_reading")# ----------------------------------------------------------------------# STEP 3: the thrust-to-weight family (on your own, from EL01, section 2.7).# ----------------------------------------------------------------------@quantities(max_thrust_per_motor="[force]",mass="[mass]",g="[acceleration]",returns="[]")defthrust_to_weight(max_thrust_per_motor,motor_count,mass,g=G0):"""T/W: the total maximum thrust of all motors divided by the drone's weight. max_thrust_per_motor one motor's maximum thrust (for example from a thrust table). motor_count how many motors (an int: 4 for a quad). Returns a pure number: 2.0 means the motors together can lift twice the weight. """raiseNotImplementedError("Step 3: thrust_to_weight")@quantities(mass="[mass]",g="[acceleration]",returns="[force]")defhover_thrust_per_motor(mass,motor_count,g=G0):"""The thrust each motor must make to hover, sharing the weight equally. Returns newtons. (EL02 shows what changes when the centre of mass is off-centre.) """raiseNotImplementedError("Step 3: hover_thrust_per_motor")@quantities(max_thrust_per_motor="[force]",mass="[mass]",g="[acceleration]",returns="[]")defhover_thrust_fraction(max_thrust_per_motor,motor_count,mass,g=G0):"""The fraction of maximum thrust spent just holding a hover: weight / total max thrust. Equal to 1 / (T/W). A value above 1 means the drone cannot hover at all; return it anyway, because the report uses it to say by how much. """raiseNotImplementedError("Step 3: hover_thrust_fraction")@quantities(max_thrust_per_motor="[force]",mass="[mass]",g="[acceleration]",returns="[acceleration]")defmax_climb_acceleration(max_thrust_per_motor,motor_count,mass,g=G0):"""The largest upward acceleration at full thrust, ignoring drag: g (T/W - 1). Returns m/s^2. Negative means that even full thrust cannot lift the drone. """raiseNotImplementedError("Step 3: max_climb_acceleration")