PageRenderTime 42ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/src/kernel/ao_sample.c

https://github.com/ajtowns/altos
C | 372 lines | 266 code | 46 blank | 60 comment | 16 complexity | f5c3f1529ebbfbc1fb8f2920aa431488 MD5 | raw file
  1. /*
  2. * Copyright © 2011 Keith Packard <keithp@keithp.com>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; version 2 of the License.
  7. *
  8. * This program is distributed in the hope that it will be useful, but
  9. * WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. * General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License along
  14. * with this program; if not, write to the Free Software Foundation, Inc.,
  15. * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  16. */
  17. #ifndef AO_FLIGHT_TEST
  18. #include "ao.h"
  19. #include <ao_data.h>
  20. #endif
  21. #if HAS_GYRO
  22. #include <ao_quaternion.h>
  23. #endif
  24. /*
  25. * Current sensor values
  26. */
  27. #ifndef PRES_TYPE
  28. #define PRES_TYPE int32_t
  29. #define ALT_TYPE int32_t
  30. #define ACCEL_TYPE int16_t
  31. #endif
  32. __pdata uint16_t ao_sample_tick; /* time of last data */
  33. __pdata pres_t ao_sample_pres;
  34. __pdata alt_t ao_sample_alt;
  35. __pdata alt_t ao_sample_height;
  36. #if HAS_ACCEL
  37. __pdata accel_t ao_sample_accel;
  38. #endif
  39. #if HAS_GYRO
  40. __pdata accel_t ao_sample_accel_along;
  41. __pdata accel_t ao_sample_accel_across;
  42. __pdata accel_t ao_sample_accel_through;
  43. __pdata gyro_t ao_sample_roll;
  44. __pdata gyro_t ao_sample_pitch;
  45. __pdata gyro_t ao_sample_yaw;
  46. __pdata angle_t ao_sample_orient;
  47. #endif
  48. __data uint8_t ao_sample_data;
  49. /*
  50. * Sensor calibration values
  51. */
  52. __pdata pres_t ao_ground_pres; /* startup pressure */
  53. __pdata alt_t ao_ground_height; /* MSL of ao_ground_pres */
  54. #if HAS_ACCEL
  55. __pdata accel_t ao_ground_accel; /* startup acceleration */
  56. __pdata accel_t ao_accel_2g; /* factory accel calibration */
  57. __pdata int32_t ao_accel_scale; /* sensor to m/s² conversion */
  58. #endif
  59. #if HAS_GYRO
  60. __pdata accel_t ao_ground_accel_along;
  61. __pdata accel_t ao_ground_accel_across;
  62. __pdata accel_t ao_ground_accel_through;
  63. __pdata int32_t ao_ground_pitch;
  64. __pdata int32_t ao_ground_yaw;
  65. __pdata int32_t ao_ground_roll;
  66. #endif
  67. static __pdata uint8_t ao_preflight; /* in preflight mode */
  68. static __pdata uint16_t nsamples;
  69. __pdata int32_t ao_sample_pres_sum;
  70. #if HAS_ACCEL
  71. __pdata int32_t ao_sample_accel_sum;
  72. #endif
  73. #if HAS_GYRO
  74. __pdata int32_t ao_sample_accel_along_sum;
  75. __pdata int32_t ao_sample_accel_across_sum;
  76. __pdata int32_t ao_sample_accel_through_sum;
  77. __pdata int32_t ao_sample_pitch_sum;
  78. __pdata int32_t ao_sample_yaw_sum;
  79. __pdata int32_t ao_sample_roll_sum;
  80. static struct ao_quaternion ao_rotation;
  81. #endif
  82. #if HAS_FLIGHT_DEBUG
  83. extern uint8_t ao_orient_test;
  84. #endif
  85. static void
  86. ao_sample_preflight_add(void)
  87. {
  88. #if HAS_ACCEL
  89. ao_sample_accel_sum += ao_sample_accel;
  90. #endif
  91. ao_sample_pres_sum += ao_sample_pres;
  92. #if HAS_GYRO
  93. ao_sample_accel_along_sum += ao_sample_accel_along;
  94. ao_sample_accel_across_sum += ao_sample_accel_across;
  95. ao_sample_accel_through_sum += ao_sample_accel_through;
  96. ao_sample_pitch_sum += ao_sample_pitch;
  97. ao_sample_yaw_sum += ao_sample_yaw;
  98. ao_sample_roll_sum += ao_sample_roll;
  99. #endif
  100. ++nsamples;
  101. }
  102. static void
  103. ao_sample_preflight_set(void)
  104. {
  105. #if HAS_ACCEL
  106. ao_ground_accel = ao_sample_accel_sum >> 9;
  107. ao_sample_accel_sum = 0;
  108. #endif
  109. ao_ground_pres = ao_sample_pres_sum >> 9;
  110. ao_ground_height = pres_to_altitude(ao_ground_pres);
  111. ao_sample_pres_sum = 0;
  112. #if HAS_GYRO
  113. ao_ground_accel_along = ao_sample_accel_along_sum >> 9;
  114. ao_ground_accel_across = ao_sample_accel_across_sum >> 9;
  115. ao_ground_accel_through = ao_sample_accel_through_sum >> 9;
  116. ao_ground_pitch = ao_sample_pitch_sum;
  117. ao_ground_yaw = ao_sample_yaw_sum;
  118. ao_ground_roll = ao_sample_roll_sum;
  119. ao_sample_accel_along_sum = 0;
  120. ao_sample_accel_across_sum = 0;
  121. ao_sample_accel_through_sum = 0;
  122. ao_sample_pitch_sum = 0;
  123. ao_sample_yaw_sum = 0;
  124. ao_sample_roll_sum = 0;
  125. ao_sample_orient = 0;
  126. struct ao_quaternion orient;
  127. /* Take the pad IMU acceleration values and compute our current direction
  128. */
  129. ao_quaternion_init_vector(&orient,
  130. (ao_ground_accel_across - ao_config.accel_zero_across),
  131. (ao_ground_accel_through - ao_config.accel_zero_through),
  132. (ao_ground_accel_along - ao_config.accel_zero_along));
  133. ao_quaternion_normalize(&orient,
  134. &orient);
  135. /* Here's up */
  136. struct ao_quaternion up = { .r = 0, .x = 0, .y = 0, .z = 1 };
  137. if (ao_config.pad_orientation != AO_PAD_ORIENTATION_ANTENNA_UP)
  138. up.z = -1;
  139. /* Compute rotation to get from up to our current orientation, set
  140. * that as the current rotation vector
  141. */
  142. ao_quaternion_vectors_to_rotation(&ao_rotation, &up, &orient);
  143. #if HAS_FLIGHT_DEBUG
  144. if (ao_orient_test)
  145. printf("\n\treset\n");
  146. #endif
  147. #endif
  148. nsamples = 0;
  149. }
  150. #if HAS_GYRO
  151. #define TIME_DIV 200.0f
  152. static void
  153. ao_sample_rotate(void)
  154. {
  155. #ifdef AO_FLIGHT_TEST
  156. float dt = (ao_sample_tick - ao_sample_prev_tick) / TIME_DIV;
  157. #else
  158. static const float dt = 1/TIME_DIV;
  159. #endif
  160. float x = ao_mpu6000_gyro((float) ((ao_sample_pitch << 9) - ao_ground_pitch) / 512.0f) * dt;
  161. float y = ao_mpu6000_gyro((float) ((ao_sample_yaw << 9) - ao_ground_yaw) / 512.0f) * dt;
  162. float z = ao_mpu6000_gyro((float) ((ao_sample_roll << 9) - ao_ground_roll) / 512.0f) * dt;
  163. struct ao_quaternion rot;
  164. ao_quaternion_init_half_euler(&rot, x, y, z);
  165. ao_quaternion_multiply(&ao_rotation, &rot, &ao_rotation);
  166. /* And normalize to make sure it remains a unit vector */
  167. ao_quaternion_normalize(&ao_rotation, &ao_rotation);
  168. /* Compute pitch angle from vertical by taking the pad
  169. * orientation vector and rotating it by the current total
  170. * rotation value. That will be a unit vector pointing along
  171. * the airframe axis. The Z value will be the cosine of the
  172. * change in the angle from vertical since boost.
  173. *
  174. * rot = ao_rotation * vertical * ao_rotation°
  175. * rot = ao_rotation * (0,0,0,1) * ao_rotation°
  176. * = ((a.z, a.y, -a.x, a.r) * (a.r, -a.x, -a.y, -a.z)) .z
  177. *
  178. * = (-a.z * -a.z) + (a.y * -a.y) - (-a.x * -a.x) + (a.r * a.r)
  179. * = a.z² - a.y² - a.x² + a.r²
  180. *
  181. * rot = ao_rotation * (0, 0, 0, -1) * ao_rotation°
  182. * = ((-a.z, -a.y, a.x, -a.r) * (a.r, -a.x, -a.y, -a.z)) .z
  183. *
  184. * = (a.z * -a.z) + (-a.y * -a.y) - (a.x * -a.x) + (-a.r * a.r)
  185. * = -a.z² + a.y² + a.x² - a.r²
  186. */
  187. float rotz;
  188. rotz = ao_rotation.z * ao_rotation.z - ao_rotation.y * ao_rotation.y - ao_rotation.x * ao_rotation.x + ao_rotation.r * ao_rotation.r;
  189. ao_sample_orient = acosf(rotz) * (float) (180.0/M_PI);
  190. #if HAS_FLIGHT_DEBUG
  191. if (ao_orient_test) {
  192. printf ("rot %d %d %d orient %d \r",
  193. (int) (x * 1000),
  194. (int) (y * 1000),
  195. (int) (z * 1000),
  196. ao_sample_orient);
  197. }
  198. #endif
  199. }
  200. #endif
  201. static void
  202. ao_sample_preflight(void)
  203. {
  204. /* startup state:
  205. *
  206. * Collect 512 samples of acceleration and pressure
  207. * data and average them to find the resting values
  208. */
  209. if (nsamples < 512) {
  210. ao_sample_preflight_add();
  211. } else {
  212. #if HAS_ACCEL
  213. ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g;
  214. ao_accel_scale = to_fix32(GRAVITY * 2 * 16) / ao_accel_2g;
  215. #endif
  216. ao_sample_preflight_set();
  217. ao_preflight = FALSE;
  218. }
  219. }
  220. /*
  221. * While in pad mode, constantly update the ground state by
  222. * re-averaging the data. This tracks changes in orientation, which
  223. * might be caused by adjustments to the rocket on the pad and
  224. * pressure, which might be caused by changes in the weather.
  225. */
  226. static void
  227. ao_sample_preflight_update(void)
  228. {
  229. if (nsamples < 512)
  230. ao_sample_preflight_add();
  231. else if (nsamples < 1024)
  232. ++nsamples;
  233. else
  234. ao_sample_preflight_set();
  235. }
  236. #if 0
  237. #if HAS_GYRO
  238. static int32_t p_filt;
  239. static int32_t y_filt;
  240. static gyro_t inline ao_gyro(void) {
  241. gyro_t p = ao_sample_pitch - ao_ground_pitch;
  242. gyro_t y = ao_sample_yaw - ao_ground_yaw;
  243. p_filt = p_filt - (p_filt >> 6) + p;
  244. y_filt = y_filt - (y_filt >> 6) + y;
  245. p = p_filt >> 6;
  246. y = y_filt >> 6;
  247. return ao_sqrt(p*p + y*y);
  248. }
  249. #endif
  250. #endif
  251. uint8_t
  252. ao_sample(void)
  253. {
  254. ao_wakeup(DATA_TO_XDATA(&ao_sample_data));
  255. ao_sleep((void *) DATA_TO_XDATA(&ao_data_head));
  256. while (ao_sample_data != ao_data_head) {
  257. __xdata struct ao_data *ao_data;
  258. /* Capture a sample */
  259. ao_data = (struct ao_data *) &ao_data_ring[ao_sample_data];
  260. ao_sample_tick = ao_data->tick;
  261. #if HAS_BARO
  262. ao_data_pres_cook(ao_data);
  263. ao_sample_pres = ao_data_pres(ao_data);
  264. ao_sample_alt = pres_to_altitude(ao_sample_pres);
  265. ao_sample_height = ao_sample_alt - ao_ground_height;
  266. #endif
  267. #if HAS_ACCEL
  268. ao_sample_accel = ao_data_accel_cook(ao_data);
  269. if (ao_config.pad_orientation != AO_PAD_ORIENTATION_ANTENNA_UP)
  270. ao_sample_accel = ao_data_accel_invert(ao_sample_accel);
  271. ao_data_set_accel(ao_data, ao_sample_accel);
  272. #endif
  273. #if HAS_GYRO
  274. ao_sample_accel_along = ao_data_along(ao_data);
  275. ao_sample_accel_across = ao_data_across(ao_data);
  276. ao_sample_accel_through = ao_data_through(ao_data);
  277. ao_sample_pitch = ao_data_pitch(ao_data);
  278. ao_sample_yaw = ao_data_yaw(ao_data);
  279. ao_sample_roll = ao_data_roll(ao_data);
  280. #endif
  281. if (ao_preflight)
  282. ao_sample_preflight();
  283. else {
  284. if (ao_flight_state < ao_flight_boost)
  285. ao_sample_preflight_update();
  286. ao_kalman();
  287. #if HAS_GYRO
  288. ao_sample_rotate();
  289. #endif
  290. }
  291. #ifdef AO_FLIGHT_TEST
  292. ao_sample_prev_tick = ao_sample_tick;
  293. #endif
  294. ao_sample_data = ao_data_ring_next(ao_sample_data);
  295. }
  296. return !ao_preflight;
  297. }
  298. void
  299. ao_sample_init(void)
  300. {
  301. ao_config_get();
  302. nsamples = 0;
  303. ao_sample_pres_sum = 0;
  304. ao_sample_pres = 0;
  305. #if HAS_ACCEL
  306. ao_sample_accel_sum = 0;
  307. ao_sample_accel = 0;
  308. #endif
  309. #if HAS_GYRO
  310. ao_sample_accel_along_sum = 0;
  311. ao_sample_accel_across_sum = 0;
  312. ao_sample_accel_through_sum = 0;
  313. ao_sample_accel_along = 0;
  314. ao_sample_accel_across = 0;
  315. ao_sample_accel_through = 0;
  316. ao_sample_pitch_sum = 0;
  317. ao_sample_yaw_sum = 0;
  318. ao_sample_roll_sum = 0;
  319. ao_sample_pitch = 0;
  320. ao_sample_yaw = 0;
  321. ao_sample_roll = 0;
  322. ao_sample_orient = 0;
  323. #endif
  324. ao_sample_data = ao_data_head;
  325. ao_preflight = TRUE;
  326. }