ardupilot/Tools/ArdupilotMegaPlanner/HIL/Utils.cs

280 lines
9.6 KiB
C#
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ArdupilotMega.HIL
{
public class Utils
{
public const double rad2deg = (180 / System.Math.PI);
public const double deg2rad = (1.0 / rad2deg);
public const double ft2m = (1.0 / 3.2808399);
public const double kts2fps = 1.68780986;
public static double sin(double val)
{
return System.Math.Sin(val);
}
public static double cos(double val)
{
return System.Math.Cos(val);
}
public static double acos(double val)
{
return System.Math.Acos(val);
}
public static double asin(double val)
{
return System.Math.Asin(val);
}
public static double atan2(double val, double val2)
{
return System.Math.Atan2(val, val2);
}
public static double radians(double val)
{
return val * deg2rad;
}
public static double degrees(double val)
{
return val * rad2deg;
}
public static double sqrt(double val)
{
return System.Math.Sqrt(val);
}
public static int[] range(int no)
{
int[] range = new int[no];
for (int a = 0; a < no; a++)
{
range[a] = a;
}
return range;
}
public static double fabs(double val)
{
return System.Math.Abs(val);
}
public static double tan(double val)
{
return System.Math.Tan(val);
}
public static int len(object[] data)
{
return data.Length;
}
public static Tuple<double, double, double> EarthRatesToBodyRates(double roll, double pitch, double yaw,
double rollRate, double pitchRate, double yawRate)
{
//convert the angular velocities from earth frame to
//body frame. Thanks to James Goppert for the formula
//all inputs and outputs are in degrees
//returns a tuple, (p,q,r)
var phi = radians(roll);
var theta = radians(pitch);
var phiDot = radians(rollRate);
var thetaDot = radians(pitchRate);
var psiDot = radians(yawRate);
var p = phiDot - psiDot * sin(theta);
var q = cos(phi) * thetaDot + sin(phi) * psiDot * cos(theta);
var r = cos(phi) * psiDot * cos(theta) - sin(phi) * thetaDot;
return new Tuple<double, double, double>(degrees(p), degrees(q), degrees(r));
}
public static Tuple<double, double, double> EarthRatesToBodyRatesRyan(double roll, double pitch, double yaw,
double x, double y, double z)
{
// thanks to ryan beall
var phi = radians(roll);
var theta = radians(pitch);
var psi = radians((360 - yaw) * 1.0);
var Po = radians(x);
var Qo = radians(y);
var Ro = radians(-z);
var P = Po * cos(psi) * cos(theta) - Ro * sin(theta) + Qo * cos(theta) * sin(psi);
var Q = Qo * (cos(phi) * cos(psi) + sin(phi) * sin(psi) * sin(theta)) - Po * (cos(phi) * sin(psi) - cos(psi) * sin(phi) * sin(theta)) + Ro * cos(theta) * sin(phi);
var R = Po * (sin(phi) * sin(psi) + cos(phi) * cos(psi) * sin(theta)) - Qo * (cos(psi) * sin(phi) - cos(phi) * sin(psi) * sin(theta)) + Ro * cos(phi) * cos(theta);
// P = 0;
//Q = 0;
//R = 0;
return new Tuple<double, double, double>(degrees(P), degrees(Q), degrees(R));
}
public static Tuple<double, double, double> EarthRatesToBodyRatesMine(double roll, double pitch, double yaw,
double rollRate, double pitchRate, double yawRate)
{
// thanks to ryan beall
var phi = radians(roll);
var theta = radians(pitch);
var psi = radians(yaw);
var Po = radians(pitchRate);
var Ro = radians(yawRate);
var Qo = radians(rollRate);
var Q = Po * cos(psi) + Qo * sin(psi);
var P = Po * sin(psi) + Qo * cos(psi); ;
var R = Ro;
return new Tuple<double, double, double>(degrees(P), degrees(Q), degrees(R));
/*
double Cr, Cp, Cz;
double Sr, Sp, Sz;
var phi = radians(roll);
var theta = radians(pitch);
var psi = radians(yaw);
var Po = radians(rollRate);
var Ro = radians(pitchRate);
var Qo = radians(yawRate);
Cr = Math.Cos((phi));
Cp = Math.Cos((theta));
Cz = Math.Cos((psi));
Sr = Math.Sin((phi));
Sp = Math.Sin((theta));
Sz = Math.Sin((psi));
// http://planning.cs.uiuc.edu/node102.html
// Z Y X
// roll -Sp, CpSr, CpCr
// pitch SzCp, SzSpSr+CzCr, SzSpCr-CpCr
// yaw CzCp, CzSpSr-SzCr, CzSpCr+SzSr
var P = -(Qo * Sp) + Po * Cp * Sr + Ro * Cp * Cr;
var Q = Qo * (Sz * Cp) + Po * (Sz * Sp * Sr + Cz * Cr) + Ro * (Sz * Sp * Cr - Cp * Cr);
var R = Qo * (Cz * Cp) + Po * (Cz * Sp * Sr - Sz * Cr) + Ro * (Cz * Sp * Cr + Sz * Sr);
return new Tuple<double, double, double>(degrees(P), degrees(Q), degrees(R));
* */
}
public static Tuple<double, double, double> OGLtoBCBF(double phi, double theta, double psi, double x, double y, double z)
{
double x_NED, y_NED, z_NED;
double Cr, Cp, Cy;
double Sr, Sp, Sy;
//Accelerations in X-Plane are expressed in the local OpenGL reference frame, for whatever reason.
//This coordinate system is defined as follows (taken from the X-Plane SDK Wiki):
// The origin 0,0,0 is on the surface of the earth at sea level at some "reference point".
// The +X axis points east from the reference point.
// The +Z axis points south from the reference point.
// The +Y axis points straight up away from the center of the earth at the reference point.
// First we shall convert from this East Up South frame, to a more conventional NED (North East Down) frame.
x_NED = (x) * -1.0;
y_NED = (y) * 1.0;
z_NED = (z) * -1.0;
// Next calculate cos & sin of angles for use in the transformation matrix.
// r, p & y subscripts stand for roll pitch and yaw.
Cr = Math.Cos((phi));
Cp = Math.Cos((theta));
Cy = Math.Cos((psi));
Sr = Math.Sin((phi));
Sp = Math.Sin((theta));
Sy = Math.Sin((psi));
// Next we need to rotate our accelerations from the NED reference frame, into the body fixed reference frame
// THANKS TO GEORGE M SIOURIS WHOSE "MISSILE GUIDANCE AND CONTROL SYSTEMS" BOOK SEEMS TO BE THE ONLY EASY TO FIND REFERENCE THAT
// ACTUALLY GETS THE NED TO BODY FRAME ROTATION MATRIX CORRECT!!
// CpCy, CpSy, -Sp | local_ax
// SrSpCy-CrSy, SrSpSy+CrCy, SrCp | local_ay
// CrSpCy+SrSy, CrSpSy-SrCy, CrCp | local_az
x = (x_NED * Cp * Cy) + (y_NED * Cp * Sy) - (z_NED * Sp);
y = (x_NED * ((Sr * Sp * Cy) - (Cr * Sy))) + (y_NED * ((Sr * Sp * Sy) + (Cr * Cy))) + (z_NED * Sr * Cp);
z = (x_NED * ((Cr * Sp * Cy) + (Sr * Sy))) + (y_NED * ((Cr * Sp * Sy) - (Sr * Cy))) + (z_NED * Cr * Cp);
return new Tuple<double, double, double>((x), (y), (z));
}
/// <summary>
/// From http://code.google.com/p/gentlenav/source/browse/trunk/Tools/XP_UDB_HILSIM/utility.cpp
/// Converts from xplanes to fixed body ref
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="z"></param>
/// <param name="alpha"></param>
/// <param name="beta"></param>
public static void FLIGHTtoBCBF(ref float x, ref float y, ref float z, float alpha, float beta)
{
float Ca = (float)Math.Cos(alpha);
float Cb = (float)Math.Cos(beta);
float Sa = (float)Math.Sin(alpha);
float Sb = (float)Math.Sin(beta);
float X_plane = (x * Ca * Cb) - (z * Sa * Cb) - (y * Sb);
float Y_plane = (z * Sa * Sb) - (x * Ca * Sb) - (y * Cb);
float Z_plane = (x * Sa) + (z * Ca);
x = X_plane;
y = Y_plane;
z = Z_plane;
}
public static Vector3 BodyRatesToEarthRates(Matrix3 dcm, Vector3 gyro)
{
//'''convert the angular velocities from body frame to
//earth frame.
//all inputs and outputs are in radians/s
//returns a earth rate vector
//'''
var p = gyro.x;
var q = gyro.y;
var r = gyro.z;
double phi = 0;
double theta = 0;
double psi = 0;
dcm.to_euler(ref phi, ref theta, ref psi);
var phiDot = p + tan(theta) * (q * sin(phi) + r * cos(phi));
var thetaDot = q * cos(phi) - r * sin(phi);
if (fabs(cos(theta)) < 1.0e-20)
theta += 1.0e-10;
var psiDot = (q * sin(phi) + r * cos(phi)) / cos(theta);
return new Vector3((phiDot), (thetaDot), (psiDot));
}
}
}