TeensyNanoExoCode
Loading...
Searching...
No Matches
error_triggers.h
Go to the documentation of this file.
1#ifndef ERROR_TRIGGERS_H
2#define ERROR_TRIGGERS_H
3
4#if defined(ARDUINO_TEENSY36) || defined(ARDUINO_TEENSY41)
5
6#include "ExoData.h"
7#include "Exo.h"
8#include "error_types.h"
9
10#include "Arduino.h"
11#include "Utilities.h"
12#include "Config.h"
13#include "ParseIni.h"
14
15// TODO: Make these device configuration dependent
16
17namespace error_triggers_state
18{
19 bool triggered_error = false;
20
21 // Motor Inertia goodies
22 const float motor_inertia_threshold = 0.01;
23 float left_prev_velocity = 0;
24 float right_prev_velocity = 0;
25
26 // Motor Position goodies
27 const float motor_position_alpha = 0.1;
28 const float motor_position_tolerance = 10; // degrees
29 float filtered_motor_position_left = 0;
30 float filtered_motor_position_right = 0;
31 const std::pair<float, float> left_position_bounds = std::make_pair<float, float> (12-motor_position_tolerance, 10+motor_position_tolerance);
32 const std::pair<float, float> right_position_bounds = std::make_pair<float, float> (12-motor_position_tolerance, 10+motor_position_tolerance);
33
34 // Torque goodies
35 const float torque_output_alpha = 0.2;
36 const float torque_output_threshold = 45;
37 float average_torque_output_left = 0;
38 float average_torque_output_right = 0;
39
40 // X-Sigma Rejection on sensor goodies
41 const int failure_count_threshold = 2;
42
43 const int torque_std_dev_multiple = 10;
44 const float torque_window_size = 100;
45 std::queue<float> torque_sensor_queue_left;
46 std::queue<float> torque_sensor_queue_right;
47 int torque_failure_count_left = 0;
48 int torque_failure_count_right = 0;
49
50 const int force_std_dev_multiple = 10;
51 const float force_window_size = 100;
52 std::queue<float> force_sensor_queue_left;
53 std::queue<float> force_sensor_queue_right;
54 int force_failure_count_left = 0;
55 int force_failure_count_right = 0;
56
57 // Tracking goodies
58 const float tracking_alpha = 0.1;
59 const float tracking_threshold = 15; // Nm
60 float average_tracking_error_left = 0;
61 float average_tracking_error_right = 0;
62
63 // Transimission efficiency goodies
64 const float transmission_efficiency_alpha = 0.1;
65 const float transmission_efficiency_threshold = 0.01;
66 float average_motor_torque_left = 0;
67 float average_motor_torque_right = 0;
68
69 // PJMC State goodies
70 // alpha = 2 / (N + 1), where N is the equivalent moving average window size
71 const float pjmc_state_time = 25; // seconds
72 const float pjmc_state_alpha = 2 / ((pjmc_state_time * LOOP_FREQ_HZ) + 1);
73 const float pjmc_state_threshold = 0.95;
74 float average_pjmc_state_left = 0;
75 float average_pjmc_state_right = 0;
76}
77
78// Returns true if error
79namespace error_triggers
80{
81 int soft(Exo* exo, ExoData* exo_data)
82 {
83 // if (error_triggers_state::triggered_error)
84 // return NO_ERROR;
85 return NO_ERROR;
86 }
87
88 int hard(Exo* exo, ExoData* exo_data)
89 {
90 // if (error_triggers_state::triggered_error)
91 // return NO_ERROR;
92 // Check if the legs have been in stance for too long
93 // error_triggers_state::average_pjmc_state_left = utils::ewma(exo_data->left_leg.toe_stance,
94 // error_triggers_state::average_pjmc_state_left, error_triggers_state::pjmc_state_alpha);
95 // error_triggers_state::average_pjmc_state_right = utils::ewma(exo_data->right_leg.toe_stance,
96 // error_triggers_state::average_pjmc_state_right, error_triggers_state::pjmc_state_alpha);
97 // bool left_stance_error = (error_triggers_state::average_pjmc_state_left > error_triggers_state::pjmc_state_threshold);
98 // bool right_stance_error = (error_triggers_state::average_pjmc_state_right > error_triggers_state::pjmc_state_threshold);
99 // if (left_stance_error || right_stance_error)
100 // {
101 // //logger::println("Error: PJMC State too high");
102 // error_triggers_state::triggered_error = true;
103 // exo_data->error_joint_id = (left_stance_error) ? (uint8_t)config_defs::joint_id::left_ankle : (uint8_t)config_defs::joint_id::right_ankle;
104 // return POOR_STATE_VARIANCE;
105 // }
106
107 return NO_ERROR;
108 }
109
110 int fatal(Exo* exo, ExoData* exo_data)
111 {
112 // if (error_triggers_state::triggered_error)
113 // return NO_ERROR;
114
115 // Only run for configurations with torque sensors
116 if (exo_data->config[config_defs::exo_name_idx] == (uint8_t)config_defs::exo_name::bilateral_ankle ||
117 exo_data->config[config_defs::exo_name_idx] == (uint8_t)config_defs::exo_name::bilateral_hip_ankle)
118 {
119 // Check if the torque is too high
120 error_triggers_state::average_torque_output_left = utils::ewma(exo_data->left_leg.ankle.torque_reading,
121 error_triggers_state::average_torque_output_left, error_triggers_state::torque_output_alpha);
122 error_triggers_state::average_torque_output_right = utils::ewma(exo_data->right_leg.ankle.torque_reading*-1,
123 error_triggers_state::average_torque_output_right, error_triggers_state::torque_output_alpha);
124 bool left_torque_error = (abs(error_triggers_state::average_torque_output_left) > error_triggers_state::torque_output_threshold);
125 bool right_torque_error = (abs(error_triggers_state::average_torque_output_right) > error_triggers_state::torque_output_threshold);
126 if (left_torque_error || right_torque_error)
127 {
128 //logger::println("Error: Torque too high");
129 error_triggers_state::triggered_error = true;
130 exo_data->error_joint_id = (left_torque_error) ? (uint8_t)config_defs::joint_id::left_ankle : (uint8_t)config_defs::joint_id::right_ankle;
132 }
133
134 // Check if the tracking error is too high
135 // float tracking_error_left = exo_data->left_leg.ankle.torque_reading - exo_data->left_leg.ankle.controller.ff_setpoint;
136 // float tracking_error_right = (exo_data->right_leg.ankle.torque_reading*-1) - exo_data->right_leg.ankle.controller.ff_setpoint;
137 // error_triggers_state::average_tracking_error_left = utils::ewma(tracking_error_left,
138 // error_triggers_state::average_tracking_error_left, error_triggers_state::tracking_alpha);
139 // error_triggers_state::average_tracking_error_right = utils::ewma(tracking_error_right,
140 // error_triggers_state::average_tracking_error_right, error_triggers_state::tracking_alpha);
141 // bool left_tracking_error = (abs(error_triggers_state::average_tracking_error_left) > error_triggers_state::tracking_threshold);
142 // bool right_tracking_error = (abs(error_triggers_state::average_tracking_error_right) > error_triggers_state::tracking_threshold);
143 // if (left_tracking_error || right_tracking_error)
144 // {
145 // //logger::println("Error: Tracking error too high");
146 // error_triggers_state::triggered_error = true;
147 // exo_data->error_joint_id = (left_tracking_error) ? (uint8_t)config_defs::joint_id::left_ankle : (uint8_t)config_defs::joint_id::right_ankle;
148 // return TRACKING_ERROR;
149 // }
150
151
152 // Check the torque sensor variance, if the variance is too high, then the sensor may be faulty
153 error_triggers_state::torque_sensor_queue_left.push(exo_data->left_leg.ankle.torque_reading);
154 error_triggers_state::torque_sensor_queue_right.push(exo_data->right_leg.ankle.torque_reading*-1);
155 if (error_triggers_state::torque_sensor_queue_left.size() > error_triggers_state::torque_window_size)
156 {
157 error_triggers_state::torque_sensor_queue_left.pop();
158 error_triggers_state::torque_sensor_queue_right.pop();
159
160 std::pair<float, float> left_population_vals = utils::online_std_dev(error_triggers_state::torque_sensor_queue_left);
161 std::pair<float, float> right_population_vals = utils::online_std_dev(error_triggers_state::torque_sensor_queue_right);
162 std::pair<float, float> left_bounds = std::make_pair(left_population_vals.first - error_triggers_state::torque_std_dev_multiple*left_population_vals.second,
163 left_population_vals.first + error_triggers_state::torque_std_dev_multiple*left_population_vals.second);
164 std::pair<float, float> right_bounds = std::make_pair(right_population_vals.first - error_triggers_state::torque_std_dev_multiple*right_population_vals.second,
165 right_population_vals.first + error_triggers_state::torque_std_dev_multiple*right_population_vals.second);
166
167 error_triggers_state::torque_failure_count_left += float(utils::is_outside_range(exo_data->left_leg.ankle.torque_reading, left_bounds.first, left_bounds.second));
168 error_triggers_state::torque_failure_count_right += float(utils::is_outside_range(exo_data->right_leg.ankle.torque_reading*-1, right_bounds.first, right_bounds.second));
169 bool left_torque_variance_error = (error_triggers_state::torque_failure_count_left > error_triggers_state::failure_count_threshold);
170 bool right_torque_variance_error = (error_triggers_state::torque_failure_count_right > error_triggers_state::failure_count_threshold);
171 if (left_torque_variance_error || right_torque_variance_error)
172 {
173 //logger::println("Error: Torque sensor variance too high");
174 error_triggers_state::triggered_error = true;
175 exo_data->error_joint_id = (left_torque_variance_error) ? (uint8_t)config_defs::joint_id::left_ankle : (uint8_t)config_defs::joint_id::right_ankle;
177 }
178 }
179
180 // Check the force sensor variance, if the variance is too high, then the sensor may be faulty
181 error_triggers_state::force_sensor_queue_left.push(exo_data->left_leg.toe_fsr);
182 error_triggers_state::force_sensor_queue_right.push(exo_data->right_leg.toe_fsr);
183 if (error_triggers_state::force_sensor_queue_left.size() > error_triggers_state::force_window_size)
184 {
185 error_triggers_state::force_sensor_queue_left.pop();
186 error_triggers_state::force_sensor_queue_right.pop();
187
188 std::pair<float, float> left_population_vals = utils::online_std_dev(error_triggers_state::force_sensor_queue_left);
189 std::pair<float, float> right_population_vals = utils::online_std_dev(error_triggers_state::force_sensor_queue_right);
190 std::pair<float, float> left_bounds = std::make_pair(left_population_vals.first - error_triggers_state::force_std_dev_multiple*left_population_vals.second,
191 left_population_vals.first + error_triggers_state::force_std_dev_multiple*left_population_vals.second);
192 std::pair<float, float> right_bounds = std::make_pair(right_population_vals.first - error_triggers_state::force_std_dev_multiple*right_population_vals.second,
193 right_population_vals.first + error_triggers_state::force_std_dev_multiple*right_population_vals.second);
194
195 error_triggers_state::force_failure_count_left += float(utils::is_outside_range(exo_data->left_leg.toe_fsr, left_bounds.first, left_bounds.second));
196 error_triggers_state::force_failure_count_right += float(utils::is_outside_range(exo_data->right_leg.toe_fsr, right_bounds.first, right_bounds.second));
197 bool left_force_outside_range = utils::is_outside_range(exo_data->left_leg.toe_fsr, left_bounds.first, left_bounds.second);
198 bool right_force_outside_range = utils::is_outside_range(exo_data->right_leg.toe_fsr, right_bounds.first, right_bounds.second);
199 if (error_triggers_state::force_failure_count_left > error_triggers_state::failure_count_threshold ||
200 error_triggers_state::force_failure_count_right > error_triggers_state::failure_count_threshold)
201 {
202 error_triggers_state::triggered_error = true;
203 exo_data->error_joint_id = (left_force_outside_range) ? (uint8_t)config_defs::joint_id::left_ankle : (uint8_t)config_defs::joint_id::right_ankle;
205 }
206 }
207
208
209 // Limit the motor positions, Too much drift!
210 // error_triggers_state::filtered_motor_position_left = utils::ewma(exo_data->left_leg.ankle.motor.p,
211 // error_triggers_state::filtered_motor_position_left, error_triggers_state::motor_position_alpha);
212 // error_triggers_state::filtered_motor_position_right = utils::ewma(exo_data->right_leg.ankle.motor.p,
213 // error_triggers_state::filtered_motor_position_right, error_triggers_state::motor_position_alpha);
214
215 // // print the motor positions every 100 iterations
216 // static int count = 0;
217 // if (count++ % 100 == 0)
218 // {
219 // logger::print("LP:"+String(error_triggers_state::filtered_motor_position_left)+"\t");
220 // logger::print("RP:"+String(error_triggers_state::filtered_motor_position_right)+"\n");
221 // }
222
223 // bool left_motor_position_error = utils::is_outside_range(error_triggers_state::filtered_motor_position_left,
224 // error_triggers_state::left_position_bounds.first, error_triggers_state::left_position_bounds.second);
225 // bool right_motor_position_error = utils::is_outside_range(error_triggers_state::filtered_motor_position_right,
226 // error_triggers_state::right_position_bounds.first, error_triggers_state::right_position_bounds.second);
227
228 // if (left_motor_position_error || right_motor_position_error)
229 // {
230 // error_triggers_state::triggered_error = true;
231 // return MOTOR_POSTION_OUT_OF_BOUNDS;
232 // }
233
234 // // Check the motors a mechanical break, if the moment of ineria drops there may be a break, Too much noise!
235 // const float left_motor_torque = exo_data->left_leg.ankle.motor.i * exo->left_leg.get_Kt_for_joint((uint8_t) config_defs::joint_id::left_ankle);
236 // const float right_motor_torque = exo_data->right_leg.ankle.motor.i * exo->right_leg.get_Kt_for_joint((uint8_t) config_defs::joint_id::right_ankle);
237 // const float left_motor_accel = (exo_data->left_leg.ankle.motor.v - error_triggers_state::left_prev_velocity) / (1000 / LOOP_FREQ_HZ);
238 // const float right_motor_accel = (exo_data->right_leg.ankle.motor.v - error_triggers_state::right_prev_velocity) / (1000 / LOOP_FREQ_HZ);
239
240 // error_triggers_state::left_prev_velocity = exo_data->left_leg.ankle.motor.v;
241 // error_triggers_state::right_prev_velocity = exo_data->right_leg.ankle.motor.v;
242
243 // float left_motor_inertia = 0;
244 // float right_motor_inertia = 0;
245
246 // // if the motor is not accelerating, then the inertia is 0
247 // if (!utils::is_close_to(left_motor_accel, 0, 0.001))
248 // {
249 // left_motor_inertia = left_motor_torque / left_motor_accel;
250 // }
251 // if (!utils::is_close_to(right_motor_accel, 0, 0.001))
252 // {
253 // right_motor_inertia = right_motor_torque / right_motor_accel;
254 // }
255
256 // // print the motor inertia every 100 loops
257 // static int loop_count = 0;
258 // loop_count++;
259 // if (loop_count >= 99)
260 // {
261 // loop_count = 0;
262 // // logger::print("LN:"+String(left_motor_torque)+"\t");
263 // // logger::print("LD:"+String(left_motor_accel)+"\t");
264 // //logger::print("LI:"+String(left_motor_inertia)+"\t");
265 // logger::print("RN:"+String(right_motor_torque)+"\t");
266 // logger::print("RD:"+String(right_motor_accel)+"\t");
267 // logger::print("RI:"+String(right_motor_inertia)+"\n");
268 // }
269
270 // if (left_motor_inertia < error_triggers_state::motor_inertia_threshold ||
271 // right_motor_inertia < error_triggers_state::motor_inertia_threshold)
272 // {
273 // error_triggers_state::triggered_error = true;
274 // return MOTOR_INERTIA_ERROR;
275 // }
276
277 // Check the transmission efficiency. If its too low, the cable may be broken. Must low pass motor current to account for time delay, Too much noise!
278 // float left_motor_torque = abs(exo_data->left_leg.ankle.motor.i) * exo->left_leg.get_Kt_for_joint((uint8_t) config_defs::joint_id::left_ankle);
279 // error_triggers_state::average_motor_torque_left = utils::ewma(abs(left_motor_torque),
280 // error_triggers_state::average_motor_torque_left, error_triggers_state::transmission_efficiency_alpha);
281 // float right_motor_torque = abs(exo_data->right_leg.ankle.motor.i) * exo->right_leg.get_Kt_for_joint((uint8_t) config_defs::joint_id::right_ankle);
282 // error_triggers_state::average_motor_torque_right = utils::ewma(abs(right_motor_torque),
283 // error_triggers_state::average_motor_torque_right, error_triggers_state::transmission_efficiency_alpha);
284
285 // float left_transmission_efficiency = 1;
286 // float right_transmission_efficiency = 1;
287 // if (!utils::is_close_to(error_triggers_state::average_motor_torque_left, 0, 0.001))
288 // {
289 // left_transmission_efficiency = exo_data->left_leg.ankle.torque_reading / error_triggers_state::average_motor_torque_left;
290 // }
291 // if (!utils::is_close_to(error_triggers_state::average_motor_torque_right, 0, 0.001))
292 // {
293 // right_transmission_efficiency = exo_data->right_leg.ankle.torque_reading / error_triggers_state::average_motor_torque_right;
294 // }
295
296 // if ((abs(left_transmission_efficiency) < error_triggers_state::transmission_efficiency_threshold) ||
297 // (abs(right_transmission_efficiency) < error_triggers_state::transmission_efficiency_threshold))
298 // {
299 // logger::println("Error: Transmission efficiency too low");
300 // return POOR_TRANSMISSION_EFFICIENCY;
301 // }
302 }
303
304 return NO_ERROR;
305 }
306}
307
308#endif
309
310#endif // defined(ARDUINO_TEENSY36) || defined(ARDUINO_TEENSY41)
#define LOOP_FREQ_HZ
Definition Config.h:17
Declares for the different exo class that all the other components will live in.
Declares a class used to store data for the Exo to access.
Declares the functions needed and defines mapping between the INI keys and the exo components.
Class to store all the data related to the exo.
Definition ExoData.h:38
LegData right_leg
Definition ExoData.h:122
int error_joint_id
Definition ExoData.h:130
uint8_t * config
Definition ExoData.h:126
LegData left_leg
Definition ExoData.h:121
float torque_reading
Definition JointData.h:47
JointData ankle
Definition LegData.h:44
float toe_fsr
Definition LegData.h:59
@ FORCE_VARIANCE_ERROR
Definition error_types.h:31
@ TORQUE_OUT_OF_BOUNDS
Definition error_types.h:29
@ TORQUE_VARIANCE_ERROR
Definition error_types.h:30
@ NO_ERROR
Definition error_types.h:15
int size()
Check the size of the FIFO queue.
Definition BleMessageQueue.cpp:55
std::pair< float, float > online_std_dev(std::queue< float > set)
Given a set of data and maximum size. Returns the new mean and standard deviation.
Definition Utilities.cpp:350
float ewma(float new_value, float filter_value, float alpha)
Exponential Weighted Moving Average. Used to smooth out noisy data.
Definition Utilities.cpp:317
bool is_outside_range(float val, float min, float max)
Checks if a value is outside of a range.
Definition Utilities.cpp:384