diff --git a/quad/sw/modular_quad_pid/src/computation_graph.c b/quad/sw/modular_quad_pid/src/computation_graph.c new file mode 120000 index 0000000000000000000000000000000000000000..b4ff9ed9c10b3956ed2f586c7e3fab989e5f550d --- /dev/null +++ b/quad/sw/modular_quad_pid/src/computation_graph.c @@ -0,0 +1 @@ +computation_graph/src/computation_graph.c \ No newline at end of file diff --git a/quad/sw/modular_quad_pid/src/computation_graph.h b/quad/sw/modular_quad_pid/src/computation_graph.h new file mode 120000 index 0000000000000000000000000000000000000000..b8b749d0f0e89c67392f7d4d610cddf7e44bb374 --- /dev/null +++ b/quad/sw/modular_quad_pid/src/computation_graph.h @@ -0,0 +1 @@ +computation_graph/src/computation_graph.h \ No newline at end of file diff --git a/quad/sw/modular_quad_pid/src/control_algorithm.c b/quad/sw/modular_quad_pid/src/control_algorithm.c index 63ba756137739578a39f2609048a3728027266c7..757cc8a9b628a10fd5a547bdb9ed6730766f28a7 100644 --- a/quad/sw/modular_quad_pid/src/control_algorithm.c +++ b/quad/sw/modular_quad_pid/src/control_algorithm.c @@ -6,58 +6,111 @@ */ // This implemented modular quadrotor software implements a PID control algorithm - + #include "control_algorithm.h" #include "communication.h" +#include "graph_blocks/node_pid.h" +#include "graph_blocks/node_bounds.h" +#include "graph_blocks/node_constant.h" #define ROLL_PITCH_MAX_ANGLE 0.3490 // 20 degrees - int control_algorithm_init(parameter_t * parameter_struct) + int control_algorithm_init(parameter_t * ps) { - // HUMAN Piloted (RC) PID DEFINITIONS ////// - // RC PIDs for roll (2 loops: angle --> angular velocity) - parameter_struct->pid_controllers[ROLL_ID].dt = 0.005; parameter_struct->pid_controllers[ROLL_RATE_ID].dt = 0.005; // 5 ms calculation period - - // RC PIDs for pitch (2 loops: angle --> angular velocity) - parameter_struct->pid_controllers[PITCH_ID].dt = 0.005; parameter_struct->pid_controllers[PITCH_RATE_ID].dt = 0.005; // 5 ms calculation period - - // initialize Yaw PID_t and PID constants - // RC PID for yaw (1 loop angular velocity) - parameter_struct->pid_controllers[YAW_RATE_ID].dt = 0.005; // 5 ms calculation period - - // AUTOMATIC Pilot (Position) PID DEFINITIONS ////// - // Local X PID using a translation from X camera system data to quad local X position (3 loops: local y position --> angle --> angular velocity) - parameter_struct->pid_controllers[LOCAL_X_ID].dt = 0.100; - - // Local Y PID using a translation from Y camera system data to quad local Y position(3 loops: local x position --> angle --> angular velocity) - parameter_struct->pid_controllers[LOCAL_Y_ID].dt = 0.100; - - // CAM PIDs for yaw (2 loops angle --> angular velocity) - parameter_struct->pid_controllers[YAW_ID].dt = 0.100; - - // CAM PID for altitude (1 loop altitude) - parameter_struct->pid_controllers[ALT_ID].dt = 0.100; - - // PID coeffiecients (Position) - setPIDCoeff(&(parameter_struct->pid_controllers[LOCAL_Y_ID]), YPOS_KP, YPOS_KI, YPOS_KD); - setPIDCoeff(&(parameter_struct->pid_controllers[LOCAL_X_ID]), XPOS_KP, XPOS_KI, XPOS_KD); - setPIDCoeff(&(parameter_struct->pid_controllers[ALT_ID]), ALT_ZPOS_KP, ALT_ZPOS_KI, ALT_ZPOS_KD); - - // PID coefficients (Angle) - setPIDCoeff(&(parameter_struct->pid_controllers[PITCH_ID]), PITCH_ANGLE_KP, PITCH_ANGLE_KI, PITCH_ANGLE_KD); - setPIDCoeff(&(parameter_struct->pid_controllers[ROLL_ID]), ROLL_ANGLE_KP, ROLL_ANGLE_KI, ROLL_ANGLE_KD); - setPIDCoeff(&(parameter_struct->pid_controllers[YAW_ID]), YAW_ANGLE_KP, YAW_ANGLE_KI, YAW_ANGLE_KD); - - // PID coefficients (Angular Velocity) - setPIDCoeff(&(parameter_struct->pid_controllers[PITCH_RATE_ID]), PITCH_ANGULAR_VELOCITY_KP, PITCH_ANGULAR_VELOCITY_KI, PITCH_ANGULAR_VELOCITY_KD); - setPIDCoeff(&(parameter_struct->pid_controllers[ROLL_RATE_ID]), ROLL_ANGULAR_VELOCITY_KP, ROLL_ANGULAR_VELOCITY_KI, ROLL_ANGULAR_VELOCITY_KD); - setPIDCoeff(&(parameter_struct->pid_controllers[YAW_RATE_ID]), YAW_ANGULAR_VELOCITY_KP, YAW_ANGULAR_VELOCITY_KI, YAW_ANGULAR_VELOCITY_KD); + struct computation_graph* graph = create_graph(); + ps->graph = graph; + + // Create all the PID blocks + ps->roll_pid = graph_add_node_pid("Roll PID"); + ps->pitch_pid = graph_add_node_pid("Pitch PID"); + ps->yaw_pid = graph_add_node_pid("Yaw PID"); + ps->roll_r_pid = graph_add_node_pid("Roll Rate PID"); + ps->pitch_r_pid = graph_add_node_pid("Pitch Rate PID"); + ps->yaw_r_pid = graph_add_node_pid("Yaw Rate PID"); + ps->x_pos_pid = graph_add_node_pid("X pos PID PID"); + ps->y_pos_pid = graph_add_node_pid("Y pos PID"); + ps->alt_pid = graph_add_node_pid("Altitude"); + + // Create blocks for sensor inputs + ps->cur_pitch = graph_add_node_const("Pitch"); + ps->cur_roll = graph_add_node_const("Roll"); + ps->cur_yaw = graph_add_node_const("Yaw"); + // Yaw angular velocity PID + // theta_dot is the angular velocity about the y-axis + // phi_dot is the angular velocity about the x-axis + // psi_dot is the angular velocity about the z-axis + // These are calculated from using the gimbal equations + ps->theta = graph_add_node_const("Theta"); + ps->phi = graph_add_node_const("Phi"); + ps->psi = graph_add_node_const("Psi"); + + // Create blocks for RC controller + ps->rc_pitch = graph_add_node_const("RC Pitch"); + ps->rc_roll = graph_add_node_const("RC Roll"); + ps->rc_yaw = graph_add_node_const("RC Yaw"); + ps->rc_throttle = graph_add_node_const("RC Throttle"); + + ps->dt = graph_add_node_const("dT"); + + // Connect pitch PID chain + graph_set_source(graph, ps->pitch_r_pid, PID_SETPOINT, ps->pitch_pid, PID_CORRECTION); + graph_set_source(graph, ps->pitch_r_pid, PID_CUR_POINT, ps->theta, CONST_VAL); + graph_set_source(graph, ps->pitch_r_pid, PID_DT, ps->dt, CONST_VAL); + graph_set_source(graph, ps->pitch_pid, PID_SETPOINT, ps->rc_pitch, CONST_VAL); + graph_set_source(graph, ps->pitch_pid, PID_CUR_POINT, ps->pitch, CONST_VAL); + graph_set_source(graph, ps->pitch_pid, PID_DT, ps->dt, CONST_VAL); + + // Connect roll PID chain + graph_set_source(graph, ps->roll_r_pid, PID_SETPOINT, ps->roll_pid, PID_CORRECTION); + graph_set_source(graph, ps->roll_r_pid, PID_CUR_POINT, ps->phi, CONST_VAL); + graph_set_source(graph, ps->roll_r_pid, PID_DT, ps->dt, CONST_VAL); + graph_set_source(graph, ps->roll_pid, PID_SETPOINT, ps->rc_roll, CONST_VAL); + graph_set_source(graph, ps->roll_pid, PID_CUR_POINT, ps->roll, CONST_VAL); + graph_set_source(graph, ps->roll_pid, PID_DT, ps->dt, CONST_VAL); + + // Connect yaw PID chain + graph_set_source(graph, ps->yaw_r_pid, PID_SETPOINT, ps->rc_yaw, PID_CORRECTION); + graph_set_source(graph, ps->yaw_r_pid, PID_CUR_POINT, ps->psi, CONST_VAL); + graph_set_source(graph, ps->yaw_r_pid, PID_DT, ps->dt, CONST_VAL); + /* + graph_set_source(graph, ps->yaw_pid, PID_SETPOINT, ps->rc_yaw, CONST_VAL); + graph_set_source(graph, ps->yaw_pid, PID_CUR_POINT, ps->yaw, CONST_VAL); + graph_set_source(graph, ps->yaw_pid, PID_DT, ps->dt, CONST_VAL); + */ + + // Set pitch PID constants + graph_set_param_val(graph, ps->pitch_pid, PID_KP, PITCH_ANGLE_KP); + graph_set_param_val(graph, ps->pitch_pid, PID_KI, PITCH_ANGLE_KI); + graph_set_param_val(graph, ps->pitch_pid, PID_KD, PITCH_ANGLE_KD); + graph_set_param_val(graph, ps->pitch_r_pid, PID_KP, PITCH_ANGULAR_VELOCITY_KP); + graph_set_param_val(graph, ps->pitch_r_pid, PID_KI, PITCH_ANGULAR_VELOCITY_KI); + graph_set_param_val(graph, ps->pitch_r_pid, PID_KD, PITCH_ANGULAR_VELOCITY_KD); + + // Set roll PID constants + graph_set_param_val(graph, ps->roll_pid, PID_KP, ROLL_ANGLE_KP); + graph_set_param_val(graph, ps->roll_pid, PID_KI, ROLL_ANGLE_KI); + graph_set_param_val(graph, ps->roll_pid, PID_KD, ROLL_ANGLE_KD); + graph_set_param_val(graph, ps->roll_r_pid, PID_KP, ROLL_ANGULAR_VELOCITY_KP); + graph_set_param_val(graph, ps->roll_r_pid, PID_KI, ROLL_ANGULAR_VELOCITY_KI); + graph_set_param_val(graph, ps->roll_r_pid, PID_KD, ROLL_ANGULAR_VELOCITY_KD); + + // Set yaw PID constants + graph_set_param_val(graph, ps->yaw_pid, PID_KP, YAW_ANGLE_KP); + graph_set_param_val(graph, ps->yaw_pid, PID_KI, YAW_ANGLE_KI); + graph_set_param_val(graph, ps->yaw_pid, PID_KD, YAW_ANGLE_KD); + graph_set_param_val(graph, ps->yaw_r_pid, PID_KP, YAW_ANGULAR_VELOCITY_KP); + graph_set_param_val(graph, ps->yaw_r_pid, PID_KI, YAW_ANGULAR_VELOCITY_KI); + graph_set_param_val(graph, ps->yaw_r_pid, PID_KD, YAW_ANGULAR_VELOCITY_KD); + + // TODO: Change this to use LOOP_TIME + graph_set_param_val(graph, ps->dt, CONST_SET, 0.005); return 0; } - + int control_algorithm(log_t* log_struct, user_input_t * user_input_struct, sensor_t* sensor_struct, setpoint_t* setpoint_struct, parameter_t* parameter_struct, user_defined_t* user_defined_struct, raw_actuator_t* raw_actuator_struct, modular_structs_t* structs) { + struct computation_graph* graph = parameter_struct->graph; // use the 'flap' switch as the flight mode selector int cur_fm_switch = read_flap(user_input_struct->rc_commands[FLAP]); static int last_fm_switch = MANUAL_FLIGHT_MODE; @@ -101,6 +154,8 @@ // also reset the previous error and accumulated error from the position PIDs if((cur_fm_switch == AUTO_FLIGHT_MODE) && (user_defined_struct->engaging_auto == 2)) { + // TODO: Change this to reconnect PIDs + /* // zero out the accumulated error so the I terms don't cause wild things to happen parameter_struct->pid_controllers[ALT_ID].acc_error = 0.0; parameter_struct->pid_controllers[LOCAL_X_ID].acc_error = 0.0; @@ -118,7 +173,7 @@ // reset the flag that engages auto mode user_defined_struct->engaging_auto = 0; - + */ // finally engage the AUTO_FLIGHT_MODE // this ensures that we've gotten a new update packet right after the switch was set to auto mode user_defined_struct->flight_mode = AUTO_FLIGHT_MODE; @@ -135,6 +190,8 @@ if(user_input_struct->locationFresh) { + // TODO: Change this to populate VRPN block + /* parameter_struct->pid_controllers[LOCAL_Y_ID].current_point = sensor_struct->currentQuadPosition.y_pos; parameter_struct->pid_controllers[LOCAL_Y_ID].setpoint = setpoint_struct->desiredQuadPosition.y_pos; @@ -143,90 +200,46 @@ parameter_struct->pid_controllers[ALT_ID].current_point = sensor_struct->currentQuadPosition.alt_pos; parameter_struct->pid_controllers[ALT_ID].setpoint = setpoint_struct->desiredQuadPosition.alt_pos; - + */ //logging and PID computation - log_struct->local_y_PID_values = pid_computation(&(parameter_struct->pid_controllers[LOCAL_Y_ID])); - log_struct->local_x_PID_values = pid_computation(&(parameter_struct->pid_controllers[LOCAL_X_ID])); - log_struct->altitude_PID_values = pid_computation(&(parameter_struct->pid_controllers[ALT_ID])); + //log_struct->local_y_PID_values = pid_computation(&(parameter_struct->pid_controllers[LOCAL_Y_ID])); + //log_struct->local_x_PID_values = pid_computation(&(parameter_struct->pid_controllers[LOCAL_X_ID])); + //log_struct->altitude_PID_values = pid_computation(&(parameter_struct->pid_controllers[ALT_ID])); // yaw angular position PID calculation - parameter_struct->pid_controllers[YAW_ID].current_point = sensor_struct->currentQuadPosition.yaw;// in radians - parameter_struct->pid_controllers[YAW_ID].setpoint = setpoint_struct->desiredQuadPosition.yaw; // constant setpoint + graph_set_param_val(graph, parameter_struct->cur_yaw, CONST_SET, sensor_struct->currentQuadPosition.yaw); + // TODO: Set yaw setpoint + //parameter_struct->pid_controllers[YAW_ID].current_point = sensor_struct->currentQuadPosition.yaw;// in radians + //parameter_struct->pid_controllers[YAW_ID].setpoint = setpoint_struct->desiredQuadPosition.yaw; // constant setpoint //logging and PID computation - log_struct->angle_yaw_PID_values = pid_computation(&(parameter_struct->pid_controllers[YAW_ID])); + //log_struct->angle_yaw_PID_values = pid_computation(&(parameter_struct->pid_controllers[YAW_ID])); } + graph_set_param_val(graph, parameter_struct->cur_pitch, CONST_SET, sensor_struct->pitch_angle_filtered); + graph_set_param_val(graph, parameter_struct->cur_roll, CONST_SET, sensor_struct->roll_angle_filtered); + graph_set_param_val(graph, parameter_struct->cur_theta, CONST_SET, sensor_struct->theta_dot); + graph_set_param_val(graph, parameter_struct->cur_phi, CONST_SET, sensor_struct->phi_dot); + graph_set_param_val(graph, parameter_struct->cur_psi, CONST_SET, sensor_struct->psi_dot); - /* Angle loop - * Calculates current orientation, and outputs - * a pitch, roll, or yaw velocity for the angular velocity loop PIDs - */ + graph_set_param_val(graph, parameter_struct->rc_pitch, CONST_SET, user_input_struct->pitch_angle_manual_setpoint); + graph_set_param_val(graph, parameter_struct->rc_roll, CONST_SET, user_input_struct->roll_angle_manual_setpoint); + graph_set_param_val(graph, parameter_struct->rc_yaw, CONST_SET, user_input_struct->yaw_manual_setpoint); - //angle boundaries - if(parameter_struct->pid_controllers[LOCAL_X_ID].pid_correction > ROLL_PITCH_MAX_ANGLE) - { - parameter_struct->pid_controllers[LOCAL_X_ID].pid_correction = ROLL_PITCH_MAX_ANGLE; - } - if(parameter_struct->pid_controllers[LOCAL_X_ID].pid_correction < -ROLL_PITCH_MAX_ANGLE) - { - parameter_struct->pid_controllers[LOCAL_X_ID].pid_correction = -ROLL_PITCH_MAX_ANGLE; - } - if(parameter_struct->pid_controllers[LOCAL_Y_ID].pid_correction > ROLL_PITCH_MAX_ANGLE) - { - parameter_struct->pid_controllers[LOCAL_Y_ID].pid_correction = ROLL_PITCH_MAX_ANGLE; - } - if(parameter_struct->pid_controllers[LOCAL_Y_ID].pid_correction < -ROLL_PITCH_MAX_ANGLE) - { - parameter_struct->pid_controllers[LOCAL_Y_ID].pid_correction = -ROLL_PITCH_MAX_ANGLE; - } - parameter_struct->pid_controllers[PITCH_ID].current_point = sensor_struct->pitch_angle_filtered; - parameter_struct->pid_controllers[PITCH_ID].setpoint = - /*(user_defined_struct->flight_mode == AUTO_FLIGHT_MODE)? - (parameter_struct->pid_controllers[LOCAL_X_ID].pid_correction) + pitch_trim :*/ user_input_struct->pitch_angle_manual_setpoint; + /*parameter_struct->pid_controllers[PITCH_ID].setpoint = + (user_defined_struct->flight_mode == AUTO_FLIGHT_MODE)? + (parameter_struct->pid_controllers[LOCAL_X_ID].pid_correction) + pitch_trim : user_input_struct->pitch_angle_manual_setpoint; - parameter_struct->pid_controllers[ROLL_ID].current_point = sensor_struct->roll_angle_filtered; parameter_struct->pid_controllers[ROLL_ID].setpoint = - /*(user_defined_struct->flight_mode == AUTO_FLIGHT_MODE)? - (parameter_struct->pid_controllers[LOCAL_Y_ID].pid_correction) + roll_trim :*/ user_input_struct->roll_angle_manual_setpoint; - - - //logging and PID computation - log_struct->angle_pitch_PID_values = pid_computation(&(parameter_struct->pid_controllers[PITCH_ID])); - log_struct->angle_roll_PID_values = pid_computation(&(parameter_struct->pid_controllers[ROLL_ID])); - - - /* Angular Velocity Loop - * Takes the desired angular velocity from the angle loop, - * and calculates a PID correction with the current angular velocity - */ - - // theta_dot is the angular velocity about the y-axis - // it is calculated from using the gimbal equations - parameter_struct->pid_controllers[PITCH_RATE_ID].current_point = sensor_struct->theta_dot; - parameter_struct->pid_controllers[PITCH_RATE_ID].setpoint = parameter_struct->pid_controllers[PITCH_ID].pid_correction; - - // phi_dot is the angular velocity about the x-axis - // it is calculated from using the gimbal equations - parameter_struct->pid_controllers[ROLL_RATE_ID].current_point = sensor_struct->phi_dot; - parameter_struct->pid_controllers[ROLL_RATE_ID].setpoint = parameter_struct->pid_controllers[ROLL_ID].pid_correction; - - // Yaw angular velocity PID - // psi_dot is the angular velocity about the z-axis - // it is calculated from using the gimbal equations - parameter_struct->pid_controllers[YAW_RATE_ID].current_point = sensor_struct->psi_dot; - parameter_struct->pid_controllers[YAW_RATE_ID].setpoint = /*(user_defined_struct->flight_mode == AUTO_FLIGHT_MODE)? - parameter_struct->pid_controllers[YAW_ID].pid_correction :*/ user_input_struct->yaw_manual_setpoint; // no trim added because the controller already works well - - //logging and PID computation - log_struct->ang_vel_pitch_PID_values = pid_computation(&(parameter_struct->pid_controllers[PITCH_RATE_ID])); - log_struct->ang_vel_roll_PID_values = pid_computation(&(parameter_struct->pid_controllers[ROLL_RATE_ID])); - log_struct->ang_vel_yaw_PID_values = pid_computation(&(parameter_struct->pid_controllers[YAW_RATE_ID])); - - //END PIDs/////////////////////////////////////////////////////////////////////// + (user_defined_struct->flight_mode == AUTO_FLIGHT_MODE)? + (parameter_struct->pid_controllers[LOCAL_Y_ID].pid_correction) + roll_trim : user_input_struct->roll_angle_manual_setpoint; + */ + graph_compute_node(graph, parameter_struct->pitch_r_pid); + graph_compute_node(graph, parameter_struct->roll_r_pid); + graph_compute_node(graph, parameter_struct->yaw_r_pid); // here for now so in case any flight command is not PID controlled, it will default to rc_command value: memcpy(raw_actuator_struct->controller_corrected_motor_commands, user_input_struct->rc_commands, sizeof(int) * 6); @@ -238,6 +251,7 @@ if(user_defined_struct->flight_mode == AUTO_FLIGHT_MODE) { + /* //THROTTLE raw_actuator_struct->controller_corrected_motor_commands[THROTTLE] = ((int)(parameter_struct->pid_controllers[ALT_ID].pid_correction)) + sensor_struct->trims.throttle; @@ -253,6 +267,7 @@ //YAW raw_actuator_struct->controller_corrected_motor_commands[YAW] = parameter_struct->pid_controllers[YAW_RATE_ID].pid_correction;// + sensor_struct->trims.yaw; + */ // static int slow_down = 0; // slow_down++; @@ -268,17 +283,18 @@ else{ //ROLL raw_actuator_struct->controller_corrected_motor_commands[ROLL] = - parameter_struct->pid_controllers[ROLL_RATE_ID].pid_correction; + graph_get_output(graph, parameter_struct->roll_r_pid, PID_CORRECTION); //PITCH raw_actuator_struct->controller_corrected_motor_commands[PITCH] = - parameter_struct->pid_controllers[PITCH_RATE_ID].pid_correction; + graph_get_output(graph, parameter_struct->pitch_r_pid, PID_CORRECTION); //YAW raw_actuator_struct->controller_corrected_motor_commands[YAW] = - parameter_struct->pid_controllers[YAW_RATE_ID].pid_correction; + graph_get_output(graph, parameter_struct->yaw_r_pid, PID_CORRECTION); } + // TODO: Make these blocks //BOUNDS CHECKING if(raw_actuator_struct->controller_corrected_motor_commands[THROTTLE] < 0) raw_actuator_struct->controller_corrected_motor_commands[THROTTLE] = 0; @@ -314,6 +330,7 @@ // here we are not actually duplicating the logging from the PID computation // the PID computation logs PID_values struct where this logs the PID struct // they contain different sets of data + /* log_struct->local_y_PID = parameter_struct->pid_controllers[LOCAL_Y_ID]; log_struct->local_x_PID = parameter_struct->pid_controllers[LOCAL_X_ID]; log_struct->altitude_PID = parameter_struct->pid_controllers[ALT_ID]; @@ -325,7 +342,7 @@ log_struct->ang_vel_roll_PID = parameter_struct->pid_controllers[ROLL_RATE_ID]; log_struct->ang_vel_pitch_PID = parameter_struct->pid_controllers[PITCH_RATE_ID]; log_struct->ang_vel_yaw_PID = parameter_struct->pid_controllers[YAW_RATE_ID]; - + */ last_fm_switch = cur_fm_switch; // Make location stale now @@ -333,7 +350,7 @@ return 0; } - + void setPIDCoeff(PID_t* p, float pValue, float iValue, float dValue) { p->Kp = pValue; @@ -341,4 +358,3 @@ p->Kd = dValue; } - diff --git a/quad/sw/modular_quad_pid/src/graph_blocks/node_bounds.c b/quad/sw/modular_quad_pid/src/graph_blocks/node_bounds.c new file mode 100644 index 0000000000000000000000000000000000000000..aae4a67957a3d76c89d44480962e7b426b94f235 --- /dev/null +++ b/quad/sw/modular_quad_pid/src/graph_blocks/node_bounds.c @@ -0,0 +1,33 @@ +#include "node_bounds.h" +#include <stdlib.h> + +static void bounds_computation(void *state, const double* params, const double *inputs, double *outputs) { + double to_be_bounded = inputs[BOUNDS_IN]; + if (to_be_bounded < params[BOUNDS_MIN]) { + to_be_bounded = params[BOUNDS_MIN]; + } + if (to_be_bounded > params[BOUNDS_MAX]) { + to_be_bounded = params[BOUNDS_MAX]; + } + outputs[BOUNDS_OUT] = to_be_bounded; +} + +static void reset_bounds(void *state) {} + +static const char* const in_names[1] = {"Bounds in"}; +static const char* const out_names[1] = {"Bounded"}; +static const char* const param_names[2] = {"Min", "Max"}; +const struct graph_node_type node_bounds_type = { + .input_names = in_names, + .output_names = out_names, + .param_names = param_names, + .n_inputs = 1, + .n_outputs = 1, + .n_params = 2, + .execute = bounds_computation, + .reset = reset_bounds +}; + +int graph_add_node_bounds(struct computation_graph *graph, const char* name) { + return graph_add_node(graph, name, &node_bounds_type, NULL); +} diff --git a/quad/sw/modular_quad_pid/src/graph_blocks/node_bounds.h b/quad/sw/modular_quad_pid/src/graph_blocks/node_bounds.h new file mode 100644 index 0000000000000000000000000000000000000000..15415488f46e61d425931d9b363c9fc6479d750a --- /dev/null +++ b/quad/sw/modular_quad_pid/src/graph_blocks/node_bounds.h @@ -0,0 +1,22 @@ +#ifndef __NODE_BOUNDS_H__ +#define __NODE_BOUNDS_H__ +#include "computation_graph.h" + +int graph_add_node_bounds(struct computation_graph *graph, const char* name); + +extern const struct graph_node_type node_bounds_type; + +enum graph_node_bounds_inputs { + BOUNDS_IN, // Input to be bounded +}; + +enum graph_node_bounds_outputs { + BOUNDS_OUT // Boundde output +}; + +enum graph_node_bounds_params { + BOUNDS_MIN, + BOUNDS_MAX +}; + +#endif // __NODE_BOUNDS_H__ diff --git a/quad/sw/modular_quad_pid/src/graph_blocks/node_constant.c b/quad/sw/modular_quad_pid/src/graph_blocks/node_constant.c new file mode 120000 index 0000000000000000000000000000000000000000..0e47b26d1b909f68d792a4d8326da82893ffb76a --- /dev/null +++ b/quad/sw/modular_quad_pid/src/graph_blocks/node_constant.c @@ -0,0 +1 @@ +computation_graph/src/node_constant.c \ No newline at end of file diff --git a/quad/sw/modular_quad_pid/src/graph_blocks/node_constant.h b/quad/sw/modular_quad_pid/src/graph_blocks/node_constant.h new file mode 120000 index 0000000000000000000000000000000000000000..a231d9af0f982561c18f45fe9838f5e2862a7610 --- /dev/null +++ b/quad/sw/modular_quad_pid/src/graph_blocks/node_constant.h @@ -0,0 +1 @@ +computation_graph/src/node_constant.h \ No newline at end of file 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 new file mode 100644 index 0000000000000000000000000000000000000000..745cf0dad11b68a7611885db034d76aeb0bccf66 --- /dev/null +++ b/quad/sw/modular_quad_pid/src/graph_blocks/node_pid.c @@ -0,0 +1,89 @@ +#include "node_pid.h" +#include <stdlib.h> + +struct pid_node_state { + double prev_error; // Previous error + double acc_error; // Accumulated error +}; + +// The generic PID diagram. This function takes in pid inputs (CUR_POINT and SETOINT) and calculates the output "pid_correction" +// part based on those parameters. +// +// + --- error ------------------ P + --- ---------------------------- +// setpoint ---> / sum \ --------->| Kp * error |--------------->/ sum \ -------->| output: "pid_correction" | +// \ / | ------------------ \ / ---------------------------- +// --- | --- || +// - ^ | + ^ ^ + || +// | | ------------------------------- | | ------- \/------------ +// | |----->| Ki * accumulated error * dt |----+ | | | +// | | ------------------------------- I | | SYSTEM | +// | | | | | +// | | | --------||------------ +// | | | || +// | | ---------------------------------- | || +// | |----->| Kd * (error - last error) / dt |----+ || +// | ---------------------------------- D || +// | || +// | -----------\/----------- +// |____________________________________________________________| Sensor measurements: | +// | "current point" | +// ------------------------ +// +static void pid_computation(void *state, const double* params, const double *inputs, double *outputs) { + struct pid_node_state* pid_state = (struct pid_state*)state; + + double P = 0.0, I = 0.0, D = 0.0; + + // calculate the current error + double error = inputs[PID_SETPOINT] - inputs[PID_CUR_POINT]; + + // Accumulate the error (if Ki is less than epsilon, rougly 0, + // then reset the accumulated error for safety) + if (fabs(pid->Ki) <= FLT_EPSILON) { + pid_state->acc_error = 0; + } else { + 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->acc_error * inputs[PID_DT]; + D = params[PID_KD] * (change_in_error / inputs[PID_DT]); + + pid_state->prev_error = error; // Store the current error into the state + + output[PID_CORRECTION] = P + I + D; // Store the computed correction +} + +// This function sets the accumulated error and previous error to 0 +// to prevent previous errors from affecting output after a reset +static void reset_pid(void *state) { + struct pid_node_state* pid_state = (struct pid_state*)state; + pid_state->acc_error = 0; + pid_state->prev_error = 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"}; +const struct graph_node_type node_accum_type = { + .input_names = in_names, + .output_names = out_names, + .param_names = param_names, + .n_inputs = 3, + .n_outputs = 1, + .n_params = 3, + .execute = pid_computation, + .reset = reset_pid +}; + +int graph_add_node_pid(struct computation_graph *graph, const char* name) { + struct pid_node_state* node_state = malloc(sizeof(struct pid_node_state)); + if (sizeof(struct accum_state) && !node_state) { + return -1; // malloc failed + } + return graph_add_node(graph, name, &node_accum_type, node_state); +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..ce87339b7f39adc410263b48005539f8fac47da2 --- /dev/null +++ b/quad/sw/modular_quad_pid/src/graph_blocks/node_pid.h @@ -0,0 +1,25 @@ +#ifndef __NODE_PID_H__ +#define __NODE_PID_H__ +#include "computation_graph.h" + +int graph_add_node_pid(struct computation_graph *graph, const char* name); + +extern const struct graph_node_type node_pid_type; + +enum graph_node_pid_inputs { + PID_CUR_POINT, // Current value of the system + PID_SETPOINT, // Desired value of the system + PID_DT // sample period +}; + +enum graph_node_pid_outputs { + PID_CORRECTION // Correction factor computed by the PID +}; + +enum graph_node_pid_params { + PID_KP, // Proportional constant + PID_KI, // Integral constant + PID_KD // Derivative constant +}; + +#endif // __NODE_PID_H__ diff --git a/quad/sw/modular_quad_pid/src/main.c b/quad/sw/modular_quad_pid/src/main.c index d703e348dbdeaf14dae299732c0eff36b892767c..8ef38990d98c1a5415c9be48a5b0c2d8a829b6ec 100644 --- a/quad/sw/modular_quad_pid/src/main.c +++ b/quad/sw/modular_quad_pid/src/main.c @@ -134,5 +134,3 @@ int main() return 0; } - - diff --git a/quad/sw/modular_quad_pid/src/type_def.h b/quad/sw/modular_quad_pid/src/type_def.h index c6f89b496581f5241b2bfa392d50f1fbda319fd5..acc5815903d4b63695013cab39c3bc84382700b9 100644 --- a/quad/sw/modular_quad_pid/src/type_def.h +++ b/quad/sw/modular_quad_pid/src/type_def.h @@ -1,4 +1,24 @@ -/* +int roll_pid = +int pitch_pid = +int yaw_pid = g +int roll_r_pid +int pitch_r_pid +int yaw_r_pid = +int x_pos_pid = +int y_pos_pid = +int alt_pid = g +// Create block +int cur_pitch = +int cur_roll = +int cur_yaw = g +int theta = gra +int phi = graph +int psi = graph +// Create block +int rc_pitch = +int rc_roll = g +int rc_yaw = gr +int rc_throttle/* * struct_def.h * * Created on: Mar 2, 2016 @@ -10,6 +30,7 @@ #include <stdint.h> #include "commands.h" +#include "computation_graph.h" /** * @brief @@ -288,6 +309,31 @@ typedef struct setpoint_t { */ typedef struct parameter_t { PID_t pid_controllers[MAX_CONTROLLER_ID]; + struct computation_graph* graph; + // PID blocks + int roll_pid; + int pitch_pid; + int yaw_pid; + int roll_r_pid; + int pitch_r_pid; + int yaw_r_pid; + int x_pos_pid; + int y_pos_pid; + int alt_pid; + // Sensor blocks + int cur_pitch; + int cur_roll; + int cur_yaw; + int theta; + int phi; + int psi; + // RC blocks + int rc_pitch; + int rc_roll; + int rc_yaw; + int rc_throttle; + // Loop time + int dt; } parameter_t; /**