Jump to content

The Cheap and Cheerful Rocket Payload Challenge 1.0.5


Recommended Posts

5 hours ago, numerobis said:

26 kickbacks. Ouch. How do you pack them in so densely?

The Rhino is not even 10% of your first-stage thrust. I wonder: would it be worth adding a pair of kickbacks and ditching the fuel and fuel lines on the first stage, making it SRB only?

Every test I did showed that running an upper stage engine at an inefficient time leaves more DV in orbit I am guessing this is due to lower gravity losses being greater than inefficient engines. You also have to remember that most of the vacuum engines have 90% of their ISP by 10000 meters

Has anyone limited their speed at any point in their launch? That is other than of course to keep ap at 80 km

Edited by Nich
Link to comment
Share on other sites

55 minutes ago, Nich said:

Every test I did showed that running an upper stage engine at an inefficient time leaves more DV in orbit I am guessing this is due to lower gravity losses being greater than inefficient engines. You also have to remember that most of the vacuum engines have 90% of their ISP by 10000 meters

I guess my real point was: is it worthwhile adding fuel tanks above the SRBs, because you're only burning a minute's worth of fuel out of them, so they'll be smaller, less cost-effective tanks, plus you have to pay for a fuel line.

Regardless, I'm starting to make progress on flight: I got maccollo's "medium" rocket up with a slightly lighter payload, for 750 per tonne.

Link to comment
Share on other sites

1 hour ago, Nich said:

Every test I did showed that running an upper stage engine at an inefficient time leaves more DV in orbit I am guessing this is due to lower gravity losses being greater than inefficient engines. You also have to remember that most of the vacuum engines have 90% of their ISP by 10000 meters

Has anyone limited their speed at any point in their launch? That is other than of course to keep ap at 80 km

I limited my thrust, but not my speed (if that makes any sense).

I throttled back my stage 2 SRBs in order to extend their burn time. That may have limited my design's efficiency...

 I tried to get mine to "float" around 45 km without excessive cosine losses until apoapsis was established. This yielded my best efficiency, but I clearly left some on the table since I don't have MJ.

I agree with your findings; using upper stages in parallel is a definite no-no at least until their Isp matches that of the SRBs. I tried a Poodle cluster both ways, and the series lifter was far cheaper (though not cheap enough to bother submitting here).

Best,
-Slashy

Link to comment
Share on other sites

I fired up the poodles att about 3-4km, with ruffly corresponds to when their isp reaches that os the SRBs.

I was thinking about making my rocket twice as big and basically duplicating all parts.   This would allow me to remove the last inline decoupler  and replace it with small hard points as the twin-boars would be radially attached.  This would in theory mean a 0.5 % or 3 funds/ton improvement.

 

Link to comment
Share on other sites

The benefit is a bit bigger I think than what you accounted for: Doubling up, you can also merge the boosters together. That means a Jumbo instead of two X200-32s, and it means you still only need two fuel lines and two hard-points to the twin-boar stage even though you doubled up. That's another 920 funds you save, putting you over 1% savings.

There's also that you win on upper-stage mass: you save 350kg on that big decoupler, most of the way up to orbit, and you can either have twin poodles on a single hard-point (save 50kg to orbit), or asparagus poodles (save a couple tonnes for the last 200m/s). Those mean you can move some mass to the payload.

I'm not counting struts in here, which matter too. Doubling up, you may be able to get away with fewer -- or you might need more, not sure.

Link to comment
Share on other sites

7 hours ago, PacThePhoenix said:

Using your scoring system, I can spend any amount of credits to launch nothing into orbit, giving me a divide-by-zero error and therefore a score of UNDEFINED. Does that mean I win? :D

Well, if you keep the cost of the rocket fixed, as the payload mass approaches zero your funds/tonne approaches infinity. So you'd have the worst possible score. Sorry.

Link to comment
Share on other sites

11 hours ago, Meithan said:

Well, if you keep the cost of the rocket fixed, as the payload mass approaches zero your funds/tonne approaches infinity. So you'd have the worst possible score. Sorry.

