TeensyNanoExoCode
Loading...
Searching...
No Matches
ble_commands.h
Go to the documentation of this file.
1
9#ifndef BLE_COMMANDS_H
10#define BLE_COMMANDS_H
11
12#include "Arduino.h"
13#include "ExoData.h"
14#include "ParseIni.h" // For config_defs
15#include "StatusDefs.h" // For ExoDataStatus_t
16#include "BleMessage.h"
17#include "ParamsFromSD.h"
18
19#include "UARTHandler.h"
20#include "uart_commands.h"
21#include "UART_msg_t.h"
22#include "Logger.h"
23
28typedef struct
29{
30 char command;
31 int length;
33
38namespace ble_names
39{
40 // Recieved Commands
41 static const char start = 'E';
42 static const char stop = 'G';
43 static const char cal_trq = 'H';
44 static const char cal_fsr = 'L';
45 static const char new_trq = 'F';
46 static const char new_fsr = 'R';
47 static const char assist = 'c';
48 static const char resist = 'S';
49 static const char motors_on = 'x';
50 static const char motors_off = 'w';
51 static const char mark = 'N';
52 static const char update_param = 'f';
53 static const char perturb = 'Y'; //TO DO: CHANGE THIS
54
55 // Sending Commands
56 static const char send_real_time_data = '?';
57 static const char send_batt = '~';
58 static const char send_cal_done = 'n';
59 static const char send_error_count = 'w';
60 static const char send_trq_cal = 'H';
61 static const char send_step_count = 's';
62 static const char cal_fsr_finished = 'n';
63
64};
65
66
67
72namespace ble
73{
74 static const ble_command_t commands[] =
75 {
76 // Recieved Commands
77 {ble_names::start, 0},
78 {ble_names::stop, 0},
79 {ble_names::cal_trq, 0},
80 {ble_names::cal_fsr, 0},
81 {ble_names::assist, 0},
82 {ble_names::resist, 0},
83 {ble_names::motors_on, 0},
84 {ble_names::motors_off, 0},
85 {ble_names::mark, 0},
86 {ble_names::perturb, 0},
87 {ble_names::new_fsr, 2},
88 {ble_names::new_trq, 4},
89 {ble_names::update_param, 4},
90
91 // Sending Commands
92 {ble_names::send_batt, 1},
93 {ble_names::send_real_time_data, 9},
94 {ble_names::send_error_count, 1},
95 {ble_names::send_cal_done, 0},
96 {ble_names::send_trq_cal, 2},
97 {ble_names::send_step_count, 2},
98 {ble_names::cal_fsr_finished, 0},
99 };
100};
101
107{
114 inline static int get_length_for_command(char command)
115 {
116 int length = -1;
117 //Get the ammount of characters to wait for
118 for(unsigned int i=0; i < sizeof(ble::commands)/sizeof(ble::commands[0]); i++)
119 {
120 if(command == ble::commands[i].command)
121 {
122 length = ble::commands[i].length;
123 break;
124 }
125 }
126 return length;
127 }
128
129
130}
131
137{
138 // Should be used sparingly, we chose to do this so that ExoData wasn't needlessly populated with variables
139 static const uint8_t k_max_joints = 6;
140 static uint8_t prev_controllers[k_max_joints] = {0, 0, 0, 0, 0, 0};
141
142}
143
151{
152 inline static void start(ExoData* data, BleMessage* msg)
153 {
154 // Start the trial (ie Enable motors and begin streaming data)
155 // if the joint is used; enable the motor, and set the controller to zero torque
156 data->for_each_joint(
157 // This is a lamda or anonymous function, see https://www.learncpp.com/cpp-tutorial/introduction-to-lambdas-anonymous-functions/
158 [](JointData* j_data, float* args)
159 {
160 if (j_data->is_used)
161 {
162 j_data->motor.enabled = 1;
163 }
164 return;
165 }
166 );
167
168 // Set the data status to running
170
171 // Send status update
172 UARTHandler* uart_handler = UARTHandler::get_instance();
173 UART_msg_t tx_msg;
174 tx_msg.command = UART_command_names::update_status;
175 tx_msg.joint_id = 0;
176 tx_msg.data[(uint8_t)UART_command_enums::status::STATUS] = data->get_status();
177 tx_msg.len = (uint8_t)UART_command_enums::status::LENGTH;
178 uart_handler->UART_msg(tx_msg);
179
180 delayMicroseconds(10);
181 // Send motor enable update
182 tx_msg.command = UART_command_names::update_motor_enable_disable;
183 tx_msg.joint_id = 0;
186 uart_handler->UART_msg(tx_msg);
187
188 delayMicroseconds(10);
189 // Send FSR Calibration and Refinement
190 tx_msg.command = UART_command_names::update_cal_fsr;
191 tx_msg.len = 0;
192 uart_handler->UART_msg(tx_msg);
193 }
194 inline static void stop(ExoData* data, BleMessage* msg)
195 {
196 // Stop the trial (inverse of start)
197 // Send trial summary data (step information)
198 data->for_each_joint(
199 // This is a lamda or anonymous function, see https://www.learncpp.com/cpp-tutorial/introduction-to-lambdas-anonymous-functions/
200 [](JointData* j_data, float* args)
201 {
202 if (j_data->is_used)
203 {
204 j_data->motor.enabled = 0;
205 }
206 return;
207 }
208 );
209
210 // Set the data status to off
212
213 // Send status update
214 UARTHandler* uart_handler = UARTHandler::get_instance();
215 UART_msg_t tx_msg;
216 tx_msg.command = UART_command_names::update_status;
217 tx_msg.joint_id = 0;
218 tx_msg.data[(uint8_t)UART_command_enums::status::STATUS] = data->get_status();
219 tx_msg.len = (uint8_t)UART_command_enums::status::LENGTH;
220 uart_handler->UART_msg(tx_msg);
221
222 delayMicroseconds(100);
223 // Send motor enable update
224 tx_msg.command = UART_command_names::update_motor_enable_disable;
225 tx_msg.joint_id = 0;
228 uart_handler->UART_msg(tx_msg);
229
230 //TODO: Reset ExoData and Exo
231 data->mark = 10;
232 }
233 inline static void cal_trq(ExoData* data, BleMessage* msg)
234 {
235 // Raise cal_trq flag for all joints being used, (Out of context: Should send calibration info upon cal completion)
236 data->for_each_joint([](JointData* j_data, float* args) {j_data->calibrate_torque_sensor = j_data->is_used;});
237
238 // Send cal_trq
239 UARTHandler* uart_handler = UARTHandler::get_instance();
240 UART_msg_t tx_msg;
241 tx_msg.command = UART_command_names::update_cal_trq_sensor;
242 tx_msg.joint_id = 0;
245 uart_handler->UART_msg(tx_msg);
246 }
247 inline static void cal_fsr(ExoData* data, BleMessage* msg)
248 {
249 UARTHandler* uart_handler = UARTHandler::get_instance();
250 UART_msg_t tx_msg;
251 tx_msg.command = UART_command_names::update_cal_fsr;
252 tx_msg.joint_id = 0;
253 tx_msg.data[(uint8_t)UART_command_enums::cal_fsr::CAL_FSR] = 1;
255 uart_handler->UART_msg(tx_msg);
256 tx_msg.command = UART_command_names::update_refine_fsr;
257 tx_msg.len = 0;
258 uart_handler->UART_msg(tx_msg);
259 }
260 inline static void assist(ExoData* data, BleMessage* msg)
261 {
262 // Change PJMC parameter to assist
263 // Need to implement PJMC
264 }
265 inline static void resist(ExoData* data, BleMessage* msg)
266 {
267 // Change PJMC parameter to resist
268 // Need to implement PJMC
269 }
270 inline static void motors_on(ExoData* data, BleMessage* msg)
271 {
272 // Enable Motors, stateless (ie keep running fault detection algorithms)
273 // int count = 0;
274 // data->for_each_joint(
275 // [&count, &(ble_handler_vars::prev_controllers)](JointData* j_data)
276 // {
277 // j_data->controller.controller = ble_handler_vars::prev_controllers[count];
278 // count++;
279 // }
280 // );
281
282 data->for_each_joint(
283 // This is a lamda or anonymous function, see https://www.learncpp.com/cpp-tutorial/introduction-to-lambdas-anonymous-functions/
284 [](JointData* j_data, float* args)
285 {
286 if (j_data->is_used)
287 {
288 j_data->motor.enabled = 1;
289 }
290 return;
291 }
292 );
293
294 UARTHandler* uart_handler = UARTHandler::get_instance();
295 UART_msg_t tx_msg;
296 tx_msg.command = UART_command_names::update_motor_enable_disable;
297 tx_msg.joint_id = 0;
300 uart_handler->UART_msg(tx_msg);
301
302 }
303 inline static void motors_off(ExoData* data, BleMessage* msg)
304 {
305 // Disable Motors, stateless (ie keep running fault detection algorithms)
306 // Chnage to stasis and save the previous controller
307 // int count = 0;
308 // data->for_each_joint(
309 // [&count, &(ble_handler_vars::prev_controllers)](JointData* j_data)
310 // {
311 // ble_handler_vars::prev_controllers[count] = (uint8_t)j_data->controller.controller;
312 // count++;
313
314 // j_data->controller.controller = (uint8_t)config_defs::ankle_controllers::stasis;
315 // }
316 // );
317
318 data->for_each_joint(
319 // This is a lamda or anonymous function, see https://www.learncpp.com/cpp-tutorial/introduction-to-lambdas-anonymous-functions/
320 [](JointData* j_data, float* args)
321 {
322 if (j_data->is_used)
323 {
324 j_data->motor.enabled = 0;
325 }
326 return;
327 }
328 );
329
330 UARTHandler* uart_handler = UARTHandler::get_instance();
331 UART_msg_t tx_msg;
332 tx_msg.command = UART_command_names::update_motor_enable_disable;
333 tx_msg.joint_id = 0;
336 uart_handler->UART_msg(tx_msg);
337
338 }
339 inline static void mark(ExoData* data, BleMessage* msg)
340 {
341 // Increment mark variable (Done by sending different data on one of the real time signals, we should raise a flag or inc a var in exo_data)
342 data->mark++;
343 }
344 inline static void new_trq(ExoData* data, BleMessage* msg)
345 {
346 // logger::print("Ankle ID: "); logger::println((uint8_t)data->left_leg.ankle.id);
347 // logger::println("Got New Trq:");
348 // logger::print(msg->data[0]); logger::print("\t");
349 // logger::print(msg->data[1]); logger::print("\t");
350 // logger::print(msg->data[2]); logger::print("\t");
351 // logger::print(msg->data[3]); logger::print("\t\r\n");
352 // (LSP, LDSP, RSP, RDSP) Unpack message data
353 config_defs::joint_id joint_id = (config_defs::joint_id)msg->data[0];
354 uint8_t controller_id = (uint8_t)msg->data[1];
355 uint8_t set_num = (uint8_t)msg->data[2];
356 // Update Exo_Data controller for each joint
357 ControllerData* cont_data = NULL;
358
359 // Map the joint IDs because the GUI limits the maximum number for the message
360 joint_id = (joint_id==(config_defs::joint_id)1)?(data->left_leg.hip.id):(joint_id);
361 joint_id = (joint_id==(config_defs::joint_id)2)?(data->left_leg.knee.id):(joint_id);
362 joint_id = (joint_id==(config_defs::joint_id)3)?(data->left_leg.ankle.id):(joint_id);
363 joint_id = (joint_id==(config_defs::joint_id)4)?(data->right_leg.hip.id):(joint_id);
364 joint_id = (joint_id==(config_defs::joint_id)5)?(data->right_leg.knee.id):(joint_id);
365 joint_id = (joint_id==(config_defs::joint_id)6)?(data->right_leg.ankle.id):(joint_id);
366
367 if (joint_id == data->left_leg.ankle.id) {
368 //logger::println("ble_handlers::new_trq() - Left Ankle");
369 cont_data = &data->left_leg.ankle.controller;
370 } else if (joint_id == data->left_leg.knee.id) {
371 cont_data = &data->left_leg.knee.controller;
372 } else if (joint_id == data->left_leg.hip.id) {
373 cont_data = &data->left_leg.hip.controller;
374 } else if (joint_id == data->right_leg.ankle.id) {
375 //logger::println("ble_handlers::new_trq() - Right Ankle");
376 cont_data = &data->right_leg.ankle.controller;
377 } else if (joint_id == data->right_leg.knee.id) {
378 cont_data = &data->right_leg.knee.controller;
379 } else if (joint_id == data->right_leg.hip.id) {
380 cont_data = &data->right_leg.hip.controller;
381 }
382 if (cont_data == NULL) {
383 //logger::println("cont_data is NULL!");
384 }
385 if (cont_data != NULL) {
386 cont_data->controller = controller_id;
387 cont_data->parameter_set = set_num;
388 }
389
390 //set_controller_params((uint8_t)joint_id, controller_id, set_num, data);
391 UARTHandler* uart_handler = UARTHandler::get_instance();
392 UART_msg_t tx_msg;
393 tx_msg.command = UART_command_names::update_controller_params;
394 tx_msg.joint_id = (uint8_t) joint_id;
395 tx_msg.data[(uint8_t)UART_command_enums::controller_params::CONTROLLER_ID] = controller_id;
398 tx_msg.len = 3;
399 uart_handler->UART_msg(tx_msg);
400 //logger::println("ble_handlers::new_trq() - Sent UART message");
401 UART_msg_t_utils::print_msg(tx_msg);
402 }
403 inline static void new_fsr(ExoData* data, BleMessage* msg)
404 {
405 // Change contact thresholds for the feet
406 // Send UART message to update FSR thresholds
407 UARTHandler* uart_handler = UARTHandler::get_instance();
408 UART_msg_t tx_msg;
409 tx_msg.command = UART_command_names::update_FSR_thesholds;
410 tx_msg.joint_id = 0;
412 tx_msg.data[(uint8_t)UART_command_enums::FSR_thresholds::LEFT_THRESHOLD] = msg->data[0];
413 tx_msg.data[(uint8_t)UART_command_enums::FSR_thresholds::RIGHT_THRESHOLD] = msg->data[1];
414 uart_handler->UART_msg(tx_msg);
415 }
416
417 inline static void update_param(ExoData* data, BleMessage* msg)
418 {
419 //Send UART message to update parameter
420 //logger::println("ble_handlers::update_param() - Got update param message");
421 //logger::print("ble_handlers::update_param() - Joint ID: "); logger::println((uint8_t)msg->data[0]);
422 //logger::print("ble_handlers::update_param() - Controller ID: "); logger::println((uint8_t)msg->data[1]);
423 //logger::print("ble_handlers::update_param() - Param Index: "); logger::println((uint8_t)msg->data[2]);
424 //logger::print("ble_handlers::update_param() - Param Value: "); logger::println((uint8_t)msg->data[3]);
425 UARTHandler* uart_handler = UARTHandler::get_instance();
426 UART_msg_t tx_msg;
427 tx_msg.command = UART_command_names::update_controller_param;
428 tx_msg.joint_id = (uint8_t) msg->data[0];
429 tx_msg.data[(uint8_t)UART_command_enums::controller_param::CONTROLLER_ID] = (uint8_t) msg->data[1];
430 tx_msg.data[(uint8_t)UART_command_enums::controller_param::PARAM_INDEX] = (uint8_t) msg->data[2];
431 tx_msg.data[(uint8_t)UART_command_enums::controller_param::PARAM_VALUE] = (uint8_t) msg->data[3];
432 tx_msg.len = 3;
433 uart_handler->UART_msg(tx_msg);
434 }
435
436 inline static void perturb(ExoData* data, BleMessage* msg)
437 {
438 // Get joints that are being used
439 const uint8_t max_joints = 6;
440 uint8_t used_joints[max_joints];
441 uint8_t used_joint_len = data->get_used_joints(used_joints);
442 bool is_hip;
443 bool is_knee;
444 bool is_ankle;
445
446 // Pick a used jointa at random
447 uint8_t rand_idx = (uint8_t)random(0, used_joint_len);
448 // Determine if the selected joint is hip, knee, or ankle
449 if (used_joints[rand_idx] != 0 && (data->left_leg.hip.is_used == 1 || data->right_leg.hip.is_used ==1))
450 {
451 is_hip = 1;
452 }
453 else
454 {
455 is_hip = 0;
456 }
457 if (used_joints[rand_idx] != 0 && (data->left_leg.knee.is_used == 1 || data->right_leg.knee.is_used == 1))
458 {
459 is_knee = 1;
460 }
461 else
462 {
463 is_knee = 0;
464 }
465 if (used_joints[rand_idx] != 0 && (data->left_leg.ankle.is_used == 1 || data->right_leg.ankle.is_used == 1))
466 {
467 is_ankle = 1;
468 }
469 else
470 {
471 is_ankle = 0;
472 }
473 // Safety check
474 if (((is_hip + is_knee + is_ankle) > 1) || (is_hip + is_knee + is_ankle) == 0)
475 {
476 // The joint type check failed, abort
477 logger::println("ble_handlers::perturb()->Failed to reconcile joint type!");
478 return;
479 }
480
481 // Get controller id
482 uint8_t controller_id = 0;
483 if (is_hip)
484 {
485 controller_id = (uint8_t)config_defs::hip_controllers::perturbation;
486 }
487 else if (is_knee)
488 {
489 controller_id = (uint8_t)config_defs::knee_controllers::perturbation;
490 }
491 else if (is_ankle)
492 {
493 controller_id = (uint8_t)config_defs::ankle_controllers::perturbation;
494 }
495
496 //TODO: Check that the controller is already the pertubation controller
497 //JointData* joint = data->get_joint_with(used_joints[rand_idx]);
498 //if (joint->controller.controller)
499
500 // Send message over UART
501 /* UARTHandler* uart_handler = UARTHandler::get_instance();
502 UART_msg_t tx_msg;
503 tx_msg.command = UART_command_names::update_controller_param;
504 tx_msg.joint_id = used_joints[rand_idx];
505 tx_msg.data[(uint8_t)UART_command_enums::controller_param::CONTROLLER_ID] = controller_id;
506 tx_msg.data[(uint8_t)UART_command_enums::controller_param::PARAM_INDEX] = (uint8_t)controller_defs::perturbation::perturb_idx;
507 tx_msg.data[(uint8_t)UART_command_enums::controller_param::PARAM_VALUE] = (uint8_t)1;
508 tx_msg.len = 4;
509 uart_handler->UART_msg(tx_msg);*/
510
511 // If Perturb all joints
512 /*
513 for (int i = 0; i < used_joint_len; i++)
514 {
515 uint8_t is_hip = used_joints[i] & config_defs::joint_id::hip;
516 uint8_t is_knee = used_joints[i] & config_defs::joint_id::knee;
517 uint8_t is_ankle = used_joints[i] & config_defs::joint_id::ankle;
518 // Safety check
519 if (((is_hip + is_knee + is_ankle) > 1) || (is_hip + is_knee + is_ankle) == 0)
520 {
521 // The joint type check failed, abort
522 logger::println("ble_handlers::perturb()->Failed to reconcile joint type!");
523 return;
524 }
525
526 // Get controller id
527 uint8_t controller_id = 0;
528 if (is_hip)
529 {
530 controller_id = (uint8_t)config_defs::hip_controllers::perturbation;
531 }
532 else if (is_knee)
533 {
534 controller_id = (uint8_t)config_defs::knee_controllers::perturbation;
535 }
536 else if (is_ankle)
537 {
538 controller_id = (uint8_t)config_defs::ankle_controllers::perturbation;
539 }
540
541 // Send message over UART
542 UARTHandler* uart_handler = UARTHandler::get_instance();
543 UART_msg_t tx_msg;
544 tx_msg.command = UART_command_names::update_controller_param;
545 tx_msg.joint_id = used_joints[rand_idx];
546 tx_msg.data[(uint8_t)UART_command_enums::controller_param::CONTROLLER_ID] = controller_id;
547 tx_msg.data[(uint8_t)UART_command_enums::controller_param::PARAM_INDEX] = (uint8_t)controller_defs::perturbation::perturb_idx;
548 tx_msg.data[(uint8_t)UART_command_enums::controller_param::PARAM_VALUE] = (uint8_t)1;
549 tx_msg.len = 4;
550 uart_handler->UART_msg(tx_msg);
551 delayMicroseconds(10);
552 }
553 */
554 }
555
556}
557
558#endif
Defines the BleMessage class used to hold command-data pairs exchanged between the GUI.
Declares a class used to store data for the Exo to access.
Declares the functions to pull controller parameters from the SD card and defines the mapping to the ...
Declares the functions needed and defines mapping between the INI keys and the exo components.
Stores the different status messages for the system.
Singleton class that manages the UART data. NOT THREAD SAFE. The class queues recieved messages.
Definition BleMessage.h:16
class to store information related to controllers.
Definition ControllerData.h:301
uint8_t parameter_set
Definition ControllerData.h:326
uint8_t controller
Definition ControllerData.h:320
Class to store all the data related to the exo.
Definition ExoData.h:38
void for_each_joint(F &&func)
performs a function for each joint
Definition ExoData.h:55
uint32_t mark
Definition ExoData.h:124
LegData right_leg
Definition ExoData.h:122
uint8_t get_used_joints(uint8_t *used_joints)
Definition ExoData.cpp:37
uint16_t get_status(void)
Get the status object.
Definition ExoData.cpp:98
LegData left_leg
Definition ExoData.h:121
void set_status(uint16_t status_to_set)
Set the status object.
Definition ExoData.cpp:88
class to store information related to joint.
Definition JointData.h:33
bool calibrate_torque_sensor
Definition JointData.h:51
config_defs::joint_id id
Definition JointData.h:44
bool is_used
Definition JointData.h:50
ControllerData controller
Definition JointData.h:46
JointData knee
Definition LegData.h:43
JointData ankle
Definition LegData.h:44
JointData hip
Definition LegData.h:42
Singleton Class to handle the UART Work.
Definition UARTHandler.h:54
void UART_msg(uint8_t msg_id, uint8_t len, uint8_t joint_id, float *buffer)
Packs and sends a UART message.
Definition UARTHandler.cpp:35
static UARTHandler * get_instance()
Get the instance object.
Definition UARTHandler.cpp:29
Helper function(s) to be used with the command array.
Definition ble_commands.h:107
Variables used by the Handlers to track state.
Definition ble_commands.h:137
Holds the functions that should be called when a command is received. All command handlers should hav...
Definition ble_commands.h:151
Creates a variable for each command value.
Definition ble_commands.h:39
Associates the command and ammount of data that it expects to be sent/received.
Definition ble_commands.h:73
joint_id
Definition ParseIni.h:106
const uint16_t trial_on
Definition StatusDefs.h:31
const uint16_t trial_off
Definition StatusDefs.h:30
Definition UART_msg_t.h:9
float data[UART_MSG_T_MAX_DATA_LEN]
Definition UART_msg_t.h:12
uint8_t len
Definition UART_msg_t.h:13
uint8_t joint_id
Definition UART_msg_t.h:11
uint8_t command
Definition UART_msg_t.h:10
Type to associate a command with an ammount of data.
Definition ble_commands.h:29
char command
Definition ble_commands.h:30
int length
Definition ble_commands.h:31