Documente Academic
Documente Profesional
Documente Cultură
PROJECT SENSORS AND VECTOR FUNCTION SPRING 2009 REPORT
DEPARTMENT OF ELECTRICAL AND COMPUTER ENGINEERING
CALIFORNIA STATE UNIVERSITY FRESNO
FRESNO, CALIFORNIA
JONATHAN FLERCHINGER
JULY 2009
TABLE OF CONTENTS
Section Page
1. Introduction..............................................................................................................1
2. Sensors Packages......................................................................................................1
1. Proof of Concept Sensors...................................................................................1
2. Demonstration Sensors......................................................................................5
3. Theory of Operation.................................................................................................6
4. The Vector Function.................................................................................................6
1. Frames of Reference and Coordinate Systems...................................................6
2. Calculation of Position.......................................................................................7
3. Calculation of Attitude.......................................................................................9
4. Calculation of Final Gimbal Angles.................................................................10
Appendix............................................................................................................................11
1. INTRODUCTION
The California State University Fresno Unmanned Aerial Vehicle (CSUF UAV) project is
a joint venture between the Mechanical and Electrical Engineering departments at CSUF
and is sponsored as an educational exercise through Edwards Air Force Base (EAFB).
The project has two phases: Phase 1 involves a remotely piloted UAV that will acquire a
known Global Positioning System (GPS) target and laser designate it with a targeting
gimbal. Phase 2 involves making the UAV autonomous, such that the aircraft would fly
itself without direct human interaction. This paper will discuss the sensors package of the
aircraft being used in Phase One and the algorithms used to collect the sensor data and
output the gimbal angles.
2. SENSORS PACKAGES
The Sensors subsystem of the aircraft was broken into two separate systems, a proofof
concept (POC) grade system that was integrated from several cheap off the shelf
integrated circuits (ICs) and a final demonstration grade system purchased as an all in one
unit. We decided to do a POC primarily to avoid purchasing an expensive system that
wouldn't suit our needs, but also as an academic exercise to further increase our
knowledge and understanding of how our final package would work.
2.1 Proof of Concept Sensors
The POC system comprises a complete attitude, heading, and reference system (AHRS).
This means that we can expect to know the roll, pitch, and yaw of the aircraft at all times.
Along with a GPS the entire picture for attitude and position of the aircraft will be
known. In addition, the different sensors each have different error characteristics that
allow us to implement a type of Kalman filter to increase overall system accuracy. The
1
POC system is composed of: 3 Analog Devices ADXRS401 MEMS gyroscopes. A
Freescale MMA7260Q 3axis MEMS accelerometer. 2 VTI Technologies SCP1000D01
MEMS barometers. A PNI MicroMag3 3axis magnetometer. A Locosys LS20031 GPS
receiver.
The Analog Devices ADXRS401 is a
MEMS package that outputs a voltage level
corresponding to the rotation rate it
experiences about its normal axis. By
including 3 of them, mounted orthogonally
from each other, and integrating the rotation
rate versus time, we can determine the roll,
pitch, and yaw of the aircraft. The maximum
rotation rate the ADXRS401 can detect is 75
Figure 1: ADXRS401 Gyroscope
°/s. This is barely adequate for our purposes,
but suitable for a POC system. The ADXRS401 is a 5V system and outputs a 2.5V
reference pin for more accurate integration. We use a voltage divider to bring the outputs
into the 3.3V window that the 10bit analog to digital converters (ADC) can accept. This
corresponds to a minimum resolution of 0.08 °/bit.
−165∗G
r new = r old
512∗SPS
Equation 1
The instantaneous rotational position is defined by the constants given in Equation 1,
where rold is the unupdated rotational position and G is the current gyroscope reading in
bits, and SPS is the number of samples per second.
2
The Freescale MMA7260Q 3axis accelerometer is a
MEMS package that outputs a voltage level
corresponding to the accelerations it is experiencing
on each of its orthogonal axes. It can be configured to
measure a maximum acceleration of 1.5g, 2g, 4g, or
6g. We have configured it to its most sensitive at 1.5g
max. This corresponds to 800mV/g on the output pins
with a 3.3V power supply. With the 10bit ADC that
we have in our PIC32 our resolution is 4mg. The Figure 2: MMA7260Q 3axis
primary function of the accelerometers is to help accelerometer
correct the pitch and roll data we calculate from the gyroscopes. Accelerometers can also
be double integrated with respect to time to get short term positioning data for use in an
extended Kalman filter, but we have not implemented that function.
pitch = sin−1
xa
∣x a∣∣y a∣∣z a∣ roll = sin−1
ya
∣x a∣∣y a∣∣z a∣
Equation 3
With equation 3 the static orientation can be calculated from the acceleration values
along the x, y, and z axis. xa, ya, and za respectively. The units are unimportant as long as
they are all identical.
The VTI Technologies SCP1000D01 barometer
is a MEMS package that outputs pressure and
temperature as 2 words in SPI protocol. The
absolute pressure is represented by 19bits and
each bit corresponds to .25 Pascals. The
temperature is represented by 14bits and each
bit corresponds to .05 °C. We measure the static
Figure 3: SCP1000 Barometric Sensor
3
air pressure inside the aircraft and on the ground and use the difference to get a more
accurate above ground level (AGL) altitude than by GPS alone.
[ ]
R
T0 P −dT ∗
h= ∗ 1− dh g
−dT P0
dh
Equation 4
The altitude of one barometer over another is calculated with Equation 1. The altitude of
one barometer above another h is a function of the temperature on the ground T0 (K), the
standard atmospheric temperature gradient dT/dh (K/m), the pressures on the plane P
(Pa), and the ground P0 (Pa), the R value of air (m2/s2/K), and gravity (m/s2). Substituting
standard values for dT/dh and R gives:
[ ]
0.19
P
h = T 0∗153.8∗ 1− P
0
Equation 5
The PNI MicroMag3 3axis magnetometer
is a MEMS package that outputs three 16
bit SPI words corresponding to the
magnetic field along the three principle
axes. It has a maximum reading of 1.1 mT
and a minimum resolution of 17 nT. The
primary function of the magnetometer is to
help correct yaw data from the gyroscopes.
= 2 −atan2 y m , x m Figure 4: Micromag3 3Axis Magnetometer
Equation 6
Heading Ɵ as a function of the magnetic reading along the x and y axes of the
magnetometer.
4
The Locosys LS20031 is an integrated GPS
receiver and antenna module. The receiver is a
MediaTek MT3318 which is L2 band and
supports up to 32 channels and can output at up
to 5 Hz. The output format is TTL serial data in
NMEA format. The receiver supports GPS only
or SBAS support for increased accuracy via
DGPS. The output format of the GPS string is
decimal minutes to four decimal places. This
gives a resolution in the centimeter range
Figure 5: LS20031 5Hz GPS Receiver
depending upon latitude.
2.2 Demonstration Sensors
The demonstration grade AHRS system is a
self contained unit manufactured by SBG
Systems. The IG500n contains its own
MEMS gyroscopes, accelerometers,,
barometer, magnetometer, and GPS unit. It
also contains its own microprocessor to collect
the inputs, run them through an extended
Kalman filter, and output its best estimate of
the aircraft's attitude and position in real time Figure 6: SBG IG500n AHRS
at a 100 Hz refresh rate. The IG500n is capable of 0.5 ° accuracy for pitch and roll, and
1.0 ° accuracy for yaw, with double floating point precision. The position output accuracy
is less than 2.0m for latitude, longitude, and altitude. The IG500n outputs serial RS232
data with position and attitude represented by double precision floating point numbers.
5
The barometer is configured to work with standard definition atmospheric pressure
absolute altitude estimation, or with a ground sample pressure for relative altitude.
3. THEORY OF OPERATION
The POC system differs from the demonstration grade system in that all sensor inputs are
collected and then calculations must be performed to determine the attitude of the
aircraft. The gyroscopic input is integrated to give roll, pitch, and yaw. However, since the
integration is subject to to increasing error over time, the other sensors are necessary to
help correct this error. The accelerometers can give accurate roll and pitch if the aircraft
is not accelerating or rotating. The magnetometer is used to correct the yaw. When used
together, the gyroscope, accelerometer, and magnetometer give us an approximate
accuracy of 5 °RMS. The GPS gives reasonable accuracy for latitude and longitude
(<3.0m), but altitude accuracy is terrible (~10m). The barometer is subject to daily
atmospheric pressure changes, but when used in tandem with one on the ground it can
give much better relative altitude accuracy (~1.0m).
4.0 THE VECTOR FUNCTION
The vector function is meant to be a self contained C function within the PIC that takes
the gathered sensor data and outputs two angles to drive the gimbal to point at the target
on the ground. The vector function works with whatever data is available to it, from either
the POC system or the SBG system, and subject to user selectable input masking. The
outputs of the vector function are 2 signed integer angles, in degrees, between 180° and
180°.
4.1 Frames of Reference and Coordinate Systems
6
In order to understand what the vector function
does, it is first necessary to define a coordinate
convention for the aircraft, the target, and the
gimbal. Our targeting system works on a line of
sight basis, at an altitude of less than 1000m, so
it is useful to consider the ground a flat plane.
We define the target as the origin of a Cartesian
coordinate system with East as the positive x
axis, North as the positive yaxis, and the
Figure 7: East North Up coordinate
system positive zaxis is up (ENU coordinate system).
For the aircraft, we define a Cartesian coordinate system with the origin at the aircraft's
center of mass. The aircraft's positive xaxis is out the
nose, the positive yaxis is out the left wing, and the
positive zaxis is up. All rotational axes are right hand
rule with roll, pitch, and yaw corresponding to x, y,
and z, respectively. The gimbal has two degrees of
freedom, tilt and pan. These correspond directly to phi
and theta of a spherical coordinate system with the z
axis up, and the rotational plane parallel to the xy
Figure 8: Roll, Pitch, and Yaw
plane of the
axes
aircraft where a 0° theta is out the nose of the aircraft.
The distance to target corresponds directly to the
radius of this spherical coordinate system.
4.2 Calculation of Position
The first task for the vector function is to take the
GPS coordinates and altitude of the aircraft and target
Figure 9: Geocentric Coordinate
System
7
and convert them to a local Cartesian coordinate system. The GPS coordinate system that
our receivers output is actually the WGS84 standard that models the earth as a geode. We
convert the geodetic coordinate system to a geocentric coordinate system that models the
Earth in a Cartesian coordinate frame with the center of the Earth as the origin with the
zaxis through the north pole, the xaxis through the equator at 0° longitude and the y
axis through 90° E longitude. This conversion is done to account for the eccentricity of
the earth as an ellipsoid. We then take a standard rotational matrix to convert those
coordinates to a local Earth level system with the origin at the target. These conversions
lose less than a millimeter accuracy when done with double precision floating point
numbers and give us a much more convenient reference frame with which to work.
a
N=
1−e 2 sin2
2 a −b
2 2
e = a=6378137mb=6356752.3142m
a2
x=N h cos cos
y= Nh cos sin
z=N 1−e 2h
Equation 1
Equation 1 shows the calculations necessary to transform the geodetic coordinate system
(latitude and longitude) to the geocentric coordinate system. ɸ is the latitude, λ is
longitude, h is the altitude above mean sea level. The semimajor axis of the earth a, along
with the semiminor axis is used to define the eccentricity of the earth's ellipsoid e. This
calculation needs to be performed twice, for the aircraft and the target.
8
[ ]
−sin cos 0
M = −sin cos −sin sin cos
cos cos cos sin sin
[ ] []
x p −x 0 x
P= y p− y 0 y = M⋅P
z p −z 0 z
Equation 2
Equation 2 shows the rotation matrix used to make the final calculation to a local earth
level coordinate system. xp, yp, and zp are the aircraft's geocentric coordinates and x0, y0,
and z0 are the target's geocentric coordinates. ɸ and λ are the latitude and longitude of
the target. The final x, y, and z are the local earth level cartesian coordinates of the plane
with the target at the origin and x, y, z coaligned with East North and Up respectively.
4.3 Calculation of Attitude
The second task for the vector function is to determine the aircraft's attitude. Of course
with the SBG system, the attitude is precomputed, but the POC system outputs are raw
sensor readings and attitude must be calculated from them. The POC system feeds the
vector function barometric pressure readings from the aircraft and the basestation, if they
are available. The barometric readings are then used to calculate an altitude above ground
level which is an order of magnitude more accurate than the altitude that can be
calculated by GPS readings alone. The vector function chooses the accelerometer
corrected roll and pitch from the gyroscopes and the magnetometer corrected yaw from
the gyroscopes if all those sensors are available. Otherwise it will choose the
accelerometer for pitch and roll and magnetometer for yaw if the gyroscopes are not
available. If no sensors data is available with which to calculate the pitch and roll, the
vector function will assume the plane is level and give an output based upon the position
and heading, or position only . The vector function can still drive a useful 2D vector with
just magnetometer and GPS readings.
9
4.4 Calculation of Gimbal Angles
The final task for the vector function is to use the calculated 3D position and attitude
information to actually calculate the spherical coordinate vector to point back from the
gimbal at the target. The only way to do this is with a matrix transforms method that takes
all of the rotational and position axes into account at the same time.
[ ]
−cos ∗cos
= atan2 y , x = atan2 z , x 2y 2 d = −cos ∗sin
−sin
Equation 3
Equation 3 shows how the positional matrix is formed before final gimbal angles are
calculated. x, y, and z are the local earth level cartesian coordinates for the aircraft.
[ ]
cos ∗cos sin ∗sin ∗cos −cos ∗sin cos ∗sin ∗cos −sin ∗sin
M = cos ∗sin sin ∗sin ∗sin cos ∗cos cos ∗sin ∗sin −sin ∗cos
−sin sin ∗cos cos ∗cos
Equation 4
Equation 4 shows how the rotational matrix is populated. α, β, and Ɣ correspond to the
aircraft's roll, pitch, and yaw, respectively.
10
APPENDIX A:
Vector Function and Related Code
// GPS type struct
typedef struct _GPS
{
unsigned long UTC;
struct _Lat
{
double decimal;
unsigned char deg;
unsigned char min;
unsigned short sec;
unsigned char dir; // usually either 'N' or 'S'
} Lat;
struct _Long
{
double decimal;
unsigned char deg;
unsigned char min;
unsigned short sec;
unsigned char dir; // usually either 'E' or 'W'
} Long;
struct _Time
{
unsigned char hour;
unsigned char min;
unsigned short sec;
unsigned short ms;
} Time;
unsigned char fix;
unsigned char sat;
int altitude; // 551 = 55.1 meters
unsigned short velocity; //
int heading; //
} GPS_type;
typedef struct _Gimbal
{
int bSetTiltStatic;
int bSetPanStatic;
int theta;
int phi;
int DTT;
int x;
int y;
int z;
11
}Gimbal_type;
typedef struct _SBG
{
struct _GPS_
{
unsigned int time;
unsigned char fix; // 4 states: none, time only, 2D fix, 3D fix
unsigned char sats;
double altitude;
double Lat;
double Long;
} GPS;
float roll;
float pitch;
float yaw;
} SBG_type;
#include "utils.h"
#include "main.h"
#include "math.h"
#include "stdlib.h"
#include "stdio.h"
int quadrant(double angle) //given an angle in radians, this function returns the quadrant
{
int degangle = (int)(angle * _180_div_PI) % 360;
if ((degangle >= 0) && (degangle < 90)) return 1;
if ((degangle >= 90) && (degangle < 180)) return 2;
if ((degangle >= 180) && (degangle < 270)) return 3;
else return 4;
// return (int(((int(angle*180/3.1415926))%360)/90)+1); //should give the same value, in one line.
}
void invert(double a[3],double b[3],double c[3], double X[3][3])
{
int i, j;
double x, n=0.0, A[3][3], B[3][3], C[3][3];
A[0][0] = a[0];
A[0][1] = a[1];
A[0][2] = a[2];
A[1][0] = b[0];
A[1][1] = b[1];
A[1][2] = b[2];
A[2][0] = c[0];
A[2][1] = c[1];
12
A[2][2] = c[2];
for(i=0,j=0;j<3;j++)
{
if(j==2) n+=A[i][j]*A[i+1][0]*A[i+2][1];
else if(j==1) n+=A[i][j]*A[i+1][j+1]*A[i+2][0];
else n+=A[i][j]*A[i+1][j+1]*A[i+2][j+2];
}
for(i=2,j=0;j<3;j++)
{
if(j==2) n=A[i][j]*A[i1][0]*A[i2][1];
else if(j==1) n=A[i][j]*A[i1][j+1]*A[i2][0];
else n=A[i][j]*A[i1][j+1]*A[i2][j+2];
}//n now holds det(A);
//n=A[0][0]*(A[1][1]*A[2][2]A[1][2]*A[2][1])A[1][0]*(A[0][1]*A[2][2]A[0][2]*A[2][1])
+A[2][0]*(A[0][1]*A[1][2]A[0][2]*A[2][1]);
if (n!=0) x = 1.0/n;
else x = 99999999999.0; //if we are passed a singular matrix, return results that don't make sense,
not crash
for(i=0;i<3;i++) for(j=0;j<3;j++) B[i][j]=A[j][i];//B now holds transpose(A)
C[0][0]=B[1][1]*B[2][2](B[2][1]*B[1][2]);
C[0][1]=(1)*(B[1][0]*B[2][2](B[2][0]*B[1][2]));
C[0][2]=B[1][0]*B[2][1](B[2][0]*B[1][1]);
C[1][0]=(1)*(B[0][1]*B[2][2]B[2][1]*B[0][2]);
C[1][1]=B[0][0]*B[2][2]B[2][0]*B[0][2];
C[1][2]=(1)*(B[0][0]*B[2][1]B[2][0]*B[0][1]);
C[2][0]=B[0][1]*B[1][2]B[1][1]*B[0][2];
C[2][1]=(1)*(B[0][0]*B[1][2]B[1][0]*B[0][2]);
C[2][2]=B[0][0]*B[1][1]B[1][0]*B[0][1];//C now holds adjunct(B)
for(i=0;i<3;i++) for(j=0;j<3;j++) X[j][i]=C[i][j]*x; //X now holds A^1
Gimbal_type Vector()
{
// This is the Vector.
Gimbal_type vector; // create
Gimbal_type entity. (this function returns this type)
// If the GPS sensor is selected its data will be used in the Vector calculations
// if the GPS unit is disabled in this function we will not calculate anything. The gimbal will be set
to a control
// position and DTT set to 0.
if (!(Sensor_Enable & SENSOR_ENABLE_GPS) && !(Sensor_Enable &
SENSOR_ENABLE_SBG))
{
vector.theta= 0;
vector.phi= 0;
13
vector.DTT=0;
return(vector);
}
// ****************************** Calculate the Vector
*********************************************
// Collect needed data for static calculation.
vector_GPS = current_GPS; // create snapshot of plane's
GPS for vector calculation.
vector_COMPASS = current_COMPASS; // create snapshot of COMPASS for
vector calculation.
target_vector_GPS = target_GPS; // create snapshot of target GPS for
vector calculation.
Gyro_type vector_GYRO = Current_Gyro; // create snapshot of GYRO for vector
calculation.
double target_temp_altitude;
double pitch=0,roll=0,yaw=0;
/*
//Define the yaxis of the plane as positive off the left wing
pitch = Current_Gyro.Y.position * GYRO_SKEW; //in degrees
//Define the xaxis of the plane as positive out through the plane's nose
roll = Current_Gyro.X.position * GYRO_SKEW;
//Define the xaxis of the plane as positive out through the plane's nose
yaw = Current_Gyro.Z.position * GYRO_SKEW;
*/
// ********WARNING********** using current_Gyro. instead of vector_Gyro. in the vector
calcs
// can result in using data from different sample sets. Copy the data then use this static
// set of variables for the calculations. Freddy made the fix.
//Define the yaxis of the plane as positive off the left wing
if (Sensor_Enable & SENSOR_ENABLE_SBG)
{
vector_GPS.Lat.decimal = SBG.GPS.Lat;
vector_GPS.Long.decimal = SBG.GPS.Long;
Current_Altitude = SBG.GPS.altitude;
target_temp_altitude = (double)target_vector_GPS.altitude/10.0;
}
else
{
Current_Gyro.Y.angle = (int)((Current_Gyro.Y.position*165/
(512*TOGGLES_PER_SEC_T4))%360); //165 is an experimentally determined constant based upon the
sample rate, I think (Jon)
Current_Gyro.X.angle = (int)((Current_Gyro.X.position*165/
14
(512*TOGGLES_PER_SEC_T4))%360);
Current_Gyro.Z.angle = (int)((Current_Gyro.Z.position*165/
(512*TOGGLES_PER_SEC_T4))%360);
if (abs(Current_Gyro.Y.angle) > 180 ) Current_Gyro.Y.angle = (Current_Gyro.Y.angle/
(abs(Current_Gyro.Y.angle)))*360; //ensures that the angles are between +pi
if (abs(Current_Gyro.X.angle) > 180 ) Current_Gyro.X.angle = (Current_Gyro.X.angle/
(abs(Current_Gyro.X.angle)))*360;
if (abs(Current_Gyro.Z.angle) > 180 ) Current_Gyro.Z.angle = (Current_Gyro.Z.angle/
(abs(Current_Gyro.Z.angle)))*360;
if (Sensor_Enable & SENSOR_ENABLE_GYRO_Y) pitch = Current_Gyro.Y.angle; //in
degrees
//Define the xaxis of the plane as positive out through the plane's nose
if (Sensor_Enable & SENSOR_ENABLE_GYRO_X) roll = Current_Gyro.X.angle;
//Define the zaxis of the plane as positive up from the pilot's position
if (Sensor_Enable & SENSOR_ENABLE_GYRO_Z) yaw = Current_Gyro.Z.angle;
//prefer the use of the magnetometer for heading, so if it's enabled, use it.
if ((Sensor_Enable & SENSOR_ENABLE_MAG) && !(Sensor_Enable &
SENSOR_ENABLE_GYRO_Z)) yaw = 1*vector_COMPASS.heading/100 + 90;
double apitch,aroll;
apitch = SQRT2*_180_div_PI*asin((double)((double)(Current_Accel.X.raw)/((double)
(abs(Current_Accel.X.raw)) + (double)(abs(Current_Accel.Y.raw)) + (double)
(abs(Current_Accel.Z.raw)))));
aroll = SQRT2*_180_div_PI*asin((double)((double)(Current_Accel.Y.raw)/((double)
(abs(Current_Accel.X.raw)) + (double)(abs(Current_Accel.Y.raw)) + (double)
(abs(Current_Accel.Z.raw)))));
if ((Sensor_Enable & SENSOR_ENABLE_ACCEL_Y) && !(Sensor_Enable &
SENSOR_ENABLE_GYRO_X)) pitch = apitch;
//Define the xaxis of the plane as positive out through the plane's nose
if ((Sensor_Enable & SENSOR_ENABLE_ACCEL_X) && !(Sensor_Enable &
SENSOR_ENABLE_GYRO_Y)) roll = aroll;
// if Altitude is used in calculations for 3D vector.
if (Sensor_Enable & SENSOR_ENABLE_ALT)
{
// if Altitude ON and Barometer is Altitude source.
if (Sensor_Enable & SENSOR_ENABLE_ALT_BAR)
{
double pressure = current_BAR.pressure + Barometer_Offset; //these
numbers are actually the pressure x 4, but they
double groundpressure = base_BAR.pressure; //are only used as a
quotient, so we don't need to modify them
double temperature = current_BAR.temp/20.0 +273.15;
double groundtemp = base_BAR.temp/20.0 +273.15;
Current_Altitude = (groundtemp / .0065) * (1
pow(pressure/groundpressure , 0.19));
target_temp_altitude = 0;
15
}
// if Altitude is ON and Barometer is OFF then GPS is Altitude source.
else if (Sensor_Enable & SENSOR_ENABLE_ALT_GPS)
{
Current_Altitude = (double)vector_GPS.altitude/10.0;
target_temp_altitude = (double)target_vector_GPS.altitude/10.0;
}
}
// if Altitude not used in vector calculation (2D control).
else
{
Current_Altitude = 0;
target_temp_altitude = 0;
}
// find quadrant (+) ,() for East West/ North South
if (vector_GPS.Lat.dir == 'S') vector_GPS.Lat.decimal = (vector_GPS.Lat.decimal)* 1;
if (vector_GPS.Long.dir == 'W') vector_GPS.Long.decimal = (vector_GPS.Long.decimal)* 1;
if (target_vector_GPS.Lat.dir == 'S') target_vector_GPS.Lat.decimal =
(target_vector_GPS.Lat.decimal)* 1;
if (vector_GPS.Long.dir == 'W') target_vector_GPS.Long.decimal =
(target_vector_GPS.Long.decimal)* 1;
}
vector_GPS.Lat.decimal = vector_GPS.Lat.decimal*PI_div_180; //convert gps coords to radians
vector_GPS.Long.decimal = vector_GPS.Long.decimal*PI_div_180;
target_vector_GPS.Lat.decimal = target_vector_GPS.Lat.decimal*PI_div_180;
target_vector_GPS.Long.decimal = target_vector_GPS.Long.decimal*PI_div_180;
double a = 6378137, b = 6356752.3142;
double esquared = (a*ab*b)/(a*a); //earth constants, the eccentricity squared, approx .0067
double phi = vector_GPS.Lat.decimal; //% latitude in radians assume 90 degrees north of
plane
double lambda = vector_GPS.Long.decimal; //% lon in radians assume positive to east of
plane
double h = Current_Altitude; //% in meters assume altitude from mean sea level
double phi0 = target_vector_GPS.Lat.decimal; //% latitude in radians assume 90 degrees
north of target
double lambda0 = target_vector_GPS.Long.decimal; //% lon in radians assume positive to east of
target
double h0 = target_temp_altitude; //% in meters altitude of target above mean sea level
double sinphi = sin(phi); // duh
double cosphi = cos(phi); // duh
double sinlambda0 = sin(lambda0);
double coslambda0 = cos(lambda0);
double N = a/(sqrt(1(esquared*sinphi*sinphi))); //normalization
double x = (N + h) * cosphi * cos(lambda);
double y = (N + h) * cosphi * sin(lambda);
double z = (N*(1 esquared) + h) * sinphi; //x, y, and z are now the geocentric coords of the plane
double sinphi0 = sin(phi0); // duh
16
double cosphi0 = cos(phi0); // duh
double N0 = a / sqrt(1 esquared * sinphi0*sinphi0); //normalization
double x0 = (N0 + h0) * cosphi0 * coslambda0;
double y0 = (N0 + h0) * cosphi0 * sinlambda0;
double z0 = (N0*(1 esquared) + h0) * sinphi0; //x0, y0, and z0 are now the geocentric coords of
the target
//Now that both coords are geocentric, a simple matrix rotation will produce local reference frame
coords
double M[3][3];
M[0][0] = sinlambda0;
M[1][0] = coslambda0;
M[2][0] = 0;
M[0][1] = sinphi0*coslambda0;
M[1][1] = sinphi0*sinlambda0;
M[2][1] = cosphi0;
M[0][2] = cosphi0*coslambda0;
M[1][2] = cosphi0*sinlambda0;
M[2][2] = sinphi0;
double xlocal = (xx0)*M[0][0]+(yy0)*M[1][0]+(zz0)*M[2][0];
double ylocal = (xx0)*M[0][1]+(yy0)*M[1][1]+(zz0)*M[2][1];
double zlocal = (xx0)*M[0][2]+(yy0)*M[1][2]+(zz0)*M[2][2];
double DTT = sqrt(xlocal*xlocal+ylocal*ylocal+zlocal*zlocal);
//begin non rpy method
double theta1 = atan2(ylocal, xlocal);
phi = atan2(zlocal, sqrt(xlocal*xlocal+ ylocal*ylocal)); //changed for rpy calcs
// begin transform method
roll*=PI_div_180;
pitch*=PI_div_180;
yaw*=PI_div_180;
double cosroll = cos(roll), sinroll = sin(roll), cospitch = cos(pitch), sinpitch = sin(pitch), cosyaw =
cos(yaw), sinyaw = sin(yaw), costheta = cos(theta1), sintheta = sin(theta1);
cosphi = cos(phi);
sinphi = sin(phi);
double am[3],bm[3],c[3], d[3], A[3];
int i,j;
for (i=0;i<3;i++)
{
am[i]=0;
bm[i]=0;
c[i]=0;
d[i]=0;
A[i]=0;
}
c[2] = cosroll*cospitch;
bm[2] = sinroll*cospitch;
am[2] = sinpitch;
c[1] = cosroll*sinpitch*sinyaw sinroll*cosyaw;
17
bm[1]= sinroll*sinpitch*sinyaw + cosroll*cosyaw;
am[1] = cospitch*sinyaw;
c[0] = cosroll*sinpitch*cosyaw sinroll*sinyaw;
bm[0] = sinroll*sinpitch*cosyaw cosroll*sinyaw;
am[0] = cospitch*cosyaw;
d[0] = cosphi*costheta;
d[1] = cosphi*sintheta;
d[2] = sinphi;
//A[0,1,2] = inverse of matrix am,bm,cm * d[0,1,2]
double inv[3][3];
invert(am,bm,c,inv);
for (i = 0; i < 3; i++) for (j=0; j<3; j++) A[i]+=inv[i][j]*d[j]*1.0;
theta1 = atan2(A[1],A[0]);
phi = atan2(A[2], (A[0]/cos(theta13.1415926)))* _180_div_PI;
// end transform method
theta1*=_180_div_PI;
vector.theta = (int)theta1; // theta becomes an int.
// "flip the sign" adjust for the fact that jon and shawn disagreed on the sign convention for theta
vector.theta = vector.theta*1;
// Adjust for heading. Then take the modulus of theta with 360
//Now theta will be between 360 and +360
//this uses the compass for yaw, we must choose between compass and gyro for this
reading
//to be decided later
//vector.theta = (vector.theta vector_COMPASS.heading/100 + 90) % 360;
//vector.theta = (vector.theta + (int)(yaw*_180_div_PI)) % 360; //commented for debug,
maybe wrong coefficients?
// Adjust quadrant after heading shift, this is current theta for gimbal control
//We wish theta to be between 180 and +180, so if it is outside this range, we add or subtract 360
//as appropriate.
if (abs(vector.theta) > 180 ) //with our current matrix transforms, this should never happen
{
vector.theta = (vector.theta/(abs(vector.theta)))*360;
}
// Phi
vector.phi=(int)(phi);
// (DTT) is the magnitude of the vector (in meters) from the plane to the target.
// this value is calculated here and then saved to current_Gimbal.DTT.
vector.DTT= (int)DTT;
vector.x = (int)xlocal;
18
vector.y = (int)ylocal;
vector.z = (int)zlocal;
// This function returns a type_Gimbal .theta, .phi, .DTT. calculated here.
return vector;
19