SDK Question Multiple RCS Configurations

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
Hello Everyone

Im coming down the home strech in designing my first orbiter addon vessel
Woohoo!

:hailprobe:

And, anyways I was wondering if anyone knows how to implement multiple RCS configurations in a vessel class, similar to how the XR guys added the Docking RCS on the XR5 Vanguard. Im thinking of just including a "module tug" mode that activates only the rear RCS when attempting to steer a new station module to docking. Having spent 20-30 minutes before, trying to wrestle an uncooperative module into its berth on my space station, I noticed how annoying it became when the normal RCS ROT on the DG created translational velocity while trying to align directions and vice versa

Thanks for any help :)
 
You reassign the rcs thrusters accordingly. For example, you assign the thrusters that wouls actually pitch the vessel down to the THGROUP_ATT_YAWRIGHT group instead, etc.

You can do this either by static assignment (e.g. put this thruster into this group if this camera mode is selected), or by calculating it dynamically from the thruster direction and viewport direction (only makes sense if you have a real lot of them, or if you don't know in advance how many you have at all).
I noticed how annoying it became when the normal RCS ROT on the DG created translational velocity while trying to align directions and vice versa

Since there's no way to keep a balanced cog with a docked module, this is actually a very nice idea... In that case, you don't even have to reassign thrustergroups, just set the propellant resource of the thrusters you want to shut down to NULL.
 
Last edited:
Here's the pertinant code from my old Caterpillar OUV

Code:
// ==============================================================
// Thruster Control / CG Comp
// ==============================================================
void CaterpillarOUV::clbkPreStep(double SimT, double SimDT, double MJD) 
{
	//Return a value between -1 and 1 for all RCS inputs... 
	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); 
	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);
	
	// Calculate the combined CG of OUV and any docked modules...
	VECTOR3 cg;
	double CG_X_Offset = (GetSuperstructureCG (cg) ? cg.x : 0.0); // Horizontal offset of CG
	double CG_Y_Offset = (GetSuperstructureCG (cg) ? cg.y : 0.0); // Vertical offset of CG
	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",CG_X_Offset, CG_Y_Offset,CG_Z_Offset); //Debuggery

	// RCS Stack Optimization...
	double RCSMode = GetAttitudeMode (); // Checks current RCS mode 1 = ROT, 2 = LIN
	if (RCSMode==2)
	{ 
		//Calculate Torque
		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
		
		//Cancel Linear Torque.
		IncThrusterLevel_SingleStep (th_rcs[14],-LatThrust*Ratio); 	
		IncThrusterLevel_SingleStep (th_rcs[15], LatThrust*Ratio);
		IncThrusterLevel_SingleStep (th_rcs[12], VertThrust*Ratio*0.965925826289); 
		IncThrusterLevel_SingleStep (th_rcs[13],-VertThrust*Ratio*0.965925826289); 
		// because the forward vertical thrusters are offset by 15 degrees thier 'Ratio' must be multiplied by the cosine of 15' (0.965925826289)
	
		//Cancel Roll
		//Nothing here yet...
	}
}

Note that the rotational thrusters refer are on the end of a 6.5 meter lever arm (similar to the dragonfly).

This function simply calculates the amount of torque created by the translational ('lateral') thrusters at the front of the craft and the corisponding lever lever force needed to counter it.
 
There's another way to do it. You can declare all the thrusters in clbkSetClassCaps, then initialize some of them with "NULL" as the propellant resource. That way they won't fire.

Then you make a condition (triggered by a key for example) that sets a valid propellant resource to those thrusters, and sets to "NULL" those that were in use. That way you can toggle between two RCS configs (or more).

Something like this :

Code:
// Orientation mode switch

	if (GetThrusterGroupLevel(THGROUP_MAIN) >= 0.6)
	{
		SetThrusterResource(th_rcs[14], hpr);
		SetThrusterResource(th_rcs[15], hpr);
		SetThrusterResource(th_rcs[16], hpr);
		SetThrusterResource(th_rcs[17], hpr);

		SetThrusterResource(th_rcs[1], NULL);
		SetThrusterResource(th_rcs[4], NULL);
		SetThrusterResource(th_rcs[7], NULL);
		SetThrusterResource(th_rcs[10], NULL);
	}
	if (GetThrusterGroupLevel(THGROUP_MAIN) < 0.6)
	{
		SetThrusterResource(th_rcs[14], NULL);
		SetThrusterResource(th_rcs[15], NULL);
		SetThrusterResource(th_rcs[16], NULL);
		SetThrusterResource(th_rcs[17], NULL);

		SetThrusterResource(th_rcs[1], hpr);
		SetThrusterResource(th_rcs[4], hpr);
		SetThrusterResource(th_rcs[7], hpr);
		SetThrusterResource(th_rcs[10], hpr);
	}
 
There's another way to do it. You can declare all the thrusters in clbkSetClassCaps, then initialize some of them with "NULL" as the propellant resource. That way they won't fire.

Then you make a condition (triggered by a key for example) that sets a valid propellant resource to those thrusters, and sets to "NULL" those that were in use. That way you can toggle between two RCS configs (or more).

