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.
Revision 2:dc7840a67f77, committed 2019-02-25
- Comitter:
- fbob
- Date:
- Mon Feb 25 16:39:52 2019 +0000
- Parent:
- 1:085840a3d767
- Commit message:
- Update
Changed in this revision
--- a/AttitudeEstimator/AttitudeEstimator.cpp Wed Feb 13 17:06:28 2019 +0000
+++ b/AttitudeEstimator/AttitudeEstimator.cpp Mon Feb 25 16:39:52 2019 +0000
@@ -2,83 +2,209 @@
#include "AttitudeEstimator.h"
// Class constructor
-AttitudeEstimator::AttitudeEstimator() : x(4,1), z(3,1), A(4,4), H(3,4), P(4,4), K(4,3), Q(4,4), R(3,3), imu(A4,A5)
+AttitudeEstimator::AttitudeEstimator() : imu(A4,A5)
{
}
-// Initialize class
+// Initialize class
void AttitudeEstimator::init()
{
// Initialize IMU sensor object
imu.init();
-
- dt = 0.01;
-
- x(1,1) = 1.0;
- x(2,1) = 0.0;
- x(3,1) = 0.0;
- x(4,1) = 0.0;
+
+ dt = 0.005;
+ dt_half = dt/2.0;
- P(1,1) = 1.0;
- P(2,2) = 1.0;
- P(3,3) = 1.0;
- P(4,4) = 1.0;
+ x = eye(4,1);
+ A = eye(4);
+ P = eye(4);
+ Q = 0.001*eye(4);
+ R = 10.0*eye(4);
+ H = eye(4);
+ I = eye(4);
- Q(1,1) = 1.0;
- Q(2,2) = 1.0;
- Q(3,3) = 1.0;
- Q(4,4) = 1.0;
+ g = zeros(3,1);
+ a = zeros(3,1);
+ m = zeros(3,1);
- R(1,1) = 100.0;
- R(2,2) = 100.0;
- R(3,3) = 100.0;
+ q = zeros(4,1);
-
+ BN = eye(3);
+
}
// Estimate euler angles (rad) and angular velocity (rad/s)
void AttitudeEstimator::estimate()
{
// Read IMU sensor data
- imu.read();
+ read();
+ get_output();
+
+ float omega_x = g(1,1)*dt_half;
+ float omega_y = g(2,1)*dt_half;
+ float omega_z = g(3,1)*dt_half;
- A(1,2) = -imu.gx/2.0;
- A(1,3) = -imu.gy/2.0;
- A(1,4) = -imu.gz/2.0;
- A(2,1) = imu.gx/2.0;
- A(2,3) = imu.gz/2.0;
- A(2,4) = -imu.gy/2.0;
- A(3,1) = imu.gy/2.0;
- A(3,2) = -imu.gz/2.0;
- A(3,4) = imu.gx/2.0;
- A(4,1) = imu.gz/2.0;
- A(4,2) = imu.gy/2.0;
- A(4,3) = -imu.gx/2.0;
+ /*A(1,1) = 1.0;
+ A(1,2) = -g(1,1)*dt/2.0;
+ A(1,3) = -g(2,1)*dt/2.0;
+ A(1,4) = -g(3,1)*dt/2.0;
+ A(2,1) = g(1,1)*dt/2.0;
+ A(2,2) = 1.0;
+ A(2,3) = g(3,1)*dt/2.0;
+ A(2,4) = -g(2,1)*dt/2.0;
+ A(3,1) = g(2,1)*dt/2.0;
+ A(3,2) = -g(3,1)*dt/2.0;
+ A(3,3) = 1.0;
+ A(3,4) = g(1,1)*dt/2.0;
+ A(4,1) = g(3,1)*dt/2.0;
+ A(4,2) = g(2,1)*dt/2.0;
+ A(4,3) = -g(1,1)*dt/2.0;
+ A(4,4) = 1.0;*/
- H(1,1) = 2.0*x(3,1);
- H(1,2) = -2.0*x(4,1);
- H(1,3) = 2.0*x(1,1);
- H(1,4) = -2.0*x(2,1);
- H(2,1) = -2.0*x(2,1);
- H(2,2) = -2.0*x(1,1);
- H(2,3) = -2.0*x(4,1);
- H(2,4) = -2.0*x(3,1);
- H(3,1) = -2.0*x(1,1);
- H(3,2) = 2.0*x(2,1);
- H(3,3) = 2.0*x(3,1);
- H(3,4) = -2.0*x(4,1);
+ A(1,2) = -omega_x;
+ A(1,3) = -omega_y;
+ A(1,4) = -omega_z;
+ A(2,1) = omega_x;
+ A(2,3) = omega_z;
+ A(2,4) = -omega_y;
+ A(3,1) = omega_y;
+ A(3,2) = -omega_z;
+ A(3,4) = omega_x;
+ A(4,1) = omega_z;
+ A(4,2) = omega_y;
+ A(4,3) = -omega_x;
+
+ x = A*x;
+ x = x/norm(x);
+
+ P = A*P*transpose(A)+Q;
+
+ //K = P*transpose(H)*inverse(H*P*transpose(H)+R);
+ K = P*inverse(P+R);
+
+ //x = x+K*(q-H*x);
+ x = x+K*(q-x);
+ x = x/norm(x);
+ //P = P-K*H*P;
+ P = P-K*P;
+ //P = P*(I-K*H);
+ //P = P-K*(H*P*transpose(H)+R)*transpose(K);
+ //P = (eye(4)-K*H)*P*transpose(eye(4)-K*H)+K*R*transpose(K);
+}
+
+void AttitudeEstimator::read()
+{
+ imu.read();
+ g(1,1) = imu.gx-0.0099;
+ g(2,1) = imu.gy+0.0693;
+ g(3,1) = imu.gz-0.0339;
+ a(1,1) = 1.0077*(imu.ax-0.0975);
+ a(2,1) = 1.0061*(imu.ay-0.0600);
+ a(3,1) = 0.9926*(imu.az-0.5156);
+ m(1,1) = 0.8838*(imu.mx+21.0631);
+ m(2,1) = 1.1537*(imu.my+8.9233);
+ m(3,1) = 0.9982*(imu.mz-11.8958);
+}
+
+void AttitudeEstimator::get_output()
+{
+ a = a/norm(a);
+ m = m/norm(m);
+
+ Matrix t1(3,1), t2(3,1), t3(3,1);
+ t1 = a;
+ //t2 = cross(a,m)/norm(cross(a,m));
+ t2 = cross(a,m);
+ t2 = t2/norm(t2);
+ t3 = cross(t1,t2);
+
+ /*Matrix BT(3,3), NT(3,3);
+ BT(1,1) = t1(1,1);
+ BT(2,1) = t1(2,1);
+ BT(3,1) = t1(3,1);
+ BT(1,2) = t2(1,1);
+ BT(2,2) = t2(2,1);
+ BT(3,2) = t2(3,1);
+ BT(1,3) = t3(1,1);
+ BT(2,3) = t3(2,1);
+ BT(3,3) = t3(3,1);
+
+ NT(1,2) = -0.3666;
+ NT(1,3) = -0.9304;
+ NT(2,2) = -0.9304;
+ NT(2,3) = 0.3666;
+ NT(3,1) = -1.0;
+
+ BN = BT*transpose(NT);*/
- z(1,1) = imu.ax/9.81;
- z(2,1) = imu.ay/9.81;
- z(3,1) = imu.az/9.81;
- x = x+A*x*dt;
- x = x/norm(x);
- P = A*P*transpose(A)+Q;
+ BN(1,1) = -t3(1,1);
+ BN(2,1) = -t3(2,1);
+ BN(3,1) = -t3(3,1);
+ BN(1,2) = -t2(1,1);
+ BN(2,2) = -t2(2,1);
+ BN(3,2) = -t2(3,1);
+ BN(1,3) = -t1(1,1);
+ BN(2,3) = -t1(2,1);
+ BN(3,3) = -t1(3,1);
+
+ /*q(4,1) = 0.0;
+
+ float tr = trace(BN);
+ if (tr > 0.0) {
+ float sqtrp1 = sqrt( tr + 1.0);
+ q(1,1) = 0.5*sqtrp1;
+ q(2,1) = (BN(2,3) - BN(3,2))/(2.0*sqtrp1);
+ q(3,1) = (BN(3,1) - BN(1,3))/(2.0*sqtrp1);
+ q(4,1) = (BN(1,2) - BN(2,1))/(2.0*sqtrp1);
+ } else {
+ if ((BN(2,2) > BN(1,1)) && (BN(2,2) > BN(3,3))) {
+ float sqdip1 = sqrt(BN(2,2) - BN(1,1) - BN(3,3) + 1.0 );
+ q(3,1) = 0.5*sqdip1;
+ if ( sqdip1 != 0 ) {
+ sqdip1 = 0.5/sqdip1;
+ }
+ q(1,1) = (BN(3,1) - BN(1,3))*sqdip1;
+ q(2,1) = (BN(1,2) + BN(2,1))*sqdip1;
+ q(4,1) = (BN(2,3) + BN(3,2))*sqdip1;
+ } else if (BN(3,3) > BN(1,1)) {
+ float sqdip1 = sqrt(BN(3,3) - BN(1,1) - BN(2,2) + 1.0 );
+ q(4,1) = 0.5*sqdip1;
+ if ( sqdip1 != 0 ) {
+ sqdip1 = 0.5/sqdip1;
+ }
+ q(1,1) = (BN(1,2) - BN(2,1))*sqdip1;
+ q(2,1) = (BN(3,1) + BN(1,3))*sqdip1;
+ q(3,1) = (BN(2,3) + BN(3,2))*sqdip1;
+ } else {
+ float sqdip1 = sqrt(BN(1,1) - BN(2,2) - BN(3,3) + 1.0 );
+ q(2,1) = 0.5*sqdip1;
+ if ( sqdip1 != 0 ) {
+ sqdip1 = 0.5/sqdip1;
+ }
+ q(1,1) = (BN(2,3) - BN(3,2))*sqdip1;
+ q(3,1) = (BN(1,2) + BN(2,1))*sqdip1;
+ q(4,1) = (BN(3,1) + BN(1,3))*sqdip1;
+ }
+ }*/
- K = P*transpose(H)*inverse(H*P*transpose(H)+R);
-
- x = x+K*(z-H*x);
- x = x/norm(x);
- P = P-K*H*P;
-}
\ No newline at end of file
+ q = dcm2quat(BN);
+
+ if((abs(x(1,1)) > abs(x(2,1))) && (abs(x(1,1)) > abs(x(3,1))) && (abs(x(1,1)) > abs(x(4,1)))) {
+ if (((x(1,1) > 0) && (q(1,1) < 0)) || ((x(1,1) < 0) && (q(1,1) > 0))) {
+ q = -q;
+ }
+ } else if ((abs(x(2,1)) > abs(x(3,1))) && (abs(x(2,1)) > abs(x(4,1)))) {
+ if (((x(2,1) > 0) && (q(2,1) < 0)) || ((x(2,1) < 0) && (q(2,1) > 0))) {
+ q = -q;
+ }
+ } else if ((abs(x(3,1)) > abs(x(4,1)))) {
+ if (((x(3,1) > 0) && (q(3,1) < 0)) || ((x(3,1) < 0) && (q(3,1) > 0))) {
+ q = -q;
+ }
+ } else {
+ if (((x(4,1) > 0) && (q(4,1) < 0)) || ((x(4,1) < 0) && (q(4,1) > 0))) {
+ q = -q;
+ }
+ }
+}
--- a/AttitudeEstimator/AttitudeEstimator.h Wed Feb 13 17:06:28 2019 +0000
+++ b/AttitudeEstimator/AttitudeEstimator.h Mon Feb 25 16:39:52 2019 +0000
@@ -16,14 +16,27 @@
// Estimate Euler angles (rad) and angular velocities (rad/s)
void estimate();
//
+ void get_output();
+ //
Matrix x;
//
- Matrix z, A, H, P, K, Q, R;
+ Matrix A, H, P, K, Q, R;
+ //
+ Matrix g, a, m;
+ //
+ Matrix q;
+ //
+ Matrix BN;
+ //
+ Matrix I;
private:
//
- float dt;
+ float dt, dt_half;
+ //
+ void read();
// IMU sensor object
LSM9DS1 imu;
+ //
};
#endif
\ No newline at end of file
--- a/LSM9DS1/LSM9DS1.cpp Wed Feb 13 17:06:28 2019 +0000
+++ b/LSM9DS1/LSM9DS1.cpp Mon Feb 25 16:39:52 2019 +0000
@@ -14,8 +14,9 @@
// Test I2C bus
if (test_i2c()) {
// Setup accelerometer and gyroscope configurations
- setup_accel();
- setup_gyro();
+ setup_gyr();
+ setup_acc();
+ setup_mag();
return true;
} else {
return false;
@@ -26,8 +27,9 @@
void LSM9DS1::read()
{
// Read accelerometer and gyroscope data
- read_accel();
- read_gyro();
+ read_acc();
+ read_gyr();
+ read_mag();
}
/** Setup I2C bus */
@@ -39,68 +41,149 @@
/** Test I2C bus */
bool LSM9DS1::test_i2c()
-{
- // Read device identity
- uint8_t device_id = read_reg(WHO_AM_I);
-
- // Check if device identity is 0x71
- if (device_id == 0x68) {
+{
+ // Register addresses
+ char reg_acc_gyr[1] = {WHO_AM_I};
+ char reg_mag[1] = {WHO_AM_I_M};
+ // Data that we're going to read
+ char data_acc_gyr[1];
+ char data_mag[1];
+
+ // Point to register address
+ i2c.write(LSM9DS1_ADDRESS_ACC_GYR, reg_acc_gyr, 1);
+ // Read data from this address
+ i2c.read(LSM9DS1_ADDRESS_ACC_GYR, data_acc_gyr, 1);
+
+ // Point to register address
+ i2c.write(LSM9DS1_ADDRESS_MAG, reg_mag, 1);
+ // Read data from this address
+ i2c.read(LSM9DS1_ADDRESS_MAG, data_mag, 1);
+
+ // Check if device identity is 0x68 (acc/gyr) and 0x3D (mag)
+ if ((data_acc_gyr[0] == 0x68) && (data_mag[0] == 0x3D)) {
return true;
} else {
return false;
}
}
-/** Setup accelerometer configurations (full-scale range) */
-void LSM9DS1::setup_accel(accel_scale a_scale)
+/** Setup gyroscope configurations (full-scale range) */
+void LSM9DS1::setup_gyr(gyr_scale g_scale)
{
- // Write configuration data
- write_reg(CTRL_REG6_XL, (0b011 << 5) | (a_scale << 3) | 0b000);
+ // Register address and data that will be writed
+ char reg_data[2] = {CTRL_REG1_G, (0b011 << 5) | (g_scale << 3) | 0b000};
+
+ // Point to register address and write data
+ i2c.write(LSM9DS1_ADDRESS_ACC_GYR, reg_data, 2);
+
+ // Adjust resolution [rad/s / bit] accordingly to choose scale
+ switch (g_scale) {
+ case GYR_SCALE_245DPS:
+ g_res = (245.0f*(PI/180.0f))/32768.0f;
+ break;
+ case GYR_SCALE_500DPS:
+ g_res = (500.0f*(PI/180.0f))/32768.0f;
+ break;
+ case GYR_SCALE_2000DPS:
+ g_res = (2000.0f*(PI/180.0f))/32768.0f;
+ break;
+ }
+}
+
+/** Setup accelerometer configurations (full-scale range) */
+void LSM9DS1::setup_acc(acc_scale a_scale)
+{
+ // Register address and data that will be writed
+ char reg_data[2] = {CTRL_REG6_XL, (0b011 << 5) | (a_scale << 3) | 0b000};
+
+ // Point to register address and write data
+ i2c.write(LSM9DS1_ADDRESS_ACC_GYR, reg_data, 2);
// Adjust resolution [m/s^2 / bit] accordingly to choose scale (g)
switch (a_scale) {
- case ACCEL_SCALE_2G:
+ case ACC_SCALE_2G:
a_res = (2.0f*GRAVITY)/32768.0f;
break;
- case ACCEL_SCALE_4G:
+ case ACC_SCALE_4G:
a_res = (4.0f*GRAVITY)/32768.0f;
break;
- case ACCEL_SCALE_8G:
+ case ACC_SCALE_8G:
a_res = (8.0f*GRAVITY)/32768.0f;
break;
- case ACCEL_SCALE_16G:
+ case ACC_SCALE_16G:
a_res = (16.0f*GRAVITY)/32768.0f;
break;
}
}
/** Setup gyroscope configurations (full-scale range) */
-void LSM9DS1::setup_gyro(gyro_scale g_scale)
+void LSM9DS1::setup_mag(mag_scale m_scale)
{
- // Write configuration data
- write_reg(CTRL_REG1_G, (0b011 << 5) | (g_scale << 3) | 0b000);
+ // Register address and data that will be writed
+ /*char reg_data[2] = {CTRL_REG2_M, (0b0 << 7) | (m_scale << 5) | 0b00000};
+
+ // Point to register address and write data
+ i2c.write(LSM9DS1_ADDRESS_MAG, reg_data, 2);*/
+
+ char cmd[4] = {
+ CTRL_REG1_M,
+ 0x10, // Default data rate, xy axes mode, and temp comp
+ m_scale << 5, // Set mag scale
+ 0 // Enable I2C, write only SPI, not LP mode, Continuous conversion mode
+ };
- // Adjust resolution [rad/s / bit] accordingly to choose scale
- switch (g_scale) {
- case GYRO_SCALE_245DPS:
- g_res = (245.0f*(PI/180.0f))/32768.0f;
+ // Write the data to the mag control registers
+ i2c.write(LSM9DS1_ADDRESS_MAG, cmd, 4);
+
+ // Adjust resolution [gauss / bit] accordingly to choosed scale
+ switch (m_scale) {
+ case MAG_SCALE_4G:
+ m_res = 400.0f/32768.0f;
break;
- case GYRO_SCALE_500DPS:
- g_res = (500.0f*(PI/180.0f))/32768.0f;
+ case MAG_SCALE_8G:
+ m_res = 800.0f/32768.0f;
break;
- case GYRO_SCALE_2000DPS:
- g_res = (2000.0f*(PI/180.0f))/32768.0f;
+ case MAG_SCALE_12G:
+ m_res = 1200.0f/32768.0f;
+ break;
+ case MAG_SCALE_16G:
+ m_res = 1600.0f/32768.0f;
break;
}
}
-/** Read accelerometer output data */
-void LSM9DS1::read_accel()
+/** Read gyroscope data */
+void LSM9DS1::read_gyr()
{
// LSM9DS1 I2C bus address
- char address = LSM9DS1_ADDRESS;
+ char address = LSM9DS1_ADDRESS_ACC_GYR;
// Register address
- char reg[1] = {OUT_X_XL_L};
+ char reg[1] = {OUT_X_L_G};
+ // Data that we're going to read
+ char data[6];
+
+ // Point to register address
+ i2c.write(address, reg, 1);
+ // Read data from this address (register address will auto-increment and all three axis information (two 8 bit data each) will be read)
+ i2c.read(address, data, 6);
+
+ // Reassemble the data (two 8 bit data into one 16 bit data)
+ int16_t gx_raw = data[0] | ( data[1] << 8 );
+ int16_t gy_raw = data[2] | ( data[3] << 8 );
+ int16_t gz_raw = data[4] | ( data[5] << 8 );
+ // Convert to SI units [rad/s]
+ gx = gx_raw * g_res;
+ gy = -gy_raw * g_res;
+ gz = gz_raw * g_res;
+}
+
+/** Read accelerometer output data */
+void LSM9DS1::read_acc()
+{
+ // LSM9DS1 I2C bus address
+ char address = LSM9DS1_ADDRESS_ACC_GYR;
+ // Register address
+ char reg[1] = {OUT_X_L_XL};
// Data that we're going to read
char data[6];
@@ -114,18 +197,18 @@
int16_t ay_raw = data[2] | ( data[3] << 8 );
int16_t az_raw = data[4] | ( data[5] << 8 );
// Convert to SI units [m/s^2]
- ax = -ay_raw * a_res;
- ay = -ax_raw * a_res;
+ ax = -ax_raw * a_res;
+ ay = ay_raw * a_res;
az = -az_raw * a_res;
}
-/** Read gyroscope data */
-void LSM9DS1::read_gyro()
+/** Read magnetometer output data */
+void LSM9DS1::read_mag()
{
// LSM9DS1 I2C bus address
- char address = LSM9DS1_ADDRESS;
+ char address = LSM9DS1_ADDRESS_MAG;
// Register address
- char reg[1] = {OUT_X_G_L};
+ char reg[1] = {OUT_X_L_M};
// Data that we're going to read
char data[6];
@@ -135,38 +218,11 @@
i2c.read(address, data, 6);
// Reassemble the data (two 8 bit data into one 16 bit data)
- int16_t gx_raw = data[0] | ( data[1] << 8 );
- int16_t gy_raw = data[2] | ( data[3] << 8 );
- int16_t gz_raw = data[4] | ( data[5] << 8 );
- // Convert to SI units [rad/s]
- gx = gy_raw * g_res;
- gy = gx_raw * g_res;
- gz = gz_raw * g_res;
-}
-
-/** Write data into register on LSM9DS1 I2C bus address */
-void LSM9DS1::write_reg(uint8_t reg, uint8_t data)
-{
- // Register address and data that will be writed
- char i2c_reg_data[2] = {reg, data};
-
- // Point to register address and write data
- i2c.write(LSM9DS1_ADDRESS, i2c_reg_data, 2);
-}
-
-/** Read data from register on LSM9DS1 I2C bus address */
-char LSM9DS1::read_reg(uint8_t reg)
-{
- // Register address
- char i2c_reg[1] = {reg};
- // Data that will be readed
- char i2c_data[1];
-
- // Point to register address
- i2c.write(LSM9DS1_ADDRESS, i2c_reg, 1);
- // Read data
- i2c.read(LSM9DS1_ADDRESS, i2c_data, 1);
-
- // Return readed data
- return i2c_data[0];
+ int16_t mx_raw = data[0] | ( data[1] << 8 );
+ int16_t my_raw = data[2] | ( data[3] << 8 );
+ int16_t mz_raw = data[4] | ( data[5] << 8 );
+ // Convert to SI units [m/s^2]
+ mx = -mx_raw * m_res;
+ my = -my_raw * m_res;
+ mz = mz_raw * m_res;
}
\ No newline at end of file
--- a/LSM9DS1/LSM9DS1.h Wed Feb 13 17:06:28 2019 +0000
+++ b/LSM9DS1/LSM9DS1.h Mon Feb 25 16:39:52 2019 +0000
@@ -8,46 +8,68 @@
#define PI 3.14159f
// LSM9DS1 I2C bus address
-#define LSM9DS1_ADDRESS 0xD6
+#define LSM9DS1_ADDRESS_ACC_GYR 0x6B << 1 // (0xD6) Shift 1 bit left because mbed utilizes 8-bit addresses and not 7-bit
+#define LSM9DS1_ADDRESS_MAG 0x1E << 1 // (0x3C) Shift 1 bit left because mbed utilizes 8-bit addresses and not 7-bit
// Device identity
-#define WHO_AM_I 0x0F
+#define WHO_AM_I 0x0F
+#define WHO_AM_I_M 0x0F
+
+// Gyroscope configuration registers addresses
+#define CTRL_REG1_G 0x10
+// Gyroscope output register addresses
+#define OUT_X_L_G 0x18
+#define OUT_X_H_G 0x19
+#define OUT_Y_L_G 0x1A
+#define OUT_Y_H_G 0x1B
+#define OUT_Z_L_G 0x1C
+#define OUT_Z_H_G 0x1D
// Accelerometer configuration registers addresses
#define CTRL_REG6_XL 0x20
// Accelerometer output register addresses
-#define OUT_X_XL_L 0x28
-#define OUT_X_XL_H 0x29
-#define OUT_Y_XL_L 0x2A
-#define OUT_Y_XL_H 0x2B
-#define OUT_Z_XL_L 0x2C
-#define OUT_Z_XL_H 0x2D
+#define OUT_X_L_XL 0x28
+#define OUT_X_H_XL 0x29
+#define OUT_Y_L_XL 0x2A
+#define OUT_Y_H_XL 0x2B
+#define OUT_Z_L_XL 0x2C
+#define OUT_Z_H_XL 0x2D
-// Gyroscope configuration registers addresses
-#define CTRL_REG1_G 0x10
-// Accelerometer output register addresses
-#define OUT_X_G_L 0x18
-#define OUT_X_G_H 0x19
-#define OUT_Y_G_L 0x1A
-#define OUT_Y_G_H 0x1B
-#define OUT_Z_G_L 0x1C
-#define OUT_Z_G_H 0x1D
+// Magnetometer configuration registers addresses
+#define CTRL_REG1_M 0x20
+#define CTRL_REG2_M 0x21
+// Magnetometer output register addresses
+#define OUT_X_L_M 0x28
+#define OUT_X_H_M 0x29
+#define OUT_Y_L_M 0x2A
+#define OUT_Y_H_M 0x2B
+#define OUT_Z_L_M 0x2C
+#define OUT_Z_H_M 0x2D
+
+// Gyroscope full-scale ranges
+enum gyr_scale
+{
+ GYR_SCALE_245DPS = 0b00,
+ GYR_SCALE_500DPS = 0b01,
+ GYR_SCALE_2000DPS = 0b11
+};
// Accelerometer full-scale ranges
-enum accel_scale
+enum acc_scale
{
- ACCEL_SCALE_2G = 0b00,
- ACCEL_SCALE_4G = 0b10,
- ACCEL_SCALE_8G = 0b11,
- ACCEL_SCALE_16G = 0b01
+ ACC_SCALE_2G = 0b00,
+ ACC_SCALE_4G = 0b10,
+ ACC_SCALE_8G = 0b11,
+ ACC_SCALE_16G = 0b01
};
-// Gyroscope full-scale ranges
-enum gyro_scale
+// Magnetometer full-scale ranges
+enum mag_scale
{
- GYRO_SCALE_245DPS = 0b00,
- GYRO_SCALE_500DPS = 0b01,
- GYRO_SCALE_2000DPS = 0b11
+ MAG_SCALE_4G = 0b00,
+ MAG_SCALE_8G = 0b01,
+ MAG_SCALE_12G = 0b10,
+ MAG_SCALE_16G = 0b11
};
/** LSM9DS1 (IMU sensor) class
@@ -67,8 +89,9 @@
* while(1)
* {
* imu.read();
- * pc.printf("Accel [m/s^2]: %6.2f %6.2f %6.2f \n", imu.ax, imu.ay, imu.az);
- * pc.printf("Gyro [rad/s]: %6.2f %6.2f %6.2f \n\n", imu.gx, imu.gy, imu.gz);
+ pc.printf("Acc [m/s^2]: %.1f | %.1f | %.1f \n", imu.ax, imu.ay, imu.az);
+ pc.printf("Gyr [rad/s]: %.1f | %.1f | %.1f \n", imu.gx, imu.gy, imu.gz);
+ pc.printf("Mag [uT]: %.1f | %.1f | %.1f \n\n", imu.mx, imu.my, imu.mz);
* wait(0.2);
* }
* }
@@ -78,6 +101,7 @@
class LSM9DS1
{
public:
+
/** Class constructor */
LSM9DS1(PinName sda, PinName scl);
@@ -86,19 +110,27 @@
/** Read sensor data */
void read();
+ /** Gyroscope data in x-axis [rad/s]*/
+ float gx;
+ /** Gyroscope data in y-axis [rad/s]*/
+ float gy;
+ /** Gyroscope data in z-axis [rad/s]*/
+ float gz;
/** Accelerometer data in x-axis [m/s^2]*/
float ax;
/** Accelerometer data in y-axis [m/s^2]*/
float ay;
/** Accelerometer data in z-axis [m/s^2]*/
float az;
- /** Gyroscope data in x-axis [rad/s]*/
- float gx;
- /** Gyroscope data in y-axis [rad/s]*/
- float gy;
- /** Gyroscope data in z-axis [rad/s]*/
- float gz;
+ /** Magnetometer data in x-axis [??]*/
+ float mx;
+ /** Magnetometer data in y-axis [??]*/
+ float my;
+ /** Magnetometer data in z-axis [??]*/
+ float mz;
+
private:
+
/** I2C bus */
I2C i2c;
@@ -107,24 +139,26 @@
/** Test I2C bus */
bool test_i2c();
+ /** Setup gyroscope configurations (full-scale range) */
+ void setup_gyr(gyr_scale g_scale = GYR_SCALE_2000DPS);
/** Setup accelerometer configurations (full-scale range) */
- void setup_accel(accel_scale a_scale = ACCEL_SCALE_2G);
- /** Setup gyroscope configurations (full-scale range) */
- void setup_gyro(gyro_scale g_scale = GYRO_SCALE_245DPS);
- /** Read accelerometer data */
- void read_accel();
+ void setup_acc(acc_scale a_scale = ACC_SCALE_2G);
+ /** Setup magnetometer configurations (full-scale range) */
+ void setup_mag(mag_scale m_scale = MAG_SCALE_4G);
+
/** Read gyroscope data */
- void read_gyro();
+ void read_gyr();
+ /** Read accelerometer data */
+ void read_acc();
+ /** Read magnetometer data */
+ void read_mag();
- /** Write data into register on LSM9DS1 I2C bus address */
- void write_reg(uint8_t reg, uint8_t data);
- /** Read data from register on LSM9DS1 I2C bus address */
- char read_reg(uint8_t reg);
-
+ /** Gyroscope resolution [rad/s / bit] */
+ float g_res;
/** Accelerometer resolution [m/s^2 / bit] */
float a_res;
- /** Gyroscope resolution [rad/s / bit] */
- float g_res;
+ /** Magnetometers resolution [uT / bit] */
+ float m_res;
};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MadgwickAHRS/MadgwickAHRS.cpp Mon Feb 25 16:39:52 2019 +0000
@@ -0,0 +1,227 @@
+//=====================================================================================================
+// MadgwickAHRS.c
+//=====================================================================================================
+//
+// Implementation of Madgwick's IMU and AHRS algorithms.
+// See: http://www.x-io.co.uk/node/8#open_source_ahrs_and_imu_algorithms
+//
+// Date Author Notes
+// 29/09/2011 SOH Madgwick Initial release
+// 02/10/2011 SOH Madgwick Optimised for reduced CPU load
+// 19/02/2012 SOH Madgwick Magnetometer measurement is normalised
+//
+//=====================================================================================================
+
+//---------------------------------------------------------------------------------------------------
+// Header files
+
+#include "MadgwickAHRS.h"
+#include <math.h>
+
+//---------------------------------------------------------------------------------------------------
+// Definitions
+
+#define sampleFreq 512.0f // sample frequency in Hz
+#define betaDef 0.1f // 2 * proportional gain
+
+//---------------------------------------------------------------------------------------------------
+// Variable definitions
+
+volatile float beta = betaDef; // 2 * proportional gain (Kp)
+volatile float q0 = 1.0f, q1 = 0.0f, q2 = 0.0f, q3 = 0.0f; // quaternion of sensor frame relative to auxiliary frame
+
+//---------------------------------------------------------------------------------------------------
+// Function declarations
+
+float invSqrt(float x);
+
+//====================================================================================================
+// Functions
+
+//---------------------------------------------------------------------------------------------------
+// AHRS algorithm update
+
+void MadgwickAHRSupdate(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz) {
+ float recipNorm;
+ float s0, s1, s2, s3;
+ float qDot1, qDot2, qDot3, qDot4;
+ float hx, hy;
+ float _2q0mx, _2q0my, _2q0mz, _2q1mx, _2bx, _2bz, _4bx, _4bz, _2q0, _2q1, _2q2, _2q3, _2q0q2, _2q2q3, q0q0, q0q1, q0q2, q0q3, q1q1, q1q2, q1q3, q2q2, q2q3, q3q3;
+
+ // Use IMU algorithm if magnetometer measurement invalid (avoids NaN in magnetometer normalisation)
+ if((mx == 0.0f) && (my == 0.0f) && (mz == 0.0f)) {
+ MadgwickAHRSupdateIMU(gx, gy, gz, ax, ay, az);
+ return;
+ }
+
+ // Rate of change of quaternion from gyroscope
+ qDot1 = 0.5f * (-q1 * gx - q2 * gy - q3 * gz);
+ qDot2 = 0.5f * (q0 * gx + q2 * gz - q3 * gy);
+ qDot3 = 0.5f * (q0 * gy - q1 * gz + q3 * gx);
+ qDot4 = 0.5f * (q0 * gz + q1 * gy - q2 * gx);
+
+ // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation)
+ if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) {
+
+ // Normalise accelerometer measurement
+ recipNorm = invSqrt(ax * ax + ay * ay + az * az);
+ ax *= recipNorm;
+ ay *= recipNorm;
+ az *= recipNorm;
+
+ // Normalise magnetometer measurement
+ recipNorm = invSqrt(mx * mx + my * my + mz * mz);
+ mx *= recipNorm;
+ my *= recipNorm;
+ mz *= recipNorm;
+
+ // Auxiliary variables to avoid repeated arithmetic
+ _2q0mx = 2.0f * q0 * mx;
+ _2q0my = 2.0f * q0 * my;
+ _2q0mz = 2.0f * q0 * mz;
+ _2q1mx = 2.0f * q1 * mx;
+ _2q0 = 2.0f * q0;
+ _2q1 = 2.0f * q1;
+ _2q2 = 2.0f * q2;
+ _2q3 = 2.0f * q3;
+ _2q0q2 = 2.0f * q0 * q2;
+ _2q2q3 = 2.0f * q2 * q3;
+ q0q0 = q0 * q0;
+ q0q1 = q0 * q1;
+ q0q2 = q0 * q2;
+ q0q3 = q0 * q3;
+ q1q1 = q1 * q1;
+ q1q2 = q1 * q2;
+ q1q3 = q1 * q3;
+ q2q2 = q2 * q2;
+ q2q3 = q2 * q3;
+ q3q3 = q3 * q3;
+
+ // Reference direction of Earth's magnetic field
+ hx = mx * q0q0 - _2q0my * q3 + _2q0mz * q2 + mx * q1q1 + _2q1 * my * q2 + _2q1 * mz * q3 - mx * q2q2 - mx * q3q3;
+ hy = _2q0mx * q3 + my * q0q0 - _2q0mz * q1 + _2q1mx * q2 - my * q1q1 + my * q2q2 + _2q2 * mz * q3 - my * q3q3;
+ _2bx = sqrt(hx * hx + hy * hy);
+ _2bz = -_2q0mx * q2 + _2q0my * q1 + mz * q0q0 + _2q1mx * q3 - mz * q1q1 + _2q2 * my * q3 - mz * q2q2 + mz * q3q3;
+ _4bx = 2.0f * _2bx;
+ _4bz = 2.0f * _2bz;
+
+ // Gradient decent algorithm corrective step
+ s0 = -_2q2 * (2.0f * q1q3 - _2q0q2 - ax) + _2q1 * (2.0f * q0q1 + _2q2q3 - ay) - _2bz * q2 * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (-_2bx * q3 + _2bz * q1) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + _2bx * q2 * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz);
+ s1 = _2q3 * (2.0f * q1q3 - _2q0q2 - ax) + _2q0 * (2.0f * q0q1 + _2q2q3 - ay) - 4.0f * q1 * (1 - 2.0f * q1q1 - 2.0f * q2q2 - az) + _2bz * q3 * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (_2bx * q2 + _2bz * q0) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + (_2bx * q3 - _4bz * q1) * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz);
+ s2 = -_2q0 * (2.0f * q1q3 - _2q0q2 - ax) + _2q3 * (2.0f * q0q1 + _2q2q3 - ay) - 4.0f * q2 * (1 - 2.0f * q1q1 - 2.0f * q2q2 - az) + (-_4bx * q2 - _2bz * q0) * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (_2bx * q1 + _2bz * q3) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + (_2bx * q0 - _4bz * q2) * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz);
+ s3 = _2q1 * (2.0f * q1q3 - _2q0q2 - ax) + _2q2 * (2.0f * q0q1 + _2q2q3 - ay) + (-_4bx * q3 + _2bz * q1) * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (-_2bx * q0 + _2bz * q2) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + _2bx * q1 * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz);
+ recipNorm = invSqrt(s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3); // normalise step magnitude
+ s0 *= recipNorm;
+ s1 *= recipNorm;
+ s2 *= recipNorm;
+ s3 *= recipNorm;
+
+ // Apply feedback step
+ qDot1 -= beta * s0;
+ qDot2 -= beta * s1;
+ qDot3 -= beta * s2;
+ qDot4 -= beta * s3;
+ }
+
+ // Integrate rate of change of quaternion to yield quaternion
+ q0 += qDot1 * (1.0f / sampleFreq);
+ q1 += qDot2 * (1.0f / sampleFreq);
+ q2 += qDot3 * (1.0f / sampleFreq);
+ q3 += qDot4 * (1.0f / sampleFreq);
+
+ // Normalise quaternion
+ recipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
+ q0 *= recipNorm;
+ q1 *= recipNorm;
+ q2 *= recipNorm;
+ q3 *= recipNorm;
+}
+
+//---------------------------------------------------------------------------------------------------
+// IMU algorithm update
+
+void MadgwickAHRSupdateIMU(float gx, float gy, float gz, float ax, float ay, float az) {
+ float recipNorm;
+ float s0, s1, s2, s3;
+ float qDot1, qDot2, qDot3, qDot4;
+ float _2q0, _2q1, _2q2, _2q3, _4q0, _4q1, _4q2 ,_8q1, _8q2, q0q0, q1q1, q2q2, q3q3;
+
+ // Rate of change of quaternion from gyroscope
+ qDot1 = 0.5f * (-q1 * gx - q2 * gy - q3 * gz);
+ qDot2 = 0.5f * (q0 * gx + q2 * gz - q3 * gy);
+ qDot3 = 0.5f * (q0 * gy - q1 * gz + q3 * gx);
+ qDot4 = 0.5f * (q0 * gz + q1 * gy - q2 * gx);
+
+ // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation)
+ if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) {
+
+ // Normalise accelerometer measurement
+ recipNorm = invSqrt(ax * ax + ay * ay + az * az);
+ ax *= recipNorm;
+ ay *= recipNorm;
+ az *= recipNorm;
+
+ // Auxiliary variables to avoid repeated arithmetic
+ _2q0 = 2.0f * q0;
+ _2q1 = 2.0f * q1;
+ _2q2 = 2.0f * q2;
+ _2q3 = 2.0f * q3;
+ _4q0 = 4.0f * q0;
+ _4q1 = 4.0f * q1;
+ _4q2 = 4.0f * q2;
+ _8q1 = 8.0f * q1;
+ _8q2 = 8.0f * q2;
+ q0q0 = q0 * q0;
+ q1q1 = q1 * q1;
+ q2q2 = q2 * q2;
+ q3q3 = q3 * q3;
+
+ // Gradient decent algorithm corrective step
+ s0 = _4q0 * q2q2 + _2q2 * ax + _4q0 * q1q1 - _2q1 * ay;
+ s1 = _4q1 * q3q3 - _2q3 * ax + 4.0f * q0q0 * q1 - _2q0 * ay - _4q1 + _8q1 * q1q1 + _8q1 * q2q2 + _4q1 * az;
+ s2 = 4.0f * q0q0 * q2 + _2q0 * ax + _4q2 * q3q3 - _2q3 * ay - _4q2 + _8q2 * q1q1 + _8q2 * q2q2 + _4q2 * az;
+ s3 = 4.0f * q1q1 * q3 - _2q1 * ax + 4.0f * q2q2 * q3 - _2q2 * ay;
+ recipNorm = invSqrt(s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3); // normalise step magnitude
+ s0 *= recipNorm;
+ s1 *= recipNorm;
+ s2 *= recipNorm;
+ s3 *= recipNorm;
+
+ // Apply feedback step
+ qDot1 -= beta * s0;
+ qDot2 -= beta * s1;
+ qDot3 -= beta * s2;
+ qDot4 -= beta * s3;
+ }
+
+ // Integrate rate of change of quaternion to yield quaternion
+ q0 += qDot1 * (1.0f / sampleFreq);
+ q1 += qDot2 * (1.0f / sampleFreq);
+ q2 += qDot3 * (1.0f / sampleFreq);
+ q3 += qDot4 * (1.0f / sampleFreq);
+
+ // Normalise quaternion
+ recipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
+ q0 *= recipNorm;
+ q1 *= recipNorm;
+ q2 *= recipNorm;
+ q3 *= recipNorm;
+}
+
+//---------------------------------------------------------------------------------------------------
+// Fast inverse square-root
+// See: http://en.wikipedia.org/wiki/Fast_inverse_square_root
+
+float invSqrt(float x) {
+ float halfx = 0.5f * x;
+ float y = x;
+ long i = *(long*)&y;
+ i = 0x5f3759df - (i>>1);
+ y = *(float*)&i;
+ y = y * (1.5f - (halfx * y * y));
+ return y;
+}
+
+//====================================================================================================
+// END OF CODE
+//====================================================================================================
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MadgwickAHRS/MadgwickAHRS.h Mon Feb 25 16:39:52 2019 +0000 @@ -0,0 +1,31 @@ +//===================================================================================================== +// MadgwickAHRS.h +//===================================================================================================== +// +// Implementation of Madgwick's IMU and AHRS algorithms. +// See: http://www.x-io.co.uk/node/8#open_source_ahrs_and_imu_algorithms +// +// Date Author Notes +// 29/09/2011 SOH Madgwick Initial release +// 02/10/2011 SOH Madgwick Optimised for reduced CPU load +// +//===================================================================================================== +#ifndef MadgwickAHRS_h +#define MadgwickAHRS_h + +//---------------------------------------------------------------------------------------------------- +// Variable declaration + +extern volatile float beta; // algorithm gain +extern volatile float q0, q1, q2, q3; // quaternion of sensor frame relative to auxiliary frame + +//--------------------------------------------------------------------------------------------------- +// Function declarations + +void MadgwickAHRSupdate(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz); +void MadgwickAHRSupdateIMU(float gx, float gy, float gz, float ax, float ay, float az); + +#endif +//===================================================================================================== +// End of file +//=====================================================================================================
--- a/Matrix/Matrix.cpp Wed Feb 13 17:06:28 2019 +0000
+++ b/Matrix/Matrix.cpp Mon Feb 25 16:39:52 2019 +0000
@@ -1,26 +1,27 @@
#include "Matrix.h"
-Matrix::Matrix() : _rows(1), _cols(1)
+Matrix::Matrix()
{
+ // Set matrix size
+ rows = 1;
+ cols = 1;
// Allocate memory
- _data = (float **)malloc(sizeof(float *));
- _data[0] = (float *)malloc(sizeof(float));
- // Initialize values
- _data[0][0] = 0.0;
+ allocate_memmory();
+ // Initialize data
+ data[0][0] = 0.0;
}
-Matrix::Matrix(int rows, int cols) : _rows(rows), _cols(cols)
+Matrix::Matrix(int r, int c)
{
-
+ // Set matrix size
+ rows = r;
+ cols = c;
// Allocate memory
- _data = (float **)malloc(_rows * sizeof(float *)); // = new float*[_rows];
- for (int i = 1; i <= _rows; i++) {
- _data[i-1] = (float *)malloc(_cols * sizeof(float)); // = new float[_cols];
- }
- // Initialize values
- for (int i = 1; i <= _rows; i++) {
- for (int j = 1; j <= _cols; j++) {
- _data[i-1][j-1] = 0.0;
+ allocate_memmory();
+ // Initialize data
+ for (int i = 0; i < rows; i++) {
+ for (int j = 0; j < cols; j++) {
+ data[i][j] = 0.0;
}
}
}
@@ -28,55 +29,57 @@
Matrix::~Matrix()
{
// Free memory
- for (int i = 1; i <= _rows; i++) {
- free(_data[i-1]);
- }
- free(_data);
+ deallocate_memmory();
}
Matrix& Matrix::operator=(const Matrix& m)
{
- for (int i = 1; i <= _rows; i++) {
- for (int j = 1; j <= _cols; j++) {
- _data[i-1][j-1] = m._data[i-1][j-1];
+ // Re-allocate memmory (in case size is different)
+ if (rows != m.rows || cols != m.cols) {
+ deallocate_memmory();
+ rows = m.rows;
+ cols = m.cols;
+ allocate_memmory();
+ }
+ // Copy data
+ for (int i = 0; i < rows; i++) {
+ for (int j = 0; j < cols; j++) {
+ data[i][j] = m.data[i][j];
}
}
return *this;
}
-float& Matrix::operator()(int row, int col)
+float& Matrix::operator()(int r, int c)
{
// Return cell data
- return _data[row-1][col-1];
+ return data[r-1][c-1];
+}
+
+void Matrix::allocate_memmory()
+{
+ data = (float **)malloc(rows * sizeof(float *));
+ for (int i = 0; i < rows; i++) {
+ data[i] = (float *)malloc(cols * sizeof(float));
+ }
+}
+
+void Matrix::deallocate_memmory()
+{
+ for (int i = 0; i < rows; i++) {
+ free(data[i]);
+ }
+ free(data);
}
Matrix operator+(const Matrix& A, const Matrix& B)
{
- /*// Auxiliary matrix where C = A+B
- Matrix C(A._rows,A._cols);
- for (int i = 1; i <= A._rows; i++)
- {
- for (int j = 1; j <= A._cols; j++)
- {
- C._data[i-1][j-1] += A._data[i-1][j-1]+B._data[i-1][j-1];
- }
- }
- return C;
- */
-
- /*Matrix temp(m1);
- return (temp += m2);
- */
-
- //Matrix A(m1);
- //Matrix B(m2);
- Matrix C(A._rows,A._cols);
- for (int i = 1; i <= A._rows; i++)
- {
- for (int j = 1; j <= A._cols; j++)
- {
- C._data[i-1][j-1] += A._data[i-1][j-1]+B._data[i-1][j-1];
- }
+ // Auxiliary matrix where C = A+B
+ Matrix C(A.rows,A.cols);
+ for (int i = 0; i < C.rows; i++) {
+ for (int j = 0; j < C.cols; j++) {
+ C.data[i][j] = A.data[i][j]+B.data[i][j];
+ }
}
return C;
}
@@ -84,10 +87,22 @@
Matrix operator-(const Matrix& A, const Matrix& B)
{
// Auxiliary matrix where C = A-B
- Matrix C(A._rows,A._cols);
- for (int i = 1; i <= A._rows; i++) {
- for (int j = 1; j <= A._cols; j++) {
- C._data[i-1][j-1] += A._data[i-1][j-1]-B._data[i-1][j-1];
+ Matrix C(A.rows,A.cols);
+ for (int i = 0; i < C.rows; i++) {
+ for (int j = 0; j < C.cols; j++) {
+ C.data[i][j] = A.data[i][j]-B.data[i][j];
+ }
+ }
+ return C;
+}
+
+Matrix operator-(const Matrix& A)
+{
+ // Auxiliary matrix where C = -A
+ Matrix C(A.rows,A.cols);
+ for (int i = 0; i < C.rows; i++) {
+ for (int j = 0; j < C.cols; j++) {
+ C.data[i][j] = -A.data[i][j];
}
}
return C;
@@ -96,109 +111,134 @@
Matrix operator*(const Matrix& A, const Matrix& B)
{
// Auxiliary matrix where C = A*B
- Matrix C(A._rows,B._cols);
- for (int i = 1; i <= A._rows; i++) {
- for (int j = 1; j <= B._cols; j++) {
- for (int k = 1; k <= A._cols; k++) {
- C._data[i-1][j-1] += A._data[i-1][k-1]*B._data[k-1][j-1];
+ Matrix C(A.rows,B.cols);
+ for (int i = 0; i < A.rows; i++) {
+ for (int j = 0; j < B.cols; j++) {
+ for (int k = 0; k < A.cols; k++) {
+ C.data[i][j] += A.data[i][k]*B.data[k][j];
}
}
}
return C;
}
-Matrix operator*(float scalar, const Matrix& A)
+Matrix operator*(float k, const Matrix& A)
{
- // Auxiliary matrix where C = scalar*A
- Matrix C(A._rows,A._cols);
- for (int i = 1; i <= A._rows; i++) {
- for (int j = 1; j <= A._cols; j++) {
- C._data[i-1][j-1] += scalar*A._data[i-1][j-1];
+ // Auxiliary matrix where B = k*A
+ Matrix B(A.rows,A.cols);
+ for (int i = 0; i < B.rows; i++) {
+ for (int j = 0; j < B.cols; j++) {
+ B.data[i][j] = k*A.data[i][j];
}
}
- return C;
+ return B;
+}
+
+Matrix operator*(const Matrix& A, float k)
+{
+ // Auxiliary matrix where B = A*k
+ Matrix B(A.rows,A.cols);
+ for (int i = 0; i < B.rows; i++) {
+ for (int j = 0; j < B.cols; j++) {
+ B.data[i][j] = A.data[i][j]*k;
+ }
+ }
+ return B;
}
-Matrix operator*(const Matrix& A, float scalar)
+Matrix operator/(const Matrix& A, float k)
{
- // Auxiliary matrix where C = scalar*A
- Matrix C(A._rows,A._cols);
- for (int i = 1; i <= A._rows; i++) {
- for (int j = 1; j <= A._cols; j++) {
- C._data[i-1][j-1] += A._data[i-1][j-1]*scalar;
+ // Auxiliary matrix where B = A/k
+ Matrix B(A.rows,A.cols);
+ for (int i = 0; i < B.rows; i++) {
+ for (int j = 0; j < B.cols; j++) {
+ B.data[i][j] = A.data[i][j]/k;
}
}
- return C;
+ return B;
}
-Matrix operator/(const Matrix& A, float scalar)
+Matrix eye(int r, int c)
{
- // Auxiliary matrix where C = scalar*A
- Matrix C(A._rows,A._cols);
- for (int i = 1; i <= A._rows; i++) {
- for (int j = 1; j <= A._cols; j++) {
- C._data[i-1][j-1] += A._data[i-1][j-1]/scalar;
+ if (c == 0) {
+ c = r;
+ }
+ Matrix m(r, c);
+ for (int i = 0; i < m.rows; i++) {
+ for (int j = 0; j < m.cols; j++) {
+ if (i == j) {
+ m.data[i][j] = 1.0;
+ }
}
}
- return C;
+ return m;
+}
+
+Matrix zeros(int r, int c)
+{
+ if (c == 0) {
+ c = r;
+ }
+ Matrix m(r, c);
+ return m;
}
Matrix transpose(const Matrix& A)
{
- // Auxiliary matrix where C = A'
- Matrix C(A._cols, A._rows);
- for (int i = 1; i <= C._rows; i++) {
- for (int j = 1; j <= C._cols; j++) {
- C._data[i-1][j-1] = A._data[j-1][i-1];
+ // Auxiliary matrix where B = A'
+ Matrix B(A.cols, A.rows);
+ for (int i = 0; i < B.rows; i++) {
+ for (int j = 0; j < B.cols; j++) {
+ B.data[i][j] = A.data[j][i];
}
}
- return C;
+ return B;
}
Matrix inverse(const Matrix& A)
{
// Apply A = LDL' factorization where L is a lower triangular matrix and D
// is a block diagonal matrix
- Matrix L(A._cols, A._rows);
- Matrix D(A._cols, A._rows);
+ Matrix L(A.rows, A.cols);
+ Matrix D(A.rows, A.cols);
float L_sum;
float D_sum;
- for (int i = 1; i <= A._rows; i++) {
- for (int j = 1; j <= A._rows; j++) {
+ for (int i = 0; i < A.rows; i++) {
+ for (int j = 0; j < A.rows; j++) {
if (i >= j) {
if (i == j) {
- L._data[i-1][j-1] = 1.0;
+ L.data[i][j] = 1.0;
D_sum = 0.0;
- for (int k = 1; k <= (i-1); k++) {
- D_sum += L._data[i-1][k-1]*L._data[i-1][k-1]*D._data[k-1][k-1];
+ for (int k = 0; k <= (i-1); k++) {
+ D_sum += L.data[i][k]*L.data[i][k]*D.data[k][k];
}
- D._data[i-1][j-1] = A._data[i-1][j-1] - D_sum;
+ D.data[i][j] = A.data[i][j] - D_sum;
} else {
L_sum = 0.0;
- for (int k = 1; k <= (j-1); k++) {
- L_sum += L._data[i-1][k-1]*L._data[j-1][k-1]*D._data[k-1][k-1];
+ for (int k = 0; k <= (j-1); k++) {
+ L_sum += L.data[i][k]*L.data[j][k]*D.data[k][k];
}
- L._data[i-1][j-1] = (1.0/D._data[j-1][j-1])*(A._data[i-1][j-1]-L_sum);
+ L.data[i][j] = (1.0/D.data[j][j])*(A.data[i][j]-L_sum);
}
}
}
}
// Compute the inverse of L and D matrices
- Matrix L_inv(A._cols, A._rows);
- Matrix D_inv(A._cols, A._rows);
+ Matrix L_inv(A.rows, A.cols);
+ Matrix D_inv(A.rows, A.cols);
float L_inv_sum;
- for (int i = 1; i <= A._rows; i++) {
- for (int j = 1; j <= A._rows; j++) {
+ for (int i = 0; i < A.rows; i++) {
+ for (int j = 0; j < A.rows; j++) {
if (i >= j) {
if (i == j) {
- L_inv._data[i-1][j-1] = 1.0/L._data[i-1][j-1];
- D_inv._data[i-1][j-1] = 1.0/D._data[i-1][j-1];
+ L_inv.data[i][j] = 1.0/L.data[i][j];
+ D_inv.data[i][j] = 1.0/D.data[i][j];
} else {
L_inv_sum = 0.0;
for (int k = j; k <= (i-1); k++) {
- L_inv_sum += L._data[i-1][k-1]*L_inv._data[k-1][j-1];
+ L_inv_sum += L.data[i][k]*L_inv.data[k][j];
}
- L_inv._data[i-1][j-1] = -L_inv_sum;
+ L_inv.data[i][j] = -L_inv_sum;
}
}
}
@@ -208,13 +248,73 @@
return transpose(L_inv)*D_inv*L_inv;
}
+float trace(const Matrix& A)
+{
+ float t = 0.0;
+ for (int i = 0; i < A.rows; i++) {
+ t += A.data[i][i];
+ }
+ return t;
+}
+
+Matrix cross(const Matrix& u, const Matrix& v)
+{
+ // Auxiliary matrix where w = uXv
+ Matrix w(u.rows,u.cols);
+ w.data[0][0] = u.data[1][0]*v.data[2][0]-u.data[2][0]*v.data[1][0];
+ w.data[1][0] = u.data[2][0]*v.data[0][0]-u.data[0][0]*v.data[2][0];
+ w.data[2][0] = u.data[0][0]*v.data[1][0]-u.data[1][0]*v.data[0][0];
+ return w;
+}
+
float norm(const Matrix& A)
{
- // Auxiliary matrix where C = A'
- float n;
- n = 0.0;
- for (int i = 1; i <= A._rows; i++) {
- n += A._data[i-1][0]*A._data[i-1][0];
- }
+ float n = 0.0;
+ for (int i = 0; i < A.rows; i++) {
+ n += A.data[i][0]*A.data[i][0];
+ }
return sqrt(n);
}
+
+Matrix dcm2quat(const Matrix& R)
+{
+ Matrix q(4, 1);
+ float tr = trace(R);
+ if (tr > 0.0) {
+ float sqtrp1 = sqrt( tr + 1.0);
+ q.data[0][0] = 0.5*sqtrp1;
+ q.data[1][0] = (R.data[1][2] - R.data[2][1])/(2.0*sqtrp1);
+ q.data[2][0] = (R.data[2][0] - R.data[0][2])/(2.0*sqtrp1);
+ q.data[3][0] = (R.data[0][1] - R.data[1][0])/(2.0*sqtrp1);
+ } else {
+ if ((R.data[1][1] > R.data[0][0]) && (R.data[1][1] > R.data[2][2])) {
+ float sqdip1 = sqrt(R.data[1][1] - R.data[0][0] - R.data[2][2] + 1.0 );
+ q.data[2][0] = 0.5*sqdip1;
+ if ( sqdip1 != 0 ) {
+ sqdip1 = 0.5/sqdip1;
+ }
+ q.data[0][0] = (R.data[2][0] - R.data[0][2])*sqdip1;
+ q.data[1][0] = (R.data[0][1] + R.data[1][0])*sqdip1;
+ q.data[3][0] = (R.data[1][2] + R.data[2][1])*sqdip1;
+ } else if (R.data[2][2] > R.data[0][0]) {
+ float sqdip1 = sqrt(R.data[2][2] - R.data[0][0] - R.data[1][1] + 1.0 );
+ q.data[3][0] = 0.5*sqdip1;
+ if ( sqdip1 != 0 ) {
+ sqdip1 = 0.5/sqdip1;
+ }
+ q.data[0][0] = (R.data[0][1] - R.data[1][0])*sqdip1;
+ q.data[1][0] = (R.data[2][0] + R.data[0][2])*sqdip1;
+ q.data[2][0] = (R.data[1][2] + R.data[2][1])*sqdip1;
+ } else {
+ float sqdip1 = sqrt(R.data[0][0] - R.data[1][1] - R.data[2][2] + 1.0 );
+ q.data[1][0] = 0.5*sqdip1;
+ if ( sqdip1 != 0 ) {
+ sqdip1 = 0.5/sqdip1;
+ }
+ q.data[0][0] = (R.data[1][2] - R.data[2][1])*sqdip1;
+ q.data[2][0] = (R.data[0][1] + R.data[1][0])*sqdip1;
+ q.data[3][0] = (R.data[2][0] + R.data[0][2])*sqdip1;
+ }
+ }
+ return q;
+}
\ No newline at end of file
--- a/Matrix/Matrix.h Wed Feb 13 17:06:28 2019 +0000
+++ b/Matrix/Matrix.h Mon Feb 25 16:39:52 2019 +0000
@@ -7,32 +7,46 @@
/** Matrix class */
class Matrix
{
- public:
+public:
/** Constructors */
Matrix();
- Matrix(int rows, int cols);
+ Matrix(int, int);
/** Destructor */
~Matrix();
/** Assignment */
- Matrix& operator=(const Matrix& m);
+ Matrix& operator=(const Matrix&);
+ /** Cell data */
+ float& operator()(int, int);
/** Parameters */
- int _rows, _cols;
- float **_data;
- /** Cell data */
- float& operator()(int row, int col);
+ int rows, cols;
+ float **data;
+private:
+ /** Memmory managment **/
+ void allocate_memmory();
+ void deallocate_memmory();
};
/** Math operators */
Matrix operator+(const Matrix&, const Matrix&);
Matrix operator-(const Matrix&, const Matrix&);
+Matrix operator-(const Matrix&);
Matrix operator*(const Matrix&, const Matrix&);
Matrix operator*(float, const Matrix&);
Matrix operator*(const Matrix&, float);
Matrix operator/(const Matrix&, float);
/** Matriz algebra */
+Matrix eye(int, int = 0);
+Matrix zeros(int, int = 0);
Matrix transpose(const Matrix&);
Matrix inverse(const Matrix&);
+float trace(const Matrix&);
+
+/** Vector algebra **/
+Matrix cross(const Matrix&, const Matrix&);
float norm(const Matrix&);
+/** Orientation algebra **/
+Matrix dcm2quat(const Matrix&);
+
#endif