From 3018e23e897b1fcc23a91551b692486f070041de Mon Sep 17 00:00:00 2001 From: Paul Beuchat <beuchatp@control.ee.ethz.ch> Date: Mon, 16 Apr 2018 19:08:20 +0200 Subject: [PATCH] Added filtering structure to Demo controller --- .../include/DemoControllerService.h | 180 +++++- .../src/d_fall_pps/param/DemoController.yaml | 72 ++- .../d_fall_pps/src/DemoControllerService.cpp | 530 ++++++++++++++---- 3 files changed, 635 insertions(+), 147 deletions(-) diff --git a/pps_ws/src/d_fall_pps/include/DemoControllerService.h b/pps_ws/src/d_fall_pps/include/DemoControllerService.h index b651eeaf..43abad43 100644 --- a/pps_ws/src/d_fall_pps/include/DemoControllerService.h +++ b/pps_ws/src/d_fall_pps/include/DemoControllerService.h @@ -91,27 +91,63 @@ // command directly to each of the motors, and additionally request the // body frame roll, pitch, and yaw angles from the PID attitude // controllers implemented in the Crazyflie 2.0 firmware. -#define MOTOR_MODE 6 -#define RATE_MODE 7 -#define ANGLE_MODE 8 +#define CF_COMMAND_TYPE_MOTOR 6 +#define CF_COMMAND_TYPE_RATE 7 +#define CF_COMMAND_TYPE_ANGLE 8 + // These constants define the controller used for computing the response in the // "calculateControlOutput" function // The following is a short description about each mode: -// LQR_RATE_MODE LQR controller based on the state vector: +// +// LQR_MODE_MOTOR LQR controller based on the state vector: +// [position,velocity,angles,angular velocity] +// commands per motor thrusts +// +// LQR_MODE_ACTUATOR LQR controller based on the state vector: +// [position,velocity,angles,angular velocity] +// commands actuators of total force and bodz torques +// +// LQR_MODE_RATE LQR controller based on the state vector: // [position,velocity,angles] // -// LQR_ANGLE_MODE LQR controller based on the state vector: +// LQR_MODE_ANGLE LQR controller based on the state vector: // [position,velocity] // -#define LQR_RATE_MODE 1 // (DEFAULT) -#define LQR_ANGLE_MODE 2 +#define LQR_MODE_MOTOR 1 +#define LQR_MODE_ACTUATOR 2 +#define LQR_MODE_RATE 3 // (DEFAULT) +#define LQR_MODE_ANGLE 4 + + +// These constants define the method used for estimating the Inertial +// frame state. +// All methods are run at all times, this flag indicates which estimate +// is passed onto the controller. +// The following is a short description about each mode: +// +// ESTIMATOR_METHOD_FINITE_DIFFERENCE +// Takes the poisition and angles directly as measured, +// and estimates the velocities as a finite different to the +// previous measurement +// +// ESTIMATOR_METHOD_POINT_MASS_PER_DIMENSION +// Uses a 2nd order random walk estimator independently for +// each of (x,y,z,roll,pitch,yaw) +// +// ESTIMATOR_METHOD_QUADROTOR_MODEL_BASED +// Uses the model of the quad-rotor and the previous inputs +// +#define ESTIMATOR_METHOD_FINITE_DIFFERENCE 1 +#define ESTIMATOR_METHOD_POINT_MASS_PER_DIMENSION 2 // (DEFAULT) +#define ESTIMATOR_METHOD_QUADROTOR_MODEL_BASED 3 + // Constants for feching the yaml paramters -#define FETCH_YAML_SAFE_CONTROLLER_AGENT 1 -#define FETCH_YAML_DEMO_CONTROLLER_AGENT 2 -#define FETCH_YAML_SAFE_CONTROLLER_COORDINATOR 3 -#define FETCH_YAML_DEMO_CONTROLLER_COORDINATOR 4 +//#define FETCH_YAML_SAFE_CONTROLLER_AGENT 1 +#define FETCH_YAML_DEMO_CONTROLLER_AGENT 2 +//#define FETCH_YAML_SAFE_CONTROLLER_COORDINATOR 3 +#define FETCH_YAML_DEMO_CONTROLLER_COORDINATOR 4 // Namespacing the package using namespace d_fall_pps; @@ -128,31 +164,97 @@ using namespace d_fall_pps; // V A A R R III A A BBBB LLLLL EEEEE SSSS // ---------------------------------------------------------------------------------- -// Variables for controller -float cf_mass; // Crazyflie mass in grams -std::vector<float> motorPoly(3); // Coefficients of the 16-bit command to thrust conversion -float control_frequency; // Frequency at which the controller is running -float gravity_force; // The weight of the Crazyflie in Newtons, i.e., mg +// VARIABLES FOR SOME "ALMOST CONSTANTS" +// > Mass of the Crazyflie quad-rotor, in [grams] +float cf_mass; +// > Coefficients of the 16-bit command to thrust conversion +std::vector<float> motorPoly(3); +// The weight of the Crazyflie in [Newtons], i.e., mg +float gravity_force; +// One quarter of the "gravity_force" +float gravity_force_quarter; + + + + +// VARIABLES FOR THE CONTROLLER + +// Frequency at which the controller is running +float control_frequency; + + +// > The setpoints for (x,y,z) position and yaw angle, in that order +float setpoint[4] = {0.0,0.0,0.4,0.0}; -float previous_stateErrorInertial[9]; // The location error of the Crazyflie at the "previous" time step -std::vector<float> setpoint{0.0,0.0,0.4,0.0}; // The setpoints for (x,y,z) position and yaw angle, in that order // The controller type to run in the "calculateControlOutput" function -int controller_type = LQR_RATE_MODE; +int lqr_controller_mode = LQR_MODE_RATE; + + +// The LQR Controller parameters for "LQR_MODE_MOTOR" +std::vector<float> gainMatrixMotor1; +std::vector<float> gainMatrixMotor2; +std::vector<float> gainMatrixMotor3; +std::vector<float> gainMatrixMotor4; + + + + + + -// The LQR Controller parameters for "LQR_RATE_MODE" +// The LQR Controller parameters for "LQR_MODE_ACTUATOR" +std::vector<float> gainMatrixThrust_TwelveStateVector = { 0.00,-1.72, 0.00, 0.00,-1.34, 0.00, 5.12, 0.00, 0.00, 0.00, 0.00, 0.00}; +std::vector<float> gainMatrixRollTorque = { 1.72, 0.00, 0.00, 1.34, 0.00, 0.00, 0.00, 5.12, 0.00, 0.00, 0.00, 0.00}; +std::vector<float> gainMatrixPitchTorque = { 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 2.84, 0.00, 0.00, 0.00}; +std::vector<float> gainMatrixYawTorque = { 0.00, 0.00, 0.25, 0.00, 0.00, 0.14, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00}; + + +// The LQR Controller parameters for "LQR_MODE_RATE" +std::vector<float> gainMatrixThrust_NineStateVector = { 0.00, 0.00, 0.25, 0.00, 0.00, 0.14, 0.00, 0.00, 0.00}; std::vector<float> gainMatrixRollRate = { 0.00,-1.72, 0.00, 0.00,-1.34, 0.00, 5.12, 0.00, 0.00}; std::vector<float> gainMatrixPitchRate = { 1.72, 0.00, 0.00, 1.34, 0.00, 0.00, 0.00, 5.12, 0.00}; std::vector<float> gainMatrixYawRate = { 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 2.84}; -std::vector<float> gainMatrixThrust_NineStateVector = { 0.00, 0.00, 0.25, 0.00, 0.00, 0.14, 0.00, 0.00, 0.00}; -// The LQR Controller parameters for "LQR_ANGLE_MODE" + +// The LQR Controller parameters for "LQR_MODE_ANGLE" +std::vector<float> gainMatrixThrust_SixStateVector = { 0.00, 0.00, 0.31, 0.00, 0.00, 0.14}; std::vector<float> gainMatrixRollAngle = { 0.00,-0.20, 0.00, 0.00,-0.20, 0.00}; std::vector<float> gainMatrixPitchAngle = { 0.20, 0.00, 0.00, 0.20, 0.00, 0.00}; -std::vector<float> gainMatrixThrust_SixStateVector = { 0.00, 0.00, 0.31, 0.00, 0.00, 0.14}; + + + +// The 16-bit command limits +float cmd_sixteenbit_min; +float cmd_sixteenbit_max; + + +// VARIABLES FOR THE ESTIMATOR + +// Frequency at which the controller is running +float estimator_frequency; + +// > A flag for which estimator to use: +int estimator_method = ESTIMATOR_METHOD_FINITE_DIFFERENCE; +// > The current state interial estimate, +// for use by the controller +float current_stateInertialEstimate[12]; + +// > The measurement of the Crazyflie at the "current" time step, +// to avoid confusion +float current_xzy_rpy_measurement[6]; + +// > The measurement of the Crazyflie at the "previous" time step, +// used for computing finite difference velocities +float previous_xzy_rpy_measurement[6]; + +// > The full 12 state estimate maintained by the finite +// difference state estimator +float stateInterialEstimate_viaFiniteDifference[12]; + // ROS Publisher for debugging variables ros::Publisher debugPublisher; @@ -255,12 +357,25 @@ ros::Subscriber xyz_yaw_to_follow_subscriber; // called from another function, hence why the "main" function is at the bottom. // CONTROLLER COMPUTATIONS +// > The function that is called to "start" all estimation and control computations bool calculateControlOutput(Controller::Request &request, Controller::Response &response); -void calculateControlOutput_viaLQRforRates(float stateErrorBody[9], Controller::Request &request, Controller::Response &response); -void calculateControlOutput_viaLQRforAngles(float stateErrorBody[9], Controller::Request &request, Controller::Response &response); + +// > The various functions that implement an LQR controller +void calculateControlOutput_viaLQR( float stateErrorBody[12], Controller::Request &request, Controller::Response &response); +void calculateControlOutput_viaLQRforMotors( float stateErrorBody[12], Controller::Request &request, Controller::Response &response); +void calculateControlOutput_viaLQRforActuators(float stateErrorBody[12], Controller::Request &request, Controller::Response &response); +void calculateControlOutput_viaLQRforRates( float stateErrorBody[12], Controller::Request &request, Controller::Response &response); +void calculateControlOutput_viaLQRforAngles( float stateErrorBody[12], Controller::Request &request, Controller::Response &response); + +// ESTIMATOR COMPUTATIONS +void performEstimatorUpdate_forStateInterial(Controller::Request &request); +void performEstimatorUpdate_forStateInterial_viaFiniteDifference(); + +// TRANSFORMATION FROM INTERIAL ESTIMATE TO BODY FRAME ERROR +void convert_stateInertial_to_bodyFrameError(float stateInertial[12], float setpoint[4], float (&bodyFrameError)[12]); // TRANSFORMATION OF THE (x,y) INERTIAL FRAME ERROR INTO AN (x,y) BODY FRAME ERROR -void convertIntoBodyFrame(float stateInertial[9], float (&stateBody)[9], float yaw_measured); +void convertIntoBodyFrame(float stateInertial[12], float (&stateBody)[12], float yaw_measured); // CONVERSION FROM THRUST IN NEWTONS TO 16-BIT COMMAND float computeMotorPolyBackward(float thrust); @@ -269,13 +384,16 @@ float computeMotorPolyBackward(float thrust); void setpointCallback(const Setpoint& newSetpoint); void xyz_yaw_to_follow_callback(const Setpoint& newSetpoint); +// PUBLISH THE CURRENT X,Y,Z, AND YAW +void publish_current_xyz_yaw(float x, float y, float z, float yaw); + // LOAD PARAMETERS float getParameterFloat(ros::NodeHandle& nodeHandle, std::string name); -void getParameterFloatVector(ros::NodeHandle& nodeHandle, std::string name, std::vector<float>& val, int length); -int getParameterInt(ros::NodeHandle& nodeHandle, std::string name); -void getParameterIntVectorWithKnownLength(ros::NodeHandle& nodeHandle, std::string name, std::vector<int>& val, int length); -int getParameterIntVectorWithUnknownLength(ros::NodeHandle& nodeHandle, std::string name, std::vector<int>& val); -bool getParameterBool(ros::NodeHandle& nodeHandle, std::string name); +void getParameterFloatVector(ros::NodeHandle& nodeHandle, std::string name, std::vector<float>& val, int length); +int getParameterInt(ros::NodeHandle& nodeHandle, std::string name); +void getParameterIntVectorWithKnownLength(ros::NodeHandle& nodeHandle, std::string name, std::vector<int>& val, int length); +int getParameterIntVectorWithUnknownLength(ros::NodeHandle& nodeHandle, std::string name, std::vector<int>& val); +bool getParameterBool(ros::NodeHandle& nodeHandle, std::string name); void yamlReadyForFetchCallback(const std_msgs::Int32& msg); void fetchYamlParameters(ros::NodeHandle& nodeHandle); diff --git a/pps_ws/src/d_fall_pps/param/DemoController.yaml b/pps_ws/src/d_fall_pps/param/DemoController.yaml index 15659071..b3aaa678 100644 --- a/pps_ws/src/d_fall_pps/param/DemoController.yaml +++ b/pps_ws/src/d_fall_pps/param/DemoController.yaml @@ -27,20 +27,68 @@ follow_in_a_line_agentIDs : [1, 2, 3] shouldPublishDebugMessage : false # Boolean indiciating whether the debugging ROS_INFO_STREAM should be displayed or not -shouldDisplayDebugInfo : false +shouldDisplayDebugInfo : true + +# A flag for which LQR controller mode to use, defined as: +# 1 - LQR controller based on the state vector: [position,velocity,angles,angular velocity] +# commands per motor thrusts +# 2 - LQR controller based on the state vector: [position,velocity,angles,angular velocity] +# commands actuators of total force and bodz torques +# 3 - LQR controller based on the state vector: [position,velocity,angles] +# 4 - LQR controller based on the state vector: [position,velocity] +lqr_controller_mode : 1 + + +# A flag for which estimator to use, defined as: +# 1 - Finite Different Method, +# Takes the poisition and angles directly as measured, +# and estimates the velocities as a finite different to the +# previous measurement +# 2 - Point Mass Per Dimension Method +# Uses a 2nd order random walk estimator independently for +# each of (x,y,z,roll,pitch,yaw) +# 3 - Quad-rotor Model Based Method +# Uses the model of the quad-rotor and the previous inputs +estimator_method : 1 + + -# A flag for which controller to use, defined as: -# 1 - LQR controller based on the state vector: [position,velocity,angles] -# 2 - LQR controller based on the state vector: [position,velocity] -controller_type : 1 # The LQR Controller parameters for "mode = 1" -gainMatrixRollRate : [ 0.00,-1.72, 0.00, 0.00,-1.34, 0.00, 5.12, 0.00, 0.00] -gainMatrixPitchRate : [ 1.72, 0.00, 0.00, 1.34, 0.00, 0.00, 0.00, 5.12, 0.00] -gainMatrixYawRate : [ 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 2.84] -gainMatrixThrust_NineStateVector : [ 0.00, 0.00, 0.25, 0.00, 0.00, 0.14, 0.00, 0.00, 0.00] +gainMatrixMotor1 : [ -0.0620, 0.0620, 0.0496,-0.0445, 0.0445, 0.0282,-0.1567,-0.1568,-0.0688,-0.0063,-0.0063,-0.0130] +gainMatrixMotor2 : [ 0.0620, 0.0620, 0.0496, 0.0445, 0.0445, 0.0282,-0.1567, 0.1568, 0.0688,-0.0063, 0.0063, 0.0130] +gainMatrixMotor3 : [ 0.0620,-0.0620, 0.0496, 0.0445,-0.0445, 0.0282, 0.1567, 0.1568,-0.0688, 0.0063, 0.0063,-0.0130] +gainMatrixMotor4 : [ -0.0620,-0.0620, 0.0496,-0.0445,-0.0445, 0.0282, 0.1567,-0.1568, 0.0688, 0.0063,-0.0063, 0.0130] + + + + + + + + # The LQR Controller parameters for "mode = 2" -gainMatrixRollAngle : [ 0.00,-0.20, 0.00, 0.00,-0.20, 0.00] -gainMatrixPitchAngle : [ 0.20, 0.00, 0.00, 0.20, 0.00, 0.00] -gainMatrixThrust_SixStateVector : [ 0.00, 0.00, 0.31, 0.00, 0.00, 0.14] +gainMatrixThrust_TwelveStateVector : [ 0.00, 0.00, 0.98, 0.00, 0.00, 0.25, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00] +gainMatrixRollTorque : [ 0.00,-1.80, 0.00, 0.00,-1.38, 0.00, 5.20, 0.00, 0.00, 0.00, 0.00, 0.00] +gainMatrixPitchTorque : [ 1.80, 0.00, 0.00, 1.38, 0.00, 0.00, 0.00, 5.20, 0.00, 0.00, 0.00, 0.00] +gainMatrixYawTorque : [ 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 2.30, 0.00, 0.00, 0.00] + + +# The LQR Controller parameters for "mode = 3" +gainMatrixThrust_NineStateVector : [ 0.00, 0.00, 0.98, 0.00, 0.00, 0.25, 0.00, 0.00, 0.00] +gainMatrixRollRate : [ 0.00,-1.80, 0.00, 0.00,-1.38, 0.00, 5.20, 0.00, 0.00] +gainMatrixPitchRate : [ 1.80, 0.00, 0.00, 1.38, 0.00, 0.00, 0.00, 5.20, 0.00] +gainMatrixYawRate : [ 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 2.30] + + +# The LQR Controller parameters for "mode = 4" +gainMatrixThrust_SixStateVector : [ 0.00, 0.00, 0.31, 0.00, 0.00, 0.14] +gainMatrixRollAngle : [ 0.00,-0.20, 0.00, 0.00,-0.20, 0.00] +gainMatrixPitchAngle : [ 0.20, 0.00, 0.00, 0.20, 0.00, 0.00] + + + +# The max and minimum thrust for a 16-bit command +command_sixteenbit_min : 1000 +command_sixteenbit_max : 60000 \ No newline at end of file diff --git a/pps_ws/src/d_fall_pps/src/DemoControllerService.cpp b/pps_ws/src/d_fall_pps/src/DemoControllerService.cpp index 9cc9c9f6..da2eaa52 100644 --- a/pps_ws/src/d_fall_pps/src/DemoControllerService.cpp +++ b/pps_ws/src/d_fall_pps/src/DemoControllerService.cpp @@ -114,16 +114,18 @@ // // IMPORTANT NOTES FOR "onboardControllerType" AND AXIS CONVENTIONS // > The allowed values for "onboardControllerType" are in the "Defines" section at the -// top of this file, they are MOTOR_MODE, RATE_MODE, OR ANGLE_MODE. -// > In the PPS exercise we will only use the RATE_MODE. -// > In RATE_MODE the ".roll", ".ptich", and ".yaw" properties of "response.ControlCommand" +// top of this file, they are: +// CF_COMMAND_TYPE_MOTOR +// CF_COMMAND_TYPE_RATE +// CF_COMMAND_TYPE_ANGLE. +// > With CF_COMMAND_TYPE_RATE the ".roll", ".ptich", and ".yaw" properties of "response.ControlCommand" // specify the angular rate in [radians/second] that will be requested from the // PID controllers running in the Crazyflie 2.0 firmware. -// > In RATE_MODE the ".motorCmd1" to ".motorCmd4" properties of "response.ControlCommand" +// > With CF_COMMAND_TYPE_RATE the ".motorCmd1" to ".motorCmd4" properties of "response.ControlCommand" // are the baseline motor commands requested from the Crazyflie, with the adjustment // for body rates being added on top of this in the firmware (i.e., as per the code // of the "distribute_power" function provided in exercise sheet 2). -// > In RATE_MODE the axis convention for the roll, pitch, and yaw body rates returned +// > With CF_COMMAND_TYPE_RATE the axis convention for the roll, pitch, and yaw body rates returned // in "response.ControlCommand" should use right-hand coordinate axes with x-forward // and z-upwards (i.e., the positive z-axis is aligned with the direction of positive // thrust). To assist, teh following is an ASCII art of this convention: @@ -163,73 +165,184 @@ bool calculateControlOutput(Controller::Request &request, Controller::Response &response) { - // This is the "start" of the outer loop controller, add all your control - // computation here, or you may find it convienient to create functions - // to keep you code cleaner + // THIS IS THE START OF THE "OUTER" CONTROL LOOP + // > i.e., this is the control loop run on this laptop + // > this function is called at the frequency specified + // > this function performs all estimation and control - // Define a local array to fill in with the state error - float stateErrorInertial[9]; + // PERFORM THE ESTIMATOR UPDATE FOR THE INTERIAL FRAME STATE + // > After this function is complete the class variable + // "current_stateInertialEstimate" is updated and ready + // to be used for subsequent controller copmutations + performEstimatorUpdate_forStateInterial(request); - // Fill in the (x,y,z) position error - stateErrorInertial[0] = request.ownCrazyflie.x - setpoint[0]; - stateErrorInertial[1] = request.ownCrazyflie.y - setpoint[1]; - stateErrorInertial[2] = request.ownCrazyflie.z - setpoint[2]; + + // CONVERT THE CURRENT INERTIAL FRAME STATE ESTIMATE, INTO + // THE BODY FRAME ERROR REQUIRED BY THE CONTROLLER + // > Define a local array to fill in with the body frame error + float current_bodyFrameError[12]; + // > Call the function to perform the conversion + convert_stateInertial_to_bodyFrameError(current_stateInertialEstimate,setpoint,current_bodyFrameError); - // Compute an estimate of the velocity - // > As simply the derivative between the current and previous position - stateErrorInertial[3] = (stateErrorInertial[0] - previous_stateErrorInertial[0]) * control_frequency; - stateErrorInertial[4] = (stateErrorInertial[1] - previous_stateErrorInertial[1]) * control_frequency; - stateErrorInertial[5] = (stateErrorInertial[2] - previous_stateErrorInertial[2]) * control_frequency; + - // Fill in the roll and pitch angle measurements directly - stateErrorInertial[6] = request.ownCrazyflie.roll; - stateErrorInertial[7] = request.ownCrazyflie.pitch; + - // Fill in the yaw angle error - // > This error should be "unwrapped" to be in the range - // ( -pi , pi ) - // > First, get the yaw error into a local variable - float yawError = request.ownCrazyflie.yaw - setpoint[3]; - // > Second, "unwrap" the yaw error to the interval ( -pi , pi ) - while(yawError > PI) {yawError -= 2 * PI;} - while(yawError < -PI) {yawError += 2 * PI;} - // > Third, put the "yawError" into the "stateError" variable - stateErrorInertial[8] = yawError; + + // PERFORM THE BASIC LQR CONTROLLER + calculateControlOutput_viaLQR(current_bodyFrameError,request,response); - // CONVERSION INTO BODY FRAME - // Conver the state erorr from the Inertial frame into the Body frame - // > Note: the function "convertIntoBodyFrame" is implemented in this file - // and by default does not perform any conversion. The equations to convert - // the state error into the body frame should be implemented in that function - // for successful completion of the PPS exercise - float stateErrorBody[9]; - convertIntoBodyFrame(stateErrorInertial, stateErrorBody, request.ownCrazyflie.yaw); - // SAVE THE STATE ERROR TO BE USED NEXT TIME THIS FUNCTION IS CALLED - // > as we have already used previous error we can now update it update it - for(int i = 0; i < 9; ++i) + + // PUBLISH THE CURRENT X,Y,Z, AND YAW (if required) + if (shouldPublishCurrent_xyz_yaw) { - previous_stateErrorInertial[i] = stateErrorInertial[i]; + publish_current_xyz_yaw(request.ownCrazyflie.x,request.ownCrazyflie.y,request.ownCrazyflie.z,request.ownCrazyflie.yaw); } + // RETURN "true" TO INDICATE THAT THE COMPUTATIONS WERE SUCCESSFUL + return true; +} + + + + +// ------------------------------------------------------------------------------ +// EEEEE SSSS TTTTT III M M A TTTTT III OOO N N +// E S T I MM MM A A T I O O NN N +// EEE SSS T I M M M A A T I O O N N N +// E S T I M M AAAAA T I O O N NN +// EEEEE SSSS T III M M A A T III OOO N N +// ------------------------------------------------------------------------------ +void performEstimatorUpdate_forStateInterial(Controller::Request &request) +{ + + // PUT THE CURRENT MEASURED DATA INTO THE CLASS VARIABLE + // > for (x,y,z) position + current_xzy_rpy_measurement[0] = request.ownCrazyflie.x; + current_xzy_rpy_measurement[1] = request.ownCrazyflie.y; + current_xzy_rpy_measurement[2] = request.ownCrazyflie.z; + // > for (roll,pitch,yaw) angles + current_xzy_rpy_measurement[3] = request.ownCrazyflie.roll; + current_xzy_rpy_measurement[4] = request.ownCrazyflie.pitch; + current_xzy_rpy_measurement[5] = request.ownCrazyflie.yaw; + + // RUN THE FINITE DIFFERENCE ESTIMATOR + performEstimatorUpdate_forStateInterial_viaFiniteDifference(); - // SWITCH BETWEEN THE DIFFERENT CONTROLLER TYPES: - switch (controller_type) + + // FILLE IN THE STATE INERTIAL ESTIMATE TO BE USED FOR CONTROL + switch (estimator_method) { - // LQR controller based on the state vector: [position,velocity,angles] - case LQR_RATE_MODE: + // Estimator based on finte differences + case ESTIMATOR_METHOD_FINITE_DIFFERENCE: + { + // Transfer the estimate + for(int i = 0; i < 12; ++i) + { + current_stateInertialEstimate[i] = stateInterialEstimate_viaFiniteDifference[i]; + } + break; + } + default: + { + // Display that the "estimator_method" was not recognised + ROS_INFO_STREAM("ERROR: in the 'calculateControlOutput' function of the 'DemoControllerService': the 'estimator_method' is not recognised."); + // Transfer the finite difference estimate by default + for(int i = 0; i < 12; ++i) + { + current_stateInertialEstimate[i] = stateInterialEstimate_viaFiniteDifference[i]; + } + break; + } + } + + + // NOW THAT THE ESTIMATORS HAVE ALL BEEN RUN, PUT THE CURRENT + // MEASURED DATA INTO THE CLASS VARIABLE FOR THE PREVIOUS + // > for (x,y,z) position + previous_xzy_rpy_measurement[0] = current_xzy_rpy_measurement[0]; + previous_xzy_rpy_measurement[1] = current_xzy_rpy_measurement[1]; + previous_xzy_rpy_measurement[2] = current_xzy_rpy_measurement[2]; + // > for (roll,pitch,yaw) angles + previous_xzy_rpy_measurement[3] = current_xzy_rpy_measurement[3]; + previous_xzy_rpy_measurement[4] = current_xzy_rpy_measurement[4]; + previous_xzy_rpy_measurement[5] = current_xzy_rpy_measurement[5]; +} + + +void performEstimatorUpdate_forStateInterial_viaFiniteDifference() +{ + // PUT IN THE CURRENT MEASUREMENT DIRECTLY + // > for (x,y,z) position + stateInterialEstimate_viaFiniteDifference[0] = current_xzy_rpy_measurement[0]; + stateInterialEstimate_viaFiniteDifference[1] = current_xzy_rpy_measurement[1]; + stateInterialEstimate_viaFiniteDifference[2] = current_xzy_rpy_measurement[2]; + // > for (roll,pitch,yaw) angles + stateInterialEstimate_viaFiniteDifference[6] = current_xzy_rpy_measurement[3]; + stateInterialEstimate_viaFiniteDifference[7] = current_xzy_rpy_measurement[4]; + stateInterialEstimate_viaFiniteDifference[8] = current_xzy_rpy_measurement[5]; + + // COMPUTE THE VELOCITIES VIA FINITE DIFFERENCE + // > for (x,y,z) velocities + stateInterialEstimate_viaFiniteDifference[3] = (current_xzy_rpy_measurement[0] - previous_xzy_rpy_measurement[0]) * estimator_frequency; + stateInterialEstimate_viaFiniteDifference[4] = (current_xzy_rpy_measurement[1] - previous_xzy_rpy_measurement[1]) * estimator_frequency; + stateInterialEstimate_viaFiniteDifference[5] = (current_xzy_rpy_measurement[2] - previous_xzy_rpy_measurement[2]) * estimator_frequency; + // > for (roll,pitch,yaw) velocities + stateInterialEstimate_viaFiniteDifference[9] = (current_xzy_rpy_measurement[3] - previous_xzy_rpy_measurement[3]) * estimator_frequency; + stateInterialEstimate_viaFiniteDifference[10] = (current_xzy_rpy_measurement[4] - previous_xzy_rpy_measurement[4]) * estimator_frequency; + stateInterialEstimate_viaFiniteDifference[11] = (current_xzy_rpy_measurement[5] - previous_xzy_rpy_measurement[5]) * estimator_frequency; +} + + + +// ---------------------------------------------------------------------------------- +// L QQQ RRRR +// L Q Q R R +// L Q Q RRRR +// L Q Q R R +// LLLLL QQ Q R R +// ---------------------------------------------------------------------------------- + +void calculateControlOutput_viaLQR(float stateErrorBody[12], Controller::Request &request, Controller::Response &response) +{ + // SWITCH BETWEEN THE DIFFERENT LQR CONTROLLER MODES: + switch (lqr_controller_mode) + { + // LQR controller based on the state vector: + // [position,velocity,angles,angular velocity] + // commands per motor thrusts + case LQR_MODE_MOTOR: + { + // Call the function that performs the control computations for this mode + calculateControlOutput_viaLQRforMotors(stateErrorBody,request,response); + break; + } + // LQR controller based on the state vector: + // [position,velocity,angles,angular velocity] + // commands actuators of total force and bodz torques + case LQR_MODE_ACTUATOR: + { + // Call the function that performs the control computations for this mode + calculateControlOutput_viaLQRforActuators(stateErrorBody,request,response); + break; + } + // LQR controller based on the state vector: + // [position,velocity,angles] + case LQR_MODE_RATE: { // Call the function that performs the control computations for this mode calculateControlOutput_viaLQRforRates(stateErrorBody,request,response); break; } - // LQR controller based on the state vector: [position,velocity] - case LQR_ANGLE_MODE: + // LQR controller based on the state vector: + // [position,velocity] + case LQR_MODE_ANGLE: { // Call the function that performs the control computations for this mode calculateControlOutput_viaLQRforAngles(stateErrorBody,request,response); @@ -238,8 +351,8 @@ bool calculateControlOutput(Controller::Request &request, Controller::Response & default: { - // Display that the "controller_type" was not recognised - ROS_INFO_STREAM("ERROR: in the 'calculateControlOutput' function of the 'DemoControllerService': the 'controller_type' is not recognised."); + // Display that the "lqr_controller_mode" was not recognised + ROS_INFO_STREAM("ERROR: in the 'calculateControlOutput' function of the 'DemoControllerService': the 'lqr_controller_mode' is not recognised."); // Set everything in the response to zero response.controlOutput.roll = 0; response.controlOutput.pitch = 0; @@ -248,55 +361,155 @@ bool calculateControlOutput(Controller::Request &request, Controller::Response & response.controlOutput.motorCmd2 = 0; response.controlOutput.motorCmd3 = 0; response.controlOutput.motorCmd4 = 0; - response.controlOutput.onboardControllerType = MOTOR_MODE; + response.controlOutput.onboardControllerType = CF_COMMAND_TYPE_MOTOR; break; } + } +} + + +void calculateControlOutput_viaLQRforMotors(float stateErrorBody[12], Controller::Request &request, Controller::Response &response) +{ + // PERFORM THE "u=Kx" LQR CONTROLLER COMPUTATION + // Instantiate the local variables for the per motor thrust + // adjustment. These will be requested from the Crazyflie's + // on-baord "inner-loop" controller + float motor1_thrustAdjustment = 0; + float motor2_thrustAdjustment = 0; + float motor3_thrustAdjustment = 0; + float motor4_thrustAdjustment = 0; + + // Perform the "-Kx" LQR computation for the rates and thrust: + for(int i = 0; i < 12; ++i) + { + // MOTORS 1,2,3,4 + motor1_thrustAdjustment -= gainMatrixMotor1[i] * stateErrorBody[i]; + motor2_thrustAdjustment -= gainMatrixMotor2[i] * stateErrorBody[i]; + motor3_thrustAdjustment -= gainMatrixMotor3[i] * stateErrorBody[i]; + motor4_thrustAdjustment -= gainMatrixMotor4[i] * stateErrorBody[i]; } + motor1_thrustAdjustment = -gravity_force_quarter/2.0; + motor2_thrustAdjustment = -gravity_force_quarter/2.0; + motor3_thrustAdjustment = -gravity_force_quarter/2.0; + motor4_thrustAdjustment = -gravity_force_quarter/2.0; + + // UPDATE THE "RETURN" THE VARIABLE NAME "response" + + // Put the roll, pitch, and yaw command to zero + response.controlOutput.roll = 0; + response.controlOutput.pitch = 0; + response.controlOutput.yaw = 0; + // > For the thrust adjustment we must add the feed-forward thrust to counter-act gravity. + // > NOTE: the "gravity_force_quarter" value was already divided by 4 when + // it was loaded/processes from the .yaml file. + response.controlOutput.motorCmd1 = computeMotorPolyBackward(motor1_thrustAdjustment + gravity_force_quarter); + response.controlOutput.motorCmd2 = computeMotorPolyBackward(motor2_thrustAdjustment + gravity_force_quarter); + response.controlOutput.motorCmd3 = computeMotorPolyBackward(motor3_thrustAdjustment + gravity_force_quarter); + response.controlOutput.motorCmd4 = computeMotorPolyBackward(motor4_thrustAdjustment + gravity_force_quarter); + // Specify that this controller is a rate controller + response.controlOutput.onboardControllerType = CF_COMMAND_TYPE_MOTOR; + // response.controlOutput.onboardControllerType = CF_COMMAND_TYPE_RATE; + // response.controlOutput.onboardControllerType = CF_COMMAND_TYPE_ANGLE; + + // An alternate debugging technique is to print out data directly to the + // command line from which this node was launched. + if (shouldDisplayDebugInfo) + { + // An example of "printing out" the data from the "request" argument to the + // command line. This might be useful for debugging. + //ROS_INFO_STREAM("x-coordinate [m]: " << request.ownCrazyflie.x); + //ROS_INFO_STREAM("y-coordinate [m]: " << request.ownCrazyflie.y); + //ROS_INFO_STREAM("z-coordinate [m]: " << request.ownCrazyflie.z); + //ROS_INFO_STREAM("roll [deg]: " << request.ownCrazyflie.roll); + //ROS_INFO_STREAM("pitch [deg]: " << request.ownCrazyflie.pitch); + //ROS_INFO_STREAM("yaw [deg]: " << request.ownCrazyflie.yaw); + //ROS_INFO_STREAM("Delta t [s]: " << request.ownCrazyflie.acquiringTime); + + ROS_INFO_STREAM("f1 [N]: " << motor1_thrustAdjustment); + ROS_INFO_STREAM("f2 [N]: " << motor2_thrustAdjustment); + ROS_INFO_STREAM("f3 [N]: " << motor3_thrustAdjustment); + ROS_INFO_STREAM("f4 [N]: " << motor4_thrustAdjustment); + } +} - // ************************************************************************************************ - // PPPP U U BBBB L III SSSS H H X X Y Y ZZZZZ Y Y A W W - // P P U U B B L I S H H X X Y Y Z Y Y A A W W - // PPPP U U BBBB L I SSS HHHH X Y Z Y A A W W - // P U U B B L I S H H X X Y Z Y AAAAA W W W - // P UUU BBBB LLLLL III SSSS H H X X Y ZZZZZ Y A A W W +void calculateControlOutput_viaLQRforActuators(float stateErrorBody[12], Controller::Request &request, Controller::Response &response) +{ + // PERFORM THE "u=Kx" LQR CONTROLLER COMPUTATION - // PUBLISH THE CURRENT X,Y,Z, AND YAW (if required) - if (shouldPublishCurrent_xyz_yaw) + // Instantiate the local variables for the per motor thrust + // adjustment. These will be requested from the Crazyflie's + // on-baord "inner-loop" controller + float motor1_thrustAdjustment = 0; + float motor2_thrustAdjustment = 0; + float motor3_thrustAdjustment = 0; + float motor4_thrustAdjustment = 0; + + // Perform the "-Kx" LQR computation for the rates and thrust: + for(int i = 0; i < 12; ++i) { - // publish setpoint for FollowController of another student group - Setpoint temp_current_xyz_yaw; - // Fill in the x,y,z, and yaw info directly from the data provided to this - // function - temp_current_xyz_yaw.x = request.ownCrazyflie.x; - temp_current_xyz_yaw.y = request.ownCrazyflie.y; - temp_current_xyz_yaw.z = request.ownCrazyflie.z; - temp_current_xyz_yaw.yaw = request.ownCrazyflie.yaw; - my_current_xyz_yaw_publisher.publish(temp_current_xyz_yaw); + // MOTORS 1,2,3,4 + motor1_thrustAdjustment -= gainMatrixMotor1[i] * stateErrorBody[i]; + motor2_thrustAdjustment -= gainMatrixMotor2[i] * stateErrorBody[i]; + motor3_thrustAdjustment -= gainMatrixMotor3[i] * stateErrorBody[i]; + motor4_thrustAdjustment -= gainMatrixMotor4[i] * stateErrorBody[i]; } + // UPDATE THE "RETURN" THE VARIABLE NAME "response" + // Put the computed rates and thrust into the "response" variable + // > For roll, pitch, and yaw: + response.controlOutput.roll = motor2_thrustAdjustment; + response.controlOutput.pitch = motor3_thrustAdjustment; + response.controlOutput.yaw = motor4_thrustAdjustment; + // > For the thrust adjustment we must add the feed-forward thrust to counter-act gravity. + // > NOTE: remember that the thrust is commanded per motor, so you sohuld + // consider whether the "thrustAdjustment" computed by your + // controller needed to be divided by 4 or not. + float thrustAdjustment = motor1_thrustAdjustment / 4.0; + // > NOTE: the "gravity_force_quarter" value was already divided by 4 when + // it was loaded/processes from the .yaml file. + response.controlOutput.motorCmd1 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter); + response.controlOutput.motorCmd2 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter); + response.controlOutput.motorCmd3 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter); + response.controlOutput.motorCmd4 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter); + // Specify that this controller is a rate controller + // response.controlOutput.onboardControllerType = CF_COMMAND_TYPE_MOTOR; + response.controlOutput.onboardControllerType = CF_COMMAND_TYPE_RATE; + // response.controlOutput.onboardControllerType = CF_COMMAND_TYPE_ANGLE; - // Return "true" to indicate that the control computation was performed successfully - return true; -} + // An alternate debugging technique is to print out data directly to the + // command line from which this node was launched. + if (shouldDisplayDebugInfo) + { + // An example of "printing out" the data from the "request" argument to the + // command line. This might be useful for debugging. + ROS_INFO_STREAM("x-coordinate [m]: " << request.ownCrazyflie.x); + ROS_INFO_STREAM("y-coordinate [m]: " << request.ownCrazyflie.y); + ROS_INFO_STREAM("z-coordinate [m]: " << request.ownCrazyflie.z); + ROS_INFO_STREAM("roll [deg]: " << request.ownCrazyflie.roll); + ROS_INFO_STREAM("pitch [deg]: " << request.ownCrazyflie.pitch); + ROS_INFO_STREAM("yaw [deg]: " << request.ownCrazyflie.yaw); + ROS_INFO_STREAM("Delta t [s]: " << request.ownCrazyflie.acquiringTime); + } +} -void calculateControlOutput_viaLQRforRates(float stateErrorBody[9], Controller::Request &request, Controller::Response &response) +void calculateControlOutput_viaLQRforRates(float stateErrorBody[12], Controller::Request &request, Controller::Response &response) { // PERFORM THE "u=Kx" LQR CONTROLLER COMPUTATION @@ -336,19 +549,19 @@ void calculateControlOutput_viaLQRforRates(float stateErrorBody[9], Controller:: // > NOTE: remember that the thrust is commanded per motor, so you sohuld // consider whether the "thrustAdjustment" computed by your // controller needed to be divided by 4 or not. - // > NOTE: the "gravity_force" value was already divided by 4 when is was - // loaded from the .yaml file via the "fetchYamlParameters" - // class function in this file. - response.controlOutput.motorCmd1 = computeMotorPolyBackward(thrustAdjustment + gravity_force); - response.controlOutput.motorCmd2 = computeMotorPolyBackward(thrustAdjustment + gravity_force); - response.controlOutput.motorCmd3 = computeMotorPolyBackward(thrustAdjustment + gravity_force); - response.controlOutput.motorCmd4 = computeMotorPolyBackward(thrustAdjustment + gravity_force); + thrustAdjustment = thrustAdjustment / 4.0; + // > NOTE: the "gravity_force_quarter" value was already divided by 4 when + // it was loaded/processes from the .yaml file. + response.controlOutput.motorCmd1 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter); + response.controlOutput.motorCmd2 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter); + response.controlOutput.motorCmd3 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter); + response.controlOutput.motorCmd4 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter); // Specify that this controller is a rate controller - // response.controlOutput.onboardControllerType = MOTOR_MODE; - response.controlOutput.onboardControllerType = RATE_MODE; - // response.controlOutput.onboardControllerType = ANGLE_MODE; + // response.controlOutput.onboardControllerType = CF_COMMAND_TYPE_MOTOR; + response.controlOutput.onboardControllerType = CF_COMMAND_TYPE_RATE; + // response.controlOutput.onboardControllerType = CF_COMMAND_TYPE_ANGLE; @@ -429,7 +642,7 @@ void calculateControlOutput_viaLQRforRates(float stateErrorBody[9], Controller:: -void calculateControlOutput_viaLQRforAngles(float stateErrorBody[9], Controller::Request &request, Controller::Response &response) +void calculateControlOutput_viaLQRforAngles(float stateErrorBody[12], Controller::Request &request, Controller::Response &response) { // PERFORM THE "u=Kx" LQR CONTROLLER COMPUTATION @@ -464,19 +677,18 @@ void calculateControlOutput_viaLQRforAngles(float stateErrorBody[9], Controller: // > NOTE: remember that the thrust is commanded per motor, so you sohuld // consider whether the "thrustAdjustment" computed by your // controller needed to be divided by 4 or not. - // > NOTE: the "gravity_force" value was already divided by 4 when is was - // loaded from the .yaml file via the "fetchYamlParameters" - // class function in this file. - response.controlOutput.motorCmd1 = computeMotorPolyBackward(thrustAdjustment + gravity_force); - response.controlOutput.motorCmd2 = computeMotorPolyBackward(thrustAdjustment + gravity_force); - response.controlOutput.motorCmd3 = computeMotorPolyBackward(thrustAdjustment + gravity_force); - response.controlOutput.motorCmd4 = computeMotorPolyBackward(thrustAdjustment + gravity_force); + // > NOTE: the "gravity_force_quarter" value was already divided by 4 when + // it was loaded/processes from the .yaml file. + response.controlOutput.motorCmd1 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter); + response.controlOutput.motorCmd2 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter); + response.controlOutput.motorCmd3 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter); + response.controlOutput.motorCmd4 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter); // Specify that this controller is a rate controller - // response.controlOutput.onboardControllerType = MOTOR_MODE; - // response.controlOutput.onboardControllerType = RATE_MODE; - response.controlOutput.onboardControllerType = ANGLE_MODE; + // response.controlOutput.onboardControllerType = CF_COMMAND_TYPE_MOTOR; + // response.controlOutput.onboardControllerType = CF_COMMAND_TYPE_RATE; + response.controlOutput.onboardControllerType = CF_COMMAND_TYPE_ANGLE; } @@ -486,6 +698,10 @@ void calculateControlOutput_viaLQRforAngles(float stateErrorBody[9], Controller: + + + + // ------------------------------------------------------------------------------ // RRRR OOO TTTTT A TTTTT EEEEE III N N TTTTT OOO // R R O O T A A T E I NN N T O O @@ -498,7 +714,7 @@ void calculateControlOutput_viaLQRforAngles(float stateErrorBody[9], Controller: // BBBB O O D D Y FFF RRRR A A M M M EEE // B B O O D D Y F R R AAAAA M M E // BBBB OOO DDDD Y F R R A A M M EEEEE -// ---------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------ // The arguments for this function are as follows: // stateInertial @@ -523,7 +739,7 @@ void calculateControlOutput_viaLQRforAngles(float stateErrorBody[9], Controller: // This is the yaw component of the intrinsic Euler angles in [radians] as measured by // the Vicon motion capture system // -void convertIntoBodyFrame(float stateInertial[9], float (&stateBody)[9], float yaw_measured) +void convertIntoBodyFrame(float stateInertial[12], float (&stateBody)[12], float yaw_measured) { if (shouldPerformConvertIntoBodyFrame) { @@ -544,6 +760,11 @@ void convertIntoBodyFrame(float stateInertial[9], float (&stateBody)[9], float y stateBody[6] = stateInertial[6]; stateBody[7] = stateInertial[7]; stateBody[8] = stateInertial[8]; + + // Fill in the (roll,pitch,yaw) velocity estimates to be returned + stateBody[9] = stateInertial[9]; + stateBody[10] = stateInertial[10]; + stateBody[11] = stateInertial[11]; } else { @@ -561,12 +782,59 @@ void convertIntoBodyFrame(float stateInertial[9], float (&stateBody)[9], float y stateBody[6] = stateInertial[6]; stateBody[7] = stateInertial[7]; stateBody[8] = stateInertial[8]; + + // Fill in the (roll,pitch,yaw) velocity estimates to be returned + stateBody[9] = stateInertial[9]; + stateBody[10] = stateInertial[10]; + stateBody[11] = stateInertial[11]; } } +void convert_stateInertial_to_bodyFrameError(float stateInertial[12], float setpoint[4], float (&bodyFrameError)[12]) +{ + // Store the current YAW in a local variable + float temp_stateInertial_yaw = stateInertial[8]; + + // Adjust the INERTIAL (x,y,z) position for the setpoint + stateInertial[0] = stateInertial[0] - setpoint[0]; + stateInertial[1] = stateInertial[1] - setpoint[1]; + stateInertial[2] = stateInertial[2] - setpoint[2]; + + // Fill in the yaw angle error + // > This error should be "unwrapped" to be in the range + // ( -pi , pi ) + // > First, get the yaw error into a local variable + float yawError = stateInertial[8] - setpoint[3]; + // > Second, "unwrap" the yaw error to the interval ( -pi , pi ) + while(yawError > PI) {yawError -= 2 * PI;} + while(yawError < -PI) {yawError += 2 * PI;} + // > Third, put the "yawError" into the "stateError" variable + stateInertial[8] = yawError; + + + if (yawError>(PI/6)) + { + yawError = (PI/6); + } + else if (yawError<(-PI/6)) + { + yawError = (-PI/6); + } + + // CONVERSION INTO BODY FRAME + // Conver the state erorr from the Inertial frame into the Body frame + // > Note: the function "convertIntoBodyFrame" is implemented in this file + // and by default does not perform any conversion. The equations to convert + // the state error into the body frame should be implemented in that function + // for successful completion of the PPS exercise + convertIntoBodyFrame(stateInertial, bodyFrameError, temp_stateInertial_yaw); +} + + + // ------------------------------------------------------------------------------ // N N EEEEE W W TTTTT OOO N N CCCC M M DDDD @@ -580,12 +848,25 @@ void convertIntoBodyFrame(float stateInertial[9], float (&stateBody)[9], float y // C O O N N N V V EEE RRRR SSS I O O N N N // C O O N NN V V E R R S I O O N NN // CCCC OOO N N V EEEEE R R SSSS III OOO N N -// ---------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------ // This function DOES NOT NEED TO BE edited for successful completion of the PPS exercise float computeMotorPolyBackward(float thrust) { - return (-motorPoly[1] + sqrt(motorPoly[1] * motorPoly[1] - 4 * motorPoly[2] * (motorPoly[0] - thrust))) / (2 * motorPoly[2]); + // Compute the 16-bit command signal that generates the "thrust" force + float cmd = (-motorPoly[1] + sqrt(motorPoly[1] * motorPoly[1] - 4 * motorPoly[2] * (motorPoly[0] - thrust))) / (2 * motorPoly[2]); + + // Saturate the signal to be 0 or in the range [1000,65000] + if (cmd < cmd_sixteenbit_min) + { + cmd = 0; + } + else if (cmd > cmd_sixteenbit_max) + { + cmd = cmd_sixteenbit_max; + } + + return cmd; } @@ -636,6 +917,30 @@ void xyz_yaw_to_follow_callback(const Setpoint& newSetpoint) +// ************************************************************************************************ +// PPPP U U BBBB L III SSSS H H X X Y Y ZZZZZ Y Y A W W +// P P U U B B L I S H H X X Y Y Z Y Y A A W W +// PPPP U U BBBB L I SSS HHHH X Y Z Y A A W W +// P U U B B L I S H H X X Y Z Y AAAAA W W W +// P UUU BBBB LLLLL III SSSS H H X X Y ZZZZZ Y A A W W + +// PUBLISH THE CURRENT X,Y,Z, AND YAW (if required) +void publish_current_xyz_yaw(float x, float y, float z, float yaw) +{ + // publish setpoint for FollowController of another student group + Setpoint temp_current_xyz_yaw; + // Fill in the x,y,z, and yaw info directly from the data provided to this + // function + temp_current_xyz_yaw.x = x; + temp_current_xyz_yaw.y = y; + temp_current_xyz_yaw.z = z; + temp_current_xyz_yaw.yaw = yaw; + my_current_xyz_yaw_publisher.publish(temp_current_xyz_yaw); +} + + + + // ---------------------------------------------------------------------------------- // L OOO A DDDD @@ -752,21 +1057,34 @@ void fetchYamlParameters(ros::NodeHandle& nodeHandle) // THE CONTROLLER GAINS: - // A flag for which controller to use, defined as: - controller_type = getParameterInt( nodeHandle_for_demoController , "controller_type" ); + // A flag for which controller to use: + lqr_controller_mode = getParameterInt( nodeHandle_for_demoController , "lqr_controller_mode" ); + + // A flag for which estimator to use: + estimator_method = getParameterInt( nodeHandle_for_demoController , "estimator_method" ); + + // The LQR Controller parameters for "LQR_MODE_MOTOR" + getParameterFloatVector(nodeHandle_for_demoController, "gainMatrixMotor1", gainMatrixMotor1, 12); + getParameterFloatVector(nodeHandle_for_demoController, "gainMatrixMotor2", gainMatrixMotor2, 12); + getParameterFloatVector(nodeHandle_for_demoController, "gainMatrixMotor3", gainMatrixMotor3, 12); + getParameterFloatVector(nodeHandle_for_demoController, "gainMatrixMotor4", gainMatrixMotor4, 12); - // The LQR Controller parameters for "LQR_RATE_MODE" + // The LQR Controller parameters for "LQR_MODE_RATE" getParameterFloatVector(nodeHandle_for_demoController, "gainMatrixRollRate", gainMatrixRollRate, 9); getParameterFloatVector(nodeHandle_for_demoController, "gainMatrixPitchRate", gainMatrixPitchRate, 9); getParameterFloatVector(nodeHandle_for_demoController, "gainMatrixYawRate", gainMatrixYawRate, 9); getParameterFloatVector(nodeHandle_for_demoController, "gainMatrixThrust_NineStateVector", gainMatrixThrust_NineStateVector, 9); - // The LQR Controller parameters for "LQR_ANGLE_MODE" + // The LQR Controller parameters for "LQR_MODE_ANGLE" getParameterFloatVector(nodeHandle_for_demoController, "gainMatrixRollAngle", gainMatrixRollAngle, 6); getParameterFloatVector(nodeHandle_for_demoController, "gainMatrixPitchAngle", gainMatrixPitchAngle, 6); getParameterFloatVector(nodeHandle_for_demoController, "gainMatrixThrust_SixStateVector", gainMatrixThrust_SixStateVector, 6); + // 16-BIT COMMAND LIMITS + cmd_sixteenbit_min = getParameterFloat(nodeHandle_for_demoController, "command_sixteenbit_min"); + cmd_sixteenbit_max = getParameterFloat(nodeHandle_for_demoController, "command_sixteenbit_max"); + // DEBUGGING: Print out one of the parameters that was loaded ROS_INFO_STREAM("DEBUGGING: the fetched SafeController/mass = " << cf_mass); @@ -784,7 +1102,11 @@ void processFetchedParameters() { // Compute the feed-forward force that we need to counteract gravity (i.e., mg) // > in units of [Newtons] - gravity_force = cf_mass * 9.81/(1000*4); + gravity_force = cf_mass * 9.81/(1000); + gravity_force_quarter = cf_mass * 9.81/(1000*4); + + // Set that the estimator frequency is the same as the control frequency + estimator_frequency = control_frequency; // Look-up which agent should be followed if (shouldFollowAnotherAgent) -- GitLab