Something like this :

Code:
// Orientation mode switch

	if (GetThrusterGroupLevel(THGROUP_MAIN) >= 0.6)
	{
		SetThrusterResource(th_rcs[14], hpr);
		SetThrusterResource(th_rcs[15], hpr);
		SetThrusterResource(th_rcs[16], hpr);
		SetThrusterResource(th_rcs[17], hpr);

		SetThrusterResource(th_rcs[1], NULL);
		SetThrusterResource(th_rcs[4], NULL);
		SetThrusterResource(th_rcs[7], NULL);
		SetThrusterResource(th_rcs[10], NULL);
	}
	if (GetThrusterGroupLevel(THGROUP_MAIN) < 0.6)
	{
		SetThrusterResource(th_rcs[14], NULL);
		SetThrusterResource(th_rcs[15], NULL);
		SetThrusterResource(th_rcs[16], NULL);
		SetThrusterResource(th_rcs[17], NULL);

		SetThrusterResource(th_rcs[1], hpr);
		SetThrusterResource(th_rcs[4], hpr);
		SetThrusterResource(th_rcs[7], hpr);
		SetThrusterResource(th_rcs[10], hpr);
	}

Just not sure how to set up said condition. Is it a variable like a propellant handle?
 
Just not sure how to set up said condition. Is it a variable like a propellant handle?

It can be a lot of things. In the above example, the switch occurs when the main engines average level is higher or smaller than 60%.
 
It can be a lot of things. In the above example, the switch occurs when the main engines average level is higher or smaller than 60%.

Well, that might not be my thing. If I were to ty it to a variable that only dealt with that one thing, i figure I should use a Boolean? If that does work how can I tell clbkconsumebufferedkey to revert the variable? By the way, I imagine youre fairly busy, but I was wondering if you would be willing to help with some of the final development hurdles in my project. I wont mind too much if it doesnt get done, but I would like to set up a specialized drawing class to allow the UMMU/UCGO Hud Messages to be displayed on a sytem status screen I set up, and I was hoping to get the MFD controls working (theyre diplaying, but I dont have any input buttons working yet)

Any help would be great :)
 
I suggest you this very good tutorial, which should really help you :

http://www.orbiterwiki.org/wiki/Vessel_Tutorial_1

Thanks for the link, although I think tutorial 2 will be better for this. I dont mean to sound whiny, but I think we need to start getting all but the most advanced developers in the habit of releasing the source code with all of their OHM releases. I understand that looking at the source for say, the DGIV or XR2 would be gibberish to most new developers, but I found it easiest to add new C++ features when I could see an actual example in my compiler. Anyways, thank you very much for all the help :thumbup:

Oh By the way, does math.lib support trigonometric functions?
 
Last edited:
It does.

Code:
output = sin(input);

Will give the sine of an angle, "asin(input)" will do the inverse. likwise for cos/acos and tan/atan.

if you need sec or csc just do.

Code:
output = 1/sin(input);

ETA: note that input is assumed to be in radians
 
It does.

Code:
output = sin(input);

Will give the sine of an angle, "asin(input)" will do the inverse. likwise for cos/acos and tan/atan.

if you need sec or csc just do.

Code:
output = 1/sin(input);

ETA: note that input is assumed to be in radians

Excellent, if there is support for that, I should be able to construct a Dlled centrifuge sometime in the future for station building
 
Here's the pertinant code from my old Caterpillar OUV

Code:
// ==============================================================
// Thruster Control / CG Comp
// ==============================================================
void CaterpillarOUV::clbkPreStep(double SimT, double SimDT, double MJD) 
{
	//Return a value between -1 and 1 for all RCS inputs... 
	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); 
	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);
	
	// Calculate the combined CG of OUV and any docked modules...
	VECTOR3 cg;
	double CG_X_Offset = (GetSuperstructureCG (cg) ? cg.x : 0.0); // Horizontal offset of CG
	double CG_Y_Offset = (GetSuperstructureCG (cg) ? cg.y : 0.0); // Vertical offset of CG
	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",CG_X_Offset, CG_Y_Offset,CG_Z_Offset); //Debuggery

	// RCS Stack Optimization...
	double RCSMode = GetAttitudeMode (); // Checks current RCS mode 1 = ROT, 2 = LIN
	if (RCSMode==2)
	{ 
		//Calculate Torque
		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
		
		//Cancel Linear Torque.
		IncThrusterLevel_SingleStep (th_rcs[14],-LatThrust*Ratio); 	
		IncThrusterLevel_SingleStep (th_rcs[15], LatThrust*Ratio);
		IncThrusterLevel_SingleStep (th_rcs[12], VertThrust*Ratio*0.965925826289); 
		IncThrusterLevel_SingleStep (th_rcs[13],-VertThrust*Ratio*0.965925826289); 
		// because the forward vertical thrusters are offset by 15 degrees thier 'Ratio' must be multiplied by the cosine of 15' (0.965925826289)
	
		//Cancel Roll
		//Nothing here yet...
	}
}

Note that the rotational thrusters refer are on the end of a 6.5 meter lever arm (similar to the dragonfly).

