General Question pointing the hover engine

Topper

Addon Developer
Addon Developer
Donator
Joined
Mar 28, 2008
Messages
666
Reaction score
20
Points
33
I'm a bit lost at the moment...

How can I get the pitch and the "2D - direction projected onto the surface" (lets say heading) of the hover engine?
This should work even if the pitch is > 90°... ?

Do I have to use the rotation matrix and "transform" it to the local frame???
 
Last edited:

Lisias

Space Traveller Wanna-be
Joined
May 31, 2015
Messages
346
Reaction score
3
Points
18
Website
www.youtube.com
It's kind of a wild guess, but did you tried the

Code:
bool VESSEL::GetThrustVector (VECTOR3 & T) const

method? It returns the current thrusting vector on vessel coordinates, and with the GetPitch() and GetBank() methods you can convert it to the reference coordinates.
 

Topper

Addon Developer
Addon Developer
Donator
Joined
Mar 28, 2008
Messages
666
Reaction score
20
Points
33
Hi ok,

for the pitch I've got it (see attached code).

But I need also the angel between the ships airspeed vector and the hover engines left / right orientation.
In other words: I want to know the ships accelerration to the left / right relativ to the flight path, if the hover engine would be used.

Code:
    VESSEL *V = oapiGetFocusInterface();
    
    double alpha = V->GetYaw();
    double beta = V->GetPitch();
    double gamma = V->GetBank();

    MATRIX3 m3;
    m3.m11 = cos(alpha) * cos(beta);
    m3.m12 = cos(alpha) * sin(beta) * sin(gamma) - sin(alpha) * cos(gamma);
    m3.m13 = cos(alpha) * sin(beta) * cos(gamma) + sin(alpha) * sin(gamma);

    m3.m21 = sin(alpha) * cos(beta);
    m3.m22 = sin(alpha) * sin(beta) * sin(gamma) + cos(alpha) * cos(gamma);
    m3.m23 = sin(alpha) * sin(beta) * cos(gamma) - cos(alpha) * sin(gamma);

    m3.m31 = -sin(beta);
    m3.m32 = cos(beta) * sin(gamma);
    m3.m33 = cos(beta) * cos(gamma);

    //Rotating by 90° = PI/2
    double delta = PI/2;
    MATRIX3 m3_delta;
    m3_delta.m11 = cos(delta);    m3_delta.m12 = 0;    m3_delta.m13 = sin(delta);
    m3_delta.m21 = 0;            m3_delta.m22 = 1;    m3_delta.m23 = 0;
    m3_delta.m31 = -sin(delta);    m3_delta.m32 = 0;    m3_delta.m33 = cos(delta);
    
    //Multiplying the 2 matrix
    m3 = mul(m3,m3_delta);

    //Getting pitch of the hover engine
    double pitch_hoverengine = asin(-m3.m31);
 
Last edited:

Lisias

Space Traveller Wanna-be
Joined
May 31, 2015
Messages
346
Reaction score
3
Points
18
Website
www.youtube.com
What do you think on using

Code:
void VESSEL::GetLinearMoment (VECTOR3 & F) const

to get the moving force vector? If I'm right, all you need is to subtract the .Y from the Linear Moment from the Thrusting Vector to see if to what vessel's side you are drifting.
 

Topper

Addon Developer
Addon Developer
Donator
Joined
Mar 28, 2008
Messages
666
Reaction score
20
Points
33
My problem is I don't exactly know what I need and it's even more harder to explain ;-)

In a first step, I want to point the hover engine onto the "airspeed vector", so I just need the AOA and the slip angel of the thrust direction of the hover engine.

If I use *VESSEL=>GetAOA() or *VESSEL=>GetSlipAngle, it returns the AOA for the direction of the Cockpit, and I need this not for the direction of the Cockpit, but for the direction of the hover engine e.g..
I even need to avoid the gimbal lock if this will be a problem, so do I have to work with quaternions?
 
Last edited:

meson800

