Advanced Question Calculating optimal thruster choice...

thepenguin

Flying Penguin
Addon Developer
Joined
Jul 27, 2013
Messages
220
Reaction score
1
Points
16
Location
Earth-Moon Lagrange Point (L4)
It works! I have prograde, retrograde, and killrot working (had to pretty much rewrite your code from the ground up).

I want to get normal, antinormal, and manual controls working, too.

A few questions before I actually release it:

1. What are you using as code for the CoG shift? I want to make sure that part works before I release it. I just need the position vector in local vessel coordinates for the CoG as a VECTOR3 (it's half of a line of code to implement, once I have the CoG position).

2. What is the ISP of the LEM Ascent Module RCS? I think it's somewhere around 3000, but I wanted to double check with you on this.
 

Hlynkacg

Aspiring rocket scientist
Addon Developer
Tutorial Publisher
Donator
Joined
Dec 27, 2010
Messages
1,870
Reaction score
3
Points
0
Location
San Diego
Don't worry about Norm and Anti-Norm they are identical to Prograde and Retrograde, the inputs are just rotated 90 degrees.

Likewise manual control is trivially easy once you can set a desired angular Velocity or Acceleration. SetAngularVelocity (GetManualControlInput (rot)) see? Trivial.

as for your questions...

1: CoG shift is a vector in local coordinates, the locations of propellant tanks crew, and cargo relative to the module/mesh that contains them are constants the position of that mesh/module is the offset. Every couple of frames I perform a standard balance equation to determine how far from the "True" CoG would be from the current "Orbiter" CoG. If that distance is greater than 5 cm a new CoG is calculated and the "VESSEL::ShiftCOG ()" function is called.

2: 290 Seconds at normal operating temp so figure 2845 or so. Don't see why it would matter though, you can get the ISP from the thruster itself.
 

thepenguin

Flying Penguin
Addon Developer
Joined
Jul 27, 2013
Messages
220
Reaction score
1
Points
16
Location
Earth-Moon Lagrange Point (L4)
Don't worry about Norm and Anti-Norm they are identical to Prograde and Retrograde, the inputs are just rotated 90 degrees.

Likewise manual control is trivially easy once you can set a desired angular Velocity or Acceleration. SetAngularVelocity (GetManualControlInput (rot)) see? Trivial.

as for your questions...

1: CoG shift is a vector in local coordinates, the locations of propellant tanks crew, and cargo relative to the module/mesh that contains them are constants the position of that mesh/module is the offset. Every couple of frames I perform a standard balance equation to determine how far from the "True" CoG would be from the current "Orbiter" CoG. If that distance is greater than 5 cm a new CoG is calculated and the "VESSEL::ShiftCOG ()" function is called.

2: 290 Seconds at normal operating temp so figure 2845 or so. Don't see why it would matter though, you can get the ISP from the thruster itself.

As to the first one, I'm glad that you just move around everything instead of having to do it some other way.

As for the second, it only matters when you are adding a main engine to your ship for testing purposes and need the value. I want to make sure that the ship doesn't try to use the main engine in a killrot program. ;)

Likewise, manual control is just for more dynamic testing. (By the way, I fixed the weird roll at the end of the KILLROT, and also the system is more fuel efficient now.)
 
Last edited:

Hlynkacg

Aspiring rocket scientist
Addon Developer
Tutorial Publisher
Donator
Joined
Dec 27, 2010
Messages
1,870
Reaction score
3
Points
0
Location
San Diego
As for the second, it only matters when you are adding a main engine to your ship for testing purposes and need the value. I want to make sure that the ship doesn't try to use the main engine in a killrot program.

You should have a list of available RCS thrusters in your solver, if you don't add the main engine to that list that won't be an issue.

Besides if you're going to use TVC in your control scheme you might want to do just that.

By the way, I fixed the weird roll at the end of the KILLROT, and also the system is more fuel efficient now.

Glad to hear it but kind of wish you'd share the code. :tiphat:
 

thepenguin

Flying Penguin
Addon Developer
Joined
Jul 27, 2013
Messages
220
Reaction score
1
Points
16
Location
Earth-Moon Lagrange Point (L4)
The code that controls user interaction isn't as polished as I would like it to be, but this function (RCS_CTRL(simdt);) is the core functionality. (the full class and header code is attatched in the .zip)

I designed for it to be run in the clbkPreStep function of the parent vessel, and I have done some optimizations. One thing I haven't done is to break off the part that does not need to be run every frame into a separate function, but you can do that easily.

Also, some minor modifications will probably be needed in order to make it work with AAPO. Once again, feel free to ask if what I did was confusing.

Code:
//RCS thruster direct control algorithm
void RcsManager::RCS_CTRL(double simdt) {
	int ThCount = hParent->GetThrusterCount();

	VECTOR3 Position;
	VECTOR3 Direction;

	std::vector<VECTOR3> Potential_Acc, Potential_Tor;

	std::vector<double> Thruster_Level;

	VECTOR3 NetAccelerationSum = -RCS_Thruster_Target_Acceleration;
	VECTOR3 NetTorqueSum = -RCS_Thruster_Target_Torque;

	for (int i = 0 ; i < ThCount ; i++) {
		//Variable Declarations
		
		double MaxTh;
		double Level;
		//Initialize Values:
		hParent->GetThrusterRef(hParent->GetThrusterHandleByIndex(i), Position);
		hParent->GetThrusterDir(hParent->GetThrusterHandleByIndex(i), Direction);
		MaxTh = hParent->GetThrusterMax(hParent->GetThrusterHandleByIndex(i));
		Level = hParent->GetThrusterLevel(hParent->GetThrusterHandleByIndex(i));

		//Calculating Vectors and Constants
		Potential_Acc.push_back(Direction*MaxTh);
		Potential_Tor.push_back(crossp(Position, Potential_Acc[i]));
		Thruster_Level.push_back(Level);
		
		//Calculating Summations
		NetAccelerationSum += Potential_Acc[i]*Level;
		NetTorqueSum += Potential_Tor[i]*Level;
	}

	//Variable[Index][Thruster Parameter]
	std::vector<MotionConstants> A, B;

	//Generate (ax-b)^2 Terms (a,b);
	for (int i = 0 ; i < ThCount ; i++) {
		VECTOR3 SubASum = NetAccelerationSum - Potential_Acc[i]*Thruster_Level[i];
		VECTOR3 SubTSum = NetTorqueSum - Potential_Tor[i]*Thruster_Level[i];

		MotionConstants TempA, TempB;
		
		TempA.X_LIN = Potential_Acc[i].x;
		TempA.Y_LIN = Potential_Acc[i].y;
		TempA.Z_LIN = Potential_Acc[i].z;
		
		TempA.X_ROT = Potential_Tor[i].x;
		TempA.Y_ROT = Potential_Tor[i].y;
		TempA.Z_ROT = Potential_Tor[i].z;
		
		TempB.X_LIN = SubASum.x;
		TempB.Y_LIN = SubASum.y;
		TempB.Z_LIN = SubASum.z;

		TempB.X_ROT = SubTSum.x;
		TempB.Y_ROT = SubTSum.y;
		TempB.Z_ROT = SubTSum.z;

		A.push_back(TempA);
		B.push_back(TempB);
	}
	
	std::vector<double> Target;
	
	//y = (ax-b)^2 = (ax)^2-2abx+b^2 = aaxx-2abx+bb
	//y'= 2aax-2ab, at y' = 0:
	//x = 2ab/2aa  = ab/aa
	//Calculate Derivatives and Targets;
	for (int i = 0 ; i < ThCount ; i++) {
		double numer = 0;
		double denom = 0;

		numer += A[i].X_LIN*B[i].X_LIN + A[i].Y_LIN*B[i].Y_LIN + A[i].Z_LIN*B[i].Z_LIN;
		denom += A[i].X_LIN*A[i].X_LIN + A[i].Y_LIN*A[i].Y_LIN + A[i].Z_LIN*A[i].Z_LIN;
		
		numer += A[i].X_ROT*B[i].X_ROT + A[i].Y_ROT*B[i].Y_ROT + A[i].Z_ROT*B[i].Z_ROT;
		denom += A[i].X_ROT*A[i].X_ROT + A[i].Y_ROT*A[i].Y_ROT + A[i].Z_ROT*A[i].Z_ROT;

		Target.push_back(min(max(numer/denom, 0.0), MaxLevel));
	}

	for (int i = 0 ; i < ThCount ; i++) {
		double deltaT = abs(Target[i] - hParent->GetThrusterLevel(hParent->GetThrusterHandleByIndex(i)));
		if (deltaT > 0.01) {
			hParent->SetThrusterLevel(hParent->GetThrusterHandleByIndex(i), Target[i]);
		}
	}
}

My comments are sometimes incomprehensible or nonexistant. If you have any questions about the code, please ask me!
 

Attachments

  • RCS Controller.zip
    3.5 KB · Views: 9

Hlynkacg

Aspiring rocket scientist
Addon Developer
Tutorial Publisher
Donator
Joined
Dec 27, 2010
Messages
1,870
Reaction score
3
Points
0
Location
San Diego
Alright, I got a chance to test your code but I think I've run a fowl of the "weird roll" problem you described only in my case it's "weird yaw". How did you go about solving that?

I'd also appreciate it if you could walk me through the main RCS_CTRL function step-by-step as this is the part that I am especially interested in.

Is Target_Acceleration Force in newtons or m/s^2?

What role do the MotionConstants play?

that sort of stuff.

I appreciate the help but I'm going to need a better ifea of how the system actually works if I'm going to intigrate it with the vessels.
 

thepenguin

Flying Penguin
Addon Developer
Joined
Jul 27, 2013
Messages
220
Reaction score
1
Points
16
Location
Earth-Moon Lagrange Point (L4)
Alright, I got a chance to test your code but I think I've run a fowl of the "weird roll" problem you described only in my case it's "weird yaw". How did you go about solving that?

call "setMax(sqrt(length(w)));" where w is the angular velocity target vector every time you recalculate the new vector. That's how I go about it in my code. The setMax function limits the maximum thruster power to whatever value it gets. The reason for the "weird turning" is that without that one line of code, the system may go into some very minor oscillations, causing weird turning and some minor wasting of fuel.

In short, that single piece of code I posted above just limits the maximum power of the thrusters based on the size of the correction they need to make.

I'd also appreciate it if you could walk me through the main RCS_CTRL function step-by-step as this is the part that I am especially interested in.

I'll write up an explanation of it as soon as possible.

Is Target_Acceleration Force in newtons or m/s^2?

Everything is in Newtons (for linear), or Newton-meters (for angular)

What role do the MotionConstants play?

I wanted a single data-type that could store two vectors (6 double values). There isn't really a functional reason for it, it's more just to keep things simple to understand. (In short, I needed a VECTOR6.)

Here's the code for that, if you didn't see it in the header file.
Code:
struct MotionConstants {
	double X_ROT;
	double Y_ROT;
	double Z_ROT;

	double X_LIN;
	double Y_LIN;
	double Z_LIN;
};

that sort of stuff.

I appreciate the help but I'm going to need a better ifea of how the system actually works if I'm going to intigrate it with the vessels.

I thought I was a little short on documentation... I'll get on that right away.
 
Last edited:

Hlynkacg

Aspiring rocket scientist
Addon Developer
Tutorial Publisher
Donator
Joined
Dec 27, 2010
Messages
1,870
Reaction score
3
Points
0
Location
San Diego
In short, that single piece of code I posted above just limits the maximum power of the thrusters based on the size of the correction they need to make.

I guess that brings me to the next question of "How is the value of 'w' determined?"

My autopilots and manual "fly-by-wire" control module are already configured to provide a desired torque and force vector so really I just need to figure out how to get your RcsManager to read them properly.

Everything is in Newtons (for linear), or Newton-meters (for angular)

Roger that, for the sake of disambiguation then I'll be doing a search/replace to put everything in terms of Torque (Nm) and Force (N). My autopilot and FBW code already has a bunch of variables marked "acceleration" but they're in m/s^2.


Thankyou again :tiphat:
 

thepenguin

Flying Penguin
Addon Developer
Joined
Jul 27, 2013
Messages
220
Reaction score
1
Points
16
Location
Earth-Moon Lagrange Point (L4)
I guess that brings me to the next question of "How is the value of 'w' determined?"

Here's how I got from w to torque:

Code:
//w is the vector of the change in angular velocity (delta-omega)
setMax(sqrt(length(w)));
//multiply by Moment of Inertia and divide by timestep to get torque
w.x *= PMI.x;
w.y *= PMI.y;
w.z *= PMI.z;
Torque = -w / simdt;
all you have to do is reverse the code to generate w from torque.

NOTE: PMI in my code is this:
Code:
VECTOR3 PMI;
hParent->GetPMI(PMI);
PMI *= hParent->GetMass();

My autopilots and manual "fly-by-wire" control module are already configured to provide a desired torque and force vector so really I just need to figure out how to get your RcsManager to read them properly.

Here's the function you need to call:
Code:
//Set Target Vectors
void RcsManager::setThrusterTarget(VECTOR3 T, VECTOR3 A) {
	RCS_Thruster_Target_Torque = T;
	RCS_Thruster_Target_Acceleration = A;
}

It's currently listed as a private method... you'll need to change that. Also you could add the setMax() code from above here in order to simplify the process.

Roger that, for the sake of disambiguation then I'll be doing a search/replace to put everything in terms of Torque (Nm) and Force (N). My autopilot and FBW code already has a bunch of variables marked "acceleration" but they're in m/s^2.

That's fine. "Acceleration" just implied something more linear to me than "force".

Thankyou again :tiphat:
 
Last edited:

Hlynkacg

Aspiring rocket scientist
Addon Developer
Tutorial Publisher
Donator
Joined
Dec 27, 2010
Messages
1,870
Reaction score
3
Points
0
Location
San Diego
Would you mind explaining the "Navigate()" function as well?

What is the signifigance of the the different vectorsets and what would be the most efficient way of running "setThrusterTarget()"?

Simply calling "Navigate" each time step and setThrusterTarget as needed doesn't seem to be working.

Looking at the code I need to call RCS_CNTRL but calling it independantly of the rest of the controller seems to introduce it's own set of issues like unitialized variables and, the un-commanded yaw I mentioned previously.
 

thepenguin

Flying Penguin
Addon Developer
Joined
Jul 27, 2013
Messages
220
Reaction score
1
Points
16
Location
Earth-Moon Lagrange Point (L4)
Would you mind explaining the "Navigate()" function as well?

What is the signifigance of the the different vectorsets and what would be the most efficient way of running "setThrusterTarget()"?

Simply calling "Navigate" each time step and setThrusterTarget as needed doesn't seem to be working.

Looking at the code I need to call RCS_CNTRL but calling it independantly of the rest of the controller seems to introduce it's own set of issues like unitialized variables and, the un-commanded yaw I mentioned previously.

Firstly, Navigate() should not be called if you have your own control code. It was my wrapper around a wrapper around a wrapper. (Navigate oversees DynamicControl oversees SetThrusterTarget)
If you have your own autopilot, just use SetThrusterTarget() and don't bother with Navigate(). Navigate() overwrites the target vectors.

---------- Post added at 03:28 PM ---------- Previous post was at 03:01 PM ----------

Just a guess from what I am hearing:
You forgot this line of code:
Code:
RcsManager RCS = new RcsManager(this);
Then, in clbkPreStep(simt, simdt, mjd), call:
Code:
RCS->RCS_CTRL(simdt);

If that isn't it, can I see how you are implementing this into your controller? I don't quite know what is wrong until I get the context. I'm not quite sure what you are doing, but I would guess that it is a relatively simple error.
 
Last edited:
Top