This function simply calculates the amount of torque created by the translational ('lateral') thrusters at the front of the craft and the corisponding lever lever force needed to counter it.

Okay, I gave this and N Molsons version a try in clbk prestep, but the compiler always keeps telling me that the pointer to the thruster (ie th_rcs[0]), is undefined. I thought it was defined in Setclasscaps, no? Also, with say, the IncThrusterLevel_SingleStep function, do I need to copy that piece of code from the VesselAPI.h file to my header, include VesselAPI in my project, or does including the OrbiterSDK.h file cover all of that?
 
Okay, I gave this and N Molsons version a try in clbk prestep, but the compiler always keeps telling me that the pointer to the thruster (ie th_rcs[0]), is undefined. I thought it was defined in Setclasscaps, no? Also, with say, the IncThrusterLevel_SingleStep function, do I need to copy that piece of code from the VesselAPI.h file to my header, include VesselAPI in my project, or does including the OrbiterSDK.h file cover all of that?

do you have it as a class variable or is it only defined in clbkSetClassCaps?
 
do you have it as a class variable or is it only defined in clbkSetClassCaps?

The thruster is only defined in the classcaps. How do I define it as a class variable & make sure its related to the actual thruster? Also, how can I get orbiter to retrieve either which RCS mode is active (ROT, TRANS, OFF), or even better, when a particular thruster group is firing (ie when RCS TRANSLATE UP is firing, set these thrusters to this level). I tried setting the RCS thrust that clbkSetClassCaps looks for as a non constant variable in the header, then set a function in the PreStep that was supposed to use a particular set of thrust values when RCS mode was ROT or TRANSLATE. When, I tested it in orbiter, I heard the sound, saw the exhaust lighting up, but no rotation (also confirmed that the thruster thrusts were 0 by VesselParameters MFD). I think the issue is just something to do with convincing orbiter to find what the RCS mode is. ANy thoughts?
 
if it's only defined in clbkSetClassCaps it's only valid in that scope. To be able to use it in other functions, you'll have to move it out to where you declare all of your functions and class variables.

GetAttitudeMode() will get your the current attitude mode: RCS_NONE, RCS_ROT or RCS_LIN
 
if it's only defined in clbkSetClassCaps it's only valid in that scope. To be able to use it in other functions, you'll have to move it out to where you declare all of your functions and class variables.

GetAttitudeMode() will get your the current attitude mode: RCS_NONE, RCS_ROT or RCS_LIN

Can you provide an example of how it should be declared outside of clbksetclasscaps? Im not so sure that the GetAttitudeMode is working though
 
In your vessel header file
Code:
class MyVessel: public VESSEL3 {
public:
        MyVessel(OBJHANDLE hVessel, int flightmodel);
	~MyVessel();
	void clbkSetClassCaps(FILEHANDLE cfg);
	void clbkSaveState(FILEHANDLE scn);
	void clbkLoadStateEx(FILEHANDLE snc, void *vs);
	void clbkPostStep(double simt, double simdt, double mjd);

private:
        THRUSTER_HANDLE *th_rcs;

then in your clbkSetClassCaps before you use it for the first time

Code:
th_rcs = new THRUSTER_HANDLE[numThrusters];

//declare your thrusters
th_rcs[thNumber] = CreateThruster(thPos, thDir, MAXRCSTH, hpr, ISP);

And don't forget to delete the th_rcs when your done

Code:
MyVessel::~MyVessel() 
{
     delete th_rcs;
}


Why do you think GetAttitudeMode() doesn't work? I can't think of a reason it wouldn't. It doesn't care if you even have thrusters defined I think.
 
Last edited:
In your vessel header file
Code:
class MyVessel: public VESSEL3 {
public:
        MyVessel(OBJHANDLE hVessel, int flightmodel);
	~MyVessel();
	void clbkSetClassCaps(FILEHANDLE cfg);
	void clbkSaveState(FILEHANDLE scn);
	void clbkLoadStateEx(FILEHANDLE snc, void *vs);
	void clbkPostStep(double simt, double simdt, double mjd);

private:
        THRUSTER_HANDLE *th_rcs;

then in your clbkSetClassCaps before you use it for the first time

Code:
th_rcs = new THRUSTER_HANDLE[numThrusters];

//declare your thrusters
th_rcs[thNumber] = CreateThruster(thPos, thDir, MAXRCSTH, hpr, ISP);

And don't forget to delete the th_rcs when your done

Code:
MyVessel::~MyVessel() 
{
     delete th_rcs;
}


Why do you think GetAttitudeMode() doesn't work? I can't think of a reason it wouldn't. It doesn't care if you even have thrusters defined I think.

Thanks a bundle :thumbup:. Everything seems to be going much smoother now. So long as the getRCSmode call is going to come from the OrbiterSDK.h file, I think I should be fairly good from here. Just a bit of programming burnout if you follow what I mean. Thankyou!

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

Okay, I think I spoke too soon. I compiled the code adapted from the example above, but whenever I load Orbiter & try to switch RCS modes, the simulation CTDs
 
Back
Top