hal_outputs.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. /*
  2. $License:
  3. Copyright (C) 2011-2012 InvenSense Corporation, All Rights Reserved.
  4. See included License.txt for License information.
  5. $
  6. */
  7. /**
  8. * @defgroup HAL_Outputs hal_outputs
  9. * @brief Motion Library - HAL Outputs
  10. * Sets up common outputs for HAL
  11. *
  12. * @{
  13. * @file hal_outputs.c
  14. * @brief HAL Outputs.
  15. */
  16. #include <string.h>
  17. #include "hal_outputs.h"
  18. #include "log.h"
  19. #include "ml_math_func.h"
  20. #include "mlmath.h"
  21. #include "start_manager.h"
  22. #include "data_builder.h"
  23. #include "results_holder.h"
  24. struct hal_output_t {
  25. int accuracy_mag; /**< Compass accuracy */
  26. // int accuracy_gyro; /**< Gyro Accuracy */
  27. // int accuracy_accel; /**< Accel Accuracy */
  28. int accuracy_quat; /**< quat Accuracy */
  29. inv_time_t nav_timestamp;
  30. inv_time_t gam_timestamp;
  31. // inv_time_t accel_timestamp;
  32. inv_time_t mag_timestamp;
  33. long nav_quat[4];
  34. int gyro_status;
  35. int accel_status;
  36. int compass_status;
  37. int nine_axis_status;
  38. inv_biquad_filter_t lp_filter[3];
  39. float compass_float[3];
  40. };
  41. static struct hal_output_t hal_out;
  42. /** Acceleration (m/s^2) in body frame.
  43. * @param[out] values Acceleration in m/s^2 includes gravity. So while not in motion, it
  44. * should return a vector of magnitude near 9.81 m/s^2
  45. * @param[out] accuracy Accuracy of the measurment, 0 is least accurate, while 3 is most accurate.
  46. * @param[out] timestamp The timestamp for this sensor. Derived from the timestamp sent to
  47. * inv_build_accel().
  48. * @return Returns 1 if the data was updated or 0 if it was not updated.
  49. */
  50. int inv_get_sensor_type_accelerometer(float *values, int8_t *accuracy,
  51. inv_time_t * timestamp)
  52. {
  53. int status;
  54. /* Converts fixed point to m/s^2. Fixed point has 1g = 2^16.
  55. * So this 9.80665 / 2^16 */
  56. #define ACCEL_CONVERSION 0.000149637603759766f
  57. long accel[3];
  58. inv_get_accel_set(accel, accuracy, timestamp);
  59. values[0] = accel[0] * ACCEL_CONVERSION;
  60. values[1] = accel[1] * ACCEL_CONVERSION;
  61. values[2] = accel[2] * ACCEL_CONVERSION;
  62. if (hal_out.accel_status & INV_NEW_DATA)
  63. status = 1;
  64. else
  65. status = 0;
  66. return status;
  67. }
  68. /** Linear Acceleration (m/s^2) in Body Frame.
  69. * @param[out] values Linear Acceleration in body frame, length 3, (m/s^2). May show
  70. * accel biases while at rest.
  71. * @param[out] accuracy Accuracy of the measurment, 0 is least accurate, while 3 is most accurate.
  72. * @param[out] timestamp The timestamp for this sensor. Derived from the timestamp sent to
  73. * inv_build_accel().
  74. * @return Returns 1 if the data was updated or 0 if it was not updated.
  75. */
  76. int inv_get_sensor_type_linear_acceleration(float *values, int8_t *accuracy,
  77. inv_time_t * timestamp)
  78. {
  79. long gravity[3], accel[3];
  80. inv_get_accel_set(accel, accuracy, timestamp);
  81. inv_get_gravity(gravity);
  82. accel[0] -= gravity[0] >> 14;
  83. accel[1] -= gravity[1] >> 14;
  84. accel[2] -= gravity[2] >> 14;
  85. values[0] = accel[0] * ACCEL_CONVERSION;
  86. values[1] = accel[1] * ACCEL_CONVERSION;
  87. values[2] = accel[2] * ACCEL_CONVERSION;
  88. return 1;
  89. }
  90. /** Gravity vector (m/s^2) in Body Frame.
  91. * @param[out] values Gravity vector in body frame, length 3, (m/s^2)
  92. * @param[out] accuracy Accuracy of the measurment, 0 is least accurate, while 3 is most accurate.
  93. * @param[out] timestamp The timestamp for this sensor. Derived from the timestamp sent to
  94. * inv_build_accel().
  95. * @return Returns 1 if the data was updated or 0 if it was not updated.
  96. */
  97. int inv_get_sensor_type_gravity(float *values, int8_t *accuracy,
  98. inv_time_t * timestamp)
  99. {
  100. long gravity[3];
  101. *accuracy = (int8_t) hal_out.accuracy_quat;
  102. *timestamp = hal_out.nav_timestamp;
  103. inv_get_gravity(gravity);
  104. values[0] = (gravity[0] >> 14) * ACCEL_CONVERSION;
  105. values[1] = (gravity[1] >> 14) * ACCEL_CONVERSION;
  106. values[2] = (gravity[2] >> 14) * ACCEL_CONVERSION;
  107. return 1;
  108. }
  109. /* Converts fixed point to rad/sec. Fixed point has 1 dps = 2^16.
  110. * So this is: pi / 2^16 / 180 */
  111. #define GYRO_CONVERSION 2.66316109007924e-007f
  112. /** Gyroscope calibrated data (rad/s) in body frame.
  113. * @param[out] values Rotation Rate in rad/sec.
  114. * @param[out] accuracy Accuracy of the measurment, 0 is least accurate, while 3 is most accurate.
  115. * @param[out] timestamp The timestamp for this sensor. Derived from the timestamp sent to
  116. * inv_build_gyro().
  117. * @return Returns 1 if the data was updated or 0 if it was not updated.
  118. */
  119. int inv_get_sensor_type_gyroscope(float *values, int8_t *accuracy,
  120. inv_time_t * timestamp)
  121. {
  122. long gyro[3];
  123. int status;
  124. inv_get_gyro_set(gyro, accuracy, timestamp);
  125. values[0] = gyro[0] * GYRO_CONVERSION;
  126. values[1] = gyro[1] * GYRO_CONVERSION;
  127. values[2] = gyro[2] * GYRO_CONVERSION;
  128. if (hal_out.gyro_status & INV_NEW_DATA)
  129. status = 1;
  130. else
  131. status = 0;
  132. return status;
  133. }
  134. /** Gyroscope raw data (rad/s) in body frame.
  135. * @param[out] values Rotation Rate in rad/sec.
  136. * @param[out] accuracy Accuracy of the measurment, 0 is least accurate, while 3 is most accurate.
  137. * @param[out] timestamp The timestamp for this sensor. Derived from the timestamp sent to
  138. * inv_build_gyro().
  139. * @return Returns 1 if the data was updated or 0 if it was not updated.
  140. */
  141. int inv_get_sensor_type_gyroscope_raw(float *values, int8_t *accuracy,
  142. inv_time_t * timestamp)
  143. {
  144. long gyro[3];
  145. int status;
  146. inv_get_gyro_set_raw(gyro, accuracy, timestamp);
  147. values[0] = gyro[0] * GYRO_CONVERSION;
  148. values[1] = gyro[1] * GYRO_CONVERSION;
  149. values[2] = gyro[2] * GYRO_CONVERSION;
  150. if (hal_out.gyro_status & INV_NEW_DATA)
  151. status = 1;
  152. else
  153. status = 0;
  154. return status;
  155. }
  156. /**
  157. * This corresponds to Sensor.TYPE_ROTATION_VECTOR.
  158. * The rotation vector represents the orientation of the device as a combination
  159. * of an angle and an axis, in which the device has rotated through an angle @f$\theta@f$
  160. * around an axis {x, y, z}. <br>
  161. * The three elements of the rotation vector are
  162. * {x*sin(@f$\theta@f$/2), y*sin(@f$\theta@f$/2), z*sin(@f$\theta@f$/2)}, such that the magnitude of the rotation
  163. * vector is equal to sin(@f$\theta@f$/2), and the direction of the rotation vector is
  164. * equal to the direction of the axis of rotation.
  165. *
  166. * The three elements of the rotation vector are equal to the last three components of a unit quaternion
  167. * {x*sin(@f$\theta@f$/2), y*sin(@f$\theta@f$/2), z*sin(@f$\theta@f$/2)>. The 4th element is cos(@f$\theta@f$/2).
  168. *
  169. * Elements of the rotation vector are unitless. The x,y and z axis are defined in the same way as the acceleration sensor.
  170. * The reference coordinate system is defined as a direct orthonormal basis, where:
  171. -X is defined as the vector product Y.Z (It is tangential to the ground at the device's current location and roughly points East).
  172. -Y is tangential to the ground at the device's current location and points towards the magnetic North Pole.
  173. -Z points towards the sky and is perpendicular to the ground.
  174. * @param[out] values Length 4.
  175. * @param[out] accuracy Accuracy 0 to 3, 3 = most accurate
  176. * @param[out] timestamp Timestamp. In (ns) for Android.
  177. * @return Returns 1 if the data was updated or 0 if it was not updated.
  178. */
  179. int inv_get_sensor_type_rotation_vector(float *values, int8_t *accuracy,
  180. inv_time_t * timestamp)
  181. {
  182. *accuracy = (int8_t) hal_out.accuracy_quat;
  183. *timestamp = hal_out.nav_timestamp;
  184. if (hal_out.nav_quat[0] >= 0) {
  185. values[0] = hal_out.nav_quat[1] * INV_TWO_POWER_NEG_30;
  186. values[1] = hal_out.nav_quat[2] * INV_TWO_POWER_NEG_30;
  187. values[2] = hal_out.nav_quat[3] * INV_TWO_POWER_NEG_30;
  188. values[3] = hal_out.nav_quat[0] * INV_TWO_POWER_NEG_30;
  189. } else {
  190. values[0] = -hal_out.nav_quat[1] * INV_TWO_POWER_NEG_30;
  191. values[1] = -hal_out.nav_quat[2] * INV_TWO_POWER_NEG_30;
  192. values[2] = -hal_out.nav_quat[3] * INV_TWO_POWER_NEG_30;
  193. values[3] = -hal_out.nav_quat[0] * INV_TWO_POWER_NEG_30;
  194. }
  195. values[4] = inv_get_heading_confidence_interval();
  196. return hal_out.nine_axis_status;
  197. }
  198. /** Compass data (uT) in body frame.
  199. * @param[out] values Compass data in (uT), length 3. May be calibrated by having
  200. * biases removed and sensitivity adjusted
  201. * @param[out] accuracy Accuracy 0 to 3, 3 = most accurate
  202. * @param[out] timestamp Timestamp. In (ns) for Android.
  203. * @return Returns 1 if the data was updated or 0 if it was not updated.
  204. */
  205. int inv_get_sensor_type_magnetic_field(float *values, int8_t *accuracy,
  206. inv_time_t * timestamp)
  207. {
  208. int status;
  209. /* Converts fixed point to uT. Fixed point has 1 uT = 2^16.
  210. * So this is: 1 / 2^16*/
  211. //#define COMPASS_CONVERSION 1.52587890625e-005f
  212. int i;
  213. *timestamp = hal_out.mag_timestamp;
  214. *accuracy = (int8_t) hal_out.accuracy_mag;
  215. for (i=0; i<3; i++) {
  216. values[i] = hal_out.compass_float[i];
  217. }
  218. if (hal_out.compass_status & INV_NEW_DATA)
  219. status = 1;
  220. else
  221. status = 0;
  222. hal_out.compass_status = 0;
  223. return status;
  224. }
  225. static void inv_get_rotation(float r[3][3])
  226. {
  227. long rot[9];
  228. float conv = 1.f / (1L<<30);
  229. inv_quaternion_to_rotation(hal_out.nav_quat, rot);
  230. r[0][0] = rot[0]*conv;
  231. r[0][1] = rot[1]*conv;
  232. r[0][2] = rot[2]*conv;
  233. r[1][0] = rot[3]*conv;
  234. r[1][1] = rot[4]*conv;
  235. r[1][2] = rot[5]*conv;
  236. r[2][0] = rot[6]*conv;
  237. r[2][1] = rot[7]*conv;
  238. r[2][2] = rot[8]*conv;
  239. }
  240. static void google_orientation(float *g)
  241. {
  242. float rad2deg = (float)(180.0 / M_PI);
  243. float R[3][3];
  244. inv_get_rotation(R);
  245. g[0] = atan2f(-R[1][0], R[0][0]) * rad2deg;
  246. g[1] = atan2f(-R[2][1], R[2][2]) * rad2deg;
  247. g[2] = asinf ( R[2][0]) * rad2deg;
  248. if (g[0] < 0)
  249. g[0] += 360;
  250. }
  251. /** This corresponds to Sensor.TYPE_ORIENTATION. All values are angles in degrees.
  252. * @param[out] values Length 3, Degrees.<br>
  253. * - values[0]: Azimuth, angle between the magnetic north direction
  254. * and the y-axis, around the z-axis (0 to 359). 0=North, 90=East, 180=South, 270=West<br>
  255. * - values[1]: Pitch, rotation around x-axis (-180 to 180), with positive values
  256. * when the z-axis moves toward the y-axis.<br>
  257. * - values[2]: Roll, rotation around y-axis (-90 to 90), with positive
  258. * values when the x-axis moves toward the z-axis.<br>
  259. *
  260. * @note This definition is different from yaw, pitch and roll used in aviation
  261. * where the X axis is along the long side of the plane (tail to nose).
  262. * Note: This sensor type exists for legacy reasons, please use getRotationMatrix()
  263. * in conjunction with remapCoordinateSystem() and getOrientation() to compute
  264. * these values instead.
  265. * Important note: For historical reasons the roll angle is positive in the
  266. * clockwise direction (mathematically speaking, it should be positive in
  267. * the counter-clockwise direction).
  268. * @param[out] accuracy Accuracy of the measurment, 0 is least accurate, while 3 is most accurate.
  269. * @param[out] timestamp The timestamp for this sensor.
  270. * @return Returns 1 if the data was updated or 0 if it was not updated.
  271. */
  272. int inv_get_sensor_type_orientation(float *values, int8_t *accuracy,
  273. inv_time_t * timestamp)
  274. {
  275. *accuracy = (int8_t) hal_out.accuracy_quat;
  276. *timestamp = hal_out.nav_timestamp;
  277. google_orientation(values);
  278. return hal_out.nine_axis_status;
  279. }
  280. /** Main callback to generate HAL outputs. Typically not called by library users.
  281. * @param[in] sensor_cal Input variable to take sensor data whenever there is new
  282. * sensor data.
  283. * @return Returns INV_SUCCESS if successful or an error code if not.
  284. */
  285. inv_error_t inv_generate_hal_outputs(struct inv_sensor_cal_t *sensor_cal)
  286. {
  287. int use_sensor = 0;
  288. long sr = 1000;
  289. long compass[3];
  290. int8_t accuracy;
  291. int i;
  292. (void) sensor_cal;
  293. inv_get_quaternion_set(hal_out.nav_quat, &hal_out.accuracy_quat,
  294. &hal_out.nav_timestamp);
  295. hal_out.gyro_status = sensor_cal->gyro.status;
  296. hal_out.accel_status = sensor_cal->accel.status;
  297. hal_out.compass_status = sensor_cal->compass.status;
  298. // Find the highest sample rate and tie generating 9-axis to that one.
  299. if (sensor_cal->gyro.status & INV_SENSOR_ON) {
  300. sr = sensor_cal->gyro.sample_rate_ms;
  301. use_sensor = 0;
  302. }
  303. if ((sensor_cal->accel.status & INV_SENSOR_ON) && (sr > sensor_cal->accel.sample_rate_ms)) {
  304. sr = sensor_cal->accel.sample_rate_ms;
  305. use_sensor = 1;
  306. }
  307. if ((sensor_cal->compass.status & INV_SENSOR_ON) && (sr > sensor_cal->compass.sample_rate_ms)) {
  308. sr = sensor_cal->compass.sample_rate_ms;
  309. use_sensor = 2;
  310. }
  311. if ((sensor_cal->quat.status & INV_SENSOR_ON) && (sr > sensor_cal->quat.sample_rate_ms)) {
  312. sr = sensor_cal->quat.sample_rate_ms;
  313. use_sensor = 3;
  314. }
  315. // Only output 9-axis if all 9 sensors are on.
  316. if (sensor_cal->quat.status & INV_SENSOR_ON) {
  317. // If quaternion sensor is on, gyros are not required as quaternion already has that part
  318. if ((sensor_cal->accel.status & sensor_cal->compass.status & INV_SENSOR_ON) == 0) {
  319. use_sensor = -1;
  320. }
  321. } else {
  322. if ((sensor_cal->gyro.status & sensor_cal->accel.status & sensor_cal->compass.status & INV_SENSOR_ON) == 0) {
  323. use_sensor = -1;
  324. }
  325. }
  326. switch (use_sensor) {
  327. case 0:
  328. hal_out.nine_axis_status = (sensor_cal->gyro.status & INV_NEW_DATA) ? 1 : 0;
  329. hal_out.nav_timestamp = sensor_cal->gyro.timestamp;
  330. break;
  331. case 1:
  332. hal_out.nine_axis_status = (sensor_cal->accel.status & INV_NEW_DATA) ? 1 : 0;
  333. hal_out.nav_timestamp = sensor_cal->accel.timestamp;
  334. break;
  335. case 2:
  336. hal_out.nine_axis_status = (sensor_cal->compass.status & INV_NEW_DATA) ? 1 : 0;
  337. hal_out.nav_timestamp = sensor_cal->compass.timestamp;
  338. break;
  339. case 3:
  340. hal_out.nine_axis_status = (sensor_cal->quat.status & INV_NEW_DATA) ? 1 : 0;
  341. hal_out.nav_timestamp = sensor_cal->quat.timestamp;
  342. break;
  343. default:
  344. hal_out.nine_axis_status = 0; // Don't output quaternion related info
  345. break;
  346. }
  347. /* Converts fixed point to uT. Fixed point has 1 uT = 2^16.
  348. * So this is: 1 / 2^16*/
  349. #define COMPASS_CONVERSION 1.52587890625e-005f
  350. inv_get_compass_set(compass, &accuracy, &(hal_out.mag_timestamp) );
  351. hal_out.accuracy_mag = (int ) accuracy;
  352. for (i=0; i<3; i++) {
  353. if ((sensor_cal->compass.status & (INV_NEW_DATA | INV_CONTIGUOUS)) ==
  354. INV_NEW_DATA ) {
  355. // set the state variables to match output with input
  356. inv_calc_state_to_match_output(&hal_out.lp_filter[i], (float ) compass[i]);
  357. }
  358. if ((sensor_cal->compass.status & (INV_NEW_DATA | INV_RAW_DATA)) ==
  359. (INV_NEW_DATA | INV_RAW_DATA) ) {
  360. hal_out.compass_float[i] = inv_biquad_filter_process(&hal_out.lp_filter[i],
  361. (float ) compass[i]) * COMPASS_CONVERSION;
  362. } else if ((sensor_cal->compass.status & INV_NEW_DATA) == INV_NEW_DATA ) {
  363. hal_out.compass_float[i] = (float ) compass[i] * COMPASS_CONVERSION;
  364. }
  365. }
  366. return INV_SUCCESS;
  367. }
  368. /** Turns off generation of HAL outputs.
  369. * @return Returns INV_SUCCESS if successful or an error code if not.
  370. */
  371. inv_error_t inv_stop_hal_outputs(void)
  372. {
  373. inv_error_t result;
  374. result = inv_unregister_data_cb(inv_generate_hal_outputs);
  375. return result;
  376. }
  377. /** Turns on generation of HAL outputs. This should be called after inv_stop_hal_outputs()
  378. * to turn generation of HAL outputs back on. It is automatically called by inv_enable_hal_outputs().
  379. * @return Returns INV_SUCCESS if successful or an error code if not.
  380. */
  381. inv_error_t inv_start_hal_outputs(void)
  382. {
  383. inv_error_t result;
  384. result =
  385. inv_register_data_cb(inv_generate_hal_outputs,
  386. INV_PRIORITY_HAL_OUTPUTS,
  387. INV_GYRO_NEW | INV_ACCEL_NEW | INV_MAG_NEW);
  388. return result;
  389. }
  390. /* file name: lowPassFilterCoeff_1_6.c */
  391. float compass_low_pass_filter_coeff[5] =
  392. {+2.000000000000f, +1.000000000000f, -1.279632424998f, +0.477592250073f, +0.049489956269f};
  393. /** Initializes hal outputs class. This is called automatically by the
  394. * enable function. It may be called any time the feature is enabled, but
  395. * is typically not needed to be called by outside callers.
  396. * @return Returns INV_SUCCESS if successful or an error code if not.
  397. */
  398. inv_error_t inv_init_hal_outputs(void)
  399. {
  400. int i;
  401. memset(&hal_out, 0, sizeof(hal_out));
  402. for (i=0; i<3; i++) {
  403. inv_init_biquad_filter(&hal_out.lp_filter[i], compass_low_pass_filter_coeff);
  404. }
  405. return INV_SUCCESS;
  406. }
  407. /** Turns on creation and storage of HAL type results.
  408. * @return Returns INV_SUCCESS if successful or an error code if not.
  409. */
  410. inv_error_t inv_enable_hal_outputs(void)
  411. {
  412. inv_error_t result;
  413. // don't need to check the result for inv_init_hal_outputs
  414. // since it's always INV_SUCCESS
  415. inv_init_hal_outputs();
  416. result = inv_register_mpl_start_notification(inv_start_hal_outputs);
  417. return result;
  418. }
  419. /** Turns off creation and storage of HAL type results.
  420. */
  421. inv_error_t inv_disable_hal_outputs(void)
  422. {
  423. inv_error_t result;
  424. inv_stop_hal_outputs(); // Ignore error if we have already stopped this
  425. result = inv_unregister_mpl_start_notification(inv_start_hal_outputs);
  426. return result;
  427. }
  428. /**
  429. * @}
  430. */