Question Calculating & Countering RCS Torque

Hlynkacg

Aspiring rocket scientist
Addon Developer
Tutorial Publisher
Donator
Joined
Dec 27, 2010
Messages
1,868
Reaction score
4
Points
0
Location
San Diego
I'm sorry if this voilates some rule but I figured I'd post this question here as well seeing as this forum gets more traffic.

I'm working on my space tug and need help writing a function. I know how to do the math on paper (Tourqe = R * F sin a) but lack the knowledge of C++ to make it work in Orbiter.

Code:
GetsuperstructureCG;

Using the above calculate the angular moment for "RCS_Trans_group" and return the value "torque1"; 

Do the same for "RCS_Att_group" and return the value "torque2"; 

Calculate thrust-level/vector for "RCS_Att_group" where (torque2) will be the inverse of (torque1);

Set "RCS_Att_group" to the above thrust level/vector

Yes, I know I'm reinventing the dragonfly, but the comments in the sample code don't exactly explain what's going on and there are levels of system simulation that further obscure the matter.

The intent is that when the Translation thrusters fire, the Pitch/yaw thrusters will automaticaly counter any shift in CG caused by a payload or docked vessel. I've been able to do this manually using the "SetThruster Dir/Ref" functions but want this process to be completely transperant to the end user.
 
i'm not sure i get the formula you posted....

let me try to work it out for you, it's actually very simple...

coding with vectors...


VECTOR3 Vtrq = crossp(VthrAcc, VthrOff);


with VthrOff being the separation between your thruster and the CoG of your vessel (thrPos - CgPos)....

it's a simple cross product - the cross between the thruster offset from the CoG, and the acceleration generated by it gives you a torque vector...

or at least, that's what it says on the SDK docs :rolleyes:
 
As I said, My Knowledge of C++ syntax and operators is practically 0. I'm learning this as I go along.

I copy the "VECTOR3 Vtrq = crossp(VthrAcc, VthrOff);" into the definition for my torque variable correct?

How do I go about using the result of "GetsuperstructureCG" in an equation?
 
Well I've learned a bit more C++ since last update but I still need help.

Code:
// ==============================================================
// Thruster Control
// ==============================================================
void CaterpillarOUV::clbkPreStep(double SimT, double SimDT, double MJD) 
{
	double RCSMode = GetAttitudeMode (); // Checks current RCS mode 1 = ROT, 2 = LIN

	double PitchThrust = GetThrusterGroupLevel(THGROUP_ATT_PITCHUP) - GetThrusterGroupLevel(THGROUP_ATT_PITCHDOWN);
	double RollThrust =	GetThrusterGroupLevel(THGROUP_ATT_BANKRIGHT) - GetThrusterGroupLevel(THGROUP_ATT_BANKLEFT);
	double YawThrust =	GetThrusterGroupLevel(THGROUP_ATT_YAWRIGHT) - GetThrusterGroupLevel(THGROUP_ATT_YAWLEFT); 
	//sprintf(oapiDebugString(),"Pitch %f Roll %f Yaw %f Mode %f",PitchThrust,RollThrust,YawThrust,RCSMode);
	//Returns a value between -1 and 1 for all rotational inputs

	double LatThrust = GetThrusterGroupLevel (THGROUP_ATT_RIGHT) - GetThrusterGroupLevel (THGROUP_ATT_LEFT);
	double VertThrust = GetThrusterGroupLevel (THGROUP_ATT_UP) - GetThrusterGroupLevel (THGROUP_ATT_DOWN);
	double LongThrust = GetThrusterGroupLevel (THGROUP_ATT_FORWARD) - GetThrusterGroupLevel (THGROUP_ATT_BACK);
	//sprintf(oapiDebugString(),"LAT %f VERT %f LONG %f Mode %f",LatThrust,VertThrust,LongThrust,RCSMode);
	//Returns a value between -1 and 1 for all linear inputs 

	VECTOR3 cg;
	const double CG_X_Offset = (GetSuperstructureCG (cg) ? cg.x : 0.0); // Horizontal offset of CG
	const double CG_Y_Offset = (GetSuperstructureCG (cg) ? cg.y : 0.0); // Vertical offset of CG
	const double CG_Z_Offset = (GetSuperstructureCG (cg) ? cg.z : 0.0); // Longitudinal offset of CG
	sprintf(oapiDebugString(),"CG X OFFSET %f CG Y OFFSET %f CG Z OFFSET %f Mode %f",CG_X_Offset, CG_Y_Offset,CG_Z_Offset,RCSMode); //Debuggery
	// Calculates the combined CG of OUV and any docked modules, if no modules are docked offset = 0


	if (RCSMode=2) // If RCS mode = LIN perform the following...
	{ 
		double Lat_Offset = ( 1.75 + CG_Z_Offset); //Position of Lateral thrusters on Z-axis relative to CG
		double Rot_Offset = (-6.50 + CG_Z_Offset); //Position of Rotational thrusters on Z-axis relative to CG
		double ratio = ((2.0*(Lat_Offset))/(Rot_Offset)); // Torque ratio between Lateral and Rotational thrusters
		
		if		(LatThrust > 0) SetThrusterLevel_SingleStep (th_rcs[15], (LatThrust*ratio)); // If Lateral Thrust results in + Yaw activate - Yaw Thruster
		else if (LatThrust < 0) SetThrusterLevel_SingleStep (th_rcs[14], -(LatThrust*ratio)); // If Lateral Thrust results in - Yaw activate + Yaw Thruster

		if      (VertThrust > 0) SetThrusterLevel_SingleStep (th_rcs[13], (VertThrust*ratio)); // If Lateral Thrust results in + Pitch activate - Pitch Thruster
		else if (VertThrust < 0) SetThrusterLevel_SingleStep (th_rcs[12], -(VertThrust*ratio)); // If Lateral Thrust results in - Pitch activate + Pitch Thruster
	}
}

