Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: CommonTypes ESC Matrix PID Servo kalman mbed-rtos mbed
Fork of Nucleo_MPU_9250 by
Revision 0:89cf0851969b, committed 2018-06-26
- Comitter:
- AlanHuchin
- Date:
- Tue Jun 26 18:24:45 2018 +0000
- Commit message:
- hello
Changed in this revision
diff -r 000000000000 -r 89cf0851969b CID10DOF/CID10DOF.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/CID10DOF/CID10DOF.cpp Tue Jun 26 18:24:45 2018 +0000
@@ -0,0 +1,628 @@
+#include "CID10DOF.h"
+#include <math.h>
+#include "rtos.h"
+#include "Matrix.h"
+#include "Servo.h"
+#include "PIDcontroller.h"
+
+#ifndef min
+#define min(a,b) ( (a) < (b) ? (a) : (b) )
+#endif
+
+#ifndef max
+#define max(a,b) ( (a) > (b) ? (a) : (b) )
+#endif
+
+PID PID_ROLL(kp, ki, kd, Td);
+PID PID_PITCH(kp, ki, kd, Td);
+
+FIS_TYPE g_fisInput[fis_gcI];
+FIS_TYPE g_fisOutput[fis_gcO];
+
+
+CID10DOF::CID10DOF(PinName sda, PinName scl,PinName FL, PinName FR, PinName BL, PinName BR) : mpu9250(sda,scl),pc(USBTX,USBRX),telem(PC_0, PC_1)
+{
+
+ pc.baud(115200);
+ telem.baud(57600);
+
+ motor[0] = new Servo (FL); //motors are of class Servo as ESC are used in the similar manner
+ motor[1] = new Servo (FR);
+ motor[2] = new Servo (BL);
+ motor[3] = new Servo (BR);
+
+ min_calibrate = 0.0;
+ max_calibrate = 1.0;
+
+ e = 0;
+ last_e = 0;
+ l = 1.0f;
+
+
+}
+
+/**
+ * Initialize the FreeIMU I2C bus, sensors and performs gyro offsets calibration
+*/
+
+void CID10DOF::MPU9250init()
+{
+
+ uint8_t whoami = mpu9250.readByte(MPU9250_ADDRESS, WHO_AM_I_MPU9250); // Read WHO_AM_I register for MPU-9250
+ pc.printf("I AM 0x%x\n\r", whoami); pc.printf("I SHOULD BE 0x71\n\r");
+
+ if (whoami == 0x71) // WHO_AM_I should always be 0x68
+ {
+
+ mpu9250.resetMPU9250(); // Reset registers to default in preparation for device calibration
+ mpu9250.MPU9250SelfTest(SelfTest);
+ mpu9250.getAres(); // Get accelerometer sensitivity
+ mpu9250.getGres(); // Get gyro sensitivity
+ mpu9250.getMres(); // Get magnetometer sensitivity
+ mpu9250.calibrateMPU9250(gyroBias, accelBias); // Calibrate gyro and accelerometers, load biases in bias registers
+ wait(2);
+
+ mpu9250.initMPU9250();
+ pc.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);
+ pc.printf("AK8963 initialized for active data mode....\n\r"); // Initialize device for active mode read of magnetometer
+ pc.printf("Accelerometer full-scale range = %f g\n\r", 2.0f*(float)(1<<Ascale));
+ pc.printf("Gyroscope full-scale range = %f deg/s\n\r", 250.0f*(float)(1<<Gscale));
+
+ if(Mscale == 0) pc.printf("Magnetometer resolution = 14 bits\n\r");
+ if(Mscale == 1) pc.printf("Magnetometer resolution = 16 bits\n\r");
+ if(Mmode == 2) pc.printf("Magnetometer ODR = 8 Hz\n\r");
+ if(Mmode == 6) pc.printf("Magnetometer ODR = 100 Hz\n\r");
+
+ pc.printf("Mag Calibration: Wave device in a figure eight until done!");
+ wait(4);
+
+ magbias[0] = -41.563381;
+ magbias[1] = 165.252426;
+ magbias[2] = 55.095879;
+
+ magScale[0] = 0.866279;
+ magScale[1] = 1.087591;
+ magScale[2] = 1.079710;
+
+ //mpu9250.magcalMPU9250(magbias, magScale);
+ pc.printf("Mag Calibration done!\n\r");
+ pc.printf("x mag bias = %f\n\r", magbias[0]);
+ pc.printf("y mag bias = %f\n\r", magbias[1]);
+ pc.printf("z mag bias = %f\n\r", magbias[2]);
+ //pc.printf("Mag Calibration done!\n\r");
+ pc.printf("x mag Scale = %f\n\r", magScale[0]);
+ pc.printf("y mag Scale = %f\n\r", magScale[1]);
+ pc.printf("z mag Scale = %f\n\r", magScale[2]);
+ wait(2);
+
+
+ }else{
+
+ while(1) ; // Loop forever if communication doesn't happen
+ }
+
+ mpu9250.getAres(); // Get accelerometer sensitivity
+ mpu9250.getGres(); // Get gyro sensitivity
+ mpu9250.getMres(); // Get magnetometer sensitivity
+
+ t.start();
+
+}
+
+void CID10DOF::MPU9250GetValues()
+{
+ mpu9250.readAccelData(accelCount);
+
+ ax = (float)accelCount[0]*aRes - accelBias[0];
+ ay = (float)accelCount[1]*aRes - accelBias[1];
+ az = (float)accelCount[2]*aRes - accelBias[2];
+
+ mpu9250.readGyroData(gyroCount);
+
+ gx = (float)gyroCount[0]*gRes - gyroBias[0];
+ gy = (float)gyroCount[1]*gRes - gyroBias[1];
+ gz = (float)gyroCount[2]*gRes - gyroBias[2];
+
+ mpu9250.readMagData(magCount);
+
+ 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];
+ mx *= magScale[0]; // poor man's soft iron calibration
+ my *= magScale[1];
+ mz *= magScale[2];
+
+ tempCount = mpu9250.readTempData();
+ temperature = ((float) tempCount) / 333.87f + 21.0f;
+}
+
+void CID10DOF::MPU9250getYawPitchRoll()
+{
+ yaw = atan2(2.0f * (q[1] * q[2] + q[0] * q[3]), q[0] * q[0] + q[1] * q[1] - q[2] * q[2] - q[3] * q[3]);
+ pitch = -asin(2.0f * (q[1] * q[3] - q[0] * q[2]));
+ roll = atan2(2.0f * (q[0] * q[1] + q[2] * q[3]), q[0] * q[0] - q[1] * q[1] - q[2] * q[2] + q[3] * q[3]);
+
+ //float Xh = mx*cos(pitch)+my*sin(roll)*sin(pitch)-mz*cos(roll)*sin(pitch);
+ //float Yh = my*cos(roll)+mz*sin(roll);
+
+ //yawmag = atan2(Yh,Xh)+PI;
+
+ pitch *= 180.0f / PI;
+ yaw *= 180.0f / PI;
+ yaw -= 4.28; //
+ if(yaw < 0) yaw += 360.0f;
+ roll *= 180.0f / PI;
+
+}
+
+void CID10DOF::MPU9250ReadAxis(double * dat)
+{
+
+ if(mpu9250.readByte(MPU9250_ADDRESS, INT_STATUS) & 0x01) {
+ MPU9250GetValues();
+ }
+
+ Now = t.read_us();
+ deltat = (float)((Now - lastUpdate)/1000000.0f) ; // set integration time by time elapsed since last filter update
+ lastUpdate = Now;
+
+ sum += deltat;
+ sumCount++;
+
+
+
+ mpu9250.MahonyQuaternionUpdate( ax, ay, az, gx*PI/180.0f, gy*PI/180.0f, gz*PI/180.0f, my, mx, mz);
+
+ delt_t = t.read_ms() - count;
+
+ if (delt_t > 50) {
+ MPU9250getYawPitchRoll();
+ sum = 0;
+ sumCount = 0;
+ dat[0] = yaw;
+ dat[1] = pitch;
+ dat[2] = roll;
+ }
+
+
+}
+
+//----------------------------Function for ESC calibration---------------------
+void CID10DOF::Calibrate_Motors()
+{
+ for (int i = 0; i < 4; i++){ //run motors for some time in min speed
+ *motor[i] = max_calibrate;
+ }
+ wait(6.0); //wait for the response from ESC modules
+ for (int i = 0; i < 4; i++){
+ *motor[i] = min_calibrate; //run motors at maximum speed
+ }
+ wait(2.0);
+}
+
+//--------------------------Function for setting calibration limits-----------
+void CID10DOF::setLimits(double min, double max)
+{
+ if (min > max){ //here detect if someone tried making min to be more than max. If that is the case, then flip them together
+ min_calibrate = max;
+ max_calibrate = min;
+ } else {
+ min_calibrate = min;
+ max_calibrate = max;
+ }
+ if ((min_calibrate > 1.0) || (min_calibrate < 0.0)) //here chech if values are in correct range. If they are not, make them to be in correct range
+ min_calibrate = 0.0;
+ if ((max_calibrate > 1.0) || (max_calibrate < 0.0))
+ max_calibrate = 1.0;
+}
+
+//-------------------------------------Function for Stabilising---------------
+void CID10DOF::stabilise(double *speed, double *actSpeed, double *Diff){
+
+
+}
+
+//-----------------------Function for producing thrust in Z direction --------
+void CID10DOF::run (double *speed){
+ for (int i = 0; i < 4; i++){
+ *motor[i] = speed[i];
+ }
+}
+
+void CID10DOF::PID_Config(double *St_point, double *bias)
+{
+ PID_ROLL.setInputLimits(IN_MIN_ROLL,IN_MAX_ROLL);
+ PID_ROLL.setOutputLimits(OUT_MIN_ROLL, OUT_MAX_ROLL);
+ PID_ROLL.setBias(0.0);
+
+ PID_PITCH.setInputLimits(IN_MIN_PITCH,IN_MAX_PITCH);
+ PID_PITCH.setOutputLimits(OUT_MIN_PITCH, OUT_MAX_PITCH);
+ PID_PITCH.setBias(0.0);
+
+}
+
+void CID10DOF::PID_Run(double *processVariable, double *setPoint,double *pid_diff)
+{
+
+ PID_ROLL.setProcessValue(processVariable[2]);
+ PID_ROLL.setSetPoint(setPoint[1]);
+ pid_diff[2] = PID_ROLL.compute();
+
+ PID_PITCH.setProcessValue(processVariable[1]);
+ PID_PITCH.setSetPoint(setPoint[1]);
+ pid_diff[1] = PID_PITCH.compute();
+
+}
+
+float CID10DOF::FLC_roll(float Phi, float dPhi, float iPhi)
+{
+ g_fisInput[0] = Phi;// Read Input: Phi
+ g_fisInput[1] = dPhi;// Read Input: dPhi
+ g_fisInput[2] = iPhi;// Read Input: iPhi
+ g_fisOutput[0] = 0;
+ fis_evaluate();
+
+ return g_fisOutput[0];
+}
+
+
+
+//***********************************************************************
+// Support functions for Fuzzy Inference System
+//***********************************************************************
+// Trapezoidal Member Function
+FIS_TYPE fis_trapmf(FIS_TYPE x, FIS_TYPE* p)
+{
+ FIS_TYPE a = p[0], b = p[1], c = p[2], d = p[3];
+ FIS_TYPE t1 = ((x <= c) ? 1 : ((d < x) ? 0 : ((c != d) ? ((d - x) / (d - c)) : 0)));
+ FIS_TYPE t2 = ((b <= x) ? 1 : ((x < a) ? 0 : ((a != b) ? ((x - a) / (b - a)) : 0)));
+ return (FIS_TYPE) min(t1, t2);
+}
+
+// Triangular Member Function
+FIS_TYPE fis_trimf(FIS_TYPE x, FIS_TYPE* p)
+{
+ FIS_TYPE a = p[0], b = p[1], c = p[2];
+ FIS_TYPE t1 = (x - a) / (b - a);
+ FIS_TYPE t2 = (c - x) / (c - b);
+ if ((a == b) && (b == c)) return (FIS_TYPE) (x == a);
+ if (a == b) return (FIS_TYPE) (t2*(b <= x)*(x <= c));
+ if (b == c) return (FIS_TYPE) (t1*(a <= x)*(x <= b));
+ t1 = min(t1, t2);
+ return (FIS_TYPE) max(t1, 0);
+}
+
+FIS_TYPE fis_min(FIS_TYPE a, FIS_TYPE b)
+{
+ return min(a, b);
+}
+
+FIS_TYPE fis_max(FIS_TYPE a, FIS_TYPE b)
+{
+ return max(a, b);
+}
+
+FIS_TYPE fis_array_operation(FIS_TYPE *array, int size, _FIS_ARR_OP pfnOp)
+{
+ int i;
+ FIS_TYPE ret = 0;
+
+ if (size == 0) return ret;
+ if (size == 1) return array[0];
+
+ ret = array[0];
+ for (i = 1; i < size; i++)
+ {
+ ret = (*pfnOp)(ret, array[i]);
+ }
+
+ return ret;
+}
+
+
+//***********************************************************************
+// Data for Fuzzy Inference System
+//***********************************************************************
+// Pointers to the implementations of member functions
+_FIS_MF fis_gMF[] =
+{
+ fis_trapmf, fis_trimf
+};
+
+// Count of member function for each Input
+int fis_gIMFCount[] = { 3, 3, 3 };
+
+// Count of member function for each Output
+int fis_gOMFCount[] = { 5 };
+
+// Coefficients for the Input Member Functions
+FIS_TYPE fis_gMFI0Coeff1[] = { -10, -10, -0.2, 0 };
+FIS_TYPE fis_gMFI0Coeff2[] = { -0.1, 0, 0.1 };
+FIS_TYPE fis_gMFI0Coeff3[] = { 0, 0.2, 10, 10 };
+FIS_TYPE* fis_gMFI0Coeff[] = { fis_gMFI0Coeff1, fis_gMFI0Coeff2, fis_gMFI0Coeff3 };
+FIS_TYPE fis_gMFI1Coeff1[] = { -20, -20, -1, -0.25 };
+FIS_TYPE fis_gMFI1Coeff2[] = { -1, 0, 1 };
+FIS_TYPE fis_gMFI1Coeff3[] = { 0.25, 1, 20, 20 };
+FIS_TYPE* fis_gMFI1Coeff[] = { fis_gMFI1Coeff1, fis_gMFI1Coeff2, fis_gMFI1Coeff3 };
+FIS_TYPE fis_gMFI2Coeff1[] = { -20, -20, -0.8, -0.25 };
+FIS_TYPE fis_gMFI2Coeff2[] = { -0.6, 0, 0.6 };
+FIS_TYPE fis_gMFI2Coeff3[] = { 0, 1, 20, 20 };
+FIS_TYPE* fis_gMFI2Coeff[] = { fis_gMFI2Coeff1, fis_gMFI2Coeff2, fis_gMFI2Coeff3 };
+FIS_TYPE** fis_gMFICoeff[] = { fis_gMFI0Coeff, fis_gMFI1Coeff, fis_gMFI2Coeff };
+
+// Coefficients for the Input Member Functions
+FIS_TYPE fis_gMFO0Coeff1[] = { -0.1, -0.1, -0.05, -0.045 };
+FIS_TYPE fis_gMFO0Coeff2[] = { -0.05, -0.045, -0.01, -0.003 };
+FIS_TYPE fis_gMFO0Coeff3[] = { -0.01, 0, 0.01 };
+FIS_TYPE fis_gMFO0Coeff4[] = { 0.003, 0.01, 0.045, 0.05 };
+FIS_TYPE fis_gMFO0Coeff5[] = { 0.0455, 0.05, 0.1, 0.1 };
+FIS_TYPE* fis_gMFO0Coeff[] = { fis_gMFO0Coeff1, fis_gMFO0Coeff2, fis_gMFO0Coeff3, fis_gMFO0Coeff4, fis_gMFO0Coeff5 };
+FIS_TYPE** fis_gMFOCoeff[] = { fis_gMFO0Coeff };
+
+// Input membership function set
+int fis_gMFI0[] = { 0, 1, 0 };
+int fis_gMFI1[] = { 0, 1, 0 };
+int fis_gMFI2[] = { 0, 1, 0 };
+int* fis_gMFI[] = { fis_gMFI0, fis_gMFI1, fis_gMFI2};
+
+// Output membership function set
+int fis_gMFO0[] = { 0, 0, 1, 0, 0 };
+int* fis_gMFO[] = { fis_gMFO0};
+
+// Rule Weights
+FIS_TYPE fis_gRWeight[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+
+// Rule Type
+int fis_gRType[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+
+// Rule Inputs
+int fis_gRI0[] = { 1, 1, 1 };
+int fis_gRI1[] = { 2, 1, 1 };
+int fis_gRI2[] = { 3, 1, 1 };
+int fis_gRI3[] = { 1, 1, 2 };
+int fis_gRI4[] = { 2, 1, 2 };
+int fis_gRI5[] = { 3, 1, 2 };
+int fis_gRI6[] = { 1, 1, 3 };
+int fis_gRI7[] = { 2, 1, 3 };
+int fis_gRI8[] = { 3, 1, 3 };
+int fis_gRI9[] = { 1, 2, 1 };
+int fis_gRI10[] = { 2, 2, 1 };
+int fis_gRI11[] = { 3, 2, 1 };
+int fis_gRI12[] = { 1, 2, 2 };
+int fis_gRI13[] = { 2, 2, 2 };
+int fis_gRI14[] = { 3, 2, 2 };
+int fis_gRI15[] = { 1, 2, 3 };
+int fis_gRI16[] = { 2, 2, 3 };
+int fis_gRI17[] = { 3, 2, 3 };
+int fis_gRI18[] = { 1, 3, 1 };
+int fis_gRI19[] = { 2, 3, 1 };
+int fis_gRI20[] = { 3, 3, 1 };
+int fis_gRI21[] = { 1, 3, 2 };
+int fis_gRI22[] = { 2, 3, 2 };
+int fis_gRI23[] = { 3, 3, 2 };
+int fis_gRI24[] = { 1, 3, 3 };
+int fis_gRI25[] = { 2, 3, 3 };
+int fis_gRI26[] = { 3, 3, 3 };
+int* fis_gRI[] = { fis_gRI0, fis_gRI1, fis_gRI2, fis_gRI3, fis_gRI4, fis_gRI5, fis_gRI6, fis_gRI7, fis_gRI8, fis_gRI9, fis_gRI10, fis_gRI11, fis_gRI12, fis_gRI13, fis_gRI14, fis_gRI15, fis_gRI16, fis_gRI17, fis_gRI18, fis_gRI19, fis_gRI20, fis_gRI21, fis_gRI22, fis_gRI23, fis_gRI24, fis_gRI25, fis_gRI26 };
+
+// Rule Outputs
+int fis_gRO0[] = { 5 };
+int fis_gRO1[] = { 4 };
+int fis_gRO2[] = { 2 };
+int fis_gRO3[] = { 5 };
+int fis_gRO4[] = { 4 };
+int fis_gRO5[] = { 2 };
+int fis_gRO6[] = { 5 };
+int fis_gRO7[] = { 4 };
+int fis_gRO8[] = { 2 };
+int fis_gRO9[] = { 4 };
+int fis_gRO10[] = { 4 };
+int fis_gRO11[] = { 2 };
+int fis_gRO12[] = { 4 };
+int fis_gRO13[] = { 3 };
+int fis_gRO14[] = { 2 };
+int fis_gRO15[] = { 4 };
+int fis_gRO16[] = { 2 };
+int fis_gRO17[] = { 2 };
+int fis_gRO18[] = { 4 };
+int fis_gRO19[] = { 2 };
+int fis_gRO20[] = { 1 };
+int fis_gRO21[] = { 4 };
+int fis_gRO22[] = { 2 };
+int fis_gRO23[] = { 1 };
+int fis_gRO24[] = { 4 };
+int fis_gRO25[] = { 2 };
+int fis_gRO26[] = { 1 };
+int* fis_gRO[] = { fis_gRO0, fis_gRO1, fis_gRO2, fis_gRO3, fis_gRO4, fis_gRO5, fis_gRO6, fis_gRO7, fis_gRO8, fis_gRO9, fis_gRO10, fis_gRO11, fis_gRO12, fis_gRO13, fis_gRO14, fis_gRO15, fis_gRO16, fis_gRO17, fis_gRO18, fis_gRO19, fis_gRO20, fis_gRO21, fis_gRO22, fis_gRO23, fis_gRO24, fis_gRO25, fis_gRO26 };
+
+// Input range Min
+FIS_TYPE fis_gIMin[] = { -10, -20, -20 };
+
+// Input range Max
+FIS_TYPE fis_gIMax[] = { 10, 20, 20 };
+
+// Output range Min
+FIS_TYPE fis_gOMin[] = { -0.1 };
+
+// Output range Max
+FIS_TYPE fis_gOMax[] = { 0.1 };
+
+//***********************************************************************
+// Data dependent support functions for Fuzzy Inference System
+//***********************************************************************
+FIS_TYPE fis_MF_out(FIS_TYPE** fuzzyRuleSet, FIS_TYPE x, int o)
+{
+ FIS_TYPE mfOut;
+ int r;
+
+ for (r = 0; r < fis_gcR; ++r)
+ {
+ int index = fis_gRO[r][o];
+ if (index > 0)
+ {
+ index = index - 1;
+ mfOut = (fis_gMF[fis_gMFO[o][index]])(x, fis_gMFOCoeff[o][index]);
+ }
+ else if (index < 0)
+ {
+ index = -index - 1;
+ mfOut = 1 - (fis_gMF[fis_gMFO[o][index]])(x, fis_gMFOCoeff[o][index]);
+ }
+ else
+ {
+ mfOut = 0;
+ }
+
+ fuzzyRuleSet[0][r] = fis_min(mfOut, fuzzyRuleSet[1][r]);
+ }
+ return fis_array_operation(fuzzyRuleSet[0], fis_gcR, fis_max);
+}
+
+FIS_TYPE fis_defuzz_centroid(FIS_TYPE** fuzzyRuleSet, int o)
+{
+ FIS_TYPE step = (fis_gOMax[o] - fis_gOMin[o]) / (FIS_RESOLUSION - 1);
+ FIS_TYPE area = 0;
+ FIS_TYPE momentum = 0;
+ FIS_TYPE dist, slice;
+ int i;
+
+ // calculate the area under the curve formed by the MF outputs
+ for (i = 0; i < FIS_RESOLUSION; ++i){
+ dist = fis_gOMin[o] + (step * i);
+ slice = step * fis_MF_out(fuzzyRuleSet, dist, o);
+ area += slice;
+ momentum += slice*dist;
+ }
+
+ return ((area == 0) ? ((fis_gOMax[o] + fis_gOMin[o]) / 2) : (momentum / area));
+}
+
+//***********************************************************************
+// Fuzzy Inference System
+//***********************************************************************
+void CID10DOF::fis_evaluate()
+{
+ FIS_TYPE fuzzyInput0[] = { 0, 0, 0 };
+ FIS_TYPE fuzzyInput1[] = { 0, 0, 0 };
+ FIS_TYPE fuzzyInput2[] = { 0, 0, 0 };
+ FIS_TYPE* fuzzyInput[fis_gcI] = { fuzzyInput0, fuzzyInput1, fuzzyInput2, };
+ FIS_TYPE fuzzyOutput0[] = { 0, 0, 0, 0, 0 };
+ FIS_TYPE* fuzzyOutput[fis_gcO] = { fuzzyOutput0, };
+ FIS_TYPE fuzzyRules[fis_gcR] = { 0 };
+ FIS_TYPE fuzzyFires[fis_gcR] = { 0 };
+ FIS_TYPE* fuzzyRuleSet[] = { fuzzyRules, fuzzyFires };
+ FIS_TYPE sW = 0;
+
+ // Transforming input to fuzzy Input
+ int i, j, r, o;
+ for (i = 0; i < fis_gcI; ++i)
+ {
+ for (j = 0; j < fis_gIMFCount[i]; ++j)
+ {
+ fuzzyInput[i][j] =
+ (fis_gMF[fis_gMFI[i][j]])(g_fisInput[i], fis_gMFICoeff[i][j]);
+ }
+ }
+
+ int index = 0;
+ for (r = 0; r < fis_gcR; ++r)
+ {
+ if (fis_gRType[r] == 1)
+ {
+ fuzzyFires[r] = FIS_MAX;
+ for (i = 0; i < fis_gcI; ++i)
+ {
+ index = fis_gRI[r][i];
+ if (index > 0)
+ fuzzyFires[r] = fis_min(fuzzyFires[r], fuzzyInput[i][index - 1]);
+ else if (index < 0)
+ fuzzyFires[r] = fis_min(fuzzyFires[r], 1 - fuzzyInput[i][-index - 1]);
+ else
+ fuzzyFires[r] = fis_min(fuzzyFires[r], 1);
+ }
+ }
+ else
+ {
+ fuzzyFires[r] = FIS_MIN;
+ for (i = 0; i < fis_gcI; ++i)
+ {
+ index = fis_gRI[r][i];
+ if (index > 0)
+ fuzzyFires[r] = fis_max(fuzzyFires[r], fuzzyInput[i][index - 1]);
+ else if (index < 0)
+ fuzzyFires[r] = fis_max(fuzzyFires[r], 1 - fuzzyInput[i][-index - 1]);
+ else
+ fuzzyFires[r] = fis_max(fuzzyFires[r], 0);
+ }
+ }
+
+ fuzzyFires[r] = fis_gRWeight[r] * fuzzyFires[r];
+ sW += fuzzyFires[r];
+ }
+
+ if (sW == 0)
+ {
+ for (o = 0; o < fis_gcO; ++o)
+ {
+ g_fisOutput[o] = ((fis_gOMax[o] + fis_gOMin[o]) / 2);
+ }
+ }
+ else
+ {
+ for (o = 0; o < fis_gcO; ++o)
+ {
+ g_fisOutput[o] = fis_defuzz_centroid(fuzzyRuleSet, o);
+ }
+ }
+}
+
+
+
+
+
+const float def_sea_press = 1013.25;
+
+
+
+float CID10DOF::getBaroTem()
+{
+
+}
+
+float CID10DOF::getBaroPress()
+{
+
+}
+
+float CID10DOF::getBaroAlt()
+{
+
+}
+
+
+float invSqrt(float number)
+{
+ volatile long i;
+ volatile float x, y;
+ volatile const float f = 1.5F;
+
+ x = number * 0.5F;
+ y = number;
+ i = * ( long * ) &y;
+ i = 0x5f375a86 - ( i >> 1 );
+ y = * ( float * ) &i;
+ y = y * ( f - ( x * y * y ) );
+ return y;
+}
+
+double CID10DOF::map(double x, double in_min, double in_max, double out_min, double out_max){ //simply maps values in the given range
+ return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
+}
+
+
+
+
+
diff -r 000000000000 -r 89cf0851969b CID10DOF/CID10DOF.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/CID10DOF/CID10DOF.h Tue Jun 26 18:24:45 2018 +0000
@@ -0,0 +1,187 @@
+/*
+FreeIMU.h - A libre and easy to use orientation sensing library for Arduino
+Copyright (C) 2011 Fabio Varesano <fabio at varesano dot net>
+
+Development of this code has been supported by the Department of Computer Science,
+Universita' degli Studi di Torino, Italy within the Piemonte Project
+http://www.piemonte.di.unito.it/
+
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the version 3 GNU General Public License as
+published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef CID10DOF_h
+#define CID10DOF_h
+
+// Uncomment the appropriated version of FreeIMU you are using
+//#define FREEIMU_v01
+//#define FREEIMU_v02
+//#define FREEIMU_v03
+//#define FREEIMU_v035
+//#define FREEIMU_v035_MS
+//#define FREEIMU_v035_BMP
+#define FREEIMU_v04
+
+
+
+#define FREEIMU_LIB_VERSION "20121122"
+
+#define FREEIMU_DEVELOPER "Fabio Varesano - varesano.net"
+
+#if F_CPU == 16000000L
+ #define FREEIMU_FREQ "16 MHz"
+#elif F_CPU == 8000000L
+ #define FREEIMU_FREQ "8 MHz"
+#endif
+
+
+// board IDs
+
+
+#define FREEIMU_ID "Zboub"
+
+#define IS_6DOM() (defined(SEN_10121) || defined(GEN_MPU6050))
+#define IS_9DOM()
+#define HAS_AXIS_ALIGNED() (defined(FREEIMU_v01) || defined(FREEIMU_v02) || defined(FREEIMU_v03) || defined(FREEIMU_v035) || defined(FREEIMU_v035_MS) || defined(FREEIMU_v035_BMP) || defined(FREEIMU_v04) || defined(SEN_10121) || defined(SEN_10736))
+
+
+
+
+#include "mbed.h"
+
+//#include "calibration.h"
+/*
+#ifndef CALIBRATION_H
+#include <EEPROM.h>
+#endif
+#define FREEIMU_EEPROM_BASE 0x0A
+#define FREEIMU_EEPROM_SIGNATURE 0x19
+*/
+
+//include des biblis des senseurs
+
+#include "MPU9250.h"
+#include "Matrix.h"
+#include "Servo.h"
+#include "PIDcontroller.h"
+
+//ESC calibration values
+#define MAX_TRHUST 1.0
+#define MIN_TRHUST 0.45
+
+#define IN_MIN_ROLL -30.0
+#define IN_MAX_ROLL 30.0
+#define OUT_MIN_ROLL -0.1
+#define OUT_MAX_ROLL 1.0
+
+#define IN_MIN_PITCH -30.0
+#define IN_MAX_PITCH 30.0
+#define OUT_MIN_PITCH -0.1
+#define OUT_MAX_PITCH 0.1
+
+#define kp 0.69 //0.82
+#define ki 0.0 //0.01
+#define kd 0.130//0.17245
+#define Td 0.01
+
+#define FIS_TYPE float
+#define FIS_RESOLUSION 101
+#define FIS_MIN -3.4028235E+38
+#define FIS_MAX 3.4028235E+38
+
+typedef FIS_TYPE(*_FIS_MF)(FIS_TYPE, FIS_TYPE*);
+typedef FIS_TYPE(*_FIS_ARR_OP)(FIS_TYPE, FIS_TYPE);
+typedef FIS_TYPE(*_FIS_ARR)(FIS_TYPE*, int, _FIS_ARR_OP);
+
+
+
+class CID10DOF
+{
+ public:
+ CID10DOF(PinName sda, PinName scl,PinName FL, PinName FR, PinName BL, PinName BR);
+ //I2C i2c_;
+
+ //void init();
+ //void init(int accgyro_addr, bool fastmode);
+ void MPU9250init();
+ void MatrixConfig();
+ #ifndef CALIBRATION_H
+ void calLoad();
+ #endif
+ void getRawValues(int * raw_values);
+ void MPU9250GetValues();
+ void MPU9250getYawPitchRoll();
+ void MPU9250ReadAxis(double * dat);
+
+ void Calibrate_Motors();
+ void stabilise(double *speed, double *actSpeed, double *Diff);
+ void setLimits(double min, double max);
+ void run (double *speed);
+ void fis_evaluate();
+
+ //PID
+ void PID_Config(double *St_point, double *bias);
+ void PID_Run(double *processVariable, double *setPoint, double *pid_diff);
+
+ float FLC_roll(float Phi, float iPhi, float dPhi);
+ //float FLC_Roll( float setpoint, float roll_ang, float Ts, float gain);
+
+ //Sensor de presión y temperatura
+ float getBaroTem();
+ float getBaroPress();
+ float getBaroAlt();
+
+ double map(double x, double in_min, double in_max, double out_min, double out_max);
+
+ // we make them public so that users can interact directly with device classes
+
+ MPU9250 mpu9250;
+ Serial pc;
+ Serial telem;
+
+ double inMin_, inMax_, inSpan_;
+ double outMin_, outMax_, outSpan_;
+
+ int16_t accelCount[3];
+ int16_t gyroCount[3];
+ int16_t magCount[3];
+ uint32_t sumCount;
+ int16_t tempCount;
+ float edv, e_ant, P, I, D, PID_fuzz;
+ float temperature, sum;
+ double value, outputs[3];
+ float yawmag,l;
+ double last_e;
+ float e;
+ char inData[50],byteIn;
+
+ Servo* motor[4];
+
+ private:
+ Timer t;
+ int dt_us;
+
+ float min_calibrate; //min value at which each motor is calibrated
+ float max_calibrate; //max value ...
+
+};
+ const int fis_gcI = 3;
+ // Number of outputs to the fuzzy inference system
+ const int fis_gcO = 1;
+ // Number of rules to the fuzzy inference system
+ const int fis_gcR = 27;
+
+ float invSqrt(float number);
+ void arr3_rad_to_deg(float * arr);
+#endif // FreeIMU_h
\ No newline at end of file
diff -r 000000000000 -r 89cf0851969b CID10DOF/helper_3dmath.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/CID10DOF/helper_3dmath.h Tue Jun 26 18:24:45 2018 +0000
@@ -0,0 +1,216 @@
+// I2C device class (I2Cdev) demonstration Arduino sketch for MPU6050 class, 3D math helper
+// 6/5/2012 by Jeff Rowberg <jeff@rowberg.net>
+// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
+//
+// Changelog:
+// 2012-06-05 - add 3D math helper file to DMP6 example sketch
+
+/* ============================================
+I2Cdev device library code is placed under the MIT license
+Copyright (c) 2012 Jeff Rowberg
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+===============================================
+*/
+
+#ifndef _HELPER_3DMATH_H_
+#define _HELPER_3DMATH_H_
+
+class Quaternion {
+ public:
+ float w;
+ float x;
+ float y;
+ float z;
+
+ Quaternion() {
+ w = 1.0f;
+ x = 0.0f;
+ y = 0.0f;
+ z = 0.0f;
+ }
+
+ Quaternion(float nw, float nx, float ny, float nz) {
+ w = nw;
+ x = nx;
+ y = ny;
+ z = nz;
+ }
+
+ Quaternion getProduct(Quaternion q) {
+ // Quaternion multiplication is defined by:
+ // (Q1 * Q2).w = (w1w2 - x1x2 - y1y2 - z1z2)
+ // (Q1 * Q2).x = (w1x2 + x1w2 + y1z2 - z1y2)
+ // (Q1 * Q2).y = (w1y2 - x1z2 + y1w2 + z1x2)
+ // (Q1 * Q2).z = (w1z2 + x1y2 - y1x2 + z1w2
+ return Quaternion(
+ w*q.w - x*q.x - y*q.y - z*q.z, // new w
+ w*q.x + x*q.w + y*q.z - z*q.y, // new x
+ w*q.y - x*q.z + y*q.w + z*q.x, // new y
+ w*q.z + x*q.y - y*q.x + z*q.w); // new z
+ }
+
+ Quaternion getConjugate() {
+ return Quaternion(w, -x, -y, -z);
+ }
+
+ float getMagnitude() {
+ return sqrt(w*w + x*x + y*y + z*z);
+ }
+
+ void normalize() {
+ float m = getMagnitude();
+ w /= m;
+ x /= m;
+ y /= m;
+ z /= m;
+ }
+
+ Quaternion getNormalized() {
+ Quaternion r(w, x, y, z);
+ r.normalize();
+ return r;
+ }
+};
+
+class VectorInt16 {
+ public:
+ int16_t x;
+ int16_t y;
+ int16_t z;
+
+ VectorInt16() {
+ x = 0;
+ y = 0;
+ z = 0;
+ }
+
+ VectorInt16(int16_t nx, int16_t ny, int16_t nz) {
+ x = nx;
+ y = ny;
+ z = nz;
+ }
+
+ float getMagnitude() {
+ return sqrt((float)(x*x + y*y + z*z));
+ }
+
+ void normalize() {
+ float m = getMagnitude();
+ x /= m;
+ y /= m;
+ z /= m;
+ }
+
+ VectorInt16 getNormalized() {
+ VectorInt16 r(x, y, z);
+ r.normalize();
+ return r;
+ }
+
+ void rotate(Quaternion *q) {
+ // http://www.cprogramming.com/tutorial/3d/quaternions.html
+ // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/transforms/index.htm
+ // http://content.gpwiki.org/index.php/OpenGL:Tutorials:Using_Quaternions_to_represent_rotation
+ // ^ or: http://webcache.googleusercontent.com/search?q=cache:xgJAp3bDNhQJ:content.gpwiki.org/index.php/OpenGL:Tutorials:Using_Quaternions_to_represent_rotation&hl=en&gl=us&strip=1
+
+ // P_out = q * P_in * conj(q)
+ // - P_out is the output vector
+ // - q is the orientation quaternion
+ // - P_in is the input vector (a*aReal)
+ // - conj(q) is the conjugate of the orientation quaternion (q=[w,x,y,z], q*=[w,-x,-y,-z])
+ Quaternion p(0, x, y, z);
+
+ // quaternion multiplication: q * p, stored back in p
+ p = q -> getProduct(p);
+
+ // quaternion multiplication: p * conj(q), stored back in p
+ p = p.getProduct(q -> getConjugate());
+
+ // p quaternion is now [0, x', y', z']
+ x = p.x;
+ y = p.y;
+ z = p.z;
+ }
+
+ VectorInt16 getRotated(Quaternion *q) {
+ VectorInt16 r(x, y, z);
+ r.rotate(q);
+ return r;
+ }
+};
+
+class VectorFloat {
+ public:
+ float x;
+ float y;
+ float z;
+
+ VectorFloat() {
+ x = 0;
+ y = 0;
+ z = 0;
+ }
+
+ VectorFloat(float nx, float ny, float nz) {
+ x = nx;
+ y = ny;
+ z = nz;
+ }
+
+ float getMagnitude() {
+ return sqrt(x*x + y*y + z*z);
+ }
+
+ void normalize() {
+ float m = getMagnitude();
+ x /= m;
+ y /= m;
+ z /= m;
+ }
+
+ VectorFloat getNormalized() {
+ VectorFloat r(x, y, z);
+ r.normalize();
+ return r;
+ }
+
+ void rotate(Quaternion *q) {
+ Quaternion p(0, x, y, z);
+
+ // quaternion multiplication: q * p, stored back in p
+ p = q -> getProduct(p);
+
+ // quaternion multiplication: p * conj(q), stored back in p
+ p = p.getProduct(q -> getConjugate());
+
+ // p quaternion is now [0, x', y', z']
+ x = p.x;
+ y = p.y;
+ z = p.z;
+ }
+
+ VectorFloat getRotated(Quaternion *q) {
+ VectorFloat r(x, y, z);
+ r.rotate(q);
+ return r;
+ }
+};
+
+#endif /* _HELPER_3DMATH_H_ */
diff -r 000000000000 -r 89cf0851969b CID10DOF/vector_math.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/CID10DOF/vector_math.h Tue Jun 26 18:24:45 2018 +0000
@@ -0,0 +1,1116 @@
+/*
+Copyright (c) 2007, Markus Trenkwalder
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* Neither the name of the library's copyright owner nor the names of its
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VECTOR_MATH_H
+#define VECTOR_MATH_H
+
+//#include <cmath>
+
+// "minor" can be defined from GCC and can cause problems
+#undef minor
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+namespace vmath {
+
+//using std::sin;
+//using std::cos;
+//using std::acos;
+//using std::sqrt;
+
+template <typename T>
+inline T rsqrt(T x)
+{
+ return T(1) / sqrt(x);
+}
+
+template <typename T>
+inline T inv(T x)
+{
+ return T(1) / x;
+}
+
+namespace detail {
+ // This function is used heavily in this library. Here is a generic
+ // implementation for it. If you can provide a faster one for your specific
+ // types this can speed up things considerably.
+ template <typename T>
+ inline T multiply_accumulate(int count, const T *a, const T *b)
+ {
+ T result = T(0);
+ for (int i = 0; i < count; ++i)
+ result += a[i] * b[i];
+ return result;
+ }
+}
+
+#define MOP_M_CLASS_TEMPLATE(CLASS, OP, COUNT) \
+ CLASS & operator OP (const CLASS& rhs) \
+ { \
+ for (int i = 0; i < (COUNT); ++i ) \
+ (*this)[i] OP rhs[i]; \
+ return *this; \
+ }
+
+#define MOP_M_TYPE_TEMPLATE(CLASS, OP, COUNT) \
+ CLASS & operator OP (const T & rhs) \
+ { \
+ for (int i = 0; i < (COUNT); ++i ) \
+ (*this)[i] OP rhs; \
+ return *this; \
+ }
+
+#define MOP_COMP_TEMPLATE(CLASS, COUNT) \
+ bool operator == (const CLASS & rhs) \
+ { \
+ bool result = true; \
+ for (int i = 0; i < (COUNT); ++i) \
+ result = result && (*this)[i] == rhs[i]; \
+ return result; \
+ } \
+ bool operator != (const CLASS & rhs) \
+ { return !((*this) == rhs); }
+
+#define MOP_G_UMINUS_TEMPLATE(CLASS, COUNT) \
+ CLASS operator - () const \
+ { \
+ CLASS result; \
+ for (int i = 0; i < (COUNT); ++i) \
+ result[i] = -(*this)[i]; \
+ return result; \
+ }
+
+#define COMMON_OPERATORS(CLASS, COUNT) \
+ MOP_M_CLASS_TEMPLATE(CLASS, +=, COUNT) \
+ MOP_M_CLASS_TEMPLATE(CLASS, -=, COUNT) \
+ /*no *= as this is not the same for vectors and matrices */ \
+ MOP_M_CLASS_TEMPLATE(CLASS, /=, COUNT) \
+ MOP_M_TYPE_TEMPLATE(CLASS, +=, COUNT) \
+ MOP_M_TYPE_TEMPLATE(CLASS, -=, COUNT) \
+ MOP_M_TYPE_TEMPLATE(CLASS, *=, COUNT) \
+ MOP_M_TYPE_TEMPLATE(CLASS, /=, COUNT) \
+ MOP_G_UMINUS_TEMPLATE(CLASS, COUNT) \
+ MOP_COMP_TEMPLATE(CLASS, COUNT)
+
+#define VECTOR_COMMON(CLASS, COUNT) \
+ COMMON_OPERATORS(CLASS, COUNT) \
+ MOP_M_CLASS_TEMPLATE(CLASS, *=, COUNT) \
+ operator const T* () const { return &x; } \
+ operator T* () { return &x; }
+
+#define FOP_G_SOURCE_TEMPLATE(OP, CLASS) \
+ { CLASS<T> r = lhs; r OP##= rhs; return r; }
+
+#define FOP_G_CLASS_TEMPLATE(OP, CLASS) \
+ template <typename T> \
+ inline CLASS<T> operator OP (const CLASS<T> &lhs, const CLASS<T> &rhs) \
+ FOP_G_SOURCE_TEMPLATE(OP, CLASS)
+
+#define FOP_G_TYPE_TEMPLATE(OP, CLASS) \
+ template <typename T> \
+ inline CLASS<T> operator OP (const CLASS<T> &lhs, const T &rhs) \
+ FOP_G_SOURCE_TEMPLATE(OP, CLASS)
+
+// forward declarations
+template <typename T> struct vec2;
+template <typename T> struct vec3;
+template <typename T> struct vec4;
+template <typename T> struct mat2;
+template <typename T> struct mat3;
+template <typename T> struct mat4;
+template <typename T> struct quat;
+
+#define FREE_MODIFYING_OPERATORS(CLASS) \
+ FOP_G_CLASS_TEMPLATE(+, CLASS) \
+ FOP_G_CLASS_TEMPLATE(-, CLASS) \
+ FOP_G_CLASS_TEMPLATE(*, CLASS) \
+ FOP_G_CLASS_TEMPLATE(/, CLASS) \
+ FOP_G_TYPE_TEMPLATE(+, CLASS) \
+ FOP_G_TYPE_TEMPLATE(-, CLASS) \
+ FOP_G_TYPE_TEMPLATE(*, CLASS) \
+ FOP_G_TYPE_TEMPLATE(/, CLASS)
+
+FREE_MODIFYING_OPERATORS(vec2)
+FREE_MODIFYING_OPERATORS(vec3)
+FREE_MODIFYING_OPERATORS(vec4)
+FREE_MODIFYING_OPERATORS(mat2)
+FREE_MODIFYING_OPERATORS(mat3)
+FREE_MODIFYING_OPERATORS(mat4)
+FREE_MODIFYING_OPERATORS(quat)
+
+#define FREE_OPERATORS(CLASS) \
+ template <typename T> \
+ inline CLASS<T> operator + (const T& a, const CLASS<T>& b) \
+ { CLASS<T> r = b; r += a; return r; } \
+ \
+ template <typename T> \
+ inline CLASS<T> operator * (const T& a, const CLASS<T>& b) \
+ { CLASS<T> r = b; r *= a; return r; } \
+ \
+ template <typename T> \
+ inline CLASS<T> operator - (const T& a, const CLASS<T>& b) \
+ { return -b + a; } \
+ \
+ template <typename T> \
+ inline CLASS<T> operator / (const T& a, const CLASS<T>& b) \
+ { CLASS<T> r(a); r /= b; return r; }
+
+FREE_OPERATORS(vec2)
+FREE_OPERATORS(vec3)
+FREE_OPERATORS(vec4)
+FREE_OPERATORS(mat2)
+FREE_OPERATORS(mat3)
+FREE_OPERATORS(mat4)
+FREE_OPERATORS(quat)
+
+template <typename T>
+struct vec2 {
+ T x, y;
+
+ vec2() {};
+ explicit vec2(const T i) : x(i), y(i) {}
+ explicit vec2(const T ix, const T iy) : x(ix), y(iy) {}
+ explicit vec2(const vec3<T>& v);
+ explicit vec2(const vec4<T>& v);
+
+ VECTOR_COMMON(vec2, 2)
+};
+
+template <typename T>
+struct vec3 {
+ T x, y, z;
+
+ vec3() {};
+ explicit vec3(const T i) : x(i), y(i), z(i) {}
+ explicit vec3(const T ix, const T iy, const T iz) : x(ix), y(iy), z(iz) {}
+ explicit vec3(const vec2<T>& xy, const T iz) : x(xy.x), y(xy.y), z(iz) {}
+ explicit vec3(const T ix, const vec2<T>& yz) : x(ix), y(yz.y), z(yz.z) {}
+ explicit vec3(const vec4<T>& v);
+
+ VECTOR_COMMON(vec3, 3)
+};
+
+template <typename T>
+struct vec4 {
+ T x, y, z, w;
+
+ vec4() {};
+ explicit vec4(const T i) : x(i), y(i), z(i), w(i) {}
+ explicit vec4(const T ix, const T iy, const T iz, const T iw) : x(ix), y(iy), z(iz), w(iw) {}
+ explicit vec4(const vec3<T>& xyz,const T iw) : x(xyz.x), y(xyz.y), z(xyz.z), w(iw) {}
+ explicit vec4(const T ix, const vec3<T>& yzw) : x(ix), y(yzw.x), z(yzw.y), w(yzw.z) {}
+ explicit vec4(const vec2<T>& xy, const vec2<T>& zw) : x(xy.x), y(xy.y), z(zw.x), w(zw.y) {}
+
+ VECTOR_COMMON(vec4, 4)
+};
+
+// additional constructors that omit the last element
+template <typename T> inline vec2<T>::vec2(const vec3<T>& v) : x(v.x), y(v.y) {}
+template <typename T> inline vec2<T>::vec2(const vec4<T>& v) : x(v.x), y(v.y) {}
+template <typename T> inline vec3<T>::vec3(const vec4<T>& v) : x(v.x), y(v.y), z(v.z) {}
+
+#define VEC_QUAT_FUNC_TEMPLATE(CLASS, COUNT) \
+ template <typename T> \
+ inline T dot(const CLASS & u, const CLASS & v) \
+ { \
+ const T *a = u; \
+ const T *b = v; \
+ using namespace detail; \
+ return multiply_accumulate(COUNT, a, b); \
+ } \
+ template <typename T> \
+ inline T length(const CLASS & v) \
+ { \
+ return sqrt(dot(v, v)); \
+ } \
+ template <typename T> inline CLASS normalize(const CLASS & v) \
+ { \
+ return v * rsqrt(dot(v, v)); \
+ } \
+ template <typename T> inline CLASS lerp(const CLASS & u, const CLASS & v, const T x) \
+ { \
+ return u * (T(1) - x) + v * x; \
+ }
+
+VEC_QUAT_FUNC_TEMPLATE(vec2<T>, 2)
+VEC_QUAT_FUNC_TEMPLATE(vec3<T>, 3)
+VEC_QUAT_FUNC_TEMPLATE(vec4<T>, 4)
+VEC_QUAT_FUNC_TEMPLATE(quat<T>, 4)
+
+#define VEC_FUNC_TEMPLATE(CLASS) \
+ template <typename T> inline CLASS reflect(const CLASS & I, const CLASS & N) \
+ { \
+ return I - T(2) * dot(N, I) * N; \
+ } \
+ template <typename T> inline CLASS refract(const CLASS & I, const CLASS & N, T eta) \
+ { \
+ const T d = dot(N, I); \
+ const T k = T(1) - eta * eta * (T(1) - d * d); \
+ if ( k < T(0) ) \
+ return CLASS(T(0)); \
+ else \
+ return eta * I - (eta * d + static_cast<T>(sqrt(k))) * N; \
+ }
+
+VEC_FUNC_TEMPLATE(vec2<T>)
+VEC_FUNC_TEMPLATE(vec3<T>)
+VEC_FUNC_TEMPLATE(vec4<T>)
+
+template <typename T> inline T lerp(const T & u, const T & v, const T x)
+{
+ return dot(vec2<T>(u, v), vec2<T>((T(1) - x), x));
+}
+
+template <typename T> inline vec3<T> cross(const vec3<T>& u, const vec3<T>& v)
+{
+ return vec3<T>(
+ dot(vec2<T>(u.y, -v.y), vec2<T>(v.z, u.z)),
+ dot(vec2<T>(u.z, -v.z), vec2<T>(v.x, u.x)),
+ dot(vec2<T>(u.x, -v.x), vec2<T>(v.y, u.y)));
+}
+
+
+#define MATRIX_COL4(SRC, C) \
+ vec4<T>(SRC.elem[0][C], SRC.elem[1][C], SRC.elem[2][C], SRC.elem[3][C])
+
+#define MATRIX_ROW4(SRC, R) \
+ vec4<T>(SRC.elem[R][0], SRC.elem[R][1], SRC.elem[R][2], SRC.elem[R][3])
+
+#define MATRIX_COL3(SRC, C) \
+ vec3<T>(SRC.elem[0][C], SRC.elem[1][C], SRC.elem[2][C])
+
+#define MATRIX_ROW3(SRC, R) \
+ vec3<T>(SRC.elem[R][0], SRC.elem[R][1], SRC.elem[R][2])
+
+#define MATRIX_COL2(SRC, C) \
+ vec2<T>(SRC.elem[0][C], SRC.elem[1][C])
+
+#define MATRIX_ROW2(SRC, R) \
+ vec2<T>(SRC.elem[R][0], SRC.elem[R][1])
+
+#define MOP_M_MATRIX_MULTIPLY(CLASS, SIZE) \
+ CLASS & operator *= (const CLASS & rhs) \
+ { \
+ CLASS result; \
+ for (int r = 0; r < SIZE; ++r) \
+ for (int c = 0; c < SIZE; ++c) \
+ result.elem[r][c] = dot( \
+ MATRIX_ROW ## SIZE((*this), r), \
+ MATRIX_COL ## SIZE(rhs, c)); \
+ return (*this) = result; \
+ }
+
+#define MATRIX_CONSTRUCTOR_FROM_T(CLASS, SIZE) \
+ explicit CLASS(const T v) \
+ { \
+ for (int r = 0; r < SIZE; ++r) \
+ for (int c = 0; c < SIZE; ++c) \
+ if (r == c) elem[r][c] = v; \
+ else elem[r][c] = T(0); \
+ }
+
+#define MATRIX_CONSTRUCTOR_FROM_LOWER(CLASS1, CLASS2, SIZE1, SIZE2) \
+ explicit CLASS1(const CLASS2<T>& m) \
+ { \
+ for (int r = 0; r < SIZE1; ++r) \
+ for (int c = 0; c < SIZE1; ++c) \
+ if (r < SIZE2 && c < SIZE2) elem[r][c] = m.elem[r][c]; \
+ else elem[r][c] = r == c ? T(1) : T(0); \
+ }
+
+#define MATRIX_COMMON(CLASS, SIZE) \
+ COMMON_OPERATORS(CLASS, SIZE*SIZE) \
+ MOP_M_MATRIX_MULTIPLY(CLASS, SIZE) \
+ MATRIX_CONSTRUCTOR_FROM_T(CLASS, SIZE) \
+ operator const T* () const { return (const T*) elem; } \
+ operator T* () { return (T*) elem; }
+
+template <typename T> struct mat2;
+template <typename T> struct mat3;
+template <typename T> struct mat4;
+
+template <typename T>
+struct mat2 {
+ T elem[2][2];
+
+ mat2() {}
+
+ explicit mat2(
+ const T m00, const T m01,
+ const T m10, const T m11)
+ {
+ elem[0][0] = m00; elem[0][1] = m01;
+ elem[1][0] = m10; elem[1][1] = m11;
+ }
+
+ explicit mat2(const vec2<T>& v0, const vec2<T>& v1)
+ {
+ elem[0][0] = v0[0];
+ elem[1][0] = v0[1];
+ elem[0][1] = v1[0];
+ elem[1][1] = v1[1];
+ }
+
+ explicit mat2(const mat3<T>& m);
+
+ MATRIX_COMMON(mat2, 2)
+};
+
+template <typename T>
+struct mat3 {
+ T elem[3][3];
+
+ mat3() {}
+
+ explicit mat3(
+ const T m00, const T m01, const T m02,
+ const T m10, const T m11, const T m12,
+ const T m20, const T m21, const T m22)
+ {
+ elem[0][0] = m00; elem[0][1] = m01; elem[0][2] = m02;
+ elem[1][0] = m10; elem[1][1] = m11; elem[1][2] = m12;
+ elem[2][0] = m20; elem[2][1] = m21; elem[2][2] = m22;
+ }
+
+ explicit mat3(const vec3<T>& v0, const vec3<T>& v1, const vec3<T>& v2)
+ {
+ elem[0][0] = v0[0];
+ elem[1][0] = v0[1];
+ elem[2][0] = v0[2];
+ elem[0][1] = v1[0];
+ elem[1][1] = v1[1];
+ elem[2][1] = v1[2];
+ elem[0][2] = v2[0];
+ elem[1][2] = v2[1];
+ elem[2][2] = v2[2];
+ }
+
+ explicit mat3(const mat4<T>& m);
+
+ MATRIX_CONSTRUCTOR_FROM_LOWER(mat3, mat2, 3, 2)
+ MATRIX_COMMON(mat3, 3)
+};
+
+template <typename T>
+struct mat4 {
+ T elem[4][4];
+
+ mat4() {}
+
+ explicit mat4(
+ const T m00, const T m01, const T m02, const T m03,
+ const T m10, const T m11, const T m12, const T m13,
+ const T m20, const T m21, const T m22, const T m23,
+ const T m30, const T m31, const T m32, const T m33)
+ {
+ elem[0][0] = m00; elem[0][1] = m01; elem[0][2] = m02; elem[0][3] = m03;
+ elem[1][0] = m10; elem[1][1] = m11; elem[1][2] = m12; elem[1][3] = m13;
+ elem[2][0] = m20; elem[2][1] = m21; elem[2][2] = m22; elem[2][3] = m23;
+ elem[3][0] = m30; elem[3][1] = m31; elem[3][2] = m32; elem[3][3] = m33;
+ }
+
+ explicit mat4(const vec4<T>& v0, const vec4<T>& v1, const vec4<T>& v2, const vec4<T>& v3)
+ {
+ elem[0][0] = v0[0];
+ elem[1][0] = v0[1];
+ elem[2][0] = v0[2];
+ elem[3][0] = v0[3];
+ elem[0][1] = v1[0];
+ elem[1][1] = v1[1];
+ elem[2][1] = v1[2];
+ elem[3][1] = v1[3];
+ elem[0][2] = v2[0];
+ elem[1][2] = v2[1];
+ elem[2][2] = v2[2];
+ elem[3][2] = v2[3];
+ elem[0][3] = v3[0];
+ elem[1][3] = v3[1];
+ elem[2][3] = v3[2];
+ elem[3][3] = v3[3];
+ }
+
+ MATRIX_CONSTRUCTOR_FROM_LOWER(mat4, mat3, 4, 3)
+ MATRIX_COMMON(mat4, 4)
+};
+
+#define MATRIX_CONSTRUCTOR_FROM_HIGHER(CLASS1, CLASS2, SIZE) \
+ template <typename T> \
+ inline CLASS1<T>::CLASS1(const CLASS2<T>& m) \
+ { \
+ for (int r = 0; r < SIZE; ++r) \
+ for (int c = 0; c < SIZE; ++c) \
+ elem[r][c] = m.elem[r][c]; \
+ }
+
+MATRIX_CONSTRUCTOR_FROM_HIGHER(mat2, mat3, 2)
+MATRIX_CONSTRUCTOR_FROM_HIGHER(mat3, mat4, 3)
+
+#define MAT_FUNC_TEMPLATE(CLASS, SIZE) \
+ template <typename T> \
+ inline CLASS transpose(const CLASS & m) \
+ { \
+ CLASS result; \
+ for (int r = 0; r < SIZE; ++r) \
+ for (int c = 0; c < SIZE; ++c) \
+ result.elem[r][c] = m.elem[c][r]; \
+ return result; \
+ } \
+ template <typename T> \
+ inline CLASS identity ## SIZE() \
+ { \
+ CLASS result; \
+ for (int r = 0; r < SIZE; ++r) \
+ for (int c = 0; c < SIZE; ++c) \
+ result.elem[r][c] = r == c ? T(1) : T(0); \
+ return result; \
+ } \
+ template <typename T> \
+ inline T trace(const CLASS & m) \
+ { \
+ T result = T(0); \
+ for (int i = 0; i < SIZE; ++i) \
+ result += m.elem[i][i]; \
+ return result; \
+ }
+
+MAT_FUNC_TEMPLATE(mat2<T>, 2)
+MAT_FUNC_TEMPLATE(mat3<T>, 3)
+MAT_FUNC_TEMPLATE(mat4<T>, 4)
+
+#define MAT_FUNC_MINOR_TEMPLATE(CLASS1, CLASS2, SIZE) \
+ template <typename T> \
+ inline CLASS2 minor(const CLASS1 & m, int _r = SIZE, int _c = SIZE) { \
+ CLASS2 result; \
+ for (int r = 0; r < SIZE - 1; ++r) \
+ for (int c = 0; c < SIZE - 1; ++c) { \
+ int rs = r >= _r ? 1 : 0; \
+ int cs = c >= _c ? 1 : 0; \
+ result.elem[r][c] = m.elem[r + rs][c + cs]; \
+ } \
+ return result; \
+ }
+
+MAT_FUNC_MINOR_TEMPLATE(mat3<T>, mat2<T>, 3)
+MAT_FUNC_MINOR_TEMPLATE(mat4<T>, mat3<T>, 4)
+
+template <typename T>
+inline T det(const mat2<T>& m)
+{
+ return dot(
+ vec2<T>(m.elem[0][0], -m.elem[0][1]),
+ vec2<T>(m.elem[1][1], m.elem[1][0]));
+}
+
+template <typename T>
+inline T det(const mat3<T>& m)
+{
+ return dot(cross(MATRIX_COL3(m, 0), MATRIX_COL3(m, 1)), MATRIX_COL3(m, 2));
+}
+
+template <typename T>
+inline T det(const mat4<T>& m)
+{
+ vec4<T> b;
+ for (int i = 0; i < 4; ++i)
+ b[i] = (i & 1 ? -1 : 1) * det(minor(m, 0, i));
+ return dot(MATRIX_ROW4(m, 0), b);
+}
+
+#define MAT_ADJOINT_TEMPLATE(CLASS, SIZE) \
+ template <typename T> \
+ inline CLASS adjoint(const CLASS & m) \
+ { \
+ CLASS result; \
+ for (int r = 0; r < SIZE; ++r) \
+ for (int c = 0; c < SIZE; ++c) \
+ result.elem[r][c] = ((r + c) & 1 ? -1 : 1) * det(minor(m, c, r)); \
+ return result; \
+ }
+
+MAT_ADJOINT_TEMPLATE(mat3<T>, 3)
+MAT_ADJOINT_TEMPLATE(mat4<T>, 4)
+
+template <typename T>
+inline mat2<T> adjoint(const mat2<T> & m)
+{
+ return mat2<T>(
+ m.elem[1][1], -m.elem[0][1],
+ -m.elem[1][0], m.elem[0][0]
+ );
+}
+
+#define MAT_INVERSE_TEMPLATE(CLASS) \
+ template <typename T> \
+ inline CLASS inverse(const CLASS & m) \
+ { \
+ return adjoint(m) * inv(det(m)); \
+ }
+
+MAT_INVERSE_TEMPLATE(mat2<T>)
+MAT_INVERSE_TEMPLATE(mat3<T>)
+MAT_INVERSE_TEMPLATE(mat4<T>)
+
+#define MAT_VEC_FUNCS_TEMPLATE(MATCLASS, VECCLASS, SIZE) \
+ template <typename T> \
+ inline VECCLASS operator * (const MATCLASS & m, const VECCLASS & v) \
+ { \
+ VECCLASS result; \
+ for (int i = 0; i < SIZE; ++i) {\
+ result[i] = dot(MATRIX_ROW ## SIZE(m, i), v); \
+ } \
+ return result; \
+ } \
+ template <typename T> \
+ inline VECCLASS operator * (const VECCLASS & v, const MATCLASS & m) \
+ { \
+ VECCLASS result; \
+ for (int i = 0; i < SIZE; ++i) \
+ result[i] = dot(v, MATRIX_COL ## SIZE(m, i)); \
+ return result; \
+ }
+
+MAT_VEC_FUNCS_TEMPLATE(mat2<T>, vec2<T>, 2)
+MAT_VEC_FUNCS_TEMPLATE(mat3<T>, vec3<T>, 3)
+MAT_VEC_FUNCS_TEMPLATE(mat4<T>, vec4<T>, 4)
+
+// Returns the inverse of a 4x4 matrix. It is assumed that the matrix passed
+// as argument describes a rigid-body transformation.
+template <typename T>
+inline mat4<T> fast_inverse(const mat4<T>& m)
+{
+ const vec3<T> t = MATRIX_COL3(m, 3);
+ const T tx = -dot(MATRIX_COL3(m, 0), t);
+ const T ty = -dot(MATRIX_COL3(m, 1), t);
+ const T tz = -dot(MATRIX_COL3(m, 2), t);
+
+ return mat4<T>(
+ m.elem[0][0], m.elem[1][0], m.elem[2][0], tx,
+ m.elem[0][1], m.elem[1][1], m.elem[2][1], ty,
+ m.elem[0][2], m.elem[1][2], m.elem[2][2], tz,
+ T(0), T(0), T(0), T(1)
+ );
+}
+
+// Transformations for points and vectors. Potentially faster than a full
+// matrix * vector multiplication
+
+#define MAT_TRANFORMS_TEMPLATE(MATCLASS, VECCLASS, VECSIZE) \
+ /* computes vec3<T>(m * vec4<T>(v, 0.0)) */ \
+ template <typename T> \
+ inline VECCLASS transform_vector(const MATCLASS & m, const VECCLASS & v) \
+ { \
+ VECCLASS result; \
+ for (int i = 0; i < VECSIZE; ++i) \
+ result[i] = dot(MATRIX_ROW ## VECSIZE(m, i), v); \
+ return result;\
+ } \
+ /* computes vec3(m * vec4(v, 1.0)) */ \
+ template <typename T> \
+ inline VECCLASS transform_point(const MATCLASS & m, const VECCLASS & v) \
+ { \
+ /*return transform_vector(m, v) + MATRIX_ROW ## VECSIZE(m, VECSIZE); */\
+ VECCLASS result; \
+ for (int i = 0; i < VECSIZE; ++i) \
+ result[i] = dot(MATRIX_ROW ## VECSIZE(m, i), v) + m.elem[i][VECSIZE]; \
+ return result; \
+ } \
+ /* computes VECCLASS(transpose(m) * vec4<T>(v, 0.0)) */ \
+ template <typename T> \
+ inline VECCLASS transform_vector_transpose(const MATCLASS & m, const VECCLASS& v) \
+ { \
+ VECCLASS result; \
+ for (int i = 0; i < VECSIZE; ++i) \
+ result[i] = dot(MATRIX_COL ## VECSIZE(m, i), v); \
+ return result; \
+ } \
+ /* computes VECCLASS(transpose(m) * vec4<T>(v, 1.0)) */ \
+ template <typename T> \
+ inline VECCLASS transform_point_transpose(const MATCLASS & m, const VECCLASS& v) \
+ { \
+ /*return transform_vector_transpose(m, v) + MATRIX_COL ## VECSIZE(m, VECSIZE); */\
+ VECCLASS result; \
+ for (int i = 0; i < VECSIZE; ++i) \
+ result[i] = dot(MATRIX_COL ## VECSIZE(m, i), v) + m.elem[VECSIZE][i]; \
+ return result; \
+ }
+
+MAT_TRANFORMS_TEMPLATE(mat4<T>, vec3<T>, 3)
+MAT_TRANFORMS_TEMPLATE(mat3<T>, vec2<T>, 2)
+
+#define MAT_OUTERPRODUCT_TEMPLATE(MATCLASS, VECCLASS, MATSIZE) \
+ template <typename T> \
+ inline MATCLASS outer_product(const VECCLASS & v1, const VECCLASS & v2) \
+ { \
+ MATCLASS r; \
+ for ( int j = 0; j < MATSIZE; ++j ) \
+ for ( int k = 0; k < MATSIZE; ++k ) \
+ r.elem[j][k] = v1[j] * v2[k]; \
+ return r; \
+ }
+
+MAT_OUTERPRODUCT_TEMPLATE(mat4<T>, vec4<T>, 4)
+MAT_OUTERPRODUCT_TEMPLATE(mat3<T>, vec3<T>, 3)
+MAT_OUTERPRODUCT_TEMPLATE(mat2<T>, vec2<T>, 2)
+
+template <typename T>
+inline mat4<T> translation_matrix(const T x, const T y, const T z)
+{
+ mat4<T> r(T(1));
+ r.elem[0][3] = x;
+ r.elem[1][3] = y;
+ r.elem[2][3] = z;
+ return r;
+}
+
+template <typename T>
+inline mat4<T> translation_matrix(const vec3<T>& v)
+{
+ return translation_matrix(v.x, v.y, v.z);
+}
+
+template <typename T>
+inline mat4<T> scaling_matrix(const T x, const T y, const T z)
+{
+ mat4<T> r(T(0));
+ r.elem[0][0] = x;
+ r.elem[1][1] = y;
+ r.elem[2][2] = z;
+ r.elem[3][3] = T(1);
+ return r;
+}
+
+template <typename T>
+inline mat4<T> scaling_matrix(const vec3<T>& v)
+{
+ return scaling_matrix(v.x, v.y, v.z);
+}
+
+template <typename T>
+inline mat4<T> rotation_matrix(const T angle, const vec3<T>& v)
+{
+ const T a = angle * T(M_PI/180) ;
+ const vec3<T> u = normalize(v);
+
+ const mat3<T> S(
+ T(0), -u[2], u[1],
+ u[2], T(0), -u[0],
+ -u[1], u[0], T(0)
+ );
+
+ const mat3<T> uut = outer_product(u, u);
+ const mat3<T> R = uut + T(cos(a)) * (identity3<T>() - uut) + T(sin(a)) * S;
+
+ return mat4<T>(R);
+}
+
+
+template <typename T>
+inline mat4<T> rotation_matrix(const T angle, const T x, const T y, const T z)
+{
+ return rotation_matrix(angle, vec3<T>(x, y, z));
+}
+
+// Constructs a shear-matrix that shears component i by factor with
+// Respect to component j.
+template <typename T>
+inline mat4<T> shear_matrix(const int i, const int j, const T factor)
+{
+ mat4<T> m = identity4<T>();
+ m.elem[i][j] = factor;
+ return m;
+}
+
+template <typename T>
+inline mat4<T> euler(const T head, const T pitch, const T roll)
+{
+ return rotation_matrix(roll, T(0), T(0), T(1)) *
+ rotation_matrix(pitch, T(1), T(0), T(0)) *
+ rotation_matrix(head, T(0), T(1), T(0));
+}
+
+template <typename T>
+inline mat4<T> frustum_matrix(const T l, const T r, const T b, const T t, const T n, const T f)
+{
+ return mat4<T>(
+ (2 * n)/(r - l), T(0), (r + l)/(r - l), T(0),
+ T(0), (2 * n)/(t - b), (t + b)/(t - b), T(0),
+ T(0), T(0), -(f + n)/(f - n), -(2 * f * n)/(f - n),
+ T(0), T(0), -T(1), T(0)
+ );
+}
+
+template <typename T>
+inline mat4<T> perspective_matrix(const T fovy, const T aspect, const T zNear, const T zFar)
+{
+ const T dz = zFar - zNear;
+ const T rad = fovy / T(2) * T(M_PI/180);
+ const T s = sin(rad);
+
+ if ( ( dz == T(0) ) || ( s == T(0) ) || ( aspect == T(0) ) ) {
+ return identity4<T>();
+ }
+
+ const T cot = cos(rad) / s;
+
+ mat4<T> m = identity4<T>();
+ m[0] = cot / aspect;
+ m[5] = cot;
+ m[10] = -(zFar + zNear) / dz;
+ m[14] = T(-1);
+ m[11] = -2 * zNear * zFar / dz;
+ m[15] = T(0);
+
+ return m;
+}
+
+template <typename T>
+inline mat4<T> ortho_matrix(const T l, const T r, const T b, const T t, const T n, const T f)
+{
+ return mat4<T>(
+ T(2)/(r - l), T(0), T(0), -(r + l)/(r - l),
+ T(0), T(2)/(t - b), T(0), -(t + b)/(t - b),
+ T(0), T(0), -T(2)/(f - n), -(f + n)/(f - n),
+ T(0), T(0), T(0), T(1)
+ );
+}
+
+template <typename T>
+inline mat4<T> lookat_matrix(const vec3<T>& eye, const vec3<T>& center, const vec3<T>& up) {
+ const vec3<T> forward = normalize(center - eye);
+ const vec3<T> side = normalize(cross(forward, up));
+
+ const vec3<T> up2 = cross(side, forward);
+
+ mat4<T> m = identity4<T>();
+
+ m.elem[0][0] = side[0];
+ m.elem[0][1] = side[1];
+ m.elem[0][2] = side[2];
+
+ m.elem[1][0] = up2[0];
+ m.elem[1][1] = up2[1];
+ m.elem[1][2] = up2[2];
+
+ m.elem[2][0] = -forward[0];
+ m.elem[2][1] = -forward[1];
+ m.elem[2][2] = -forward[2];
+
+ return m * translation_matrix(-eye);
+}
+
+template <typename T>
+inline mat4<T> picking_matrix(const T x, const T y, const T dx, const T dy, int viewport[4]) {
+ if (dx <= 0 || dy <= 0) {
+ return identity4<T>();
+ }
+
+ mat4<T> r = translation_matrix((viewport[2] - 2 * (x - viewport[0])) / dx,
+ (viewport[3] - 2 * (y - viewport[1])) / dy, 0);
+ r *= scaling_matrix(viewport[2] / dx, viewport[2] / dy, 1);
+ return r;
+}
+
+// Constructs a shadow matrix. q is the light source and p is the plane.
+template <typename T> inline mat4<T> shadow_matrix(const vec4<T>& q, const vec4<T>& p) {
+ mat4<T> m;
+
+ m.elem[0][0] = p.y * q[1] + p.z * q[2] + p.w * q[3];
+ m.elem[0][1] = -p.y * q[0];
+ m.elem[0][2] = -p.z * q[0];
+ m.elem[0][3] = -p.w * q[0];
+
+ m.elem[1][0] = -p.x * q[1];
+ m.elem[1][1] = p.x * q[0] + p.z * q[2] + p.w * q[3];
+ m.elem[1][2] = -p.z * q[1];
+ m.elem[1][3] = -p.w * q[1];
+
+
+ m.elem[2][0] = -p.x * q[2];
+ m.elem[2][1] = -p.y * q[2];
+ m.elem[2][2] = p.x * q[0] + p.y * q[1] + p.w * q[3];
+ m.elem[2][3] = -p.w * q[2];
+
+ m.elem[3][1] = -p.x * q[3];
+ m.elem[3][2] = -p.y * q[3];
+ m.elem[3][3] = -p.z * q[3];
+ m.elem[3][0] = p.x * q[0] + p.y * q[1] + p.z * q[2];
+
+ return m;
+}
+
+// Quaternion class
+template <typename T>
+struct quat {
+ vec3<T> v;
+ T w;
+
+ quat() {}
+ quat(const vec3<T>& iv, const T iw) : v(iv), w(iw) {}
+ quat(const T vx, const T vy, const T vz, const T iw) : v(vx, vy, vz), w(iw) {}
+ quat(const vec4<T>& i) : v(i.x, i.y, i.z), w(i.w) {}
+
+ operator const T* () const { return &(v[0]); }
+ operator T* () { return &(v[0]); }
+
+ quat& operator += (const quat& q) { v += q.v; w += q.w; return *this; }
+ quat& operator -= (const quat& q) { v -= q.v; w -= q.w; return *this; }
+
+ quat& operator *= (const T& s) { v *= s; w *= s; return *this; }
+ quat& operator /= (const T& s) { v /= s; w /= s; return *this; }
+
+ quat& operator *= (const quat& r)
+ {
+ //q1 x q2 = [s1,v1] x [s2,v2] = [(s1*s2 - v1*v2),(s1*v2 + s2*v1 + v1xv2)].
+ quat q;
+ q.v = cross(v, r.v) + r.w * v + w * r.v;
+ q.w = w * r.w - dot(v, r.v);
+ return *this = q;
+ }
+
+ quat& operator /= (const quat& q) { return (*this) *= inverse(q); }
+};
+
+// Quaternion functions
+
+template <typename T>
+inline quat<T> identityq()
+{
+ return quat<T>(T(0), T(0), T(0), T(1));
+}
+
+template <typename T>
+inline quat<T> conjugate(const quat<T>& q)
+{
+ return quat<T>(-q.v, q.w);
+}
+
+template <typename T>
+inline quat<T> inverse(const quat<T>& q)
+{
+ const T l = dot(q, q);
+ if ( l > T(0) ) return conjugate(q) * inv(l);
+ else return identityq<T>();
+}
+
+// quaternion utility functions
+
+// the input quaternion is assumed to be normalized
+template <typename T>
+inline mat3<T> quat_to_mat3(const quat<T>& q)
+{
+ // const quat<T> q = normalize(qq);
+
+ const T xx = q[0] * q[0];
+ const T xy = q[0] * q[1];
+ const T xz = q[0] * q[2];
+ const T xw = q[0] * q[3];
+
+ const T yy = q[1] * q[1];
+ const T yz = q[1] * q[2];
+ const T yw = q[1] * q[3];
+
+ const T zz = q[2] * q[2];
+ const T zw = q[2] * q[3];
+
+ return mat3<T>(
+ 1 - 2*(yy + zz), 2*(xy - zw), 2*(xz + yw),
+ 2*(xy + zw), 1 - 2*(xx + zz), 2*(yz - xw),
+ 2*(xz - yw), 2*(yz + xw), 1 - 2*(xx + yy)
+ );
+}
+
+// the input quat<T>ernion is assumed to be normalized
+template <typename T>
+inline mat4<T> quat_to_mat4(const quat<T>& q)
+{
+ // const quat<T> q = normalize(qq);
+
+ return mat4<T>(quat_to_mat3(q));
+}
+
+template <typename T>
+inline quat<T> mat_to_quat(const mat4<T>& m)
+{
+ const T t = m.elem[0][0] + m.elem[1][1] + m.elem[2][2] + T(1);
+ quat<T> q;
+
+ if ( t > 0 ) {
+ const T s = T(0.5) / sqrt(t);
+ q[3] = T(0.25) * inv(s);
+ q[0] = (m.elem[2][1] - m.elem[1][2]) * s;
+ q[1] = (m.elem[0][2] - m.elem[2][0]) * s;
+ q[2] = (m.elem[1][0] - m.elem[0][1]) * s;
+ } else {
+ if ( m.elem[0][0] > m.elem[1][1] && m.elem[0][0] > m.elem[2][2] ) {
+ const T s = T(2) * sqrt( T(1) + m.elem[0][0] - m.elem[1][1] - m.elem[2][2]);
+ const T invs = inv(s);
+ q[0] = T(0.25) * s;
+ q[1] = (m.elem[0][1] + m.elem[1][0] ) * invs;
+ q[2] = (m.elem[0][2] + m.elem[2][0] ) * invs;
+ q[3] = (m.elem[1][2] - m.elem[2][1] ) * invs;
+ } else if (m.elem[1][1] > m.elem[2][2]) {
+ const T s = T(2) * sqrt( T(1) + m.elem[1][1] - m.elem[0][0] - m.elem[2][2]);
+ const T invs = inv(s);
+ q[0] = (m.elem[0][1] + m.elem[1][0] ) * invs;
+ q[1] = T(0.25) * s;
+ q[2] = (m.elem[1][2] + m.elem[2][1] ) * invs;
+ q[3] = (m.elem[0][2] - m.elem[2][0] ) * invs;
+ } else {
+ const T s = T(2) * sqrt( T(1) + m.elem[2][2] - m.elem[0][0] - m.elem[1][1] );
+ const T invs = inv(s);
+ q[0] = (m.elem[0][2] + m.elem[2][0] ) * invs;
+ q[1] = (m.elem[1][2] + m.elem[2][1] ) * invs;
+ q[2] = T(0.25) * s;
+ q[3] = (m.elem[0][1] - m.elem[1][0] ) * invs;
+ }
+ }
+
+ return q;
+}
+
+template <typename T>
+inline quat<T> mat_to_quat(const mat3<T>& m)
+{
+ return mat_to_quat(mat4<T>(m));
+}
+
+// the angle is in radians
+template <typename T>
+inline quat<T> quat_from_axis_angle(const vec3<T>& axis, const T a)
+{
+ quat<T> r;
+ const T inv2 = inv(T(2));
+ r.v = sin(a * inv2) * normalize(axis);
+ r.w = cos(a * inv2);
+
+ return r;
+}
+
+// the angle is in radians
+template <typename T>
+inline quat<T> quat_from_axis_angle(const T x, const T y, const T z, const T angle)
+{
+ return quat_from_axis_angle<T>(vec3<T>(x, y, z), angle);
+}
+
+// the angle is stored in radians
+template <typename T>
+inline void quat_to_axis_angle(const quat<T>& qq, vec3<T>* axis, T *angle)
+{
+ quat<T> q = normalize(qq);
+
+ *angle = 2 * acos(q.w);
+
+ const T s = sin((*angle) * inv(T(2)));
+ if ( s != T(0) )
+ *axis = q.v * inv(s);
+ else
+ * axis = vec3<T>(T(0), T(0), T(0));
+}
+
+// Spherical linear interpolation
+template <typename T>
+inline quat<T> slerp(const quat<T>& qq1, const quat<T>& qq2, const T t)
+{
+ // slerp(q1,q2) = sin((1-t)*a)/sin(a) * q1 + sin(t*a)/sin(a) * q2
+ const quat<T> q1 = normalize(qq1);
+ const quat<T> q2 = normalize(qq2);
+
+ const T a = acos(dot(q1, q2));
+ const T s = sin(a);
+
+ #define EPS T(1e-5)
+
+ if ( !(-EPS <= s && s <= EPS) ) {
+ return sin((T(1)-t)*a)/s * q1 + sin(t*a)/s * q2;
+ } else {
+ // if the angle is to small use a linear interpolation
+ return lerp(q1, q2, t);
+ }
+
+ #undef EPS
+}
+
+// Sperical quadtratic interpolation using a smooth cubic spline
+// The parameters a and b are the control points.
+template <typename T>
+inline quat<T> squad(
+ const quat<T>& q0,
+ const quat<T>& a,
+ const quat<T>& b,
+ const quat<T>& q1,
+ const T t)
+{
+ return slerp(slerp(q0, q1, t),slerp(a, b, t), 2 * t * (1 - t));
+}
+
+#undef MOP_M_CLASS_TEMPLATE
+#undef MOP_M_TYPE_TEMPLATE
+#undef MOP_COMP_TEMPLATE
+#undef MOP_G_UMINUS_TEMPLATE
+#undef COMMON_OPERATORS
+#undef VECTOR_COMMON
+#undef FOP_G_SOURCE_TEMPLATE
+#undef FOP_G_CLASS_TEMPLATE
+#undef FOP_G_TYPE_TEMPLATE
+#undef VEC_QUAT_FUNC_TEMPLATE
+#undef VEC_FUNC_TEMPLATE
+#undef MATRIX_COL4
+#undef MATRIX_ROW4
+#undef MATRIX_COL3
+#undef MATRIX_ROW3
+#undef MATRIX_COL2
+#undef MATRIX_ROW2
+#undef MOP_M_MATRIX_MULTIPLY
+#undef MATRIX_CONSTRUCTOR_FROM_T
+#undef MATRIX_CONSTRUCTOR_FROM_LOWER
+#undef MATRIX_COMMON
+#undef MATRIX_CONSTRUCTOR_FROM_HIGHER
+#undef MAT_FUNC_TEMPLATE
+#undef MAT_FUNC_MINOR_TEMPLATE
+#undef MAT_ADJOINT_TEMPLATE
+#undef MAT_INVERSE_TEMPLATE
+#undef MAT_VEC_FUNCS_TEMPLATE
+#undef MAT_TRANFORMS_TEMPLATE
+#undef MAT_OUTERPRODUCT_TEMPLATE
+#undef FREE_MODIFYING_OPERATORS
+#undef FREE_OPERATORS
+
+} // end namespace vmath
+
+#endif
+
+
+
+
diff -r 000000000000 -r 89cf0851969b CommonTypes.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CommonTypes.lib Tue Jun 26 18:24:45 2018 +0000 @@ -0,0 +1,1 @@ +https://mbed.org/users/RichardE/code/CommonTypes/#033e112463bb
diff -r 000000000000 -r 89cf0851969b ESC.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ESC.lib Tue Jun 26 18:24:45 2018 +0000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/users/MatteoT/code/ESC/#735702ea5519
diff -r 000000000000 -r 89cf0851969b MPU9250.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MPU9250.cpp Tue Jun 26 18:24:45 2018 +0000
@@ -0,0 +1,743 @@
+#include "MPU9250.h"
+
+// Set initial input parameters
+enum Ascale {
+ AFS_2G = 0,
+ AFS_4G,
+ AFS_8G,
+ AFS_16G
+};
+
+enum Gscale {
+ GFS_250DPS = 0,
+ GFS_500DPS,
+ GFS_1000DPS,
+ GFS_2000DPS
+};
+
+enum Mscale {
+ MFS_14BITS = 0, // 0.6 mG per LSB
+ MFS_16BITS // 0.15 mG per LSB
+};
+
+float ax,ay,az;
+float gx,gy,gz;
+float mx,my,mz;
+int16_t accelData[3],gyroData[3],tempData;
+float accelBias[3] = {0, 0, 0}; // Bias corrections for acc
+float gyroBias[3] = {0, 0, 0};
+extern float magCalibration[3]= {0, 0, 0};
+extern float magbias[3]= {0, 0, 0}, magScale[3] = {0, 0, 0};
+ float SelfTest[6];
+
+int delt_t = 0; // used to control display output rate
+int count = 0; // used to control display output rate
+
+// parameters for 6 DoF sensor fusion calculations
+float PI = 3.14159265358979323846f;
+float GyroMeasError = PI * (60.0f / 180.0f); // gyroscope measurement error in rads/s (start at 60 deg/s), then reduce after ~10 s to 3
+float beta = sqrt(3.0f / 4.0f) * GyroMeasError; // compute beta
+float GyroMeasDrift = PI * (1.0f / 180.0f); // gyroscope measurement drift in rad/s/s (start at 0.0 deg/s/s)
+float zeta = sqrt(3.0f / 4.0f) * GyroMeasDrift; // compute zeta, the other free parameter in the Madgwick scheme usually set to a small or zero value
+#define Kp 0.98 // these are the free parameters in the Mahony filter and fusion scheme, Kp for proportional feedback, Ki for integral
+#define Ki 0.0000001f
+
+float pitch, yaw, roll;
+float deltat = 0.0f; // integration interval for both filter schemes
+int lastUpdate = 0, firstUpdate = 0, Now = 0; // used to calculate integration interval // used to calculate integration interval
+float q[4] = {1.0f, 0.0f, 0.0f, 0.0f}; // vector to hold quaternion
+float eInt[3] = {0.0f, 0.0f, 0.0f};
+
+uint8_t Ascale = AFS_16G; // AFS_2G, AFS_4G, AFS_8G, AFS_16G
+uint8_t Gscale = GFS_2000DPS; // GFS_250DPS, GFS_500DPS, GFS_1000DPS, GFS_2000DPS
+uint8_t Mscale = MFS_16BITS; // MFS_14BITS or MFS_16BITS, 14-bit or 16-bit magnetometer resolution
+uint8_t Mmode = 0x06; // Either 8 Hz 0x02) or 100 Hz (0x06) magnetometer data ODR
+float aRes, gRes, mRes;
+
+MPU9250::MPU9250(PinName sda, PinName scl) : i2c(sda, scl) {
+ //this->setSleepMode(false);
+ i2c.frequency(400000);
+ //Initializations:
+ currentGyroRange = 0;
+ currentAcceleroRange=0;
+}
+
+//--------------------------------------------------
+//--------------------CONFIG------------------------
+//--------------------------------------------------
+
+void MPU9250::getAres()
+{
+ switch(Ascale)
+ {
+ case AFS_2G:
+ aRes = 2.0/32768.0;
+ break;
+ case AFS_4G:
+ aRes = 4.0/32768.0;
+ break;
+ case AFS_8G:
+ aRes = 8.0/32768.0;
+ break;
+ case AFS_16G:
+ aRes = 16.0/32768.0;
+ break;
+ }
+}
+
+void MPU9250::getGres()
+{
+ switch(Gscale)
+ {
+ case GFS_250DPS:
+ gRes = 250.0/32768.0;
+ break;
+ case GFS_500DPS:
+ gRes = 500.0/32768.0;
+ break;
+ case GFS_1000DPS:
+ gRes = 1000.0/32768.0;
+ break;
+ case GFS_2000DPS:
+ gRes = 2000.0/32768.0;
+ break;
+ }
+}
+
+void MPU9250::getMres() {
+ switch (Mscale)
+ {
+ // Possible magnetometer scales (and their register bit settings) are:
+ // 14 bit resolution (0) and 16 bit resolution (1)
+ case MFS_14BITS:
+ mRes = 10.0*4219.0/8190.0; // Proper scale to return milliGauss
+ break;
+ case MFS_16BITS:
+ mRes = 10.0*4219.0/32760.0; // Proper scale to return milliGauss
+ break;
+ }
+}
+//--------------------------------------------------
+//-------------------General------------------------
+//--------------------------------------------------
+
+void MPU9250::writeByte(uint8_t address, uint8_t subAddress, uint8_t data)
+{
+ char data_write[2];
+ data_write[0] = subAddress;
+ data_write[1] = data;
+ i2c.write(address, data_write, 2, 0);
+}
+
+char MPU9250::readByte(uint8_t address, uint8_t subAddress)
+{
+ char data[1]; // `data` will store the register data
+ char data_write[1];
+ data_write[0] = subAddress;
+ i2c.write(address, data_write, 1, 1); // no stop
+ i2c.read(address, data, 1, 0);
+ return data[0];
+}
+
+void MPU9250::readBytes(uint8_t address, uint8_t subAddress, uint8_t count, uint8_t * dest)
+{
+ char data[14];
+ char data_write[1];
+ data_write[0] = subAddress;
+ i2c.write(address, data_write, 1, 1); // no stop
+ i2c.read(address, data, count, 0);
+ for(int ii = 0; ii < count; ii++) {
+ dest[ii] = data[ii];
+ }
+}
+
+
+void MPU9250::readAccelData(int16_t * destination)
+{
+ uint8_t rawData[6]; // x/y/z accel register data stored here
+ readBytes(MPU9250_ADDRESS, ACCEL_XOUT_H, 6, &rawData[0]); // Read the six raw data registers into data array
+ destination[0] = (int16_t)(((int16_t)rawData[0] << 8) | rawData[1]) ; // Turn the MSB and LSB into a signed 16-bit value
+ destination[1] = (int16_t)(((int16_t)rawData[2] << 8) | rawData[3]) ;
+ destination[2] = (int16_t)(((int16_t)rawData[4] << 8) | rawData[5]) ;
+}
+
+void MPU9250::readGyroData(int16_t * destination)
+{
+ uint8_t rawData[6]; // x/y/z gyro register data stored here
+ readBytes(MPU9250_ADDRESS, GYRO_XOUT_H, 6, &rawData[0]); // Read the six raw data registers sequentially into data array
+ destination[0] = (int16_t)(((int16_t)rawData[0] << 8) | rawData[1]) ; // Turn the MSB and LSB into a signed 16-bit value
+ destination[1] = (int16_t)(((int16_t)rawData[2] << 8) | rawData[3]) ;
+ destination[2] = (int16_t)(((int16_t)rawData[4] << 8) | rawData[5]) ;
+}
+
+void MPU9250::readMagData(int16_t * destination)
+{
+ uint8_t rawData[7]; // x/y/z gyro register data, ST2 register stored here, must read ST2 at end of data acquisition
+ if(readByte(AK8963_ADDRESS, AK8963_ST1) & 0x01) { // wait for magnetometer data ready bit to be set
+ readBytes(AK8963_ADDRESS, AK8963_XOUT_L, 7, &rawData[0]); // Read the six raw data and ST2 registers sequentially into data array
+ uint8_t c = rawData[6]; // End data read by reading ST2 register
+ if(!(c & 0x08)) { // Check if magnetic sensor overflow set, if not then report data
+ destination[0] = (int16_t)(((int16_t)rawData[1] << 8) | rawData[0]); // Turn the MSB and LSB into a signed 16-bit value
+ destination[1] = (int16_t)(((int16_t)rawData[3] << 8) | rawData[2]) ; // Data stored as little Endian
+ destination[2] = (int16_t)(((int16_t)rawData[5] << 8) | rawData[4]) ;
+ }
+ }
+}
+
+int16_t MPU9250::readTempData()
+{
+ uint8_t rawData[2]; // x/y/z gyro register data stored here
+ readBytes(MPU9250_ADDRESS, TEMP_OUT_H, 2, &rawData[0]); // Read the two raw data registers sequentially into data array
+ return (int16_t)(((int16_t)rawData[0]) << 8 | rawData[1]) ; // Turn the MSB and LSB into a 16-bit value
+}
+
+void MPU9250::resetMPU9250() {
+ // reset device
+ writeByte(MPU9250_ADDRESS, PWR_MGMT_1, 0x80); // Write a one to bit 7 reset bit; toggle reset device
+ wait(0.1);
+ }
+
+void MPU9250::initAK8963(float * destination)
+{
+ // First extract the factory calibration for each magnetometer axis
+ uint8_t rawData[3]; // x/y/z gyro calibration data stored here
+ writeByte(AK8963_ADDRESS, AK8963_CNTL, 0x00); // Power down magnetometer
+ wait(0.01);
+ writeByte(AK8963_ADDRESS, AK8963_CNTL, 0x0F); // Enter Fuse ROM access mode
+ wait(0.01);
+ readBytes(AK8963_ADDRESS, AK8963_ASAX, 3, &rawData[0]); // Read the x-, y-, and z-axis calibration values
+ destination[0] = (float)(rawData[0] - 128)/256.0f + 1.0f; // Return x-axis sensitivity adjustment values, etc.
+ destination[1] = (float)(rawData[1] - 128)/256.0f + 1.0f;
+ destination[2] = (float)(rawData[2] - 128)/256.0f + 1.0f;
+ writeByte(AK8963_ADDRESS, AK8963_CNTL, 0x00); // Power down magnetometer
+ wait(0.01);
+ // Configure the magnetometer for continuous read and highest resolution
+ // set Mscale bit 4 to 1 (0) to enable 16 (14) bit resolution in CNTL register,
+ // and enable continuous mode data acquisition Mmode (bits [3:0]), 0010 for 8 Hz and 0110 for 100 Hz sample rates
+ writeByte(AK8963_ADDRESS, AK8963_CNTL, Mscale << 4 | Mmode); // Set magnetometer data resolution and sample ODR
+ wait(0.01);
+}
+
+void MPU9250::initMPU9250()
+{
+ // Initialize MPU9250 device
+ // wake up device
+ writeByte(MPU9250_ADDRESS, PWR_MGMT_1, 0x00); // Clear sleep mode bit (6), enable all sensors
+ wait(0.1); // Delay 100 ms for PLL to get established on x-axis gyro; should check for PLL ready interrupt
+
+ // get stable time source
+ writeByte(MPU9250_ADDRESS, PWR_MGMT_1, 0x01); // Set clock source to be PLL with x-axis gyroscope reference, bits 2:0 = 001
+
+ // Configure Gyro and Accelerometer
+ // Disable FSYNC and set accelerometer and gyro bandwidth to 44 and 42 Hz, respectively;
+ // DLPF_CFG = bits 2:0 = 010; this sets the sample rate at 1 kHz for both
+ // Maximum delay is 4.9 ms which is just over a 200 Hz maximum rate
+ writeByte(MPU9250_ADDRESS, CONFIG, 0x03);
+
+ // Set sample rate = gyroscope output rate/(1 + SMPLRT_DIV)
+ writeByte(MPU9250_ADDRESS, SMPLRT_DIV, 0x04); // Use a 200 Hz rate; the same rate set in CONFIG above
+
+ // Set gyroscope full scale range
+ // Range selects FS_SEL and AFS_SEL are 0 - 3, so 2-bit values are left-shifted into positions 4:3
+ uint8_t c = readByte(MPU9250_ADDRESS, GYRO_CONFIG); // get current GYRO_CONFIG register value
+ // c = c & ~0xE0; // Clear self-test bits [7:5]
+ c = c & ~0x02; // Clear Fchoice bits [1:0]
+ c = c & ~0x18; // Clear AFS bits [4:3]
+ c = c | Gscale << 3; // Set full scale range for the gyro
+ // c =| 0x00; // Set Fchoice for the gyro to 11 by writing its inverse to bits 1:0 of GYRO_CONFIG
+ writeByte(MPU9250_ADDRESS, GYRO_CONFIG, c ); // Write new GYRO_CONFIG value to register
+
+ // Set accelerometer full-scale range configuration
+ c = readByte(MPU9250_ADDRESS, ACCEL_CONFIG); // get current ACCEL_CONFIG register value
+ // c = c & ~0xE0; // Clear self-test bits [7:5]
+ c = c & ~0x18; // Clear AFS bits [4:3]
+ c = c | Ascale << 3; // Set full scale range for the accelerometer
+ writeByte(MPU9250_ADDRESS, ACCEL_CONFIG, c); // Write new ACCEL_CONFIG register value
+
+ // Set accelerometer sample rate configuration
+ // It is possible to get a 4 kHz sample rate from the accelerometer by choosing 1 for
+ // accel_fchoice_b bit [3]; in this case the bandwidth is 1.13 kHz
+ c = readByte(MPU9250_ADDRESS, ACCEL_CONFIG2); // get current ACCEL_CONFIG2 register value
+ c = c & ~0x0F; // Clear accel_fchoice_b (bit 3) and A_DLPFG (bits [2:0])
+ c = c | 0x03; // Set accelerometer rate to 1 kHz and bandwidth to 41 Hz
+ writeByte(MPU9250_ADDRESS, ACCEL_CONFIG2, c); // Write new ACCEL_CONFIG2 register value
+
+ // The accelerometer, gyro, and thermometer are set to 1 kHz sample rates,
+ // but all these rates are further reduced by a factor of 5 to 200 Hz because of the SMPLRT_DIV setting
+
+ // Configure Interrupts and Bypass Enable
+ // Set interrupt pin active high, push-pull, and clear on read of INT_STATUS, enable I2C_BYPASS_EN so additional chips
+ // can join the I2C bus and all can be controlled by the Arduino as master
+
+#if USE_ISR
+ writeByte(MPU9250_ADDRESS, INT_PIN_CFG, 0x12); // INT is 50 microsecond pulse and any read to clear
+#else
+ writeByte(MPU9250_ADDRESS, INT_PIN_CFG, 0x22);
+#endif
+ writeByte(MPU9250_ADDRESS, INT_ENABLE, 0x01); // Enable data ready (bit 0) interrupt
+}
+
+// Function which accumulates gyro and accelerometer data after device initialization. It calculates the average
+// of the at-rest readings and then loads the resulting offsets into accelerometer and gyro bias registers.
+void MPU9250::calibrateMPU9250(float * dest1, float * dest2)
+{
+ uint8_t data[12]; // data array to hold accelerometer and gyro x, y, z, data
+ uint16_t ii, packet_count, fifo_count;
+ int32_t gyro_bias[3] = {0, 0, 0}, accel_bias[3] = {0, 0, 0};
+
+// reset device, reset all registers, clear gyro and accelerometer bias registers
+ writeByte(MPU9250_ADDRESS, PWR_MGMT_1, 0x80); // Write a one to bit 7 reset bit; toggle reset device
+ wait(0.1);
+
+// get stable time source
+// Set clock source to be PLL with x-axis gyroscope reference, bits 2:0 = 001
+ writeByte(MPU9250_ADDRESS, PWR_MGMT_1, 0x01);
+ writeByte(MPU9250_ADDRESS, PWR_MGMT_2, 0x00);
+ wait(0.2);
+
+// Configure device for bias calculation
+ writeByte(MPU9250_ADDRESS, INT_ENABLE, 0x00); // Disable all interrupts
+ writeByte(MPU9250_ADDRESS, FIFO_EN, 0x00); // Disable FIFO
+ writeByte(MPU9250_ADDRESS, PWR_MGMT_1, 0x00); // Turn on internal clock source
+ writeByte(MPU9250_ADDRESS, I2C_MST_CTRL, 0x00); // Disable I2C master
+ writeByte(MPU9250_ADDRESS, USER_CTRL, 0x00); // Disable FIFO and I2C master modes
+ writeByte(MPU9250_ADDRESS, USER_CTRL, 0x0C); // Reset FIFO and DMP
+ wait(0.015);
+
+// Configure MPU9250 gyro and accelerometer for bias calculation
+ writeByte(MPU9250_ADDRESS, CONFIG, 0x01); // Set low-pass filter to 188 Hz
+ writeByte(MPU9250_ADDRESS, SMPLRT_DIV, 0x00); // Set sample rate to 1 kHz
+ writeByte(MPU9250_ADDRESS, GYRO_CONFIG, 0x00); // Set gyro full-scale to 250 degrees per second, maximum sensitivity
+ writeByte(MPU9250_ADDRESS, ACCEL_CONFIG, 0x00); // Set accelerometer full-scale to 2 g, maximum sensitivity
+
+ uint16_t gyrosensitivity = 131; // = 131 LSB/degrees/sec
+ uint16_t accelsensitivity = 16384; // = 16384 LSB/g
+
+// Configure FIFO to capture accelerometer and gyro data for bias calculation
+ writeByte(MPU9250_ADDRESS, USER_CTRL, 0x40); // Enable FIFO
+ writeByte(MPU9250_ADDRESS, FIFO_EN, 0x78); // Enable gyro and accelerometer sensors for FIFO (max size 512 bytes in MPU-9250)
+ wait(0.04); // accumulate 40 samples in 80 milliseconds = 480 bytes
+
+// At end of sample accumulation, turn off FIFO sensor read
+ writeByte(MPU9250_ADDRESS, FIFO_EN, 0x00); // Disable gyro and accelerometer sensors for FIFO
+ readBytes(MPU9250_ADDRESS, FIFO_COUNTH, 2, &data[0]); // read FIFO sample count
+ fifo_count = ((uint16_t)data[0] << 8) | data[1];
+ packet_count = fifo_count/12;// How many sets of full gyro and accelerometer data for averaging
+
+ for (ii = 0; ii < packet_count; ii++) {
+ int16_t accel_temp[3] = {0, 0, 0}, gyro_temp[3] = {0, 0, 0};
+ readBytes(MPU9250_ADDRESS, FIFO_R_W, 12, &data[0]); // read data for averaging
+ accel_temp[0] = (int16_t) (((int16_t)data[0] << 8) | data[1] ) ; // Form signed 16-bit integer for each sample in FIFO
+ accel_temp[1] = (int16_t) (((int16_t)data[2] << 8) | data[3] ) ;
+ accel_temp[2] = (int16_t) (((int16_t)data[4] << 8) | data[5] ) ;
+ gyro_temp[0] = (int16_t) (((int16_t)data[6] << 8) | data[7] ) ;
+ gyro_temp[1] = (int16_t) (((int16_t)data[8] << 8) | data[9] ) ;
+ gyro_temp[2] = (int16_t) (((int16_t)data[10] << 8) | data[11]) ;
+
+ accel_bias[0] += (int32_t) accel_temp[0]; // Sum individual signed 16-bit biases to get accumulated signed 32-bit biases
+ accel_bias[1] += (int32_t) accel_temp[1];
+ accel_bias[2] += (int32_t) accel_temp[2];
+ gyro_bias[0] += (int32_t) gyro_temp[0];
+ gyro_bias[1] += (int32_t) gyro_temp[1];
+ gyro_bias[2] += (int32_t) gyro_temp[2];
+
+}
+ accel_bias[0] /= (int32_t) packet_count; // Normalize sums to get average count biases
+ accel_bias[1] /= (int32_t) packet_count;
+ accel_bias[2] /= (int32_t) packet_count;
+ gyro_bias[0] /= (int32_t) packet_count;
+ gyro_bias[1] /= (int32_t) packet_count;
+ gyro_bias[2] /= (int32_t) packet_count;
+
+ if(accel_bias[2] > 0L) {accel_bias[2] -= (int32_t) accelsensitivity;} // Remove gravity from the z-axis accelerometer bias calculation
+ else {accel_bias[2] += (int32_t) accelsensitivity;}
+
+// Construct the gyro biases for push to the hardware gyro bias registers, which are reset to zero upon device startup
+ data[0] = (-gyro_bias[0]/4 >> 8) & 0xFF; // Divide by 4 to get 32.9 LSB per deg/s to conform to expected bias input format
+ data[1] = (-gyro_bias[0]/4) & 0xFF; // Biases are additive, so change sign on calculated average gyro biases
+ data[2] = (-gyro_bias[1]/4 >> 8) & 0xFF;
+ data[3] = (-gyro_bias[1]/4) & 0xFF;
+ data[4] = (-gyro_bias[2]/4 >> 8) & 0xFF;
+ data[5] = (-gyro_bias[2]/4) & 0xFF;
+
+/// Push gyro biases to hardware registers
+/* writeByte(MPU9250_ADDRESS, XG_OFFSET_H, data[0]);
+ writeByte(MPU9250_ADDRESS, XG_OFFSET_L, data[1]);
+ writeByte(MPU9250_ADDRESS, YG_OFFSET_H, data[2]);
+ writeByte(MPU9250_ADDRESS, YG_OFFSET_L, data[3]);
+ writeByte(MPU9250_ADDRESS, ZG_OFFSET_H, data[4]);
+ writeByte(MPU9250_ADDRESS, ZG_OFFSET_L, data[5]);
+*/
+ dest1[0] = (float) gyro_bias[0]/(float) gyrosensitivity; // construct gyro bias in deg/s for later manual subtraction
+ dest1[1] = (float) gyro_bias[1]/(float) gyrosensitivity;
+ dest1[2] = (float) gyro_bias[2]/(float) gyrosensitivity;
+
+// Construct the accelerometer biases for push to the hardware accelerometer bias registers. These registers contain
+// factory trim values which must be added to the calculated accelerometer biases; on boot up these registers will hold
+// non-zero values. In addition, bit 0 of the lower byte must be preserved since it is used for temperature
+// compensation calculations. Accelerometer bias registers expect bias input as 2048 LSB per g, so that
+// the accelerometer biases calculated above must be divided by 8.
+
+ int32_t accel_bias_reg[3] = {0, 0, 0}; // A place to hold the factory accelerometer trim biases
+ readBytes(MPU9250_ADDRESS, XA_OFFSET_H, 2, &data[0]); // Read factory accelerometer trim values
+ accel_bias_reg[0] = (int16_t) ((int16_t)data[0] << 8) | data[1];
+ readBytes(MPU9250_ADDRESS, YA_OFFSET_H, 2, &data[0]);
+ accel_bias_reg[1] = (int16_t) ((int16_t)data[0] << 8) | data[1];
+ readBytes(MPU9250_ADDRESS, ZA_OFFSET_H, 2, &data[0]);
+ accel_bias_reg[2] = (int16_t) ((int16_t)data[0] << 8) | data[1];
+
+ uint32_t mask = 1uL; // Define mask for temperature compensation bit 0 of lower byte of accelerometer bias registers
+ uint8_t mask_bit[3] = {0, 0, 0}; // Define array to hold mask bit for each accelerometer bias axis
+
+ for(ii = 0; ii < 3; ii++) {
+ if(accel_bias_reg[ii] & mask) mask_bit[ii] = 0x01; // If temperature compensation bit is set, record that fact in mask_bit
+ }
+
+ // Construct total accelerometer bias, including calculated average accelerometer bias from above
+ accel_bias_reg[0] -= (accel_bias[0]/8); // Subtract calculated averaged accelerometer bias scaled to 2048 LSB/g (16 g full scale)
+ accel_bias_reg[1] -= (accel_bias[1]/8);
+ accel_bias_reg[2] -= (accel_bias[2]/8);
+
+ data[0] = (accel_bias_reg[0] >> 8) & 0xFF;
+ data[1] = (accel_bias_reg[0]) & 0xFF;
+ data[1] = data[1] | mask_bit[0]; // preserve temperature compensation bit when writing back to accelerometer bias registers
+ data[2] = (accel_bias_reg[1] >> 8) & 0xFF;
+ data[3] = (accel_bias_reg[1]) & 0xFF;
+ data[3] = data[3] | mask_bit[1]; // preserve temperature compensation bit when writing back to accelerometer bias registers
+ data[4] = (accel_bias_reg[2] >> 8) & 0xFF;
+ data[5] = (accel_bias_reg[2]) & 0xFF;
+ data[5] = data[5] | mask_bit[2]; // preserve temperature compensation bit when writing back to accelerometer bias registers
+
+// Apparently this is not working for the acceleration biases in the MPU-9250
+// Are we handling the temperature correction bit properly?
+// Push accelerometer biases to hardware registers
+/* writeByte(MPU9250_ADDRESS, XA_OFFSET_H, data[0]);
+ writeByte(MPU9250_ADDRESS, XA_OFFSET_L, data[1]);
+ writeByte(MPU9250_ADDRESS, YA_OFFSET_H, data[2]);
+ writeByte(MPU9250_ADDRESS, YA_OFFSET_L, data[3]);
+ writeByte(MPU9250_ADDRESS, ZA_OFFSET_H, data[4]);
+ writeByte(MPU9250_ADDRESS, ZA_OFFSET_L, data[5]);
+*/
+// Output scaled accelerometer biases for manual subtraction in the main program
+ dest2[0] = (float)accel_bias[0]/(float)accelsensitivity;
+ dest2[1] = (float)accel_bias[1]/(float)accelsensitivity;
+ dest2[2] = (float)accel_bias[2]/(float)accelsensitivity;
+}
+
+void MPU9250::magcalMPU9250(float * dest1, float * dest2)
+{
+ uint16_t ii = 0, sample_count = 0;
+ int32_t mag_bias[3] = {0, 0, 0}, mag_scale[3] = {0, 0, 0};
+ int16_t mag_max[3] = {-32767, -32767, -32767}, mag_min[3] = {32767, 32767, 32767}, mag_temp[3] = {0, 0, 0};
+
+ // shoot for ~fifteen seconds of mag data
+ if(Mmode == 0x02) sample_count = 128; // at 8 Hz ODR, new mag data is available every 125 ms
+ if(Mmode == 0x06) sample_count = 1500; // at 100 Hz ODR, new mag data is available every 10 ms
+
+ for(ii = 0; ii < sample_count; ii++) {
+ readMagData(mag_temp); // Read the mag data
+
+ for (int jj = 0; jj < 3; jj++) {
+ if(mag_temp[jj] > mag_max[jj]) mag_max[jj] = mag_temp[jj];
+ if(mag_temp[jj] < mag_min[jj]) mag_min[jj] = mag_temp[jj];
+ }
+
+ if(Mmode == 0x02) wait(0.135); // at 8 Hz ODR, new mag data is available every 125 ms
+ if(Mmode == 0x06) wait(0.012); // at 100 Hz ODR, new mag data is available every 10 ms
+ }
+
+ // Get hard iron correction
+ mag_bias[0] = (mag_max[0] + mag_min[0])/2; // get average x mag bias in counts
+ mag_bias[1] = (mag_max[1] + mag_min[1])/2; // get average y mag bias in counts
+ mag_bias[2] = (mag_max[2] + mag_min[2])/2; // get average z mag bias in counts
+
+ dest1[0] = (float) mag_bias[0]*mRes*magCalibration[0]; // save mag biases in G for main program
+ dest1[1] = (float) mag_bias[1]*mRes*magCalibration[1];
+ dest1[2] = (float) mag_bias[2]*mRes*magCalibration[2];
+
+ // Get soft iron correction estimate
+ mag_scale[0] = (mag_max[0] - mag_min[0])/2; // get average x axis max chord length in counts
+ mag_scale[1] = (mag_max[1] - mag_min[1])/2; // get average y axis max chord length in counts
+ mag_scale[2] = (mag_max[2] - mag_min[2])/2; // get average z axis max chord length in counts
+
+ float avg_rad = mag_scale[0] + mag_scale[1] + mag_scale[2];
+ avg_rad /= 3.0;
+
+ dest2[0] = avg_rad/((float)mag_scale[0]);
+ dest2[1] = avg_rad/((float)mag_scale[1]);
+ dest2[2] = avg_rad/((float)mag_scale[2]);
+}
+
+
+// Accelerometer and gyroscope self test; check calibration wrt factory settings
+void MPU9250::MPU9250SelfTest(float * destination) // Should return percent deviation from factory trim values, +/- 14 or less deviation is a pass
+{
+ uint8_t rawData[6] = {0, 0, 0, 0, 0, 0};
+ uint8_t selfTest[6];
+ int32_t gAvg[3] = {0}, aAvg[3] = {0}, aSTAvg[3] = {0}, gSTAvg[3] = {0};
+ float factoryTrim[6];
+ uint8_t FS = 0;
+
+ writeByte(MPU9250_ADDRESS, SMPLRT_DIV, 0x00); // Set gyro sample rate to 1 kHz
+ writeByte(MPU9250_ADDRESS, CONFIG, 0x02); // Set gyro sample rate to 1 kHz and DLPF to 92 Hz
+ writeByte(MPU9250_ADDRESS, GYRO_CONFIG, 1<<FS); // Set full scale range for the gyro to 250 dps
+ writeByte(MPU9250_ADDRESS, ACCEL_CONFIG2, 0x02); // Set accelerometer rate to 1 kHz and bandwidth to 92 Hz
+ writeByte(MPU9250_ADDRESS, ACCEL_CONFIG, 1<<FS); // Set full scale range for the accelerometer to 2 g
+
+ for( int ii = 0; ii < 200; ii++) { // get average current values of gyro and acclerometer
+
+ readBytes(MPU9250_ADDRESS, ACCEL_XOUT_H, 6, &rawData[0]); // Read the six raw data registers into data array
+ aAvg[0] += (int16_t)(((int16_t)rawData[0] << 8) | rawData[1]) ; // Turn the MSB and LSB into a signed 16-bit value
+ aAvg[1] += (int16_t)(((int16_t)rawData[2] << 8) | rawData[3]) ;
+ aAvg[2] += (int16_t)(((int16_t)rawData[4] << 8) | rawData[5]) ;
+
+ readBytes(MPU9250_ADDRESS, GYRO_XOUT_H, 6, &rawData[0]); // Read the six raw data registers sequentially into data array
+ gAvg[0] += (int16_t)(((int16_t)rawData[0] << 8) | rawData[1]) ; // Turn the MSB and LSB into a signed 16-bit value
+ gAvg[1] += (int16_t)(((int16_t)rawData[2] << 8) | rawData[3]) ;
+ gAvg[2] += (int16_t)(((int16_t)rawData[4] << 8) | rawData[5]) ;
+ }
+
+ for (int ii =0; ii < 3; ii++) { // Get average of 200 values and store as average current readings
+ aAvg[ii] /= 200;
+ gAvg[ii] /= 200;
+ }
+
+// Configure the accelerometer for self-test
+ writeByte(MPU9250_ADDRESS, ACCEL_CONFIG, 0xE0); // Enable self test on all three axes and set accelerometer range to +/- 2 g
+ writeByte(MPU9250_ADDRESS, GYRO_CONFIG, 0xE0); // Enable self test on all three axes and set gyro range to +/- 250 degrees/s
+ wait(0.025); // Delay a while to let the device stabilize
+
+ for( int ii = 0; ii < 200; ii++) { // get average self-test values of gyro and acclerometer
+
+ readBytes(MPU9250_ADDRESS, ACCEL_XOUT_H, 6, &rawData[0]); // Read the six raw data registers into data array
+ aSTAvg[0] += (int16_t)(((int16_t)rawData[0] << 8) | rawData[1]) ; // Turn the MSB and LSB into a signed 16-bit value
+ aSTAvg[1] += (int16_t)(((int16_t)rawData[2] << 8) | rawData[3]) ;
+ aSTAvg[2] += (int16_t)(((int16_t)rawData[4] << 8) | rawData[5]) ;
+
+ readBytes(MPU9250_ADDRESS, GYRO_XOUT_H, 6, &rawData[0]); // Read the six raw data registers sequentially into data array
+ gSTAvg[0] += (int16_t)(((int16_t)rawData[0] << 8) | rawData[1]) ; // Turn the MSB and LSB into a signed 16-bit value
+ gSTAvg[1] += (int16_t)(((int16_t)rawData[2] << 8) | rawData[3]) ;
+ gSTAvg[2] += (int16_t)(((int16_t)rawData[4] << 8) | rawData[5]) ;
+ }
+
+ for (int ii =0; ii < 3; ii++) { // Get average of 200 values and store as average self-test readings
+ aSTAvg[ii] /= 200;
+ gSTAvg[ii] /= 200;
+ }
+
+ // Configure the gyro and accelerometer for normal operation
+ writeByte(MPU9250_ADDRESS, ACCEL_CONFIG, 0x00);
+ writeByte(MPU9250_ADDRESS, GYRO_CONFIG, 0x00);
+ wait(0.025); // Delay a while to let the device stabilize
+
+ // Retrieve accelerometer and gyro factory Self-Test Code from USR_Reg
+ selfTest[0] = readByte(MPU9250_ADDRESS, SELF_TEST_X_ACCEL); // X-axis accel self-test results
+ selfTest[1] = readByte(MPU9250_ADDRESS, SELF_TEST_Y_ACCEL); // Y-axis accel self-test results
+ selfTest[2] = readByte(MPU9250_ADDRESS, SELF_TEST_Z_ACCEL); // Z-axis accel self-test results
+ selfTest[3] = readByte(MPU9250_ADDRESS, SELF_TEST_X_GYRO); // X-axis gyro self-test results
+ selfTest[4] = readByte(MPU9250_ADDRESS, SELF_TEST_Y_GYRO); // Y-axis gyro self-test results
+ selfTest[5] = readByte(MPU9250_ADDRESS, SELF_TEST_Z_GYRO); // Z-axis gyro self-test results
+
+ // Retrieve factory self-test value from self-test code reads
+ factoryTrim[0] = (float)(2620/1<<FS)*(pow( 1.01 , ((float)selfTest[0] - 1.0) )); // FT[Xa] factory trim calculation
+ factoryTrim[1] = (float)(2620/1<<FS)*(pow( 1.01 , ((float)selfTest[1] - 1.0) )); // FT[Ya] factory trim calculation
+ factoryTrim[2] = (float)(2620/1<<FS)*(pow( 1.01 , ((float)selfTest[2] - 1.0) )); // FT[Za] factory trim calculation
+ factoryTrim[3] = (float)(2620/1<<FS)*(pow( 1.01 , ((float)selfTest[3] - 1.0) )); // FT[Xg] factory trim calculation
+ factoryTrim[4] = (float)(2620/1<<FS)*(pow( 1.01 , ((float)selfTest[4] - 1.0) )); // FT[Yg] factory trim calculation
+ factoryTrim[5] = (float)(2620/1<<FS)*(pow( 1.01 , ((float)selfTest[5] - 1.0) )); // FT[Zg] factory trim calculation
+
+ // Report results as a ratio of (STR - FT)/FT; the change from Factory Trim of the Self-Test Response
+ // To get percent, must multiply by 100
+ for (int i = 0; i < 3; i++) {
+ destination[i] = 100.0*((float)(aSTAvg[i] - aAvg[i]))/factoryTrim[i] - 100.; // Report percent differences
+ destination[i+3] = 100.0*((float)(gSTAvg[i] - gAvg[i]))/factoryTrim[i+3] - 100.; // Report percent differences
+ }
+
+}
+
+void MPU9250::MadgwickQuaternionUpdate(float ax, float ay, float az, float gx, float gy, float gz, float mx, float my, float mz)
+{
+ float q1 = q[0], q2 = q[1], q3 = q[2], q4 = q[3]; // short name local variable for readability
+ float norm;
+ float hx, hy, _2bx, _2bz;
+ float s1, s2, s3, s4;
+ float qDot1, qDot2, qDot3, qDot4;
+
+ // Auxiliary variables to avoid repeated arithmetic
+ float _2q1mx;
+ float _2q1my;
+ float _2q1mz;
+ float _2q2mx;
+ float _4bx;
+ float _4bz;
+ float _2q1 = 2.0f * q1;
+ float _2q2 = 2.0f * q2;
+ float _2q3 = 2.0f * q3;
+ float _2q4 = 2.0f * q4;
+ float _2q1q3 = 2.0f * q1 * q3;
+ float _2q3q4 = 2.0f * q3 * q4;
+ float q1q1 = q1 * q1;
+ float q1q2 = q1 * q2;
+ float q1q3 = q1 * q3;
+ float q1q4 = q1 * q4;
+ float q2q2 = q2 * q2;
+ float q2q3 = q2 * q3;
+ float q2q4 = q2 * q4;
+ float q3q3 = q3 * q3;
+ float q3q4 = q3 * q4;
+ float q4q4 = q4 * q4;
+
+ // Normalise accelerometer measurement
+ norm = sqrt(ax * ax + ay * ay + az * az);
+ if (norm == 0.0f) return; // handle NaN
+ norm = 1.0f/norm;
+ ax *= norm;
+ ay *= norm;
+ az *= norm;
+
+ // Normalise magnetometer measurement
+ norm = sqrt(mx * mx + my * my + mz * mz);
+ if (norm == 0.0f) return; // handle NaN
+ norm = 1.0f/norm;
+ mx *= norm;
+ my *= norm;
+ mz *= norm;
+
+ // Reference direction of Earth's magnetic field
+ _2q1mx = 2.0f * q1 * mx;
+ _2q1my = 2.0f * q1 * my;
+ _2q1mz = 2.0f * q1 * mz;
+ _2q2mx = 2.0f * q2 * mx;
+ hx = mx * q1q1 - _2q1my * q4 + _2q1mz * q3 + mx * q2q2 + _2q2 * my * q3 + _2q2 * mz * q4 - mx * q3q3 - mx * q4q4;
+ hy = _2q1mx * q4 + my * q1q1 - _2q1mz * q2 + _2q2mx * q3 - my * q2q2 + my * q3q3 + _2q3 * mz * q4 - my * q4q4;
+ _2bx = sqrt(hx * hx + hy * hy);
+ _2bz = -_2q1mx * q3 + _2q1my * q2 + mz * q1q1 + _2q2mx * q4 - mz * q2q2 + _2q3 * my * q4 - mz * q3q3 + mz * q4q4;
+ _4bx = 2.0f * _2bx;
+ _4bz = 2.0f * _2bz;
+
+ // Gradient decent algorithm corrective step
+ s1 = -_2q3 * (2.0f * q2q4 - _2q1q3 - ax) + _2q2 * (2.0f * q1q2 + _2q3q4 - ay) - _2bz * q3 * (_2bx * (0.5f - q3q3 - q4q4) + _2bz * (q2q4 - q1q3) - mx) + (-_2bx * q4 + _2bz * q2) * (_2bx * (q2q3 - q1q4) + _2bz * (q1q2 + q3q4) - my) + _2bx * q3 * (_2bx * (q1q3 + q2q4) + _2bz * (0.5f - q2q2 - q3q3) - mz);
+ s2 = _2q4 * (2.0f * q2q4 - _2q1q3 - ax) + _2q1 * (2.0f * q1q2 + _2q3q4 - ay) - 4.0f * q2 * (1.0f - 2.0f * q2q2 - 2.0f * q3q3 - az) + _2bz * q4 * (_2bx * (0.5f - q3q3 - q4q4) + _2bz * (q2q4 - q1q3) - mx) + (_2bx * q3 + _2bz * q1) * (_2bx * (q2q3 - q1q4) + _2bz * (q1q2 + q3q4) - my) + (_2bx * q4 - _4bz * q2) * (_2bx * (q1q3 + q2q4) + _2bz * (0.5f - q2q2 - q3q3) - mz);
+ s3 = -_2q1 * (2.0f * q2q4 - _2q1q3 - ax) + _2q4 * (2.0f * q1q2 + _2q3q4 - ay) - 4.0f * q3 * (1.0f - 2.0f * q2q2 - 2.0f * q3q3 - az) + (-_4bx * q3 - _2bz * q1) * (_2bx * (0.5f - q3q3 - q4q4) + _2bz * (q2q4 - q1q3) - mx) + (_2bx * q2 + _2bz * q4) * (_2bx * (q2q3 - q1q4) + _2bz * (q1q2 + q3q4) - my) + (_2bx * q1 - _4bz * q3) * (_2bx * (q1q3 + q2q4) + _2bz * (0.5f - q2q2 - q3q3) - mz);
+ s4 = _2q2 * (2.0f * q2q4 - _2q1q3 - ax) + _2q3 * (2.0f * q1q2 + _2q3q4 - ay) + (-_4bx * q4 + _2bz * q2) * (_2bx * (0.5f - q3q3 - q4q4) + _2bz * (q2q4 - q1q3) - mx) + (-_2bx * q1 + _2bz * q3) * (_2bx * (q2q3 - q1q4) + _2bz * (q1q2 + q3q4) - my) + _2bx * q2 * (_2bx * (q1q3 + q2q4) + _2bz * (0.5f - q2q2 - q3q3) - mz);
+ norm = sqrt(s1 * s1 + s2 * s2 + s3 * s3 + s4 * s4); // normalise step magnitude
+ norm = 1.0f/norm;
+ s1 *= norm;
+ s2 *= norm;
+ s3 *= norm;
+ s4 *= norm;
+
+ // Compute rate of change of quaternion
+ qDot1 = 0.5f * (-q2 * gx - q3 * gy - q4 * gz) - beta * s1;
+ qDot2 = 0.5f * (q1 * gx + q3 * gz - q4 * gy) - beta * s2;
+ qDot3 = 0.5f * (q1 * gy - q2 * gz + q4 * gx) - beta * s3;
+ qDot4 = 0.5f * (q1 * gz + q2 * gy - q3 * gx) - beta * s4;
+
+ // Integrate to yield quaternion
+ q1 += qDot1 * deltat;
+ q2 += qDot2 * deltat;
+ q3 += qDot3 * deltat;
+ q4 += qDot4 * deltat;
+ norm = sqrt(q1 * q1 + q2 * q2 + q3 * q3 + q4 * q4); // normalise quaternion
+ norm = 1.0f/norm;
+ q[0] = q1 * norm;
+ q[1] = q2 * norm;
+ q[2] = q3 * norm;
+ q[3] = q4 * norm;
+
+}
+
+ // Similar to Madgwick scheme but uses proportional and integral filtering on the error between estimated reference vectors and
+ // measured ones.
+void MPU9250::MahonyQuaternionUpdate(float ax, float ay, float az, float gx, float gy, float gz, float mx, float my, float mz)
+{
+ float q1 = q[0], q2 = q[1], q3 = q[2], q4 = q[3]; // short name local variable for readability
+ float norm;
+ float hx, hy, bx, bz;
+ float vx, vy, vz, wx, wy, wz;
+ float ex, ey, ez;
+ float pa, pb, pc;
+
+ // Auxiliary variables to avoid repeated arithmetic
+ float q1q1 = q1 * q1;
+ float q1q2 = q1 * q2;
+ float q1q3 = q1 * q3;
+ float q1q4 = q1 * q4;
+ float q2q2 = q2 * q2;
+ float q2q3 = q2 * q3;
+ float q2q4 = q2 * q4;
+ float q3q3 = q3 * q3;
+ float q3q4 = q3 * q4;
+ float q4q4 = q4 * q4;
+
+ // Normalise accelerometer measurement
+ norm = sqrt(ax * ax + ay * ay + az * az);
+ if (norm == 0.0f) return; // handle NaN
+ norm = 1.0f / norm; // use reciprocal for division
+ ax *= norm;
+ ay *= norm;
+ az *= norm;
+
+ // Normalise magnetometer measurement
+ norm = sqrt(mx * mx + my * my + mz * mz);
+ if (norm == 0.0f) return; // handle NaN
+ norm = 1.0f / norm; // use reciprocal for division
+ mx *= norm;
+ my *= norm;
+ mz *= norm;
+
+ // Reference direction of Earth's magnetic field
+ hx = 2.0f * mx * (0.5f - q3q3 - q4q4) + 2.0f * my * (q2q3 - q1q4) + 2.0f * mz * (q2q4 + q1q3);
+ hy = 2.0f * mx * (q2q3 + q1q4) + 2.0f * my * (0.5f - q2q2 - q4q4) + 2.0f * mz * (q3q4 - q1q2);
+ bx = sqrt((hx * hx) + (hy * hy));
+ bz = 2.0f * mx * (q2q4 - q1q3) + 2.0f * my * (q3q4 + q1q2) + 2.0f * mz * (0.5f - q2q2 - q3q3);
+
+ // Estimated direction of gravity and magnetic field
+ vx = 2.0f * (q2q4 - q1q3);
+ vy = 2.0f * (q1q2 + q3q4);
+ vz = q1q1 - q2q2 - q3q3 + q4q4;
+ wx = 2.0f * bx * (0.5f - q3q3 - q4q4) + 2.0f * bz * (q2q4 - q1q3);
+ wy = 2.0f * bx * (q2q3 - q1q4) + 2.0f * bz * (q1q2 + q3q4);
+ wz = 2.0f * bx * (q1q3 + q2q4) + 2.0f * bz * (0.5f - q2q2 - q3q3);
+
+ // Error is cross product between estimated direction and measured direction of gravity
+ ex = (ay * vz - az * vy) + (my * wz - mz * wy);
+ ey = (az * vx - ax * vz) + (mz * wx - mx * wz);
+ ez = (ax * vy - ay * vx) + (mx * wy - my * wx);
+ if (Ki > 0.0f)
+ {
+ eInt[0] += ex; // accumulate integral error
+ eInt[1] += ey;
+ eInt[2] += ez;
+ }
+ else
+ {
+ eInt[0] = 0.0f; // prevent integral wind up
+ eInt[1] = 0.0f;
+ eInt[2] = 0.0f;
+ }
+
+ // Apply feedback terms
+ gx = gx + Kp * ex + Ki * eInt[0];
+ gy = gy + Kp * ey + Ki * eInt[1];
+ gz = gz + Kp * ez + Ki * eInt[2];
+
+ // Integrate rate of change of quaternion
+ pa = q2;
+ pb = q3;
+ pc = q4;
+ q1 = q1 + (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * deltat);
+ q2 = pa + (q1 * gx + pb * gz - pc * gy) * (0.5f * deltat);
+ q3 = pb + (q1 * gy - pa * gz + pc * gx) * (0.5f * deltat);
+ q4 = pc + (q1 * gz + pa * gy - pb * gx) * (0.5f * deltat);
+
+ // Normalise quaternion
+ norm = sqrt(q1 * q1 + q2 * q2 + q3 * q3 + q4 * q4);
+ norm = 1.0f / norm;
+ q[0] = q1 * norm;
+ q[1] = q2 * norm;
+ q[2] = q3 * norm;
+ q[3] = q4 * norm;
+
+}
+
diff -r 000000000000 -r 89cf0851969b MPU9250.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MPU9250.h Tue Jun 26 18:24:45 2018 +0000
@@ -0,0 +1,269 @@
+
+
+#ifndef MPU9250_H
+#define MPU9250_H
+
+
+/**
+ * Includes
+ */
+
+#include "mbed.h"
+#include "math.h"
+
+#define USE_ISR 1 // poll or data ready interrupt
+
+// See also MPU-9250 Register Map and Descriptions, Revision 4.0, RM-MPU-9250A-00, Rev. 1.4, 9/9/2013 for registers not listed in
+// above document; the MPU9250 and MPU9150 are virtually identical but the latter has a different register map
+//
+//Magnetometer Registers
+#define AK8963_ADDRESS 0x0C<<1
+#define WHO_AM_I_AK8963 0x00 // should return 0x48
+#define INFO 0x01
+#define AK8963_ST1 0x02 // data ready status bit 0
+#define AK8963_XOUT_L 0x03 // data
+#define AK8963_XOUT_H 0x04
+#define AK8963_YOUT_L 0x05
+#define AK8963_YOUT_H 0x06
+#define AK8963_ZOUT_L 0x07
+#define AK8963_ZOUT_H 0x08
+#define AK8963_ST2 0x09 // Data overflow bit 3 and data read error status bit 2
+#define AK8963_CNTL 0x0A // Power down (0000), single-measurement (0001), self-test (1000) and Fuse ROM (1111) modes on bits 3:0
+#define AK8963_ASTC 0x0C // Self test control
+#define AK8963_I2CDIS 0x0F // I2C disable
+#define AK8963_ASAX 0x10 // Fuse ROM x-axis sensitivity adjustment value
+#define AK8963_ASAY 0x11 // Fuse ROM y-axis sensitivity adjustment value
+#define AK8963_ASAZ 0x12 // Fuse ROM z-axis sensitivity adjustment value
+
+#define SELF_TEST_X_GYRO 0x00
+#define SELF_TEST_Y_GYRO 0x01
+#define SELF_TEST_Z_GYRO 0x02
+
+/*#define X_FINE_GAIN 0x03 // [7:0] fine gain
+#define Y_FINE_GAIN 0x04
+#define Z_FINE_GAIN 0x05
+#define XA_OFFSET_H 0x06 // User-defined trim values for accelerometer
+#define XA_OFFSET_L_TC 0x07
+#define YA_OFFSET_H 0x08
+#define YA_OFFSET_L_TC 0x09
+#define ZA_OFFSET_H 0x0A
+#define ZA_OFFSET_L_TC 0x0B */
+
+#define SELF_TEST_X_ACCEL 0x0D
+#define SELF_TEST_Y_ACCEL 0x0E
+#define SELF_TEST_Z_ACCEL 0x0F
+
+#define SELF_TEST_A 0x10
+
+#define XG_OFFSET_H 0x13 // User-defined trim values for gyroscope
+#define XG_OFFSET_L 0x14
+#define YG_OFFSET_H 0x15
+#define YG_OFFSET_L 0x16
+#define ZG_OFFSET_H 0x17
+#define ZG_OFFSET_L 0x18
+#define SMPLRT_DIV 0x19
+#define CONFIG 0x1A
+#define GYRO_CONFIG 0x1B
+#define ACCEL_CONFIG 0x1C
+#define ACCEL_CONFIG2 0x1D
+#define LP_ACCEL_ODR 0x1E
+#define WOM_THR 0x1F
+
+#define MOT_DUR 0x20 // Duration counter threshold for motion interrupt generation, 1 kHz rate, LSB = 1 ms
+#define ZMOT_THR 0x21 // Zero-motion detection threshold bits [7:0]
+#define ZRMOT_DUR 0x22 // Duration counter threshold for zero motion interrupt generation, 16 Hz rate, LSB = 64 ms
+
+#define FIFO_EN 0x23
+#define I2C_MST_CTRL 0x24
+#define I2C_SLV0_ADDR 0x25
+#define I2C_SLV0_REG 0x26
+#define I2C_SLV0_CTRL 0x27
+#define I2C_SLV1_ADDR 0x28
+#define I2C_SLV1_REG 0x29
+#define I2C_SLV1_CTRL 0x2A
+#define I2C_SLV2_ADDR 0x2B
+#define I2C_SLV2_REG 0x2C
+#define I2C_SLV2_CTRL 0x2D
+#define I2C_SLV3_ADDR 0x2E
+#define I2C_SLV3_REG 0x2F
+#define I2C_SLV3_CTRL 0x30
+#define I2C_SLV4_ADDR 0x31
+#define I2C_SLV4_REG 0x32
+#define I2C_SLV4_DO 0x33
+#define I2C_SLV4_CTRL 0x34
+#define I2C_SLV4_DI 0x35
+#define I2C_MST_STATUS 0x36
+#define INT_PIN_CFG 0x37
+#define INT_ENABLE 0x38
+#define DMP_INT_STATUS 0x39 // Check DMP interrupt
+#define INT_STATUS 0x3A
+#define ACCEL_XOUT_H 0x3B
+#define ACCEL_XOUT_L 0x3C
+#define ACCEL_YOUT_H 0x3D
+#define ACCEL_YOUT_L 0x3E
+#define ACCEL_ZOUT_H 0x3F
+#define ACCEL_ZOUT_L 0x40
+#define TEMP_OUT_H 0x41
+#define TEMP_OUT_L 0x42
+#define GYRO_XOUT_H 0x43
+#define GYRO_XOUT_L 0x44
+#define GYRO_YOUT_H 0x45
+#define GYRO_YOUT_L 0x46
+#define GYRO_ZOUT_H 0x47
+#define GYRO_ZOUT_L 0x48
+#define EXT_SENS_DATA_00 0x49
+#define EXT_SENS_DATA_01 0x4A
+#define EXT_SENS_DATA_02 0x4B
+#define EXT_SENS_DATA_03 0x4C
+#define EXT_SENS_DATA_04 0x4D
+#define EXT_SENS_DATA_05 0x4E
+#define EXT_SENS_DATA_06 0x4F
+#define EXT_SENS_DATA_07 0x50
+#define EXT_SENS_DATA_08 0x51
+#define EXT_SENS_DATA_09 0x52
+#define EXT_SENS_DATA_10 0x53
+#define EXT_SENS_DATA_11 0x54
+#define EXT_SENS_DATA_12 0x55
+#define EXT_SENS_DATA_13 0x56
+#define EXT_SENS_DATA_14 0x57
+#define EXT_SENS_DATA_15 0x58
+#define EXT_SENS_DATA_16 0x59
+#define EXT_SENS_DATA_17 0x5A
+#define EXT_SENS_DATA_18 0x5B
+#define EXT_SENS_DATA_19 0x5C
+#define EXT_SENS_DATA_20 0x5D
+#define EXT_SENS_DATA_21 0x5E
+#define EXT_SENS_DATA_22 0x5F
+#define EXT_SENS_DATA_23 0x60
+#define MOT_DETECT_STATUS 0x61
+#define I2C_SLV0_DO 0x63
+#define I2C_SLV1_DO 0x64
+#define I2C_SLV2_DO 0x65
+#define I2C_SLV3_DO 0x66
+#define I2C_MST_DELAY_CTRL 0x67
+#define SIGNAL_PATH_RESET 0x68
+#define MOT_DETECT_CTRL 0x69
+#define USER_CTRL 0x6A // Bit 7 enable DMP, bit 3 reset DMP
+#define PWR_MGMT_1 0x6B // Device defaults to the SLEEP mode
+#define PWR_MGMT_2 0x6C
+#define DMP_BANK 0x6D // Activates a specific bank in the DMP
+#define DMP_RW_PNT 0x6E // Set read/write pointer to a specific start address in specified DMP bank
+#define DMP_REG 0x6F // Register in DMP from which to read or to which to write
+#define DMP_REG_1 0x70
+#define DMP_REG_2 0x71
+#define FIFO_COUNTH 0x72
+#define FIFO_COUNTL 0x73
+#define FIFO_R_W 0x74
+#define WHO_AM_I_MPU9250 0x75 // Should return 0x71
+#define XA_OFFSET_H 0x77
+#define XA_OFFSET_L 0x78
+#define YA_OFFSET_H 0x7A
+#define YA_OFFSET_L 0x7B
+#define ZA_OFFSET_H 0x7D
+#define ZA_OFFSET_L 0x7E
+
+// Using the MSENSR-9250 breakout board, ADO is set to 0
+// Seven-bit device address is 110100 for ADO = 0 and 110101 for ADO = 1
+//mbed uses the eight-bit device address, so shift seven-bit addresses left by one!
+#define ADO 0
+#if ADO
+#define MPU9250_ADDRESS 0x69<<1 // Device address when ADO = 1
+#else
+#define MPU9250_ADDRESS 0x68<<1 // Device address when ADO = 0
+#endif
+
+extern float aRes, gRes;
+
+extern Serial pc;
+
+
+extern float ax,ay,az;
+extern float gx,gy,gz;
+extern float mx,my,mz;
+extern int16_t accelData[3],gyroData[3],tempData;
+extern float accelBias[3], gyroBias[3];
+extern float magCalibration[3];
+extern float magbias[3], magScale[3];
+extern int lastUpdate, firstUpdate, Now;
+extern float deltat;
+extern int delt_t;
+extern int count;
+extern float PI;
+extern float pitch, yaw, roll;
+extern float deltat; // integration interval for both filter schemes
+extern int lastUpdate; // used to calculate integration interval // used to calculate integration interval
+extern float q[4]; // vector to hold quaternion
+extern float eInt[3];
+extern float GyroMeasError;
+extern float beta;
+extern float GyroMeasDrift;
+extern float zeta;
+extern float SelfTest[6];
+
+extern uint8_t Ascale; // AFS_2G, AFS_4G, AFS_8G, AFS_16G
+extern uint8_t Gscale; // GFS_250DPS, GFS_500DPS, GFS_1000DPS, GFS_2000DPS
+extern uint8_t Mscale; // MFS_14BITS or MFS_16BITS, 14-bit or 16-bit magnetometer resolution
+extern uint8_t Mmode; // Either 8 Hz 0x02) or 100 Hz (0x06) magnetometer data ODR
+extern float aRes, gRes, mRes;
+
+
+/** MPU9250 IMU library.
+ *
+ * Example:
+ * @code
+ * Later, maybe
+ * @endcode
+ */
+class MPU9250 {
+ public:
+ /**
+ * Constructor.
+ *
+ * Sleep mode of MPU6050 is immediatly disabled
+ *
+ * @param sda - mbed pin to use for the SDA I2C line.
+ * @param scl - mbed pin to use for the SCL I2C line.
+ */
+ MPU9250(PinName sda, PinName scl);
+
+
+ /**
+ * Tests the I2C connection by reading the WHO_AM_I register.
+ *
+ * @return True for a working connection, false for an error
+ */
+ void getAres();
+ void getGres();
+ void getMres();
+
+ void writeByte(uint8_t address, uint8_t subAddress, uint8_t data);
+ char readByte(uint8_t address, uint8_t subAddress);
+ void readBytes(uint8_t address, uint8_t subAddress, uint8_t count, uint8_t * dest);
+
+ void readAccelData(int16_t * destination);
+ void readGyroData(int16_t * destination);
+ void readMagData(int16_t * destination);
+ int16_t readTempData();
+
+ void resetMPU9250();
+ void initAK8963(float * destination);
+ void initMPU9250();
+ void calibrateMPU9250(float * dest1, float * dest2);
+ void MPU9250::magcalMPU9250(float * dest1, float * dest2) ;
+ void MPU9250SelfTest(float * destination);
+ void MadgwickQuaternionUpdate(float ax, float ay, float az, float gx, float gy, float gz, float mx, float my, float mz);
+ void MahonyQuaternionUpdate(float ax, float ay, float az, float gx, float gy, float gz, float mx, float my, float mz);
+
+ private:
+
+ I2C i2c;
+ char currentAcceleroRange;
+ char currentGyroRange;
+
+
+};
+
+
+
+#endif
+
diff -r 000000000000 -r 89cf0851969b MathFuncs.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MathFuncs.h Tue Jun 26 18:24:45 2018 +0000
@@ -0,0 +1,43 @@
+/*
+ * SOURCE FILE : MathFuncs.h
+ *
+ * Definition of class MathFuncs.
+ *
+ */
+
+#ifndef MathFuncsDefined
+
+ #define MathFuncsDefined
+
+ #include "Types.h"
+
+ /** Various useful maths related functions. */
+ class MathFuncs {
+
+ public :
+
+ /** Constrain a number to be between 2 values.
+ *
+ * @param x Number to constrain.
+ * @param min Minimum value.
+ * @param max Maximum value.
+ * @returns A number between min and max.
+ */
+ static Int16 Constrain( Int16 x, Int16 min, Int16 max ) {
+ if( x < min ) {
+ return min;
+ }
+ else if( x > max ) {
+ return max;
+ }
+ else {
+ return x;
+ }
+ }
+
+ };
+
+#endif
+
+/* END of MathFuncs.h */
+
diff -r 000000000000 -r 89cf0851969b Matrix.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Matrix.lib Tue Jun 26 18:24:45 2018 +0000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/users/Yo_Robot/code/Matrix/#a4014ab0a8cf
diff -r 000000000000 -r 89cf0851969b PID.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PID.lib Tue Jun 26 18:24:45 2018 +0000 @@ -0,0 +1,1 @@ +http://os.mbed.com/users/porizou/code/PID/#eeb41e25a490
diff -r 000000000000 -r 89cf0851969b Servo.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Servo.lib Tue Jun 26 18:24:45 2018 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/simon/code/Servo/#36b69a7ced07
diff -r 000000000000 -r 89cf0851969b kalman.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kalman.lib Tue Jun 26 18:24:45 2018 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/cdonate/code/kalman/#8a460b0d6f09
diff -r 000000000000 -r 89cf0851969b main.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Tue Jun 26 18:24:45 2018 +0000
@@ -0,0 +1,119 @@
+#include "mbed.h"
+#include "math.h"
+#include "rtos.h"
+#include "Servo.h"
+#include "CID10DOF.h"
+#include <string>
+#include "stdio.h"
+#include "MathFuncs.h"
+
+
+#define double_SIZE sizeof(double)
+
+
+Serial pc(USBTX, USBRX);
+Serial telem(PC_0, PC_1);
+CID10DOF CID10DOF(D14,D15,D2,D4,D5,D7);
+AnalogIn Analog_I(A0);
+DigitalOut led1(D6);
+DigitalOut led2(D3);
+Timer t;
+
+double bias[3] = {0.0,0.0,0.0}, setpoint[3]= {0.0,0.0,0.0}, speed[4], actSpeed[4];
+double ypr[4],M[5],Diff[3];
+
+
+void getData(void const *argument);
+void PID(void const *argument);
+void motors(void const *argument);
+
+
+int main() {
+
+ pc.baud(115200);
+ //telem.baud(57600);
+
+ led2 = !led2;
+
+ CID10DOF.MPU9250init();
+ CID10DOF.PID_Config(setpoint, bias);
+ CID10DOF.Calibrate_Motors();
+
+ for (int i = 0; i < 4; i++){ //initialise speed to be 0.3
+ speed[i] = MIN_TRHUST;
+ }
+
+ led2 = !led2;
+
+ Thread thread3(getData, NULL, osPriorityRealtime, DEFAULT_STACK_SIZE);
+ Thread thread4(PID, NULL, osPriorityRealtime, DEFAULT_STACK_SIZE);
+ Thread thread5(motors, NULL, osPriorityRealtime, DEFAULT_STACK_SIZE);
+
+ t.start();
+
+ while(1) {
+
+ led1 = !led1;
+ Thread::wait(17);
+ //pc.printf("Y:%f,P:%f,R:%f,PID_P:%.5f,PID_R:%.5f,M1:%f,M2:%f \n\r",ypr[0],ypr[1],ypr[2],Diff[1],Diff[2],actSpeed[0],actSpeed[1]);
+ pc.printf("%f, %f, %f, %f, %f, %f\n\r",ypr[1],ypr[2],0.0,t.read(),ypr[1]-setpoint[1],setpoint[1]);
+
+ if(t>10){
+ setpoint[1] = 5.0;
+ }
+
+ if(t>15){
+ setpoint[1] = 0.0;
+ }
+
+ if(t>20){
+ setpoint[1] = -5;
+ }
+
+ if(t>25){
+ setpoint[1] = 0.0;
+ }
+
+ }
+
+}
+
+
+void PID(void const *argument)
+{
+ while(true){
+
+ CID10DOF.PID_Run(ypr, setpoint, Diff);
+
+ actSpeed[0] = MIN_TRHUST - Diff[2] ;
+ actSpeed[1] = MIN_TRHUST + Diff[2] ;
+
+ if(actSpeed[0]< MIN_TRHUST){actSpeed[0] = MIN_TRHUST;}
+ if(actSpeed[0]> 1.0){actSpeed[0] = MAX_TRHUST;}
+ if(actSpeed[1]< MIN_TRHUST){actSpeed[1] = MIN_TRHUST;}
+ if(actSpeed[1]> 1.0){actSpeed[1] = MAX_TRHUST;}
+ Thread::wait(10);
+ }
+}
+
+
+
+void getData(void const *argument)
+{
+ while(true){
+
+ CID10DOF.MPU9250ReadAxis(ypr);
+ Thread::wait(5);
+ }
+}
+
+void motors(void const *argument)
+{
+ while(true){
+
+ CID10DOF.run (actSpeed);
+ Thread::wait(20);
+ }
+}
+
+
diff -r 000000000000 -r 89cf0851969b mbed-rtos.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-rtos.lib Tue Jun 26 18:24:45 2018 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed-rtos/#bdd541595fc5
diff -r 000000000000 -r 89cf0851969b mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Tue Jun 26 18:24:45 2018 +0000 @@ -0,0 +1,1 @@ +https://mbed.org/users/mbed_official/code/mbed/builds/86740a56073b \ No newline at end of file
