/EDVSBoardOS/MotionDriver/eMPL-hal/eMPL_outputs.c

https://bitbucket.org/rui_araujo/edvsboardos · C · 322 lines · 192 code · 33 blank · 97 comment · 17 complexity · 0586fcabb618104f539219f2736c402a MD5 · raw file

  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 eMPL_outputs.c
  14. * @brief Embedded MPL outputs.
  15. */
  16. #include "eMPL_outputs.h"
  17. #include "ml_math_func.h"
  18. #include "mlmath.h"
  19. #include "start_manager.h"
  20. #include "data_builder.h"
  21. #include "results_holder.h"
  22. struct eMPL_output_s {
  23. long quat[4];
  24. int quat_accuracy;
  25. int gyro_status;
  26. int accel_status;
  27. int compass_status;
  28. int nine_axis_status;
  29. inv_time_t nine_axis_timestamp;
  30. };
  31. static struct eMPL_output_s eMPL_out;
  32. /**
  33. * @brief Acceleration (g's) in body frame.
  34. * Embedded MPL defines gravity as positive acceleration pointing away from
  35. * the Earth.
  36. * @param[out] data Acceleration in g's, q16 fixed point.
  37. * @param[out] accuracy Accuracy of the measurement from 0 (least accurate)
  38. * to 3 (most accurate).
  39. * @param[out] timestamp The time in milliseconds when this sensor was read.
  40. * @return 1 if data was updated.
  41. */
  42. int inv_get_sensor_type_accel(long *data, int8_t *accuracy, inv_time_t *timestamp)
  43. {
  44. inv_get_accel_set(data, accuracy, timestamp);
  45. if (eMPL_out.accel_status & INV_NEW_DATA)
  46. return 1;
  47. else
  48. return 0;
  49. }
  50. /**
  51. * @brief Angular velocity (degrees per second) in body frame.
  52. * @param[out] data Angular velocity in dps, q16 fixed point.
  53. * @param[out] accuracy Accuracy of the measurement from 0 (least accurate)
  54. * to 3 (most accurate).
  55. * @param[out] timestamp The time in milliseconds when this sensor was read.
  56. * @return 1 if data was updated.
  57. */
  58. int inv_get_sensor_type_gyro(long *data, int8_t *accuracy, inv_time_t *timestamp)
  59. {
  60. inv_get_gyro_set(data, accuracy, timestamp);
  61. if (eMPL_out.gyro_status & INV_NEW_DATA)
  62. return 1;
  63. else
  64. return 0;
  65. }
  66. /**
  67. * @brief Magnetic field strength in body frame.
  68. * @param[out] data Field strength in microteslas, q16 fixed point.
  69. * @param[out] accuracy Accuracy of the measurement from 0 (least accurate)
  70. * to 3 (most accurate).
  71. * @param[out] timestamp The time in milliseconds when this sensor was read.
  72. * @return 1 if data was updated.
  73. */
  74. int inv_get_sensor_type_compass(long *data, int8_t *accuracy, inv_time_t *timestamp)
  75. {
  76. inv_get_compass_set(data, accuracy, timestamp);
  77. if (eMPL_out.compass_status & INV_NEW_DATA)
  78. return 1;
  79. else
  80. return 0;
  81. }
  82. /**
  83. * @brief Body-to-world frame quaternion.
  84. * The elements are output in the following order: W, X, Y, Z.
  85. * @param[out] data Quaternion, q30 fixed point.
  86. * @param[out] accuracy Accuracy of the measurement from 0 (least accurate)
  87. * to 3 (most accurate).
  88. * @param[out] timestamp The time in milliseconds when this sensor was read.
  89. * @return 1 if data was updated.
  90. */
  91. int inv_get_sensor_type_quat(long *data, int8_t *accuracy, inv_time_t *timestamp)
  92. {
  93. memcpy(data, eMPL_out.quat, sizeof(eMPL_out.quat));
  94. accuracy[0] = eMPL_out.quat_accuracy;
  95. timestamp[0] = eMPL_out.nine_axis_timestamp;
  96. return eMPL_out.nine_axis_status;
  97. }
  98. /**
  99. * @brief Quaternion-derived heading.
  100. * @param[out] data Heading in degrees, q16 fixed point.
  101. * @param[out] accuracy Accuracy of the measurement from 0 (least accurate)
  102. * to 3 (most accurate).
  103. * @param[out] timestamp The time in milliseconds when this sensor was read.
  104. * @return 1 if data was updated.
  105. */
  106. int inv_get_sensor_type_heading(long *data, int8_t *accuracy, inv_time_t *timestamp)
  107. {
  108. long t1, t2, q00, q03, q12, q22;
  109. float fdata;
  110. q00 = inv_q29_mult(eMPL_out.quat[0], eMPL_out.quat[0]);
  111. q03 = inv_q29_mult(eMPL_out.quat[0], eMPL_out.quat[3]);
  112. q12 = inv_q29_mult(eMPL_out.quat[1], eMPL_out.quat[2]);
  113. q22 = inv_q29_mult(eMPL_out.quat[2], eMPL_out.quat[2]);
  114. /* X component of the Ybody axis in World frame */
  115. t1 = q12 - q03;
  116. /* Y component of the Ybody axis in World frame */
  117. t2 = q22 + q00 - (1L << 30);
  118. fdata = atan2f((float) t1, (float) t2) * 180.f / (float) M_PI;
  119. if (fdata < 0.f)
  120. fdata += 360.f;
  121. data[0] = (long)(fdata * 65536.f);
  122. accuracy[0] = eMPL_out.quat_accuracy;
  123. timestamp[0] = eMPL_out.nine_axis_timestamp;
  124. return eMPL_out.nine_axis_status;
  125. }
  126. /**
  127. * @brief Body-to-world frame euler angles.
  128. * The euler angles are output with the following convention:
  129. * Pitch: -180 to 180
  130. * Roll: -90 to 90
  131. * Yaw: -180 to 180
  132. * @param[out] data Euler angles in degrees, q16 fixed point.
  133. * @param[out] accuracy Accuracy of the measurement from 0 (least accurate)
  134. * to 3 (most accurate).
  135. * @param[out] timestamp The time in milliseconds when this sensor was read.
  136. * @return 1 if data was updated.
  137. */
  138. int inv_get_sensor_type_euler(long *data, int8_t *accuracy, inv_time_t *timestamp)
  139. {
  140. long t1, t2, t3;
  141. long q00, q01, q02, q03, q11, q12, q13, q22, q23, q33;
  142. float values[3];
  143. q00 = inv_q29_mult(eMPL_out.quat[0], eMPL_out.quat[0]);
  144. q01 = inv_q29_mult(eMPL_out.quat[0], eMPL_out.quat[1]);
  145. q02 = inv_q29_mult(eMPL_out.quat[0], eMPL_out.quat[2]);
  146. q03 = inv_q29_mult(eMPL_out.quat[0], eMPL_out.quat[3]);
  147. q11 = inv_q29_mult(eMPL_out.quat[1], eMPL_out.quat[1]);
  148. q12 = inv_q29_mult(eMPL_out.quat[1], eMPL_out.quat[2]);
  149. q13 = inv_q29_mult(eMPL_out.quat[1], eMPL_out.quat[3]);
  150. q22 = inv_q29_mult(eMPL_out.quat[2], eMPL_out.quat[2]);
  151. q23 = inv_q29_mult(eMPL_out.quat[2], eMPL_out.quat[3]);
  152. q33 = inv_q29_mult(eMPL_out.quat[3], eMPL_out.quat[3]);
  153. /* X component of the Ybody axis in World frame */
  154. t1 = q12 - q03;
  155. /* Y component of the Ybody axis in World frame */
  156. t2 = q22 + q00 - (1L << 30);
  157. values[2] = -atan2f((float) t1, (float) t2) * 180.f / (float) M_PI;
  158. /* Z component of the Ybody axis in World frame */
  159. t3 = q23 + q01;
  160. values[0] =
  161. atan2f((float) t3,
  162. sqrtf((float) t1 * t1 +
  163. (float) t2 * t2)) * 180.f / (float) M_PI;
  164. /* Z component of the Zbody axis in World frame */
  165. t2 = q33 + q00 - (1L << 30);
  166. if (t2 < 0) {
  167. if (values[0] >= 0)
  168. values[0] = 180.f - values[0];
  169. else
  170. values[0] = -180.f - values[0];
  171. }
  172. /* X component of the Xbody axis in World frame */
  173. t1 = q11 + q00 - (1L << 30);
  174. /* Y component of the Xbody axis in World frame */
  175. t2 = q12 + q03;
  176. /* Z component of the Xbody axis in World frame */
  177. t3 = q13 - q02;
  178. values[1] =
  179. (atan2f((float)(q33 + q00 - (1L << 30)), (float)(q13 - q02)) *
  180. 180.f / (float) M_PI - 90);
  181. if (values[1] >= 90)
  182. values[1] = 180 - values[1];
  183. if (values[1] < -90)
  184. values[1] = -180 - values[1];
  185. data[0] = (long)(values[0] * 65536.f);
  186. data[1] = (long)(values[1] * 65536.f);
  187. data[2] = (long)(values[2] * 65536.f);
  188. accuracy[0] = eMPL_out.quat_accuracy;
  189. timestamp[0] = eMPL_out.nine_axis_timestamp;
  190. return eMPL_out.nine_axis_status;
  191. }
  192. /**
  193. * @brief Body-to-world frame rotation matrix.
  194. * @param[out] data Rotation matrix, q30 fixed point.
  195. * @param[out] accuracy Accuracy of the measurement from 0 (least accurate)
  196. * to 3 (most accurate).
  197. * @param[out] timestamp The time in milliseconds when this sensor was read.
  198. * @return 1 if data was updated.
  199. */
  200. int inv_get_sensor_type_rot_mat(long *data, int8_t *accuracy, inv_time_t *timestamp)
  201. {
  202. inv_quaternion_to_rotation(eMPL_out.quat, data);
  203. accuracy[0] = eMPL_out.quat_accuracy;
  204. timestamp[0] = eMPL_out.nine_axis_timestamp;
  205. return eMPL_out.nine_axis_status;
  206. }
  207. static inv_error_t inv_generate_eMPL_outputs
  208. (struct inv_sensor_cal_t *sensor_cal)
  209. {
  210. int use_sensor;
  211. long sr = 1000;
  212. inv_get_quaternion_set(eMPL_out.quat, &eMPL_out.quat_accuracy, &eMPL_out.nine_axis_timestamp);
  213. eMPL_out.gyro_status = sensor_cal->gyro.status;
  214. eMPL_out.accel_status = sensor_cal->accel.status;
  215. eMPL_out.compass_status = sensor_cal->compass.status;
  216. /* Find the highest sample rate and tie sensor fusion timestamps to that one. */
  217. if (sensor_cal->gyro.status & INV_SENSOR_ON) {
  218. sr = sensor_cal->gyro.sample_rate_ms;
  219. use_sensor = 0;
  220. }
  221. if ((sensor_cal->accel.status & INV_SENSOR_ON) && (sr > sensor_cal->accel.sample_rate_ms)) {
  222. sr = sensor_cal->accel.sample_rate_ms;
  223. use_sensor = 1;
  224. }
  225. if ((sensor_cal->compass.status & INV_SENSOR_ON) && (sr > sensor_cal->compass.sample_rate_ms)) {
  226. sr = sensor_cal->compass.sample_rate_ms;
  227. use_sensor = 2;
  228. }
  229. if ((sensor_cal->quat.status & INV_SENSOR_ON) && (sr > sensor_cal->quat.sample_rate_ms)) {
  230. sr = sensor_cal->quat.sample_rate_ms;
  231. use_sensor = 3;
  232. }
  233. switch (use_sensor) {
  234. default:
  235. case 0:
  236. eMPL_out.nine_axis_status = (sensor_cal->gyro.status & INV_NEW_DATA) ? 1 : 0;
  237. eMPL_out.nine_axis_timestamp = sensor_cal->gyro.timestamp;
  238. break;
  239. case 1:
  240. eMPL_out.nine_axis_status = (sensor_cal->accel.status & INV_NEW_DATA) ? 1 : 0;
  241. eMPL_out.nine_axis_timestamp = sensor_cal->accel.timestamp;
  242. break;
  243. case 2:
  244. eMPL_out.nine_axis_status = (sensor_cal->compass.status & INV_NEW_DATA) ? 1 : 0;
  245. eMPL_out.nine_axis_timestamp = sensor_cal->compass.timestamp;
  246. break;
  247. case 3:
  248. eMPL_out.nine_axis_status = (sensor_cal->quat.status & INV_NEW_DATA) ? 1 : 0;
  249. eMPL_out.nine_axis_timestamp = sensor_cal->quat.timestamp;
  250. break;
  251. }
  252. return INV_SUCCESS;
  253. }
  254. static inv_error_t inv_start_eMPL_outputs(void)
  255. {
  256. return inv_register_data_cb(inv_generate_eMPL_outputs,
  257. INV_PRIORITY_HAL_OUTPUTS, INV_GYRO_NEW | INV_ACCEL_NEW | INV_MAG_NEW);
  258. }
  259. static inv_error_t inv_stop_eMPL_outputs(void)
  260. {
  261. return inv_unregister_data_cb(inv_generate_eMPL_outputs);
  262. }
  263. static inv_error_t inv_init_eMPL_outputs(void)
  264. {
  265. memset(&eMPL_out, 0, sizeof(eMPL_out));
  266. return INV_SUCCESS;
  267. }
  268. /**
  269. * @brief Turns on creation and storage of HAL type results.
  270. */
  271. inv_error_t inv_enable_eMPL_outputs(void)
  272. {
  273. inv_error_t result;
  274. result = inv_init_eMPL_outputs();
  275. if (result)
  276. return result;
  277. return inv_register_mpl_start_notification(inv_start_eMPL_outputs);
  278. }
  279. /**
  280. * @brief Turns off creation and storage of HAL type results.
  281. */
  282. inv_error_t inv_disable_eMPL_outputs(void)
  283. {
  284. inv_stop_eMPL_outputs();
  285. return inv_unregister_mpl_start_notification(inv_start_eMPL_outputs);
  286. }
  287. /**
  288. * @}
  289. */