Addon Developer
Addon Developer
Donator
Joined
Aug 6, 2011
Messages
405
Reaction score
2
Points
18
How can I get the pitch and the "2D - direction projected onto the surface" (lets say heading) of the hover engine?
This should work even if the pitch is > 90°... ?

In a first step, I want to point the hover engine onto the "airspeed vector", so I just need the AOA and the slip angel of the thrust direction of the hover engine.

Here's my try at an answer :uhh:

I interpret that as you want to get the heading angle between the airspeed vector and the hover engine angle.

You can do that if you get both the airspeed vector and hover engine direction in local vehicle coordinates.
You can get airspeed in local coords with oapiGetFocusShipAirspeedVector. Then you can get the hover engine vector with VESSEL:GetThrusterMoment.

Now that you have them both in local coordinates, project them onto the X-Z plane (so you get a heading angle) by setting the Y component of each to 0

Then you should be able to do the dot product between the two to get the angle between them, which is the local heading offset the hover angle is producing.
 

Lisias

Space Traveller Wanna-be
Joined
May 31, 2015
Messages
346
Reaction score
3
Points
18
Website
www.youtube.com
I'm failing to follow you. :)

Unless I were building an atmospheric only vessel, I would not model a flight computer using the IAS, I would use the Linear Momentum to know to where I'm going (leaving on Orbiter shoulder's the handling of all that mess).

If I understood correctly, you want to pinpoint the Hover Engine thrust to the same direction the vessel is moving in order to retro-burst?
 

Topper

Addon Developer
Addon Developer
Donator
Joined
Mar 28, 2008
Messages
666
Reaction score
20
Points
33
Hi,
here is the code I got.
I need some more tests but it seems to be working.

At the moment it's just a test code which display orders on a MFD, but I reqire this to implement some autopilot functions.
In this example, THGROUP_HOVER is set fix, but it even works by replaceing it by each other thrgoup.
Code:
VESSEL *V = oapiGetFocusInterface();
	const int maxLines = 20;
	stringstream lineBuffer[maxLines];
	for (int i=0; i<20; i++) lineBuffer[i] << "";	
	VECTOR3 v3_shipAirSpeed;
	V->GetShipAirspeedVector(v3_shipAirSpeed);
	normalise(v3_shipAirSpeed);	
	THGROUP_HANDLE thgrouphandle = V->GetThrusterGroupHandle(THGROUP_HOVER);
	VECTOR3 thrusterDir;
	
	thrusterDir.x = 0;
	thrusterDir.y = 0;
	thrusterDir.z = 0;
	for (int i = 0; i < V->GetGroupThrusterCount(thgrouphandle); i++)
	{
		VECTOR3 v3_tdir; 
		THRUSTER_HANDLE th = V->GetGroupThruster(thgrouphandle,i);
		V->GetThrusterDir(th, v3_tdir);
		thrusterDir = thrusterDir + v3_tdir;		 
		th = V->GetGroupThruster(thgrouphandle,1);
	}
	normalise(thrusterDir);
	thrusterDir = thrusterDir;
	VECTOR3 deltaVector = crossp(thrusterDir,v3_shipAirSpeed);
	
	lineBuffer[0] << "Vx: " <<  v3_shipAirSpeed.x;
	lineBuffer[1] << "Vy: " <<  v3_shipAirSpeed.y;
	lineBuffer[2] << "Vz: " <<  v3_shipAirSpeed.z;
	lineBuffer[4] << "Vx: " <<  deltaVector.x;
	lineBuffer[5] << "Vy: " <<  deltaVector.y;
	lineBuffer[6] << "Vz: " <<  deltaVector.z;
	
	if (deltaVector.x < 0) lineBuffer[8] << "Pitch Nose Down " << abs(deltaVector.x);
    else lineBuffer[8] << "Pitch Nose Up " << abs(deltaVector.x);
	
	if (deltaVector.y > 0) lineBuffer[9] << "Yaw to the Left " << abs(deltaVector.y);
    else lineBuffer[9] << "Yaw to the right " << abs(deltaVector.y);

	if (deltaVector.z < 0) lineBuffer[10] << "Roll to the Left " << abs(deltaVector.z);
    else lineBuffer[10] << "Roll to the right " << abs(deltaVector.z);


	for (int i=0; i<maxLines; i++)  skp->Text(col(1),line(i+1),lineBuffer[i].str().c_str(),lineBuffer[i].str().length());
	return true;


