Hopper rocket 2.0

Tutorial

Author: smoketeer

In Hopper rocket tutorials we’re paying tribute to historical rockets capable of powered landing in atmospheric environment, namely DC-X, Grasshopper and BlueShepherd. Instead of combining every bit of fall module into one script, we’re going to gradually build complexity.


This tutorial is a continuation of Tutorial: Hopper rocket 1.0.

Mission

We already have a Hopper rocket 1.0. It flies straight up and then lands safely, but the higher it flies, the further we land from the original launch site. This, obviously, is not ideal.

When we look at rockets we’re trying to emulate, we can easily conclude that they are capable of correcting their course on the way down. They indeed land exactly where they started in most cases.

So how can we achieve this behaviour?

Hopper rocket 2.0 will use gliding guidance in the form of glideController. It will not land precisely on the launch pad just yet, but rather mitigate the distance from the launch pad significantly.

Implementation

We’re going to reuse some code from previous tutorial.

Importing FALL

First let’s see what we need:

runoncepath("0:/fall/utilities/importFall").

importFall("landingDataModel").
importFall("hoverSlamModel").
importFall("glideController").

Launch

This time we won’t go straight to launch sequence. First we’re going to prepare some data. We want our rocket to land where it started from, so it’s a good idea to store rockets position before it launches. FALL implements landingDataModel, which is constructed with desired landing geoposition parameter. It garners methods that among others calculate error between impact position and position at which we want to land. It will be used later on to construct glideController.

// ship:geoposition stands for current position
local ldata is landingDataModel(ship:geoposition).

Now we’ll reuse some of the code we’ve written in the previous tutorial:

lock steering to up. // we want to go straight up
lock throttle to 1.

// turn on the engines
wait 1.
stage.
gear off.

// gain some decent altitude
wait until ship:apoapsis > 10000. // notice it's higher than previously
lock throttle to 0.

That’s it for the launch sequence.

Gliding

In the previous tutorial, at this point we’ve waited until the ship starts falling. This time we want to add some extra logic, so the rocket will engage gliding control scheme as soon as we’re on our descent.

// tuning
local maxAoa is 10.
local errScaling is 1.

// constructing glideController object
local glide is glideController(ldata, maxAoa, errScaling).

wait until ship:verticalspeed < 0.
lock steering to glide["getSteering"]().
rcs on.

Now as soon as the ship is on its descent, our glide controller will start course adjustment.

Landing

This time our rocket isn’t just falling down, it constantly tries to mitigate landing position error. Applying thrust when gliding control scheme is active, will produce opposite results to what is expected. We have to make sure that as soon as our hoverslam["getThrottle"]() returns more than 0, the gliding control scheme ends and we continue to burn retrograde:

local hoverslam is hoverSlamModel(10).
lock throttle to hoverslam["getThrottle"]().

wait until throttle > 0.
lock steering to ship:srfretrograde. // changing control scheme

wait until ship:status = "landed".
// We've landed!

Now our results should be more promising.

Tuning

Take a look at Gliding section. As you can see we add two local variables - maxAoa and errScaling. They are used to tune glideController object.

General rule of thumb is, that we don’t need extreme corrections. In this case both errScaling and maxAoa are the default values the glideController uses. If your rocket overcompensates and oscillates, just lower the errScaling value.

The glideController we’ve used is vector oriented, it relies on proportional error corrections based on vector calculations. This doesn’t make it an extremely accurate solution, but it’s much easier to tune than PID oriented.

If you want to use PID version of the controller use glidePIDController.

Summary

 1 runoncepath("0:/fall/utilities/importFall").
 2 
 3 importFall("landingDataModel").
 4 importFall("hoverSlamModel").
 5 importFall("glideController").
 6 
 7 local ldata is landingDataModel(ship:geoposition).
 8 
 9 lock steering to up. // we want to go straight up
10 lock throttle to 1.
11 
12 wait 1.
13 stage.
14 gear off.
15 
16 wait until ship:apoapsis > 10000. // notice it's higher than previously
17 lock throttle to 0.
18 
19 local maxAoa is 5.
20 local errScaling is 0.4.
21 local glide is glideController(ldata, maxAoa, errScaling).
22 
23 wait until ship:verticalspeed < 0.
24 lock steering to glide["getSteering"]().
25 rcs on.
26 
27 local hoverslam is hoverSlamModel(10).
28 lock throttle to hoverslam["getThrottle"]().
29 
30 wait until throttle > 0.
31 when alt:radar < 50 then { gear on. }
32 lock steering to ship:srfretrograde. // changing control scheme
33 
34 wait until ship:status = "landed".

But what if?

Compensating the error with gliding guidance works fine as long as we spend enough time in the unpowered flight stage. But what if we do not have enough time to correct the course only through means of gliding?

We have to come up with a solution that performs course corrections during powered landing stage. This is exactly what we will do in the next tutorial.

Hopper Rocket 3.0