Darrien Galid
/
Fused_Boat_Program
Self-navigating boat program with sensors and control system fused
main.cpp
- Committer:
- Deanatius
- Date:
- 2019-05-24
- Revision:
- 1:736ae4695570
- Parent:
- 0:cf5854b3296f
File content as of revision 1:736ae4695570:
#include "mbed.h" #include "MPU9250.h" #include "math.h" #include "TinyGPSplus.h" #include "Servo.h" #include "PID.h" Servo motor_servo(PTB1); // Boat throttle servo PWM Servo rudder_servo(PTB0); // Boat rudder servo PWM DigitalOut led(PTD3); MPU9250 mpu9250; // Instantiate MPU9250 class Timer t; // setup a timer Serial device(PTE0, PTE1); //RF Device tx and rx at PTE0 and PTE1 Serial pc(USBTX, USBRX); // Serial communication to display resuslts on PC TinyGPSPlus tgps; // Instantiate TinyGPS class PID velocity_controller(5.0, 1.0, 0.4, 0.1); PID heading_controller(5.0, 2.0, 0.4, 0.1); #define TX5 PTD3 #define RX5 PTD2 #define GPSBaud 9600 #define destinate_lat 1.532277 #define destinate_lng 110.357754 Serial GPSSerial(TX5, RX5); //Serial communication to read data from GPS float p1,p2,p3,p4,a1,a2,a3,a4,q1i,q2i,q3i,q4i,qnorm,a2o=0,a3o=0,a4o=0,axf=0,ayf=0,azf=0,l=1.0,now_vel=0,last_vel=0; uint32_t movwind=0, ready = 0,GPS_FLAG=0,axzerocount=0,ayzerocount=0,start_time=90,stop_avg=0,count_gps_reads=0,onetime=0,print_count=0; char buffer[14]; uint8_t whoami = 0; float deltat = 0.0f,ax=0.0f,ay=0.0f,az=0.0f,mx=0.0f,my=0.0f,mz=0.0f,gx=0.0f,gy=0.0f,gz=0.0f; double D=0,Do = 0, H=0, prev_lat=0,perev_lng=0,GPSPNO=0,GPSPEO=0,GPSPN,GPSPNintial,GPSPEintial,GpsstartingptN,GpsstartingptE,GPSPNcurrent,GPSPEcurrent,GPSPE,GPSVNO,GPSVEO,GPSVN,GPSVE,accel_var=0.0023,accel_varb=0.0023,GPS_VAR = 500; double gps_lato=0,gps_longo=0,gps_lat=0,gps_long=0,position_filt_N,position_unfilt_N,position_filt_E,position_unfilt_E,position_to_dest_N,position_to_dest_E,dest_P_N,dest_P_E,unposition_to_dest_N ,unposition_to_dest_E; double actual_pk1N = 1,actual_pk2N = 0,actual_pk3N = 0,actual_pk4N = 1,actual_pk1E = 1,actual_pk2E = 0,actual_pk3E = 0,actual_pk4E = 1,predicted_lat = 0, predicted_lng = 0,dest = 0,corrected_ang,sum_avg_lng=0,sum_avg_lat=0; void ManualOverride(); // Switch the boat into manual control mode void setup(); // used in calibration of MPU9250 and setting baud rates for serial com. void Read_MPU9250_Raw();// used in reading raw accel, gyro, magneto in 2 axis from the MPU9250 (IMU) // used to fuse the accelerometer with gyro and magnetometer readings to determine the orientation in quaternion form void MadgwickUpdate(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz, float deltat); void compute_accel_world_ref();//Used to rotate the acceleration from the sensor fram to the world frame (NED) using quaternion void compute_orientation();// used in computing the roll, Pitch and yaw from quaternion void SerialInterruptHandler(void);// Interupt function where GPS data is read double latitudetometers(double latitudetom);// convert long to meters (North) on Earth double longitudetometers(double longitudetom);// convert long to meters (East) on Earth // used to perform deadreckoning void kalmanfilterpreditction(double &PO, double &VO, double acceleration, double &actual_pk1, double &actual_pk2, double &actual_pk3, double &actual_pk4,int azerocount); // used to update the accumilative (IMU) readings with absolute GPS readings void kalmanfilterupdate(double GPS_POS, double GPS_VEL, double &predicted_pos, double &predicted_vel, double &actual_pk1, double &actual_pk2, double &actual_pk3, double &actual_pk4); void IMU_GPS_Fusion();// used in impleminting the Kalman filter to output predicted velocity and position. float invSqrt(float x);// inverse square root function class USV { private: public: float u; // Surge velocity float v; // Sway velocity float r; // Yaw velocity float x; // Position in East float y; // Position in North float psi; // Yaw angle }; class Setpoint { private: public: float vel; float north; float east; float psi; }; int main() { // motor_servo = 0.0; wait(0.5); motor_servo = 1.0; wait(1.0); motor_servo = 0.0; rudder_servo = 0.5; float motor_out = 0.0; float rudder_out = 0.0; float dist = 0.0; char command; bool start_flag = false; bool destination_flag = false; int read_count = 0; USV boat; Setpoint sp; device.baud(9600); device.printf("Wireless UART connection initialised.\n\r"); // Sensor setup device.printf("Press 'r' to calibrate sensors.\n\r"); while (!start_flag) { if (device.readable() != 0) command = device.getc(); if (command == 'r') start_flag = true; } device.printf("Calibrate command accepted.\n\r"); command = ' '; start_flag = false; setup();// code to setup GPS/MPU9250 while(t.read_ms()/1000<start_time) { Read_MPU9250_Raw(); MadgwickUpdate(gx, gy, gz, ax, ay, az, mx, my, mz, deltat); compute_accel_world_ref(); compute_orientation(); } device.printf("Sensor calibration done.\n\r"); // Wait for start command device.printf("Press 'r' to set setpoint and start.\n\r"); while (!start_flag) { if (device.readable() != 0) command = device.getc(); if (command == 'r') start_flag = true; } device.printf("Start command accepted.\n\r"); command = ' '; start_flag = false; // Declare setpoints sp.vel = 1.0; sp.north = destinate_lat; sp.east = destinate_lng; device.printf("Velocity setpoint is %f.\n\r", sp.vel); device.printf("North setpoint is %f.\n\r", sp.north); device.printf("East setpoint is %f.\n\r", sp.east); velocity_controller.setOutputLimits(0.0, 0.12); velocity_controller.setMode(AUTO_MODE); velocity_controller.setSetPoint(sp.vel); device.printf("Velocity controller initialised.\n\r"); heading_controller.setOutputLimits(-0.3, 0.3); heading_controller.setMode(AUTO_MODE); device.printf("Heading controller initialised.\n\r"); device.printf("Moving boat to destination.\n\r"); while(!destination_flag) { // Update boat states from sensor Read_MPU9250_Raw(); MadgwickUpdate(gx, gy, gz, ax, ay, az, mx, my, mz, deltat); compute_accel_world_ref(); compute_orientation(); GPSSerial.attach(&SerialInterruptHandler, Serial::RxIrq);// Interrupt trigerrer if (ready == 1) { IMU_GPS_Fusion(); boat.psi = yaw*DEG_TO_RAD; boat.u = sqrt((GPSVNO*GPSVNO) + (GPSVEO*GPSVEO)); boat.x = GPSPEO; boat.y = GPSPNO; // Update heading setpoint sp.psi = dest*DEG_TO_RAD; heading_controller.setSetPoint(sp.psi); //Update the process variable. velocity_controller.setProcessValue(boat.u); heading_controller.setProcessValue(boat.psi); //Set the new output. motor_out = velocity_controller.compute(); rudder_out = heading_controller.compute(); dist = sqrt((position_to_dest_N*position_to_dest_N)+(position_to_dest_E*position_to_dest_E)); motor_servo = motor_out; rudder_servo = 0.5 + rudder_out; //device.printf("Error = %f, Rudder output = %f\n\rRudder angle = %f\n\r", corrected_ang, rudder_out, 0.5+rudder_out); //device.printf("Motor_out = %f\n\r",motor_out); // Check if destination reached if(dist < 5.0) destination_flag = true; // Check if manual override commanded if (device.readable() != 0) command = device.getc(); if (command == 'r') ManualOverride(); if(read_count == 10) { device.printf("Dist = %f\n\r", dist); read_count = 0; } read_count++; //wait(0.1); } } device.printf("Destination reached. Switching to manual mode.\n\r"); ManualOverride(); return 0; } void ManualOverride() { device.printf("Manual mode entered.\n\r"); char command; motor_servo = 0.0; rudder_servo = 0.5; device.printf("Ready to accept commands.\n\r"); while(1) { while (device.readable() != 0) { command = device.getc(); switch (command){ case 'w': if (motor_servo < 1.0) motor_servo = motor_servo + 0.01; device.printf("Motor speed increased\n\r"); break; case 's': if (motor_servo > 0.0) motor_servo = motor_servo - 0.01; device.printf("Motor speed decreased\n\r"); break; case 'a': if (rudder_servo > 0.3) rudder_servo = rudder_servo - 0.1; device.printf("Rudder tilted right\n\r"); break; case 'd': if (rudder_servo < 0.8) rudder_servo = rudder_servo + 0.1; device.printf("Rudder tilted left\n\r"); break; case 'r': motor_servo = 0.0; rudder_servo = 0.5; device.printf("Reset\n\r"); break; } } } } void MadgwickUpdate(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz, float deltat) { float recipNorm; float s0, s1, s2, s3; float qDot1, qDot2, qDot3, qDot4; float hx, hy; float _2q0mx, _2q0my, _2q0mz, _2q1mx, _2bx, _2bz, _4bx, _4bz, _2q0, _2q1, _2q2, _2q3, _2q0q2, _2q2q3, q0q0, q0q1, q0q2, q0q3, q1q1, q1q2, q1q3, q2q2, q2q3, q3q3; // Rate of change of quaternion from gyroscope qDot1 = 0.5f * (-q1 * gx - q2 * gy - q3 * gz); qDot2 = 0.5f * (q0 * gx + q2 * gz - q3 * gy); qDot3 = 0.5f * (q0 * gy - q1 * gz + q3 * gx); qDot4 = 0.5f * (q0 * gz + q1 * gy - q2 * gx); // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation) if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) { // Normalise accelerometer measurement recipNorm = invSqrt(ax * ax + ay * ay + az * az); ax *= recipNorm; ay *= recipNorm; az *= recipNorm; // Normalise magnetometer measurement recipNorm = invSqrt(mx * mx + my * my + mz * mz); mx *= recipNorm; my *= recipNorm; mz *= recipNorm; // Auxiliary variables to avoid repeated arithmetic _2q0mx = 2.0f * q0 * mx; _2q0my = 2.0f * q0 * my; _2q0mz = 2.0f * q0 * mz; _2q1mx = 2.0f * q1 * mx; _2q0 = 2.0f * q0; _2q1 = 2.0f * q1; _2q2 = 2.0f * q2; _2q3 = 2.0f * q3; _2q0q2 = 2.0f * q0 * q2; _2q2q3 = 2.0f * q2 * q3; q0q0 = q0 * q0; q0q1 = q0 * q1; q0q2 = q0 * q2; q0q3 = q0 * q3; q1q1 = q1 * q1; q1q2 = q1 * q2; q1q3 = q1 * q3; q2q2 = q2 * q2; q2q3 = q2 * q3; q3q3 = q3 * q3; // Reference direction of Earth's magnetic field hx = mx * q0q0 - _2q0my * q3 + _2q0mz * q2 + mx * q1q1 + _2q1 * my * q2 + _2q1 * mz * q3 - mx * q2q2 - mx * q3q3; hy = _2q0mx * q3 + my * q0q0 - _2q0mz * q1 + _2q1mx * q2 - my * q1q1 + my * q2q2 + _2q2 * mz * q3 - my * q3q3; _2bx = sqrtf(hx * hx + hy * hy); _2bz = -_2q0mx * q2 + _2q0my * q1 + mz * q0q0 + _2q1mx * q3 - mz * q1q1 + _2q2 * my * q3 - mz * q2q2 + mz * q3q3; _4bx = 2.0f * _2bx; _4bz = 2.0f * _2bz; // Gradient decent algorithm corrective step s0 = -_2q2 * (2.0f * q1q3 - _2q0q2 - ax) + _2q1 * (2.0f * q0q1 + _2q2q3 - ay) - _2bz * q2 * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (-_2bx * q3 + _2bz * q1) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + _2bx * q2 * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz); s1 = _2q3 * (2.0f * q1q3 - _2q0q2 - ax) + _2q0 * (2.0f * q0q1 + _2q2q3 - ay) - 4.0f * q1 * (1 - 2.0f * q1q1 - 2.0f * q2q2 - az) + _2bz * q3 * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (_2bx * q2 + _2bz * q0) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + (_2bx * q3 - _4bz * q1) * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz); s2 = -_2q0 * (2.0f * q1q3 - _2q0q2 - ax) + _2q3 * (2.0f * q0q1 + _2q2q3 - ay) - 4.0f * q2 * (1 - 2.0f * q1q1 - 2.0f * q2q2 - az) + (-_4bx * q2 - _2bz * q0) * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (_2bx * q1 + _2bz * q3) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + (_2bx * q0 - _4bz * q2) * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz); s3 = _2q1 * (2.0f * q1q3 - _2q0q2 - ax) + _2q2 * (2.0f * q0q1 + _2q2q3 - ay) + (-_4bx * q3 + _2bz * q1) * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (-_2bx * q0 + _2bz * q2) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + _2bx * q1 * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz); recipNorm = invSqrt(s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3); // normalise step magnitude s0 *= recipNorm; s1 *= recipNorm; s2 *= recipNorm; s3 *= recipNorm; // Apply feedback step qDot1 -= beta * s0; qDot2 -= beta * s1; qDot3 -= beta * s2; qDot4 -= beta * s3; } // Integrate rate of change of quaternion to yield quaternion q0 += qDot1 * deltat; q1 += qDot2 * deltat; q2 += qDot3 * deltat; q3 += qDot4 * deltat; // Normalise quaternion recipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3); q0 *= recipNorm; q1 *= recipNorm; q2 *= recipNorm; q3 *= recipNorm; } float invSqrt(float x) { float halfx = 0.5f * x; float y = x; long i = *(long*)&y; i = 0x5f3759df - (i>>1); y = *(float*)&i; y = y * (1.5f - (halfx * y * y)); y = y * (1.5f - (halfx * y * y)); return y; } double latitudetometers(double latitudetom)// Position in North { double lattom; lattom = tgps.distanceBetween(latitudetom,0, 0, 0); if(latitudetom<0) lattom *=-1; return lattom; } double longitudetometers(double longitudetom)// Position in East { double lngtom; lngtom = tgps.distanceBetween(0,longitudetom, 0, 0); if(longitudetom<0) lngtom *=-1; return lngtom; } void SerialInterruptHandler(void) { if(GPSSerial.readable()) { if (tgps.encode(GPSSerial.getc())) { gps_lat = tgps.location.lat(); gps_long = tgps.location.lng(); if((gps_lat-gps_lato !=0) || (gps_long-gps_longo !=0)) GPS_FLAG = 1; //else //{ //GPS_FLAG = 0; // pc.printf("position filter = %f\n\r",l); // } gps_lato=gps_lat; gps_longo=gps_long; if(GPSPNO==0) //loop one time only { GPSPNO=latitudetometers(tgps.location.lat()); GPSPEO=longitudetometers(tgps.location.lng()); GPSVEO=0; GPSVNO=0; GPSPNintial =GPSPNO;// used to measure the velocity by comparing the distance moved every 1 sec GPSPEintial =GPSPEO; GpsstartingptN =GPSPNO;// starting point refrence GpsstartingptE = GPSPEO; } else ready = 1; // if(ready ==1 &&GPS_FLAG == 1 && stop_avg== 0) //{ // sum_avg_lat = sum_avg_lat+GPSPNO; // sum_avg_lng = sum_avg_lng+GPSPEO; //GPSPNO=latitudetometers(tgps.location.lat()); //GPSPEO=latitudetometers(tgps.location.lat()); //count_gps_reads++; //} //if(stop_avg ==1&&onetime==0) //{ // GPSPNO=sum_avg_lat/count_gps_reads; //GPSPEO=sum_avg_lng/count_gps_reads; //onetime=1; //} } } return; } void kalmanfilterpreditction(double &PO, double &VO, double acceleration, double &actual_pk1, double &actual_pk2, double &actual_pk3, double &actual_pk4, int azerocount) { double predicted_pk1,predicted_pk2,predicted_pk3,predicted_pk4,Predicted_p,Predicted_v; Predicted_p = PO+(VO*deltat)+(0.5*deltat*deltat*acceleration); Predicted_v = VO+acceleration*deltat; predicted_pk1 = actual_pk1 +(deltat*actual_pk2)+(deltat*actual_pk3)+(deltat*deltat*actual_pk4)+accel_var; predicted_pk2 = actual_pk2 + (deltat*actual_pk4); predicted_pk3 = actual_pk3 + (deltat*actual_pk4); predicted_pk4 = actual_pk4 + accel_var; if(azerocount>=5) { VO= 0; } else { VO = Predicted_v; } PO = Predicted_p; actual_pk1 = predicted_pk1; actual_pk2 = predicted_pk2; actual_pk3 = predicted_pk3; actual_pk4 = predicted_pk4; } void kalmanfilterupdate(double GPS_POS, double GPS_VEL, double &predicted_pos, double &predicted_vel, double &actual_pk1, double &actual_pk2, double &actual_pk3, double &actual_pk4) { double y = 1/((actual_pk1*actual_pk4+actual_pk1*GPS_VAR+actual_pk4*GPS_VAR+GPS_VAR*GPS_VAR)-(actual_pk2*actual_pk3)); double GK1 = (actual_pk1*actual_pk4+actual_pk1*GPS_VAR-actual_pk2*actual_pk3)*y; double GK2 = (actual_pk2*GPS_VAR)*y; double GK3 = (actual_pk3*GPS_VAR)*y; double GK4 = (actual_pk1*actual_pk4+actual_pk4*GPS_VAR-actual_pk2*actual_pk3)*y; if(predicted_vel!=0) { predicted_pos = predicted_pos+GK1*GPS_POS-GK1*predicted_pos+GK3*GPS_VEL-GK3*predicted_vel; predicted_vel = predicted_vel+GK2*GPS_POS-GK2*predicted_pos+GK4*GPS_VEL-GK4*predicted_vel; } // predicted_pos = predicted_pos+GK1*GPS_POS-GK1*predicted_pos; // predicted_vel = predicted_vel+GK2*GPS_POS-GK2*predicted_pos; actual_pk1 = actual_pk1-actual_pk1*GK1-GK3*actual_pk2; actual_pk2 = actual_pk2-actual_pk2*GK4-GK2*actual_pk1; actual_pk3 = actual_pk3-actual_pk3*GK1-GK3*actual_pk4; actual_pk4 = actual_pk4-actual_pk4*GK4-GK2*actual_pk3; } void setup() { GPSSerial.baud(GPSBaud); wait(0.001); pc.baud(9600); myled = 0; // turn off led wait(5); //Set up I2C i2c.frequency(400000); // use fast (400 kHz) I2C t.start(); // enable system timer myled = 1; // turn on led // Read the WHO_AM_I register, this is a good test of communication whoami = mpu9250.readByte(MPU9250_ADDRESS, WHO_AM_I_MPU9250); // Read WHO_AM_I register for MPU-9250 device.printf("I AM 0x%x\n\r", whoami); device.printf("I SHOULD BE 0x73\n\r"); myled = 1; if (whoami == 0x73) // WHO_AM_I should always be 0x73 { device.printf("MPU9250 WHO_AM_I is 0x%x\n\r", whoami); device.printf("MPU9250 is online...\n\r"); wait(1); mpu9250.resetMPU9250(); // Reset registers to default in preparation for device calibration mpu9250.MPU9250SelfTest(SelfTest); // Start by performing self test and reporting values device.printf("x-axis self test: acceleration trim within: %f pct of factory value\n\r", SelfTest[1]); device.printf("y-axis self test: acceleration trim within: %f pct of factory value\n\r", SelfTest[2]); device.printf("z-axis self test: acceleration trim within: %f pct of factory value\n\r", SelfTest[2]); device.printf("x-axis self test: gyration trim within: %f pct of factory value\n\r", SelfTest[3]); device.printf("y-axis self test: gyration trim within: %f pct of factory value\n\r", SelfTest[4]); device.printf("z-axis self test: gyration trim within: %f pct of factory value\n\r", SelfTest[5]); mpu9250.getAres(); // Get accelerometer sensitivity mpu9250.getGres(); // Get gyro sensitivity mpu9250.getMres(); // Get magnetometer sensitivity device.printf("Accelerometer sensitivity is %f LSB/g \n\r", 1.0f/aRes); device.printf("Gyroscope sensitivity is %f LSB/deg/s \n\r", 1.0f/gRes); device.printf("Magnetometer sensitivity is %f LSB/G \n\r", 1.0f/mRes); mpu9250.calibrateMPU9250(gyroBias, accelBias); // Calibrate gyro and accelerometers, load biases in bias registers device.printf("x gyro bias = %f\n\r", gyroBias[0]); device.printf("y gyro bias = %f\n\r", gyroBias[1]); device.printf("z gyro bias = %f\n\r", gyroBias[2]); device.printf("x accel bias = %f\n\r", accelBias[1]); device.printf("y accel bias = %f\n\r", accelBias[0]); device.printf("z accel bias = %f\n\r", accelBias[2]); wait(2); mpu9250.initMPU9250(); device.printf("MPU9250 initialized for active data mode....\n\r"); // Initialize device for active mode read of acclerometer, gyroscope, and temperature wait(1); mpu9250.initAK8963(magCalibration); device.printf("AK8963 initialized for active data mode....\n\r"); // Initialize device for active mode read of magnetometer device.printf("Accelerometer full-scale range = %f g\n\r", 2.0f*(float)(1<<Ascale)); device.printf("Gyroscope full-scale range = %f deg/s\n\r", 250.0f*(float)(1<<Gscale)); if(Mscale == 0) device.printf("Magnetometer resolution = 14 bits\n\r"); if(Mscale == 1) device.printf("Magnetometer resolution = 16 bits\n\r"); if(Mmode == 2) device.printf("Magnetometer ODR = 8 Hz\n\r"); if(Mmode == 6) device.printf("Magnetometer ODR = 100 Hz\n\r"); device.printf("Mag Calibration: Wave device in a figure eight until done!"); wait(4); mpu9250.magcalMPU9250(magBias, magScale); device.printf("Mag Calibration done!\n\r"); device.printf("x mag bias = %f\n\r", magBias[0]); device.printf("y mag bias = %f\n\r", magBias[1]); device.printf("z mag bias = %f\n\r", magBias[2]); //predicted_pk = A*actual_pk; //predicted_pk.print(); wait(2); } else { device.printf("Could not connect to MPU9250: \n\r"); device.printf("%#x \n", whoami); myled = 0; while(1) ; // Loop forever if communication doesn't happen } } void Read_MPU9250_Raw() { //while(movwind<64) //{ mpu9250.readMPU9250Data(MPU9250Data); // INT cleared on any read ax = (float)MPU9250Data[1]*aRes - accelBias[1]; // get actual g value, this depends on scale being set ay = (float)MPU9250Data[0]*aRes - accelBias[0]; az = (float)MPU9250Data[2]*aRes - accelBias[2]; ax = (ax)*9.80665f;// to get it in m/s^2 ay = (ay)*9.80665f;// to get it in m/s^2 az = (-az)*9.80665f;// to get it in m/s^2 axf=axf+ax; ayf=ayf+ay; azf=azf+az; movwind++; //} axf = axf/movwind; ayf=ayf/movwind; azf=azf/movwind; movwind = 0; //pc.printf("ax = %f", axf); // pc.printf(" ay = %f",ayf); //pc.printf(" az = %f m/s/s\n\r",azf); mpu9250.readMagData(magCount); // Read the x/y/z adc values // Calculate the magnetometer values in milliGauss // Include factory calibration per data sheet and user environmental corrections gx = (float)MPU9250Data[5]*gRes - gyroBias[1]; // get actual gyro value, this depends on scale being set gy = (float)MPU9250Data[4]*gRes - gyroBias[0]; gz = (float)MPU9250Data[6]*gRes - gyroBias[2]; mx = (float)magCount[0]*mRes*magCalibration[0] - magBias[0]; my = (float)magCount[1]*mRes*magCalibration[1] - magBias[1]; mz = (float)magCount[2]*mRes*magCalibration[2] - magBias[2]; // poor man's soft iron calibration mx *= magScale[0]; my *= magScale[1]; mz *= magScale[2]; Now = t.read_us(); // Calculate the gyro value into actual degrees per second deltat = (float)((Now - lastUpdate)/1000000.0f) ; // set integration time by time elapsed since last filter update lastUpdate = Now; // Pass gyro rate as rad/s mx = mx/10.0f; my = my/10.0f; mz = mz/10.0f; gx = gx*(3.141592f/180.0f); gy = gy*(3.141592f/180.0f); gz = -gz*(3.141592f/180.0f); } void compute_accel_world_ref() { //quaternion inverse calculation qnorm = q0*q0+q1*q1+q2*q2+q3*q3; q1i = q0/qnorm; q2i = -q1/qnorm; q3i = -q2/qnorm; q4i = -q3/qnorm; //quaternion rotation * acceleration vector p1 = q0*0-q1*ax-q2*ay-q3*az; p2 = q0*ax+q1*0+q2*az-q3*ay; p3 = q0*ay-q1*az+q2*0+q3*ax; p4 = q0*az+q1*ay-q2*ax+q3*0; // compute acceleration vector a1 = p1*q1i-p2*q2i-p3*q3i-p4*q4i; // = 0 a2 = p1*q2i+p2*q1i+p3*q4i-p4*q3i; a3 = p1*q3i-p2*q4i+p3*q1i+p4*q2i; a4 = p1*q4i+p2*q3i-p3*q2i+p4*q1i; a4 = a4-9.80665f;//subtract the gravity component //Filtered accel // filter used to eliminate micromovements from filter readings if((a2<=0.042)&&a2>=-0.042) { a2=0; accel_var=0; } else { accel_var=accel_varb; } if((a3<=0.042)&&a3>=-0.042) { a3=0; accel_var=0; } else { accel_var=accel_varb; } if((a4<=0.035)&&a4>=-0.035) { a4=0; accel_var=0; } else { accel_var=accel_varb; } } void compute_orientation() { roll = atan2f(q0*q1 + q2*q3, 0.5f - q1*q1 - q2*q2); pitch = asinf(-2.0f * (q1*q3 - q0*q2)); yaw = atan2f(q1*q2 + q0*q3, 0.5f - q2*q2 - q3*q3); pitch *= 180.0f / PI; yaw *= 180.0f / PI; // yaw += 0.2f; // Magnetic declination at Kuching Malaysia roll *= 180.0f / PI; /*if(roll>0) roll = -(180-roll); else if(roll<0) roll = 180+roll;*/ } void IMU_GPS_Fusion() { dest_P_N=latitudetometers(destinate_lat); dest_P_E=longitudetometers(destinate_lng); if(GPS_FLAG == 0) { kalmanfilterpreditction(GPSPNO, GPSVNO,-a2,actual_pk1N,actual_pk2N,actual_pk3N,actual_pk4N,axzerocount); kalmanfilterpreditction(GPSPEO, GPSVEO,a3,actual_pk1E,actual_pk2E,actual_pk3E,actual_pk4E,ayzerocount); last_vel=now_vel; } if(GPS_FLAG == 1) { // pc.printf("vel = %f\n\r",(now_vel-last_vel)/1000000.0f); // pc.printf("vel = %f\n\r",deltat); now_vel = t.read_us(); GPSPNcurrent=latitudetometers(tgps.location.lat()); GPSPEcurrent = latitudetometers(tgps.location.lng()); //if(GPSVNO!=0) GPSVN = (GPSPNcurrent-GPSPNintial)/((now_vel-last_vel)/1000000.0f);//velocity from GPS readings North GPSVE = (GPSPEcurrent-GPSPEintial)/((now_vel-last_vel)/1000000.0f); kalmanfilterupdate(GPSPNcurrent,GPSVN, GPSPNO, GPSVNO,actual_pk1N,actual_pk2N,actual_pk3N,actual_pk4N); kalmanfilterupdate(GPSPEcurrent,GPSVE, GPSPEO, GPSVEO,actual_pk1E,actual_pk2E,actual_pk3E,actual_pk4E); GPSPNintial = GPSPNcurrent; GPSPEintial = GPSPEcurrent; //printf ("GPS = %0.2f\n\r",sqrt((unposition_to_dest_N*unposition_to_dest_N)+(unposition_to_dest_E*unposition_to_dest_E))); unposition_to_dest_N = dest_P_N - GPSPNcurrent; unposition_to_dest_E = dest_P_E - GPSPEcurrent; } //North position position_filt_N = GPSPNO-GpsstartingptN; position_unfilt_N =GPSPNcurrent-GpsstartingptN; // East position position_filt_E = GPSPEO-GpsstartingptE; position_unfilt_E = GPSPEcurrent-GpsstartingptE; position_to_dest_N = dest_P_N-GPSPNO; position_to_dest_E = dest_P_E-GPSPEO; tgps.dist_to_coord(GPSPNO,GPSPEO, predicted_lat, predicted_lng); dest = tgps.courseTo(predicted_lat,predicted_lng,destinate_lat,destinate_lng); // pc.printf("%f, %f\n\r",predicted_lat, predicted_lng); // pc.printf("%.2f\n\r",position_filt_N);//<------------------------worksN //pc.printf("%.2f\n\r",position_filt_E);//<------------------------worksE //pc.printf("%.4f & %.4f\n\r",position_filt_N,position_unfilt_N); //important //pc.printf("Roll = %.2f, Pitch = %.2f, Yaw = %.2f\n\r",roll,pitch,yaw); // algo to choose the shortes angle to turn<<<<<<<<<<<<,---- important note corrected_ang = yaw-dest; if(corrected_ang>180) corrected_ang = corrected_ang-360; else if(corrected_ang<-180) corrected_ang = corrected_ang+360; corrected_ang = - corrected_ang; //convention C.C.W destination is positive angle //pc.printf("Y = %.2f, TC = %.2f\n\r",yaw, corrected_ang);//<----------------- Heading // pc.printf("ax = %.2f, ay = %.2f, az = %.2f\n\r",ax,ay,az); //pc.printf("gx = %.4f, gy = %.4f, gz = %.4f\n\r",gx,gy,gz); //pc.printf("mx = %.2f, my = %.2f, mz = %.2f\n\r",mx,my,mz); //printf("%i\n\r",GPS_FLAG); if(GPS_FLAG == 1) { a2 = 0; //Jerk limiter a3 = 0; //Jerk limiter printf ("GPS = %0.2f\n\r",sqrt((unposition_to_dest_N*unposition_to_dest_N)+(unposition_to_dest_E*unposition_to_dest_E))); //printf("gps\n\r"); GPS_FLAG = 0; //pc.printf("GPS%.2f\n\r",dest); //pc.printf("GPS %f, %f\n\r",tgps.location.lat(), tgps.location.lng()); //pc.printf("GPS%.2f\n\r",position_unfilt_N);//<------------------------worksN // pc.printf("G PS%.2f\n\r",dest);//<----------------Course //pc.printf("GPS%.2f\n\r",position_unfilt_E);//<------------------------worksE } /* pc.printf("%f\n\r",(now_vel-last_vel)/1000000.0f); pc.printf("%.2f\n\r",deltat);*/ //if(GPS_FLAG == 0) //pc.printf("position filter = %f\n\r",l); // __enable_irq(); // led = 0; //led=1; //pc.printf("vel = %f\n\r",(now_vel-last_vel)/1000000.0f); // pc.printf("position un = %f\n\r",tgps.location.lat()); // algo used to reset the velocity to zero if no acceleration is detected for some time //x-axis if(a2==0) axzerocount++; else axzerocount = 0; /* if(axzerocount>=15) { vx = 0; vxo = 0; } else { }*/ //y-axis if(a3==0) ayzerocount++; else ayzerocount = 0; /* if(ayzerocount>=15) { vy = 0; vyo= 0; } //z-axis if(a4==0) azzerocount++; else azzerocount = 0; if(azzerocount>=15) { vz = 0; vzo= 0; } // end of reset algo */ }