The code compiles fine but Orbiter to crashes when I use the Linear RCS thrusters.
 
Last edited:
you're probably getting a "division by zero" error...

check that Rot_Offset != 0 before dividing stufff by it, see if it helps :hmm:



another crash opportunity that comes to mind from your code is an "array index out of bounds" situation - i mean, do you really have 16 thruster-handles defined in that th_rcs array?

remember, arrays count from zero up, so index number 15 is actually the 16th item in there

hope it helps :cheers:
 
Last edited:
you're probably getting a "division by zero" error...

check that Rot_Offset != 0 before dividing stufff by it, see if it helps :hmm:

I've tried setting the Offsets and ratio to '1' and still had the same problem so I'm pretty sure it's not a divide by zero problem.

Whatever's causing the crash it is happening in the "if (RCSMode==2)" function as //ing it out results in smooth sailing but no CG balancing. Is there anything simple Syntax or API-wise that I might be missing?

another crash opportunity that comes to mind from your code is an "array index out of bounds" situation - i mean, do you really have 16 thruster-handles defined in that th_rcs array?

Two sets of six lateral thrusters and 4 rotational thrusters.

6 + 6 + 4 = 16


Here's the most resent iteration of the code in question...

Code:
	if (RCSMode==2) // If RCS is in LIN mode perform the following...
	{ 
		double Lat_Offset = (-1.75 + CG_Z_Offset); //Position of Lateral thrusters on Z-axis relative to CG
		double Rot_Offset = (+6.50 + CG_Z_Offset); //Position of Rotational thrusters on Z-axis relative to CG

		if (Lat_Offset > 0) // If offset is greater than 0 Lateral + Lateral Thrust will result in - Torque
		{
			//double ratio = ((2.0*(Lat_Offset))/(Rot_Offset)); // Torque ratio between Lateral and Rotational thrusters
			SetThrusterLevel_SingleStep (th_rcs[15], (LatThrust)); // Activate corisponding + Yaw Thruster
			SetThrusterLevel_SingleStep (th_rcs[13], (VertThrust)); // Activate corisponding + Pitch Thruster
		}

		else if (Lat_Offset < 0) // If offset is less than 0 + Lateral Thrust will result in + Torque
		{
			//double ratio = ((2.0*(Lat_Offset))/(Rot_Offset)); // Torque ratio between Lateral and Rotational thrusters
			SetThrusterLevel_SingleStep (th_rcs[14], -(LatThrust)); // Activate corisponding - Yaw Thruster
			SetThrusterLevel_SingleStep (th_rcs[12], -(VertThrust)); // Activate corisponding - Pitch Thruster
		}
	}


---------- Post added at 06:49 PM ---------- Previous post was at 06:41 PM ----------

On a unrelated note how do I get the camera position to reset when switching from my VC back to the default "Glass cockpit"?

