From e862f7ba29c966aaf344903f1ac1faf9e77435d7 Mon Sep 17 00:00:00 2001 From: beuchatp <beuchatp@control.ee.ethz.ch> Date: Mon, 4 Feb 2019 10:21:09 +0100 Subject: [PATCH] Adjust the Picker Controller Node to be integrated with the GUI. Needs compiling and testing. --- .../include/nodes/PickerControllerConstants.h | 2 +- .../include/nodes/PickerControllerService.h | 136 +- .../include/nodes/StudentControllerService.h | 2 +- .../d_fall_pps/param/PickerController.yaml | 46 +- .../src/nodes/PickerControllerService.cpp | 1659 ++++++++++------- .../src/nodes/StudentControllerService.cpp | 4 +- 6 files changed, 1056 insertions(+), 793 deletions(-) diff --git a/pps_ws/src/d_fall_pps/include/nodes/PickerControllerConstants.h b/pps_ws/src/d_fall_pps/include/nodes/PickerControllerConstants.h index 3b1c36cd..41ab3321 100644 --- a/pps_ws/src/d_fall_pps/include/nodes/PickerControllerConstants.h +++ b/pps_ws/src/d_fall_pps/include/nodes/PickerControllerConstants.h @@ -36,7 +36,7 @@ // TO IDENITFY THE STATE OF THE PICKER #define PICKER_STATE_UNKNOWN -1 -#define PICKER_STATE_STANDBY 0 +#define PICKER_STATE_STANDBY 99 #define PICKER_STATE_GOTO_START 1 #define PICKER_STATE_ATTACH 2 #define PICKER_STATE_LIFT_UP 3 diff --git a/pps_ws/src/d_fall_pps/include/nodes/PickerControllerService.h b/pps_ws/src/d_fall_pps/include/nodes/PickerControllerService.h index e1cc4c15..359438b9 100644 --- a/pps_ws/src/d_fall_pps/include/nodes/PickerControllerService.h +++ b/pps_ws/src/d_fall_pps/include/nodes/PickerControllerService.h @@ -178,12 +178,18 @@ using namespace d_fall_pps; // ---------------------------------------- // VARIABLES SPECIFIC TO THE PICKER SERVICE +// The current state of the picker, i.e., +// {goto start, attach, lift up, goto end, put down, +// squat, jump, standby} +int m_picker_current_state = PICKER_STATE_STANDBY; + // Current time -int m_time_ticks = 0; -float m_time_seconds; +//int m_time_ticks = 0; +//float m_time_seconds; // > Total mass of the Crazyflie plus whatever it is carrying, in [grams] -float m_mass_total_grams; +float m_mass_total_in_grams; +float m_weight_total_in_newtons; // The setpoint to be tracked, the ordering is (x,y,z,yaw), // with units [meters,meters,meters,radians] @@ -226,7 +232,7 @@ std::string m_namespace_to_coordinator_parameter_service; // VARIABLES FOR THE CONTOLLER // > the mass of the crazyflie, in [grams] -float yaml_cf_mass_in_grams = 25.0; +float yaml_mass_cf_in_grams = 25.0; // > the coefficients of the 16-bit command to thrust conversion //std::vector<float> yaml_motorPoly(3); @@ -240,10 +246,10 @@ float yaml_control_frequency = 200.0; std::vector<float> yaml_default_setpoint = {0.0,0.0,0.4,0.0}; // The weight of the Crazyflie in Newtons, i.e., mg -float m_cf_weight_in_newtons = 0.0; +float m_weight_cf_in_newtons = 0.0; // The location error of the Crazyflie at the "previous" time step -float m_previous_stateErrorInertial[9]; +std::vector<float> m_previous_stateErrorInertial = {0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0}; // The LQR Controller parameters for "CONTROLLER_MODE_LQR_RATE" std::vector<float> yaml_gainMatrixThrust_NineStateVector (9,0.0); @@ -252,15 +258,15 @@ std::vector<float> yaml_gainMatrixPitchRate (9,0.0); std::vector<float> yaml_gainMatrixYawRate (9,0.0); // The 16-bit command limits -float yaml_cmd_sixteenbit_min; -float yaml_cmd_sixteenbit_max; +float yaml_cmd_sixteenbit_min = 1000; +float yaml_cmd_sixteenbit_max = 60000; // VARIABLES FOR THE ESTIMATOR // Frequency at which the controller is running -float yaml_estimator_frequency; +float yaml_estimator_frequency = 200.0; // > A flag for which estimator to use: int yaml_estimator_method = ESTIMATOR_METHOD_FINITE_DIFFERENCE; @@ -299,16 +305,16 @@ std::vector<float> yaml_PMKF_Kinf_for_angles (2,0.0); // VARIABLES RELATING TO PERFORMING THE CONVERSION INTO BODY FRAME // Boolean whether to execute the convert into body frame function -bool shouldPerformConvertIntoBodyFrame = false; +bool yaml_shouldPerformConvertIntoBodyFrame = false; // VARIABLES RELATING TO THE PUBLISHING OF A DEBUG MESSAGE // Boolean indiciating whether the "Debug Message" of this agent should be published or not -bool shouldPublishDebugMessage = false; +bool yaml_shouldPublishDebugMessage = false; // Boolean indiciating whether the debugging ROS_INFO_STREAM should be displayed or not -bool shouldDisplayDebugInfo = false; +bool yaml_shouldDisplayDebugInfo = false; // ROS Publisher for debugging variables ros::Publisher m_debugPublisher; @@ -530,45 +536,46 @@ ros::Publisher m_setpointChangedPublisher; void perControlCycleOperations(); // CALLBACK FROM ROS MESSAGES RECEIVED -void buttonPressedCallback(const std_msgs::Int32& msg); -void zSetpointCallback(const std_msgs::Float32& msg); -void yawSetpointCallback(const std_msgs::Float32& msg); -void massCallback(const std_msgs::Float32& msg); -void xAdjustmentCallback(const std_msgs::Float32& msg); -void yAdjustmentCallback(const std_msgs::Float32& msg); +//void buttonPressedCallback(const std_msgs::Int32& msg); +// void zSetpointCallback(const std_msgs::Float32& msg); +// void yawSetpointCallback(const std_msgs::Float32& msg); +// void massCallback(const std_msgs::Float32& msg); +// void xAdjustmentCallback(const std_msgs::Float32& msg); +// void yAdjustmentCallback(const std_msgs::Float32& msg); void buttonPressedWithSetpointCallback(const SetpointV2& newSetpointV2); // SEPARATE CALLBACK FUNCTIONS FOR EACH BUTTON -void buttonPressed_gotoStart(); +void buttonPressed_goto_start(); void buttonPressed_attach(); -void buttonPressed_pickup(); -void buttonPressed_gotoEnd(); -void buttonPressed_putdown(); +void buttonPressed_lift_up(); +void buttonPressed_goto_end(); +void buttonPressed_put_down(); void buttonPressed_squat(); void buttonPressed_jump(); +void buttonPressed_standby(); -void buttonPressed_1(); -void buttonPressed_2(); -void buttonPressed_3(); -void buttonPressed_4(); +// void buttonPressed_1(); +// void buttonPressed_2(); +// void buttonPressed_3(); +// void buttonPressed_4(); // SEPARATE CALLBACK FUNCTIONS FOR EACH BUTTON // > WITH A SETPOINT IN THE MESSAGE -void buttonPressedWithSetpoint_gotoStart(const SetpointV2& newSetpointV2); -void buttonPressedWithSetpoint_attach(const SetpointV2& newSetpointV2); -void buttonPressedWithSetpoint_pickup(const SetpointV2& newSetpointV2); -void buttonPressedWithSetpoint_gotoEnd(const SetpointV2& newSetpointV2); -void buttonPressedWithSetpoint_putdown(const SetpointV2& newSetpointV2); -void buttonPressedWithSetpoint_squat(const SetpointV2& newSetpointV2); -void buttonPressedWithSetpoint_jump(const SetpointV2& newSetpointV2); +// void buttonPressedWithSetpoint_gotoStart(const SetpointV2& newSetpointV2); +// void buttonPressedWithSetpoint_attach(const SetpointV2& newSetpointV2); +// void buttonPressedWithSetpoint_pickup(const SetpointV2& newSetpointV2); +// void buttonPressedWithSetpoint_gotoEnd(const SetpointV2& newSetpointV2); +// void buttonPressedWithSetpoint_putdown(const SetpointV2& newSetpointV2); +// void buttonPressedWithSetpoint_squat(const SetpointV2& newSetpointV2); +// void buttonPressedWithSetpoint_jump(const SetpointV2& newSetpointV2); -void buttonPressedWithSetpoint_1(const SetpointV2& newSetpointV2); -void buttonPressedWithSetpoint_2(const SetpointV2& newSetpointV2); -void buttonPressedWithSetpoint_3(const SetpointV2& newSetpointV2); -void buttonPressedWithSetpoint_4(const SetpointV2& newSetpointV2); +// void buttonPressedWithSetpoint_1(const SetpointV2& newSetpointV2); +// void buttonPressedWithSetpoint_2(const SetpointV2& newSetpointV2); +// void buttonPressedWithSetpoint_3(const SetpointV2& newSetpointV2); +// void buttonPressedWithSetpoint_4(const SetpointV2& newSetpointV2); @@ -580,39 +587,39 @@ void buttonPressedWithSetpoint_4(const SetpointV2& newSetpointV2); // > The function that is called to "start" all estimation and control computations bool calculateControlOutput(Controller::Request &request, Controller::Response &response); +// > The function that smooth changes in the setpoin +void smoothSetpointChanges(); + // > 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); -void calculateControlOutput_viaLQRforAnglesRatesNested( float stateErrorBody[12], Controller::Request &request, Controller::Response &response); -void calculateControlOutput_viaAngleResponseTest( float stateErrorBody[12], Controller::Request &request, Controller::Response &response); +void calculateControlOutput_viaLQRforRates(float stateErrorBody[12], Controller::Request &request, Controller::Response &response); // ESTIMATOR COMPUTATIONS void performEstimatorUpdate_forStateInterial(Controller::Request &request); void performEstimatorUpdate_forStateInterial_viaFiniteDifference(); void performEstimatorUpdate_forStateInterial_viaPointMassKalmanFilter(); - // PUBLISHING OF THE DEBUG MESSAGE void construct_and_publish_debug_message(Controller::Request &request, Controller::Response &response); - -// TRANSFORMATION FROM INTERIAL ESTIMATE TO BODY FRAME ERROR +// 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 +// TRANSFORMATION OF THE (x,y) INERTIAL FRAME ERROR +// INTO AN (x,y) BODY FRAME ERROR void convertIntoBodyFrame(float stateInertial[12], float (&stateBody)[12], float yaw_measured); // CONVERSION FROM THRUST IN NEWTONS TO 16-BIT COMMAND float computeMotorPolyBackward(float thrust); -// SETPOINT CHANGE CALLBACK -void setpointCallback(const Setpoint& newSetpoint); -void xyz_yaw_to_follow_callback(const Setpoint& newSetpoint); +// REQUEST SETPOINT CHANGE CALLBACK +void requestSetpointChangeCallback(const SetpointWithHeader& newSetpoint); -void publishCurrentSetpoint(); +// CHANGE SETPOINT FUNCTION +void setNewSetpoint(float x, float y, float z, float yaw); + +// GET CURRENT SETPOINT SERVICE CALLBACK +bool getCurrentSetpointCallback(GetSetpointService::Request &request, GetSetpointService::Response &response); // CUSTOM COMMAND RECEIVED CALLBACK //void customCommandReceivedCallback(const CustomButton& commandReceived); @@ -620,15 +627,18 @@ void publishCurrentSetpoint(); // 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 yamlReadyForFetchCallback(const std_msgs::Int32& msg); -void fetchYamlParameters(ros::NodeHandle& nodeHandle); -void processFetchedParameters(); +// FOR LOADING THE YAML 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 isReadyPickerControllerYamlCallback(const IntWithHeader & msg); +void fetchPickerControllerYamlParameters(ros::NodeHandle& nodeHandle); + +//void yamlReadyForFetchCallback(const std_msgs::Int32& msg); +//void fetchYamlParameters(ros::NodeHandle& nodeHandle); +//void processFetchedParameters(); diff --git a/pps_ws/src/d_fall_pps/include/nodes/StudentControllerService.h b/pps_ws/src/d_fall_pps/include/nodes/StudentControllerService.h index 42276a73..7dccc05a 100644 --- a/pps_ws/src/d_fall_pps/include/nodes/StudentControllerService.h +++ b/pps_ws/src/d_fall_pps/include/nodes/StudentControllerService.h @@ -249,6 +249,6 @@ bool getCurrentSetpointCallback(GetSetpointService::Request &request, GetSetpoin // CUSTOM COMMAND RECEIVED CALLBACK void customCommandReceivedCallback(const CustomButtonWithHeader& commandReceived); -// > For the LOADING of YAML PARAMETERS +// FOR LOADING THE YAML PARAMETERS void isReadyStudentControllerYamlCallback(const IntWithHeader & msg); void fetchStudentControllerYamlParameters(ros::NodeHandle& nodeHandle); \ No newline at end of file diff --git a/pps_ws/src/d_fall_pps/param/PickerController.yaml b/pps_ws/src/d_fall_pps/param/PickerController.yaml index 13776ed9..65e5fff4 100644 --- a/pps_ws/src/d_fall_pps/param/PickerController.yaml +++ b/pps_ws/src/d_fall_pps/param/PickerController.yaml @@ -1,35 +1,34 @@ -# Mass of the crazyflie -mass_CF : 32 + +# Max setpoint change per second +max_setpoint_change_per_second_horizontal : 0.20 # [meters] +max_setpoint_change_per_second_vertical : 0.10 # [meters] +max_setpoint_change_per_second_yaw_degrees : 90.00 # [degrees] + + + # Mass of the letters -mass_E : 3.2 -mass_T : 2.9 -mass_H : 3.3 +#mass_E : 3.2 +#mass_T : 2.9 +#mass_H : 3.3 # Thickness of the object at pick-up and put-down, in [meters] # > This should also account for extra height due to # the surface where the object is -thickness_of_object_at_pickup : 0.02 -thickness_of_object_at_putdown : 0.03 +#thickness_of_object_at_pickup : 0.02 +#thickness_of_object_at_putdown : 0.03 # (x,y) coordinates of the pickup location -pickup_coordinates_xy : [-0.26, 0.12] +#pickup_coordinates_xy : [-0.26, 0.12] # (x,y) coordinates of the drop off location -dropoff_coordinates_xy_for_E : [ 0.33, -0.03] -dropoff_coordinates_xy_for_T : [ 0.24, 0.00] -dropoff_coordinates_xy_for_H : [ 0.28, 0.00] +#dropoff_coordinates_xy_for_E : [ 0.33, -0.03] +#dropoff_coordinates_xy_for_T : [ 0.24, 0.00] +#dropoff_coordinates_xy_for_H : [ 0.28, 0.00] # Length of the string from the Crazyflie # to the end of the Picker, in [meters] -picker_string_length : 0.30 +#picker_string_length : 0.30 -# Max setpoint change per second -max_setpoint_change_per_second_horizontal : 0.20 # [meters] -max_setpoint_change_per_second_vertical : 0.10 # [meters] -max_setpoint_change_per_second_yaw_degrees : 90.00 # [degrees] - -# Frequency of the controller, in hertz -vicon_frequency : 200 @@ -40,10 +39,11 @@ vicon_frequency : 200 +# ------------------------------------------------------ +# PARAMTERS THAT ARE STANDARD FOR A "CONTROLLER SERVICE" - -# THE FOLLOWING PARAMETERS ARE USED -# FOR THE LOW-LEVEL CONTROLLER +# Mass of the crazyflie +mass_cf_in_grams : 32 # Frequency of the controller, in hertz control_frequency : 200 @@ -55,7 +55,7 @@ motorPoly : [5.484560e-4, 1.032633e-6, 2.130295e-11] shouldPerformConvertIntoBodyFrame : true # Boolean indiciating whether the (x,y,z,yaw) of this agent should be published or not -shouldPublishCurrent_xyz_yaw : true +#shouldPublishCurrent_xyz_yaw : true # Boolean indiciating whether the "Debug Message" of this agent should be published or not shouldPublishDebugMessage : true diff --git a/pps_ws/src/d_fall_pps/src/nodes/PickerControllerService.cpp b/pps_ws/src/d_fall_pps/src/nodes/PickerControllerService.cpp index 273d4a7f..ee97a8c3 100644 --- a/pps_ws/src/d_fall_pps/src/nodes/PickerControllerService.cpp +++ b/pps_ws/src/d_fall_pps/src/nodes/PickerControllerService.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2017, ETH Zurich, D-ITET, Paul Beuchat, Angel Romero, Cyrill Burgener, Marco Mueller, Philipp Friedli +// Copyright (C) 2017, ETH Zurich, D-ITET, Paul Beuchat // // This file is part of D-FaLL-System. // @@ -89,12 +89,12 @@ // // Boolean for whether to limit rate of change of the setpoint // bool m_shouldSmoothSetpointChanges = true; // // Max setpoint change per second -// float m_max_setpoint_change_per_second_horizontal; -// float m_max_setpoint_change_per_second_vertical; -// float m_max_setpoint_change_per_second_yaw_degrees; +// float yaml_max_setpoint_change_per_second_horizontal; +// float yaml_max_setpoint_change_per_second_vertical; +// float yaml_max_setpoint_change_per_second_yaw_degrees; // float m_max_setpoint_change_per_second_yaw_radians; // // Frequency at which the controller is running -// float m_vicon_frequency; +// float m_control_frequency; // A FEW EXTRA COMMENTS ABOUT THE MOST IMPORTANT VARIABLES @@ -122,65 +122,15 @@ -// THIS FUNCTION IS CALLED AT "m_vicon_frequency" HERTZ. +// THIS FUNCTION IS CALLED AT "m_control_frequency" HERTZ. // IT CAN BE USED TO ADJUST THINGS IN "REAL TIME". // For example, the equation: -// >> m_max_setpoint_change_per_second_horizontal / m_vicon_frequency +// >> yaml_max_setpoint_change_per_second_horizontal / m_control_frequency // will convert the "change per second" to a "change per cycle". void perControlCycleOperations() { - if (m_shouldSmoothSetpointChanges) - { - for(int i = 0; i < 4; ++i) - { - float max_for_this_coordinate; - // FILLE IN THE STATE INERTIAL ESTIMATE TO BE USED FOR CONTROL - switch (i) - { - case 0: - max_for_this_coordinate = m_max_setpoint_change_per_second_horizontal / m_vicon_frequency; - break; - case 1: - max_for_this_coordinate = m_max_setpoint_change_per_second_horizontal / m_vicon_frequency; - break; - case 2: - max_for_this_coordinate = m_max_setpoint_change_per_second_vertical / m_vicon_frequency; - break; - case 3: - max_for_this_coordinate = m_max_setpoint_change_per_second_yaw_radians / m_vicon_frequency; - break; - // Handle the exception - default: - max_for_this_coordinate = 0.0f; - break; - } - - // Compute the difference in setpoint - float setpoint_difference = m_setpoint[i] - m_setpoint_for_controller[i]; - - // Clip the difference to the maximum - if (setpoint_difference > max_for_this_coordinate) - { - setpoint_difference = max_for_this_coordinate; - } - else if (setpoint_difference < -max_for_this_coordinate) - { - setpoint_difference = -max_for_this_coordinate; - } - - // Update the setpoint of the controller - m_setpoint_for_controller[i] += setpoint_difference; - } - - } - else - { - m_setpoint_for_controller[0] = m_setpoint[0]; - m_setpoint_for_controller[1] = m_setpoint[1]; - m_setpoint_for_controller[2] = m_setpoint[2]; - m_setpoint_for_controller[3] = m_setpoint[3]; - } + } @@ -191,169 +141,182 @@ void perControlCycleOperations() // CALLBACK FUNCTION THAT RUN WHEN THE RESPECTIVE BUTTON IS PRESSED -void buttonPressed_gotoStart() +// These functions are called from: +// >> "buttonPressedWithSetpointCallback" +// And in that function the following variable are already +// updated appropriately: +// >> "m_picker_current_state" +// >> "m_mass_total_grams" +// >> "m_shouldSmoothSetpointChanges" + +void buttonPressed_goto_start() { ROS_INFO("[PICKER CONTROLLER] Goto Start button pressed"); - // The drone should move smoothly to the start point: - m_shouldSmoothSetpointChanges = true; - // Set the (x,y) coordinates for the start point: - m_setpoint[0] = m_pickup_coordinates_xy[0]; - m_setpoint[1] = m_pickup_coordinates_xy[1]; - // Set the z coordinate to be a little more than the - // length of the "picker string" - m_setpoint[2] = m_picker_string_length + 0.10; - // Publish the setpoint so that the GUI updates - publishCurrentSetpoint(); + // // The drone should move smoothly to the start point: + // m_shouldSmoothSetpointChanges = true; + // // Set the (x,y) coordinates for the start point: + // m_setpoint[0] = m_pickup_coordinates_xy[0]; + // m_setpoint[1] = m_pickup_coordinates_xy[1]; + // // Set the z coordinate to be a little more than the + // // length of the "picker string" + // m_setpoint[2] = m_picker_string_length + 0.10; + // // Publish the setpoint so that the GUI updates + // publishCurrentSetpoint(); } void buttonPressed_attach() { ROS_INFO("[PICKER CONTROLLER] Attach button pressed"); - m_shouldSmoothSetpointChanges = true; - m_setpoint[2] = m_picker_string_length + m_thickness_of_object_at_pickup; - publishCurrentSetpoint(); + // m_shouldSmoothSetpointChanges = true; + // m_setpoint[2] = m_picker_string_length + m_thickness_of_object_at_pickup; + // publishCurrentSetpoint(); } -void buttonPressed_pickup() +void buttonPressed_lift_up() { ROS_INFO("[PICKER CONTROLLER] Pick up button pressed"); - m_shouldSmoothSetpointChanges = true; - m_mass_total_grams = m_mass_CF_grams + m_mass_E_grams; - m_setpoint[2] = m_picker_string_length + 0.25; - publishCurrentSetpoint(); + // m_shouldSmoothSetpointChanges = true; + // m_mass_total_grams = m_mass_CF_grams + m_mass_E_grams; + // m_setpoint[2] = m_picker_string_length + 0.25; + // publishCurrentSetpoint(); } -void buttonPressed_gotoEnd() +void buttonPressed_goto_end() { ROS_INFO("[PICKER CONTROLLER] Goto End button pressed"); - m_shouldSmoothSetpointChanges = true; - m_setpoint[0] = m_dropoff_coordinates_xy_for_E[0]; - m_setpoint[1] = m_dropoff_coordinates_xy_for_E[1]; - publishCurrentSetpoint(); + // m_shouldSmoothSetpointChanges = true; + // m_setpoint[0] = m_dropoff_coordinates_xy_for_E[0]; + // m_setpoint[1] = m_dropoff_coordinates_xy_for_E[1]; + // publishCurrentSetpoint(); } -void buttonPressed_putdown() +void buttonPressed_put_down() { ROS_INFO("[PICKER CONTROLLER] Put down button pressed"); - m_shouldSmoothSetpointChanges = true; - m_setpoint[2] = m_picker_string_length + m_thickness_of_object_at_putdown; - m_mass_total_grams = m_mass_CF_grams; - publishCurrentSetpoint(); + // m_shouldSmoothSetpointChanges = true; + // m_setpoint[2] = m_picker_string_length + m_thickness_of_object_at_putdown; + // m_mass_total_grams = m_mass_CF_grams; + // publishCurrentSetpoint(); } void buttonPressed_squat() { ROS_INFO("[PICKER CONTROLLER] Squat button pressed"); - m_shouldSmoothSetpointChanges = true; - m_setpoint[2] = m_picker_string_length - 0.10; - m_mass_total_grams = m_mass_CF_grams; - publishCurrentSetpoint(); + // m_shouldSmoothSetpointChanges = true; + // m_setpoint[2] = m_picker_string_length - 0.10; + // m_mass_total_grams = m_mass_CF_grams; + // publishCurrentSetpoint(); } void buttonPressed_jump() { ROS_INFO("[PICKER CONTROLLER] Jump button pressed"); - m_shouldSmoothSetpointChanges = false; - m_setpoint[2] = m_picker_string_length + 0.10; - m_mass_total_grams = m_mass_CF_grams; - publishCurrentSetpoint(); + // m_shouldSmoothSetpointChanges = false; + // m_setpoint[2] = m_picker_string_length + 0.10; + // m_mass_total_grams = m_mass_CF_grams; + // publishCurrentSetpoint(); } - - -// THESE CALLBACK FUNCTIONS ALLOW YOU TO IMPLEMENT SOME -// CUSTOM ACTION IN RESPONSE TO THE RESPECTIVE BUTTON PRESSES - -void buttonPressed_1() -{ - ROS_INFO("[PICKER CONTROLLER] Button 1 pressed"); -} -void buttonPressed_2() +void buttonPressed_standby() { - ROS_INFO("[PICKER CONTROLLER] Button 2 pressed"); -} + ROS_INFO("[PICKER CONTROLLER] Standby button pressed"); -void buttonPressed_3() -{ - ROS_INFO("[PICKER CONTROLLER] Button 3 pressed"); + // m_shouldSmoothSetpointChanges = false; + // m_setpoint[2] = m_picker_string_length + 0.10; + // m_mass_total_grams = m_mass_CF_grams; + // publishCurrentSetpoint(); } -void buttonPressed_4() -{ - ROS_INFO("[PICKER CONTROLLER] Button 4 pressed"); -} +// THESE CALLBACK FUNCTIONS ALLOW YOU TO IMPLEMENT SOME +// CUSTOM ACTION IN RESPONSE TO THE RESPECTIVE BUTTON PRESSES +// void buttonPressed_1() +// { +// ROS_INFO("[PICKER CONTROLLER] Button 1 pressed"); +// } +// void buttonPressed_2() +// { +// ROS_INFO("[PICKER CONTROLLER] Button 2 pressed"); +// } +// void buttonPressed_3() +// { +// ROS_INFO("[PICKER CONTROLLER] Button 3 pressed"); +// } +// void buttonPressed_4() +// { +// ROS_INFO("[PICKER CONTROLLER] Button 4 pressed"); +// } -void zSetpointCallback(const std_msgs::Float32& msg) -{ - // The "data" in the message is z-height in [meters] - float z_height = msg.data; - // Display the data - ROS_INFO_STREAM("[PICKER CONTROLLER] Z Slider changed to " << z_height << " [m]" ); - // Update the z-component of the setpoint class variable - m_setpoint[2] = z_height; -} -void yawSetpointCallback(const std_msgs::Float32& msg) -{ - // The "data" in the message is yaw-angle in [radians] - float yaw_angle = msg.data; - // Display the data - ROS_INFO_STREAM("[PICKER CONTROLLER] Yaw Dial changed to " << (yaw_angle*RAD2DEG) << " [deg]" ); - // Update the yaw-component of the setpoint class variable - m_setpoint[3] = yaw_angle; -} -void massCallback(const std_msgs::Float32& msg) -{ - // The "data" in the message is mass in [grams] - float mass = msg.data; - // Display the data - ROS_INFO_STREAM("[PICKER CONTROLLER] Mass slider changed to " << mass << " [grams]" ); - // Update the total mass class variable - m_mass_total_grams = mass; -} -void xAdjustmentCallback(const std_msgs::Float32& msg) -{ - // The "data" in the message is adjustment in [meters] - float x_adjustment = msg.data; - // Display the data - ROS_INFO_STREAM("[PICKER CONTROLLER] X adjustment slider changed to " << x_adjustment << " [m]" ); - // Update the x-adjustment class variable - m_xAdjustment = x_adjustment; -} -void yAdjustmentCallback(const std_msgs::Float32& msg) -{ - // The "data" in the message is adjustment in [meters] - float y_adjustment = msg.data; - // Display the data - ROS_INFO_STREAM("[PICKER CONTROLLER] Y adjustment slider changed to " << y_adjustment << " [m]" ); - // Update the y-adjustment class variable - m_yAdjustment = y_adjustment; -} +// void zSetpointCallback(const std_msgs::Float32& msg) +// { +// // The "data" in the message is z-height in [meters] +// float z_height = msg.data; +// // Display the data +// ROS_INFO_STREAM("[PICKER CONTROLLER] Z Slider changed to " << z_height << " [m]" ); +// // Update the z-component of the setpoint class variable +// m_setpoint[2] = z_height; +// } +// void yawSetpointCallback(const std_msgs::Float32& msg) +// { +// // The "data" in the message is yaw-angle in [radians] +// float yaw_angle = msg.data; +// // Display the data +// ROS_INFO_STREAM("[PICKER CONTROLLER] Yaw Dial changed to " << (yaw_angle*RAD2DEG) << " [deg]" ); +// // Update the yaw-component of the setpoint class variable +// m_setpoint[3] = yaw_angle; +// } +// void massCallback(const std_msgs::Float32& msg) +// { +// // The "data" in the message is mass in [grams] +// float mass = msg.data; +// // Display the data +// ROS_INFO_STREAM("[PICKER CONTROLLER] Mass slider changed to " << mass << " [grams]" ); +// // Update the total mass class variable +// m_mass_total_grams = mass; +// } +// void xAdjustmentCallback(const std_msgs::Float32& msg) +// { +// // The "data" in the message is adjustment in [meters] +// float x_adjustment = msg.data; +// // Display the data +// ROS_INFO_STREAM("[PICKER CONTROLLER] X adjustment slider changed to " << x_adjustment << " [m]" ); +// // Update the x-adjustment class variable +// m_xAdjustment = x_adjustment; +// } +// void yAdjustmentCallback(const std_msgs::Float32& msg) +// { +// // The "data" in the message is adjustment in [meters] +// float y_adjustment = msg.data; +// // Display the data +// ROS_INFO_STREAM("[PICKER CONTROLLER] Y adjustment slider changed to " << y_adjustment << " [m]" ); +// // Update the y-adjustment class variable +// m_yAdjustment = y_adjustment; +// } @@ -363,123 +326,189 @@ void yAdjustmentCallback(const std_msgs::Float32& msg) -// CALLBACK FUNCTION THAT RUN WHEN THE RESPECTIVE BUTTON IS PRESSED -// > AND A SETPOINT IS PROVIDED -void buttonPressedWithSetpoint_gotoStart(const SetpointV2& newSetpointV2) -{ - ROS_INFO_STREAM("[PICKER CONTROLLER] Goto Start button pressed: (x,y,z)=(" << newSetpointV2.x << "," << newSetpointV2.y << "," << newSetpointV2.z << "), smooth=" << int(newSetpointV2.isChecked) ); - - // Use the boolean for the smoothing flag - m_shouldSmoothSetpointChanges = newSetpointV2.isChecked; - // Set the (x,y,z) coordinates: - m_setpoint[0] = newSetpointV2.x; - m_setpoint[1] = newSetpointV2.y; - m_setpoint[2] = newSetpointV2.z; - // Publish the setpoint so that the GUI updates - //publishCurrentSetpoint(); -} -void buttonPressedWithSetpoint_attach(const SetpointV2& newSetpointV2) -{ - ROS_INFO_STREAM("[PICKER CONTROLLER] Attach button pressed: z=" << newSetpointV2.z << ", smooth=" << int(newSetpointV2.isChecked) ); - - // Use the boolean for the smoothing flag - m_shouldSmoothSetpointChanges = newSetpointV2.isChecked; - // Set the z coordinate: - m_setpoint[2] = newSetpointV2.z; - // Publish the setpoint so that the GUI updates - //publishCurrentSetpoint(); -} -void buttonPressedWithSetpoint_pickup(const SetpointV2& newSetpointV2) -{ - ROS_INFO_STREAM("[PICKER CONTROLLER] Pick up button pressed: z=" << newSetpointV2.z << ", smooth=" << int(newSetpointV2.isChecked) ); - - // Use the boolean for the smoothing flag - m_shouldSmoothSetpointChanges = newSetpointV2.isChecked; - // Set the z coordinate: - m_setpoint[2] = newSetpointV2.z; - // Update the mass of the Crazyflie - m_mass_total_grams = m_mass_CF_grams + m_mass_E_grams; - // Publish the setpoint so that the GUI updates - //publishCurrentSetpoint(); -} -void buttonPressedWithSetpoint_gotoEnd(const SetpointV2& newSetpointV2) -{ - ROS_INFO_STREAM("[PICKER CONTROLLER] Goto End button pressed: (x,y)=(" << newSetpointV2.x << "," << newSetpointV2.y << "), smooth=" << int(newSetpointV2.isChecked) ); - - // Use the boolean for the smoothing flag - m_shouldSmoothSetpointChanges = newSetpointV2.isChecked; - // Set the (x,y) coordinates: - m_setpoint[0] = newSetpointV2.x; - m_setpoint[1] = newSetpointV2.y; - // Publish the setpoint so that the GUI updates - //publishCurrentSetpoint(); -} - -void buttonPressedWithSetpoint_putdown(const SetpointV2& newSetpointV2) -{ - ROS_INFO_STREAM("[PICKER CONTROLLER] Put down button pressed: z=" << newSetpointV2.z << ", smooth=" << int(newSetpointV2.isChecked) ); - - // Use the boolean for the smoothing flag - m_shouldSmoothSetpointChanges = newSetpointV2.isChecked; - // Set the z coordinate: - m_setpoint[2] = newSetpointV2.z; - // Update the mass of the Crazyflie - m_mass_total_grams = m_mass_CF_grams; - // Publish the setpoint so that the GUI updates - //publishCurrentSetpoint(); -} - -void buttonPressedWithSetpoint_squat(const SetpointV2& newSetpointV2) -{ - ROS_INFO_STREAM("[PICKER CONTROLLER] Squat button pressed: z=" << newSetpointV2.z << ", smooth=" << int(newSetpointV2.isChecked) ); - - // Use the boolean for the smoothing flag - m_shouldSmoothSetpointChanges = newSetpointV2.isChecked; - // Set the z coordinate: - m_setpoint[2] = newSetpointV2.z; - // Update the mass of the Crazyflie - m_mass_total_grams = m_mass_CF_grams; - // Publish the setpoint so that the GUI updates - //publishCurrentSetpoint(); -} - -void buttonPressedWithSetpoint_jump(const SetpointV2& newSetpointV2) -{ - ROS_INFO_STREAM("[PICKER CONTROLLER] Jump button pressed: z=" << newSetpointV2.z << ", smooth=" << int(newSetpointV2.isChecked) ); - - // Use the boolean for the smoothing flag - m_shouldSmoothSetpointChanges = newSetpointV2.isChecked; - // Set the z coordinate: - m_setpoint[2] = newSetpointV2.z; - // Update the mass of the Crazyflie - m_mass_total_grams = m_mass_CF_grams; - // Publish the setpoint so that the GUI updates - //publishCurrentSetpoint(); -} +// CALLBACK FUNCTION THAT RUN WHEN THE RESPECTIVE BUTTON IS PRESSED +// > AND A SETPOINT IS PROVIDED -void buttonPressedWithSetpoint_1(const SetpointV2& newSetpointV2) +// void buttonPressedWithSetpoint_gotoStart(const SetpointV2& newSetpointV2) +// { +// ROS_INFO_STREAM("[PICKER CONTROLLER] Goto Start button pressed: (x,y,z)=(" << newSetpointV2.x << "," << newSetpointV2.y << "," << newSetpointV2.z << "), smooth=" << int(newSetpointV2.isChecked) ); + +// // Use the boolean for the smoothing flag +// m_shouldSmoothSetpointChanges = newSetpointV2.isChecked; +// // Set the (x,y,z) coordinates: +// m_setpoint[0] = newSetpointV2.x; +// m_setpoint[1] = newSetpointV2.y; +// m_setpoint[2] = newSetpointV2.z; +// // Publish the setpoint so that the GUI updates +// //publishCurrentSetpoint(); +// } + +// void buttonPressedWithSetpoint_attach(const SetpointV2& newSetpointV2) +// { +// ROS_INFO_STREAM("[PICKER CONTROLLER] Attach button pressed: z=" << newSetpointV2.z << ", smooth=" << int(newSetpointV2.isChecked) ); + +// // Use the boolean for the smoothing flag +// m_shouldSmoothSetpointChanges = newSetpointV2.isChecked; +// // Set the z coordinate: +// m_setpoint[2] = newSetpointV2.z; +// // Publish the setpoint so that the GUI updates +// //publishCurrentSetpoint(); +// } + +// void buttonPressedWithSetpoint_pickup(const SetpointV2& newSetpointV2) +// { +// ROS_INFO_STREAM("[PICKER CONTROLLER] Pick up button pressed: z=" << newSetpointV2.z << ", smooth=" << int(newSetpointV2.isChecked) ); + +// // Use the boolean for the smoothing flag +// m_shouldSmoothSetpointChanges = newSetpointV2.isChecked; +// // Set the z coordinate: +// m_setpoint[2] = newSetpointV2.z; +// // Update the mass of the Crazyflie +// m_mass_total_grams = m_mass_CF_grams + m_mass_E_grams; +// // Publish the setpoint so that the GUI updates +// //publishCurrentSetpoint(); +// } + +// void buttonPressedWithSetpoint_gotoEnd(const SetpointV2& newSetpointV2) +// { +// ROS_INFO_STREAM("[PICKER CONTROLLER] Goto End button pressed: (x,y)=(" << newSetpointV2.x << "," << newSetpointV2.y << "), smooth=" << int(newSetpointV2.isChecked) ); + +// // Use the boolean for the smoothing flag +// m_shouldSmoothSetpointChanges = newSetpointV2.isChecked; +// // Set the (x,y) coordinates: +// m_setpoint[0] = newSetpointV2.x; +// m_setpoint[1] = newSetpointV2.y; +// // Publish the setpoint so that the GUI updates +// //publishCurrentSetpoint(); +// } + +// void buttonPressedWithSetpoint_putdown(const SetpointV2& newSetpointV2) +// { +// ROS_INFO_STREAM("[PICKER CONTROLLER] Put down button pressed: z=" << newSetpointV2.z << ", smooth=" << int(newSetpointV2.isChecked) ); + +// // Use the boolean for the smoothing flag +// m_shouldSmoothSetpointChanges = newSetpointV2.isChecked; +// // Set the z coordinate: +// m_setpoint[2] = newSetpointV2.z; +// // Update the mass of the Crazyflie +// m_mass_total_grams = m_mass_CF_grams; +// // Publish the setpoint so that the GUI updates +// //publishCurrentSetpoint(); +// } + +// void buttonPressedWithSetpoint_squat(const SetpointV2& newSetpointV2) +// { +// ROS_INFO_STREAM("[PICKER CONTROLLER] Squat button pressed: z=" << newSetpointV2.z << ", smooth=" << int(newSetpointV2.isChecked) ); + +// // Use the boolean for the smoothing flag +// m_shouldSmoothSetpointChanges = newSetpointV2.isChecked; +// // Set the z coordinate: +// m_setpoint[2] = newSetpointV2.z; +// // Update the mass of the Crazyflie +// m_mass_total_grams = m_mass_CF_grams; +// // Publish the setpoint so that the GUI updates +// //publishCurrentSetpoint(); +// } + +// void buttonPressedWithSetpoint_jump(const SetpointV2& newSetpointV2) +// { +// ROS_INFO_STREAM("[PICKER CONTROLLER] Jump button pressed: z=" << newSetpointV2.z << ", smooth=" << int(newSetpointV2.isChecked) ); + +// // Use the boolean for the smoothing flag +// m_shouldSmoothSetpointChanges = newSetpointV2.isChecked; +// // Set the z coordinate: +// m_setpoint[2] = newSetpointV2.z; +// // Update the mass of the Crazyflie +// m_mass_total_grams = m_mass_CF_grams; +// // Publish the setpoint so that the GUI updates +// //publishCurrentSetpoint(); +// } + + +// void buttonPressedWithSetpoint_1(const SetpointV2& newSetpointV2) +// { +// ROS_INFO("[PICKER CONTROLLER] Button 1 pressed with a setpoint provided"); +// } + +// void buttonPressedWithSetpoint_2(const SetpointV2& newSetpointV2) +// { +// ROS_INFO("[PICKER CONTROLLER] Button 2 pressed with a setpoint provided"); +// } + +// void buttonPressedWithSetpoint_3(const SetpointV2& newSetpointV2) +// { +// ROS_INFO("[PICKER CONTROLLER] Button 3 pressed with a setpoint provided"); +// } + +// void buttonPressedWithSetpoint_4(const SetpointV2& newSetpointV2) +// { +// ROS_INFO("[PICKER CONTROLLER] Button 4 pressed with a setpoint provided with a setpoint provided"); +// } + + + + + + + +void smoothSetpointChanges() { - ROS_INFO("[PICKER CONTROLLER] Button 1 pressed with a setpoint provided"); -} + if (m_shouldSmoothSetpointChanges) + { + for(int i = 0; i < 4; ++i) + { + float max_for_this_coordinate; + // FILL IN THE STATE INERTIAL ESTIMATE TO BE USED FOR CONTROL + switch (i) + { + case 0: + max_for_this_coordinate = yaml_max_setpoint_change_per_second_horizontal / m_control_frequency; + break; + case 1: + max_for_this_coordinate = yaml_max_setpoint_change_per_second_horizontal / m_control_frequency; + break; + case 2: + max_for_this_coordinate = yaml_max_setpoint_change_per_second_vertical / m_control_frequency; + break; + case 3: + max_for_this_coordinate = m_max_setpoint_change_per_second_yaw_radians / m_control_frequency; + break; + // Handle the exception + default: + max_for_this_coordinate = 0.0f; + break; + } -void buttonPressedWithSetpoint_2(const SetpointV2& newSetpointV2) -{ - ROS_INFO("[PICKER CONTROLLER] Button 2 pressed with a setpoint provided"); -} + // Compute the difference in setpoint + float setpoint_difference = m_setpoint[i] - m_setpoint_for_controller[i]; -void buttonPressedWithSetpoint_3(const SetpointV2& newSetpointV2) -{ - ROS_INFO("[PICKER CONTROLLER] Button 3 pressed with a setpoint provided"); -} + // Clip the difference to the maximum + if (setpoint_difference > max_for_this_coordinate) + { + setpoint_difference = max_for_this_coordinate; + } + else if (setpoint_difference < -max_for_this_coordinate) + { + setpoint_difference = -max_for_this_coordinate; + } -void buttonPressedWithSetpoint_4(const SetpointV2& newSetpointV2) -{ - ROS_INFO("[PICKER CONTROLLER] Button 4 pressed with a setpoint provided with a setpoint provided"); + // Update the setpoint of the controller + m_setpoint_for_controller[i] += setpoint_difference; + } + + } + else + { + m_setpoint_for_controller[0] = m_setpoint[0]; + m_setpoint_for_controller[1] = m_setpoint[1]; + m_setpoint_for_controller[2] = m_setpoint[2]; + m_setpoint_for_controller[3] = m_setpoint[3]; + } } @@ -494,10 +523,6 @@ void buttonPressedWithSetpoint_4(const SetpointV2& newSetpointV2) - - - - // ------------------------------------------------------------------------------ // OOO U U TTTTT EEEEE RRRR // O O U U T E R R @@ -606,8 +631,8 @@ bool calculateControlOutput(Controller::Request &request, Controller::Response & { // Keep track of time - m_time_ticks++; - m_time_seconds = float(m_time_ticks) / m_vicon_frequency; + //m_time_ticks++; + //m_time_seconds = float(m_time_ticks) / m_control_frequency; // CALL THE FUNCTION FOR PER CYLCE OPERATIONS @@ -621,17 +646,21 @@ bool calculateControlOutput(Controller::Request &request, Controller::Response & // PERFORM THE ESTIMATOR UPDATE FOR THE INTERIAL FRAME STATE // > After this function is complete the class variable - // "current_stateInertialEstimate" is updated and ready + // "m_current_stateInertialEstimate" is updated and ready // to be used for subsequent controller copmutations performEstimatorUpdate_forStateInterial(request); + + // SMOOTH ANY CHANGES THAT MAY HAVE OCCURRED IN THE + // SETPOINT + smoothSetpointChanges(); // 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,m_setpoint_for_controller,current_bodyFrameError); + convert_stateInertial_to_bodyFrameError(m_current_stateInertialEstimate,m_setpoint_for_controller,current_bodyFrameError); @@ -641,14 +670,14 @@ bool calculateControlOutput(Controller::Request &request, Controller::Response & - // PUBLISH THE CURRENT X,Y,Z, AND YAW (if required) - if (shouldPublishCurrent_xyz_yaw) - { - publish_current_xyz_yaw(request.ownCrazyflie.x,request.ownCrazyflie.y,request.ownCrazyflie.z,request.ownCrazyflie.yaw); - } + // // PUBLISH THE CURRENT X,Y,Z, AND YAW (if required) + // if (shouldPublishCurrent_xyz_yaw) + // { + // publish_current_xyz_yaw(request.ownCrazyflie.x,request.ownCrazyflie.y,request.ownCrazyflie.z,request.ownCrazyflie.yaw); + // } // PUBLISH THE DEBUG MESSAGE (if required) - if (shouldPublishDebugMessage) + if (yaml_shouldPublishDebugMessage) { construct_and_publish_debug_message(request,response); } @@ -672,13 +701,13 @@ 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; + m_current_xzy_rpy_measurement[0] = request.ownCrazyflie.x; + m_current_xzy_rpy_measurement[1] = request.ownCrazyflie.y; + m_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; + m_current_xzy_rpy_measurement[3] = request.ownCrazyflie.roll; + m_current_xzy_rpy_measurement[4] = request.ownCrazyflie.pitch; + m_current_xzy_rpy_measurement[5] = request.ownCrazyflie.yaw; // RUN THE FINITE DIFFERENCE ESTIMATOR @@ -690,7 +719,7 @@ void performEstimatorUpdate_forStateInterial(Controller::Request &request) // FILLE IN THE STATE INERTIAL ESTIMATE TO BE USED FOR CONTROL - switch (estimator_method) + switch (yaml_estimator_method) { // Estimator based on finte differences case ESTIMATOR_METHOD_FINITE_DIFFERENCE: @@ -698,7 +727,7 @@ void performEstimatorUpdate_forStateInterial(Controller::Request &request) // Transfer the estimate for(int i = 0; i < 12; ++i) { - current_stateInertialEstimate[i] = stateInterialEstimate_viaFiniteDifference[i]; + m_current_stateInertialEstimate[i] = m_stateInterialEstimate_viaFiniteDifference[i]; } break; } @@ -708,19 +737,19 @@ void performEstimatorUpdate_forStateInterial(Controller::Request &request) // Transfer the estimate for(int i = 0; i < 12; ++i) { - current_stateInertialEstimate[i] = stateInterialEstimate_viaPointMassKalmanFilter[i]; + m_current_stateInertialEstimate[i] = m_stateInterialEstimate_viaPointMassKalmanFilter[i]; } break; } // Handle the exception default: { - // Display that the "estimator_method" was not recognised - ROS_INFO_STREAM("[PICKER CONTROLLER] ERROR: in the 'calculateControlOutput' function of the 'PickerControllerService': the 'estimator_method' is not recognised."); + // Display that the "yaml_estimator_method" was not recognised + ROS_INFO_STREAM("[PICKER CONTROLLER] ERROR: in the 'calculateControlOutput' function of the 'PickerControllerService': the 'yaml_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]; + m_current_stateInertialEstimate[i] = m_stateInterialEstimate_viaFiniteDifference[i]; } break; } @@ -730,13 +759,13 @@ void performEstimatorUpdate_forStateInterial(Controller::Request &request) // 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]; + m_previous_xzy_rpy_measurement[0] = m_current_xzy_rpy_measurement[0]; + m_previous_xzy_rpy_measurement[1] = m_current_xzy_rpy_measurement[1]; + m_previous_xzy_rpy_measurement[2] = m_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]; + m_previous_xzy_rpy_measurement[3] = m_current_xzy_rpy_measurement[3]; + m_previous_xzy_rpy_measurement[4] = m_current_xzy_rpy_measurement[4]; + m_previous_xzy_rpy_measurement[5] = m_current_xzy_rpy_measurement[5]; } @@ -745,23 +774,23 @@ 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]; + m_stateInterialEstimate_viaFiniteDifference[0] = m_current_xzy_rpy_measurement[0]; + m_stateInterialEstimate_viaFiniteDifference[1] = m_current_xzy_rpy_measurement[1]; + m_stateInterialEstimate_viaFiniteDifference[2] = m_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]; + m_stateInterialEstimate_viaFiniteDifference[6] = m_current_xzy_rpy_measurement[3]; + m_stateInterialEstimate_viaFiniteDifference[7] = m_current_xzy_rpy_measurement[4]; + m_stateInterialEstimate_viaFiniteDifference[8] = m_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; + m_stateInterialEstimate_viaFiniteDifference[3] = (m_current_xzy_rpy_measurement[0] - m_previous_xzy_rpy_measurement[0]) * m_estimator_frequency; + m_stateInterialEstimate_viaFiniteDifference[4] = (m_current_xzy_rpy_measurement[1] - m_previous_xzy_rpy_measurement[1]) * m_estimator_frequency; + m_stateInterialEstimate_viaFiniteDifference[5] = (m_current_xzy_rpy_measurement[2] - m_previous_xzy_rpy_measurement[2]) * m_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; + m_stateInterialEstimate_viaFiniteDifference[9] = (m_current_xzy_rpy_measurement[3] - m_previous_xzy_rpy_measurement[3]) * m_estimator_frequency; + m_stateInterialEstimate_viaFiniteDifference[10] = (m_current_xzy_rpy_measurement[4] - m_previous_xzy_rpy_measurement[4]) * m_estimator_frequency; + m_stateInterialEstimate_viaFiniteDifference[11] = (m_current_xzy_rpy_measurement[5] - m_previous_xzy_rpy_measurement[5]) * m_estimator_frequency; } @@ -773,28 +802,28 @@ void performEstimatorUpdate_forStateInterial_viaPointMassKalmanFilter() float temp_PMKFstate[12]; for(int i = 0; i < 12; ++i) { - temp_PMKFstate[i] = stateInterialEstimate_viaPointMassKalmanFilter[i]; + temp_PMKFstate[i] = m_stateInterialEstimate_viaPointMassKalmanFilter[i]; } // > Now perform update for: // > x position and velocity: - stateInterialEstimate_viaPointMassKalmanFilter[0] = PMKF_Ahat_row1_for_positions[0]*temp_PMKFstate[0] + PMKF_Ahat_row1_for_positions[1]*temp_PMKFstate[3] + PMKF_Kinf_for_positions[0]*current_xzy_rpy_measurement[0]; - stateInterialEstimate_viaPointMassKalmanFilter[3] = PMKF_Ahat_row2_for_positions[0]*temp_PMKFstate[0] + PMKF_Ahat_row2_for_positions[1]*temp_PMKFstate[3] + PMKF_Kinf_for_positions[1]*current_xzy_rpy_measurement[0]; + m_stateInterialEstimate_viaPointMassKalmanFilter[0] = yaml_PMKF_Ahat_row1_for_positions[0]*temp_PMKFstate[0] + yaml_PMKF_Ahat_row1_for_positions[1]*temp_PMKFstate[3] + yaml_PMKF_Kinf_for_positions[0]*m_current_xzy_rpy_measurement[0]; + m_stateInterialEstimate_viaPointMassKalmanFilter[3] = yaml_PMKF_Ahat_row2_for_positions[0]*temp_PMKFstate[0] + yaml_PMKF_Ahat_row2_for_positions[1]*temp_PMKFstate[3] + yaml_PMKF_Kinf_for_positions[1]*m_current_xzy_rpy_measurement[0]; // > y position and velocity: - stateInterialEstimate_viaPointMassKalmanFilter[1] = PMKF_Ahat_row1_for_positions[0]*temp_PMKFstate[1] + PMKF_Ahat_row1_for_positions[1]*temp_PMKFstate[4] + PMKF_Kinf_for_positions[0]*current_xzy_rpy_measurement[1]; - stateInterialEstimate_viaPointMassKalmanFilter[4] = PMKF_Ahat_row2_for_positions[0]*temp_PMKFstate[1] + PMKF_Ahat_row2_for_positions[1]*temp_PMKFstate[4] + PMKF_Kinf_for_positions[1]*current_xzy_rpy_measurement[1]; + m_stateInterialEstimate_viaPointMassKalmanFilter[1] = yaml_PMKF_Ahat_row1_for_positions[0]*temp_PMKFstate[1] + yaml_PMKF_Ahat_row1_for_positions[1]*temp_PMKFstate[4] + yaml_PMKF_Kinf_for_positions[0]*m_current_xzy_rpy_measurement[1]; + m_stateInterialEstimate_viaPointMassKalmanFilter[4] = yaml_PMKF_Ahat_row2_for_positions[0]*temp_PMKFstate[1] + yaml_PMKF_Ahat_row2_for_positions[1]*temp_PMKFstate[4] + yaml_PMKF_Kinf_for_positions[1]*m_current_xzy_rpy_measurement[1]; // > z position and velocity: - stateInterialEstimate_viaPointMassKalmanFilter[2] = PMKF_Ahat_row1_for_positions[0]*temp_PMKFstate[2] + PMKF_Ahat_row1_for_positions[1]*temp_PMKFstate[5] + PMKF_Kinf_for_positions[0]*current_xzy_rpy_measurement[2]; - stateInterialEstimate_viaPointMassKalmanFilter[5] = PMKF_Ahat_row2_for_positions[0]*temp_PMKFstate[2] + PMKF_Ahat_row2_for_positions[1]*temp_PMKFstate[5] + PMKF_Kinf_for_positions[1]*current_xzy_rpy_measurement[2]; + m_stateInterialEstimate_viaPointMassKalmanFilter[2] = yaml_PMKF_Ahat_row1_for_positions[0]*temp_PMKFstate[2] + yaml_PMKF_Ahat_row1_for_positions[1]*temp_PMKFstate[5] + yaml_PMKF_Kinf_for_positions[0]*m_current_xzy_rpy_measurement[2]; + m_stateInterialEstimate_viaPointMassKalmanFilter[5] = yaml_PMKF_Ahat_row2_for_positions[0]*temp_PMKFstate[2] + yaml_PMKF_Ahat_row2_for_positions[1]*temp_PMKFstate[5] + yaml_PMKF_Kinf_for_positions[1]*m_current_xzy_rpy_measurement[2]; // > roll position and velocity: - stateInterialEstimate_viaPointMassKalmanFilter[6] = PMKF_Ahat_row1_for_angles[0]*temp_PMKFstate[6] + PMKF_Ahat_row1_for_angles[1]*temp_PMKFstate[9] + PMKF_Kinf_for_angles[0]*current_xzy_rpy_measurement[3]; - stateInterialEstimate_viaPointMassKalmanFilter[9] = PMKF_Ahat_row2_for_angles[0]*temp_PMKFstate[6] + PMKF_Ahat_row2_for_angles[1]*temp_PMKFstate[9] + PMKF_Kinf_for_angles[1]*current_xzy_rpy_measurement[3]; + m_stateInterialEstimate_viaPointMassKalmanFilter[6] = yaml_PMKF_Ahat_row1_for_angles[0]*temp_PMKFstate[6] + yaml_PMKF_Ahat_row1_for_angles[1]*temp_PMKFstate[9] + yaml_PMKF_Kinf_for_angles[0]*m_current_xzy_rpy_measurement[3]; + m_stateInterialEstimate_viaPointMassKalmanFilter[9] = yaml_PMKF_Ahat_row2_for_angles[0]*temp_PMKFstate[6] + yaml_PMKF_Ahat_row2_for_angles[1]*temp_PMKFstate[9] + yaml_PMKF_Kinf_for_angles[1]*m_current_xzy_rpy_measurement[3]; // > pitch position and velocity: - stateInterialEstimate_viaPointMassKalmanFilter[7] = PMKF_Ahat_row1_for_angles[0]*temp_PMKFstate[7] + PMKF_Ahat_row1_for_angles[1]*temp_PMKFstate[10] + PMKF_Kinf_for_angles[0]*current_xzy_rpy_measurement[4]; - stateInterialEstimate_viaPointMassKalmanFilter[10] = PMKF_Ahat_row2_for_angles[0]*temp_PMKFstate[7] + PMKF_Ahat_row2_for_angles[1]*temp_PMKFstate[10] + PMKF_Kinf_for_angles[1]*current_xzy_rpy_measurement[4]; + m_stateInterialEstimate_viaPointMassKalmanFilter[7] = yaml_PMKF_Ahat_row1_for_angles[0]*temp_PMKFstate[7] + yaml_PMKF_Ahat_row1_for_angles[1]*temp_PMKFstate[10] + yaml_PMKF_Kinf_for_angles[0]*m_current_xzy_rpy_measurement[4]; + m_stateInterialEstimate_viaPointMassKalmanFilter[10] = yaml_PMKF_Ahat_row2_for_angles[0]*temp_PMKFstate[7] + yaml_PMKF_Ahat_row2_for_angles[1]*temp_PMKFstate[10] + yaml_PMKF_Kinf_for_angles[1]*m_current_xzy_rpy_measurement[4]; // > yaw position and velocity: - stateInterialEstimate_viaPointMassKalmanFilter[8] = PMKF_Ahat_row1_for_angles[0]*temp_PMKFstate[8] + PMKF_Ahat_row1_for_angles[1]*temp_PMKFstate[11] + PMKF_Kinf_for_angles[0]*current_xzy_rpy_measurement[5]; - stateInterialEstimate_viaPointMassKalmanFilter[11] = PMKF_Ahat_row2_for_angles[0]*temp_PMKFstate[8] + PMKF_Ahat_row2_for_angles[1]*temp_PMKFstate[11] + PMKF_Kinf_for_angles[1]*current_xzy_rpy_measurement[5]; + m_stateInterialEstimate_viaPointMassKalmanFilter[8] = yaml_PMKF_Ahat_row1_for_angles[0]*temp_PMKFstate[8] + yaml_PMKF_Ahat_row1_for_angles[1]*temp_PMKFstate[11] + yaml_PMKF_Kinf_for_angles[0]*m_current_xzy_rpy_measurement[5]; + m_stateInterialEstimate_viaPointMassKalmanFilter[11] = yaml_PMKF_Ahat_row2_for_angles[0]*temp_PMKFstate[8] + yaml_PMKF_Ahat_row2_for_angles[1]*temp_PMKFstate[11] + yaml_PMKF_Kinf_for_angles[1]*m_current_xzy_rpy_measurement[5]; } @@ -828,13 +857,13 @@ void calculateControlOutput_viaLQRforRates(float stateErrorBody[12], Controller: for(int i = 0; i < 9; ++i) { // BODY FRAME Y CONTROLLER - rollRate_forResponse -= gainMatrixRollRate[i] * stateErrorBody[i]; + rollRate_forResponse -= yaml_gainMatrixRollRate[i] * stateErrorBody[i]; // BODY FRAME X CONTROLLER - pitchRate_forResponse -= gainMatrixPitchRate[i] * stateErrorBody[i]; + pitchRate_forResponse -= yaml_gainMatrixPitchRate[i] * stateErrorBody[i]; // BODY FRAME YAW CONTROLLER - yawRate_forResponse -= gainMatrixYawRate[i] * stateErrorBody[i]; + yawRate_forResponse -= yaml_gainMatrixYawRate[i] * stateErrorBody[i]; // > ALITUDE CONTROLLER (i.e., z-controller): - thrustAdjustment -= gainMatrixThrust_NineStateVector[i] * stateErrorBody[i]; + thrustAdjustment -= yaml_gainMatrixThrust_NineStateVector[i] * stateErrorBody[i]; } @@ -851,7 +880,7 @@ void calculateControlOutput_viaLQRforRates(float stateErrorBody[12], Controller: // controller needed to be divided by 4 or not. thrustAdjustment = thrustAdjustment / 4.0; // > Compute the feed-forward force - float feed_forward_thrust_per_motor = m_mass_total_grams * 9.81/(1000*4); + float feed_forward_thrust_per_motor = m_weight_total_in_newtons / 4.0; // > Put in the per motor commands response.controlOutput.motorCmd1 = computeMotorPolyBackward(thrustAdjustment + feed_forward_thrust_per_motor); response.controlOutput.motorCmd2 = computeMotorPolyBackward(thrustAdjustment + feed_forward_thrust_per_motor); @@ -867,7 +896,7 @@ void calculateControlOutput_viaLQRforRates(float stateErrorBody[12], Controller: // An alternate debugging technique is to print out data directly to the // command line from which this node was launched. - if (shouldDisplayDebugInfo) + if (yaml_shouldDisplayDebugInfo) { // An example of "printing out" the data from the "request" argument to the // command line. This might be useful for debugging. @@ -886,9 +915,9 @@ void calculateControlOutput_viaLQRforRates(float stateErrorBody[12], Controller: ROS_INFO_STREAM("controlOutput.yaw = " << response.controlOutput.yaw); // An example of "printing out" the "thrust-to-command" conversion parameters. - ROS_INFO_STREAM("motorPoly 0:" << motorPoly[0]); - ROS_INFO_STREAM("motorPoly 0:" << motorPoly[1]); - ROS_INFO_STREAM("motorPoly 0:" << motorPoly[2]); + ROS_INFO_STREAM("motorPoly 0:" << yaml_motorPoly[0]); + ROS_INFO_STREAM("motorPoly 1:" << yaml_motorPoly[1]); + ROS_INFO_STREAM("motorPoly 2:" << yaml_motorPoly[2]); // An example of "printing out" the per motor 16-bit command computed. ROS_INFO_STREAM("controlOutput.cmd1 = " << response.controlOutput.motorCmd1); @@ -939,7 +968,7 @@ void construct_and_publish_debug_message(Controller::Request &request, Controlle // debugMsg.value_10 = your_variable_name; // Publish the "debugMsg" - debugPublisher.publish(debugMsg); + m_debugPublisher.publish(debugMsg); } @@ -959,7 +988,7 @@ void construct_and_publish_debug_message(Controller::Request &request, Controlle void convertIntoBodyFrame(float stateInertial[12], float (&stateBody)[12], float yaw_measured) { - if (shouldPerformConvertIntoBodyFrame) + if (yaml_shouldPerformConvertIntoBodyFrame) { float sinYaw = sin(yaw_measured); float cosYaw = cos(yaw_measured); @@ -1017,17 +1046,18 @@ void convert_stateInertial_to_bodyFrameError(float stateInertial[12], float setp float temp_stateInertial_yaw = stateInertial[8]; // Adjust the INERTIAL (x,y,z) position for the setpoint - stateInertial[0] = stateInertial[0] - setpoint[0] - m_xAdjustment; - stateInertial[1] = stateInertial[1] - setpoint[1] - m_yAdjustment; + stateInertial[0] = stateInertial[0] - setpoint[0]; + stateInertial[1] = stateInertial[1] - setpoint[1]; stateInertial[2] = stateInertial[2] - setpoint[2]; - if (stateInertial[2] > 40.0f) + // Clip the z-coordination to +/-0.40 meters + if (stateInertial[2] > 0.40f) { - stateInertial[2] = 40.0f; + stateInertial[2] = 0.40f; } - else if (stateInertial[2] < -40.0f) + else if (stateInertial[2] < -0.40f) { - stateInertial[2] = -40.0f; + stateInertial[2] = -0.40f; } // Fill in the yaw angle error @@ -1081,16 +1111,16 @@ void convert_stateInertial_to_bodyFrameError(float stateInertial[12], float setp float computeMotorPolyBackward(float thrust) { // 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]); + float cmd = (-yaml_motorPoly[1] + sqrt(yaml_motorPoly[1] * yaml_motorPoly[1] - 4 * yaml_motorPoly[2] * (yaml_motorPoly[0] - thrust))) / (2 * yaml_motorPoly[2]); // Saturate the signal to be 0 or in the range [1000,65000] - if (cmd < cmd_sixteenbit_min) + if (cmd < yaml_cmd_sixteenbit_min) { cmd = 0; } - else if (cmd > cmd_sixteenbit_max) + else if (cmd > yaml_cmd_sixteenbit_max) { - cmd = cmd_sixteenbit_max; + cmd = yaml_cmd_sixteenbit_max; } return cmd; @@ -1113,28 +1143,184 @@ float computeMotorPolyBackward(float thrust) // GGGG UUU III CCCC A A LLLLL LLLLL BBBB A A CCCC K K // ---------------------------------------------------------------------------------- -// This function DOES NOT NEED TO BE edited for successful completion of the PPS exercise -void setpointCallback(const Setpoint& newSetpoint) + +// REQUEST SETPOINT CHANGE CALLBACK +// This function does NOT need to be edited +void requestSetpointChangeCallback(const SetpointWithHeader& newSetpoint) { - m_setpoint[0] = newSetpoint.x; - m_setpoint[1] = newSetpoint.y; - m_setpoint[2] = newSetpoint.z; - m_setpoint[3] = newSetpoint.yaw; + // Check whether the message is relevant + bool isRevelant = checkMessageHeader( m_agentID , newSetpoint.shouldCheckForAgentID , newSetpoint.agentIDs ); + + // Continue if the message is relevant + if (isRevelant) + { + // Check that the ".buttonID" property is + // actually one of the possible states + int button_index = newSetpoint.buttonID; + switch(button_index) + { + case PICKER_STATE_STANDBY: + case PICKER_STATE_GOTO_START: + case PICKER_STATE_ATTACH: + case PICKER_STATE_LIFT_UP: + case PICKER_STATE_GOTO_END: + case PICKER_STATE_PUT_DOWN: + case PICKER_STATE_SQUAT: + case PICKER_STATE_JUMP: + { + // Call the function for actually setting the setpoint + setNewSetpoint( + newSetpoint.buttonID, + newSetpoint.isChecked, + newSetpoint.x, + newSetpoint.y, + newSetpoint.z, + newSetpoint.yaw, + newSetpoint.mass + ); + break; + } + default: + { + // Let the user know that the command was not recognised + ROS_INFO_STREAM("[PICKER CONTROLLER] A button pressed message was received in the controller but not recognised, message.data = " << button_index ); + break; + } + } + + // Call the specific function for each button + switch(button_index) + { + case PICKER_STATE_STANDBY: + { + buttonPressed_standby(); + break; + } + case PICKER_STATE_GOTO_START: + { + buttonPressed_goto_start(); + break; + } + case PICKER_STATE_ATTACH: + { + buttonPressed_attach(); + break; + } + case PICKER_STATE_LIFT_UP: + { + buttonPressed_lift_up(); + break; + } + case PICKER_STATE_GOTO_END: + { + buttonPressed_goto_end(); + break; + } + case PICKER_STATE_PUT_DOWN: + { + buttonPressed_put_down(); + break; + } + case PICKER_STATE_SQUAT: + { + buttonPressed_squat(); + break; + } + case PICKER_STATE_JUMP: + { + buttonPressed_jump(); + break; + } + } + } } -void publishCurrentSetpoint() +// CHANGE SETPOINT FUNCTION +// This function does NOT need to be edited +void setNewSetpoint(int state, bool should_smooth, float x, float y, float z, float yaw, float mass) { - Setpoint msg_setpoint; - msg_setpoint.x = m_setpoint[0]; - msg_setpoint.y = m_setpoint[1]; - msg_setpoint.z = m_setpoint[2]; - msg_setpoint.yaw = m_setpoint[3]; + // Put the state into the class variable + m_picker_current_state = state; + + // Put the smoothing flag in the class variable + m_shouldSmoothSetpointChanges = should_smooth; + + // Put the new setpoint into the class variable + m_setpoint[0] = x; + m_setpoint[1] = y; + m_setpoint[2] = z; + m_setpoint[3] = yaw; + + // Put the mass into the class variable + m_mass_total_in_grams = mass; + m_weight_total_in_newtons = m_mass_total_in_grams * (9.81/1000.0); + + // Publish the change so that the network is updated + // (mainly the "flying agent GUI" is interested in + // displaying this change to the user) + + // Instantiate a local variable of type "SetpointWithHeader" + SetpointWithHeader msg; + // Fill in the setpoint + msg.buttonID = state; + msg.isChecked = should_smooth; + msg.x = x; + msg.y = y; + msg.z = z; + msg.yaw = yaw; + msg.mass = mass; + // Publish the message + m_setpointChangedPublisher.publish(msg); +} - pickerSetpointToGUIPublisher.publish(msg_setpoint); + +// GET CURRENT SETPOINT SERVICE CALLBACK +// This function does NOT need to be edited +bool getCurrentSetpointCallback(GetSetpointService::Request &request, GetSetpointService::Response &response) +{ + // Directly put the current setpoint into the response + response.setpointWithHeader.buttonID = m_picker_current_state; + response.setpointWithHeader.isChecked = m_shouldSmoothSetpointChanges; + response.setpointWithHeader.x = m_setpoint[0]; + response.setpointWithHeader.y = m_setpoint[1]; + response.setpointWithHeader.z = m_setpoint[2]; + response.setpointWithHeader.yaw = m_setpoint[3]; + response.setpointWithHeader.mass = m_mass_total_in_grams; + // Return + return true; } + + + + +// // This function DOES NOT NEED TO BE edited for successful completion of the PPS exercise +// void setpointCallback(const Setpoint& newSetpoint) +// { +// m_setpoint[0] = newSetpoint.x; +// m_setpoint[1] = newSetpoint.y; +// m_setpoint[2] = newSetpoint.z; +// m_setpoint[3] = newSetpoint.yaw; +// } + + +// void publishCurrentSetpoint() +// { +// Setpoint msg_setpoint; +// msg_setpoint.x = m_setpoint[0]; +// msg_setpoint.y = m_setpoint[1]; +// msg_setpoint.z = m_setpoint[2]; +// msg_setpoint.yaw = m_setpoint[3]; + +// pickerSetpointToGUIPublisher.publish(msg_setpoint); +// } + + + + + // ---------------------------------------------------------------------------------- // CCCC U U SSSS TTTTT OOO M M // C U U S T O O MM MM @@ -1150,107 +1336,107 @@ void publishCurrentSetpoint() // ---------------------------------------------------------------------------------- // CUSTOM COMMAND RECEIVED CALLBACK -void buttonPressedCallback(const std_msgs::Int32& msg) -{ - // Extract the data from the message - int button_index = msg.data; - - // Switch between the button pressed - switch(button_index) - { - case PICKER_BUTTON_GOTOSTART: - buttonPressed_gotoStart(); - break; - case PICKER_BUTTON_ATTACH: - buttonPressed_attach(); - break; - case PICKER_BUTTON_PICKUP: - buttonPressed_pickup(); - break; - case PICKER_BUTTON_GOTOEND: - buttonPressed_gotoEnd(); - break; - case PICKER_BUTTON_PUTDOWN: - buttonPressed_putdown(); - break; - case PICKER_BUTTON_SQUAT: - buttonPressed_squat(); - break; - case PICKER_BUTTON_JUMP: - buttonPressed_jump(); - break; - case PICKER_BUTTON_1: - buttonPressed_1(); - break; - case PICKER_BUTTON_2: - buttonPressed_2(); - break; - case PICKER_BUTTON_3: - buttonPressed_3(); - break; - case PICKER_BUTTON_4: - buttonPressed_4(); - break; - default: - { - // Let the user know that the command was not recognised - ROS_INFO_STREAM("[PICKER CONTROLLER] A button pressed message was received in the controller but not recognised, message.data = " << button_index ); - break; - } - } -} - - - -void buttonPressedWithSetpointCallback(const SetpointV2& newSetpointV2) -{ - // Extract the "buttonID" from the message - int button_index = newSetpointV2.buttonID; - - // Switch between the button pressed - switch(button_index) - { - case PICKER_BUTTON_GOTOSTART: - buttonPressedWithSetpoint_gotoStart(newSetpointV2); - break; - case PICKER_BUTTON_ATTACH: - buttonPressedWithSetpoint_attach(newSetpointV2); - break; - case PICKER_BUTTON_PICKUP: - buttonPressedWithSetpoint_pickup(newSetpointV2); - break; - case PICKER_BUTTON_GOTOEND: - buttonPressedWithSetpoint_gotoEnd(newSetpointV2); - break; - case PICKER_BUTTON_PUTDOWN: - buttonPressedWithSetpoint_putdown(newSetpointV2); - break; - case PICKER_BUTTON_SQUAT: - buttonPressedWithSetpoint_squat(newSetpointV2); - break; - case PICKER_BUTTON_JUMP: - buttonPressedWithSetpoint_jump(newSetpointV2); - break; - case PICKER_BUTTON_1: - buttonPressedWithSetpoint_1(newSetpointV2); - break; - case PICKER_BUTTON_2: - buttonPressedWithSetpoint_2(newSetpointV2); - break; - case PICKER_BUTTON_3: - buttonPressedWithSetpoint_3(newSetpointV2); - break; - case PICKER_BUTTON_4: - buttonPressedWithSetpoint_4(newSetpointV2); - break; - default: - { - // Let the user know that the command was not recognised - ROS_INFO_STREAM("[PICKER CONTROLLER] A button pressed message was received in the controller but not recognised, message.data = " << button_index ); - break; - } - } -} +// void buttonPressedCallback(const std_msgs::Int32& msg) +// { +// // Extract the data from the message +// int button_index = msg.data; + +// // Switch between the button pressed +// switch(button_index) +// { +// case PICKER_BUTTON_GOTOSTART: +// buttonPressed_gotoStart(); +// break; +// case PICKER_BUTTON_ATTACH: +// buttonPressed_attach(); +// break; +// case PICKER_BUTTON_PICKUP: +// buttonPressed_pickup(); +// break; +// case PICKER_BUTTON_GOTOEND: +// buttonPressed_gotoEnd(); +// break; +// case PICKER_BUTTON_PUTDOWN: +// buttonPressed_putdown(); +// break; +// case PICKER_BUTTON_SQUAT: +// buttonPressed_squat(); +// break; +// case PICKER_BUTTON_JUMP: +// buttonPressed_jump(); +// break; +// case PICKER_BUTTON_1: +// buttonPressed_1(); +// break; +// case PICKER_BUTTON_2: +// buttonPressed_2(); +// break; +// case PICKER_BUTTON_3: +// buttonPressed_3(); +// break; +// case PICKER_BUTTON_4: +// buttonPressed_4(); +// break; +// default: +// { +// // Let the user know that the command was not recognised +// ROS_INFO_STREAM("[PICKER CONTROLLER] A button pressed message was received in the controller but not recognised, message.data = " << button_index ); +// break; +// } +// } +// } + + + +// void buttonPressedWithSetpointCallback(const SetpointV2& newSetpointV2) +// { +// // Extract the "buttonID" from the message +// int button_index = newSetpointV2.buttonID; + +// // Switch between the button pressed +// switch(button_index) +// { +// case PICKER_BUTTON_GOTOSTART: +// buttonPressedWithSetpoint_gotoStart(newSetpointV2); +// break; +// case PICKER_BUTTON_ATTACH: +// buttonPressedWithSetpoint_attach(newSetpointV2); +// break; +// case PICKER_BUTTON_PICKUP: +// buttonPressedWithSetpoint_pickup(newSetpointV2); +// break; +// case PICKER_BUTTON_GOTOEND: +// buttonPressedWithSetpoint_gotoEnd(newSetpointV2); +// break; +// case PICKER_BUTTON_PUTDOWN: +// buttonPressedWithSetpoint_putdown(newSetpointV2); +// break; +// case PICKER_BUTTON_SQUAT: +// buttonPressedWithSetpoint_squat(newSetpointV2); +// break; +// case PICKER_BUTTON_JUMP: +// buttonPressedWithSetpoint_jump(newSetpointV2); +// break; +// case PICKER_BUTTON_1: +// buttonPressedWithSetpoint_1(newSetpointV2); +// break; +// case PICKER_BUTTON_2: +// buttonPressedWithSetpoint_2(newSetpointV2); +// break; +// case PICKER_BUTTON_3: +// buttonPressedWithSetpoint_3(newSetpointV2); +// break; +// case PICKER_BUTTON_4: +// buttonPressedWithSetpoint_4(newSetpointV2); +// break; +// default: +// { +// // Let the user know that the command was not recognised +// ROS_INFO_STREAM("[PICKER CONTROLLER] A button pressed message was received in the controller but not recognised, message.data = " << button_index ); +// break; +// } +// } +// } @@ -1294,168 +1480,156 @@ void publish_current_xyz_yaw(float x, float y, float z, float yaw) // ---------------------------------------------------------------------------------- -// This function DOES NOT NEED TO BE edited for successful completion of the PPS exercise -void yamlReadyForFetchCallback(const std_msgs::Int32& msg) +// LOADING OF YAML PARAMETERS +void isReadyPickerControllerYamlCallback(const IntWithHeader & msg) { - // Extract from the "msg" for which controller the and from where to fetch the YAML - // parameters - int controller_to_fetch_yaml = msg.data; + // Check whether the message is relevant + bool isRevelant = checkMessageHeader( m_agentID , msg.shouldCheckForID , msg.agentIDs ); - // Switch between fetching for the different controllers and from different locations - switch(controller_to_fetch_yaml) + // Continue if the message is relevant + if (isRevelant) { - - // > FOR FETCHING FROM THE AGENT'S OWN PARAMETER SERVICE - case FETCH_YAML_PICKER_CONTROLLER_FROM_OWN_AGENT: - { - // Let the user know that this message was received - ROS_INFO("[PICKER CONTROLLER] Received the message that YAML parameters were (re-)loaded. > Now fetching the parameter values from this agent."); - // Create a node handle to the parameter service running on this agent's machine - ros::NodeHandle nodeHandle_to_own_agent_parameter_service(namespace_to_own_agent_parameter_service); - // Call the function that fetches the parameters - fetchYamlParameters(nodeHandle_to_own_agent_parameter_service); - break; - } - - // > FOR FETCHING FROM THE COORDINATOR'S PARAMETER SERVICE - case FETCH_YAML_PICKER_CONTROLLER_FROM_COORDINATOR: + // Extract the data + int parameter_service_to_load_from = msg.data; + // Initialise a local variable for the namespace + std::string namespace_to_use; + // Load from the respective parameter service + switch(parameter_service_to_load_from) { - // Let the user know that this message was received - ROS_INFO("[PICKER CONTROLLER] Received the message that YAML parameters were (re-)loaded. > Now fetching the parameter values from the coordinator."); - // Create a node handle to the parameter service running on the coordinator machine - ros::NodeHandle nodeHandle_to_coordinator_parameter_service(namespace_to_coordinator_parameter_service); - // Call the function that fetches the parameters - fetchYamlParameters(nodeHandle_to_coordinator_parameter_service); - break; - } + // > FOR FETCHING FROM THE AGENT'S OWN PARAMETER SERVICE + case LOAD_YAML_FROM_AGENT: + { + ROS_INFO("[PICKER CONTROLLER] Now fetching the PickerController YAML parameter values from this agent."); + namespace_to_use = m_namespace_to_own_agent_parameter_service; + break; + } + // > FOR FETCHING FROM THE COORDINATOR'S PARAMETER SERVICE + case LOAD_YAML_FROM_COORDINATOR: + { + ROS_INFO("[PICKER CONTROLLER] Now fetching the PickerController YAML parameter values from this agent's coordinator."); + namespace_to_use = m_namespace_to_coordinator_parameter_service; + break; + } - default: - { - // Let the user know that the command was not relevant - //ROS_INFO("The PickerControllerService received the message that YAML parameters were (re-)loaded"); - //ROS_INFO("> However the parameters do not relate to this controller, hence nothing will be fetched."); - break; + default: + { + ROS_ERROR("[PICKER CONTROLLER] Paramter service to load from was NOT recognised."); + namespace_to_use = m_namespace_to_own_agent_parameter_service; + break; + } } + // Create a node handle to the selected parameter service + ros::NodeHandle nodeHandle_to_use(namespace_to_use); + // Call the function that fetches the parameters + fetchPickerControllerYamlParameters(nodeHandle_to_use); } } -// This function CAN BE edited for successful completion of the PPS exercise, and the -// use of parameters fetched from the YAML file is highly recommended to make tuning of -// your controller easier and quicker. -void fetchYamlParameters(ros::NodeHandle& nodeHandle) +void fetchPickerControllerYamlParameters(ros::NodeHandle& nodeHandle) { - // Here we load the parameters that are specified in the PickerController.yaml file + // Here we load the parameters that are specified in the file: + // StudentController.yaml // Add the "PickerController" namespace to the "nodeHandle" - ros::NodeHandle nodeHandle_for_pickerController(nodeHandle, "PickerController"); + ros::NodeHandle nodeHandle_for_paramaters(nodeHandle, "PickerController"); + - // > The mass of the crazyflie - m_mass_CF_grams = getParameterFloat(nodeHandle_for_pickerController , "mass_CF"); - // > The mass of the letters - m_mass_E_grams = getParameterFloat(nodeHandle_for_pickerController , "mass_E"); - m_mass_T_grams = getParameterFloat(nodeHandle_for_pickerController , "mass_T"); - m_mass_H_grams = getParameterFloat(nodeHandle_for_pickerController , "mass_H"); + // GET THE PARAMETERS: - // Thickness of the object at pick-up and put-down, in [meters] - // > This should also account for extra height due to the surface where the object is - m_thickness_of_object_at_pickup = getParameterFloat(nodeHandle_for_pickerController , "thickness_of_object_at_pickup"); - m_thickness_of_object_at_putdown = getParameterFloat(nodeHandle_for_pickerController , "thickness_of_object_at_putdown"); + // // // > The mass of the letters + // m_mass_E_grams = getParameterFloat(nodeHandle_for_pickerController , "mass_E"); + // m_mass_T_grams = getParameterFloat(nodeHandle_for_pickerController , "mass_T"); + // m_mass_H_grams = getParameterFloat(nodeHandle_for_pickerController , "mass_H"); - // (x,y) coordinates of the pickup location - getParameterFloatVector(nodeHandle_for_pickerController, "pickup_coordinates_xy", m_pickup_coordinates_xy, 2); + // // Thickness of the object at pick-up and put-down, in [meters] + // // > This should also account for extra height due to the surface where the object is + // m_thickness_of_object_at_pickup = getParameterFloat(nodeHandle_for_pickerController , "thickness_of_object_at_pickup"); + // m_thickness_of_object_at_putdown = getParameterFloat(nodeHandle_for_pickerController , "thickness_of_object_at_putdown"); - // (x,y) coordinates of the drop off location - getParameterFloatVector(nodeHandle_for_pickerController, "dropoff_coordinates_xy_for_E", m_dropoff_coordinates_xy_for_E, 2); - getParameterFloatVector(nodeHandle_for_pickerController, "dropoff_coordinates_xy_for_T", m_dropoff_coordinates_xy_for_T, 2); - getParameterFloatVector(nodeHandle_for_pickerController, "dropoff_coordinates_xy_for_H", m_dropoff_coordinates_xy_for_H, 2); + // // (x,y) coordinates of the pickup location + // getParameterFloatVector(nodeHandle_for_pickerController, "pickup_coordinates_xy", m_pickup_coordinates_xy, 2); - // Length of the string from the Crazyflie to the end of the Picker, in [meters] - m_picker_string_length = getParameterFloat(nodeHandle_for_pickerController , "picker_string_length"); + // // (x,y) coordinates of the drop off location + // getParameterFloatVector(nodeHandle_for_pickerController, "dropoff_coordinates_xy_for_E", m_dropoff_coordinates_xy_for_E, 2); + // getParameterFloatVector(nodeHandle_for_pickerController, "dropoff_coordinates_xy_for_T", m_dropoff_coordinates_xy_for_T, 2); + // getParameterFloatVector(nodeHandle_for_pickerController, "dropoff_coordinates_xy_for_H", m_dropoff_coordinates_xy_for_H, 2); + + // // Length of the string from the Crazyflie to the end of the Picker, in [meters] + // m_picker_string_length = getParameterFloat(nodeHandle_for_pickerController , "picker_string_length"); // Max setpoint change per second - m_max_setpoint_change_per_second_horizontal = getParameterFloat(nodeHandle_for_pickerController , "max_setpoint_change_per_second_horizontal"); - m_max_setpoint_change_per_second_vertical = getParameterFloat(nodeHandle_for_pickerController , "max_setpoint_change_per_second_vertical"); - m_max_setpoint_change_per_second_yaw_degrees = getParameterFloat(nodeHandle_for_pickerController , "max_setpoint_change_per_second_yaw_degrees"); + yaml_max_setpoint_change_per_second_horizontal = getParameterFloat(nodeHandle_for_pickerController , "max_setpoint_change_per_second_horizontal"); + yaml_max_setpoint_change_per_second_vertical = getParameterFloat(nodeHandle_for_pickerController , "max_setpoint_change_per_second_vertical"); + yaml_max_setpoint_change_per_second_yaw_degrees = getParameterFloat(nodeHandle_for_pickerController , "max_setpoint_change_per_second_yaw_degrees"); + + - // THE FOLLOWING PARAMETERS ARE USED FOR THE LOW-LEVEL CONTROLLER + // ------------------------------------------------------ + // PARAMTERS THAT ARE STANDARD FOR A "CONTROLLER SERVICE" - // > The frequency at which the "computeControlOutput" is being called, as determined - // by the frequency at which the Vicon system provides position and attitude data - m_vicon_frequency = getParameterFloat(nodeHandle_for_pickerController, "vicon_frequency"); + // > The mass of the crazyflie + yaml_mass_cf_in_grams = getParameterFloat(nodeHandle_for_pickerController , "mass_cf_in_grams"); // > The frequency at which the "computeControlOutput" is being called, as determined // by the frequency at which the Vicon system provides position and attitude data - control_frequency = getParameterFloat(nodeHandle_for_pickerController, "control_frequency"); + yaml_control_frequency = getParameterFloat(nodeHandle_for_pickerController, "control_frequency"); // > The co-efficients of the quadratic conversation from 16-bit motor command to // thrust force in Newtons - getParameterFloatVector(nodeHandle_for_pickerController, "motorPoly", motorPoly, 3); + getParameterFloatVector(nodeHandle_for_pickerController, "motorPoly", yaml_motorPoly, 3); // > The boolean for whether to execute the convert into body frame function - shouldPerformConvertIntoBodyFrame = getParameterBool(nodeHandle_for_pickerController, "shouldPerformConvertIntoBodyFrame"); + yaml_shouldPerformConvertIntoBodyFrame = getParameterBool(nodeHandle_for_pickerController, "shouldPerformConvertIntoBodyFrame"); - // > The boolean indicating whether the (x,y,z,yaw) of this agent should be published - // or not - shouldPublishCurrent_xyz_yaw = getParameterBool(nodeHandle_for_pickerController, "shouldPublishCurrent_xyz_yaw"); + // // > The boolean indicating whether the (x,y,z,yaw) of this agent should be published + // // or not + // shouldPublishCurrent_xyz_yaw = getParameterBool(nodeHandle_for_pickerController, "shouldPublishCurrent_xyz_yaw"); // Boolean indiciating whether the "Debug Message" of this agent should be published or not - shouldPublishDebugMessage = getParameterBool(nodeHandle_for_pickerController, "shouldPublishDebugMessage"); + yaml_shouldPublishDebugMessage = getParameterBool(nodeHandle_for_pickerController, "shouldPublishDebugMessage"); // Boolean indiciating whether the debugging ROS_INFO_STREAM should be displayed or not - shouldDisplayDebugInfo = getParameterBool(nodeHandle_for_pickerController, "shouldDisplayDebugInfo"); - - - // THE CONTROLLER GAINS: + yaml_shouldDisplayDebugInfo = getParameterBool(nodeHandle_for_pickerController, "shouldDisplayDebugInfo"); // A flag for which estimator to use: - estimator_method = getParameterInt( nodeHandle_for_pickerController , "estimator_method" ); + yaml_estimator_method = getParameterInt( nodeHandle_for_pickerController , "estimator_method" ); // The LQR Controller parameters for "LQR_MODE_RATE" - getParameterFloatVector(nodeHandle_for_pickerController, "gainMatrixThrust_NineStateVector", gainMatrixThrust_NineStateVector, 9); - getParameterFloatVector(nodeHandle_for_pickerController, "gainMatrixRollRate", gainMatrixRollRate, 9); - getParameterFloatVector(nodeHandle_for_pickerController, "gainMatrixPitchRate", gainMatrixPitchRate, 9); - getParameterFloatVector(nodeHandle_for_pickerController, "gainMatrixYawRate", gainMatrixYawRate, 9); + getParameterFloatVector(nodeHandle_for_pickerController, "gainMatrixThrust_NineStateVector", yaml_gainMatrixThrust_NineStateVector, 9); + getParameterFloatVector(nodeHandle_for_pickerController, "gainMatrixRollRate", yaml_gainMatrixRollRate, 9); + getParameterFloatVector(nodeHandle_for_pickerController, "gainMatrixPitchRate", yaml_gainMatrixPitchRate, 9); + getParameterFloatVector(nodeHandle_for_pickerController, "gainMatrixYawRate", yaml_gainMatrixYawRate, 9); // 16-BIT COMMAND LIMITS - cmd_sixteenbit_min = getParameterFloat(nodeHandle_for_pickerController, "command_sixteenbit_min"); - cmd_sixteenbit_max = getParameterFloat(nodeHandle_for_pickerController, "command_sixteenbit_max"); - + yaml_cmd_sixteenbit_min = getParameterFloat(nodeHandle_for_pickerController, "command_sixteenbit_min"); + yaml_cmd_sixteenbit_max = getParameterFloat(nodeHandle_for_pickerController, "command_sixteenbit_max"); // THE POINT MASS KALMAN FILTER (PMKF) GAINS AND ERROR EVOLUATION // > For the (x,y,z) position - getParameterFloatVector(nodeHandle_for_pickerController, "PMKF_Ahat_row1_for_positions", PMKF_Ahat_row1_for_positions, 2); - getParameterFloatVector(nodeHandle_for_pickerController, "PMKF_Ahat_row2_for_positions", PMKF_Ahat_row2_for_positions, 2); - getParameterFloatVector(nodeHandle_for_pickerController, "PMKF_Kinf_for_positions" , PMKF_Kinf_for_positions , 2); + getParameterFloatVector(nodeHandle_for_pickerController, "PMKF_Ahat_row1_for_positions", yaml_PMKF_Ahat_row1_for_positions, 2); + getParameterFloatVector(nodeHandle_for_pickerController, "PMKF_Ahat_row2_for_positions", yaml_PMKF_Ahat_row2_for_positions, 2); + getParameterFloatVector(nodeHandle_for_pickerController, "PMKF_Kinf_for_positions" , yaml_PMKF_Kinf_for_positions , 2); // > For the (roll,pitch,yaw) angles - getParameterFloatVector(nodeHandle_for_pickerController, "PMKF_Ahat_row1_for_angles", PMKF_Ahat_row1_for_angles, 2); - getParameterFloatVector(nodeHandle_for_pickerController, "PMKF_Ahat_row2_for_angles", PMKF_Ahat_row2_for_angles, 2); - getParameterFloatVector(nodeHandle_for_pickerController, "PMKF_Kinf_for_angles" , PMKF_Kinf_for_angles , 2); + getParameterFloatVector(nodeHandle_for_pickerController, "PMKF_Ahat_row1_for_angles", yaml_PMKF_Ahat_row1_for_angles, 2); + getParameterFloatVector(nodeHandle_for_pickerController, "PMKF_Ahat_row2_for_angles", yaml_PMKF_Ahat_row2_for_angles, 2); + getParameterFloatVector(nodeHandle_for_pickerController, "PMKF_Kinf_for_angles" , yaml_PMKF_Kinf_for_angles , 2); // DEBUGGING: Print out one of the parameters that was loaded - ROS_INFO_STREAM("[PICKER CONTROLLER] DEBUGGING: the fetched PickerController/mass_CF = " << m_mass_CF_grams); + ROS_INFO_STREAM("[PICKER CONTROLLER] DEBUGGING: the fetched PickerController/mass_cf_in_grams = " << yaml_mass_cf_in_grams); - // Call the function that computes details an values that are needed from these - // parameters loaded above - processFetchedParameters(); -} - -// This function CAN BE edited for successful completion of the PPS exercise, and the -// use of parameters loaded from the YAML file is highly recommended to make tuning of -// your controller easier and quicker. -void processFetchedParameters() -{ + // PROCESS THE PARAMTERS // Convert from degrees to radians - m_max_setpoint_change_per_second_yaw_radians = DEG2RAD * m_max_setpoint_change_per_second_yaw_degrees; + m_max_setpoint_change_per_second_yaw_radians = DEG2RAD * yaml_max_setpoint_change_per_second_yaw_degrees; // Set that the estimator frequency is the same as the control frequency - estimator_frequency = m_vicon_frequency; -} + m_estimator_frequency = yaml_control_frequency; +} @@ -1468,64 +1642,64 @@ void processFetchedParameters() // ---------------------------------------------------------------------------------- -// This function DOES NOT NEED TO BE edited for successful completion of the PPS exercise -float getParameterFloat(ros::NodeHandle& nodeHandle, std::string name) -{ - float val; - if(!nodeHandle.getParam(name, val)) - { - ROS_ERROR_STREAM("missing parameter '" << name << "'"); - } - return val; -} -// This function DOES NOT NEED TO BE edited for successful completion of the PPS exercise -void getParameterFloatVector(ros::NodeHandle& nodeHandle, std::string name, std::vector<float>& val, int length) -{ - if(!nodeHandle.getParam(name, val)){ - ROS_ERROR_STREAM("missing parameter '" << name << "'"); - } - if(val.size() != length) { - ROS_ERROR_STREAM("parameter '" << name << "' has wrong array length, " << length << " needed"); - } -} -// This function DOES NOT NEED TO BE edited for successful completion of the PPS exercise -int getParameterInt(ros::NodeHandle& nodeHandle, std::string name) -{ - int val; - if(!nodeHandle.getParam(name, val)) - { - ROS_ERROR_STREAM("missing parameter '" << name << "'"); - } - return val; -} -// This function DOES NOT NEED TO BE edited for successful completion of the PPS exercise -void getParameterIntVectorWithKnownLength(ros::NodeHandle& nodeHandle, std::string name, std::vector<int>& val, int length) -{ - if(!nodeHandle.getParam(name, val)){ - ROS_ERROR_STREAM("missing parameter '" << name << "'"); - } - if(val.size() != length) { - ROS_ERROR_STREAM("parameter '" << name << "' has wrong array length, " << length << " needed"); - } -} -// This function DOES NOT NEED TO BE edited for successful completion of the PPS exercise -int getParameterIntVectorWithUnknownLength(ros::NodeHandle& nodeHandle, std::string name, std::vector<int>& val) -{ - if(!nodeHandle.getParam(name, val)){ - ROS_ERROR_STREAM("missing parameter '" << name << "'"); - } - return val.size(); -} -// This function DOES NOT NEED TO BE edited for successful completion of the PPS exercise -bool getParameterBool(ros::NodeHandle& nodeHandle, std::string name) -{ - bool val; - if(!nodeHandle.getParam(name, val)) - { - ROS_ERROR_STREAM("missing parameter '" << name << "'"); - } - return val; -} +// // This function DOES NOT NEED TO BE edited for successful completion of the PPS exercise +// float getParameterFloat(ros::NodeHandle& nodeHandle, std::string name) +// { +// float val; +// if(!nodeHandle.getParam(name, val)) +// { +// ROS_ERROR_STREAM("missing parameter '" << name << "'"); +// } +// return val; +// } +// // This function DOES NOT NEED TO BE edited for successful completion of the PPS exercise +// void getParameterFloatVector(ros::NodeHandle& nodeHandle, std::string name, std::vector<float>& val, int length) +// { +// if(!nodeHandle.getParam(name, val)){ +// ROS_ERROR_STREAM("missing parameter '" << name << "'"); +// } +// if(val.size() != length) { +// ROS_ERROR_STREAM("parameter '" << name << "' has wrong array length, " << length << " needed"); +// } +// } +// // This function DOES NOT NEED TO BE edited for successful completion of the PPS exercise +// int getParameterInt(ros::NodeHandle& nodeHandle, std::string name) +// { +// int val; +// if(!nodeHandle.getParam(name, val)) +// { +// ROS_ERROR_STREAM("missing parameter '" << name << "'"); +// } +// return val; +// } +// // This function DOES NOT NEED TO BE edited for successful completion of the PPS exercise +// void getParameterIntVectorWithKnownLength(ros::NodeHandle& nodeHandle, std::string name, std::vector<int>& val, int length) +// { +// if(!nodeHandle.getParam(name, val)){ +// ROS_ERROR_STREAM("missing parameter '" << name << "'"); +// } +// if(val.size() != length) { +// ROS_ERROR_STREAM("parameter '" << name << "' has wrong array length, " << length << " needed"); +// } +// } +// // This function DOES NOT NEED TO BE edited for successful completion of the PPS exercise +// int getParameterIntVectorWithUnknownLength(ros::NodeHandle& nodeHandle, std::string name, std::vector<int>& val) +// { +// if(!nodeHandle.getParam(name, val)){ +// ROS_ERROR_STREAM("missing parameter '" << name << "'"); +// } +// return val.size(); +// } +// // This function DOES NOT NEED TO BE edited for successful completion of the PPS exercise +// bool getParameterBool(ros::NodeHandle& nodeHandle, std::string name) +// { +// bool val; +// if(!nodeHandle.getParam(name, val)) +// { +// ROS_ERROR_STREAM("missing parameter '" << name << "'"); +// } +// return val; +// } @@ -1546,107 +1720,186 @@ int main(int argc, char* argv[]) { // Starting the ROS-node ros::init(argc, argv, "PickerControllerService"); - // Create a "ros::NodeHandle" type local variable "nodeHandle" as the current node, - // the "~" indcates that "self" is the node handle assigned to this variable. + // Create a "ros::NodeHandle" type local variable "nodeHandle" + // as the current node, the "~" indcates that "self" is the + // node handle assigned to this variable. ros::NodeHandle nodeHandle("~"); // Get the namespace of this "PickerControllerService" node std::string m_namespace = ros::this_node::getNamespace(); ROS_INFO_STREAM("[PICKER CONTROLLER] ros::this_node::getNamespace() = " << m_namespace); - // Get the agent ID as the "ROS_NAMESPACE" this computer. - // NOTES: - // > If you look at the "Student.launch" file in the "launch" folder, you will see - // the following line of code: - // <param name="studentID" value="$(optenv ROS_NAMESPACE)" /> - // This line of code adds a parameter named "studentID" to the "PPSClient" - // > Thus, to get access to this "studentID" paremeter, we first need to get a handle - // to the "PPSClient" node within which this controller service is nested. - - // Get the handle to the "PPSClient" node - ros::NodeHandle PPSClient_nodeHandle(m_namespace + "/PPSClient"); - // Get the value of the "studentID" parameter into the instance variable "my_agentID" - if(!PPSClient_nodeHandle.getParam("agentID", my_agentID)) - { - // Throw an error if the student ID parameter could not be obtained - ROS_ERROR("[PICKER CONTROLLER] Failed to get agentID from PPSClient"); + + + // AGENT ID AND COORDINATOR ID + + // NOTES: + // > If you look at the "Agent.launch" file in the "launch" folder, + // you will see the following line of code: + // <param name="agentID" value="$(optenv ROS_NAMESPACE)" /> + // This line of code adds a parameter named "agentID" to the + // "PPSClient" node. + // > Thus, to get access to this "studentID" paremeter, we first + // need to get a handle to the "PPSClient" node within which this + // controller service is nested. + + + // Get the ID of the agent and its coordinator + bool isValid_IDs = getAgentIDandCoordIDfromClientNode( m_namespace + "/PPSClient" , &m_agentID , &m_coordID); + + // Stall the node IDs are not valid + if ( !isValid_IDs ) + { + ROS_ERROR("[PICKER CONTROLLER] Node NOT FUNCTIONING :-)"); + ros::spin(); + } + else + { + ROS_INFO_STREAM("[PICKER CONTROLLER] loaded agentID = " << m_agentID << ", and coordID = " << m_coordID); } + - // ********************************************************************************* - // EVERYTHING THAT RELATES TO FETCHING PARAMETERS FROM A YAML FILE + // PARAMETER SERVICE NAMESPACE AND NODEHANDLES: + // NOTES: + // > The parameters that are specified thorugh the *.yaml files + // are managed by a separate node called the "Parameter Service" + // > A separate node is used for reasons of speed and generality + // > To allow for a distirbuted architecture, there are two + // "ParamterService" nodes that are relevant: + // 1) the one that is nested under the "m_agentID" namespace + // 2) the one that is nested under the "m_coordID" namespace + // > The following lines of code create the namespace (as strings) + // to there two relevant "ParameterService" nodes. + // > The node handles are also created because they are needed + // for the ROS Subscriptions that follow. - // EVERYTHING FOR THE CONNECTION TO THIS AGENT's OWN PARAMETER SERVICE: + // Set the class variable "m_namespace_to_own_agent_parameter_service", + // i.e., the namespace of parameter service for this agent + m_namespace_to_own_agent_parameter_service = m_namespace + "/ParameterService"; - // Set the class variable "namespace_to_own_agent_parameter_service" to be a the - // namespace string for the parameter service that is running on the machine of this - // agent - namespace_to_own_agent_parameter_service = m_namespace + "/ParameterService"; + // Set the class variable "m_namespace_to_coordinator_parameter_service", + // i.e., the namespace of parameter service for this agent's coordinator + constructNamespaceForCoordinatorParameterService( m_coordID, m_namespace_to_coordinator_parameter_service ); - // Create a node handle to the parameter service running on this agent's machine - ros::NodeHandle nodeHandle_to_own_agent_parameter_service(namespace_to_own_agent_parameter_service); + // Inform the user of what namespaces are being used + ROS_INFO_STREAM("[PICKER CONTROLLER] m_namespace_to_own_agent_parameter_service = " << m_namespace_to_own_agent_parameter_service); + ROS_INFO_STREAM("[PICKER CONTROLLER] m_namespace_to_coordinator_parameter_service = " << m_namespace_to_coordinator_parameter_service); - // Instantiate the local variable "controllerYamlReadyForFetchSubscriber" to be a - // "ros::Subscriber" type variable that subscribes to the "controllerYamlReadyForFetch" topic - // and calls the class function "yamlReadyForFetchCallback" each time a message is - // received on this topic and the message is passed as an input argument to the - // "yamlReadyForFetchCallback" class function. - ros::Subscriber controllerYamlReadyForFetchSubscriber_to_agent = nodeHandle_to_own_agent_parameter_service.subscribe("controllerYamlReadyForFetch", 1, yamlReadyForFetchCallback); + // Create, as local variables, node handles to the parameters services + ros::NodeHandle nodeHandle_to_own_agent_parameter_service(m_namespace_to_own_agent_parameter_service); + ros::NodeHandle nodeHandle_to_coordinator_parameter_service(m_namespace_to_coordinator_parameter_service); + + + + // SUBSCRIBE TO "YAML PARAMTERS READY" MESSAGES + + // The parameter service publishes messages with names of the form: + // /dfall/.../ParameterService/<filename with .yaml extension> + ros::Subscriber pickerContoller_yamlReady_fromAgent = nodeHandle_to_own_agent_parameter_service.subscribe( "PickerController", 1, isReadyStudentControllerYamlCallback); + ros::Subscriber pickerContoller_yamlReady_fromCoord = nodeHandle_to_coordinator_parameter_service.subscribe("PickerController", 1, isReadyStudentControllerYamlCallback); + + + + // GIVE YAML VARIABLES AN INITIAL VALUE + // This can be done either here or as part of declaring the + // variables in the header file + + + + // FETCH ANY PARAMETERS REQUIRED FROM THE "PARAMETER SERVICES" + + // The yaml files for the controllers are not added to + // "Parameter Service" as part of launching. + // The process for loading the yaml parameters is to send a + // service call containing the filename of the *.yaml file, + // and then a message will be received on the above subscribers + // when the paramters are ready. + // > NOTE IMPORTANTLY that by using a serice client + // we stall the availability of this node until the + // paramter service is ready + + // Create the service client as a local variable + ros::ServiceClient requestLoadYamlFilenameServiceClient = nodeHandle_to_own_agent_parameter_service.serviceClient<LoadYamlFromFilename>("requestLoadYamlFilename", false); + // Create the service call as a local variable + LoadYamlFromFilename loadYamlFromFilenameCall; + // Specify the Yaml filename as a string + loadYamlFromFilenameCall.request.stringWithHeader.data = "StudentController"; + // Set for whom this applies to + loadYamlFromFilenameCall.request.stringWithHeader.shouldCheckForID = false; + // Wait until the serivce exists + requestLoadYamlFilenameServiceClient.waitForExistence(ros::Duration(-1)); + // Make the service call + if(requestLoadYamlFilenameServiceClient.call(loadYamlFromFilenameCall)) + { + // Nothing to do in this case. + // The "isReadyStudentControllerYamlCallback" function + // will be called once the YAML file is loaded + } + else + { + // Inform the user + ROS_ERROR("[STUDENT CONTROLLER] The request load yaml file service call failed."); + } - // EVERYTHING FOR THE CONNECTION THE COORDINATOR'S PARAMETER SERVICE: - // Set the class variable "nodeHandle_to_coordinator_parameter_service" to be a node handle - // for the parameter service that is running on the coordinate machine - // NOTE: the backslash here (i.e., "/") before the name of the node ("ParameterService") - // is very important because it specifies that the name is global - namespace_to_coordinator_parameter_service = "/ParameterService"; - // Create a node handle to the parameter service running on the coordinator machine - ros::NodeHandle nodeHandle_to_coordinator = ros::NodeHandle(); - //ros::NodeHandle nodeHandle_to_coordinator_parameter_service = ros::NodeHandle(namespace_to_own_agent_parameter_service); - - // Instantiate the local variable "controllerYamlReadyForFetchSubscriber" to be a - // "ros::Subscriber" type variable that subscribes to the "controllerYamlReadyForFetch" topic - // and calls the class function "yamlReadyForFetchCallback" each time a message is - // received on this topic and the message is passed as an input argument to the - // "yamlReadyForFetchCallback" class function. - ros::Subscriber controllerYamlReadyForFetchSubscriber_to_coordinator = nodeHandle_to_coordinator.subscribe("/ParameterService/controllerYamlReadyForFetch", 1, yamlReadyForFetchCallback); - //ros::Subscriber controllerYamlReadyForFetchSubscriber_to_coordinator = nodeHandle_to_coordinator_parameter_service.subscribe("controllerYamlReadyForFetch", 1, yamlReadyForFetchCallback); + // INITIALISE OTHER VARIABLES AS REQUIRED + m_mass_total_in_grams = yaml_mass_cf_in_grams; + m_weight_total_in_newtons = m_mass_total_in_grams * (9.81/1000.0); - // PRINT OUT SOME INFORMATION - // Let the user know what namespaces are being used for linking to the parameter service - ROS_INFO_STREAM("[PICKER CONTROLLER] the namespace strings for accessing the Paramter Services are:"); - ROS_INFO_STREAM("[PICKER CONTROLLER] namespace_to_own_agent_parameter_service = " << namespace_to_own_agent_parameter_service); - ROS_INFO_STREAM("[PICKER CONTROLLER] namespace_to_coordinator_parameter_service = " << namespace_to_coordinator_parameter_service); - // FINALLY, FETCH ANY PARAMETERS REQUIRED FROM THESE "PARAMETER SERVICES" + // PUBLISHERS AND SUBSCRIBERS - // Call the class function that loads the parameters for this class. - fetchYamlParameters(nodeHandle_to_own_agent_parameter_service); + // Instantiate the class variable "m_debugPublisher" to be a + // "ros::Publisher". This variable advertises under the name + // "DebugTopic" and is a message with the structure defined + // in the file "DebugMsg.msg" (located in the "msg" folder). + m_debugPublisher = nodeHandle.advertise<DebugMsg>("DebugTopic", 1); - // Initialise the total mass to be just the crazyflie - m_mass_total_grams = m_mass_CF_grams; + // Instantiate the local variable "requestSetpointChangeSubscriber" + // to be a "ros::Subscriber" type variable that subscribes to the + // "RequestSetpointChange" topic and calls the class function + // "requestSetpointChangeCallback" each time a messaged is received + // on this topic and the message is passed as an input argument to + // the callback function. This subscriber will mainly receive + // messages from the "flying agent GUI" when the setpoint is changed + // by the user. + ros::Subscriber requestSetpointChangeSubscriber = nodeHandle.subscribe("RequestSetpointChange", 1, requestSetpointChangeCallback); - // ********************************************************************************* + // Same again but instead for changes requested by the coordinator. + // For this we need to first create a node handle to the coordinator: + std::string namespace_to_coordinator; + constructNamespaceForCoordinator( m_coordID, namespace_to_coordinator ); + ros::NodeHandle nodeHandle_to_coordinator(namespace_to_coordinator); + // And now we can instantiate the subscriber: + ros::Subscriber requestSetpointChangeSubscriber_from_coord = nodeHandle_to_coordinator.subscribe("PickerControllerService/RequestSetpointChange", 1, requestSetpointChangeCallback); + // Instantiate the class variable "m_setpointChangedPublisher" to + // be a "ros::Publisher". This variable advertises under the name + // "SetpointChanged" and is a message with the structure defined + // in the file "SetpointWithHeader.msg" (located in the "msg" folder). + // This publisher is used by the "flying agent GUI" to update the + // field that displays the current setpoint for this controller. + m_setpointChangedPublisher = nodeHandle.advertise<SetpointWithHeader>("SetpointChanged", 1); + // Instantiate the local variable "getCurrentSetpointService" to be + // a "ros::ServiceServer" type variable that advertises the service + // called "GetCurrentSetpoint". This service has the input-output + // behaviour defined in the "GetSetpointService.srv" file (located + // in the "srv" folder). This service, when called, is provided with + // an integer (that is essentially ignored), and is expected to respond + // with the current setpoint of the controller. When a request is made + // of this service the "getCurrentSetpointCallback" function is called. + ros::ServiceServer getCurrentSetpointService = nodeHandle.advertiseService("GetCurrentSetpoint", getCurrentSetpointCallback); - // Instantiate the instance variable "debugPublisher" to be a "ros::Publisher" that - // advertises under the name "DebugTopic" and is a message with the structure - // defined in the file "DebugMsg.msg" (located in the "msg" folder). - debugPublisher = nodeHandle.advertise<DebugMsg>("DebugTopic", 1); - // Instantiate the local variable "setpointSubscriber" to be a "ros::Subscriber" - // type variable that subscribes to the "Setpoint" topic and calls the class function - // "setpointCallback" each time a messaged is received on this topic and the message - // is passed as an input argument to the "setpointCallback" class function. - ros::Subscriber setpointSubscriber = nodeHandle.subscribe("Setpoint", 1, setpointCallback); // Instantiate the local variable "service" to be a "ros::ServiceServer" type // variable that advertises the service called "PickerController". This service has @@ -1662,13 +1915,13 @@ int main(int argc, char* argv[]) { // to the name space of this node, i.e., "d_fall_pps" as specified by the line: // "using namespace d_fall_pps;" // in the "DEFINES" section at the top of this file. - ros::NodeHandle namespace_nodeHandle(ros::this_node::getNamespace()); + //ros::NodeHandle namespace_nodeHandle(ros::this_node::getNamespace()); // Instantiate the instance variable "my_current_xyz_yaw_publisher" to be a "ros::Publisher" // that advertises under the name "<my_agentID>/my_current_xyz_yaw_topic" where <my_agentID> // is filled in with the student ID number of this computer. The messages published will // have the structure defined in the file "Setpoint.msg" (located in the "msg" folder). - my_current_xyz_yaw_publisher = nodeHandle.advertise<Setpoint>("my_current_xyz_yaw_topic", 1); + //my_current_xyz_yaw_publisher = nodeHandle.advertise<Setpoint>("my_current_xyz_yaw_topic", 1); // Instantiate the local variable "customCommandSubscriber" to be a "ros::Subscriber" // type variable that subscribes to the "StudentCustomButton" topic and calls the class @@ -1678,17 +1931,17 @@ int main(int argc, char* argv[]) { - // ADDED FOR THE PICKER - ros::Subscriber pickerButtonPressedSubscriber = nodeHandle.subscribe("ButtonPressed", 1, buttonPressedCallback); - ros::Subscriber pickerZSetpointSubscriber = nodeHandle.subscribe("ZSetpoint", 1, zSetpointCallback); - ros::Subscriber pickerYawSetpointSubscriber = nodeHandle.subscribe("YawSetpoint", 1, yawSetpointCallback); - ros::Subscriber pickerMassSubscriber = nodeHandle.subscribe("Mass", 1, massCallback); - ros::Subscriber pickerXAdjustmentSubscriber = nodeHandle.subscribe("XAdjustment", 1, xAdjustmentCallback); - ros::Subscriber pickerYAdjustmentSubscriber = nodeHandle.subscribe("YAdjustment", 1, yAdjustmentCallback); + // // ADDED FOR THE PICKER + // ros::Subscriber pickerButtonPressedSubscriber = nodeHandle.subscribe("ButtonPressed", 1, buttonPressedCallback); + // ros::Subscriber pickerZSetpointSubscriber = nodeHandle.subscribe("ZSetpoint", 1, zSetpointCallback); + // ros::Subscriber pickerYawSetpointSubscriber = nodeHandle.subscribe("YawSetpoint", 1, yawSetpointCallback); + // ros::Subscriber pickerMassSubscriber = nodeHandle.subscribe("Mass", 1, massCallback); + // ros::Subscriber pickerXAdjustmentSubscriber = nodeHandle.subscribe("XAdjustment", 1, xAdjustmentCallback); + // ros::Subscriber pickerYAdjustmentSubscriber = nodeHandle.subscribe("YAdjustment", 1, yAdjustmentCallback); - pickerSetpointToGUIPublisher = nodeHandle.advertise<Setpoint>("SetpointToGUI", 1); + // pickerSetpointToGUIPublisher = nodeHandle.advertise<Setpoint>("SetpointToGUI", 1); - ros::Subscriber pickerButtonPressedWithSetpointSubscriber = nodeHandle.subscribe("ButtonPressedWithSetpoint", 1, buttonPressedWithSetpointCallback); + // ros::Subscriber pickerButtonPressedWithSetpointSubscriber = nodeHandle.subscribe("ButtonPressedWithSetpoint", 1, buttonPressedWithSetpointCallback); diff --git a/pps_ws/src/d_fall_pps/src/nodes/StudentControllerService.cpp b/pps_ws/src/d_fall_pps/src/nodes/StudentControllerService.cpp index c7e22404..426be3b4 100644 --- a/pps_ws/src/d_fall_pps/src/nodes/StudentControllerService.cpp +++ b/pps_ws/src/d_fall_pps/src/nodes/StudentControllerService.cpp @@ -962,7 +962,7 @@ int main(int argc, char* argv[]) { } else { - // Inform the user + // Inform the user ROS_ERROR("[STUDENT CONTROLLER] The request load yaml file service call failed."); } @@ -1011,7 +1011,7 @@ int main(int argc, char* argv[]) { // an integer (that is essentially ignored), and is expected to respond // with the current setpoint of the controller. When a request is made // of this service the "getCurrentSetpointCallback" function is called. - ros::ServiceServer getCurrentSetpointService = nodeHandle.advertiseService("GetCurrentSetpoint", getCurrentSetpointCallback); + ros::ServiceServer getCurrentSetpointService = nodeHandle.advertiseService("GetCurrentSetpoint", getCurrentSetpointCallback); -- GitLab