Project M-III launch vehicle

Pipcard

mikusingularity
Addon Developer
Donator
Joined
Nov 7, 2009
Messages
3,709
Reaction score
38
Points
88
Location
Negishima Space Center
Basically the first stage pitches down too much and gives you not enough vertical speed but too much horizontal speed. Then the second stage tries to correct the vertical energy but of course a big correction if not properly dampened result in big oscillations. My suggestion is to work on the first stage guidance, especially its final states.

If you don't know where to start post the code and I'll try to help there.
Yes, during that launch, the first stage was pitching down more than it should. Here is a section of the F9R code, the relevant functions seem to be "CalcFlightVector" and "GoToFlightVector." (Even though the class says that it's the second stage, it actually controls the entire rocket before separation, where it creates a separate vessel for the first stage.)

Code:
// --------------------------------------------------------------
// Start launch ascent autopilot
// --------------------------------------------------------------
void M_III_stage02::DoAscent(void)
{
    if (eng_status == 1)return;

    CalcAzimuth();
    CalcFlightVector();

    double th_max = GetThrusterMax(th_main[eng_status]);
    double mass = GetMass();
    double maxacc = th_max / mass;
    double englev = 29.5 / maxacc;
    if (englev > 1)englev = 1;

    if (ap_function == 0)
    {
        if (timer == 0) PlayVesselWave(MyID, CTDN, 0, 200, 0);
        timer = timer + step_time;
        if (timer > 10) timer = 10;
        if (timer < 10) englev = (timer - 8) / 2;
        if (englev < 0)englev = 0;
    }
    SetThrusterGroupLevel(THGROUP_MAIN, englev);

    if (GetAltitude() > 70 && ap_function == 0)
    {
        ap_function = 1;
        timer = 0;
    }
    if (ap_function > 0) RollToAz();
    if (ap_function == 2) GoToFlightVector();
    if (ap_function == 3) GoToFlightVector();
    if (ap_function == 4) GoToFlightVector();
    if (ap_function == 5)
    {
        KillAllRCS2();
        SetThrusterGroupLevel(THGROUP_MAIN, 0);
        ActivateNavmode(NAVMODE_KILLROT);
        ap_function = 0;
        ap_status = 0;
        JettisonStg();
        op_status = 1;
    }
}

double M_III_stage02::CalcAzimuth()
{
    double lon, lat, rad;
    GetEquPos(lon, lat, rad);
    if (abs(tgt_inc)<abs(lat)) {
        tgt_inc = abs(lat);
    }
    else {
        tgt_inc = tgt_inc;
    }
    /////////////
    OBJHANDLE hearth = GetSurfaceRef();
    VECTOR3 relvel = _V(0, 0, 0);
    VECTOR3 globpos = _V(0, 0, 0);
    GetRelativeVel(hearth, relvel);
    GetGlobalPos(globpos);
    VECTOR3 relvel_glob = relvel + globpos;
    VECTOR3 rel_vel_loc = _V(0, 0, 0);
    Global2Local(relvel_glob, rel_vel_loc);

    VECTOR3 ov_hrz = _V(0, 0, 0);
    HorizonRot(rel_vel_loc, ov_hrz);

    double orb_ground_spd = sqrt((ov_hrz.x*ov_hrz.x) + (ov_hrz.z*ov_hrz.z));

    VECTOR3 orb_ground_vector = _V(ov_hrz.x, 0, ov_hrz.z);

    ////////
    double tgt_inc_sc = tgt_inc;
    if (lat > 0)
    {
        if (ov_hrz.z < -1 && tgt_inc > 0) tgt_inc_sc = -tgt_inc;
    }
    else if (lat < 0)
    {
        if (ov_hrz.z > 1 && tgt_inc < 0) tgt_inc_sc = -tgt_inc;
    }

    double final_azimuth = asin(cos(tgt_inc_sc) / cos(lat));
    final_azimuth += (90 * RAD - final_azimuth)*(1 - (tgt_inc_sc / abs(tgt_inc_sc)));
    VECTOR3 final_ground_vector = _V((FinalV()*sin(final_azimuth)), 0, (FinalV()*cos(final_azimuth)));

    VECTOR3 req_ground_vector = final_ground_vector - orb_ground_vector;

    azimuth = atan2(req_ground_vector.x, req_ground_vector.z);

    vazim1 = _V(sin(azimuth), 0, cos(azimuth));

    HorizonInvRot(vazim1, azim_local);

    return azimuth;
}

double M_III_stage02::GetOS()
{
    OBJHANDLE hearth = GetSurfaceRef();
    VECTOR3 relvel;
    GetRelativeVel(hearth, relvel);
    double os = length(relvel);
    return os;
}

double M_III_stage02::FinalV()
{
    double tgtapo = 200000;
    double tgtperi = 2000000;
    double abside = tgtapo;
    if (tgtapo <= 260000) {
        abside = tgtapo;
    }
    else {
        abside = tgtperi;
    }
    if (op_status == 1) return sqrt(mu*(2 / (op_meco_alt + rt) - 1 / (0.5*(op_tgt + op_meco_alt + (2 * rt)))));
    else return sqrt(mu*(2 / (abside + rt) - 1 / (0.5*(tgtapo + tgtperi + 2 * rt))));
}

void M_III_stage02::CalcFlightVector()
{

    double plf = sin(PI05*fuel_reserve / 100000);
    if (plf < 0)plf = 0;
    else if (plf > 1)plf = 1;
    plf = (plf*1.5) - (0.25*(cos(tgt_inc)));

    double apof = 0.5 + (1.5*((ap_tgt - 200000) / 100000));

    plf = plf + apof;

    double pitch_limit = (87.1 + plf)*RAD;
    if (pitch_limit > (89 * RAD))pitch_limit = (89 * RAD);////////////////

    if (ap_function == 2)
    {
        pitch_angle = pitch_angle - (step_time*RAD);
        if (pitch_angle < pitch_limit)pitch_angle = pitch_limit;
        if (GetAOA() >(0.5*RAD)) ap_function = 3;
    }

    else if (ap_function == 3)
    {
        VECTOR3 haspdv = _V(0, 1, 0);
        GetHorizonAirspeedVector(haspdv);
        double xzlngth = sqrt((haspdv.x*haspdv.x) + (haspdv.z*haspdv.z));
        if (haspdv.y < 0)haspdv.y = 0;
        pitch_angle = atan2(haspdv.y, xzlngth);
        if (GetAltitude() > 30000) ap_function = 4;
    }

    else if (ap_function == 4)
    {
        double ap_dist = 0;
        GetApDist(ap_dist);

        double englev = GetThrusterGroupLevel(THGROUP_MAIN);
        double fuel_remaining = GetPropellantMass(hProp1) - fuel_reserve;
        double isp_curr = GetThrusterIsp(th_main[eng_status]);
        double th_max = GetThrusterMax(th_main[eng_status]);
        double fuel_rate = englev*th_max / isp_curr;
        double mintime = fuel_remaining / fuel_rate;
        if (mintime < 0)mintime = 0;

        /////////////////////////

        VECTOR3 haspdv = _V(0, 1, 0);
        GetHorizonAirspeedVector(haspdv);
        if (haspdv.y < 0)haspdv.y = 0;

        ///////////////////////////////////////////////////////
        double vmass = GetMass();

        OBJHANDLE hearth = GetSurfaceRef();
        VECTOR3 relvel = _V(0, 0, 0);
        GetRelativeVel(hearth, relvel);
        double orb_vel = length(relvel);
        double orb_grnd_spd = sqrt((orb_vel*orb_vel) - (haspdv.y*haspdv.y));
        double circ = PI2*(rt + GetAltitude());
        double ang_vel = PI2*orb_grnd_spd / circ;
        VECTOR3 angmomvect = _V(0, (-1 * ang_vel), 0);
        VECTOR3 velvect = _V(0, 0, orb_grnd_spd);
        VECTOR3 corvect = crossp(angmomvect, velvect);
        double acc_cor = length(corvect);

        double sinp = sin(GetPitch());
        double dv_grnd = isp_curr*log(vmass / (vmass - fuel_remaining));
        dv_grnd = dv_grnd*sinp;

        double final_orb_grnd_spd = orb_grnd_spd + dv_grnd;
        velvect = _V(0, 0, final_orb_grnd_spd);
        VECTOR3 final_corvect = crossp(angmomvect, velvect);
        double final_acc_cor = length(corvect);

        VECTOR3 weight = _V(0, 0, 0);
        GetWeightVector(weight);

        double gravt = length(weight);
        double gg = (gravt / vmass) - final_acc_cor;
        double aa = (mintime*mintime) / (2 * gg);
        double bb = (haspdv.y*mintime / gg) + ((mintime*mintime) / 2);
        double cc = -(ap_tgt - GetAltitude() - (haspdv.y*mintime) - ((haspdv.y*haspdv.y) / (2 * gg)));

        double req_acc_1 = (-bb + (sqrt((bb*bb) - (4 * aa*cc)))) / (2 * aa);
        double req_acc_2 = (-bb - (sqrt((bb*bb) - (4 * aa*cc)))) / (2 * aa);

        double curr_acc = th_max*englev / (vmass - (fuel_remaining*0.5));

        if (fuel_remaining < (0.5*fuel_rate*step_time))ap_function = 5;

        double total_req_acc = req_acc_1 + gg - acc_cor;

        double psc = total_req_acc / curr_acc;
        if (psc > 0.985)psc = 0.985;
        else if (psc < -0.985)psc = -0.985;
        double pangle = asin(psc);

        if (mintime < 2)pitch_angle = pitch_angle;
        else pitch_angle = pangle;
    }
    vazim2 = _V(vazim1.x, (tan(pitch_angle)), vazim1.z);
    HorizonInvRot(vazim2, flight_vector);
}

void M_III_stage02::RollToAz()
{
    DeactivateNavmode(NAVMODE_KILLROT);
    double roll_angle = atan2(azim_local.x, -azim_local.y);
    if (roll_angle > PI) roll_angle = roll_angle - PI2;
    else if (roll_angle < -PI) roll_angle = roll_angle + PI2;

    double mass = GetMass();

    double max_rcs = GetThrusterMax(th_rcs[0]);
    double max_torque = 2 * max_rcs * 4;
    double inertia = 1.9*mass;

    if (eng_status == 1)
    {
        max_rcs = GetThrusterMax(th_rcs[19]);
        max_torque = 2 * max_rcs*((1.706*0.866) - (0.123*0.25));
        inertia = 1.9*mass;
    }
    VECTOR3 avel = _V(0, 0, 0);
    GetAngularVel(avel);


    double max_acc = max_torque / inertia;

    double max_drot = max_acc*step_time;

    double reqzv = 0.9*(sqrt(abs(roll_angle*max_acc * 2)));
    if (roll_angle > 0)reqzv = -reqzv;

    double req_drot = reqzv - avel.z;

    double thz_lvl = req_drot / max_drot;


    if ((roll_angle*DEG) < 1 && (roll_angle*DEG) > -1)
    {
        reqzv = 1 * -roll_angle;
        double acc_reqz = (reqzv - avel.z) / 0.1;
        thz_lvl = acc_reqz / max_acc;
    }


    if (thz_lvl > 1)thz_lvl = 1;
    else if (thz_lvl < -1)thz_lvl = -1;


    if (thz_lvl > 0)
    {
        SetThrusterGroupLevel(THGROUP_ATT_BANKRIGHT, thz_lvl);
        SetThrusterGroupLevel(THGROUP_ATT_BANKLEFT, 0);
    }
    else if (thz_lvl < 0)
    {
        SetThrusterGroupLevel(THGROUP_ATT_BANKLEFT, -thz_lvl);
        SetThrusterGroupLevel(THGROUP_ATT_BANKRIGHT, 0);
    }
    else
    {
        SetThrusterGroupLevel(THGROUP_ATT_BANKRIGHT, 0);
        SetThrusterGroupLevel(THGROUP_ATT_BANKLEFT, 0);
    }

    if (ap_function == 1)
    {

        if (roll_angle > -0.05 && roll_angle < 0.05)
        {
            VECTOR3 aspdv = _V(0, 1, 0);
            GetHorizonAirspeedVector(aspdv);
            if (aspdv.y > 57)ap_function = 2;
        }
    }
}

void M_III_stage02::GoToFlightVector()
{
    DeactivateNavmode(NAVMODE_KILLROT);

    double angoa = atan2(-flight_vector.y, flight_vector.z);
    double slipage = atan2(flight_vector.x, flight_vector.z);

    if (angoa > PI)angoa = (PI * 2) - angoa;
    else if (angoa < -PI)angoa = (PI * 2) + angoa;

    if (slipage > PI)slipage = (PI * 2) - slipage;
    else if (slipage < -PI)slipage = (PI * 2) + slipage;

    double mass = GetMass();

    double max_rcs = GetThrusterMax(th_rcs[0]);
    double max_torque = 2 * max_rcs * 21;
    double inertia = 128 * mass;

    if (eng_status == 1)
    {
        max_rcs = GetThrusterMax(th_rcs[13]);
        max_torque = 1 * max_rcs*9.8;
        inertia = 18 * mass;
        if (rcs_sw2 == 1)
        {
            max_rcs = GetThrusterMax(th_rcs[16]);
            max_torque = 2 * max_rcs*((4.365*0.866) - (0.123*0.433));
        }
    }

    VECTOR3 avel = _V(0, 0, 0);
    GetAngularVel(avel);
    double max_acc = max_torque / inertia;
    double max_drot = max_acc*step_time;

    double reqxv = 0.9*(sqrt(abs(angoa*max_acc * 2)));
    if (reqxv > vrot_lim)reqxv = vrot_lim;
    if (angoa > 0)reqxv = -reqxv;
    double req_drotx = reqxv - avel.x;
    double thx_lvl = req_drotx / max_drot;
    if ((angoa*DEG) < 1 && (angoa*DEG) > -1)
    {
        reqxv = 1 * -angoa;
        double acc_reqx = (reqxv - avel.x) / 0.1;
        thx_lvl = acc_reqx / max_acc;
    }

    double reqyv = 0.9*(sqrt(abs(slipage*max_acc * 2)));
    if (reqyv > vrot_lim)reqyv = vrot_lim;
    if (slipage > 0)reqyv = -reqyv;
    double req_droty = reqyv - avel.y;
    double thy_lvl = req_droty / max_drot;
    if ((slipage*DEG) < 1 && (slipage*DEG) > -1)
    {
        reqyv = 1 * -slipage;
        double acc_reqy = (reqyv - avel.y) / 0.1;
        thy_lvl = acc_reqy / max_acc;
    }

    if (thx_lvl > 1)thx_lvl = 1;
    else if (thx_lvl < -1)thx_lvl = -1;

    if (thy_lvl > 1)thy_lvl = 1;
    else if (thy_lvl < -1)thy_lvl = -1;


    if (thx_lvl > 0)
    {
        SetThrusterGroupLevel(THGROUP_ATT_PITCHUP, thx_lvl);
        SetThrusterGroupLevel(THGROUP_ATT_PITCHDOWN, 0);
    }
    else if (thx_lvl < 0)
    {
        SetThrusterGroupLevel(THGROUP_ATT_PITCHDOWN, -thx_lvl);
        SetThrusterGroupLevel(THGROUP_ATT_PITCHUP, 0);
    }
    else
    {
        SetThrusterGroupLevel(THGROUP_ATT_PITCHUP, 0);
        SetThrusterGroupLevel(THGROUP_ATT_PITCHDOWN, 0);
    }


    if (thy_lvl > 0)
    {
        SetThrusterGroupLevel(THGROUP_ATT_YAWLEFT, thy_lvl);
        SetThrusterGroupLevel(THGROUP_ATT_YAWRIGHT, 0);
    }
    else if (thy_lvl < 0)
    {
        SetThrusterGroupLevel(THGROUP_ATT_YAWRIGHT, -thy_lvl);
        SetThrusterGroupLevel(THGROUP_ATT_YAWLEFT, 0);
    }
    else
    {
        SetThrusterGroupLevel(THGROUP_ATT_YAWRIGHT, 0);
        SetThrusterGroupLevel(THGROUP_ATT_YAWLEFT, 0);
    }
}

// --------------------------------------------------------------
// Start orbit insertion autopilot
// --------------------------------------------------------------
void M_III_stage02::DoOrbit()
{
    if (start_sw == 0)
    {
        timer = timer + step_time;
        if (timer < 5) return;
        else
        {
            start_sw = 1;
            timer = 0;
        }
    }

    else if (start_sw == 1 && intfair_status == 0)
    {
        timer = timer + step_time;
        if (timer > 20)
        {
            JettisonFair();
            timer = 0;
        }
    }


    DeactivateNavmode(NAVMODE_KILLROT);
    CalcAzimuth();

    double fnl_vel = sqrt(mu*(2 / (op_meco_alt + rt) - 1 / (0.5*(op_tgt + op_meco_alt + (2 * rt)))));

    double emp_mass = GetEmptyMass();
    double vmass = GetMass();

    OBJHANDLE hearth = GetSurfaceRef();

    VECTOR3 haspdv = _V(0, 0, 0);
    GetHorizonAirspeedVector(haspdv);

    VECTOR3 weight = _V(0, 0, 0);
    GetWeightVector(weight);

    //centrifugal acc
    VECTOR3 relvel = _V(0, 0, 0);
    GetRelativeVel(hearth, relvel);
    double orb_vel = length(relvel);
    double orb_grnd_spd = sqrt((orb_vel*orb_vel) - (haspdv.y*haspdv.y));
    double rds = (rt + GetAltitude());
    double ang_vel = orb_grnd_spd / rds;
    double acc_cent_fact = 1;
    double acc_cent = ang_vel*ang_vel*rds*acc_cent_fact;


    double gravt = length(weight);
    double g = -(gravt / vmass) + acc_cent;

    double aa = g / 2;
    double bb = haspdv.y;
    double cc = GetAltitude() - op_meco_alt;

    double max_th = GetThrusterMax(th_main[1]);
    double max_acc = max_th / vmass;
    double sinp = sin(GetPitch());
    double cosp = cos(GetPitch());

    double dv_req = fnl_vel - orb_grnd_spd;
    double fraction = exp(dv_req / GetThrusterIsp(th_main[1]));
    double fuelmass = vmass - (vmass / fraction);
    double englevel = GetThrusterLevel(th_main[1]);
    double fuelrate = GetThrusterMax(th_main[1])*englevel / GetThrusterIsp(th_main[1]);
    double dvtime = fuelmass / fuelrate;
    dvtime = dvtime / cosp;

    double vvel_fnl = 0;

    double acc_req = ((6 * (op_meco_alt - GetAltitude() - (haspdv.y*dvtime))) + (2 * dvtime*haspdv.y)) / (dvtime*dvtime);

    acc_req = acc_req - g;

    double srp = acc_req / max_acc;
    if (srp > 1)srp = 1;
    else if (srp < -1)srp = -1;
    double req_pitch = asin(srp);
    double crp = cos(req_pitch);

    VECTOR3 fv2d = _V(0, srp, crp);
    VECTOR3 fv_hrz = _V(0, 0, 0);
    fv_hrz.x = sin(azimuth)*crp;
    fv_hrz.y = srp;
    fv_hrz.z = cos(azimuth)*crp;

    double max_dv = step_time*max_acc;
    englevel = (fnl_vel - orb_vel) / max_dv;
    if (englevel > 1)englevel = 1;
    else if (englevel < 0)
    {
        op_status = 0;
        englevel = 0;
        KillAllRCS2();
        SetThrusterLevel(th_main[1], 0);
        ActivateNavmode(NAVMODE_KILLROT);
        return;
    }

    if ((fnl_vel - orb_vel) < 100)
    {
        ActivateNavmode(NAVMODE_KILLROT);
        if (englevel > 0)englevel = 0.7;
    }
    else
    {
        HorizonInvRot(fv_hrz, flight_vector);
        GoToFlightVector();
    }

    if (start_sw == 0)englevel = 0;
    SetThrusterLevel(th_main[1], englevel);
}

edit: could you try to launch from an higher latitude with the same small difference? something like 45 deg with 45.2 inclination and tell me if it gets there?
45.10 deg, target of 45.30, it still works.

YPZi0yb.png


bfqnwq8.png
 
Last edited:

fred18

Addon Developer
Addon Developer
Donator
Joined
Feb 2, 2012
Messages
1,667
Reaction score
104
Points
78
I recognize part of my code but not all of it, so I need a bit of time to study it, i'll get back to you
 

Pipcard

mikusingularity
Addon Developer
Donator
Joined
Nov 7, 2009
Messages
3,709
Reaction score
38
Points
88
Location
Negishima Space Center
What part of the code do you recognize? Never mind, perhaps it's mixed up. But I'm still wondering what exactly determines the trajectory of the rocket.

edit: countdown

 
Last edited:

fred18

Addon Developer
Addon Developer
Donator
Joined
Feb 2, 2012
Messages
1,667
Reaction score
104
Points
78
What part of the code do you recognize? Never mind, perhaps it's mixed up. But I'm still wondering what exactly determines the trajectory of the rocket.

It is actually mixed up, so not an easy task.

The Powered Explicit Guidance algorithm is an iterative system, and I simplified it a bit to make it easier to be programmed. The original algorithm finds out by itself the cutoff conditions (altitude, tangential speed and vertical speed) by continuos iterations, and solves the system finding the pitch angle to reach that target. But this was not always as accurate as it could be if you fix by yourself the target conditions (example cutoff at perialtitude). So I simplified it a bit introducing a simple scheme of decision based on the input parameters which find at the origin the target parameters and then solves the system to find pitch angle.

So parameters that influence the trajectory are:
from a positioning point of view:
- vertical speed
- tangential speed
- altitude
from a vehicle point of view:
- acceleration capacity and time of it, so basically:
- Weight, fuel weight, thrust power

I recommend to google for Powered Explicit Guidance and read some articles about it, the math behind it is not immediate, but the concept can be understood easily.
 

fred18

Addon Developer
Addon Developer
Donator
Joined
Feb 2, 2012
Messages
1,667
Reaction score
104
Points
78
If it is possible, can you please tell me how you calibrated your ascent program?

Well for the Jarvis I had an open loop first part of the ascent (up to 35 km of altitude) which was done at constant vertical acceleration, and after that there was the PEG algorithm starting to work. It was mostly a matter of getting the right vertical acceleration for the first part, but now that I found the complete PEG solution it's not the way I would recommend anymore.

I suggest you to download Multistage2015 and check the peg.cpp file, where the algorithm is contained. I think it can be plugged into your project, since it is already working with multistage2015 that is an highly generical module.
 

Loru

Retired Staff Member
Retired Staff
Addon Developer
Donator
Joined
Sep 30, 2008
Messages
3,731
Reaction score
6
Points
36
Location
Warsaw
No wonder Themis-A uses an MFD for launch control...

Idea behind it wasn't HUD or additional info to be displayed there but ability to launch vehicle from payload's POV or ground station and provide rudimentarty telemetry back to controlling MFD.
 

Pipcard

mikusingularity
Addon Developer
Donator
Joined
Nov 7, 2009
Messages
3,709
Reaction score
38
Points
88
Location
Negishima Space Center
That is exactly the same issue I encountered when coding the various type of jarvis. I solved it with the general guidance solution of MS2015.
The problem was the multistage peg algorithm that still wasn't perfect at that time.

Basically the first stage pitches down too much and gives you not enough vertical speed but too much horizontal speed. Then the second stage tries to correct the vertical energy but of course a big correction if not properly dampened result in big oscillations. My suggestion is to work on the first stage guidance, especially its final states.

If you don't know where to start post the code and I'll try to help there.

edit: could you try to launch from an higher latitude with the same small difference? something like 45 deg with 45.2 inclination and tell me if it gets there?

I still don't quite understand how the algorithms work, but from my understanding, the F9R guidance autopilot tries to pitch the rocket after reaching a certain altitude (30 km) so that the rocket reaches a certain specified apogee (default of 135 km) as soon as the first stage runs out of propellant; changing these variables doesn't seem to solve the problem of the first stage pitching down too much.

Most of the F9R ascent functions seem to be like a generic algorithm, so I keep thinking that there has to be some variables that you can change in order to calibrate the pitch profile. So far, I still have no clue.

The reason I am not sure about the "general guidance solution" (which I am also not sure how to implement in my add-on, due to potential incompatibilities with variables) is I don't know if it would work with a boost-back first stage.
 
Last edited:

fred18

Addon Developer
Addon Developer
Donator
Joined
Feb 2, 2012
Messages
1,667
Reaction score
104
Points
78
Idea behind it wasn't HUD or additional info to be displayed there but ability to launch vehicle from payload's POV or ground station and provide rudimentarty telemetry back to controlling MFD.

That is the very same idea behind MS2015 MFD.

I still don't quite understand how the algorithms work, but from my understanding, the F9R guidance autopilot tries to pitch the rocket after reaching a certain altitude (30 km) so that the rocket reaches a certain specified apogee (default of 135 km) as soon as the first stage runs out of propellant; changing these variables doesn't seem to solve the problem of the first stage pitching down too much.

Most of the F9R ascent functions seem to be like a generic algorithm, so I keep thinking that there has to be some variables that you can change in order to calibrate the pitch profile. So far, I still have no clue.

The reason I am not sure about the "general guidance solution" (which I am also not sure how to implement in my add-on, due to potential incompatibilities with variables) is I don't know if it would work with a boost-back first stage.

Well I have to ask I small question, forgive me for this, I don't want to advertise my addon, but have you tried to implement this in ms2015?

And anyway I recommend to check its peg.cpp file for general guidance solution. It is completely tweakable. I tried to make the ms2015 autoguidance realistic by default but customizable by users. Also if you want to code your addon by yourself (which of course it's good because you acquire a lot of knowloedge) you will have a path on how to solve your issues here.
 

Pipcard

mikusingularity
Addon Developer
Donator
Joined
Nov 7, 2009
Messages
3,709
Reaction score
38
Points
88
Location
Negishima Space Center
But how can I implement peg.cpp in this custom dll? Is that possible?

I could implement it in ms2015. But the point of this was to have the boost-back first stage. Another thing is that the F9R code tries to get the first stage to a certain apogee at the same time it reaches a certain reserved propellant level (0 kg in expendable mode, several dozen thousand kg in reusable mode).
 
Last edited:

fred18

Addon Developer
Addon Developer
Donator
Joined
Feb 2, 2012
Messages
1,667
Reaction score
104
Points
78
I could implement it in ms2015. But the point of this was to have the boost-back first stage.

that is easily possible with ms2015: you can spawn the first stage with a module different from the default stage.dll, and you can therefore code this module so once jettisoned it will perform the flight back. you will of course have to tweak launch parameters in order to have a possible flight back condition, but that's not hard
 

Pipcard

mikusingularity
Addon Developer
Donator
Joined
Nov 7, 2009
Messages
3,709
Reaction score
38
Points
88
Location
Negishima Space Center
that is easily possible with ms2015: you can spawn the first stage with a module different from the default stage.dll, and you can therefore code this module so once jettisoned it will perform the flight back. you will of course have to tweak launch parameters in order to have a possible flight back condition, but that's not hard
But here's the issue, it needs to be able to set the landing target before the spawning at separation.
 

fred18

Addon Developer
Addon Developer
Donator
Joined
Feb 2, 2012
Messages
1,667
Reaction score
104
Points
78
But here's the issue, it needs to be able to set the landing target before the spawning at separation.

Well for that there are other work arounds, what comes to my mind is just for giving ideas:
- the launch tower can contain this parameter, so user can choose before launch from there. Once spawned the first stage will query the launch tower vehicle on "where to go" and it will just reply (clbkGeneric is a friend for this type of operations)
- the landing site can be a vehicle which sends a signal to the first stage similar to the point before but directly from the landing site
- A "ghost" live payload can be added to the vehicle that will handle all of this, like a mission control center
- A MCC can be create that will handle all of this like the ghost payload before (ms2015 has many features built for simulating MCC, that was my small "dream" so it is oriented in that way)

I mean, if you want to build it with your own code I fully support you, but if you want to exploit the work behind ms2015 you can skip many difficult steps (first of all the guidance system, on which I literally spent years to fully develop it)
 

Pipcard

mikusingularity
Addon Developer
Donator
Joined
Nov 7, 2009
Messages
3,709
Reaction score
38
Points
88
Location
Negishima Space Center
Based on several exchanges I've had between BrianJ and myself, I think I have figured out the reason for why it tends to overshoot. These are the issues:

BrianJ said:
the 2nd stage only has maybe half the fuel of the Falcon9 - so only has half the burntime

Again, this rocket is based on the ratios of this hypothetical methalox Falcon 9. I also looked at the Silverbird Launch Vehicle Performance Calculator as well.

Since this rocket is inspired by the "commonality" philosophy of SpaceX, I had made the second stage's thrust 1/7th of the the first stage. But that turns out to be about the same thrust as the F9 second stage (but slightly smaller). With the lower mass of the M-III second stage, there is a higher thrust/weight ratio (the TWR for the first stage, however, is currently about the same as the F9's). So the second stage autopilot tries to get to the target orbit (200 x 200 km) with higher relative thrust and within a shorter burn time, leading to the overshooting. It is like starting an apoapsis burn to raise your orbit, a minute too early.

What the rocket would need to do is get to an apogee near 200 km before stage separation, separate, then coast for a while before burning instead of starting the engines after only a few seconds. One of BrianJ's recommendations was to
BrianJ said:
Delay firing the 2nd stg. until ApT (time to apogee) is at a certain value. At the moment, 2nd stg. ignition is on a timer after stg.sep. so youll need to change that.

I couldn't find anything like a "GetApT" function in API_Reference.pdf, though. So there must be some way to detect or retrieve that value?
 
Last edited:

fred18

Addon Developer
Addon Developer
Donator
Joined
Feb 2, 2012
Messages
1,667
Reaction score
104
Points
78
IIRC it should be a parameter of the orbital elements,

so it should be GetElements, and inside that there should be an ORBITPARAM item. then the ApT is member of the ORBITPARAM item.

something like
Code:
OBJHANDLE hearth=GetSurfaceRef();
ELEMENTS el;
ORBITPARAM op;
GetElements (hearth, el, &op, 0, 1);
double apt=op.ApT;
 

Pipcard

mikusingularity
Addon Developer
Donator
Joined
Nov 7, 2009
Messages
3,709
Reaction score
38
Points
88
Location
Negishima Space Center
(note: by changing the "pitch_limit" variable within the F9R source code, the pitching profile of the first stage can be calibrated (BrianJ pointed out to me that it was very sensitive, i.e. changing it by 0.1 can be significant) up to a certain point (30 km) where the autopilot switches to a mode in which it tries to reach a pre-determined apogee at the same time of first stage engine cut-off.)

So far, I had been testing my rocket without an actual payload. The second stage was left with no more than 16.5-17.5 tonnes of propellant in it when it reached a 200 km circular orbit. But when there was an actual payload, the maximum capacity of that could be 19 tonnes.

Also, all the overshooting problems I have been having were a result of me testing the rocket without any payload. In the case of a payload being there, having a higher apogee at stage separation is actually detrimental as it causes an oscillating pitch during second stage guidance.
 
Last edited:

Pipcard

mikusingularity
Addon Developer
Donator
Joined
Nov 7, 2009
Messages
3,709
Reaction score
38
Points
88
Location
Negishima Space Center
Update:

For some time I have had a problem in which the first stage return to launch site program would overshoot the target. Recently, and with BrianJ's help, I found that could be solved by modifying the "timetoimp" (not timetoimp2) and "k_factor" variables within the DoReentryCorrection() function of the F9R first stage code. I still have to tweak the code some more to save delta-v, though.

Also, I have the almost-final parameters for the rocket. Using a modified version (modified meaning that bulkheads are shorter, and things such as common bulkheads and landing legs are taken into account) of Phil Smith's method for estimating stage dry masses, I calculated the parameters and did some testing in Orbiter.

SdtN6ab.png


g0Zs4yc.png


It's going to be a relatively stubby rocket with its wider diameter.

In expendable mode, the M-III can lift 20500 kg to low Earth orbit and 7800 kg to geostationary transfer orbit.

In reusable mode (return-to-launch-site), it can lift 13500 kg to LEO and 4200 kg to GTO. I haven't tested it with a barge yet.

---------- Post added at 07:14 PM ---------- Previous post was at 04:19 PM ----------

It would look something like this:

AksVCOH.png


It has similar proportions to this speculative concept by Dmitry Vorontsov for the SpaceX BFR (Big "Falcon" Rocket), except with a smaller diameter.

OcE5U1P.png


(this was from before the time Elon Musk said that the BFR/Mars colonization rocket would only have a "single monster boost stage")

---------- Post added at 09:19 PM ---------- Previous post was at 07:14 PM ----------

08ICcoX.png


Indeed it is shorter, but:

- If SpaceX-style reuse somehow fails to be economical (I've seen some doubters, but so far, SpaceX is only considering price drops for F9R), it would have to work in expendable-only mode. 20.5 tonnes to LEO in expendable is as far as I can push it (maybe a few tonnes higher?) considering that Falcon 9's "true" expendable payload capacity might be around that range (with a margin for reusability built in for the advertised capacity of ~13 tonnes).

- It will need to have wide fairings for certain exploration missions beyond Earth orbit that I plan to do.

- If I make it as tall and skinny as the M-II, it would look more like a F9R ripoff.

- Stumpy reusable first stages are less prone to toppling over.

Also, for the pre-Vulcan "Atlas V Evolution" proposal, you would see that for "Phase 2," there is what appears to be a stubby rocket that would probably have the same payload as a pre-Phase 2 single-core Atlas V.

aEva0Am.png
 
Last edited:

Pipcard

mikusingularity
Addon Developer
Donator
Joined
Nov 7, 2009
Messages
3,709
Reaction score
38
Points
88
Location
Negishima Space Center
I felt that it was a bit too short, and I wanted to make it a few meters taller. I decreased the thrust/weight ratio of the rocket from ~1.37 (the twr of Dmitry's F9M concept) to ~1.2 (twr of the real F9) and made some other minor changes (Dmitry told me via message on the NASASpaceflight forum that the propellant mixture ratio could range from 3.4 to 3.8).

Hcg5njR.png


Here are the new stats:

2fdkveG.png


Bk6GMxM.png


The payload capacity for LEO is 21400 kg (expendable) or 14100 kg (RTLS).
For GTO, it is 8200 kg (expendable) or 4200 kg (RTLS).

Last time, when I claimed that the GTO payload capacity in reusable mode was 4200 kg, I was assuming that I could reduce the amount of delta-v used up during landing (it ran out of propellant just a few meters above ground). The Falcon 9 add-on uses up more dV than it should because it decelerates at a slower rate (~2 m/s^2) prior to landing than the real thing (~7 m/s^2):

I asked BrianJ about how the "hoverslam" could be made to have a higher acceleration, and he replied that I could change these values within the "DoLand" function (note: from [ame="http://www.orbithangar.com/searchid.php?ID=6593"]F9R v1.1[/ame])

Code:
double start_alt = (100+(750*alt_factor));//-250

Code:
else if (alt > ((alt_factor*200)-100))

and halve them, resulting in something like (50+(375*altfactor)). He warned that "the quicker you land - the less time there is to correct for targeting errors," and so I made the values 87.5% instead of 50%.

---------- Post added 03-25-16 at 08:29 PM ---------- Previous post was 03-24-16 at 11:07 PM ----------

fmfOCjb.png


Second stage - engine model is based on illustrations here
 
Last edited:
Top