---------- Post added at 08:53 PM ---------- Previous post was at 06:49 PM ----------

Ok I've narrowed it down even further.

its the "SetThrusterLevel_SingleStep ();" operator.

The problem now is how to fix it.
 
Last edited:
its the "SetThrusterLevel_SingleStep ();" operator.

The problem now is how to fix it.



that part seems alright, i guess...

could you show us the code where you init those thrusters and set them up into that array?
 
As requested...

Code:
	//Thruster Definitions
	THRUSTER_HANDLE th_main, th_rcs[16], th_group[2];

	// Main Engine
	th_main = CreateThruster (_V( 0.0, 0.0,-8.4), _V(0,0,1), MAINMAXTH, hpr, OUV_ISP);
	CreateThrusterGroup (&th_main, 1, THGROUP_MAIN);

	// Port RCS Pod
	th_rcs[ 0] = CreateThruster (_V(-1.80, 0.45, 1.75), _V( 0.333,-1.00, 0.00), RCSMAXTHRUST, hpr, OUV_ISP);//Up
	th_rcs[ 1] = CreateThruster (_V(-1.80,-0.45, 1.75), _V( 0.333, 1.00, 0.00), RCSMAXTHRUST, hpr, OUV_ISP);//Down
	th_rcs[ 2] = CreateThruster (_V(-1.80, 0.00, 2.20), _V( 0.333, 0.00,-1.00), RCSMAXTHRUST, hpr, OUV_ISP);//Fore
	th_rcs[ 3] = CreateThruster (_V(-1.80, 0.00, 1.30), _V( 0.333, 0.00, 1.00), RCSMAXTHRUST, hpr, OUV_ISP);//Aft
	th_rcs[ 4] = CreateThruster (_V(-2.10, 0.10, 1.85), _V( 1.00, 0.00, 0.00), RCSMAXTHRUST, hpr, OUV_ISP);//Lateral
	th_rcs[ 5] = CreateThruster (_V(-2.10,-0.10, 1.65), _V( 1.00, 0.00, 0.00), RCSMAXTHRUST, hpr, OUV_ISP);//Lateral
	// Stbd RCS Pod
	th_rcs[ 6] = CreateThruster (_V( 1.80, 0.45, 1.75), _V(-0.333,-1.00, 0.00), RCSMAXTHRUST, hpr, OUV_ISP);//Up
	th_rcs[ 7] = CreateThruster (_V( 1.80,-0.45, 1.75), _V(-0.333, 1.00, 0.00), RCSMAXTHRUST, hpr, OUV_ISP);//Down
	th_rcs[ 8] = CreateThruster (_V( 1.80, 0.00, 2.20), _V(-0.333, 0.00,-1.00), RCSMAXTHRUST, hpr, OUV_ISP);//Fore
	th_rcs[ 9] = CreateThruster (_V( 1.80, 0.00, 1.30), _V(-0.333, 0.00, 1.00), RCSMAXTHRUST, hpr, OUV_ISP);//Aft
	th_rcs[10] = CreateThruster (_V( 2.10, 0.10, 1.65), _V(-1.00, 0.00, 0.00), RCSMAXTHRUST, hpr, OUV_ISP);//Lateral
	th_rcs[11] = CreateThruster (_V( 2.10,-0.10, 1.85), _V(-1.00, 0.00, 0.00), RCSMAXTHRUST, hpr, OUV_ISP);//Lateral
	// Aft Thruster Pod (Pitch/Yaw Thrusters)
	th_rcs[12] = CreateThruster (_V( 0.00, 0.75,-6.50), _V( 0,-1, 0), RCSMAXTHRUST, hpr, OUV_ISP);//Pitch Up
	th_rcs[13] = CreateThruster (_V( 0.00,-0.75,-6.50), _V( 0, 1, 0), RCSMAXTHRUST, hpr, OUV_ISP);//Pitch Down
	th_rcs[14] = CreateThruster (_V( 0.75, 0.00,-6.50), _V( 1, 0, 0), RCSMAXTHRUST, hpr, OUV_ISP);//Yaw Left
	th_rcs[15] = CreateThruster (_V(-0.75, 0.00,-6.50), _V(-1, 0, 0), RCSMAXTHRUST, hpr, OUV_ISP);//Yaw Right
	
	th_group[0] = th_rcs[12];
	CreateThrusterGroup (th_group, 1, THGROUP_ATT_PITCHUP);

	th_group[0] = th_rcs[13];
	CreateThrusterGroup (th_group, 1, THGROUP_ATT_PITCHDOWN);

	th_group[0] = th_rcs[ 0];
	th_group[1] = th_rcs[ 7];
	CreateThrusterGroup (th_group, 2, THGROUP_ATT_BANKLEFT);

	th_group[0] = th_rcs[ 1];
	th_group[1] = th_rcs[ 6];
	CreateThrusterGroup (th_group, 2, THGROUP_ATT_BANKRIGHT);
	
	th_group[0] = th_rcs[14];
	CreateThrusterGroup (th_group, 1, THGROUP_ATT_YAWLEFT);

	th_group[0] = th_rcs[15];
	CreateThrusterGroup (th_group, 1, THGROUP_ATT_YAWRIGHT);

	th_group[0] = th_rcs[ 1];
	th_group[1] = th_rcs[ 7];
	CreateThrusterGroup (th_group, 2, THGROUP_ATT_UP);

	th_group[0] = th_rcs[ 0];
	th_group[1] = th_rcs[ 6];
	CreateThrusterGroup (th_group, 2, THGROUP_ATT_DOWN);

	th_group[0] = th_rcs[10];
	th_group[1] = th_rcs[11];
	CreateThrusterGroup (th_group, 2, THGROUP_ATT_LEFT);

	th_group[0] = th_rcs[ 4];
	th_group[1] = th_rcs[ 5];
	CreateThrusterGroup (th_group, 2, THGROUP_ATT_RIGHT);

	th_group[0] = th_rcs[ 3];
	th_group[1] = th_rcs[ 9];
	CreateThrusterGroup (th_group, 2, THGROUP_ATT_FORWARD);

	th_group[0] = th_rcs[ 2];
	th_group[1] = th_rcs[ 8];
	CreateThrusterGroup (th_group, 2, THGROUP_ATT_BACK);


