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.)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.
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);
}
45.10 deg, target of 45.30, it still works.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?
Last edited: