df

Dependencies:   mbed

Fork of APP1 by Team APP

Committer:
dupm2216
Date:
Sun Jan 15 03:32:36 2017 +0000
Revision:
8:862e28c7f6f6
Parent:
7:1e00dfecc92d
Child:
9:12519f9dd3cd
Fix NaN bug with forces > 1g; ; Problem was with forces higher than 1g because the algorithm uses arc cos with this value.; Fix is to assume the accelerometer is flat when the force is > 1g

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dupm2216 1:7becb0e903e3 1 #include "Accelerometer.hpp"
dupm2216 6:3facf0329142 2 #include "Utility.hpp"
dupm2216 1:7becb0e903e3 3
dupm2216 8:862e28c7f6f6 4 #include <cmath>
dupm2216 8:862e28c7f6f6 5
dupm2216 7:1e00dfecc92d 6 namespace accelerometer
dupm2216 5:f59b51ac4b40 7 {
dupm2216 7:1e00dfecc92d 8 //Compute inverse two's complement to obtain a signed value
dupm2216 7:1e00dfecc92d 9 //See page 21: https://www.gel.usherbrooke.ca/s5info/h17/doc/app1/file/MMA8452Q.pdf
dupm2216 7:1e00dfecc92d 10 //See: https://en.wikipedia.org/wiki/Two's_complement
dupm2216 7:1e00dfecc92d 11 //Turns out, the signed char does it for free
dupm2216 7:1e00dfecc92d 12 //We have to specify "signed char" because the "standard does not specify if plain char is signed or unsigned"
dupm2216 7:1e00dfecc92d 13 //http://stackoverflow.com/a/2054941/3212785
dupm2216 7:1e00dfecc92d 14 int raw_axis_data_to_int(signed char raw_axis_data)
dupm2216 7:1e00dfecc92d 15 {
dupm2216 7:1e00dfecc92d 16 return raw_axis_data;
dupm2216 7:1e00dfecc92d 17 }
dupm2216 7:1e00dfecc92d 18
dupm2216 7:1e00dfecc92d 19 char get_axis_register(Axis axis)
dupm2216 7:1e00dfecc92d 20 {
dupm2216 7:1e00dfecc92d 21 switch(axis)
dupm2216 7:1e00dfecc92d 22 {
dupm2216 7:1e00dfecc92d 23 case AXIS_X: return OUT_X_MSB_REGISTER;
dupm2216 7:1e00dfecc92d 24 case AXIS_Y: return OUT_Y_MSB_REGISTER;
dupm2216 7:1e00dfecc92d 25 case AXIS_Z: return OUT_Z_MSB_REGISTER;
dupm2216 7:1e00dfecc92d 26 default: return AXIS_INVALID;
dupm2216 7:1e00dfecc92d 27 }
dupm2216 7:1e00dfecc92d 28 }
dupm2216 8:862e28c7f6f6 29
dupm2216 7:1e00dfecc92d 30 double g_force_from_int_axis_data(const int axis_data)
dupm2216 1:7becb0e903e3 31 {
dupm2216 7:1e00dfecc92d 32 return (double)axis_data / 64.0;
dupm2216 7:1e00dfecc92d 33 }
dupm2216 7:1e00dfecc92d 34
dupm2216 7:1e00dfecc92d 35 //Z axis is perpendicular to the horizontal plane, towards the floor when the accelerometer is flat
dupm2216 7:1e00dfecc92d 36 //Therefore,
dupm2216 7:1e00dfecc92d 37 // - if the Z force is +1g, the accelerometer is flat
dupm2216 7:1e00dfecc92d 38 // - if the Z force is -1g, the accelerometer is upside down
dupm2216 7:1e00dfecc92d 39 // - if the Z force is 0g, the accelerometer 90 degree from the horizontal
dupm2216 8:862e28c7f6f6 40 //cos(theta) = Z force in g
dupm2216 7:1e00dfecc92d 41 double angle_from_int_axis_data(const int axis_data)
dupm2216 7:1e00dfecc92d 42 {
dupm2216 7:1e00dfecc92d 43 const double z_g_force = g_force_from_int_axis_data(axis_data);
dupm2216 8:862e28c7f6f6 44 const double absolute_z_g_force = std::fabs(z_g_force);
dupm2216 8:862e28c7f6f6 45 if(absolute_z_g_force > 1.0)
dupm2216 8:862e28c7f6f6 46 {
dupm2216 8:862e28c7f6f6 47 return 0.0;
dupm2216 8:862e28c7f6f6 48 }
dupm2216 8:862e28c7f6f6 49
dupm2216 8:862e28c7f6f6 50 const double angle_radian = std::acos(absolute_z_g_force);
dupm2216 7:1e00dfecc92d 51 return utility::degree_from_radian(angle_radian);
dupm2216 1:7becb0e903e3 52 }
dupm2216 7:1e00dfecc92d 53
dupm2216 7:1e00dfecc92d 54 Accelerometer::Accelerometer(
dupm2216 7:1e00dfecc92d 55 PinName sda_pin,
dupm2216 7:1e00dfecc92d 56 PinName scl_pin,
dupm2216 7:1e00dfecc92d 57 const int slave_address
dupm2216 7:1e00dfecc92d 58 ) :
dupm2216 7:1e00dfecc92d 59 device(sda_pin, scl_pin),
dupm2216 7:1e00dfecc92d 60 slave_address(slave_address)
dupm2216 7:1e00dfecc92d 61 {
dupm2216 7:1e00dfecc92d 62 }
dupm2216 7:1e00dfecc92d 63
dupm2216 7:1e00dfecc92d 64 void Accelerometer::write_register(const char register_address, const char new_value)
dupm2216 7:1e00dfecc92d 65 {
dupm2216 7:1e00dfecc92d 66 const int left_shifted_slave_address = slave_address << 1;
dupm2216 7:1e00dfecc92d 67 char data[2];
dupm2216 7:1e00dfecc92d 68 data[0] = register_address;
dupm2216 7:1e00dfecc92d 69 data[1] = new_value;
dupm2216 7:1e00dfecc92d 70
dupm2216 7:1e00dfecc92d 71 const int write_return = device.write(left_shifted_slave_address, data, 2);
dupm2216 7:1e00dfecc92d 72 if(write_return < 0)
dupm2216 7:1e00dfecc92d 73 {
dupm2216 7:1e00dfecc92d 74 printf("Write error: I2C error");
dupm2216 7:1e00dfecc92d 75 }
dupm2216 7:1e00dfecc92d 76 }
dupm2216 7:1e00dfecc92d 77
dupm2216 7:1e00dfecc92d 78 char Accelerometer::read_register(const char register_address)
dupm2216 1:7becb0e903e3 79 {
dupm2216 7:1e00dfecc92d 80 char result;
dupm2216 7:1e00dfecc92d 81 const int left_shifted_slave_address = slave_address << 1;
dupm2216 7:1e00dfecc92d 82
dupm2216 7:1e00dfecc92d 83 const int write_return = device.write(left_shifted_slave_address, &register_address, 1, true);
dupm2216 7:1e00dfecc92d 84 if(write_return < 0)
dupm2216 7:1e00dfecc92d 85 {
dupm2216 7:1e00dfecc92d 86 printf("Write error: I2C error");
dupm2216 7:1e00dfecc92d 87 }
dupm2216 7:1e00dfecc92d 88
dupm2216 7:1e00dfecc92d 89 const int read_return = device.read(left_shifted_slave_address, &result, 1);
dupm2216 7:1e00dfecc92d 90 if(read_return != 0)
dupm2216 7:1e00dfecc92d 91 {
dupm2216 7:1e00dfecc92d 92 printf("Read error: I2C error (nack)");
dupm2216 7:1e00dfecc92d 93 }
dupm2216 7:1e00dfecc92d 94
dupm2216 7:1e00dfecc92d 95 return result;
dupm2216 1:7becb0e903e3 96 }
dupm2216 7:1e00dfecc92d 97
dupm2216 7:1e00dfecc92d 98 //axis_data must be an array of 6 bytes
dupm2216 7:1e00dfecc92d 99 void Accelerometer::read_all_axis(signed char* axis_data)
dupm2216 1:7becb0e903e3 100 {
dupm2216 7:1e00dfecc92d 101 for(int i = 0; i < NUMBER_OF_DATA_REGISTERS; ++i)
dupm2216 7:1e00dfecc92d 102 {
dupm2216 7:1e00dfecc92d 103 const char current_register = OUT_X_MSB_REGISTER + i;
dupm2216 7:1e00dfecc92d 104 axis_data[i] = read_register(current_register);
dupm2216 7:1e00dfecc92d 105 }
dupm2216 1:7becb0e903e3 106 }
dupm2216 7:1e00dfecc92d 107
dupm2216 7:1e00dfecc92d 108 void Accelerometer::print_all_axis_data()
dupm2216 1:7becb0e903e3 109 {
dupm2216 7:1e00dfecc92d 110 signed char axis_data[NUMBER_OF_DATA_REGISTERS];
dupm2216 7:1e00dfecc92d 111 for(int i=0; i<NUMBER_OF_DATA_REGISTERS; i++)
dupm2216 7:1e00dfecc92d 112 {
dupm2216 7:1e00dfecc92d 113 axis_data[i] = 0;
dupm2216 7:1e00dfecc92d 114 }
dupm2216 7:1e00dfecc92d 115
dupm2216 7:1e00dfecc92d 116 read_all_axis(axis_data);
dupm2216 7:1e00dfecc92d 117
dupm2216 7:1e00dfecc92d 118 printf("Register content: ");
dupm2216 7:1e00dfecc92d 119 for(int i=0; i<NUMBER_OF_DATA_REGISTERS; i++)
dupm2216 7:1e00dfecc92d 120 {
dupm2216 7:1e00dfecc92d 121 const int current_data = (int)(axis_data[i]);
dupm2216 7:1e00dfecc92d 122 printf("%d, ", current_data);
dupm2216 7:1e00dfecc92d 123 }
dupm2216 7:1e00dfecc92d 124 printf("\r\n");
dupm2216 7:1e00dfecc92d 125 }
dupm2216 7:1e00dfecc92d 126
dupm2216 7:1e00dfecc92d 127 void Accelerometer::set_standby()
dupm2216 7:1e00dfecc92d 128 {
dupm2216 7:1e00dfecc92d 129 const char previous_ctrl_reg1 = read_register(CTRL_REG1_REGISTER_ADDRESS);
dupm2216 7:1e00dfecc92d 130 const char new_ctrl_reg1_value = previous_ctrl_reg1 & ~(0x01);
dupm2216 7:1e00dfecc92d 131 write_register(CTRL_REG1_REGISTER_ADDRESS, new_ctrl_reg1_value);
dupm2216 1:7becb0e903e3 132 }
dupm2216 7:1e00dfecc92d 133
dupm2216 7:1e00dfecc92d 134 void Accelerometer::set_active()
dupm2216 7:1e00dfecc92d 135 {
dupm2216 7:1e00dfecc92d 136 const char previous_ctrl_reg1 = read_register(CTRL_REG1_REGISTER_ADDRESS);
dupm2216 7:1e00dfecc92d 137 const char new_ctrl_reg1_value = previous_ctrl_reg1 | 0x01;
dupm2216 7:1e00dfecc92d 138 write_register(CTRL_REG1_REGISTER_ADDRESS, new_ctrl_reg1_value);
dupm2216 7:1e00dfecc92d 139 }
dupm2216 7:1e00dfecc92d 140
dupm2216 7:1e00dfecc92d 141 void Accelerometer::init()
dupm2216 7:1e00dfecc92d 142 {
dupm2216 7:1e00dfecc92d 143 set_active();
dupm2216 7:1e00dfecc92d 144 }
dupm2216 7:1e00dfecc92d 145
dupm2216 7:1e00dfecc92d 146 int Accelerometer::read_axis_data_8_bits(Axis axis)
dupm2216 7:1e00dfecc92d 147 {
dupm2216 7:1e00dfecc92d 148 const char axis_register = get_axis_register(axis);
dupm2216 7:1e00dfecc92d 149 const char register_value = read_register(axis_register);
dupm2216 7:1e00dfecc92d 150 return raw_axis_data_to_int(register_value);
dupm2216 7:1e00dfecc92d 151 }
dupm2216 7:1e00dfecc92d 152
dupm2216 7:1e00dfecc92d 153 double Accelerometer::get_angle_from_horizontal()
dupm2216 7:1e00dfecc92d 154 {
dupm2216 8:862e28c7f6f6 155 const int z_axis_data = read_axis_data_8_bits(AXIS_Z);
dupm2216 7:1e00dfecc92d 156 return angle_from_int_axis_data(z_axis_data);
dupm2216 7:1e00dfecc92d 157 }
dupm2216 7:1e00dfecc92d 158 };