I am aware of that. Any amount of payload would result in a score >zero. What I was joking about was launching a rocket without a payload, so the payload mass is zero. No matter what amount of credits you divide by zero, it will always be undefined, which could either be the best or worst score mathematically (probably the latter as undefined is not a number and is, really, cheating) :D.

Link to comment
Share on other sites

37 minutes ago, PacThePhoenix said:

I am aware of that. Any amount of payload would result in a score >zero. What I was joking about was launching a rocket without a payload, so the payload mass is zero. No matter what amount of credits you divide by zero, it will always be undefined, which could either be the best or worst score mathematically (probably the latter as undefined is not a number and is, really, cheating) :D.

Well no, my point was that the result of dividing a nonzero quantity by zero can technically be considered to be infinity, so your score would then be the worst possible, not just undefined.

But I'm just joking as well. Let's not drift too much off-topic.

Link to comment
Share on other sites

  • 3 weeks later...

I am getting very, very close to replicating @Nefrums flight with a MechJeb ascent. I just need to lighten it up by a couple tonnes and add a smidge of fuel: an extra T100 on each of the SRBs (they were running dry a bit early anyway) and reduce the C7 adapter in the payload to just 308 OX and no LF. Then I get (103709 - 25567) / 126.790 = 616.31 funds per tonne. I've got 153kg of fuel left in the tanks after circularizing at 80km.

The MechJeb parameters: turn immediately (0.1km, 3 m/s) on a 50% turn ending at 13km and 18 degrees thenceforth, aim for 80.1km. At the last stage, ideally I let time-to-Ap hit 0s exactly at the time that we circularize. 

The SRB stage decoupling is exciting, but seems reliable.

Now I'm working on making a cheaper version by doubling up. Scaling up isn't as easy as it seems. I got a flight at 612, but there's a lot of launch failures.

Link to comment
Share on other sites

  • 3 weeks later...

OK, finally got something very similar to Nefrums' ship up to space, in a repeatable way. Here's the kOS code for it:

Spoiler

// Off the pad we pitch over to this attitude (degrees)
set pitchoverAngle to 89.

// "Off the pad" is defined as up to this vertical speed (m/s)
set pitchoverSpeed to 5.

// The final orbit goal (meters)
set targetOrbitAltitude to 80000.

// Pitch up if time to apoapsis falls below here (seconds)
// Best to make this a smooth curve, so we don't jerk around.
function targetTTA {
 set targetAltitude to 40000.
 set ttaOnGround to 120.
 set ttaAtAltitude to 20.
 set ratio to max(0, (targetAltitude - ship:apoapsis) / targetAltitude).
 return ratio * ttaOnGround + (1-ratio) * ttaAtAltitude.
}

// In addition to thrusting enough to maintain your altitude, boost a bit more
// (m/s^2).
function thrustBoost {
  // Boost 1m/s^2 until we reach a safe altitude, then reduce to zero at 40km.
  // Don't reduce it all at once because it causes us to lurch.
  set fullBoost to 1.
  set decayStart to 37000.
  set decayEnd to 40000.
  set ratio to (decayEnd - ship:altitude) / (decayEnd - decayStart).
  return fullBoost * max(0, min(1, ratio)).
}

// In the lower atmosphere, don't let angle of attack exceed this (degrees)
// TODO: make this a smooth curve so we don't jerk around, but it's not too
// bad as-is.
set maxAoA to 1.5.
when ship:altitude > 10000 then {
  set maxAoA to 3.
  when ship:altitude > 15000 then {
    set maxAoA to 6.
    when ship:altitude > 20000 then {
      set maxAoA to 10.
      when ship:altitude > 25000 then {
        set maxAoA to 20.
        when ship:altitude > 30000 then {
          set maxAoA to 45.
        }
      }
    }
  }
}

// Voodoo magic.
set STEERINGMANAGER:MAXSTOPPINGTIME to 10.
set STEERINGMANAGER:PITCHTS to 10.
set STEERINGMANAGER:YAWTS to 4.