---------- Post added 10-08-15 at 14:38 ---------- Previous post was 09-08-15 at 23:47 ----------

Sorry one point I didn't got...

How it's possible to get the heading of the hover engine, if the pitch is ~ 90° (And also from any other orientation)?

Is this the "gimbal lock problem"?

Here are my ideas to avoid this problem, but I don't know if they can't work or if I'm doning something wrong:
1.
- Get the rotation matrix from yaw, pitch and roll
- Rotate the matrix by 90° around pitch axis
- read out heading from the rotated matrix

2.
Use quaternions (I have still no Idea how to use them)
 
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
I suspect that I have encountered and surmounted what ever issues you're working on in my own lunar lander's code.

If you could explain a what you are trying to accomplish I might be able to throw some cod your way. Or at least help you avoid the numerous false starts and dead ends that I wandered down.
 

Topper

Addon Developer
Addon Developer
Donator
Joined
Mar 28, 2008
Messages
666
Reaction score
20
Points
33
The normal values for pitch, yaw, bank, AOA and Slip are for the direction X=0 Y=0 Z=1 (forward).

I want to know how I can calculate them for any other given vector, like X=0, Y=-1, Z=0 (downward) for the hover engine (Without gimbal lock problem)?
 
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
No matter how you set it up you are going to have an area where one or more of your values is going to come back undefined resulting in "Gimbal lock". For the default PYR (pitch yaw roll) set-up this occurs at a pitch of + or - 90 degrees.

The question is what are you trying to accomplish in this case?

If you are not going to be doing full pitch or inverted maneuvers there is no reason not to use the default values. If you are, it gets a bit more complicated as you need to determine what your reference frame is going to be and construct a rotation matrix based on that.

Are you trying to use your hover engine for orbital maneuvers or are you "flying to a point" like a helicopter?
 

Topper

Addon Developer
Addon Developer
Donator
Joined
Mar 28, 2008
Messages
666
Reaction score
20
Points
33
Ha did some progress.

Now I can get the rotation matrix relativ to the local horizon:

Code:
    OBJHANDLE hVessel = oapiGetFocusInterface()->GetHandle();
    OBJHANDLE hMoon = oapiGetObjectByName("Moon");
    MATRIX3 m3Vessel = getRotationMatrixFromHandle(hVessel);
    MATRIX3 m3Moon  = getRotationMatrixFromHandle(hMoon);
    
    MATRIX3 m3rel = mul(invertMatrix(m3Vessel), m3Moon);

    double ln,lt,r;
    oapiGetEquPos(hVessel,&ln,&lt,&r);    
    
    VECTOR3 ve;
    ve.x = 0;
    ve.y = 1;
    ve.z = 0;
    m3rel = rotateMatrix(ve, m3rel, -ln); //Rotate m around ve

    ve.x = 0;
    ve.y = 0;
    ve.z = 1;
    m3rel = rotateMatrix(ve, m3rel, lt); //Rotate m around ve

    matrixOut(m3rel,4);

Or is there an easier way?
 

Hlynkacg

Aspiring rocket scientist
Addon Developer
Tutorial Publisher
Donator
Joined
Dec 27, 2010
Messages
1,870
Reaction score
3
Points
0
Location
San Diego
That will work, but "easier way" is largely dependent on what your intended end point is.

For instance, if you're building a hover autopilot that just needs to maintain a given course you can equate forward/aft motion to pitch and left/right motion to roll. in which case you can use embedded OAPI functions like "HorizonInvRot".
 

Topper