---------- Post added at 05:08 AM ---------- Previous post was at 12:11 AM ----------

I've been experimenting with alternatives to the "SetThrusterLevel_SingleStep ();" operator, and "IncThrusterGroupLevel_SingleStep" seems to work without crashing the Sim.

---------- Post added at 08:52 PM ---------- Previous post was at 05:08 AM ----------

Ok I have something that kind of works...

Code:
	if (RCSMode==2) // If RCS is in LIN mode perform the following...
	{ 
		double Lat_Offset = (-1.75 + CG_Z_Offset); //Position of Lateral thrusters relative to CG
		double Rot_Offset = ( 6.50 + CG_Z_Offset); //Position of Pitch/Yaw thrusters relative to CG
		double ratio = ((2.0*(Lat_Offset))/(Rot_Offset)); // Torque ratio between Lateral and Rotational thrusters

		if (Lat_Offset > 0) // If offset is greater than 0 Lateral + Lateral Thrust will result in - Torque
		{
			IncThrusterGroupLevel_SingleStep (THGROUP_ATT_YAWRIGHT, ratio*-LatThrust);
			IncThrusterGroupLevel_SingleStep (THGROUP_ATT_YAWLEFT, ratio*LatThrust);
			IncThrusterGroupLevel_SingleStep (THGROUP_ATT_PITCHUP, 0.955710431655*ratio*-VertThrust);
			IncThrusterGroupLevel_SingleStep (THGROUP_ATT_PITCHDOWN, 0.955710431655*ratio*VertThrust);  
		}		
		else if (Lat_Offset < 0) // If Lat_Offset is less than 0 + Lateral Thrust will result in + Torque
		{
			IncThrusterGroupLevel_SingleStep (THGROUP_ATT_YAWRIGHT, ratio*LatThrust);
			IncThrusterGroupLevel_SingleStep (THGROUP_ATT_YAWLEFT, ratio*-LatThrust);
			IncThrusterGroupLevel_SingleStep (THGROUP_ATT_PITCHUP, 0.955710431655*ratio*VertThrust);
			IncThrusterGroupLevel_SingleStep (THGROUP_ATT_PITCHDOWN, 0.955710431655*ratio*-VertThrust);  
		}	
	}

It's still not perfect but the vessel is noticably easier to control.
 
ah - you're losing the th_rcs array after the clbkSetClassCaps function ends - that's expected, since you declare them inside there...


the cure: mark them "static" :thumbup:


i.e:
Code:
static THRUSTER_HANDLE th_main, th_rcs[16], th_group[2];


