diff --git a/controls/DataAnalysisTool/Tool/simplePlots.m b/controls/DataAnalysisTool/Tool/simplePlots.m new file mode 100644 index 0000000000000000000000000000000000000000..edd91bf4aa05002531109897c7c0f6ca162ed387 --- /dev/null +++ b/controls/DataAnalysisTool/Tool/simplePlots.m @@ -0,0 +1,70 @@ +%% +plot(Time, Cam_Meas_Roll*(180/pi)); hold on; +plot(Time, Quad_Meas_Roll*(180/pi)); + +%% +plot(Time, pitch_velocity*(180/pi)); hold on; +plot(Time, roll_velocity*(180/pi)); +plot(Time, yaw_velocity*(180/pi)); + +%% +figure; +plot(time, VRPNPitchConstant*(180/pi)); hold on; +plot(time, PitchConstant*(180/pi)); +legend('Camera Pitch', 'Quad Pitch'); +xlabel('seconds'); ylabel('degrees'); + +%% +figure; +plot(time, (VRPNRollConstant + pi)*(180/pi)); hold on; +plot(time, RollConstant*(180/pi)); +legend('Camera Roll', 'Quad Roll'); +xlabel('seconds'); ylabel('degrees'); + +%% +%plot(Time, X_setpoint); hold on; +markerSize = 3; +ax1 = subplot(2,1,1); +plot(time, (XSetpointConstant - VRPNXConstant), '-o', 'MarkerSize', markerSize); hold on; +plot(time, -XposPIDCorrection * (180/pi), '-o', 'MarkerSize', markerSize); hold off; +legend('X Error', 'X PID output'); + + +ax2 = subplot(2,1,2); +plot(time, (180/pi)*PitchConstant, '-o', 'MarkerSize', markerSize); hold on; +plot(time, (180/pi)*PitchPIDCorrection, '-o', 'MarkerSize', markerSize); +legend('Pitch Error', 'Pitch PID output'); + +linkaxes([ax1, ax2], 'x'); +%% +ax2 = subplot(2,2,1); +plot(time, XSetpointConstant - VRPNXConstant); +title('X error'); + +ax1 = subplot(2,2,2); +plot(time, XposPIDCorrection); +title('x output'); + +ax3 = subplot(2,2,3); +plot(time, PitchPIDCorrection); hold on; +plot(time, VRPNPitchConstant .* 10); +title('pitch output'); +legend('output', 'Pitch'); + +ax4 = subplot(2,2,4); +plot(time, PitchRatePIDCorrection); hold on; +plot(time, gyro_y .* 1044.26); +legend('output', 'Pitch rate'); +title('pitch rate output'); + +linkaxes([ax1, ax2, ax3, ax4], 'x'); +%% +plot(time, 1044.26 .* (PitchPIDCorrection - gyro_y));hold on; +%plot(time, PitchRatePIDCorrection); +%% +ax2 = subplot(2, 1, 1); +plot(time, YawConstant); +ax1 = subplot(2, 1, 2); +plot(time, gyro_z); hold on; +plot(time, YawRatePIDCorrection); +linkaxes([ax1, ax2], 'x'); \ No newline at end of file diff --git a/controls/model/c_controller.c b/controls/model/c_controller.c new file mode 100644 index 0000000000000000000000000000000000000000..6bcee0997d9c72199d6983b738bac881478fdbe6 --- /dev/null +++ b/controls/model/c_controller.c @@ -0,0 +1,72 @@ +#include "c_controller.h" +#include "quad_files/control_algorithm.c" +#include "quad_files/computation_graph.c" +double c_controller(int vrpn_id, double vrpn_ts, double set_x, double set_y, double set_z, double set_yaw, + double cur_x, double cur_y, double cur_z, + double cur_phi, double cur_theta, double cur_psi, + double cur_phi_d, double cur_theta_d, double cur_psi_d, + double *z_out, double *y_out, double *x_out, double *yaw_out, + double* pid_y_out, double* pid_roll_out) { + + static log_t log_struct; + static user_input_t user_input_struct; + static sensor_t sensor_struct; + static setpoint_t setpoint_struct; + static parameter_t ps; + static user_defined_t user_defined_struct; + static actuator_command_t actuator_struct; + static modular_structs_t structs; + + static int last_vrpn_id = -1; + static int initialized = 0; + if (!initialized) { + control_algorithm_init(&ps); + sensor_struct.currentQuadPosition.packetId = vrpn_id; + initialized = 1; + } + + // Check VRPN update + if (vrpn_id != last_vrpn_id) { + user_input_struct.locationFresh = 1; + int vrpn_ts_packets = (vrpn_ts / 0.01) + 0.5; // + 0.5 to round + sensor_struct.currentQuadPosition.packetId += vrpn_ts_packets; + // VRPN values + sensor_struct.currentQuadPosition.x_pos = cur_x; + sensor_struct.currentQuadPosition.y_pos = cur_y; + sensor_struct.currentQuadPosition.alt_pos = cur_z; + sensor_struct.currentQuadPosition.pitch = cur_theta; + sensor_struct.currentQuadPosition.roll = cur_phi; + sensor_struct.currentQuadPosition.yaw = cur_psi; + last_vrpn_id = vrpn_id; + } + + // Setpoints + /* + setpoint_struct.desiredQuadPosition.x_pos = set_x; + setpoint_struct.desiredQuadPosition.y_pos = set_y; + setpoint_struct.desiredQuadPosition.alt_pos = set_z; + setpoint_struct.desiredQuadPosition.yaw = set_yaw; + */ + int i; + + // Sensors + sensor_struct.pitch_angle_filtered = cur_theta; + sensor_struct.roll_angle_filtered = cur_phi; + sensor_struct.theta_dot = cur_theta_d; + sensor_struct.phi_dot = cur_phi_d; + sensor_struct.psi_dot = cur_psi_d; + + control_algorithm(&log_struct, &user_input_struct, &sensor_struct, &setpoint_struct, &ps, &user_defined_struct, &actuator_struct, NULL); + + *z_out = graph_get_output(ps.graph, ps.alt_pid, PID_CORRECTION); + *y_out = graph_get_output(ps.graph, ps.roll_r_pid, PID_CORRECTION); + *x_out = graph_get_output(ps.graph, ps.pitch_r_pid, PID_CORRECTION); + *yaw_out = graph_get_output(ps.graph, ps.yaw_r_pid, PID_CORRECTION); + + *pid_y_out = graph_get_output(ps.graph, ps.y_pos_pid, PID_CORRECTION); + *pid_roll_out = graph_get_output(ps.graph, ps.roll_pid, PID_CORRECTION); + return 0; +} + +int read_flap(int flap) { return AUTO_FLIGHT_MODE; } +float get_last_loop_time() { return 0.005; } diff --git a/controls/model/c_controller.h b/controls/model/c_controller.h new file mode 100644 index 0000000000000000000000000000000000000000..e53b1a508409d70211a99fe6ba6de76e092ae7a5 --- /dev/null +++ b/controls/model/c_controller.h @@ -0,0 +1,18 @@ +#ifndef C_CONTROLLER_H +#define C_CONTROLLER_H +#include "quad_files/computation_graph.h" +#include "quad_files/graph_blocks/node_pid.h" +#include "quad_files/graph_blocks/node_bounds.h" +#include "quad_files/graph_blocks/node_constant.h" +#include "quad_files/graph_blocks/node_mixer.h" +#include "quad_files/PID.h" +#include "quad_files/control_algorithm.h" + +double c_controller(int vrpn_id, double vrpn_ts, double set_x, double set_y, double set_z, double set_yaw, + double cur_x, double cur_y, double cur_z, + double cur_phi, double cur_theta, double cur_psi, + double cur_phi_d, double cur_theta_d, double cur_psi_d, + double *z_out, double *y_out, double *x_out, double *yaw_out, + double* pid_y_out, double* pid_roll_out); + +#endif // C_CONTROLLER_H \ No newline at end of file diff --git a/controls/model/modelParameters.m b/controls/model/modelParameters.m index e457e0332bd2705446dba5aa74145ebb9f26aeb0..f01946f1f512a9e114c26b68b801b0581d243f04 100644 --- a/controls/model/modelParameters.m +++ b/controls/model/modelParameters.m @@ -20,7 +20,8 @@ If = 0.511; % Motor internal friction current Pmin = 1e5; % Minimum zybo output duty cycle command Pmax = 2e5; % Maximum zybo output duty cycle command - Tc = 0.01; % Camera system sampling period + Tc = 0.04; % Camera system sampling period + Tq = 0.005; % Quad sampling period tau_c = 0; % Camera system total latency Vb = 11.1; % Nominal battery voltage (V) x_controlled_o = 0; % Equilibrium lateral controller output diff --git a/controls/model/quad_files/.gitignore b/controls/model/quad_files/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..1c4bc674e912af84e9c6bed639cd5780a68b7846 --- /dev/null +++ b/controls/model/quad_files/.gitignore @@ -0,0 +1,3 @@ +# Don't track the copied files here +*.h +*.c \ No newline at end of file diff --git a/controls/model/quad_files/copy_files.bat b/controls/model/quad_files/copy_files.bat new file mode 100644 index 0000000000000000000000000000000000000000..bd5f65861b103ddaf3b761a47c9bc584bb35b50b --- /dev/null +++ b/controls/model/quad_files/copy_files.bat @@ -0,0 +1,27 @@ +copy ..\..\..\quad\computation_graph\src\computation_graph.c computation_graph.c +copy ..\..\..\quad\computation_graph\src\computation_graph.h computation_graph.h + +copy ..\..\..\quad\sw\modular_quad_pid\src\control_algorithm.h control_algorithm.h +copy ..\..\..\quad\sw\modular_quad_pid\src\control_algorithm.c control_algorithm.c + +copy ..\..\..\quad\sw\modular_quad_pid\src\PID.h PID.h +copy ..\..\..\quad\sw\modular_quad_pid\src\type_def.h type_def.h +copy ..\..\..\quad\sw\modular_quad_pid\src\sensor_processing.h sensor_processing.h +copy ..\..\..\quad\sw\modular_quad_pid\src\log_data.h log_data.h +copy ..\..\..\quad\sw\modular_quad_pid\src\quadposition.h quadposition.h +copy ..\..\..\quad\sw\modular_quad_pid\src\util.h util.h +copy ..\..\..\quad\sw\modular_quad_pid\src\timer.h timer.h +copy ..\..\..\groundStation\src\backend\commands.h commands.h +copy ..\..\..\groundStation\src\backend\callbacks.h callbacks.h + +mkdir graph_blocks +copy ..\..\..\quad\computation_graph\src\graph_blocks\node_constant.h graph_blocks\node_constant.h +copy ..\..\..\quad\computation_graph\src\graph_blocks\node_constant.c graph_blocks\node_constant.c +copy ..\..\..\quad\computation_graph\src\graph_blocks\node_add.h graph_blocks\node_add.h +copy ..\..\..\quad\computation_graph\src\graph_blocks\node_add.c graph_blocks\node_add.c +copy ..\..\..\quad\sw\modular_quad_pid\src\graph_blocks\node_mixer.c graph_blocks\node_mixer.c +copy ..\..\..\quad\sw\modular_quad_pid\src\graph_blocks\node_mixer.h graph_blocks\node_mixer.h +copy ..\..\..\quad\sw\modular_quad_pid\src\graph_blocks\node_pid.c graph_blocks\node_pid.c +copy ..\..\..\quad\sw\modular_quad_pid\src\graph_blocks\node_pid.h graph_blocks\node_pid.h +copy ..\..\..\quad\sw\modular_quad_pid\src\graph_blocks\node_bounds.c graph_blocks\node_bounds.c +copy ..\..\..\quad\sw\modular_quad_pid\src\graph_blocks\node_bounds.h graph_blocks\node_bounds.h \ No newline at end of file diff --git a/controls/model/test_model.slx b/controls/model/test_model.slx index 805e43a9e1d83040c87b713476195126ca17d371..d95ac846d3726b2898b9a6499f563588a52764c8 100644 Binary files a/controls/model/test_model.slx and b/controls/model/test_model.slx differ diff --git a/quad/computation_graph/src/computation_graph.c b/quad/computation_graph/src/computation_graph.c index 5fcfd4c5c76ad7c221da927c410f45184c5c0578..7434e14a112117b8dbe22a3ecd300b04c6c90413 100644 --- a/quad/computation_graph/src/computation_graph.c +++ b/quad/computation_graph/src/computation_graph.c @@ -103,7 +103,7 @@ int graph_add_node(struct computation_graph *graph, new_node->n_children = 0; new_node->updated = 1; new_node->output_values = malloc(type->n_outputs * sizeof(double)); - new_node->param_values = malloc(type->n_params * sizeof(double)); + new_node->param_values = calloc(type->n_params, sizeof(double)); new_node->input_srcs = malloc(type->n_inputs * sizeof(struct input_type)); // Check that malloc succeeded in every case which memory was requested if ((type->n_outputs && !new_node->output_values) || diff --git a/quad/computation_graph/src/graph_blocks/node_add.c b/quad/computation_graph/src/graph_blocks/node_add.c index eefb22fde9ae9a5cc72d2eb679905f2e70038ac9..048a49b3b6a9c054f74900e356e6377f17a6a4b7 100644 --- a/quad/computation_graph/src/graph_blocks/node_add.c +++ b/quad/computation_graph/src/graph_blocks/node_add.c @@ -8,7 +8,7 @@ static void reset(void *state) {} static const char* const in_names[2] = {"Summand 1", "Summand 2"}; static const char* const out_names[1] = {"Sum"}; -static const char* const param_names[0] = {}; +static const char* const param_names[1] = {"Error if you see this"}; const struct graph_node_type node_add_type = { .input_names = in_names, .output_names = out_names, diff --git a/quad/computation_graph/src/graph_blocks/node_constant.c b/quad/computation_graph/src/graph_blocks/node_constant.c index 8ad9f8c5afdb5dc8f4cfacac00f2725ad388a59a..b2a46e757eef397b4c9805d4b76a159fccc6c9a0 100644 --- a/quad/computation_graph/src/graph_blocks/node_constant.c +++ b/quad/computation_graph/src/graph_blocks/node_constant.c @@ -6,7 +6,7 @@ static void output_const(void *state, const double *params, const double *inputs } static void reset(void *state) {} -static const char* const in_names[0] = {}; +static const char* const in_names[1] = {"You shouldn't see this"}; static const char* const out_names[1] = {"Constant"}; static const char* const param_names[1] = {"Constant"}; const struct graph_node_type node_const_type = { diff --git a/quad/sw/modular_quad_pid/src/PID.h b/quad/sw/modular_quad_pid/src/PID.h index a7701ab2a8a8701343d4e65d5688759d70aba2b9..4c5e4b81f0273a9a62aa175b6c0f350914fb67a2 100644 --- a/quad/sw/modular_quad_pid/src/PID.h +++ b/quad/sw/modular_quad_pid/src/PID.h @@ -49,6 +49,7 @@ #define YPOS_KP 0.015f #define YPOS_KI 0.005f #define YPOS_KD 0.03f +#define YPOS_ALPHA 0 //Pitch constants @@ -74,6 +75,7 @@ #define XPOS_KP -0.015f #define XPOS_KI -0.005f #define XPOS_KD -0.03f +#define XPOS_ALPHA 0 //Throttle constants diff --git a/quad/sw/modular_quad_pid/src/control_algorithm.c b/quad/sw/modular_quad_pid/src/control_algorithm.c index 7a92f9f6bf6b7883d37f12d4f9cbc0dc207041fc..428323fd44a78db6f0be841ea870d0dcdd8deff9 100644 --- a/quad/sw/modular_quad_pid/src/control_algorithm.c +++ b/quad/sw/modular_quad_pid/src/control_algorithm.c @@ -174,9 +174,11 @@ int control_algorithm_init(parameter_t * ps) graph_set_param_val(graph, ps->x_pos_pid, PID_KP, XPOS_KP); graph_set_param_val(graph, ps->x_pos_pid, PID_KI, XPOS_KI); graph_set_param_val(graph, ps->x_pos_pid, PID_KD, XPOS_KD); + graph_set_param_val(graph, ps->x_pos_pid, PID_ALPHA, XPOS_ALPHA); graph_set_param_val(graph, ps->y_pos_pid, PID_KP, YPOS_KP); graph_set_param_val(graph, ps->y_pos_pid, PID_KI, YPOS_KI); graph_set_param_val(graph, ps->y_pos_pid, PID_KD, YPOS_KD); + graph_set_param_val(graph, ps->y_pos_pid, PID_ALPHA, YPOS_ALPHA); graph_set_param_val(graph, ps->alt_pid, PID_KP, ALT_ZPOS_KP); graph_set_param_val(graph, ps->alt_pid, PID_KI, ALT_ZPOS_KI); graph_set_param_val(graph, ps->alt_pid, PID_KD, ALT_ZPOS_KD); @@ -189,6 +191,10 @@ int control_algorithm_init(parameter_t * ps) graph_set_param_val(graph, ps->clamp_d_pwmY, BOUNDS_MIN, -PWM_DIFF_BOUNDS); graph_set_param_val(graph, ps->clamp_d_pwmY, BOUNDS_MAX, PWM_DIFF_BOUNDS); + + // Initial value for sampling periods + graph_set_param_val(graph, ps->pos_time, CONST_SET, 0.04); + graph_set_param_val(graph, ps->angle_time, CONST_SET, 0.005); // Set initial mode connect_manual(ps); @@ -243,7 +249,7 @@ int control_algorithm_init(parameter_t * ps) user_defined_struct->flight_mode = AUTO_FLIGHT_MODE; connect_autonomous(ps); // Reset this when autonomous is engaged, so there is not a large difference at the start of autonomous - last_vrpn_id = sensor_struct->currentQuadPosition.packetId; + last_vrpn_id = sensor_struct->currentQuadPosition.packetId - 1; } //PIDS/////////////////////////////////////////////////////////////////////// diff --git a/quad/sw/modular_quad_pid/src/graph_blocks/node_mixer.c b/quad/sw/modular_quad_pid/src/graph_blocks/node_mixer.c index 8b702b360654b3e957d19743abc24b433f58f64d..316c1ce8218b835ee002c8c4352c97af111b318d 100644 --- a/quad/sw/modular_quad_pid/src/graph_blocks/node_mixer.c +++ b/quad/sw/modular_quad_pid/src/graph_blocks/node_mixer.c @@ -25,7 +25,7 @@ static void reset_mixer(void *state) {} static const char* const in_names[4] = {"Throttle", "Pitch", "Roll", "Yaw"}; static const char* const out_names[4] = {"PWM 0", "PWM 1", "PWM 2", "PWM 3"}; -static const char* const param_names[0] = {}; +static const char* const param_names[1] = {"You shouldnt see this"}; const struct graph_node_type node_mixer_type = { .input_names = in_names, .output_names = out_names, diff --git a/quad/sw/modular_quad_pid/src/graph_blocks/node_pid.c b/quad/sw/modular_quad_pid/src/graph_blocks/node_pid.c index acf77b5b4051c446067dfaea395a05cf89d1f916..7222094577d6c4ba1f41c93f65e5bdbe00c4dc75 100644 --- a/quad/sw/modular_quad_pid/src/graph_blocks/node_pid.c +++ b/quad/sw/modular_quad_pid/src/graph_blocks/node_pid.c @@ -8,6 +8,7 @@ static double FLT_EPSILON = 0.0001; struct pid_node_state { double prev_error; // Previous error double acc_error; // Accumulated error + double last_filtered; // Last output from the filtered derivative }; // The generic PID diagram. This function takes in pid inputs (CUR_POINT and SETOINT) and calculates the output "pid_correction" @@ -49,13 +50,20 @@ static void pid_computation(void *state, const double* params, const double *inp pid_state->acc_error += error; } - double change_in_error = error - pid_state->prev_error; // Compute each term's contribution P = params[PID_KP] * error; I = params[PID_KI] * pid_state->acc_error * inputs[PID_DT]; - D = params[PID_KD] * (change_in_error / inputs[PID_DT]); - + // Low-pass filter on derivative + double change_in_error = error - pid_state->prev_error; + double term1 = params[PID_ALPHA] * pid_state->last_filtered; + double derivative = change_in_error / inputs[PID_DT]; + if (inputs[PID_DT] == 0) { // Divide by zero check + derivative = 0; + } + double term2 = params[PID_KD] * (1.0f - params[PID_ALPHA]) * derivative; + D = term1 + term2; + pid_state->last_filtered = D; // Store filtered value for next filter iteration pid_state->prev_error = error; // Store the current error into the state outputs[PID_CORRECTION] = P + I + D; // Store the computed correction @@ -67,19 +75,20 @@ static void reset_pid(void *state) { struct pid_node_state* pid_state = (struct pid_node_state*)state; pid_state->acc_error = 0; pid_state->prev_error = 0; + pid_state->last_filtered = 0; } static const char* const in_names[3] = {"Cur point", "Setpoint", "dt"}; static const char* const out_names[1] = {"Correction"}; -static const char* const param_names[3] = {"Kp", "Ki", "Kd"}; +static const char* const param_names[4] = {"Kp", "Ki", "Kd", "alpha"}; const struct graph_node_type node_pid_type = { .input_names = in_names, .output_names = out_names, .param_names = param_names, .n_inputs = 3, .n_outputs = 1, - .n_params = 3, + .n_params = 4, .execute = pid_computation, .reset = reset_pid }; diff --git a/quad/sw/modular_quad_pid/src/graph_blocks/node_pid.h b/quad/sw/modular_quad_pid/src/graph_blocks/node_pid.h index 75ded4af02edbc2cacbc68035f5a0970d65e38dc..ee841adde3e19f7ef86930bdb94da4e8eee76488 100644 --- a/quad/sw/modular_quad_pid/src/graph_blocks/node_pid.h +++ b/quad/sw/modular_quad_pid/src/graph_blocks/node_pid.h @@ -19,7 +19,8 @@ enum graph_node_pid_outputs { enum graph_node_pid_params { PID_KP, // Proportional constant PID_KI, // Integral constant - PID_KD // Derivative constant + PID_KD, // Derivative constant + PID_ALPHA // alpha = (1 - N*T_s); High values mean more filtering }; #endif // __NODE_PID_H__