Addon Developer
Addon Developer
Donator
Joined
Mar 28, 2008
Messages
666
Reaction score
20
Points
33
That will work, but "easier way" is largely dependent on what your intended end point is.

For instance, if you're building a hover autopilot that just needs to maintain a given course you can equate forward/aft motion to pitch and left/right motion to roll. in which case you can use embedded OAPI functions like "HorizonInvRot".

Hi Hlynkacg,
I think for any kind of autopiliot I want to create from now on I need (for none-atmospheric flight) a way to set yaw, pitch and roll without any gimbal lock problems.
Another issue is to rotate fast to the given setpoints. I think the example code comes very close to my requirements.
Maybe it's not always the optimum way to rotate a vessel to a setpoint (not fuel optimized), but it's very fast.
For example, it just tooks less then 14 seconds to rotate from 0 0 0 to 180 0 0 in the Delta Glieder :)
My minimum time I can get maunaly is 18. seconds. (If I accelerate rotation speed from 0 to 90° heading and then use killrot, but not such precisely as the autopilot does it :) ).
Such great changes are not normal for an autopilot, and for "small" changes it works much better as I can do manual, but however... :)

My wish is to recreate the baseland autopilot one day and make it possible to land just using the hover engine.
I tested the used of quaternions, so I can set any yaw, pitch an roll as required and it's working without gimbal lock problems now :)
So here is the very pre alpha code (experimental only!):
Code:
void Mymod::clbkPostStep(double simt,double simdt,double mjd)
{
	for (int i=0; i<20; i++)
	{
		mfdi.lineBuffer[i] << fixed<<setprecision(2 )<< 2;
		mfdi.lineBuffer[i] << internal << showpos;
		mfdi.lineBuffer[i].str("");	
	}

	// Rotate quaternian
	double ur = 0.01745329251994329576923690768489;//57.295779513082320876798154814105;
	
	//mfdi.bankSetPoint = 90;

	double c1 = cos(mfdi.headSetPoint*ur/2);
    double s1 = sin(mfdi.headSetPoint*ur/2);
    double c2 = cos(mfdi.pitchSetPoint*ur/2);
    double s2 = sin(mfdi.pitchSetPoint*ur/2);
	double c3 = cos(mfdi.bankSetPoint*ur/2);
    double s3 = sin(mfdi.bankSetPoint*ur/2);
    double c1c2 = c1*c2;
    double s1s2 = s1*s2;
    double w =c1c2*c3 - s1s2*s3;
	VECTOR3 q;
  	q.x =c1c2*s3 + s1s2*c3;
	q.y =s1*c2*c3 + c1*s2*s3;
	q.z =c1*s2*c3 - s1*c2*s3;

	q.x = s1 * s2 * c3 + c1 * c2 * s3;
	q.y = s1 * c2 * c3 + c1 * s2 * s3;
	q.z = c1 * s2 * c3 - s1 * c2 * s3;
	

	// create matrix from the quaternions
	double sqw = w*w;
    double sqx = q.x*q.x;
    double sqy = q.y*q.y;
    double sqz = q.z*q.z;

    // invers (inverse square length) is only required if quaternion is not already normalised
    double invs = 1 / (sqx + sqy + sqz + sqw);

	MATRIX3 mq;
	mq.m11 = ( sqx - sqy - sqz + sqw)*invs ; // since sqw + sqx + sqy + sqz =1/invs*invs
    mq.m22 = (-sqx + sqy - sqz + sqw)*invs ;
    mq.m33 = (-sqx - sqy + sqz + sqw)*invs ;
    
    double tmp1 = q.x*q.y;
    double tmp2 = q.z*w;
    mq.m21 = 2.0 * (tmp1 + tmp2)*invs ;
    mq.m12 = 2.0 * (tmp1 - tmp2)*invs ;
    
    tmp1 = q.x*q.z;
    tmp2 = q.y*w;
    mq.m31 = 2.0 * (tmp1 - tmp2)*invs ;
    mq.m13 = 2.0 * (tmp1 + tmp2)*invs ;
    tmp1 = q.y*q.z;
    tmp2 = q.x*w;
    mq.m32 = 2.0 * (tmp1 + tmp2)*invs ;
    mq.m23 = 2.0 * (tmp1 - tmp2)*invs ; 
	


	// ROTATE MATRIX------------------------------------
	MATRIX3 v_matrix = getLocalRotationMatrix2();
	MATRIX3 dm = mul(mq ,invertMatrix(v_matrix));
	matrixOut (v_matrix,4);

	VECTOR3 dv;
	
	dv.x = atan2(-dm.m31,dm.m11);
	dv.y = atan2(-dm.m23, dm.m22);
	dv.z = asin(dm.m21);
	
	vectorOut(dv,9);
	 // Sorry bank and head are swapped ;-)
	mfdi.lineBuffer[0] << "Head Set:" <<  mfdi.bankSetPoint * -1;
	mfdi.lineBuffer[1] << "Pitch Set:" <<  mfdi.pitchSetPoint;
	mfdi.lineBuffer[2] << "Bank Set:" <<  mfdi.headSetPoint + 90;
	

	VECTOR3 va;
	oapiGetFocusInterface()->GetAngularAcc(va);
	vectorOut(va,10);

	if (mfdi.apPwr) // If Autopilot is active...
	{

		// Delta Glieder
		const double maxPitch = 0.1 * 0.9; // first value is maxumum angle acceleration; Second is for security (Use only 90 % of maximum)
		const double maxYaw = 0.16 * 0.9;
		const double maxBank = 0.06 * 0.9;

		//  Atlantis
		const double maxPitch = 0.02 * 0.9; // first value is maxumum angle acceleration; Second is for security (Use only 90 % of maximum)
		const double maxYaw = 0.03 * 0.9;
		const double maxBank = 0.02 * 0.9;

		const double q = 3;
		double pitchSpeed, bankSpeed, yawSpeed;
		
		VESSEL *pVessel = oapiGetFocusInterface();
		VECTOR3 v0;
		pVessel->GetAngularVel(v0);
		
		if (abs(dv.x) > 0.02) dv.x = dv.x > 0 ? sqrt(2*maxYaw*abs(dv.x)): - sqrt(2*maxYaw*abs(dv.x)); 
		else dv.x = dv.x / q;

		if (abs(dv.y) > 0.02) dv.y = dv.y > 0 ? sqrt(2*maxPitch*abs(dv.y)): - sqrt(2*maxPitch*abs(dv.y)); 
		else dv.y = dv.y / q;

		if (abs(dv.z) > 0.02) dv.z = dv.z > 0 ? sqrt(2*maxBank*abs(dv.z)): - sqrt(2*maxBank*abs(dv.z)); 
		else dv.z = dv.z / q;

		pitchSpeed = -dv.y;
		yawSpeed = dv.x;
		bankSpeed = dv.z;
		setPitchSpeed(pitchSpeed);
		setYawSpeed(bankSpeed); // Sorry ! ;-)
		setBankSpeed(yawSpeed);
	}
}

