Loading...
Searching...
No Matches
hdataacquisition.c
1/***********************************************************************************
2 * @file hDataAcquisition.c *
3 * @author Matt Ricci *
4 * @addtogroup RTOS *
5 * *
6 * @{ *
7 ***********************************************************************************/
8
9#include "FreeRTOS.h"
10#include "event_groups.h"
11#include "groups.h"
12#include "message_buffer.h"
13#include "semphr.h"
14
15#include "dataframe.h"
16#include "devicelist.h"
17#include "membuff.h"
18#include "sensors.h"
19
20#include "state.h"
21#include "accelerometer.h"
22#include "gyroscope.h"
23#include "hdataacquisition.h"
24
25#include "quaternion.h"
26
27extern EventGroupHandle_t xTaskEnableGroup;
28extern MessageBufferHandle_t xUsbTxBuff;
29extern SemaphoreHandle_t xUsbMutex;
30
31#define ACCEL_MOTION_THRESHOLD 1.125f
32#define GYRO_MOTION_THRESHOLD 2.0f
33
34#define SQ(x) (x * x)
35#define EWMA(a, ewma, x) (((1 - a) * ewma) + (a * x))
36#define MAG(v) (sqrtf(SQ(v[0]) + SQ(v[1]) + SQ(v[2])))
37
38#define SWAP_AXES(device, oldIdx, newIdx) \
39 { \
40 uint8_t temp = device->axes[oldIdx]; \
41 device->axes[oldIdx] = device->axes[newIdx]; \
42 device->axes[newIdx] = temp; \
43 }
44
45float gyroBiasX = 0.0f;
46float gyroBiasY = 0.0f;
47float gyroBiasZ = 0.0f;
48uint32_t numSamples = 0;
49
50/* =============================================================================== */
65void vHDataAcquisition(void *argument) {
66 float dt = 0.002;
67
68 const TickType_t xFrequency = pdMS_TO_TICKS(2); // 500Hz
69 const TickType_t blockTime = pdMS_TO_TICKS(0);
70
71 // Devices
72 Accel_t *hAccel = DeviceList_getDeviceHandle(DEVICE_ACCEL_HIGH).device;
73 Accel_t *lAccel = DeviceList_getDeviceHandle(DEVICE_ACCEL_LOW).device;
74 Gyro_t *gyro = DeviceList_getDeviceHandle(DEVICE_GYRO).device;
75
76 // Selected accelerometer (high/low)
77 DeviceHandle_t *accelHandlePtr = DeviceList_getDeviceHandlePointer(DEVICE_ACCEL);
78 Accel_t *accel = accelHandlePtr->device;
79
80 State *state = State_getState();
81
82 // Average weighted vector magnitudes
83 float accelEWMA = 0; // Moving average for acceleration vector magnitude
84 float gyroEWMA = 0; // Moving average for gyroscope rate vector magnitude
85
86 for (;;) {
87 // Block until 2ms interval
88 TickType_t xLastWakeTime = xTaskGetTickCount();
89 vTaskDelayUntil(&xLastWakeTime, xFrequency);
90
91 // --- Sample device measurements ---
92 taskENTER_CRITICAL();
93 lAccel->update(lAccel);
94 hAccel->update(hAccel);
95 gyro->update(gyro);
96 taskEXIT_CRITICAL();
97
98 // --- Select which accelerometer to use ---
99 accelHandlePtr->device = (accel->accelData[ZINDEX] < 15) ? lAccel : hAccel;
100
101 // --- Calibrate devices before launch ---
102 if (state->flightState == PRELAUNCH) {
103
104 // Calculate moving average of acceleration vector magnitude
105 accelEWMA = EWMA(0.5, accelEWMA, MAG(accel->accelData));
106
107 // Calculate moving average of gyroscope rate vector magnitude
108 gyroEWMA = EWMA(0.5, gyroEWMA, MAG(gyro->gyroData));
109
110 // --- Perform calibration whilst stationary ---
111 //
112 // Here, the rocket is determined to be "stationary" if the moving
113 // average magnitude of gyroscope and accelerometer measurement
114 // vectors are below the threshold.
115 //
116 // Gyroscope bias is estimated as a cumulative average of all
117 // gyroscope readings whilst stationary.
118 //
119 // Axis adjustments are performed as a function of the index of
120 // accelerometer measurement with greatest magnitude. All devices
121 // have the same adjustment performed to maintain equivalence.
122
123 if (accelEWMA < ACCEL_MOTION_THRESHOLD && gyroEWMA < GYRO_MOTION_THRESHOLD) {
124 // Cumulative sum gyro bias samples
125 gyro->bias[0] += 0.5 * (gyro->gyroData[0]) * dt;
126 gyro->bias[1] += 0.5 * (gyro->gyroData[1]) * dt;
127 gyro->bias[2] += 0.5 * (gyro->gyroData[2]) * dt;
128
129 int oldIdx = 0;
130 // Determine current Z axis index
131 for (; oldIdx < ZINDEX; oldIdx++) {
132 if (accel->axes[oldIdx] == ZINDEX)
133 break;
134 }
135
136 int newIdx = ZINDEX;
137 // Determine current largest axis of acceleration
138 for (int i = 0; i < ZINDEX; i++) {
139 float indexedAxisAbsolute = fabs(accel->accelData[accel->axes[i]]);
140 float currentAxisAbsolute = fabs(accel->accelData[accel->axes[newIdx]]);
141 if (indexedAxisAbsolute > currentAxisAbsolute)
142 newIdx = i;
143 }
144
145 // Swap indices of current Z axis and axis of largest magnitude
146 SWAP_AXES(hAccel, oldIdx, newIdx)
147 SWAP_AXES(lAccel, oldIdx, newIdx)
148 SWAP_AXES(gyro, oldIdx, newIdx)
149
150 // Invert Z-axis sign if necessary
151 if (accel->accelData[ZINDEX] < 0) {
152 lAccel->sign[ZINDEX] *= -1;
153 hAccel->sign[ZINDEX] *= -1;
154 gyro->sign[ZINDEX] *= -1;
155 }
156 }
157 }
158
159 // --- Add sensor data to dataframe ---
160 state->mem.append(&state->mem, HEADER_HIGHRES);
161 state->mem.appendBytes(&state->mem, accel->rawAccelData, accel->dataSize);
162 state->mem.appendBytes(&state->mem, gyro->rawGyroData, gyro->dataSize);
163
164 // --- Calculate state variables ---
165 EventBits_t uxBits = xEventGroupWaitBits(xTaskEnableGroup, GROUP_TASK_ENABLE_HIGHRES, pdFALSE, pdFALSE, blockTime);
166 if (uxBits & GROUP_TASK_ENABLE_HIGHRES) {
167 // Integrate attitude quaternion from rotations
168 Quaternion qDot = Quaternion_new();
169 qDot.fromEuler(
170 &qDot,
171 (float)(dt * gyro->gyroData[ROLL_INDEX]),
172 (float)(dt * gyro->gyroData[PITCH_INDEX]),
173 (float)(dt * gyro->gyroData[YAW_INDEX])
174 );
175 state->rotation = Quaternion_mul(&state->rotation, &qDot);
176 state->rotation.normalise(&state->rotation); // New attitude quaternion
177
178 // Apply rotation to z-axis unit vector
179 state->rotation.fRotateVector3D(&state->rotation, state->launchAngle, state->attitude);
180
181 // Calculate tilt angle
182 // tilt = cos^-1(attitude ยท initial)
183 state->cosine = state->launchAngle[0] * state->attitude[0] + state->launchAngle[1] * state->attitude[1] + state->launchAngle[2] * state->attitude[2];
184 state->tilt = acosf(state->cosine) * (180 / 3.14159265);
185
186 state->flightTimeMs += 2;
187 }
188 }
189}
190
Defines the API for the Accelerometer sensor.
uint8_t * rawAccelData
Pointer to driver defined raw data array.
void(* update)(struct Accel *accel)
Pointer to update method.
float * accelData
Pointer to driver defined data array.
uint8_t * axes
Pointer to driver defined axes.
int8_t * sign
Pointer to driver defined signs.
uint8_t dataSize
Total data size.
int8_t * sign
Array defining sign of axes.
Definition gyroscope.h:65
float * gyroData
Processed angular rates array.
Definition gyroscope.h:67
uint8_t * rawGyroData
Raw angular rates array.
Definition gyroscope.h:66
void(* update)(struct Gyro *gyro)
Pointer to update method.
Definition gyroscope.h:24
float * bias
Bias offset array.
Definition gyroscope.h:68
uint8_t dataSize
Total data size.
Definition gyroscope.h:63
DeviceHandle_t DeviceList_getDeviceHandle(DeviceKey)
Retrieve device handle from list by key.
Definition devicelist.c:36
DeviceHandle_t * DeviceList_getDeviceHandlePointer(DeviceKey)
Retrieve device handle pointer from list by key.
Definition devicelist.c:86
State * State_getState()
Definition state.c:69
@ PRELAUNCH
Initial boot condition.
Definition state.h:25
State variable struct.
Definition state.h:36
Defines the API for the Gyroscope sensor.