Launch into Orbit

This tutorial launches a two-stage rocket into a 150km circular orbit. The program assumes you are using this craft file.

The program is available in a variety of languages:

C#, C++, Java, Lua, Python

The following code connects to the server, gets the active vessel, sets up a bunch of streams to get flight telemetry then prepares the rocket for launch.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using System;
using System.Collections.Generic;
using System.Net;
using KRPC.Client;
using KRPC.Client.Services.SpaceCenter;

class LaunchIntoOrbit
{
    public static void Main ()
    {
        var conn = new Connection ("Launch into orbit");
        var vessel = conn.SpaceCenter ().ActiveVessel;

        float turnStartAltitude = 250;
        float turnEndAltitude = 45000;
        float targetAltitude = 150000;

        // Set up streams for telemetry
        var ut = conn.AddStream (() => conn.SpaceCenter ().UT);
        var flight = vessel.Flight ();
        var altitude = conn.AddStream (() => flight.MeanAltitude);
        var apoapsis = conn.AddStream (() => vessel.Orbit.ApoapsisAltitude);
        var stage2Resources =
            vessel.ResourcesInDecoupleStage (stage: 2, cumulative: false);
        var srbFuel = conn.AddStream(() => stage2Resources.Amount("SolidFuel"));

        // Pre-launch setup
        vessel.Control.SAS = false;
        vessel.Control.RCS = false;
        vessel.Control.Throttle = 1;

        // Countdown...
        Console.WriteLine ("3...");
        System.Threading.Thread.Sleep (1000);
        Console.WriteLine ("2...");
        System.Threading.Thread.Sleep (1000);
        Console.WriteLine ("1...");
        System.Threading.Thread.Sleep (1000);
        Console.WriteLine ("Launch!");
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <chrono>
#include <cmath>
#include <thread>
#include <krpc.hpp>
#include <krpc/services/space_center.hpp>

int main() {
  krpc::Client conn = krpc::connect("Launch into orbit");
  krpc::services::SpaceCenter space_center(&conn);
  auto vessel = space_center.active_vessel();

  float turn_start_altitude = 250;
  float turn_end_altitude = 45000;
  float target_altitude = 150000;

  // Set up streams for telemetry
  auto ut = space_center.ut_stream();
  auto altitude = vessel.flight().mean_altitude_stream();
  auto apoapsis = vessel.orbit().apoapsis_altitude_stream();
  auto stage_2_resources = vessel.resources_in_decouple_stage(2, false);
  auto srb_fuel = stage_2_resources.amount_stream("SolidFuel");

  // Pre-launch setup
  vessel.control().set_sas(false);
  vessel.control().set_rcs(false);
  vessel.control().set_throttle(1);

  // Countdown...
  std::cout << "3..." << std::endl;
  std::this_thread::sleep_for(std::chrono::seconds(1));
  std::cout << "2..." << std::endl;
  std::this_thread::sleep_for(std::chrono::seconds(1));
  std::cout << "1..." << std::endl;
  std::this_thread::sleep_for(std::chrono::seconds(1));
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import krpc.client.Connection;
import krpc.client.RPCException;
import krpc.client.Stream;
import krpc.client.StreamException;
import krpc.client.services.SpaceCenter;
import krpc.client.services.SpaceCenter.Flight;
import krpc.client.services.SpaceCenter.Node;
import krpc.client.services.SpaceCenter.ReferenceFrame;
import krpc.client.services.SpaceCenter.Resources;

import org.javatuples.Triplet;

import java.io.IOException;
import java.lang.Math;

public class LaunchIntoOrbit {
    public static void main(String[] args)
        throws IOException, RPCException, InterruptedException, StreamException {
        Connection connection = Connection.newInstance("Launch into orbit");
        SpaceCenter spaceCenter = SpaceCenter.newInstance(connection);
        SpaceCenter.Vessel vessel = spaceCenter.getActiveVessel();

        float turnStartAltitude = 250;
        float turnEndAltitude = 45000;
        float targetAltitude = 150000;

        // Set up streams for telemetry
        spaceCenter.getUT();
        Stream<Double> ut = connection.addStream(SpaceCenter.class, "getUT");
        ReferenceFrame refFrame = vessel.getSurfaceReferenceFrame();
        Flight flight = vessel.flight(refFrame);
        Stream<Double> altitude = connection.addStream(flight, "getMeanAltitude");
        Stream<Double> apoapsis =
            connection.addStream(vessel.getOrbit(), "getApoapsisAltitude");
        Resources stage2Resources = vessel.resourcesInDecoupleStage(2, false);
        Stream<Float> srbFuel =
            connection.addStream(stage2Resources, "amount", "SolidFuel");

        // Pre-launch setup
        vessel.getControl().setSAS(false);
        vessel.getControl().setRCS(false);
        vessel.getControl().setThrottle(1);

        // Countdown...
        System.out.println("3...");
        Thread.sleep(1000);
        System.out.println("2...");
        Thread.sleep(1000);
        System.out.println("1...");
        Thread.sleep(1000);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
local krpc = require 'krpc'
local platform = require 'krpc.platform'
local math = require 'math'
local List = require 'pl.List'

local turn_start_altitude = 250
local turn_end_altitude = 45000
local target_altitude = 150000

local conn = krpc.connect('Launch into orbit')
local vessel = conn.space_center.active_vessel

flight = vessel:flight()
stage_2_resources = vessel:resources_in_decouple_stage(2, False)

-- Pre-launch setup
vessel.control.sas = false
vessel.control.rcs = false
vessel.control.throttle = 1

-- Countdown...
print('3...')
platform.sleep(1)
print('2...')
platform.sleep(1)
print('1...')
platform.sleep(1)
print('Launch!')
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import math
import time
import krpc

turn_start_altitude = 250
turn_end_altitude = 45000
target_altitude = 150000

conn = krpc.connect(name='Launch into orbit')
vessel = conn.space_center.active_vessel

# Set up streams for telemetry
ut = conn.add_stream(getattr, conn.space_center, 'ut')
altitude = conn.add_stream(getattr, vessel.flight(), 'mean_altitude')
apoapsis = conn.add_stream(getattr, vessel.orbit, 'apoapsis_altitude')
stage_2_resources = vessel.resources_in_decouple_stage(stage=2, cumulative=False)
srb_fuel = conn.add_stream(stage_2_resources.amount, 'SolidFuel')

# Pre-launch setup
vessel.control.sas = False
vessel.control.rcs = False
vessel.control.throttle = 1.0

# Countdown...
print('3...')
time.sleep(1)
print('2...')
time.sleep(1)
print('1...')
time.sleep(1)
print('Launch!')

The next part of the program launches the rocket. The main loop continuously updates the auto-pilot heading to gradually pitch the rocket towards the horizon. It also monitors the amount of solid fuel remaining in the boosters, separating them when they run dry. The loop exits when the rockets apoapsis is close to the target apoapsis.

41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
        // Activate the first stage
        vessel.Control.ActivateNextStage ();
        vessel.AutoPilot.Engage ();
        vessel.AutoPilot.TargetPitchAndHeading (90, 90);

        // Main ascent loop
        bool srbsSeparated = false;
        double turnAngle = 0;
        while (true) {

            // Gravity turn
            if (altitude.Get () > turnStartAltitude &&
                altitude.Get () < turnEndAltitude) {
                double frac = (altitude.Get () - turnStartAltitude)
                              / (turnEndAltitude - turnStartAltitude);
                double newTurnAngle = frac * 90.0;
                if (Math.Abs (newTurnAngle - turnAngle) > 0.5) {
                    turnAngle = newTurnAngle;
                    vessel.AutoPilot.TargetPitchAndHeading (
                        (float)(90 - turnAngle), 90);
                }
            }

            // Separate SRBs when finished
            if (!srbsSeparated) {
                if (srbFuel.Get () < 0.1) {
                    vessel.Control.ActivateNextStage ();
                    srbsSeparated = true;
                    Console.WriteLine ("SRBs separated");
                }
            }

            // Decrease throttle when approaching target apoapsis
            if (apoapsis.Get () > targetAltitude * 0.9) {
                Console.WriteLine ("Approaching target apoapsis");
                break;
            }
        }
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
  // Activate the first stage
  vessel.control().activate_next_stage();
  vessel.auto_pilot().engage();
  vessel.auto_pilot().target_pitch_and_heading(90, 90);

  // Main ascent loop
  bool srbs_separated = false;
  double turn_angle = 0;
  while (true) {
    // Gravity turn
    if (altitude() > turn_start_altitude && altitude() < turn_end_altitude) {
      double frac = (altitude() - turn_start_altitude)
                    / (turn_end_altitude - turn_start_altitude);
      double new_turn_angle = frac * 90.0;
      if (std::abs(new_turn_angle - turn_angle) > 0.5) {
        turn_angle = new_turn_angle;
        vessel.auto_pilot().target_pitch_and_heading(90.0 - turn_angle, 90.0);
      }
    }

    // Separate SRBs when finished
    if (!srbs_separated) {
      if (srb_fuel() < 0.1) {
        vessel.control().activate_next_stage();
        srbs_separated = true;
        std::cout << "SRBs separated" << std::endl;
      }
    }

    // Decrease throttle when approaching target apoapsis
    if (apoapsis() > target_altitude * 0.9) {
      std::cout << "Approaching target apoapsis" << std::endl;
      break;
    }
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
        // Activate the first stage
        vessel.getControl().activateNextStage();
        vessel.getAutoPilot().engage();
        vessel.getAutoPilot().targetPitchAndHeading(90, 90);

        // Main ascent loop
        boolean srbsSeparated = false;
        double turnAngle = 0;
        while (true) {

            // Gravity turn
            if (altitude.get() > turnStartAltitude &&
                altitude.get() < turnEndAltitude) {
                double frac = (altitude.get() - turnStartAltitude)
                              / (turnEndAltitude - turnStartAltitude);
                double newTurnAngle = frac * 90.0;
                if (Math.abs(newTurnAngle - turnAngle) > 0.5) {
                    turnAngle = newTurnAngle;
                    vessel.getAutoPilot().targetPitchAndHeading(
                        (float)(90 - turnAngle), 90);
                }
            }

            // Separate SRBs when finished
            if (!srbsSeparated) {
              if (srbFuel.get() < 0.1) {
                    vessel.getControl().activateNextStage();
                    srbsSeparated = true;
                    System.out.println("SRBs separated");
                }
            }

            // Decrease throttle when approaching target apoapsis
            if (apoapsis.get() > targetAltitude * 0.9) {
                System.out.println("Approaching target apoapsis");
                break;
            }
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
-- Activate the first stage
vessel.control:activate_next_stage()
vessel.auto_pilot:engage()
vessel.auto_pilot:target_pitch_and_heading(90, 90)

-- Main ascent loop
local srbs_separated = false
local turn_angle = 0
while true do

    -- Gravity turn
    if flight.mean_altitude > turn_start_altitude and flight.mean_altitude < turn_end_altitude then
        frac = (flight.mean_altitude - turn_start_altitude) / (turn_end_altitude - turn_start_altitude)
        new_turn_angle = frac * 90
        if math.abs(new_turn_angle - turn_angle) > 0.5 then
            turn_angle = new_turn_angle
            vessel.auto_pilot:target_pitch_and_heading(90-turn_angle, 90)
        end
    end

    -- Separate SRBs when finished
    if not srbs_separated then
        if stage_2_resources:amount('SolidFuel') < 0.1 then
            vessel.control:activate_next_stage()
            srbs_separated = true
            print('SRBs separated')
        end
    end

    -- Decrease throttle when approaching target apoapsis
    if vessel.orbit.apoapsis_altitude > target_altitude*0.9 then
        print('Approaching target apoapsis')
        break
    end
end
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# Activate the first stage
vessel.control.activate_next_stage()
vessel.auto_pilot.engage()
vessel.auto_pilot.target_pitch_and_heading(90, 90)

# Main ascent loop
srbs_separated = False
turn_angle = 0
while True:

    # Gravity turn
    if altitude() > turn_start_altitude and altitude() < turn_end_altitude:
        frac = ((altitude() - turn_start_altitude) /
                (turn_end_altitude - turn_start_altitude))
        new_turn_angle = frac * 90
        if abs(new_turn_angle - turn_angle) > 0.5:
            turn_angle = new_turn_angle
            vessel.auto_pilot.target_pitch_and_heading(90-turn_angle, 90)

    # Separate SRBs when finished
    if not srbs_separated:
        if srb_fuel() < 0.1:
            vessel.control.activate_next_stage()
            srbs_separated = True
            print('SRBs separated')

    # Decrease throttle when approaching target apoapsis
    if apoapsis() > target_altitude*0.9:
        print('Approaching target apoapsis')
        break

Next, the program fine tunes the apoapsis, using 10% thrust, then waits until the rocket has left Kerbin’s atmosphere.

80
81
82
83
84
85
86
87
88
89
90
        // Disable engines when target apoapsis is reached
        vessel.Control.Throttle = 0.25f;
        while (apoapsis.Get () < targetAltitude) {
        }
        Console.WriteLine ("Target apoapsis reached");
        vessel.Control.Throttle = 0;

        // Wait until out of atmosphere
        Console.WriteLine ("Coasting out of atmosphere");
        while (altitude.Get () < 70500) {
        }
73
74
75
76
77
78
79
80
81
82
  // Disable engines when target apoapsis is reached
  vessel.control().set_throttle(0.25);
  while (apoapsis() < target_altitude) {
  }
  std::cout << "Target apoapsis reached" << std::endl;
  vessel.control().set_throttle(0);

  // Wait until out of atmosphere
  std::cout << "Coasting out of atmosphere" << std::endl;
  while (altitude() < 70500) {
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
        // Disable engines when target apoapsis is reached
        vessel.getControl().setThrottle(0.25f);
        while (apoapsis.get() < targetAltitude) {
        }
        System.out.println("Target apoapsis reached");
        vessel.getControl().setThrottle(0);

        // Wait until out of atmosphere
        System.out.println("Coasting out of atmosphere");
        while (altitude.get() < 70500) {
66
67
68
69
70
71
72
73
74
75
76
-- Disable engines when target apoapsis is reached
vessel.control.throttle = 0.25
while vessel.orbit.apoapsis_altitude < target_altitude do
end
print('Target apoapsis reached')
vessel.control.throttle = 0

-- Wait until out of atmosphere
print('Coasting out of atmosphere')
while flight.mean_altitude < 70500 do
end
64
65
66
67
68
69
70
71
72
73
74
# Disable engines when target apoapsis is reached
vessel.control.throttle = 0.25
while apoapsis() < target_altitude:
    pass
print('Target apoapsis reached')
vessel.control.throttle = 0.0

# Wait until out of atmosphere
print('Coasting out of atmosphere')
while altitude() < 70500:
    pass

It is now time to plan the circularization burn. First, we calculate the delta-v required to circularize the orbit using the vis-viva equation. We then calculate the burn time needed to achieve this delta-v, using the Tsiolkovsky rocket equation.

 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
        // Plan circularization burn (using vis-viva equation)
        Console.WriteLine ("Planning circularization burn");
        double mu = vessel.Orbit.Body.GravitationalParameter;
        double r = vessel.Orbit.Apoapsis;
        double a1 = vessel.Orbit.SemiMajorAxis;
        double a2 = r;
        double v1 = Math.Sqrt (mu * ((2.0 / r) - (1.0 / a1)));
        double v2 = Math.Sqrt (mu * ((2.0 / r) - (1.0 / a2)));
        double deltaV = v2 - v1;
        var node = vessel.Control.AddNode (
            ut.Get () + vessel.Orbit.TimeToApoapsis, prograde: (float)deltaV);

        // Calculate burn time (using rocket equation)
        double F = vessel.AvailableThrust;
        double Isp = vessel.SpecificImpulse * 9.82;
        double m0 = vessel.Mass;
        double m1 = m0 / Math.Exp (deltaV / Isp);
        double flowRate = F / Isp;
        double burnTime = (m0 - m1) / flowRate;
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
  // Plan circularization burn (using vis-viva equation)
  std::cout << "Planning circularization burn" << std::endl;
  double mu = vessel.orbit().body().gravitational_parameter();
  double r = vessel.orbit().apoapsis();
  double a1 = vessel.orbit().semi_major_axis();
  double a2 = r;
  double v1 = std::sqrt(mu * ((2.0 / r) - (1.0 / a1)));
  double v2 = std::sqrt(mu * ((2.0 / r) - (1.0 / a2)));
  double delta_v = v2 - v1;
  auto node = vessel.control().add_node(
    ut() + vessel.orbit().time_to_apoapsis(), delta_v);

  // Calculate burn time (using rocket equation)
  double F = vessel.available_thrust();
  double Isp = vessel.specific_impulse() * 9.82;
  double m0 = vessel.mass();
  double m1 = m0 / std::exp(delta_v / Isp);
  double flow_rate = F / Isp;
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
        // Plan circularization burn (using vis-viva equation)
        System.out.println("Planning circularization burn");
        double mu = vessel.getOrbit().getBody().getGravitationalParameter();
        double r = vessel.getOrbit().getApoapsis();
        double a1 = vessel.getOrbit().getSemiMajorAxis();
        double a2 = r;
        double v1 = Math.sqrt(mu * ((2.0 / r) - (1.0 / a1)));
        double v2 = Math.sqrt(mu * ((2.0 / r) - (1.0 / a2)));
        double deltaV = v2 - v1;
        Node node = vessel.getControl().addNode(
          ut.get() + vessel.getOrbit().getTimeToApoapsis(), (float)deltaV, 0, 0);

        // Calculate burn time (using rocket equation)
        double force = vessel.getAvailableThrust();
        double isp = vessel.getSpecificImpulse() * 9.82;
        double m0 = vessel.getMass();
        double m1 = m0 / Math.exp(deltaV / isp);
        double flowRate = force / isp;
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
---- Plan circularization burn (using vis-viva equation)
print('Planning circularization burn')
local mu = vessel.orbit.body.gravitational_parameter
local r = vessel.orbit.apoapsis
local a1 = vessel.orbit.semi_major_axis
local a2 = r
local v1 = math.sqrt(mu*((2./r)-(1./a1)))
local v2 = math.sqrt(mu*((2./r)-(1./a2)))
local delta_v = v2 - v1
local node = vessel.control:add_node(conn.space_center.ut + vessel.orbit.time_to_apoapsis, delta_v, 0, 0)

---- Calculate burn time (using rocket equation)
local F = vessel.available_thrust
local Isp = vessel.specific_impulse * 9.82
local m0 = vessel.mass
local m1 = m0 / math.exp(delta_v/Isp)
local flow_rate = F / Isp
local burn_time = (m0 - m1) / flow_rate
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# Plan circularization burn (using vis-viva equation)
print('Planning circularization burn')
mu = vessel.orbit.body.gravitational_parameter
r = vessel.orbit.apoapsis
a1 = vessel.orbit.semi_major_axis
a2 = r
v1 = math.sqrt(mu*((2./r)-(1./a1)))
v2 = math.sqrt(mu*((2./r)-(1./a2)))
delta_v = v2 - v1
node = vessel.control.add_node(
    ut() + vessel.orbit.time_to_apoapsis, prograde=delta_v)

# Calculate burn time (using rocket equation)
F = vessel.available_thrust
Isp = vessel.specific_impulse * 9.82
m0 = vessel.mass
m1 = m0 / math.exp(delta_v/Isp)
flow_rate = F / Isp
burn_time = (m0 - m1) / flow_rate

Next, we need to rotate the craft and wait until the circularization burn. We orientate the ship along the y-axis of the maneuver node’s reference frame (i.e. in the direction of the burn) then time warp to 5 seconds before the burn.

112
113
114
115
116
117
118
119
120
121
122
        // Orientate ship
        Console.WriteLine ("Orientating ship for circularization burn");
        vessel.AutoPilot.ReferenceFrame = node.ReferenceFrame;
        vessel.AutoPilot.TargetDirection = Tuple.Create (0.0, 1.0, 0.0);
        vessel.AutoPilot.Wait ();

        // Wait until burn
        Console.WriteLine ("Waiting until circularization burn");
        double burnUT = ut.Get () + vessel.Orbit.TimeToApoapsis - (burnTime / 2.0);
        double leadTime = 5;
        conn.SpaceCenter ().WarpTo (burnUT - leadTime);
105
106
107
108
109
110
111
112
113
114
  // Orientate ship
  std::cout << "Orientating ship for circularization burn" << std::endl;
  vessel.auto_pilot().set_reference_frame(node.reference_frame());
  vessel.auto_pilot().set_target_direction(std::make_tuple(0.0, 1.0, 0.0));
  vessel.auto_pilot().wait();

  // Wait until burn
  std::cout << "Waiting until circularization burn" << std::endl;
  double burn_ut = ut() + vessel.orbit().time_to_apoapsis() - (burn_time / 2.0);
  double lead_time = 5;
123
124
125
126
127
128
129
130
131
132
133
134
        // Orientate ship
        System.out.println("Orientating ship for circularization burn");
        vessel.getAutoPilot().setReferenceFrame(node.getReferenceFrame());
        vessel.getAutoPilot().setTargetDirection(
          new Triplet<Double,Double,Double>(0.0, 1.0, 0.0));
        vessel.getAutoPilot().wait_();

        // Wait until burn
        System.out.println("Waiting until circularization burn");
        double burnUt =
          ut.get() + vessel.getOrbit().getTimeToApoapsis() - (burnTime / 2.0);
        double leadTime = 5;
 97
 98
 99
100
101
102
103
104
105
106
107
-- Orientate ship
print('Orientating ship for circularization burn')
vessel.auto_pilot.reference_frame = node.reference_frame
vessel.auto_pilot.target_direction = List{0, 1, 0}
vessel.auto_pilot:wait()

-- Wait until burn
print('Waiting until circularization burn')
local burn_ut = conn.space_center.ut + vessel.orbit.time_to_apoapsis - (burn_time/2.)
local lead_time = 5
conn.space_center.warp_to(burn_ut - lead_time)
 96
 97
 98
 99
100
101
102
103
104
105
106
# Orientate ship
print('Orientating ship for circularization burn')
vessel.auto_pilot.reference_frame = node.reference_frame
vessel.auto_pilot.target_direction = (0, 1, 0)
vessel.auto_pilot.wait()

# Wait until burn
print('Waiting until circularization burn')
burn_ut = ut() + vessel.orbit.time_to_apoapsis - (burn_time/2.)
lead_time = 5
conn.space_center.warp_to(burn_ut - lead_time)

This next part executes the burn. It sets maximum throttle, then throttles down to 5% approximately a tenth of a second before the predicted end of the burn. It then monitors the remaining delta-v until it flips around to point retrograde (at which point the node has been executed).

124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
        // Execute burn
        Console.WriteLine ("Ready to execute burn");
        var timeToApoapsis = conn.AddStream (() => vessel.Orbit.TimeToApoapsis);
        while (timeToApoapsis.Get () - (burnTime / 2.0) > 0) {
        }
        Console.WriteLine ("Executing burn");
        vessel.Control.Throttle = 1;
        System.Threading.Thread.Sleep ((int)((burnTime - 0.1) * 1000));
        Console.WriteLine ("Fine tuning");
        vessel.Control.Throttle = 0.05f;
        var remainingBurn = conn.AddStream (
            () => node.RemainingBurnVector (node.ReferenceFrame));
        while (remainingBurn.Get ().Item1 > 0) {
        }
        vessel.Control.Throttle = 0;
        node.Remove ();

        Console.WriteLine ("Launch complete");
        conn.Dispose();
    }
}
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
  // Execute burn
  std::cout << "Ready to execute burn" << std::endl;
  auto time_to_apoapsis = vessel.orbit().time_to_apoapsis_stream();
  while (time_to_apoapsis() - (burn_time / 2.0) > 0) {
  }
  std::cout << "Executing burn" << std::endl;
  vessel.control().set_throttle(1);
  std::this_thread::sleep_for(
    std::chrono::milliseconds(static_cast<int>((burn_time - 0.1) * 1000)));
  std::cout << "Fine tuning" << std::endl;
  vessel.control().set_throttle(0.05);
  auto remaining_burn = node.remaining_burn_vector_stream(node.reference_frame());
  while (std::get<0>(remaining_burn()) > 0) {
  }
  vessel.control().set_throttle(0);
  node.remove();

  std::cout << "Launch complete" << std::endl;
}
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
        // Execute burn
        System.out.println("Ready to execute burn");
        Stream<Double> timeToApoapsis =
          connection.addStream(vessel.getOrbit(), "getTimeToApoapsis");
        while (timeToApoapsis.get() - (burnTime / 2.0) > 0) {
        }
        System.out.println("Executing burn");
        vessel.getControl().setThrottle(1);
        Thread.sleep((int)((burnTime - 0.1) * 1000));
        System.out.println("Fine tuning");
        vessel.getControl().setThrottle(0.05f);
        Stream<Triplet<Double,Double,Double>> remainingBurn =
          connection.addStream(
            node, "remainingBurnVector", node.getReferenceFrame());
        while (remainingBurn.get().getValue1() > 0) {
        }
        vessel.getControl().setThrottle(0);
        node.remove();

        System.out.println("Launch complete");
        connection.close();
    }
}
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
-- Execute burn
print('Ready to execute burn')
while vessel.orbit.time_to_apoapsis - (burn_time/2.) > 0 do
end
print('Executing burn')
vessel.control.throttle = 1
platform.sleep(burn_time - 0.1)
print('Fine tuning')
vessel.control.throttle = 0.05
while node:remaining_burn_vector(node.reference_frame)[2] > 0 do
end
vessel.control.throttle = 0
node:remove()

print('Launch complete')
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# Execute burn
print('Ready to execute burn')
time_to_apoapsis = conn.add_stream(getattr, vessel.orbit, 'time_to_apoapsis')
while time_to_apoapsis() - (burn_time/2.) > 0:
    pass
print('Executing burn')
vessel.control.throttle = 1.0
time.sleep(burn_time - 0.1)
print('Fine tuning')
vessel.control.throttle = 0.05
remaining_burn = conn.add_stream(node.remaining_burn_vector, node.reference_frame)
while remaining_burn()[1] > 0:
    pass
vessel.control.throttle = 0.0
node.remove()

print('Launch complete')

The rocket should now be in a circular 150km orbit above Kerbin.