if you don't, you lose the pointer (other stuff gets written over where it was, its a whole mess),
since anything created inside a scope (stuff inside { ... } blocks) will only be valid for as long as that scope is alive :rolleyes:

that's one of the greatest features - and biggest learning hurdles of C++ - but once you get it, it makes so much sense you won't be able to live without it (which is why Flash really gets on my nerves every so often)

hope this fixes it for ya - :cheers:
 
Figures that it would be something simple like that. :facepalm:

Fortunatly I save my prior code iterations, and once I'm feeling a less burnt-out i'll go back and see if that works any better than what I've currently got.

Thank you for the assistance.
 
ah - you're losing the th_rcs array after the clbkSetClassCaps function ends - that's expected, since you declare them inside there...


the cure: mark them "static" :thumbup:


i.e:
Code:
static THRUSTER_HANDLE th_main, th_rcs[16], th_group[2];


if you don't, you lose the pointer (other stuff gets written over where it was, its a whole mess),
since anything created inside a scope (stuff inside { ... } blocks) will only be valid for as long as that scope is alive :rolleyes:

that's one of the greatest features - and biggest learning hurdles of C++ - but once you get it, it makes so much sense you won't be able to live without it (which is why Flash really gets on my nerves every so often)

hope this fixes it for ya - :cheers:

I hate to re-open what should be a solved thread but do I just mark the above line in the clbkSetClassCaps function as static or do I have to do it in the overall class definition as well?

I ask because I made the change as reccomended and am still running into trouble (CTDs).

Would it help to mark each individual thruster as static?
 
I hate to re-open what should be a solved thread but do I just mark the above line in the clbkSetClassCaps function as static or do I have to do it in the overall class definition as well?

I ask because I made the change as reccomended and am still running into trouble (CTDs).

Would it help to mark each individual thruster as static?

not rly....


i think it's time you have a look at what it really means to have [ame=http://en.wikipedia.org/wiki/Static_variable]"static variables"[/ame]

in short, it's a variable that remains available until the program is shut down, and doesn't depend on the availability of a contaning class or function - i.e. a "static" variable is invariant of any "scopes", EVEN IF, it was declared inside a function


how does that work? you might ask - you see, C++ allows a variable to be static even inside a function... that being the case, the variable behaves as if it were a global one, but it is ONLY accessible under that name inside that function
(and i say "under that name" because it can still be tossed around as a pointer - even if the defining function has ended to never be ran again)

so no - and actually, if you define a static var inside a function, you don't declare it on the class at all...
that variable is independent of any classes (it exists in "program level") - so while it only exists under that name inside the function, the memory that stores it will remain fixed "forever" - which is how Orbiter can use it under the hood even after your function has closed up and gone home


the whole point of defining it like that (static inside function), is that you most likely won't need it anywhere else and/or can reach it by other means, such as through the getThruster functions in the API


and you don't have to mark each of them static, you put it before the type name ("THRUSTER_HANDLE" for you) and all the vars on that line should comply



:cheers:
 
not rly....


i think it's time you have a look at what it really means to have "static variables"

in short, it's a variable that remains available until the program is shut down, and doesn't depend on the availability of a contaning class or function - i.e. a "static" variable is invariant of any "scopes", EVEN IF, it was declared inside a function

That's what I thought. But VS flags it as an "undeclared identifier" when I try to call it in another function unless I put something in the class definition as well.
 
Declaring thruster handles static is not a good idea here. Thrusters are objects attached to individual vessels, so they should be represented as non-static data members of the vessel class. This way, each vessel object gets its own set of thruster handles.

Static data members, on the other hand, are shared between all instances of that vessel class. This is good for things like textures which really are shared between all vessels but not modified by individual ones. But sharing a single set of thrusters between all instances of a vessel type is not correct. Each newly instantiated vessel object would then overwrite the handles of the previous vessel.

Similarly, static nonmember variables are shared between all instances of a module. This would be an even worse choice here, since thrusters are a part of the spacecraft, so they should be a part of the class definition.

Of course, if you don't need to access the thruster handles outside the clbkSetClassCaps function, there is no need to declare them as class members. A local declaration as automatic variables, like you had in your code snippet, is then sufficient.
 
So what should I do?

As stated before, Orbiter doesn't seem to recognize thruster handles outside of clbkClassCaps even when I include them in the class definition.
 
Back
Top