/H8mini_test/src/imu.c

https://github.com/silver13/h8mini-testing · C · 303 lines · 183 code · 80 blank · 40 comment · 22 complexity · e7903c872f5ae090e409ee2c1e5b89bb MD5 · raw file

  1. // library headers
  2. #include <stdbool.h>
  3. #include <inttypes.h>
  4. //#define _USE_MATH_DEFINES
  5. #include <math.h>
  6. #include "drv_time.h"
  7. #include "util.h"
  8. #include "sixaxis.h"
  9. #include "config.h"
  10. #include <stdlib.h>
  11. // for arm_sin_f32
  12. // --"-- cos
  13. //#define ARM_MATH_CM3
  14. //#include <arm_math.h>
  15. #define ACC_1G 2048.0f
  16. // disable drift correction ( for testing)
  17. #define DISABLE_ACC 0
  18. // filter time in seconds
  19. // time to correct gyro readings using the accelerometer
  20. // 1-4 are generally good
  21. #define FILTERTIME 2.0
  22. // accel magnitude limits for drift correction
  23. #define ACC_MIN 0.7f
  24. #define ACC_MAX 1.3f
  25. // rotation matrix method
  26. // small angle approx = fast, somewhat more inaccurate
  27. #define SMALL_ANGLE_APPROX
  28. // options for non small angle approx
  29. // rotation matrix with float sinf and cosf
  30. // used when SMALL_ANGLE_APPROX in NOT defined
  31. // best (numeric) performance but a lot of flash
  32. // define one set out of the three below
  33. #define _sinf(val) sinf(val)
  34. #define _cosf(val) cosf(val)
  35. // the lib is not included here for now
  36. //#define _sinf(val) arm_sin_f32(val)
  37. //#define _cosf(val) arm_cos_f32(val)
  38. // rotation matrix with approximations for sin and cos
  39. // smaller size then above versions, and faster
  40. //#define _sinf(val) (val)
  41. //#define _cosf(val) (1 - ((val)*(val))*0.5)
  42. // Small angle approximation rotation
  43. // with simple sin and cos
  44. // do not change
  45. #define ssin(val) (val)
  46. #define scos(val) 1.0f
  47. float GEstG[3] = { 0, 0, ACC_1G };
  48. float attitude[3];
  49. extern float gyro[3];
  50. extern float accel[3];
  51. extern float accelcal[3];
  52. void imu_init(void)
  53. {
  54. // init the gravity vector with accel values
  55. for (int y = 0; y < 100; y++)
  56. {
  57. sixaxis_read();
  58. for (int x = 0; x < 3; x++)
  59. {
  60. lpf(&GEstG[x], accel[x], 0.85);
  61. }
  62. delay(1000);
  63. }
  64. }
  65. // from http://en.wikipedia.org/wiki/Fast_inverse_square_root
  66. // originally from quake3 code
  67. float Q_rsqrt( float number )
  68. {
  69. long i;
  70. float x2, y;
  71. const float threehalfs = 1.5F;
  72. x2 = number * 0.5F;
  73. y = number;
  74. i = * ( long * ) &y;
  75. i = 0x5f3759df - ( i >> 1 );
  76. y = * ( float * ) &i;
  77. y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
  78. y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
  79. // y = y * ( threehalfs - ( x2 * y * y ) ); // 3nd iteration, this can be removed
  80. return y;
  81. }
  82. void vectorcopy(float *vector1, float *vector2);
  83. float atan2approx(float y, float x);
  84. float calcmagnitude(float vector[3])
  85. {
  86. float accmag = 0;
  87. for (uint8_t axis = 0; axis < 3; axis++)
  88. {
  89. accmag += vector[axis] * vector[axis];
  90. }
  91. accmag = 1.0f/Q_rsqrt(accmag);
  92. return accmag;
  93. }
  94. void vectorcopy(float *vector1, float *vector2)
  95. {
  96. for (int axis = 0; axis < 3; axis++)
  97. {
  98. vector1[axis] = vector2[axis];
  99. }
  100. }
  101. static unsigned long imu_time;
  102. void imu_calc(void)
  103. {
  104. float EstG[3];
  105. float deltatime; // time in seconds
  106. vectorcopy(&EstG[0], &GEstG[0]);
  107. unsigned long time = gettime();
  108. deltatime = time - imu_time;
  109. imu_time = time;
  110. if (deltatime < 1)
  111. deltatime = 1;
  112. if (deltatime > 20000)
  113. deltatime = 20000;
  114. deltatime = deltatime * 1e-6f; // uS to seconds
  115. for (int x = 0; x < 3; x++)
  116. {
  117. accel[x] = accel[x] - accelcal[x];
  118. }
  119. #ifndef SMALL_ANGLE_APPROX
  120. float gyros[3];
  121. for (int i = 0; i < 3; i++)
  122. {
  123. gyros[i] = gyro[i] * deltatime;
  124. }
  125. // This does a "proper" matrix rotation using gyro deltas without small-angle approximation
  126. float mat[3][3];
  127. float cosx, sinx, cosy, siny, cosz, sinz;
  128. float coszcosx, coszcosy, sinzcosx, coszsinx, sinzsinx;
  129. cosx = _cosf(gyros[1]);
  130. sinx = _sinf(gyros[1]);
  131. cosy = _cosf(gyros[0]);
  132. siny = _sinf(-gyros[0]);
  133. cosz = _cosf(gyros[2]);
  134. sinz = _sinf(-gyros[2]);
  135. coszcosx = cosz * cosx;
  136. coszcosy = cosz * cosy;
  137. sinzcosx = sinz * cosx;
  138. coszsinx = sinx * cosz;
  139. sinzsinx = sinx * sinz;
  140. mat[0][0] = coszcosy;
  141. mat[0][1] = -cosy * sinz;
  142. mat[0][2] = siny;
  143. mat[1][0] = sinzcosx + (coszsinx * siny);
  144. mat[1][1] = coszcosx - (sinzsinx * siny);
  145. mat[1][2] = -sinx * cosy;
  146. mat[2][0] = (sinzsinx) - (coszcosx * siny);
  147. mat[2][1] = (coszsinx) + (sinzcosx * siny);
  148. mat[2][2] = cosy * cosx;
  149. EstG[0] = GEstG[0] * mat[0][0] + GEstG[1] * mat[1][0] + GEstG[2] * mat[2][0];
  150. EstG[1] = GEstG[0] * mat[0][1] + GEstG[1] * mat[1][1] + GEstG[2] * mat[2][1];
  151. EstG[2] = GEstG[0] * mat[0][2] + GEstG[1] * mat[1][2] + GEstG[2] * mat[2][2];
  152. // */
  153. #endif // end rotation matrix
  154. #ifdef SMALL_ANGLE_APPROX
  155. float deltaGyroAngle = (gyro[0]) * deltatime;
  156. EstG[2] = scos(deltaGyroAngle) * EstG[2] - ssin(deltaGyroAngle) * EstG[0];
  157. EstG[0] = ssin(deltaGyroAngle) * EstG[2] + scos(deltaGyroAngle) * EstG[0];
  158. deltaGyroAngle = (gyro[1]) * deltatime;
  159. EstG[1] = scos(deltaGyroAngle) * EstG[1] + ssin(deltaGyroAngle) * EstG[2];
  160. EstG[2] = -ssin(deltaGyroAngle) * EstG[1] + scos(deltaGyroAngle) * EstG[2];
  161. deltaGyroAngle = (gyro[2]) * deltatime;
  162. EstG[0] = scos(deltaGyroAngle) * EstG[0] - ssin(deltaGyroAngle) * EstG[1];
  163. EstG[1] = ssin(deltaGyroAngle) * EstG[0] + scos(deltaGyroAngle) * EstG[1];
  164. #endif // end small angle approx
  165. // orientation vector magnitude
  166. // calc acc mag
  167. float accmag;
  168. accmag = calcmagnitude(&accel[0]);
  169. static unsigned int count = 0;
  170. if ((accmag > ACC_MIN * ACC_1G) && (accmag < ACC_MAX * ACC_1G) && !DISABLE_ACC)
  171. {
  172. if (count >= 3 || 1) //
  173. {
  174. // normalize acc
  175. for (int axis = 0; axis < 3; axis++)
  176. {
  177. accel[axis] = accel[axis] * ( ACC_1G / accmag);
  178. }
  179. float filtcoeff = lpfcalc(deltatime, FILTERTIME);
  180. for (int x = 0; x < 3; x++)
  181. {
  182. lpf(&EstG[x], accel[x], filtcoeff);
  183. }
  184. }
  185. count++;
  186. }
  187. else
  188. {
  189. // acc mag out of bounds
  190. count = 0;
  191. }
  192. vectorcopy(&GEstG[0], &EstG[0]);
  193. #ifdef DEBUG
  194. attitude[0] = atan2approx(EstG[0], EstG[2]) ;
  195. attitude[1] = atan2approx(EstG[1], EstG[2]) ;
  196. #endif
  197. }
  198. #define M_PI 3.14159265358979323846 /* pi */
  199. #define OCTANTIFY(_x, _y, _o) do { \
  200. float _t; \
  201. _o= 0; \
  202. if(_y< 0) { _x= -_x; _y= -_y; _o += 4; } \
  203. if(_x<= 0) { _t= _x; _x= _y; _y= -_t; _o += 2; } \
  204. if(_x<=_y) { _t= _y-_x; _x= _x+_y; _y= _t; _o += 1; } \
  205. } while(0);
  206. // +-0.09 deg error
  207. float atan2approx(float y, float x)
  208. {
  209. if (x == 0)
  210. x = 123e-15f;
  211. float phi = 0;
  212. float dphi;
  213. float t;
  214. OCTANTIFY(x, y, phi);
  215. t = (y / x);
  216. // atan function for 0 - 1 interval
  217. dphi = t*( ( M_PI/4 + 0.2447f ) + t *( ( -0.2447f + 0.0663f ) + t*( - 0.0663f)) );
  218. phi *= M_PI / 4;
  219. dphi = phi + dphi;
  220. if (dphi > (float) M_PI)
  221. dphi -= 2 * M_PI;
  222. return RADTODEG * dphi;
  223. }