///////////////////////////////////////////////////////////////////////////
// No more settings left. Now it's just code.
set mysteer to heading(90,90).
set mythrottle to 1.
lock steering to mysteer.
lock throttle to mythrottle.

function steer {
 PARAMETER pitch.
 // Limit the lurch by pointing at most 8 degrees from the current pitch.
 // Otherwise we risk overshooting.
 set currentPitch to 90 - vang(ship:up:vector, ship:facing:forevector).
 set limitedPitch to max(currentPitch - 8, min(currentPitch + 8, pitch)).
 set mysteer to heading(90, limitedPitch).
}

function targetPitch {
  PARAMETER flightPathAngle.

  set horizontalOrbitSpeed to sqrt(ship:velocity:orbit:mag^2 - ship:verticalSpeed^2).

  // Calculate what pitch we need to hit our time-to-apoapsis target.
  set localR to ship:altitude + ship:body:radius.
  // local gravity, points down, m/s^2
  set localG to ship:body:mu / localR^2.
  // centripetal acceleration, points up, m/s^2
  set localC to horizontalOrbitSpeed^2 / localR. 
  // apparent gravity
  set apparentG to localG - localC.
  // what fraction of apparent gravity to do we want to cancel out?
  // Interpolate the time-to-apoapsis target: at 0 TTA, we cancel it all out;
  // at the targetTTA, we burn horizontally. If we're falling, TTA is large
  // but useless; cancel all the local gravity out, and then some.
  set tta to targetTTA().
  set targetRatio to (tta - ETA:APOAPSIS) / tta.
  if (ship:verticalSpeed < 0) {
    set targetRatio to 1.5.
  } else if targetRatio < 0 {
    return 0.
  }
  set targetAccel to apparentG * targetRatio + thrustBoost().

  // what pitch achieves that target vertical acceleration?
  set thrustAccel to ship:availableThrust / ship:mass.
  if (thrustAccel < targetAccel) {
    return 90.
  } else {
    return arcsin(targetAccel / thrustAccel).
  }
}

// on launch, go straight up until we reach 5 m/s: until then our direction
// readouts are wonky
until ship:verticalSpeed > pitchoverSpeed {
  print "pitch-over".
  steer(pitchoverAngle).
}

// from then on, be smarter.
until ship:apoapsis > targetOrbitAltitude {
  // Calculate what direction is "prograde"
  set flightPathAngle to 90 - vang(ship:up:vector, ship:velocity:surface).

  // Calculate what direction we want to point to maintain TTA
  set ttaAngle to targetPitch(flightPathAngle).

  // Aim for the TTA but mind the angle of attack
  set pitch to min(flightPathAngle + maxAoA, max(flightPathAngle - maxAoA, ttaAngle)).
  steer(pitch).

  // log what we're doing
  set progradeDeg to round(flightPathAngle, 2).
  set ttaDeg to round(ttaAngle, 2).
  set pitchDeg to round(pitch, 2).
  print "pitch " + pitchDeg + ": prograde (" + progradeDeg + ") / TTA (" + ttaDeg + ")".
}

print "coasting to apoapsis".

until ship:altitude > 70000 {
  set flightPathAngle to 90 - vang(ship:up:vector, ship:velocity:surface).
  steer(flightPathAngle).
  if ship:apoapsis < targetOrbitAltitude {
    set mythrottle to 0.1.
  } else {
    set mythrottle to 0.
  }
}

set mythrottle to 0.

// make sure we are at zero throttle when we release the control back to the
// pilot.
set SHIP:CONTROL:PILOTMAINTHROTTLE to 0.

print "out of atmosphere; control released".

 

I reliably end with 5 m/s. I must have a tiny amount less payload onboard than @Nefrums does -- or an extra strut or something --because I get 603 funds per tonne for my build.

I'm curious if this kOS script plays well with other spacecraft. I'll have to try!

By the way, I recommend turning on mechjeb auto staging while running this script, because I didn't implement it.

Link to comment
Share on other sites

  • 2 weeks later...