But another question:
How is it possible to get the maximum angular acceleration of a thruster group like ATT_PITCH_UP?


[Edit]
ok, I just found something in the API Reference:
void VESSEL::GetThrusterRef (THRUSTER_HANDLE th, VECTOR3 & pos) const
I think I have to use it with lever rule I will try tomorrow...
 
Last edited:

Topper

Addon Developer
Addon Developer
Donator
Joined
Mar 28, 2008
Messages
666
Reaction score
20
Points
33
Method to set vertical acceleration

Hi this function sets the vertical acceleration without "regulating" but by calculating.
Code:
        VECTOR3 getThrGroupDir(THGROUP_TYPE thgt)
        {
            VECTOR3 dirTotal = {0,0,0};
            for(unsigned int i=0; i<v->GetGroupThrusterCount(thgt); i++) 
            {                        
                THRUSTER_HANDLE th=v->GetGroupThruster(thgt,i);            
                VECTOR3 dir;
                v->GetThrusterDir(th,dir);
                dirTotal = dirTotal + dir;
            }
            dirTotal = dirTotal / v->GetGroupThrusterCount(thgt);
            return dirTotal;            
        }

        double getEngineVectorDownward(THGROUP_TYPE thgt)
        {
            VECTOR3 edirLocal =  getThrGroupDir(thgt);
            VECTOR3 edirGlobal = {0,0,0};
            v->HorizonRot(edirLocal,edirGlobal);
            return -edirGlobal.y;
        }

        double getEngineVectorDownward(THRUSTER_HANDLE th)
        {
            VECTOR3 edirLocal;
            v->GetThrusterDir(th, edirLocal);
            VECTOR3 edirGlobal = {0,0,0};
            v->HorizonRot(edirLocal,edirGlobal);
            return -edirGlobal.y;
        }

        double getMaxThrGroupAcceleration(THGROUP_TYPE thg)
        {
            return getMaxThrGroupForce(thg) / v->GetMass();
        }

        double getMaxThrGroupForce(THGROUP_TYPE thgt)
        {
            double force = 0;
            for(unsigned int i=0; i<v->GetGroupThrusterCount(thgt); i++) 
            {                        
                THRUSTER_HANDLE th=v->GetGroupThruster(thgt,i);                    
                force = force + v->GetThrusterMax(th);        
            }        
            return force * length(getThrGroupDir(thgt));            
        }

        VECTOR3 getThrGroupForce(THGROUP_TYPE thgt)
        {
            return getThrGroupDir(thgt) * v->GetThrusterGroupLevel(thgt) * getMaxThrGroupForce(thgt);
        }

        VECTOR3 getThrusterGroupTypeForceVector(THGROUP_TYPE thgt)
        {
            VECTOR3 totalEngineForce = {0,0,0};
            for(unsigned int i=0; i<v->GetGroupThrusterCount(thgt); i++) 
            {                        
                THRUSTER_HANDLE th=v->GetGroupThruster(thgt,i);            
                VECTOR3 dir;
                v->GetThrusterDir(th,dir);
                double currentForce = v->GetThrusterMax(th) * v->GetThrusterLevel(th);
                totalEngineForce = totalEngineForce + (dir * currentForce);
            }
            return totalEngineForce;
        }

        void setVerticalACCByThrusterGroup(double acceleration,THGROUP_TYPE thgt)
        {
            double max_acceleration = getMaxThrGroupAcceleration(thgt);
            VECTOR3 totalForce, force, thrustv;
            v->GetForceVector(force);
            v->GetThrustVector(thrustv);
            //totalForce = force - thrustv;                                    //Using this, RCS Translation can change horizontal velocity
            totalForce = force - getThrusterGroupTypeForceVector(thgt);        //Using this, RCS Translation etc. has no effect 
            VECTOR3 v3_spd;            
            double x, y, r;
            v->GetEquPos(x,y,r);
            v->GetHorizonAirspeedVector(v3_spd);
            double lng, lat, r2;
            v->GetEquPos(lng,lat,r2);
            VECTOR3 vgv = oapiGetGroundVector(v->GetGravityRef(),lng,lat);
            v3_spd += vgv;
            double vhsqr = (v3_spd.x * v3_spd.x) + (v3_spd.z * v3_spd.z);
            double fz = (v->GetMass() * vhsqr) / r; //centrifugal force
            double dweight = sqrt((totalForce.x * totalForce.x) + (totalForce.y * totalForce.y) +  (totalForce.z * totalForce.z));
            double thrust = -(((dweight / v->GetMass()) - (-acceleration + (fz/ v->GetMass()) )) / max_acceleration);
            thrust = thrust / (getEngineVectorDownward(thgt));
            v->SetThrusterGroupLevel(thgt,thrust);
        }
It works! (Under almost all conditions if the available engine force is high enogh!?)
setVerticalACCByThrusterGroup() is the public part
:lol::tiphat:

I don't know why, but it's not working 100% atmospheres...
 
Last edited:
Top