Watch on YouTube: https://youtu.be/q7GDV539nnc
I don’t want to start off on the wrong foot and say automating a munar landing was easy, so let me say this instead. I was not prepared for the level of difficulty presented by Minmus. To be clear, the Mun landing required more than 25 attempts to achieve a 50% success rate, and that felt like a near miracle. With Mun, the goal was simpler. Its orbit around Kerbin is aligned with the ecliptic. This was a design decision made by the game designers to make it easier for players to make meaningful progress in the game. I’m glad they did because the game is arguably one of the most difficult on the market. The script suffers the same penalties experienced by new players. Things can go sideways quickly.
To review, the munar automation script stabilizes into low Kerbin orbit at 80km before computing a transfer orbit maneuver with a predetermined prograde delta-v. Then, after executing the maneuver, it settles into an elliptical orbit with a low periapsis before circularizing at 20km munar altitude. Finally, deorbit and hoverslam to land on the surface. Simple, right? Again, no.
Turns out you can’t simply adjust the prograde delta-v and let the script figure things out. After about ten attempts doing exactly that, I realized there were some significant barriers. For one, the Mun is in the way sometimes, and the script takes a looooooong time to find a solution. Also, it became clear there was a lot of room for improvement in my approach to throttle control. At this point, the results were not good. In the rare cases when I was able to chart an intercept course, the maneuver execution was … imprecise … and I ended up on an escape trajectory.
This makes sense, if you think about it. There’s a lag between the moment we detect some condition is satisfied and the moment the engines stop producing thrust. Chalk it up to a symptom of an engine with high thrust and high specific impulse. We overshoot every time, as a direct result of this delay. We can use simple solutions attempting to compensate, like decreasing throttle by 75% when we approach the engine cutoff condition. This only really reduces the magnitude of the observed effect and does very little to contribute to a more robust solution.
Our best approach is to rethink the control strategy entirely. The first time, it was simply a matter of activating engines at full throttle, deactivating when a condition is met. To achieve a more nuanced result, we will need to take into consideration how far away we are from achieving the condition. In mathematical terms, this means using a ramp input instead of a step input. A ramp input is more like slowing down gradually before stopping, whereas a step input is like slamming on the brakes at the last moment.
Let’s start by incorporating a proportional controller. Rather than providing a constant step input to the throttle, we reduce the throttle based on the remaining delta-v required for the maneuver. This allows us to go full throttle at the beginning, when there’s a large gap to traverse, and then reduce throttle as we approach the target. This gives us the ability to exercise fine control at the end of the maneuver when precision is most important.
Using this proportional control technique, the script is able to stabilize on an intercept orbit with Minmus. However, even with our precise throttle control, we still experience strange oscillations around the target in some cases. In one case, this was caused by a less-than where I needed a less-than-or-equal-to. In most cases, though, it was because the conditions were error-prone.
One key error I encountered was assumptions about the precision of the time warp tool. I incorrectly assumed the ETA for orbital transition would be accurate within a second. Sadly, it is not. This means sometimes the warp completes before the vessel enters the Minmus orbital patch. This has catastrophic effects on the automation process, as it picks the planet periapsis ETA instead of the Minmus periapsis, which is highly correlated with my cursing at the game. After sorting out this subtle nuance in the logic, the rest fell into place. Ok, so what does the code look like?
As with the Mun landing script, we use a runmode variable to manage each phase of the mission. We’ll start from orbit this time, to focus on the differences presented by a Minmus transfer orbit. Let’s dive in!
The main difference between Minmus and Mun orbits is the inclination. Minmus is inclined about 6 degrees from the ecliptic plane. Without adjusting the inclination, we may need to wait considerably longer to plot a transfer orbit, as Minmus shifts in and out of plane relative to Kerbin. Also, Mun intermittently interferes, making it more important to match the inclination.
As a result, our first maneuver after achieving stable orbit is to compute an inclination maneuver. We do this by creating a node with a starting delta-v in the normal direction. We move the node forward in time, comparing the inclination of the resulting orbit against the previous value until we detect an inflection point. Then, we adjust the delta-v until the resulting relative inclination approaches zero.
Once we have our maneuver planned, we simply time warp to the maneuver and execute the burn. Here, we use a proportional controller based on the ship’s scalar speed and the maneuver delta-v requirement. The limit condition is defined based on a simple threshold. We cut the throttle when the relative inclination approaches zero. Then, we proceed to the next runmode to compute the elliptical transfer orbit.
This phase uses the same iterative technique with constant prograde delta-v to find a maneuver node time with a Minmus intercept. Once we have a valid transfer orbit planned, we time warp to the maneuver and execute another burn. Again, we use a proportional controller based on speed and delta-v requirement. Again we use a limit condition.
Early versions of the logic simply added the appropriate delta-v and hoped for the best. This often left the vehicle on an elliptical orbit, but not necessarily on a Minmus intercept. This is because of the extended burn time introduced by the proportional controller. Maneuver nodes assume instantaneous impulse, and there’s no way to add so much energy so fast without squishing the meatbags.
A better way to achieve our stable intercept is to use a different condition entirely. Rather than wait for a specific delta-v change, we cut the engines immediately upon detecting a Minmus intercept. This helps to guarantee an intercept, but it’s worth noting this is not an efficient algorithm. It simply results in a well understood landing sequence, where we can re-use the components from our Mun landing script. We use different values for the altitudes, but otherwise the rules are the same. At this point, we have achieved our most significant milestone in the process. Time to enjoy the fruit of our labor.
While we watch the best attempt, let’s reflect again on the difficulty of this challenge. For the Mun landing, it took 25 attempts. This time, it took more than twice as many attempts. In total, this video required 64 attempts to reach the same success rate criteria. It seems only fitting to show all the attempts as one magnificent composite. So, sit back and relax. Enjoy this time lapse of all the attempts at the same time.
Tag: automation
How to Automate a Mun Landing
Watch on YouTube: https://www.youtube.com/watch?v=t4dIED5JLos
Getting to orbit with any vessel in Kerbal Space Program is a challenge that should not be understated. Players often make many mistakes in attempts at suborbital flights before they reach a stable low orbit. The road to efficient orbital launch is a long punishing ordeal, ripe with uncertainty. Moreover, every vessel flies differently; hard-learned rules from flight testing with one vessel prove useless or even counterproductive with other vessels. So, to talk about designing an automated control system capable of landing on Mun is to set the bar high. The good news is aiming high is kinda the point.
Normally, it takes a lot of staging and clever redistribution of mass and fuel to coordinate a lunar landing. In the interest of eating the elephant in smaller bites, this exercise uses a vehicle with a modified engine. Our resident rocket scientist adjusted the aerospike to boost the exhaust velocity up to about 10% of light speed. The resulting engine has enough thrust to take off from sea level on Eve and enough fuel to accelerate at 1G for a little over a day. This makes it a little easier to design our automation system. No pesky staging to interfere with our script.
But enough about rocket science… This is about computer science! :nerd:
Any sensible solution likely involves breaking down the problem into smaller chunks we might be able to tackle individually. This is a process called decomposition. While it shares its name with the process of death and decaying organic material, that is precisely the outcome we wish to prevent. It is worth noting in the vacuum of space there is no organic decay. Mostly we just turn into frozen desiccated meat bricks if things go horribly wrong, basically the worst freezer burn imaginable. But this is about robots, not meat bags, and we’re hoping to make robots who protect the meat bags and deliver them safely to a totally inhospitable environment because that’s what they wanted.
Before we dive into the various phases of the mission plan, let’s establish some rules. Ideally, each time we wait for a condition to be satisfied, we want the smallest number of components in our logic. This means using simple conditions wherever possible. Also, we don’t want to overconstrain the operational parameters, or the system may not converge toward the conditions and be forever stuck in a loop. For example, most of the conditions in this experiment use single edge bounded constraints, like “wait until periapsis is greater than threshold.” These simple constraints increase the chance of overall system stability, as they are less sensitive to unexpected side effects.
Our first step is to escape the gravity well and stabilize into low orbit. This is pretty much as simple as going as fast as we can while staying below transonic speed in the atmosphere. This specific craft has its aerodynamic center co-located with its center of mass to enable atmospheric re-entry with engines pointed retrograde without inverting and impersonating a badminton birdie. Plummeting head first in a swan dive into the dirt is the exact opposite of our desired outcome, so it’s helpful if we can orient the vehicle regardless of the environment.
Because we’ve decomposed our larger problem into smaller ones, it’s worth noting these represent discrete phases of our launch-and-land objective. As we review the script in detail, you’ll see this represented by the runmode variable. For example, runmode 1 engages our engines at a safe thrust. Once we reach a threshold velocity, we transition to runmode 2 where the launch profile maintains a TWR of about 1.25 during the ascent. This is the slow gentle climb up to our target altitude of 80km. Once we push the apoapsis to our target altitude, we cut the engines switch to runmode 3, where we coast up to the apoapsis. Just before the peak of ascent, runmode 4 engages and we raise the periapsis up to our target altitude to circularize.
Once we have a stable circular orbit, we move into runmode 5 and begin the process of computing a transfer orbit to the Mun. Using this script, we could launch at any time and still find a valid transfer orbit. This is because we rely on the known delta-v required to make the trip as we consider possible transfer points along our orbit. The script does this by creating a maneuver node and evaluating the resulting orbit. If the maneuver results in an encounter where the lunar periapsis is above ground, we have found a viable transfer point. Otherwise, advance the node by ten seconds and try again. Eventually, we will find an intercept and we move onto runmode 6.
With a valid intercept course plotted, we wait until the maneuver time and then execute the maneuver. There are several ways to do this. In this case, we compute a target scalar velocity and engage the engine until the velocity reaches the target. If we’ve done our homework, this should result in a transfer orbit with a Mun encounter with a subsequent lunar orbit matching our desired parameters. Now we engage runmode 7 where we manipulate time to advance to the lunar encounter, as the transfer takes about a day of real time.
Once we arrive at our encounter with the Mun’s sphere of influence, we activate runmode 8 to begin circularizing into a lunar orbit. We advance time again to bring the vehicle to the periapsis, where we engage the engines once again in retrograde to drop into an elliptical orbit with a low periapsis around the Mun. Once the periapsis falls below its target threshold, we cut the engines and wait until we coast down to the periapsis.
Here, we have one more retrograde burn to stabilize into a circular orbit around the Mun. This design uses a lunar orbit of 20km to reduce the impact of in-game time warp constraints. At this altitude, we engage runmode 9 and wait until we reach a longitude threshold before initiating deorbit. In this case, the specific value was chosen based on manual scouting. It was important for filming to have a landing in the sun. The first landing was indeed in the dark, and it wasn’t very camera friendly.
It’s much better to land on the sunny side where the audience can see it. I’m sure there’s a positivity metaphor in there somewhere… but I’m sure you’re more interested in the landing logic. The deorbit phase completes when we detect the vessel’s ground speed is below a threshold. At this point, we transition into our final runmode, the hoverslam. I found an example KOS script from an engineer at SpaceX, who was kind enough to share the code. Hoverslam is simple: control the throttle during powered descent such that the velocity and altitude reach zero simultaneously. I was extremely pleased with the hoverslam phase, which was fortunately the most reliable part of the experiment.
Now that we’ve reviewed each part separately, let’s put it all together as a time lapse of the best attempt! For what it’s worth, I really enjoy the cloud mod, as it adds a rich context and a sense of realism to take these recordings to the next level.
Okay, so we’ve reviewed all the parts individually and seen a full example of the mission from beginning to end. By now, I’m sure you’re excited about outtakes. Like how did it fail? It turns out it failed in several very tightly clustered groups. Let’s take a look.
First, it failed on overconstrained logic conditions. This version of the script does not show all the terribly stupid things I did in earlier examples. For one thing, I had an extra phase dedicated to lowering the periapsis immediately upon entering the Mun sphere of influence. This extra phase added complexity without adding much value, so I settled on the simpler version you see here. I also had weird logic errors, which didn’t manifest until late in the script. Much like the early pioneers of space travel, we don’t have the luxury of resetting a virtual environment to retry with different code. KSP doesn’t offer the ability to simulate any scenario without first doing all the hard work to get there.
The most common failure I encountered was misinterpretation of conditions upon entering the lunar sphere of influence. The script frequently went rapid fire through the lunar circularization sequence, often skipping important parts and leaving the vessel spinning out of control. Automating time warp was a critical aspect of standardizing this behavior enough to make meaningful recordings. Using manual time warp led to unpredictable results in the script itself, likely because of poor precision. By automating timing in the script directly, the system behavior was substantially more predictable.
With a stable trigger for a landing sequence, the script was able to achieve impressive results, with tight grouping on the final landing locations. All examples use a hoverslam technique to control velocity during descent. In every case, the landing was successful, except one instance when the vehicle landed on a steep incline and was lost shortly afterward.
So, let’s watch a grid of the sixteen best attempts, all together at the same time. If you’re interested, you can watch this same video in real time here. And as always, thanks for watching Kerbalism!