Some improvements to the program:

Spoiler

// The final orbit goal (meters ASL)
set targetOrbitAltitude to 80000.

// The initial orbit goal (meters ASL)
set targetInitialOrbit to 38000.

// The curve that describes our pitch depending on altitude.
// Altitude is in meters, target is in degrees; at that altitude, we want
// to hit that flight path angle.
// Piecewise linear curve maps altitude to degrees pitch.
set gravityTurnPitchAltitude to list( 0, 500, 4000, 5500, 10000, 15000, 20000, 25000, targetInitialOrbit).
set gravityTurnPitchAngle    to list(90,  75,   60,   45,    30,    20,    17,    15, 0).

// Below this altitude, do the gravity turn without worrying about TTA (meters)
set lowAtmosphereAltitude to 10000.

// Ensure that we never get to less than this amount of time until we reach
// apoapsis, taking into account that we are thrusting upwards. The estimated
// time to apoapsis can freely dive below this, because it assumes we don't
// thrust upwards at all. (seconds)
set targetTTA to 20.

// In the lower atmosphere, don't let angle of attack exceed certain bounds.
// Piecewise linear curve maps altitude to degrees angle of attack bound.
set maxAoAAltitude to list(0, 1000, 10000, 15000, 20000, 25000, 30000, 70000).
set maxAoAAngle    to list(5,  1.5,   1.5,     3,     6,    10,    20,    45).

// Voodoo magic.
set STEERINGMANAGER:MAXSTOPPINGTIME to 10.
set STEERINGMANAGER:PITCHTS to 10.
set STEERINGMANAGER:YAWTS to 10.

///////////////////////////////////////////////////////////////////////////
// No more settings left. Now it's just code.
set mysteer to heading(90,90).
set mythrottle to 1.
lock steering to mysteer.
lock throttle to mythrottle.

function lerp {
  parameter t.
  parameter min.
  parameter max.
  parameter minY.
  parameter maxY.
  return (t - min) / (max - min) * (maxY - minY) + minY.
}

function curve {
  parameter t.
  parameter keys.
  parameter values.

  from {local i is 1.}
  until i = keys:length
  step { set i to i + 1. }
  do {
    if t < keys[i] {
      return lerp(t, keys[i-1], keys[i], values[i-1], values[i]).
    }
  }
  return values[keys:length - 1].
}

function steer {
 PARAMETER pitch.
 // Limit the lurch by pointing at most 8 degrees from the current pitch.
 // Otherwise we risk overshooting.
 set currentPitch to 90 - vang(ship:up:vector, ship:facing:forevector).
 set limitedPitch to max(currentPitch - 8, min(currentPitch + 8, pitch)).
 set mysteer to heading(90, limitedPitch).
}

function gravityTurnPitch {
  return curve(ship:altitude, gravityTurnPitchAltitude, gravityTurnPitchAngle).
}

function targetPitchForAcceleration {
  parameter targetAccel.
  set thrustAccel to ship:availableThrust / ship:mass.
  if (thrustAccel < targetAccel) {
    return 90.
  } else if (targetAccel < 0) {
    return 0.
  } else {
    return arcsin(targetAccel / thrustAccel).
  }
}

// Compute the apparent gravity (gravity minus centripetal acceleration)
function apparentGravity {
  set horizontalOrbitSpeed to sqrt(ship:velocity:orbit:mag^2 - ship:verticalSpeed^2).
  set localR to ship:altitude + ship:body:radius.
  set localG to ship:body:mu / localR^2.
  set localC to horizontalOrbitSpeed^2 / localR.
  return localG - localC.
}

// How much vertical acceleration do we need to keep apoapsis ahead of us?
function targetAccelToMaintainTTA {
  // What downward acceleration can we tolerate? Enough to wipe out
  // our vertical speed in TTA seconds. That means: v = (g - a) t
  // solve for a:  a = g - v/t
  // This works equally well for negative vertical speed.
  return apparentGravity() - (ship:verticalSpeed / targetTTA).
}


// How much acceleration do we need in order to fight gravity just enough
// that our apoapsis, including thrust, will reach the initial orbit altitude?
function targetAccelToEstablishApoapsis {
  // Move long names into mathy ones so I can describe things:
  set Apn to targetInitialOrbit.
  set Ap to ship:apoapsis.

  // If we already reached the Ap for initial orbit, we have nothing to say.
  if (Ap > Apn) { return 0. }

  // Apparent gravity is pulling us down at a rate of g m/s^2.
  // Thrust is pushing us up at a rate of T m/s^2.
  // Overall we're losing vertical speed at a = (g - T).
  // The amount of vertical speed to lose is v.
  // That means our time to apoapsis is t = v/a.
  // During that time we'll go (at^2/2) m up, which equals 0.5 v^2/a
  // We need to go up by (Apn - h) m:
  //  (Apn-h) = 0.5 v^2/a
  //  a = 0.5 v^2 / (Apn-h)
  //  T = g - 0.5 v^2 / (Apn-h)
  // Setting our thrust to T will guarantee we hit apoapsis.
  //
  // This ignores drag, loss of mass, staging, horizontal acceleration,
  // and some more minor sources of error. Most of them would argue for
  // a flatter pitch; staging can argue for either way.
  //
  // This assumes v is positive; negative v is handled by the TTA function.

  return apparentGravity() - 0.5 * ship:verticalSpeed^2 / (Apn - ship:altitude).
}
///////////////////////////////////////////////////////////////////////////
// Flight control!

until ship:apoapsis > targetOrbitAltitude {
  // At low speed, just go up; "prograde" doesn't exist yet.
  if (ship:velocity:surface:mag < 1) { set flightPathAngle to 90. }

  // Calculate what direction is prograde.
  set flightPathAngle to 90 - vang(ship:up:vector, ship:velocity:surface).

  // Generally, follow the gravity turn.
  set targetPitch to gravityTurnPitch().
  set targetReason to "gravity turn".

  // Once we get into the upper atmosphere, start adjusting for
  // TTA and actually reaching the initial orbit.
  if (ship:altitude > lowAtmosphereAltitude) {
    // Check how much we need to accelerate to make sure we get to our
    // staging orbit, or how much to avoid overshooting the apoapsis.
    set ttaAccel to targetAccelToMaintainTTA().
    set apAccel to targetAccelToEstablishApoapsis().
    set accelPitch to targetPitchForAcceleration(max(ttaAccel, apAccel)).
    // If it's more than the nominal flight plan allows for, pull up!
    if (accelPitch > targetPitch) {
      set targetPitch to accelPitch.
      if (ttaAccel > apAccel) {
        set targetReason to "TTA".
      } else {
        set targetReason to "apoapsis".
      }
    }
  }

  // Stay within angle-of-attack bounds and never pitch below the horizon.
  set maxAoA to curve(ship:altitude, maxAoAAltitude, maxAoAAngle).
  set aoaLimitedPitch to min(flightPathAngle + maxAoA, max(flightPathAngle - maxAoA, targetPitch)).
  set pitch to max(0, aoaLimitedPitch).
  steer(pitch).

  // log what we're doing
  set pitchDeg to round(pitch, 2).
  print "pitch " + pitchDeg + " => " + targetReason + " " + round(targetPitch, 2) + " degrees".
}

print "coasting to apoapsis".
until ship:altitude > 70000 {
  set flightPathAngle to 90 - vang(ship:up:vector, ship:velocity:surface).
  steer(flightPathAngle).
  if ship:apoapsis < targetOrbitAltitude + 10 {
    set mythrottle to 0.05.
  } else {
    set mythrottle to 0.
  }
}

// make sure we are at zero throttle when we release the control back to the
// pilot.
set mythrottle to 0.
set SHIP:CONTROL:PILOTMAINTHROTTLE to 0.

print "out of atmosphere; control released".

 

This gets me a smoother flight and 12 m/s remaining when I hit 70km: eTc8jRC.png

For some reason I can't hit enter to make paragraphs... I love this comment software.

Oh but now I can, after reloading.

So as you can see, 12 m/s in the fuel tanks, 36 m/s to circularize at 80 km.

@Nefrums mentioned being about 30 m/s from empty upon reaching a 80x1km orbit. To get to 80x38 from there costs about 35 m/s, so I'm 47 m/s more efficient than their flight plan. Woot! I have difficulty believing I can do substantially better.

About the code: there are three bits. I start the ascent with just a fixed turn profile, nothing fancy, but pretty steep: I cross 45 degrees pitch at just 5500m altitude, and by 10km I'm pushing down to get to 30 degrees.

Afterwards, what takes over is code to make sure that when I get to apoapsis, I'll be at 38km. The logic is: figure out how much vertical thrust is needed so that we reach 38km before vertical velocity goes to zero.

Finally, near apoapsis, I thrust upwards just enough that am guaranteed never to get to within 20s of actually reaching apoapsis. Improving this logic -- approaching apoapsis a bit more -- might save a few more m/s.

Edited by numerobis
Link to comment
Share on other sites

Try to keep as little angle of attack as possible when below 30 km as drag increases allot if the rocket is not pointing pro grade.  I used prograde lock for the most of the first and second stage.

Also you can save a few funds/ton by attaching the struts from the payload and out rather than the other way,  As the mass of the strut then stays with the payload

Link to comment
Share on other sites

Indeed; my script limits AoA to 1.5 degrees below 10km and eases up after.

There isn't a lot left to save on drag: of that 144 m/s, nearly 100 m/s is in the first 10km. There's a lot more to save on gravity losses, which means pitching over more steeply at the start so I get more horizontal velocity from the SRBs.

I didn't program in your trick of starting the poodles at altitude. The spacecraft has about 3200 m/s of vacuum fuel packed on board and ends up burning 3092 m/s, so that's 100 m/s lost to atmospheric pressure. But there's the risk of extra gravity loss from having an even lower TWR at the start.

Link to comment
Share on other sites

  • 2 weeks later...

I just circularized @Nefrums' build (plus, indeed, two extra struts) at 80km.

Two key bits:

  • Go higher. Establish the initial orbit at about 42km. Lower is not necessarily better, because of the high drag losses on the low-thrust stage.
  • Turn off the poodles for 26s in the lower reaches, so that when they're on they are at higher efficiency. I kept them on for the first 10s, off for 26s, then on again for the rest of the ride. Why 26s is that this makes the SRBs run out of fuel at the same time as the fuel tanks they are pushing. Why have them on for 10s is gut instinct -- I should optimize that -- but you get a huge benefit from marginal thrust at the very start.

There's a few more minor bits in there as well.

I reach the top of the atmosphere in an 80x42km orbit, with a bit over 32 m/s in the tanks. Circularizing that orbit costs a bit over 32 m/s. Coincidence!

The spacecraft I have gets 603.57 funds per tonne. Shifting that excess fuel into the payload would save me money for the fuel, plus increase the payload, so that I'd be at exactly 596 funds per tonne.

 

Link to comment
Share on other sites

Geez... this thread is making it hard to beat the cost with an STS style launcher... and a whole lot more convenient if no recovery is needed to get that cost.

My previous STS style was just under 700 per ton, seeing this thread, I designed one to take a bigger payload (and make use of the vector, since my old design was pre-vector).

I filled the mk3 cargobay with mostly ore tanks, and some other "stuff" to get to 72.31 tons

SRBs cost 19,040 -> no recovery

Assuming all LFO is consumed (not quite true): 17,029 funds for fuel

External tank cost: 22,490

The external tank is recoverable, but the sandbox tests didn't tell me the recovery %

It typically lands near the shores accross the ocean from KSC

Cost per ton at 50% recovery (of ET, 100% of orbiter): 654 funds/ton

Cost per ton at 75% recovery (of ET, 100% of orbiter): 576 funds/ton

There doesn't seem to be much room for a partially disposable system to fit between a SSTO and a disposable.

Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...