diff --git a/pps_ws/src/d_fall_pps/CMakeLists.txt b/pps_ws/src/d_fall_pps/CMakeLists.txt
index ea93a9fdffd97cc5736e86fb8e93052040542245..065f356282490ed3a1ae91a0e8d40d6a16dfe2f5 100755
--- a/pps_ws/src/d_fall_pps/CMakeLists.txt
+++ b/pps_ws/src/d_fall_pps/CMakeLists.txt
@@ -270,6 +270,7 @@ add_executable(DemoControllerService    src/nodes/DemoControllerService.cpp)
 add_executable(StudentControllerService src/nodes/StudentControllerService.cpp)
 add_executable(MpcControllerService     src/nodes/MpcControllerService.cpp)
 add_executable(RemoteControllerService  src/nodes/RemoteControllerService.cpp)
+add_executable(TuningControllerService  src/nodes/TuningControllerService.cpp)
 add_executable(CentralManagerService    src/nodes/CentralManagerService.cpp src/CrazyflieIO.cpp)
 add_executable(ParameterService         src/nodes/ParameterService.cpp)
 
@@ -323,6 +324,7 @@ add_dependencies(DemoControllerService    d_fall_pps_generate_messages_cpp ${cat
 add_dependencies(StudentControllerService d_fall_pps_generate_messages_cpp ${catkin_EXPORTED_TARGETS})
 add_dependencies(MpcControllerService     d_fall_pps_generate_messages_cpp ${catkin_EXPORTED_TARGETS})
 add_dependencies(RemoteControllerService  d_fall_pps_generate_messages_cpp ${catkin_EXPORTED_TARGETS})
+add_dependencies(TuningControllerService  d_fall_pps_generate_messages_cpp ${catkin_EXPORTED_TARGETS})
 add_dependencies(CentralManagerService    d_fall_pps_generate_messages_cpp ${catkin_EXPORTED_TARGETS})
 add_dependencies(ParameterService         d_fall_pps_generate_messages_cpp ${catkin_EXPORTED_TARGETS})
 
@@ -364,6 +366,7 @@ else()
   target_link_libraries(MpcControllerService     ${catkin_LIBRARIES})
 endif()
 target_link_libraries(RemoteControllerService  ${catkin_LIBRARIES})
+target_link_libraries(TuningControllerService  ${catkin_LIBRARIES})
 target_link_libraries(CentralManagerService    ${catkin_LIBRARIES})
 target_link_libraries(ParameterService         ${catkin_LIBRARIES})
 
diff --git a/pps_ws/src/d_fall_pps/GUI_Qt/studentGUI/include/MainWindow.h b/pps_ws/src/d_fall_pps/GUI_Qt/studentGUI/include/MainWindow.h
index e8480b3a54822766677e0baef0763626425bc38d..cea18ddcd5dc1c8098df34e4ed5c4211beff7000 100644
--- a/pps_ws/src/d_fall_pps/GUI_Qt/studentGUI/include/MainWindow.h
+++ b/pps_ws/src/d_fall_pps/GUI_Qt/studentGUI/include/MainWindow.h
@@ -52,6 +52,7 @@
 #define STUDENT_CONTROLLER 3
 #define MPC_CONTROLLER     4
 #define REMOTE_CONTROLLER  5
+#define TUNING_CONTROLLER  6
 
 
 // Commands for CrazyRadio
@@ -72,6 +73,7 @@
 #define CMD_USE_STUDENT_CONTROLLER   3
 #define CMD_USE_MPC_CONTROLLER       4
 #define CMD_USE_REMOTE_CONTROLLER    5
+#define CMD_USE_TUNING_CONTROLLER    6
 
 #define CMD_CRAZYFLY_TAKE_OFF        11
 #define CMD_CRAZYFLY_LAND            12
@@ -93,12 +95,14 @@
 #define LOAD_YAML_STUDENT_CONTROLLER_AGENT        3
 #define LOAD_YAML_MPC_CONTROLLER_AGENT            4
 #define LOAD_YAML_REMOTE_CONTROLLER_AGENT         5
+#define LOAD_YAML_TUNING_CONTROLLER_AGENT         6
 
 #define LOAD_YAML_SAFE_CONTROLLER_COORDINATOR     11
 #define LOAD_YAML_DEMO_CONTROLLER_COORDINATOR     12
 #define LOAD_YAML_STUDENT_CONTROLLER_COORDINATOR  13
 #define LOAD_YAML_MPC_CONTROLLER_COORDINATOR      14
 #define LOAD_YAML_REMOTE_CONTROLLER_COORDINATOR   15
+#define LOAD_YAML_TUNING_CONTROLLER_COORDINATOR   16
 
 // Universal constants
 #define PI 3.141592653589
@@ -142,6 +146,7 @@ private slots:
     void on_load_student_yaml_button_clicked();
     void on_load_mpc_yaml_button_clicked();
     void on_load_remote_yaml_button_clicked();
+    void on_load_tuning_yaml_button_clicked();
 
     // # Enable controllers
     void on_enable_safe_controller_clicked();
@@ -149,6 +154,7 @@ private slots:
     void on_enable_student_controller_clicked();
     void on_enable_mpc_controller_clicked();
     void on_enable_remote_controller_clicked();
+    void on_enable_tuning_controller_clicked();
 
     
 
@@ -162,6 +168,15 @@ private slots:
     void on_remote_activate_button_clicked();
     void on_remote_deactivate_button_clicked();
 
+    // Buttons within the TUNING controller tab
+    void on_tuning_test_horizontal_button_clicked();
+    void on_tuning_test_vertical_button_clicked();
+    void on_tuning_test_heading_button_clicked();
+    void on_tuning_test_all_button_clicked();
+    void on_tuning_slider_horizontal_valueChanged(int value);
+    void on_tuning_slider_vertical_valueChanged(int value);
+    void on_tuning_slider_heading_valueChanged(int value);
+
 
 
 private:
@@ -179,6 +194,8 @@ private:
     ros::Timer m_timer_yaml_file_for_student_controller;
     ros::Timer m_timer_yaml_file_for_mpc_controller;
     ros::Timer m_timer_yaml_file_for_remote_controller;
+    ros::Timer m_timer_yaml_file_for_tuning_controller;
+
 
     int m_student_id;
     CrazyflieContext m_context;
@@ -210,6 +227,7 @@ private:
     // > For the MPC Controller SETPOINTS
     ros::Publisher  mpcSetpointPublisher;
     ros::Subscriber mpcSetpointSubscriber;
+
     // > For the Remote Controller subscribe action
     ros::Publisher remoteSubscribePublisher;
     // > For the Remote Controller activate action
@@ -219,6 +237,13 @@ private:
     // > For the Remote Control setpoint
     ros::Subscriber remoteControlSetpointSubscriber;
 
+    // > For the TUNING CONTROLLER "test" button publisher
+    ros::Publisher tuningActivateTestPublisher;
+    // > For the TUNING CONTOLLER "gain" sliders
+    ros::Publisher tuningHorizontalGainPublisher;
+    ros::Publisher tuningVerticalGainPublisher;
+    ros::Publisher tuningHeadingGainPublisher;
+
 
 
     ros::Publisher PPSClientStudentCustomButtonPublisher;
@@ -265,6 +290,7 @@ private:
     void studentYamlFileTimerCallback(const ros::TimerEvent&);
     void mpcYamlFileTimerCallback(const ros::TimerEvent&);
     void remoteYamlFileTimerCallback(const ros::TimerEvent&);
+    void tuningYamlFileTimerCallback(const ros::TimerEvent&);
     
 
 
@@ -290,6 +316,7 @@ private:
     void highlightStudentControllerTab();
     void highlightMpcControllerTab();
     void highlightRemoteControllerTab();
+    void highlightTuningControllerTab();
 
     bool setpointInsideBox(Setpoint setpoint, CrazyflieContext context);
     Setpoint correctSetpointBox(Setpoint setpoint, CrazyflieContext context);
diff --git a/pps_ws/src/d_fall_pps/GUI_Qt/studentGUI/src/MainWindow.cpp b/pps_ws/src/d_fall_pps/GUI_Qt/studentGUI/src/MainWindow.cpp
index dcb30009b620cb1614a2e229c7e75f7d4d060a34..afedd1f4546fb4f3e0e8bacd7ba91f3c068e7261 100644
--- a/pps_ws/src/d_fall_pps/GUI_Qt/studentGUI/src/MainWindow.cpp
+++ b/pps_ws/src/d_fall_pps/GUI_Qt/studentGUI/src/MainWindow.cpp
@@ -89,6 +89,15 @@ MainWindow::MainWindow(int argc, char **argv, QWidget *parent) :
     remoteControlSetpointSubscriber = nodeHandle.subscribe("RemoteControllerService/RemoteControlSetpoint", 1, &MainWindow::remoteControlSetpointCallback, this);;
 
 
+    // > For the TUNING CONTROLLER "test" button publisher
+    tuningActivateTestPublisher = nodeHandle.advertise<std_msgs::Int32>("TuningControllerService/ActivateTest", 1);
+    // > For the TUNING CONTOLLER "gain" sliders
+    tuningHorizontalGainPublisher = nodeHandle.advertise<std_msgs::Int32>("TuningControllerService/HorizontalGain", 1);
+    tuningVerticalGainPublisher = nodeHandle.advertise<std_msgs::Int32>("TuningControllerService/VerticalGain", 1);
+    tuningHeadingGainPublisher = nodeHandle.advertise<std_msgs::Int32>("TuningControllerService/HeadingGain", 1);
+
+
+
     // subscribers
     crazyRadioStatusSubscriber = nodeHandle.subscribe("CrazyRadio/CrazyRadioStatus", 1, &MainWindow::crazyRadioStatusCallback, this);
 
@@ -208,6 +217,7 @@ void MainWindow::highlightSafeControllerTab()
     ui->tabWidget->tabBar()->setTabTextColor(2, Qt::black);
     ui->tabWidget->tabBar()->setTabTextColor(3, Qt::black);
     ui->tabWidget->tabBar()->setTabTextColor(4, Qt::black);
+    ui->tabWidget->tabBar()->setTabTextColor(5, Qt::black);
 }
 void MainWindow::highlightDemoControllerTab()
 {
@@ -216,6 +226,7 @@ void MainWindow::highlightDemoControllerTab()
     ui->tabWidget->tabBar()->setTabTextColor(2, Qt::black);
     ui->tabWidget->tabBar()->setTabTextColor(3, Qt::black);
     ui->tabWidget->tabBar()->setTabTextColor(4, Qt::black);
+    ui->tabWidget->tabBar()->setTabTextColor(5, Qt::black);
 }
 void MainWindow::highlightStudentControllerTab()
 {
@@ -224,6 +235,7 @@ void MainWindow::highlightStudentControllerTab()
     ui->tabWidget->tabBar()->setTabTextColor(2, Qt::green);
     ui->tabWidget->tabBar()->setTabTextColor(3, Qt::black);
     ui->tabWidget->tabBar()->setTabTextColor(4, Qt::black);
+    ui->tabWidget->tabBar()->setTabTextColor(5, Qt::black);
 }
 void MainWindow::highlightMpcControllerTab()
 {
@@ -232,6 +244,7 @@ void MainWindow::highlightMpcControllerTab()
     ui->tabWidget->tabBar()->setTabTextColor(2, Qt::black);
     ui->tabWidget->tabBar()->setTabTextColor(3, Qt::green);
     ui->tabWidget->tabBar()->setTabTextColor(4, Qt::black);
+    ui->tabWidget->tabBar()->setTabTextColor(5, Qt::black);
 }
 void MainWindow::highlightRemoteControllerTab()
 {
@@ -240,6 +253,16 @@ void MainWindow::highlightRemoteControllerTab()
     ui->tabWidget->tabBar()->setTabTextColor(2, Qt::black);
     ui->tabWidget->tabBar()->setTabTextColor(3, Qt::black);
     ui->tabWidget->tabBar()->setTabTextColor(4, Qt::green);
+    ui->tabWidget->tabBar()->setTabTextColor(5, Qt::black);
+}
+void MainWindow::highlightTuningControllerTab()
+{
+    ui->tabWidget->tabBar()->setTabTextColor(0, Qt::black);
+    ui->tabWidget->tabBar()->setTabTextColor(1, Qt::black);
+    ui->tabWidget->tabBar()->setTabTextColor(2, Qt::black);
+    ui->tabWidget->tabBar()->setTabTextColor(3, Qt::black);
+    ui->tabWidget->tabBar()->setTabTextColor(4, Qt::black);
+    ui->tabWidget->tabBar()->setTabTextColor(5, Qt::green);
 }
 
 void MainWindow::DBChangedCallback(const std_msgs::Int32& msg)
@@ -266,6 +289,8 @@ void MainWindow::controllerUsedChangedCallback(const std_msgs::Int32& msg)
             break;
         case REMOTE_CONTROLLER:
             highlightRemoteControllerTab();
+        case TUNING_CONTROLLER:
+            highlightTuningControllerTab();
             break;
         default:
             break;
@@ -868,6 +893,36 @@ void MainWindow::remoteYamlFileTimerCallback(const ros::TimerEvent&)
 
 
 
+void MainWindow::on_load_tuning_yaml_button_clicked()
+{
+    // Set the "load tuning yaml" button to be disabled
+    ui->load_tuning_yaml_button->setEnabled(false);
+
+    // Send a message requesting the parameters from the YAML
+    // file to be reloaded for the tuning controller
+    std_msgs::Int32 msg;
+    msg.data = LOAD_YAML_TUNING_CONTROLLER_AGENT;
+    this->requestLoadControllerYamlPublisher.publish(msg);
+    ROS_INFO("[STUDENT GUI] Request load of tuning controller YAML published");
+
+    // Start a timer which will enable the button in its callback
+    // > This is required because the agent node waits some time between
+    //   re-loading the values from the YAML file and then assigning then
+    //   to the local variable of the agent.
+    // > Thus we use this timer to prevent the user from clicking the
+    //   button in the GUI repeatedly.
+    ros::NodeHandle nodeHandle("~");
+    m_timer_yaml_file_for_tuning_controller = nodeHandle.createTimer(ros::Duration(1.5), &MainWindow::tuningYamlFileTimerCallback, this, true);
+}
+
+void MainWindow::tuningYamlFileTimerCallback(const ros::TimerEvent&)
+{
+    // Enble the "load tuning yaml" button again
+    ui->load_tuning_yaml_button->setEnabled(true);
+}
+
+
+
 void MainWindow::requestLoadControllerYaml_from_my_GUI_Callback(const std_msgs::Int32& msg)
 {
     // Extract from the "msg" for which controller the YAML
@@ -955,6 +1010,21 @@ void MainWindow::requestLoadControllerYaml_from_my_GUI_Callback(const std_msgs::
 
             break;
 
+        case LOAD_YAML_TUNING_CONTROLLER_AGENT:
+        case LOAD_YAML_TUNING_CONTROLLER_COORDINATOR:
+            // Set the "load tuning yaml" button to be disabled
+            ui->load_tuning_yaml_button->setEnabled(false);
+
+            // Start a timer which will enable the button in its callback
+            // > This is required because the agent node waits some time between
+            //   re-loading the values from the YAML file and then assigning then
+            //   to the local variable of the agent.
+            // > Thus we use this timer to prevent the user from clicking the
+            //   button in the GUI repeatedly.
+            m_timer_yaml_file_for_tuning_controller = nodeHandle.createTimer(ros::Duration(1.5), &MainWindow::tuningYamlFileTimerCallback, this, true);    
+
+            break;
+
         default:
             ROS_INFO("Unknown 'all controllers to load yaml' command, thus nothing will be disabled");
             break;
@@ -1001,6 +1071,13 @@ void MainWindow::on_enable_remote_controller_clicked()
     this->PPSClientCommandPublisher.publish(msg);
 }
 
+void MainWindow::on_enable_tuning_controller_clicked()
+{
+    std_msgs::Int32 msg;
+    msg.data = CMD_USE_TUNING_CONTROLLER;
+    this->PPSClientCommandPublisher.publish(msg);
+}
+
 
 
 // # Custom command buttons
@@ -1034,6 +1111,60 @@ void MainWindow::on_customButton_3_clicked()
 
 
 
+Setpoint MainWindow::correctSetpointBox(Setpoint setpoint, CrazyflieContext context)
+{
+    Setpoint corrected_setpoint;
+    corrected_setpoint =  setpoint;
+
+    float x_size = context.localArea.xmax - context.localArea.xmin;
+    float y_size = context.localArea.ymax - context.localArea.ymin;
+    float z_size = context.localArea.zmax - context.localArea.zmin;
+
+    if(setpoint.x > x_size/2)
+        corrected_setpoint.x = x_size/2;
+    if(setpoint.y > y_size/2)
+        corrected_setpoint.y = y_size/2;
+    if(setpoint.z > z_size)
+        corrected_setpoint.z = z_size;
+
+    if(setpoint.x < -x_size/2)
+        corrected_setpoint.x = -x_size/2;
+    if(setpoint.y < -y_size/2)
+        corrected_setpoint.y = -y_size/2;
+    if(setpoint.z < 0)
+        corrected_setpoint.z = 0;
+
+    return corrected_setpoint;
+}
+
+bool MainWindow::setpointInsideBox(Setpoint setpoint, CrazyflieContext context)
+{
+
+    float x_size = context.localArea.xmax - context.localArea.xmin;
+    float y_size = context.localArea.ymax - context.localArea.ymin;
+    float z_size = context.localArea.zmax - context.localArea.zmin;
+    //position check
+	if((setpoint.x < -x_size/2) or (setpoint.x > x_size/2)) {
+		ROS_INFO_STREAM("x outside safety box");
+		return false;
+	}
+	if((setpoint.y < -y_size/2) or (setpoint.y > y_size/2)) {
+		ROS_INFO_STREAM("y outside safety box");
+		return false;
+	}
+	if((setpoint.z < 0) or (setpoint.z > z_size)) {
+		ROS_INFO_STREAM("z outside safety box");
+		return false;
+	}
+
+	return true;
+}
+
+
+
+
+
+
 
 
 // # Custom buttons for the REMOTE controller service
@@ -1127,52 +1258,75 @@ void MainWindow::remoteControlSetpointCallback(const CrazyflieData& setpointData
 
 
 
+// TUNING CONTROLLER TAB
+void MainWindow::on_tuning_test_horizontal_button_clicked()
+{
+	// Initialise the message
+    std_msgs::Int32 msg;
+    // Set the msg data
+    msg.data = 1;
+    // Publish the message
+    this->tuningActivateTestPublisher.publish(msg);
+}
 
-Setpoint MainWindow::correctSetpointBox(Setpoint setpoint, CrazyflieContext context)
+void MainWindow::on_tuning_test_vertical_button_clicked()
 {
-    Setpoint corrected_setpoint;
-    corrected_setpoint =  setpoint;
+	// Initialise the message
+    std_msgs::Int32 msg;
+    // Set the msg data
+    msg.data = 2;
+    // Publish the message
+    this->tuningActivateTestPublisher.publish(msg);
+}
 
-    float x_size = context.localArea.xmax - context.localArea.xmin;
-    float y_size = context.localArea.ymax - context.localArea.ymin;
-    float z_size = context.localArea.zmax - context.localArea.zmin;
+void MainWindow::on_tuning_test_heading_button_clicked()
+{
+	// Initialise the message
+    std_msgs::Int32 msg;
+    // Set the msg data
+    msg.data = 3;
+    // Publish the message
+    this->tuningActivateTestPublisher.publish(msg);
+}
 
-    if(setpoint.x > x_size/2)
-        corrected_setpoint.x = x_size/2;
-    if(setpoint.y > y_size/2)
-        corrected_setpoint.y = y_size/2;
-    if(setpoint.z > z_size)
-        corrected_setpoint.z = z_size;
+void MainWindow::on_tuning_test_all_button_clicked()
+{
+	// Initialise the message
+    std_msgs::Int32 msg;
+    // Set the msg data
+    msg.data = 4;
+    // Publish the message
+    this->tuningActivateTestPublisher.publish(msg);
+}
 
-    if(setpoint.x < -x_size/2)
-        corrected_setpoint.x = -x_size/2;
-    if(setpoint.y < -y_size/2)
-        corrected_setpoint.y = -y_size/2;
-    if(setpoint.z < 0)
-        corrected_setpoint.z = 0;
+void MainWindow::on_tuning_slider_horizontal_valueChanged(int value)
+{
+    // Initialise the message
+    std_msgs::Int32 msg;
+    // Set the msg data
+    msg.data = value;
+    // Publish the message
+    this->tuningHorizontalGainPublisher.publish(msg);
+}
 
-    return corrected_setpoint;
+void MainWindow::on_tuning_slider_vertical_valueChanged(int value)
+{
+    // Initialise the message
+    std_msgs::Int32 msg;
+    // Set the msg data
+    msg.data = value;
+    // Publish the message
+    this->tuningVerticalGainPublisher.publish(msg);
 }
 
-bool MainWindow::setpointInsideBox(Setpoint setpoint, CrazyflieContext context)
+void MainWindow::on_tuning_slider_heading_valueChanged(int value)
 {
+    // Initialise the message
+    std_msgs::Int32 msg;
+    // Set the msg data
+    msg.data = value;
+    // Publish the message
+    this->tuningHeadingGainPublisher.publish(msg);
+}
 
-    float x_size = context.localArea.xmax - context.localArea.xmin;
-    float y_size = context.localArea.ymax - context.localArea.ymin;
-    float z_size = context.localArea.zmax - context.localArea.zmin;
-    //position check
-	if((setpoint.x < -x_size/2) or (setpoint.x > x_size/2)) {
-		ROS_INFO_STREAM("x outside safety box");
-		return false;
-	}
-	if((setpoint.y < -y_size/2) or (setpoint.y > y_size/2)) {
-		ROS_INFO_STREAM("y outside safety box");
-		return false;
-	}
-	if((setpoint.z < 0) or (setpoint.z > z_size)) {
-		ROS_INFO_STREAM("z outside safety box");
-		return false;
-	}
 
-	return true;
-}
diff --git a/pps_ws/src/d_fall_pps/GUI_Qt/studentGUI/src/MainWindow.ui b/pps_ws/src/d_fall_pps/GUI_Qt/studentGUI/src/MainWindow.ui
index 7513dcb809cac1e95ef34c7b436380b82ca8954c..58644b6da549fd7fe991aea8d3f30aa3db945871 100644
--- a/pps_ws/src/d_fall_pps/GUI_Qt/studentGUI/src/MainWindow.ui
+++ b/pps_ws/src/d_fall_pps/GUI_Qt/studentGUI/src/MainWindow.ui
@@ -369,7 +369,7 @@
            </font>
           </property>
           <property name="currentIndex">
-           <number>4</number>
+           <number>5</number>
           </property>
           <property name="usesScrollButtons">
            <bool>true</bool>
@@ -2811,6 +2811,397 @@
             </item>
            </layout>
           </widget>
+          <widget class="QWidget" name="tab">
+           <attribute name="title">
+            <string>Tuning</string>
+           </attribute>
+           <layout class="QGridLayout" name="gridLayout_16">
+            <item row="0" column="0">
+             <layout class="QGridLayout" name="gridLayout_15">
+              <property name="leftMargin">
+               <number>6</number>
+              </property>
+              <property name="topMargin">
+               <number>0</number>
+              </property>
+              <property name="rightMargin">
+               <number>6</number>
+              </property>
+              <property name="bottomMargin">
+               <number>0</number>
+              </property>
+              <item row="4" column="0">
+               <widget class="QLabel" name="label_45">
+                <property name="text">
+                 <string>Vertical Controller Gain</string>
+                </property>
+               </widget>
+              </item>
+              <item row="2" column="0">
+               <widget class="Line" name="line_13">
+                <property name="lineWidth">
+                 <number>5</number>
+                </property>
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+               </widget>
+              </item>
+              <item row="2" column="1">
+               <widget class="Line" name="line_15">
+                <property name="lineWidth">
+                 <number>5</number>
+                </property>
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+               </widget>
+              </item>
+              <item row="11" column="0">
+               <spacer name="verticalSpacer_4">
+                <property name="orientation">
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeType">
+                 <enum>QSizePolicy::Minimum</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>20</width>
+                  <height>10</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item row="1" column="1">
+               <widget class="QPushButton" name="tuning_test_horizontal_button">
+                <property name="sizePolicy">
+                 <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+                  <horstretch>0</horstretch>
+                  <verstretch>0</verstretch>
+                 </sizepolicy>
+                </property>
+                <property name="maximumSize">
+                 <size>
+                  <width>160</width>
+                  <height>50</height>
+                 </size>
+                </property>
+                <property name="text">
+                 <string>Test</string>
+                </property>
+               </widget>
+              </item>
+              <item row="6" column="1">
+               <widget class="Line" name="line_16">
+                <property name="lineWidth">
+                 <number>5</number>
+                </property>
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+               </widget>
+              </item>
+              <item row="8" column="0">
+               <widget class="QLabel" name="label_46">
+                <property name="text">
+                 <string>Heading Controller Gain</string>
+                </property>
+               </widget>
+              </item>
+              <item row="12" column="0">
+               <layout class="QHBoxLayout" name="horizontalLayout_10">
+                <property name="leftMargin">
+                 <number>6</number>
+                </property>
+                <property name="topMargin">
+                 <number>0</number>
+                </property>
+                <property name="rightMargin">
+                 <number>6</number>
+                </property>
+                <property name="bottomMargin">
+                 <number>0</number>
+                </property>
+                <item>
+                 <widget class="QPushButton" name="tuning_test_all_button">
+                  <property name="sizePolicy">
+                   <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+                    <horstretch>0</horstretch>
+                    <verstretch>0</verstretch>
+                   </sizepolicy>
+                  </property>
+                  <property name="minimumSize">
+                   <size>
+                    <width>0</width>
+                    <height>0</height>
+                   </size>
+                  </property>
+                  <property name="maximumSize">
+                   <size>
+                    <width>400</width>
+                    <height>50</height>
+                   </size>
+                  </property>
+                  <property name="text">
+                   <string>Test All</string>
+                  </property>
+                 </widget>
+                </item>
+               </layout>
+              </item>
+              <item row="6" column="0">
+               <widget class="Line" name="line_14">
+                <property name="lineWidth">
+                 <number>5</number>
+                </property>
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+               </widget>
+              </item>
+              <item row="3" column="0">
+               <spacer name="verticalSpacer_5">
+                <property name="orientation">
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeType">
+                 <enum>QSizePolicy::Minimum</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>20</width>
+                  <height>5</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item row="9" column="1">
+               <widget class="QPushButton" name="tuning_test_heading_button">
+                <property name="sizePolicy">
+                 <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+                  <horstretch>0</horstretch>
+                  <verstretch>0</verstretch>
+                 </sizepolicy>
+                </property>
+                <property name="maximumSize">
+                 <size>
+                  <width>160</width>
+                  <height>50</height>
+                 </size>
+                </property>
+                <property name="text">
+                 <string>Test</string>
+                </property>
+               </widget>
+              </item>
+              <item row="0" column="0">
+               <widget class="QLabel" name="label_37">
+                <property name="text">
+                 <string>Horizontal Controller Gain</string>
+                </property>
+                <property name="alignment">
+                 <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+                </property>
+               </widget>
+              </item>
+              <item row="5" column="0">
+               <layout class="QHBoxLayout" name="horizontalLayout_4">
+                <property name="leftMargin">
+                 <number>6</number>
+                </property>
+                <property name="rightMargin">
+                 <number>6</number>
+                </property>
+                <item>
+                 <widget class="QLabel" name="label_39">
+                  <property name="text">
+                   <string>Min</string>
+                  </property>
+                 </widget>
+                </item>
+                <item>
+                 <widget class="QSlider" name="tuning_slider_vertical">
+                  <property name="maximum">
+                   <number>1000</number>
+                  </property>
+                  <property name="value">
+                   <number>100</number>
+                  </property>
+                  <property name="tracking">
+                   <bool>false</bool>
+                  </property>
+                  <property name="orientation">
+                   <enum>Qt::Horizontal</enum>
+                  </property>
+                  <property name="tickPosition">
+                   <enum>QSlider::TicksAbove</enum>
+                  </property>
+                  <property name="tickInterval">
+                   <number>100</number>
+                  </property>
+                 </widget>
+                </item>
+                <item>
+                 <widget class="QLabel" name="label_40">
+                  <property name="text">
+                   <string>Max</string>
+                  </property>
+                 </widget>
+                </item>
+               </layout>
+              </item>
+              <item row="5" column="1">
+               <widget class="QPushButton" name="tuning_test_vertical_button">
+                <property name="sizePolicy">
+                 <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+                  <horstretch>0</horstretch>
+                  <verstretch>0</verstretch>
+                 </sizepolicy>
+                </property>
+                <property name="maximumSize">
+                 <size>
+                  <width>160</width>
+                  <height>50</height>
+                 </size>
+                </property>
+                <property name="text">
+                 <string>Test</string>
+                </property>
+               </widget>
+              </item>
+              <item row="7" column="0">
+               <spacer name="verticalSpacer_6">
+                <property name="orientation">
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeType">
+                 <enum>QSizePolicy::Minimum</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>20</width>
+                  <height>5</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item row="9" column="0">
+               <layout class="QHBoxLayout" name="horizontalLayout_6">
+                <property name="leftMargin">
+                 <number>6</number>
+                </property>
+                <property name="rightMargin">
+                 <number>6</number>
+                </property>
+                <item>
+                 <widget class="QLabel" name="label_41">
+                  <property name="text">
+                   <string>Min</string>
+                  </property>
+                 </widget>
+                </item>
+                <item>
+                 <widget class="QSlider" name="tuning_slider_heading">
+                  <property name="maximum">
+                   <number>1000</number>
+                  </property>
+                  <property name="value">
+                   <number>100</number>
+                  </property>
+                  <property name="tracking">
+                   <bool>false</bool>
+                  </property>
+                  <property name="orientation">
+                   <enum>Qt::Horizontal</enum>
+                  </property>
+                  <property name="tickPosition">
+                   <enum>QSlider::TicksAbove</enum>
+                  </property>
+                  <property name="tickInterval">
+                   <number>100</number>
+                  </property>
+                 </widget>
+                </item>
+                <item>
+                 <widget class="QLabel" name="label_42">
+                  <property name="text">
+                   <string>Max</string>
+                  </property>
+                 </widget>
+                </item>
+               </layout>
+              </item>
+              <item row="1" column="0">
+               <layout class="QHBoxLayout" name="horizontalLayout_7">
+                <property name="leftMargin">
+                 <number>6</number>
+                </property>
+                <property name="rightMargin">
+                 <number>6</number>
+                </property>
+                <item>
+                 <widget class="QLabel" name="label_43">
+                  <property name="text">
+                   <string>Min</string>
+                  </property>
+                 </widget>
+                </item>
+                <item>
+                 <widget class="QSlider" name="tuning_slider_horizontal">
+                  <property name="maximum">
+                   <number>1000</number>
+                  </property>
+                  <property name="value">
+                   <number>100</number>
+                  </property>
+                  <property name="tracking">
+                   <bool>false</bool>
+                  </property>
+                  <property name="orientation">
+                   <enum>Qt::Horizontal</enum>
+                  </property>
+                  <property name="tickPosition">
+                   <enum>QSlider::TicksAbove</enum>
+                  </property>
+                  <property name="tickInterval">
+                   <number>100</number>
+                  </property>
+                 </widget>
+                </item>
+                <item>
+                 <widget class="QLabel" name="label_44">
+                  <property name="text">
+                   <string>Max</string>
+                  </property>
+                 </widget>
+                </item>
+               </layout>
+              </item>
+              <item row="10" column="0">
+               <widget class="Line" name="line_17">
+                <property name="lineWidth">
+                 <number>5</number>
+                </property>
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+               </widget>
+              </item>
+              <item row="10" column="1">
+               <widget class="Line" name="line_18">
+                <property name="lineWidth">
+                 <number>5</number>
+                </property>
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </item>
+           </layout>
+          </widget>
          </widget>
         </item>
         <item>
@@ -2834,6 +3225,30 @@
           <property name="bottomMargin">
            <number>6</number>
           </property>
+          <item row="6" column="2">
+           <widget class="QPushButton" name="load_mpc_yaml_button">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="maximumSize">
+             <size>
+              <width>16777215</width>
+              <height>50</height>
+             </size>
+            </property>
+            <property name="font">
+             <font>
+              <pointsize>14</pointsize>
+             </font>
+            </property>
+            <property name="text">
+             <string>MPC</string>
+            </property>
+           </widget>
+          </item>
           <item row="7" column="2">
            <widget class="QPushButton" name="load_remote_yaml_button">
             <property name="sizePolicy">
@@ -3001,7 +3416,7 @@
             </property>
            </widget>
           </item>
-          <item row="8" column="0">
+          <item row="9" column="0">
            <spacer name="verticalSpacer">
             <property name="orientation">
              <enum>Qt::Vertical</enum>
@@ -3109,36 +3524,36 @@
             </property>
            </widget>
           </item>
-          <item row="3" column="1">
-           <widget class="Line" name="line_3">
+          <item row="4" column="1">
+           <widget class="Line" name="line_4">
             <property name="orientation">
              <enum>Qt::Vertical</enum>
             </property>
            </widget>
           </item>
-          <item row="1" column="1">
-           <widget class="Line" name="line_6">
+          <item row="3" column="1">
+           <widget class="Line" name="line_3">
             <property name="orientation">
              <enum>Qt::Vertical</enum>
             </property>
            </widget>
           </item>
-          <item row="4" column="1">
-           <widget class="Line" name="line_4">
+          <item row="1" column="1">
+           <widget class="Line" name="line_6">
             <property name="orientation">
              <enum>Qt::Vertical</enum>
             </property>
            </widget>
           </item>
-          <item row="8" column="1">
-           <widget class="Line" name="line_5">
+          <item row="0" column="1">
+           <widget class="Line" name="line_7">
             <property name="orientation">
              <enum>Qt::Vertical</enum>
             </property>
            </widget>
           </item>
-          <item row="0" column="1">
-           <widget class="Line" name="line_7">
+          <item row="9" column="1">
+           <widget class="Line" name="line_5">
             <property name="orientation">
              <enum>Qt::Vertical</enum>
             </property>
@@ -3168,14 +3583,20 @@
             </property>
            </widget>
           </item>
-          <item row="6" column="2">
-           <widget class="QPushButton" name="load_mpc_yaml_button">
+          <item row="7" column="0">
+           <widget class="QPushButton" name="enable_remote_controller">
             <property name="sizePolicy">
              <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
               <horstretch>0</horstretch>
               <verstretch>0</verstretch>
              </sizepolicy>
             </property>
+            <property name="minimumSize">
+             <size>
+              <width>0</width>
+              <height>0</height>
+             </size>
+            </property>
             <property name="maximumSize">
              <size>
               <width>16777215</width>
@@ -3188,24 +3609,42 @@
              </font>
             </property>
             <property name="text">
-             <string>MPC</string>
+             <string>Remote</string>
             </property>
            </widget>
           </item>
-          <item row="7" column="0">
-           <widget class="QPushButton" name="enable_remote_controller">
+          <item row="8" column="0">
+           <widget class="QPushButton" name="enable_tuning_controller">
             <property name="sizePolicy">
              <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
               <horstretch>0</horstretch>
               <verstretch>0</verstretch>
              </sizepolicy>
             </property>
-            <property name="minimumSize">
+            <property name="maximumSize">
              <size>
-              <width>0</width>
-              <height>0</height>
+              <width>16777215</width>
+              <height>50</height>
              </size>
             </property>
+            <property name="font">
+             <font>
+              <pointsize>14</pointsize>
+             </font>
+            </property>
+            <property name="text">
+             <string>Tuning</string>
+            </property>
+           </widget>
+          </item>
+          <item row="8" column="2">
+           <widget class="QPushButton" name="load_tuning_yaml_button">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
             <property name="maximumSize">
              <size>
               <width>16777215</width>
@@ -3218,7 +3657,7 @@
              </font>
             </property>
             <property name="text">
-             <string>Remote</string>
+             <string>Tuning</string>
             </property>
            </widget>
           </item>
diff --git a/pps_ws/src/d_fall_pps/include/nodes/PPSClient.h b/pps_ws/src/d_fall_pps/include/nodes/PPSClient.h
index 3a37faf9d1bdafe6e65e9d559b1c4c13696ca09e..82d1be478e0ec7c4f5ee39f13646dfac63520507 100644
--- a/pps_ws/src/d_fall_pps/include/nodes/PPSClient.h
+++ b/pps_ws/src/d_fall_pps/include/nodes/PPSClient.h
@@ -88,6 +88,7 @@
 #define STUDENT_CONTROLLER   3
 #define MPC_CONTROLLER       4
 #define REMOTE_CONTROLLER    5
+#define TUNING_CONTROLLER    6
 
 // The constants that "command" changes in the
 // operation state of this agent
@@ -96,6 +97,8 @@
 #define CMD_USE_STUDENT_CONTROLLER   3
 #define CMD_USE_MPC_CONTROLLER       4
 #define CMD_USE_REMOTE_CONTROLLER    5
+#define CMD_USE_TUNING_CONTROLLER    6
+
 
 #define CMD_CRAZYFLY_TAKE_OFF        11
 #define CMD_CRAZYFLY_LAND            12
@@ -153,6 +156,8 @@ ros::ServiceClient studentController;
 ros::ServiceClient mpcController;
 // The Remote controller specified in the ClientConfig.yaml
 ros::ServiceClient remoteController;
+// The Tuning controller specified in the ClientConfig.yaml
+ros::ServiceClient tuningController;
 
 
 //values for safteyCheck
@@ -297,6 +302,7 @@ void loadDemoController();
 void loadStudentController();
 void loadMpcController();
 void loadRemoteController();
+void loadTuningController();
 
 void sendMessageUsingController(int controller);
 void setInstantController(int controller);
diff --git a/pps_ws/src/d_fall_pps/include/nodes/ParameterServiceDefinitions.h b/pps_ws/src/d_fall_pps/include/nodes/ParameterServiceDefinitions.h
index 7edcebdd65bd87a0b7253d5b9850fb584035f36a..12ef8b42b6c02b580a75bc1864b8002b3eaf7bc1 100644
--- a/pps_ws/src/d_fall_pps/include/nodes/ParameterServiceDefinitions.h
+++ b/pps_ws/src/d_fall_pps/include/nodes/ParameterServiceDefinitions.h
@@ -40,12 +40,14 @@
 #define LOAD_YAML_STUDENT_CONTROLLER_AGENT          3
 #define LOAD_YAML_MPC_CONTROLLER_AGENT              4
 #define LOAD_YAML_REMOTE_CONTROLLER_AGENT           5
+#define LOAD_YAML_TUNING_CONTROLLER_AGENT           6
 
 #define LOAD_YAML_SAFE_CONTROLLER_COORDINATOR       11
 #define LOAD_YAML_DEMO_CONTROLLER_COORDINATOR       12
 #define LOAD_YAML_STUDENT_CONTROLLER_COORDINATOR    13
 #define LOAD_YAML_MPC_CONTROLLER_COORDINATOR        14
 #define LOAD_YAML_REMOTE_CONTROLLER_COORDINATOR     15
+#define LOAD_YAML_TUNING_CONTROLLER_COORDINATOR     16
 
 
 // For sending commands to the controller node informing
@@ -60,9 +62,11 @@
 #define FETCH_YAML_STUDENT_CONTROLLER_FROM_OWN_AGENT   3
 #define FETCH_YAML_MPC_CONTROLLER_FROM_OWN_AGENT       4
 #define FETCH_YAML_REMOTE_CONTROLLER_FROM_OWN_AGENT    5
+#define FETCH_YAML_TUNING_CONTROLLER_FROM_OWN_AGENT    6
 
 #define FETCH_YAML_SAFE_CONTROLLER_FROM_COORDINATOR      11
 #define FETCH_YAML_DEMO_CONTROLLER_FROM_COORDINATOR      12
 #define FETCH_YAML_STUDENT_CONTROLLER_FROM_COORDINATOR   13
 #define FETCH_YAML_MPC_CONTROLLER_FROM_COORDINATOR       14
-#define FETCH_YAML_REMOTE_CONTROLLER_FROM_COORDINATOR    15
\ No newline at end of file
+#define FETCH_YAML_REMOTE_CONTROLLER_FROM_COORDINATOR    15
+#define FETCH_YAML_TUNING_CONTROLLER_FROM_COORDINATOR    16
\ No newline at end of file
diff --git a/pps_ws/src/d_fall_pps/include/nodes/TuningControllerService.h b/pps_ws/src/d_fall_pps/include/nodes/TuningControllerService.h
new file mode 100644
index 0000000000000000000000000000000000000000..71068b101959deb1df1df31f02921e0a1429c7c6
--- /dev/null
+++ b/pps_ws/src/d_fall_pps/include/nodes/TuningControllerService.h
@@ -0,0 +1,452 @@
+//    Copyright (C) 2017, ETH Zurich, D-ITET, Paul Beuchat
+//
+//    This file is part of D-FaLL-System.
+//    
+//    D-FaLL-System is free software: you can redistribute it and/or modify
+//    it under the terms of the GNU General Public License as published by
+//    the Free Software Foundation, either version 3 of the License, or
+//    (at your option) any later version.
+//    
+//    D-FaLL-System is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU General Public License for more details.
+//    
+//    You should have received a copy of the GNU General Public License
+//    along with D-FaLL-System.  If not, see <http://www.gnu.org/licenses/>.
+//    
+//
+//    ----------------------------------------------------------------------------------
+//    DDDD        FFFFF        L     L           SSSS  Y   Y   SSSS  TTTTT  EEEEE  M   M
+//    D   D       F      aaa   L     L          S       Y Y   S        T    E      MM MM
+//    D   D  ---  FFFF  a   a  L     L     ---   SSS     Y     SSS     T    EEE    M M M
+//    D   D       F     a  aa  L     L              S    Y        S    T    E      M   M
+//    DDDD        F      aa a  LLLL  LLLL       SSSS     Y    SSSS     T    EEEEE  M   M
+//
+//
+//    DESCRIPTION:
+//    Place for students to implement their controller
+//
+//    ----------------------------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+//    ----------------------------------------------------------------------------------
+//    III  N   N   CCCC  L      U   U  DDDD   EEEEE   SSSS
+//     I   NN  N  C      L      U   U  D   D  E      S
+//     I   N N N  C      L      U   U  D   D  EEE     SSS
+//     I   N  NN  C      L      U   U  D   D  E          S
+//    III  N   N   CCCC  LLLLL   UUU   DDDD   EEEEE  SSSS
+//    ----------------------------------------------------------------------------------
+
+// These various headers need to be included so that this controller service can be
+// connected with the D-FaLL system.
+
+//some useful libraries
+#include <math.h>
+#include <stdlib.h>
+#include "ros/ros.h"
+#include <ros/package.h>
+
+//the generated structs from the msg-files have to be included
+#include "d_fall_pps/ViconData.h"
+#include "d_fall_pps/Setpoint.h"
+#include "d_fall_pps/ControlCommand.h"
+#include "d_fall_pps/Controller.h"
+#include "d_fall_pps/DebugMsg.h"
+#include "d_fall_pps/CustomButton.h"
+#include "d_fall_pps/ViconSubscribeObjectName.h"
+#include "d_fall_pps/CustomControllerYAML.h"
+
+// Include the Parameter Service shared definitions
+#include "nodes/ParameterServiceDefinitions.h"
+
+#include <std_msgs/Int32.h>
+
+
+
+
+//    ----------------------------------------------------------------------------------
+//    DDDD   EEEEE  FFFFF  III  N   N  EEEEE   SSSS
+//    D   D  E      F       I   NN  N  E      S
+//    D   D  EEE    FFF     I   N N N  EEE     SSS
+//    D   D  E      F       I   N  NN  E          S
+//    DDDD   EEEEE  F      III  N   N  EEEEE  SSSS
+//    ----------------------------------------------------------------------------------
+
+// These constants are defined to make the code more readable and adaptable.
+
+// Universal constants
+#define PI 3.1415926535
+
+// These constants define the modes that can be used for controller the Crazyflie 2.0,
+// the constants defined here need to be in agreement with those defined in the
+// firmware running on the Crazyflie 2.0.
+// The following is a short description about each mode:
+// MOTOR_MODE    In this mode the Crazyflie will apply the requested 16-bit per motor
+//               command directly to each of the motors
+// RATE_MODE     In this mode the Crazyflie will apply the requested 16-bit per motor
+//               command directly to each of the motors, and additionally request the
+//               body frame roll, pitch, and yaw angular rates from the PID rate
+//               controllers implemented in the Crazyflie 2.0 firmware.
+// ANGE_MODE     In this mode the Crazyflie will apply the requested 16-bit per motor
+//               command directly to each of the motors, and additionally request the
+//               body frame roll, pitch, and yaw angles from the PID attitude
+//               controllers implemented in the Crazyflie 2.0 firmware.
+
+#define CF_COMMAND_TYPE_MOTOR   6
+#define CF_COMMAND_TYPE_RATE    7
+#define CF_COMMAND_TYPE_ANGLE   8
+
+
+// These constants define the controller used for computing the response in the
+// "calculateControlOutput" function
+// The following is a short description about each mode:
+//
+// LQR_MODE_MOTOR     LQR controller based on the state vector:
+//                    [position,velocity,angles,angular velocity]
+//                    commands per motor thrusts
+//
+// LQR_MODE_ACTUATOR  LQR controller based on the state vector:
+//                    [position,velocity,angles,angular velocity]
+//                    commands actuators of total force and bodz torques
+//
+// LQR_MODE_RATE      LQR controller based on the state vector:
+//                    [position,velocity,angles]
+//
+// LQR_MODE_ANGLE     LQR controller based on the state vector:
+//                    [position,velocity]
+//
+//#define CONTROLLER_MODE_LQR_MOTOR               1
+//#define CONTROLLER_MODE_LQR_ACTUATOR            2
+#define CONTROLLER_MODE_LQR_RATE                3   // (DEFAULT)
+#define CONTROLLER_MODE_LQR_ANGLE               4
+#define CONTROLLER_MODE_LQR_ANGLE_RATE_NESTED   5
+//#define CONTROLLER_MODE_ANGLE_RESPONSE_TEST     6
+
+
+// These constants define the method used for estimating the Inertial
+// frame state.
+// All methods are run at all times, this flag indicates which estimate
+// is passed onto the controller.
+// The following is a short description about each mode:
+//
+// ESTIMATOR_METHOD_FINITE_DIFFERENCE
+//       Takes the poisition and angles directly as measured,
+//       and estimates the velocities as a finite different to the
+//       previous measurement
+//
+// ESTIMATOR_METHOD_POINT_MASS_PER_DIMENSION
+//       Uses a 2nd order random walk estimator independently for
+//       each of (x,y,z,roll,pitch,yaw)
+//
+// ESTIMATOR_METHOD_QUADROTOR_MODEL_BASED
+//       Uses the model of the quad-rotor and the previous inputs
+//
+#define ESTIMATOR_METHOD_FINITE_DIFFERENCE          1
+#define ESTIMATOR_METHOD_POINT_MASS_PER_DIMENSION   2   // (DEFAULT)
+#define ESTIMATOR_METHOD_QUADROTOR_MODEL_BASED      3
+
+// These constants define the controller used for computing the response in the
+// "calculateControlOutput" function
+// The following is a short description about each mode:
+// LQR_RATE_MODE      LQR controller based on the state vector:
+//                    [position,velocity,angles]
+//
+// LQR_ANGLE_MODE     LQR controller based on the state vector:
+//                    [position,velocity]
+//
+#define LQR_RATE_MODE   1   // (DEFAULT)
+#define LQR_ANGLE_MODE  2
+
+// Namespacing the package
+using namespace d_fall_pps;
+
+
+//    ----------------------------------------------------------------------------------
+//    V   V    A    RRRR   III    A    BBBB   L      EEEEE   SSSS
+//    V   V   A A   R   R   I    A A   B   B  L      E      S
+//    V   V  A   A  RRRR    I   A   A  BBBB   L      EEE     SSS
+//     V V   AAAAA  R  R    I   AAAAA  B   B  L      E          S
+//      V    A   A  R   R  III  A   A  BBBB   LLLLL  EEEEE  SSSS
+//    ----------------------------------------------------------------------------------
+
+
+// ******************************************************************************* //
+// VARIABLES SPECIFIC TO THE TUNING CONTROL FEATURE
+
+// Setpoint for the HORIZONTAL test
+int test_horizontal_currentpoint = 1;
+std::vector<float> test_horizontal_setpoint1 (4,0.0);
+std::vector<float> test_horizontal_setpoint2 (4,0.0);
+
+// Setpoint for the VERTICAL test
+int test_vertical_currentpoint = 1;
+std::vector<float> test_vertical_setpoint1 (4,0.0);
+std::vector<float> test_vertical_setpoint2 (4,0.0);
+
+// Setpoint for the HEADING test
+int test_heading_currentpoint = 1;
+std::vector<float> test_heading_setpoint1 (4,0.0);
+std::vector<float> test_heading_setpoint2 (4,0.0);
+
+// Setpoint for the ALL test
+int test_all_currentpoint = 1;
+std::vector<float> test_all_setpoint1 (4,0.0);
+std::vector<float> test_all_setpoint2 (4,0.0);
+
+
+// LQR Gain matrix for tracking the angle commands from the Crazyflie
+std::vector<float> gainMatrixRollRate_forRemoteControl     (3,0.0);
+std::vector<float> gainMatrixPitchRate_forRemoteControl    (3,0.0);
+std::vector<float> gainMatrixYawRate_forRemoteControl      (3,0.0);
+
+// ******************************************************************************* //
+
+
+
+// VARIABLES FOR SOME "ALMOST CONSTANTS"
+// > Mass of the Crazyflie quad-rotor, in [grams]
+float cf_mass;
+// > Coefficients of the 16-bit command to thrust conversion
+std::vector<float> motorPoly(3);
+// The weight of the Crazyflie in [Newtons], i.e., mg
+float gravity_force;
+// One quarter of the "gravity_force"
+float gravity_force_quarter;
+
+
+
+
+// VARIABLES FOR THE CONTROLLER
+
+// Frequency at which the controller is running
+float vicon_frequency;
+
+// Frequency at which the controller is running
+float control_frequency;
+
+
+// > The setpoints for (x,y,z) position and yaw angle, in that order
+float setpoint[4] = {0.0,0.0,0.4,0.0};
+
+
+
+
+// The controller type to run in the "calculateControlOutput" function
+int controller_mode = CONTROLLER_MODE_LQR_RATE;
+
+// The LQR Controller parameters for "CONTROLLER_MODE_LQR_RATE"
+std::vector<float> gainMatrixThrust_NineStateVector (9,0.0);
+std::vector<float> gainMatrixRollRate               (9,0.0);
+std::vector<float> gainMatrixPitchRate              (9,0.0);
+std::vector<float> gainMatrixYawRate                (9,0.0);
+
+// The LQR Controller parameters for "CONTROLLER_MODE_LQR_ANGLE"
+std::vector<float> gainMatrixThrust_SixStateVector (6,0.0);
+std::vector<float> gainMatrixRollAngle             (6,0.0);
+std::vector<float> gainMatrixPitchAngle            (6,0.0);
+
+// The LQR Controller parameters for "CONTROLLER_MODE_LQR_ANGLE_RATE_NESTED"
+std::vector<float> gainMatrixThrust_SixStateVector_50Hz (6,0.0);
+std::vector<float> gainMatrixRollAngle_50Hz             (6,0.0);
+std::vector<float> gainMatrixPitchAngle_50Hz            (6,0.0);
+
+std::vector<float> gainMatrixRollRate_Nested            (3,0.0);
+std::vector<float> gainMatrixPitchRate_Nested           (3,0.0);
+std::vector<float> gainMatrixYawRate_Nested             (3,0.0);
+
+int   lqr_angleRateNested_counter = 4;
+float lqr_angleRateNested_prev_thrustAdjustment = 0.0;
+float lqr_angleRateNested_prev_rollAngle        = 0.0;
+float lqr_angleRateNested_prev_pitchAngle       = 0.0;
+float lqr_angleRateNested_prev_yawAngle         = 0.0;
+
+
+// The 16-bit command limits
+float cmd_sixteenbit_min;
+float cmd_sixteenbit_max;
+
+
+// VARIABLES FOR THE ESTIMATOR
+
+// Frequency at which the controller is running
+float estimator_frequency;
+
+// > A flag for which estimator to use:
+int estimator_method = ESTIMATOR_METHOD_FINITE_DIFFERENCE;
+// > The current state interial estimate,
+//   for use by the controller
+float current_stateInertialEstimate[12];
+
+// > The measurement of the Crazyflie at the "current" time step,
+//   to avoid confusion
+float current_xzy_rpy_measurement[6];
+
+// > The measurement of the Crazyflie at the "previous" time step,
+//   used for computing finite difference velocities
+float previous_xzy_rpy_measurement[6];
+
+// > The full 12 state estimate maintained by the finite
+//   difference state estimator
+float stateInterialEstimate_viaFiniteDifference[12];
+
+// > The full 12 state estimate maintained by the point mass
+//   kalman filter state estimator
+float stateInterialEstimate_viaPointMassKalmanFilter[12];
+
+// THE POINT MASS KALMAN FILTER (PMKF) GAINS AND ERROR EVOLUATION
+// > For the (x,y,z) position
+std::vector<float> PMKF_Ahat_row1_for_positions (2,0.0);
+std::vector<float> PMKF_Ahat_row2_for_positions (2,0.0);
+std::vector<float> PMKF_Kinf_for_positions      (2,0.0);
+// > For the (roll,pitch,yaw) angles
+std::vector<float> PMKF_Ahat_row1_for_angles    (2,0.0);
+std::vector<float> PMKF_Ahat_row2_for_angles    (2,0.0);
+std::vector<float> PMKF_Kinf_for_angles         (2,0.0);
+
+
+
+// VARIABLES FOR THE NAMESPACES FOR THE PARAMETER SERVICES
+// > For the paramter service of this agent
+std::string namespace_to_own_agent_parameter_service;
+// > For the parameter service of the coordinator
+std::string namespace_to_coordinator_parameter_service;
+
+
+// ROS PUBLISHER FOR SENDING OUT THE DEBUG MESSAGES
+ros::Publisher debugPublisher;
+
+
+// VARIABLES RELATING TO PERFORMING THE CONVERSION INTO BODY FRAME
+
+// Boolean whether to execute the convert into body frame function
+bool 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;
+
+// Boolean indiciating whether the debugging ROS_INFO_STREAM should be displayed or not
+bool shouldDisplayDebugInfo = false;
+
+
+// VARIABLES RELATING TO PUBLISHING CURRENT POSITION AND FOLLOWING ANOTHER AGENT'S
+// POSITION
+
+// The ID of this agent, i.e., the ID of this compute
+int my_agentID = 0;
+
+
+
+
+// RELEVANT NOTES ABOUT THE VARIABLES DECLARE HERE:
+// The "CrazyflieData" type used for the "request" variable is a
+// structure as defined in the file "CrazyflieData.msg" which has the following
+// properties:
+//     string crazyflieName              The name given to the Crazyflie in the Vicon software
+//     float64 x                         The x position of the Crazyflie [metres]
+//     float64 y                         The y position of the Crazyflie [metres]
+//     float64 z                         The z position of the Crazyflie [metres]
+//     float64 roll                      The roll component of the intrinsic Euler angles [radians]
+//     float64 pitch                     The pitch component of the intrinsic Euler angles [radians]
+//     float64 yaw                       The yaw component of the intrinsic Euler angles [radians]
+//     float64 acquiringTime #delta t    The time elapsed since the previous "CrazyflieData" was received [seconds]
+//     bool occluded                     A boolean indicted whether the Crazyflie for visible at the time of this measurement
+
+
+
+
+
+//    ----------------------------------------------------------------------------------
+//    FFFFF  U   U  N   N   CCCC  TTTTT  III   OOO   N   N
+//    F      U   U  NN  N  C        T     I   O   O  NN  N
+//    FFF    U   U  N N N  C        T     I   O   O  N N N
+//    F      U   U  N  NN  C        T     I   O   O  N  NN
+//    F       UUU   N   N   CCCC    T    III   OOO   N   N
+//
+//    PPPP   RRRR    OOO   TTTTT   OOO   TTTTT  Y   Y  PPPP   EEEEE   SSSS
+//    P   P  R   R  O   O    T    O   O    T     Y Y   P   P  E      S
+//    PPPP   RRRR   O   O    T    O   O    T      Y    PPPP   EEE     SSS
+//    P      R  R   O   O    T    O   O    T      Y    P      E          S
+//    P      R   R   OOO     T     OOO     T      Y    P      EEEEE  SSSS
+//    ----------------------------------------------------------------------------------
+
+// These function prototypes are not strictly required for this code to complile, but
+// adding the function prototypes here means the the functions can be written below in
+// any order. If the function prototypes are not included then the function need to
+// written below in an order that ensure each function is implemented before it is
+// called from another function, hence why the "main" function is at the bottom.
+
+// CONTROLLER COMPUTATIONS
+// > The function that is called to "start" all estimation and control computations
+bool calculateControlOutput(Controller::Request &request, Controller::Response &response);
+
+// > 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);
+
+// 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
+void convert_stateInertial_to_bodyFrameError(float stateInertial[12], float setpoint[4], float (&bodyFrameError)[12]);
+
+// TRANSFORMATION OF THE (x,y) INERTIAL FRAME ERROR INTO AN (x,y) BODY FRAME ERROR
+void convertIntoBodyFrame(float stateInertial[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);
+
+
+
+// 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);
+std::string getParameterString(ros::NodeHandle& nodeHandle, std::string name);
+
+void yamlReadyForFetchCallback(const std_msgs::Int32& msg);
+void fetchYamlParameters(ros::NodeHandle& nodeHandle);
+void processFetchedParameters();
+
+
+
+// ******************************************************************************* //
+// FUNCTIONS SPECIFIC TO THE TUNING CONTROL FEATURE
+
+// ACTIVATE THE TESTS
+void activateTestCallback(const std_msgs::Int32& msg);
+// CHANGE THE GAINS
+void horizontalGainCallback(const std_msgs::Int32& msg);
+void verticalGainCallback(const std_msgs::Int32& msg);
+void headingGainCallback(const std_msgs::Int32& msg);
+
+// ******************************************************************************* //
\ No newline at end of file
diff --git a/pps_ws/src/d_fall_pps/param/ClientConfig.yaml b/pps_ws/src/d_fall_pps/param/ClientConfig.yaml
index 73d16618f0566630facb936297788c32a286f929..c525b10152e175be591335bd3bf900015a440cbe 100755
--- a/pps_ws/src/d_fall_pps/param/ClientConfig.yaml
+++ b/pps_ws/src/d_fall_pps/param/ClientConfig.yaml
@@ -3,6 +3,7 @@ demoController:    "DemoControllerService/DemoController"
 studentController: "StudentControllerService/StudentController"
 mpcController:     "MpcControllerService/MpcController"
 remoteController:  "RemoteControllerService/RemoteController"
+tuningController:  "TuningControllerService/TuningController"
 
 strictSafety: false
 angleMargin: 0.6
diff --git a/pps_ws/src/d_fall_pps/param/TuningController.yaml b/pps_ws/src/d_fall_pps/param/TuningController.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c03384f7e9a9d6b40326402bfdbea5d1b571be00
--- /dev/null
+++ b/pps_ws/src/d_fall_pps/param/TuningController.yaml
@@ -0,0 +1,113 @@
+# ***************************************************************************** #
+# PARAMETERS SPECIFIC TO THE REMOTE CONTROL FEATURE
+
+# Setpoint for the HORIZONTAL test
+test_horizontal_setpoint1 : [0.3, 0.0, 0.4, 0.0];
+test_horizontal_setpoint2 : [-0.3, 0.0, 0.4, 0.0];
+
+# Setpoint for the VERTICAL test
+test_vertical_setpoint1 : [0.0, 0.0, 0.4, 0.0];
+test_vertical_setpoint2 : [0.0, 0.0, 0.8, 0.0];
+
+# Setpoint for the HEADING test
+test_heading_setpoint1 : [0.0, 0.0, 0.4, 0.0];
+test_heading_setpoint2 : [0.0, 0.0, 0.4, 1.5];
+
+# Setpoint for the ALL test
+test_all_setpoint1 : [0.3, 0.0, 0.4, 0.0];
+test_all_setpoint2 : [-0.3, 0.0, 0.8, 1.5];
+
+# ***************************************************************************** #
+
+
+
+# Mass of the crazyflie
+mass : 29
+
+# Frequency of the controller, in hertz
+vicon_frequency : 200
+control_frequency : 200
+
+# Quadratic motor regression equation (a0, a1, a2)
+motorPoly : [5.484560e-4, 1.032633e-6, 2.130295e-11]
+
+# Boolean for whether to execute the convert into body frame function
+shouldPerformConvertIntoBodyFrame : true
+
+# Boolean indiciating whether the "Debug Message" of this agent should be published or not
+shouldPublishDebugMessage : false
+
+# Boolean indiciating whether the debugging ROS_INFO_STREAM should be displayed or not
+shouldDisplayDebugInfo : false
+
+
+# A flag for which controller mode to use, defined as:
+# 1 CONTROLLER_MODE_LQR_MOTOR
+#    -  LQR controller based on the state vector: [position,velocity,angles,angular velocity]
+#       commands per motor thrusts
+# 2 CONTROLLER_MODE_LQR_ACTUATOR
+#    -  LQR controller based on the state vector: [position,velocity,angles,angular velocity]
+#       commands actuators of total force and bodz torques
+# 3 CONTROLLER_MODE_LQR_RATE
+#    -  LQR controller based on the state vector: [position,velocity,angles]
+# 4 CONTROLLER_MODE_LQR_ANGLE
+#    -  LQR controller based on the state vector: [position,velocity]
+# 5 CONTROLLER_MODE_LQR_ANGLE_RATE_NESTED
+#    -  LQR Nested angle and rate controller
+# 6 CONTROLLER_MODE_ANGLE_RESPONSE_TEST
+#    -  Swaps between pitch set-points to test angle set-point response time
+#       i.e., this controller test the assumption that "the inner loop is infinitely fast"
+#
+controller_mode : 3
+
+
+# A flag for which estimator to use, defined as:
+# 1  -  Finite Different Method,
+#       Takes the poisition and angles directly as measured,
+#       and estimates the velocities as a finite different to the
+#       previous measurement
+# 2  -  Point Mass Per Dimension Method
+#       Uses a 2nd order random walk estimator independently for
+#       each of (x,y,z,roll,pitch,yaw)
+# 3  -  Quad-rotor Model Based Method
+#       Uses the model of the quad-rotor and the previous inputs
+estimator_method : 1
+
+
+# The LQR Controller parameters for "mode = 3"
+gainMatrixThrust_NineStateVector    :  [ 0.00, 0.00, 0.98, 0.00, 0.00, 0.25, 0.00, 0.00, 0.00]
+gainMatrixRollRate                  :  [ 0.00,-1.80, 0.00, 0.00,-1.38, 0.00, 5.20, 0.00, 0.00]
+gainMatrixPitchRate                 :  [ 1.80, 0.00, 0.00, 1.38, 0.00, 0.00, 0.00, 5.20, 0.00]
+gainMatrixYawRate                   :  [ 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 2.30]
+
+# The LQR Controller parameters for "mode = 4"
+gainMatrixThrust_SixStateVector     :  [ 0.00, 0.00, 0.98, 0.00, 0.00, 0.25]
+gainMatrixRollAngle                 :  [ 0.00,-0.20, 0.00, 0.00,-0.20, 0.00]
+gainMatrixPitchAngle                :  [ 0.20, 0.00, 0.00, 0.20, 0.00, 0.00]
+
+# The LQR Controller parameters for "mode = 5"
+gainMatrixThrust_SixStateVector_50Hz:  [ 0.00, 0.00, 0.82, 0.00, 0.00, 0.22]
+gainMatrixRollAngle_50Hz            :  [ 0.00,-0.31, 0.00, 0.00,-0.25, 0.00]
+gainMatrixPitchAngle_50Hz           :  [ 0.31, 0.00, 0.00, 0.25, 0.00, 0.00]
+
+gainMatrixRollRate_Nested           :  [ 4.00, 0.00, 0.00]
+gainMatrixPitchRate_Nested          :  [ 0.00, 4.00, 0.00]
+gainMatrixYawRate_Nested            :  [ 0.00, 0.00, 2.30]
+
+
+# The max and minimum thrust for a 16-bit command
+command_sixteenbit_min : 1000
+command_sixteenbit_max : 60000
+
+
+# THE POINT MASS KALMAN FILTER (PMKF) GAINS AND ERROR EVOLUATION
+# > For the (x,y,z) position
+PMKF_Ahat_row1_for_positions  :  [  0.6723, 0.0034]
+PMKF_Ahat_row2_for_positions  :  [-12.9648, 0.9352]
+PMKF_Kinf_for_positions       :  [  0.3277,12.9648]
+
+
+# > For the (roll,pitch,yaw) angles
+PMKF_Ahat_row1_for_angles     :  [  0.6954, 0.0035]
+PMKF_Ahat_row2_for_angles     :  [-11.0342, 0.9448]
+PMKF_Kinf_for_angles          :  [  0.3046,11.0342]
diff --git a/pps_ws/src/d_fall_pps/src/nodes/PPSClient.cpp b/pps_ws/src/d_fall_pps/src/nodes/PPSClient.cpp
index e14630c8370ff649fa194c33f2ec846ae9b39684..bebe2e1251ee4b29263b3733aa9807f563798d5d 100755
--- a/pps_ws/src/d_fall_pps/src/nodes/PPSClient.cpp
+++ b/pps_ws/src/d_fall_pps/src/nodes/PPSClient.cpp
@@ -301,6 +301,9 @@ void viconCallback(const ViconData& viconData)
                             case REMOTE_CONTROLLER:
                                 success = remoteController.call(controllerCall);
                                 break;
+                            case TUNING_CONTROLLER:
+                                success = tuningController.call(controllerCall);
+                                break;
                             default:
                                 ROS_ERROR("[PPS CLIENT] the current controller was not recognised");
                                 break;
@@ -457,6 +460,11 @@ void commandCallback(const std_msgs::Int32& commandMsg) {
             setControllerUsed(REMOTE_CONTROLLER);
             break;
 
+        case CMD_USE_TUNING_CONTROLLER:
+            ROS_INFO("[PPS CLIENT] USE_TUNING_CONTROLLER Command received");
+            setControllerUsed(TUNING_CONTROLLER);
+            break;
+
     	case CMD_CRAZYFLY_TAKE_OFF:
             if(flying_state == STATE_MOTORS_OFF)
             {
@@ -832,6 +840,21 @@ void loadRemoteController()
     ROS_INFO_STREAM("[PPS CLIENT] Loaded remote controller " << remoteController.getService());
 }
 
+void loadTuningController()
+{
+    ros::NodeHandle nodeHandle("~");
+
+    std::string tuningControllerName;
+    if(!nodeHandle.getParam("tuningController", tuningControllerName))
+    {
+        ROS_ERROR("[PPS CLIENT] Failed to get tuning controller name");
+        return;
+    }
+
+    tuningController = ros::service::createClient<Controller>(tuningControllerName, true);
+    ROS_INFO_STREAM("[PPS CLIENT] Loaded tuning controller " << tuningController.getService());
+}
+
 void sendMessageUsingController(int controller)
 {
     // send a message in topic for the studentGUI to read it
@@ -861,6 +884,9 @@ void setInstantController(int controller) //for right now, temporal use
         case REMOTE_CONTROLLER:
             loadRemoteController();
             break;
+        case TUNING_CONTROLLER:
+            loadTuningController();
+            break;
         default:
             break;
     }
diff --git a/pps_ws/src/d_fall_pps/src/nodes/ParameterService.cpp b/pps_ws/src/d_fall_pps/src/nodes/ParameterService.cpp
index f3faa81ade9e6632ab46fa4fca10ab11f18a0efa..2fd671074cab9aeb1183dafb56b120be14c1529d 100644
--- a/pps_ws/src/d_fall_pps/src/nodes/ParameterService.cpp
+++ b/pps_ws/src/d_fall_pps/src/nodes/ParameterService.cpp
@@ -150,6 +150,17 @@ void requestLoadControllerYamlCallback(const std_msgs::Int32& msg)
         // Re-load the parameters of the demo controller:
         cmd = "rosparam load " + d_fall_pps_path + "/param/RemoteController.yaml " + m_base_namespace + "/RemoteController";
     }
+    //    ----------------------------------------
+    // FOR THE TUNING CONTROLLER
+    else if (
+        ((controller_to_load_yaml==LOAD_YAML_TUNING_CONTROLLER_COORDINATOR) && (my_type==TYPE_COORDINATOR))
+        ||
+        ((controller_to_load_yaml==LOAD_YAML_TUNING_CONTROLLER_AGENT)       && (my_type==TYPE_AGENT))
+    )
+    {
+        // Re-load the parameters of the demo controller:
+        cmd = "rosparam load " + d_fall_pps_path + "/param/TuningController.yaml " + m_base_namespace + "/TuningController";
+    }
     else
     {
         // Let the user know that the command was not recognised
diff --git a/pps_ws/src/d_fall_pps/src/nodes/TuningControllerService.cpp b/pps_ws/src/d_fall_pps/src/nodes/TuningControllerService.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..815e664b01bf405c6cbfa6c533001c40d9fed648
--- /dev/null
+++ b/pps_ws/src/d_fall_pps/src/nodes/TuningControllerService.cpp
@@ -0,0 +1,1605 @@
+//    Copyright (C) 2017, ETH Zurich, D-ITET, Paul Beuchat
+//
+//    This file is part of D-FaLL-System.
+//    
+//    D-FaLL-System is free software: you can redistribute it and/or modify
+//    it under the terms of the GNU General Public License as published by
+//    the Free Software Foundation, either version 3 of the License, or
+//    (at your option) any later version.
+//    
+//    D-FaLL-System is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU General Public License for more details.
+//    
+//    You should have received a copy of the GNU General Public License
+//    along with D-FaLL-System.  If not, see <http://www.gnu.org/licenses/>.
+//    
+//
+//    ----------------------------------------------------------------------------------
+//    DDDD        FFFFF        L     L           SSSS  Y   Y   SSSS  TTTTT  EEEEE  M   M
+//    D   D       F      aaa   L     L          S       Y Y   S        T    E      MM MM
+//    D   D  ---  FFFF  a   a  L     L     ---   SSS     Y     SSS     T    EEE    M M M
+//    D   D       F     a  aa  L     L              S    Y        S    T    E      M   M
+//    DDDD        F      aa a  LLLL  LLLL       SSSS     Y    SSSS     T    EEEEE  M   M
+//
+//
+//    DESCRIPTION:
+//    Place for students to implement their controller
+//
+//    ----------------------------------------------------------------------------------
+
+
+
+
+
+// INCLUDE THE HEADER
+#include "nodes/TuningControllerService.h"
+
+
+
+
+
+//    ----------------------------------------------------------------------------------
+//    FFFFF  U   U  N   N   CCCC  TTTTT  III   OOO   N   N
+//    F      U   U  NN  N  C        T     I   O   O  NN  N
+//    FFF    U   U  N N N  C        T     I   O   O  N N N
+//    F      U   U  N  NN  C        T     I   O   O  N  NN
+//    F       UUU   N   N   CCCC    T    III   OOO   N   N
+//
+//    III M   M PPPP  L     EEEEE M   M EEEEE N   N TTTTT   A   TTTTT III  OOO  N   N
+//     I  MM MM P   P L     E     MM MM E     NN  N   T    A A    T    I  O   O NN  N
+//     I  M M M PPPP  L     EEE   M M M EEE   N N N   T   A   A   T    I  O   O N N N
+//     I  M   M P     L     E     M   M E     N  NN   T   AAAAA   T    I  O   O N  NN
+//    III M   M P     LLLLL EEEEE M   M EEEEE N   N   T   A   A   T   III  OOO  N   N
+//    ----------------------------------------------------------------------------------
+
+
+
+
+
+//    ------------------------------------------------------------------------------
+//     OOO   U   U  TTTTT  EEEEE  RRRR
+//    O   O  U   U    T    E      R   R
+//    O   O  U   U    T    EEE    RRRR
+//    O   O  U   U    T    E      R  R
+//     OOO    UUU     T    EEEEE  R   R
+//
+//     CCCC   OOO   N   N  TTTTT  RRRR    OOO   L           L       OOO    OOO   PPPP
+//    C      O   O  NN  N    T    R   R  O   O  L           L      O   O  O   O  P   P
+//    C      O   O  N N N    T    RRRR   O   O  L           L      O   O  O   O  PPPP
+//    C      O   O  N  NN    T    R  R   O   O  L           L      O   O  O   O  P
+//     CCCC   OOO   N   N    T    R   R   OOO   LLLLL       LLLLL   OOO    OOO   P
+//    ----------------------------------------------------------------------------------
+
+// This function is the callback that is linked to the "CustomController" service that
+// is advertised in the main function. This must have arguments that match the
+// "input-output" behaviour defined in the "Controller.srv" file (located in the "srv"
+// folder)
+//
+// The arument "request" is a structure provided to this service with the following two
+// properties:
+// request.ownCrazyflie
+// This property is itself a structure of type "CrazyflieData",  which is defined in the
+// file "CrazyflieData.msg", and has the following properties
+// string crazyflieName
+//     float64 x                         The x position of the Crazyflie [metres]
+//     float64 y                         The y position of the Crazyflie [metres]
+//     float64 z                         The z position of the Crazyflie [metres]
+//     float64 roll                      The roll component of the intrinsic Euler angles [radians]
+//     float64 pitch                     The pitch component of the intrinsic Euler angles [radians]
+//     float64 yaw                       The yaw component of the intrinsic Euler angles [radians]
+//     float64 acquiringTime #delta t    The time elapsed since the previous "CrazyflieData" was received [seconds]
+//     bool occluded                     A boolean indicted whether the Crazyflie for visible at the time of this measurement
+// The values in these properties are directly the measurement taken by the Vicon
+// motion capture system of the Crazyflie that is to be controlled by this service
+//
+// request.otherCrazyflies
+// This property is an array of "CrazyflieData" structures, what allows access to the
+// Vicon measurements of other Crazyflies.
+//
+// The argument "response" is a structure that is expected to be filled in by this
+// service by this function, it has only the following property
+// response.ControlCommand
+// This property is iteself a structure of type "ControlCommand", which is defined in
+// the file "ControlCommand.msg", and has the following properties:
+//     float32 roll                      The command sent to the Crazyflie for the body frame x-axis
+//     float32 pitch                     The command sent to the Crazyflie for the body frame y-axis
+//     float32 yaw                       The command sent to the Crazyflie for the body frame z-axis
+//     uint16 motorCmd1                  The command sent to the Crazyflie for motor 1
+//     uint16 motorCmd2                  The command sent to the Crazyflie for motor 1
+//     uint16 motorCmd3                  The command sent to the Crazyflie for motor 1
+//     uint16 motorCmd4                  The command sent to the Crazyflie for motor 1
+//     uint8 onboardControllerType       The flag sent to the Crazyflie for indicating how to implement the command
+// 
+// IMPORTANT NOTES FOR "onboardControllerType"  AND AXIS CONVENTIONS
+// > The allowed values for "onboardControllerType" are in the "Defines" section at the
+//   top of this file, they are MOTOR_MODE, RATE_MODE, OR ANGLE_MODE.
+// > In the PPS exercise we will only use the RATE_MODE.
+// > In RATE_MODE the ".roll", ".ptich", and ".yaw" properties of "response.ControlCommand"
+//   specify the angular rate in [radians/second] that will be requested from the
+//   PID controllers running in the Crazyflie 2.0 firmware.
+// > In RATE_MODE the ".motorCmd1" to ".motorCmd4" properties of "response.ControlCommand"
+//   are the baseline motor commands requested from the Crazyflie, with the adjustment
+//   for body rates being added on top of this in the firmware (i.e., as per the code
+//   of the "distribute_power" function provided in exercise sheet 2).
+// > In RATE_MODE the axis convention for the roll, pitch, and yaw body rates returned
+//   in "response.ControlCommand" should use right-hand coordinate axes with x-forward
+//   and z-upwards (i.e., the positive z-axis is aligned with the direction of positive
+//   thrust). To assist, teh following is an ASCII art of this convention:
+//
+// ASCII ART OF THE CRAZYFLIE 2.0 LAYOUT
+//
+//  > This is a top view,
+//  > M1 to M4 stand for Motor 1 to Motor 4,
+//  > "CW"  indicates that the motor rotates Clockwise,
+//  > "CCW" indicates that the motor rotates Counter-Clockwise,
+//  > By right-hand axis convention, the positive z-direction points our of the screen,
+//  > This being a "top view" means tha the direction of positive thrust produced
+//    by the propellers is also out of the screen.
+//
+//        ____                         ____
+//       /    \                       /    \
+//  (CW) | M4 |           x           | M1 | (CCW)
+//       \____/\          ^          /\____/
+//            \ \         |         / /
+//             \ \        |        / /
+//              \ \______ | ______/ /
+//               \        |        /
+//                |       |       |
+//        y <-------------o       |
+//                |               |
+//               / _______________ \
+//              / /               \ \
+//             / /                 \ \
+//        ____/ /                   \ \____
+//       /    \/                     \/    \
+// (CCW) | M3 |                       | M2 | (CW)
+//       \____/                       \____/
+//
+//
+//
+// This function WILL NEED TO BE edited for successful completion of the PPS exercise
+
+
+
+bool calculateControlOutput(Controller::Request &request, Controller::Response &response)
+{
+
+	// THIS IS THE START OF THE "OUTER" CONTROL LOOP
+	// > i.e., this is the control loop run on this laptop
+	// > this function is called at the frequency specified
+	// > this function performs all estimation and control
+
+
+	// PERFORM THE ESTIMATOR UPDATE FOR THE INTERIAL FRAME STATE
+	// > After this function is complete the class variable
+	//   "current_stateInertialEstimate" is updated and ready
+	//   to be used for subsequent controller copmutations
+	performEstimatorUpdate_forStateInterial(request);
+
+	
+	// CONVERT THE CURRENT INERTIAL FRAME STATE ESTIMATE, INTO
+	// THE BODY FRAME ERROR REQUIRED BY THE CONTROLLER
+	// > Define a local array to fill in with the body frame error
+	float current_bodyFrameError[12];
+	// > Call the function to perform the conversion
+	convert_stateInertial_to_bodyFrameError(current_stateInertialEstimate,setpoint,current_bodyFrameError);
+
+	
+	// CARRY OUT THE CONTROLLER COMPUTATIONS
+	calculateControlOutput_viaLQR(current_bodyFrameError,request,response);
+
+
+	// PUBLISH THE DEBUG MESSAGE (if required)
+	if (shouldPublishDebugMessage)
+	{
+		construct_and_publish_debug_message(request,response);
+	}
+
+    // Return "true" to indicate that the control computation was performed successfully
+    return true;
+}
+
+
+
+
+
+//    ----------------------------------------------------------------------------------
+//    RRRR   EEEEE  M   M   OOO   TTTTT  EEEEE
+//    R   R  E      MM MM  O   O    T    E
+//    RRRR   EEE    M M M  O   O    T    EEE
+//    R  R   E      M   M  O   O    T    E
+//    R   R  EEEEE  M   M   OOO     T    EEEEE
+//    
+//     CCCC   OOO   N   N  TTTTT  RRRR    OOO   L
+//    C      O   O  NN  N    T    R   R  O   O  L
+//    C      O   O  N N N    T    RRRR   O   O  L
+//    C      O   O  N  NN    T    R  R   O   O  L
+//     CCCC   OOO   N   N    T    R   R   OOO   LLLLL
+//    ----------------------------------------------------------------------------------
+
+
+// ACTIVATE THE TESTS
+void activateTestCallback(const std_msgs::Int32& msg)
+{
+
+	// Get the test index from the message
+	int test_index = msg.data;
+
+	switch (test_index)
+	{
+		// Test the HORIZONTAL controller
+		case 1:
+		{
+			switch (test_horizontal_currentpoint)
+			{
+				// Currently at setpoint 1 => change to setpoint 2
+				case 1:
+				{
+					setpoint[0] = test_horizontal_setpoint2[0];
+					setpoint[1] = test_horizontal_setpoint2[1];
+					setpoint[2] = test_horizontal_setpoint2[2];
+					setpoint[3] = test_horizontal_setpoint2[3];
+					test_horizontal_currentpoint = 2;
+					break;
+				}
+				// Currently at setpoint 2 => change to setpoint 1
+				case 2:
+				{
+					setpoint[0] = test_horizontal_setpoint1[0];
+					setpoint[1] = test_horizontal_setpoint1[1];
+					setpoint[2] = test_horizontal_setpoint1[2];
+					setpoint[3] = test_horizontal_setpoint1[3];
+					test_horizontal_currentpoint = 1;	
+					break;
+				}
+				// Handle the exception
+				default:
+				{
+					// Display that the "estimator_method" was not recognised
+					ROS_INFO_STREAM("[TUNING CONTROLLER] ERROR: in the 'activateTestCallback' function of the 'TuningControllerService': the 'test_horizontal_currentpoint' is not recognised.");
+					break;
+				}
+			}
+			break;
+		}
+
+
+		// Test the VERTICAL controller
+		case 2:
+		{
+			switch (test_vertical_currentpoint)
+			{
+				// Currently at setpoint 1 => change to setpoint 2
+				case 1:
+				{
+					setpoint[0] = test_vertical_setpoint2[0];
+					setpoint[1] = test_vertical_setpoint2[1];
+					setpoint[2] = test_vertical_setpoint2[2];
+					setpoint[3] = test_vertical_setpoint2[3];
+					test_vertical_currentpoint = 2;
+					break;
+				}
+				// Currently at setpoint 2 => change to setpoint 1
+				case 2:
+				{
+					setpoint[0] = test_vertical_setpoint1[0];
+					setpoint[1] = test_vertical_setpoint1[1];
+					setpoint[2] = test_vertical_setpoint1[2];
+					setpoint[3] = test_vertical_setpoint1[3];
+					test_vertical_currentpoint = 1;	
+					break;
+				}
+				// Handle the exception
+				default:
+				{
+					// Display that the "estimator_method" was not recognised
+					ROS_INFO_STREAM("[TUNING CONTROLLER] ERROR: in the 'activateTestCallback' function of the 'TuningControllerService': the 'test_vertical_currentpoint' is not recognised.");
+					break;
+				}
+			}
+			break;
+		}
+
+
+		// Test the HEADING controller
+		case 3:
+		{
+			switch (test_heading_currentpoint)
+			{
+				// Currently at setpoint 1 => change to setpoint 2
+				case 1:
+				{
+					setpoint[0] = test_heading_setpoint2[0];
+					setpoint[1] = test_heading_setpoint2[1];
+					setpoint[2] = test_heading_setpoint2[2];
+					setpoint[3] = test_heading_setpoint2[3];
+					test_heading_currentpoint = 2;
+					break;
+				}
+				// Currently at setpoint 2 => change to setpoint 1
+				case 2:
+				{
+					setpoint[0] = test_heading_setpoint1[0];
+					setpoint[1] = test_heading_setpoint1[1];
+					setpoint[2] = test_heading_setpoint1[2];
+					setpoint[3] = test_heading_setpoint1[3];
+					test_heading_currentpoint = 1;	
+					break;
+				}
+				// Handle the exception
+				default:
+				{
+					// Display that the "estimator_method" was not recognised
+					ROS_INFO_STREAM("[TUNING CONTROLLER] ERROR: in the 'activateTestCallback' function of the 'TuningControllerService': the 'test_heading_currentpoint' is not recognised.");
+					break;
+				}
+			}
+			break;
+		}
+
+
+		// Test ALL the controllers
+		case 4:
+		{
+			switch (test_all_currentpoint)
+			{
+				// Currently at setpoint 1 => change to setpoint 2
+				case 1:
+				{
+					setpoint[0] = test_all_setpoint2[0];
+					setpoint[1] = test_all_setpoint2[1];
+					setpoint[2] = test_all_setpoint2[2];
+					setpoint[3] = test_all_setpoint2[3];
+					test_all_currentpoint = 2;
+					break;
+				}
+				// Currently at setpoint 2 => change to setpoint 1
+				case 2:
+				{
+					setpoint[0] = test_all_setpoint1[0];
+					setpoint[1] = test_all_setpoint1[1];
+					setpoint[2] = test_all_setpoint1[2];
+					setpoint[3] = test_all_setpoint1[3];
+					test_all_currentpoint = 1;	
+					break;
+				}
+				// Handle the exception
+				default:
+				{
+					// Display that the "estimator_method" was not recognised
+					ROS_INFO_STREAM("[TUNING CONTROLLER] ERROR: in the 'activateTestCallback' function of the 'TuningControllerService': the 'test_all_currentpoint' is not recognised.");
+					break;
+				}
+			}
+			break;
+		}
+
+
+		// Handle the exception
+		default:
+		{
+			// Display that the "estimator_method" was not recognised
+			ROS_INFO_STREAM("[TUNING CONTROLLER] ERROR: in the 'activateTestCallback' function of the 'TuningControllerService': the 'test_index' is not recognised.");
+			break;
+		}
+	}
+}
+
+// CHANGE THE GAIN FOR THE HORIZONTAL CONTROLLER
+void horizontalGainCallback(const std_msgs::Int32& msg)
+{
+
+}
+
+// CHANGE THE GAIN FOR THE VERTICAL CONTROLLER
+void verticalGainCallback(const std_msgs::Int32& msg)
+{
+
+}
+
+// CHANGE THE GAIN FOR THE HEADING CONTROLLER
+void headingGainCallback(const std_msgs::Int32& msg)
+{
+
+}
+
+
+
+
+
+
+
+
+
+//    ------------------------------------------------------------------------------
+//    EEEEE   SSSS  TTTTT  III  M   M    A    TTTTT  III   OOO   N   N
+//    E      S        T     I   MM MM   A A     T     I   O   O  NN  N
+//    EEE     SSS     T     I   M M M  A   A    T     I   O   O  N N N
+//    E          S    T     I   M   M  AAAAA    T     I   O   O  N  NN
+//    EEEEE  SSSS     T    III  M   M  A   A    T    III   OOO   N   N
+//    ------------------------------------------------------------------------------
+void performEstimatorUpdate_forStateInterial(Controller::Request &request)
+{
+
+	// PUT THE CURRENT MEASURED DATA INTO THE CLASS VARIABLE
+	// > for (x,y,z) position
+	current_xzy_rpy_measurement[0] = request.ownCrazyflie.x;
+	current_xzy_rpy_measurement[1] = request.ownCrazyflie.y;
+	current_xzy_rpy_measurement[2] = request.ownCrazyflie.z;
+	// > for (roll,pitch,yaw) angles
+	current_xzy_rpy_measurement[3] = request.ownCrazyflie.roll;
+	current_xzy_rpy_measurement[4] = request.ownCrazyflie.pitch;
+	current_xzy_rpy_measurement[5] = request.ownCrazyflie.yaw;
+
+
+	// RUN THE FINITE DIFFERENCE ESTIMATOR
+	performEstimatorUpdate_forStateInterial_viaFiniteDifference();
+
+
+	// RUN THE POINT MASS KALMAN FILTER ESTIMATOR
+	performEstimatorUpdate_forStateInterial_viaPointMassKalmanFilter();
+
+
+	// FILLE IN THE STATE INERTIAL ESTIMATE TO BE USED FOR CONTROL
+	switch (estimator_method)
+	{
+		// Estimator based on finte differences
+		case ESTIMATOR_METHOD_FINITE_DIFFERENCE:
+		{
+			// Transfer the estimate
+			for(int i = 0; i < 12; ++i)
+			{
+				current_stateInertialEstimate[i]  = stateInterialEstimate_viaFiniteDifference[i];
+			}
+			break;
+		}
+		// Estimator based on Point Mass Kalman Filter
+		case ESTIMATOR_METHOD_POINT_MASS_PER_DIMENSION:
+		{
+			// Transfer the estimate
+			for(int i = 0; i < 12; ++i)
+			{
+				current_stateInertialEstimate[i]  = stateInterialEstimate_viaPointMassKalmanFilter[i];
+			}
+			break;
+		}
+		// Handle the exception
+		default:
+		{
+			// Display that the "estimator_method" was not recognised
+			ROS_INFO_STREAM("[TUNING CONTROLLER] ERROR: in the 'calculateControlOutput' function of the 'TuningControllerService': the 'estimator_method' is not recognised.");
+			// Transfer the finite difference estimate by default
+			for(int i = 0; i < 12; ++i)
+			{
+				current_stateInertialEstimate[i]  = stateInterialEstimate_viaFiniteDifference[i];
+			}
+			break;
+		}
+	}
+
+
+	// NOW THAT THE ESTIMATORS HAVE ALL BEEN RUN, PUT THE CURRENT
+	// MEASURED DATA INTO THE CLASS VARIABLE FOR THE PREVIOUS 
+	// > for (x,y,z) position
+	previous_xzy_rpy_measurement[0] = current_xzy_rpy_measurement[0];
+	previous_xzy_rpy_measurement[1] = current_xzy_rpy_measurement[1];
+	previous_xzy_rpy_measurement[2] = current_xzy_rpy_measurement[2];
+	// > for (roll,pitch,yaw) angles
+	previous_xzy_rpy_measurement[3] = current_xzy_rpy_measurement[3];
+	previous_xzy_rpy_measurement[4] = current_xzy_rpy_measurement[4];
+	previous_xzy_rpy_measurement[5] = current_xzy_rpy_measurement[5];
+}
+
+
+
+void performEstimatorUpdate_forStateInterial_viaFiniteDifference()
+{
+	// PUT IN THE CURRENT MEASUREMENT DIRECTLY
+	// > for (x,y,z) position
+	stateInterialEstimate_viaFiniteDifference[0]  = current_xzy_rpy_measurement[0];
+	stateInterialEstimate_viaFiniteDifference[1]  = current_xzy_rpy_measurement[1];
+	stateInterialEstimate_viaFiniteDifference[2]  = current_xzy_rpy_measurement[2];
+	// > for (roll,pitch,yaw) angles
+	stateInterialEstimate_viaFiniteDifference[6]  = current_xzy_rpy_measurement[3];
+	stateInterialEstimate_viaFiniteDifference[7]  = current_xzy_rpy_measurement[4];
+	stateInterialEstimate_viaFiniteDifference[8]  = current_xzy_rpy_measurement[5];
+
+	// COMPUTE THE VELOCITIES VIA FINITE DIFFERENCE
+	// > for (x,y,z) velocities
+	stateInterialEstimate_viaFiniteDifference[3]  = (current_xzy_rpy_measurement[0] - previous_xzy_rpy_measurement[0]) * estimator_frequency;
+	stateInterialEstimate_viaFiniteDifference[4]  = (current_xzy_rpy_measurement[1] - previous_xzy_rpy_measurement[1]) * estimator_frequency;
+	stateInterialEstimate_viaFiniteDifference[5]  = (current_xzy_rpy_measurement[2] - previous_xzy_rpy_measurement[2]) * estimator_frequency;
+	// > for (roll,pitch,yaw) velocities
+	stateInterialEstimate_viaFiniteDifference[9]  = (current_xzy_rpy_measurement[3] - previous_xzy_rpy_measurement[3]) * estimator_frequency;
+	stateInterialEstimate_viaFiniteDifference[10] = (current_xzy_rpy_measurement[4] - previous_xzy_rpy_measurement[4]) * estimator_frequency;
+	stateInterialEstimate_viaFiniteDifference[11] = (current_xzy_rpy_measurement[5] - previous_xzy_rpy_measurement[5]) * estimator_frequency;
+}
+
+
+
+void performEstimatorUpdate_forStateInterial_viaPointMassKalmanFilter()
+{
+	// PERFORM THE KALMAN FILTER UPDATE STEP
+	// > First take a copy of the estimator state
+	float temp_PMKFstate[12];
+	for(int i = 0; i < 12; ++i)
+	{
+		temp_PMKFstate[i]  = 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];
+	// > 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];
+	// > 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];
+
+	// > 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];
+	// > 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];
+	// > 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];
+}
+
+
+
+
+//    ----------------------------------------------------------------------------------
+//    L       QQQ   RRRR
+//    L      Q   Q  R   R
+//    L      Q   Q  RRRR
+//    L      Q  Q   R  R
+//    LLLLL   QQ Q  R   R
+//    ----------------------------------------------------------------------------------
+
+void calculateControlOutput_viaLQR(float stateErrorBody[12], Controller::Request &request, Controller::Response &response)
+{
+	// SWITCH BETWEEN THE DIFFERENT LQR CONTROLLER MODES:
+	switch (controller_mode)
+	{
+		// LQR controller based on the state vector:
+		// [position,velocity,angles]
+		case CONTROLLER_MODE_LQR_RATE:
+		{
+			// Call the function that performs the control computations for this mode
+			calculateControlOutput_viaLQRforRates(stateErrorBody,request,response);
+			break;
+		}
+
+		// LQR controller based on the state vector:
+		// [position,velocity]
+		case CONTROLLER_MODE_LQR_ANGLE:
+		{
+			// Call the function that performs the control computations for this mode
+			calculateControlOutput_viaLQRforAngles(stateErrorBody,request,response);
+			break;
+		}
+
+		// LQR controller based on the state vector:
+		// [position,velocity,angles]
+		case CONTROLLER_MODE_LQR_ANGLE_RATE_NESTED:
+		{
+			// Call the function that performs the control computations for this mode
+			calculateControlOutput_viaLQRforAnglesRatesNested(stateErrorBody,request,response);
+			break;
+		}
+
+		default:
+		{
+			// Display that the "controller_mode" was not recognised
+			ROS_INFO_STREAM("[TUNING CONTROLLER] ERROR: in the 'calculateControlOutput' function of the 'TuningControllerService': the 'controller_mode' is not recognised.");
+			// Set everything in the response to zero
+			response.controlOutput.roll       =  0;
+			response.controlOutput.pitch      =  0;
+			response.controlOutput.yaw        =  0;
+			response.controlOutput.motorCmd1  =  0;
+			response.controlOutput.motorCmd2  =  0;
+			response.controlOutput.motorCmd3  =  0;
+			response.controlOutput.motorCmd4  =  0;
+			response.controlOutput.onboardControllerType = CF_COMMAND_TYPE_MOTOR;
+			break;
+		}
+	}
+}
+
+
+
+
+void calculateControlOutput_viaLQRforRates(float stateErrorBody[12], Controller::Request &request, Controller::Response &response)
+{
+	// PERFORM THE "u=Kx" LQR CONTROLLER COMPUTATION
+
+	// Instantiate the local variables for the following:
+	// > body frame roll rate,
+	// > body frame pitch rate,
+	// > body frame yaw rate,
+	// > total thrust adjustment.
+	// These will be requested from the Crazyflie's on-baord "inner-loop" controller
+	float rollRate_forResponse = 0;
+	float pitchRate_forResponse = 0;
+	float yawRate_forResponse = 0;
+	float thrustAdjustment = 0;
+	
+	// Perform the "-Kx" LQR computation for the rates and thrust:
+	for(int i = 0; i < 9; ++i)
+	{
+		// BODY FRAME Y CONTROLLER
+		rollRate_forResponse  -= gainMatrixRollRate[i] * stateErrorBody[i];
+		// BODY FRAME X CONTROLLER
+		pitchRate_forResponse -= gainMatrixPitchRate[i] * stateErrorBody[i];
+		// BODY FRAME YAW CONTROLLER
+		yawRate_forResponse   -= gainMatrixYawRate[i] * stateErrorBody[i];
+		// > ALITUDE CONTROLLER (i.e., z-controller):
+		thrustAdjustment      -= gainMatrixThrust_NineStateVector[i] * stateErrorBody[i];
+	}
+
+
+	// UPDATE THE "RETURN" THE VARIABLE NAMED "response"
+
+	// Put the computed rates and thrust into the "response" variable
+	// > For roll, pitch, and yaw:
+	response.controlOutput.roll  = rollRate_forResponse;
+	response.controlOutput.pitch = pitchRate_forResponse;
+	response.controlOutput.yaw   = yawRate_forResponse;
+	// > For the thrust adjustment we must add the feed-forward thrust to counter-act gravity.
+	// > NOTE: remember that the thrust is commanded per motor, so you sohuld
+	//         consider whether the "thrustAdjustment" computed by your
+	//         controller needed to be divided by 4 or not.
+	thrustAdjustment = thrustAdjustment / 4.0;
+	// > NOTE: the "gravity_force_quarter" value was already divided by 4 when
+	//   it was loaded/processes from the .yaml file.
+	response.controlOutput.motorCmd1 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter);
+	response.controlOutput.motorCmd2 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter);
+	response.controlOutput.motorCmd3 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter);
+	response.controlOutput.motorCmd4 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter);
+
+	
+	// Specify that this controller is a rate controller
+	// response.controlOutput.onboardControllerType = CF_COMMAND_TYPE_MOTOR;
+	response.controlOutput.onboardControllerType = CF_COMMAND_TYPE_RATE;
+	// response.controlOutput.onboardControllerType = CF_COMMAND_TYPE_ANGLE;
+
+
+	// An alternate debugging technique is to print out data directly to the
+	// command line from which this node was launched.
+	if (shouldDisplayDebugInfo)
+	{
+		// An example of "printing out" the data from the "request" argument to the
+		// command line. This might be useful for debugging.
+		ROS_INFO_STREAM("x-coordinate [m]: " << request.ownCrazyflie.x);
+		ROS_INFO_STREAM("y-coordinate [m]: " << request.ownCrazyflie.y);
+		ROS_INFO_STREAM("z-coordinate [m]: " << request.ownCrazyflie.z);
+		ROS_INFO_STREAM("roll       [deg]: " << request.ownCrazyflie.roll);
+		ROS_INFO_STREAM("pitch      [deg]: " << request.ownCrazyflie.pitch);
+		ROS_INFO_STREAM("yaw        [deg]: " << request.ownCrazyflie.yaw);
+		ROS_INFO_STREAM("Delta t      [s]: " << request.ownCrazyflie.acquiringTime);
+
+		// An example of "printing out" the control actions computed.
+		ROS_INFO_STREAM("thrustAdjustment = " << thrustAdjustment);
+		ROS_INFO_STREAM("controlOutput.roll = " << response.controlOutput.roll);
+		ROS_INFO_STREAM("controlOutput.pitch = " << response.controlOutput.pitch);
+		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]);
+
+		// An example of "printing out" the per motor 16-bit command computed.
+		ROS_INFO_STREAM("controlOutput.cmd1 = " << response.controlOutput.motorCmd1);
+		ROS_INFO_STREAM("controlOutput.cmd3 = " << response.controlOutput.motorCmd2);
+		ROS_INFO_STREAM("controlOutput.cmd2 = " << response.controlOutput.motorCmd3);
+		ROS_INFO_STREAM("controlOutput.cmd4 = " << response.controlOutput.motorCmd4);
+	}
+}
+
+
+
+
+void calculateControlOutput_viaLQRforAngles(float stateErrorBody[12], Controller::Request &request, Controller::Response &response)
+{
+	// PERFORM THE "u=Kx" LQR CONTROLLER COMPUTATION
+
+	// Instantiate the local variables for the following:
+	// > body frame roll angle,
+	// > body frame pitch angle,
+	// > total thrust adjustment.
+	// These will be requested from the Crazyflie's on-baord "inner-loop" controller
+	float rollAngle_forResponse = 0;
+	float pitchAngle_forResponse = 0;
+	float thrustAdjustment = 0;
+
+	// Perform the "-Kx" LQR computation for the rates and thrust:
+	for(int i = 0; i < 6; ++i)
+	{
+		// BODY FRAME Y CONTROLLER
+		rollAngle_forResponse -= gainMatrixRollAngle[i] * stateErrorBody[i];
+		// BODY FRAME X CONTROLLER
+		pitchAngle_forResponse -= gainMatrixPitchAngle[i] * stateErrorBody[i];
+		// > ALITUDE CONTROLLER (i.e., z-controller):
+		thrustAdjustment      -= gainMatrixThrust_SixStateVector[i] * stateErrorBody[i];
+	}
+
+	// UPDATE THE "RETURN" THE VARIABLE NAMED "response"
+
+	// Put the computed rates and thrust into the "response" variable
+	// > For roll, pitch, and yaw:
+	response.controlOutput.roll  = rollAngle_forResponse;
+	response.controlOutput.pitch = pitchAngle_forResponse;
+	response.controlOutput.yaw   = setpoint[3];
+	// > For the thrust adjustment we must add the feed-forward thrust to counter-act gravity.
+	// > NOTE: remember that the thrust is commanded per motor, so you sohuld
+	//         consider whether the "thrustAdjustment" computed by your
+	//         controller needed to be divided by 4 or not.
+	thrustAdjustment = thrustAdjustment / 4.0;
+	// > NOTE: the "gravity_force_quarter" value was already divided by 4 when
+	//         it was loaded/processes from the .yaml file.
+	response.controlOutput.motorCmd1 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter);
+	response.controlOutput.motorCmd2 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter);
+	response.controlOutput.motorCmd3 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter);
+	response.controlOutput.motorCmd4 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter);
+
+	
+	// Specify that this controller is a rate controller
+	// response.controlOutput.onboardControllerType = CF_COMMAND_TYPE_MOTOR;
+	// response.controlOutput.onboardControllerType = CF_COMMAND_TYPE_RATE;
+	response.controlOutput.onboardControllerType = CF_COMMAND_TYPE_ANGLE;
+
+
+}
+
+
+
+void calculateControlOutput_viaLQRforAnglesRatesNested( float stateErrorBody[12], Controller::Request &request, Controller::Response &response)
+{
+	// PERFORM THE NESTED "u=Kx" LQR CONTROLLER COMPUTATION
+
+	// Increment the counter variable
+	lqr_angleRateNested_counter++;
+
+	if (lqr_angleRateNested_counter > 4)
+	{
+		//ROS_INFO("Outer called");
+			
+		// Reset the counter to 1
+		lqr_angleRateNested_counter = 1;
+
+		// PERFORM THE OUTER "u=Kx" LQR CONTROLLER COMPUTATION
+
+		// Reset the class variable to zero for the following:
+		// > body frame roll angle,
+		// > body frame pitch angle,
+		// > body frame yaw angle,
+		// > total thrust adjustment.
+		// These will be requested from the "inner-loop" LQR controller below
+		lqr_angleRateNested_prev_rollAngle        = 0;
+		lqr_angleRateNested_prev_pitchAngle       = 0;
+		lqr_angleRateNested_prev_thrustAdjustment = 0;
+
+		// Perform the "-Kx" LQR computation for the rates and thrust:
+		for(int i = 0; i < 6; ++i)
+		{
+			// BODY FRAME Y CONTROLLER
+			lqr_angleRateNested_prev_rollAngle        -= gainMatrixRollAngle_50Hz[i] * stateErrorBody[i];
+			// BODY FRAME X CONTROLLER
+			lqr_angleRateNested_prev_pitchAngle       -= gainMatrixPitchAngle_50Hz[i] * stateErrorBody[i];
+			// > ALITUDE CONTROLLER (i.e., z-controller):
+			lqr_angleRateNested_prev_thrustAdjustment -= gainMatrixThrust_SixStateVector_50Hz[i] * stateErrorBody[i];
+		}
+
+		// BODY FRAME Z CONTROLLER
+		//lqr_angleRateNested_prev_yawAngle = setpoint[3];
+		lqr_angleRateNested_prev_yawAngle = stateErrorBody[8];
+
+
+	}
+
+	//ROS_INFO("Inner called");
+
+	// PERFORM THE INNER "u=Kx" LQR CONTROLLER COMPUTATION
+	// Instantiate the local variables for the following:
+	// > body frame roll rate,
+	// > body frame pitch rate,
+	// > body frame yaw rate,
+	// These will be requested from the Crazyflie's on-baord "inner-loop" controller
+	float rollRate_forResponse  = 0;
+	float pitchRate_forResponse = 0;
+	float yawRate_forResponse   = 0;
+
+	// Create the angle error to use for the inner controller
+	float temp_stateAngleError[3] = {
+		stateErrorBody[6] - lqr_angleRateNested_prev_rollAngle,
+		stateErrorBody[7] - lqr_angleRateNested_prev_pitchAngle,
+		lqr_angleRateNested_prev_yawAngle
+	};
+	
+	// Perform the "-Kx" LQR computation for the rates and thrust:
+	for(int i = 0; i < 4; ++i)
+	{
+		// BODY FRAME Y CONTROLLER
+		rollRate_forResponse  -= gainMatrixRollRate_Nested[i]  * temp_stateAngleError[i];
+		// BODY FRAME X CONTROLLER
+		pitchRate_forResponse -= gainMatrixPitchRate_Nested[i] * temp_stateAngleError[i];
+		// BODY FRAME Z CONTROLLER
+		yawRate_forResponse   -= gainMatrixYawRate_Nested[i]   * temp_stateAngleError[i];
+	}
+
+
+	// UPDATE THE "RETURN" THE VARIABLE NAMED "response"
+
+	// Put the computed rates and thrust into the "response" variable
+	// > For roll, pitch, and yaw:
+	response.controlOutput.roll  = rollRate_forResponse;
+	response.controlOutput.pitch = pitchRate_forResponse;
+	response.controlOutput.yaw   = yawRate_forResponse;
+	// > For the thrust adjustment we must add the feed-forward thrust to counter-act gravity.
+	// > NOTE: remember that the thrust is commanded per motor, so you sohuld
+	//         consider whether the "thrustAdjustment" computed by your
+	//         controller needed to be divided by 4 or not.
+	float thrustAdjustment = lqr_angleRateNested_prev_thrustAdjustment / 4.0;
+	// > NOTE: the "gravity_force_quarter" value was already divided by 4 when
+	//         it was loaded/processes from the .yaml file.
+	response.controlOutput.motorCmd1 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter);
+	response.controlOutput.motorCmd2 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter);
+	response.controlOutput.motorCmd3 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter);
+	response.controlOutput.motorCmd4 = computeMotorPolyBackward(thrustAdjustment + gravity_force_quarter);
+
+	
+	// Specify that this controller is a rate controller
+	// response.controlOutput.onboardControllerType = CF_COMMAND_TYPE_MOTOR;
+	response.controlOutput.onboardControllerType = CF_COMMAND_TYPE_RATE;
+	// response.controlOutput.onboardControllerType = CF_COMMAND_TYPE_ANGLE;
+
+	// Display some details (if requested)
+	if (shouldDisplayDebugInfo)
+	{
+		ROS_INFO_STREAM("thrust    =" << lqr_angleRateNested_prev_thrustAdjustment );
+		ROS_INFO_STREAM("rollrate  =" << response.controlOutput.roll );
+		ROS_INFO_STREAM("pitchrate =" << response.controlOutput.pitch );
+		ROS_INFO_STREAM("yawrate   =" << response.controlOutput.yaw );
+	}
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void construct_and_publish_debug_message(Controller::Request &request, Controller::Response &response)
+{
+	//  ***********************************************************
+	//  DDDD   EEEEE  BBBB   U   U   GGGG       M   M   SSSS   GGGG
+	//  D   D  E      B   B  U   U  G           MM MM  S      G
+	//  D   D  EEE    BBBB   U   U  G           M M M   SSS   G
+	//  D   D  E      B   B  U   U  G   G       M   M      S  G   G
+	//  DDDD   EEEEE  BBBB    UUU    GGGG       M   M  SSSS    GGGG
+
+    // DEBUGGING CODE:
+    // As part of the D-FaLL-System we have defined a message type names"DebugMsg".
+    // By fill this message with data and publishing it you can display the data in
+    // real time using rpt plots. Instructions for using rqt plots can be found on
+    // the wiki of the D-FaLL-System repository
+    
+	// Instantiate a local variable of type "DebugMsg", see the file "DebugMsg.msg"
+	// (located in the "msg" folder) to see the full structure of this message.
+	DebugMsg debugMsg;
+
+	// Fill the debugging message with the data provided by Vicon
+	debugMsg.vicon_x      = request.ownCrazyflie.x;
+	debugMsg.vicon_y      = request.ownCrazyflie.y;
+	debugMsg.vicon_z      = request.ownCrazyflie.z;
+	debugMsg.vicon_roll   = request.ownCrazyflie.roll;
+	debugMsg.vicon_pitch  = request.ownCrazyflie.pitch;
+	debugMsg.vicon_yaw    = request.ownCrazyflie.yaw;
+
+	// Fill in the debugging message with any other data you would like to display
+	// in real time. For example, it might be useful to display the thrust
+	// adjustment computed by the z-altitude controller.
+	// The "DebugMsg" type has 10 properties from "value_1" to "value_10", all of
+	// type "float64" that you can fill in with data you would like to plot in
+	// real-time.
+	// debugMsg.value_1 = thrustAdjustment;
+	// ......................
+	// debugMsg.value_10 = your_variable_name;
+
+	// Publish the "debugMsg"
+	debugPublisher.publish(debugMsg);
+}
+
+
+
+
+//    ------------------------------------------------------------------------------
+//    RRRR    OOO   TTTTT    A    TTTTT  EEEEE       III  N   N  TTTTT   OOO
+//    R   R  O   O    T     A A     T    E            I   NN  N    T    O   O
+//    RRRR   O   O    T    A   A    T    EEE          I   N N N    T    O   O
+//    R  R   O   O    T    AAAAA    T    E            I   N  NN    T    O   O
+//    R   R   OOO     T    A   A    T    EEEEE       III  N   N    T     OOO
+//
+//    BBBB    OOO   DDDD   Y   Y       FFFFF  RRRR     A    M   M  EEEEE
+//    B   B  O   O  D   D   Y Y        F      R   R   A A   MM MM  E
+//    BBBB   O   O  D   D    Y         FFF    RRRR   A   A  M M M  EEE
+//    B   B  O   O  D   D    Y         F      R  R   AAAAA  M   M  E
+//    BBBB    OOO   DDDD     Y         F      R   R  A   A  M   M  EEEEE
+//    ------------------------------------------------------------------------------
+
+// The arguments for this function are as follows:
+// stateInertial
+// This is an array of length 9 with the estimates the error of of the following values
+// relative to the sepcifed setpoint:
+//     stateInertial[0]    x position of the Crazyflie relative to the inertial frame origin [meters]
+//     stateInertial[1]    y position of the Crazyflie relative to the inertial frame origin [meters]
+//     stateInertial[2]    z position of the Crazyflie relative to the inertial frame origin [meters]
+//     stateInertial[3]    x-axis component of the velocity of the Crazyflie in the inertial frame [meters/second]
+//     stateInertial[4]    y-axis component of the velocity of the Crazyflie in the inertial frame [meters/second]
+//     stateInertial[5]    z-axis component of the velocity of the Crazyflie in the inertial frame [meters/second]
+//     stateInertial[6]    The roll  component of the intrinsic Euler angles [radians]
+//     stateInertial[7]    The pitch component of the intrinsic Euler angles [radians]
+//     stateInertial[8]    The yaw   component of the intrinsic Euler angles [radians]
+// 
+// stateBody
+// This is an empty array of length 9, this function should fill in all elements of this
+// array with the same ordering as for the "stateInertial" argument, expect that the (x,y)
+// position and (x,y) velocities are rotated into the body frame.
+//
+// yaw_measured
+// This is the yaw component of the intrinsic Euler angles in [radians] as measured by
+// the Vicon motion capture system
+//
+void convertIntoBodyFrame(float stateInertial[12], float (&stateBody)[12], float yaw_measured)
+{
+	if (shouldPerformConvertIntoBodyFrame)
+	{
+		float sinYaw = sin(yaw_measured);
+    	float cosYaw = cos(yaw_measured);
+
+    	// Fill in the (x,y,z) position estimates to be returned
+	    stateBody[0] = stateInertial[0] * cosYaw  +  stateInertial[1] * sinYaw;
+	    stateBody[1] = stateInertial[1] * cosYaw  -  stateInertial[0] * sinYaw;
+	    stateBody[2] = stateInertial[2];
+
+	    // Fill in the (x,y,z) velocity estimates to be returned
+	    stateBody[3] = stateInertial[3] * cosYaw  +  stateInertial[4] * sinYaw;
+	    stateBody[4] = stateInertial[4] * cosYaw  -  stateInertial[3] * sinYaw;
+	    stateBody[5] = stateInertial[5];
+
+	    // Fill in the (roll,pitch,yaw) estimates to be returned
+	    stateBody[6] = stateInertial[6];
+	    stateBody[7] = stateInertial[7];
+	    stateBody[8] = stateInertial[8];
+
+	    // Fill in the (roll,pitch,yaw) velocity estimates to be returned
+	    stateBody[9]  = stateInertial[9];
+	    stateBody[10] = stateInertial[10];
+	    stateBody[11] = stateInertial[11];
+	}
+	else
+	{
+	    // Fill in the (x,y,z) position estimates to be returned
+	    stateBody[0] = stateInertial[0];
+	    stateBody[1] = stateInertial[1];
+	    stateBody[2] = stateInertial[2];
+
+	    // Fill in the (x,y,z) velocity estimates to be returned
+	    stateBody[3] = stateInertial[3];
+	    stateBody[4] = stateInertial[4];
+	    stateBody[5] = stateInertial[5];
+
+	    // Fill in the (roll,pitch,yaw) estimates to be returned
+	    stateBody[6] = stateInertial[6];
+	    stateBody[7] = stateInertial[7];
+	    stateBody[8] = stateInertial[8];
+
+	    // Fill in the (roll,pitch,yaw) velocity estimates to be returned
+	    stateBody[9]  = stateInertial[9];
+	    stateBody[10] = stateInertial[10];
+	    stateBody[11] = stateInertial[11];
+	}
+}
+
+
+
+
+void convert_stateInertial_to_bodyFrameError(float stateInertial[12], float setpoint[4], float (&bodyFrameError)[12])
+{
+	// Store the current YAW in a local variable
+	float temp_stateInertial_yaw = stateInertial[8];
+
+	// Adjust the INERTIAL (x,y,z) position for the setpoint
+	stateInertial[0] = stateInertial[0] - setpoint[0];
+	stateInertial[1] = stateInertial[1] - setpoint[1];
+	stateInertial[2] = stateInertial[2] - setpoint[2];
+
+	// Fill in the yaw angle error
+	// > This error should be "unwrapped" to be in the range
+	//   ( -pi , pi )
+	// > First, get the yaw error into a local variable
+	float yawError = stateInertial[8] - setpoint[3];
+	// > Second, "unwrap" the yaw error to the interval ( -pi , pi )
+	while(yawError > PI) {yawError -= 2 * PI;}
+	while(yawError < -PI) {yawError += 2 * PI;}
+	// > Third, put the "yawError" into the "stateError" variable
+	stateInertial[8] = yawError;
+
+
+	if (yawError>(PI/6))
+	{
+		yawError = (PI/6);
+	}
+	else if (yawError<(-PI/6))
+	{
+		yawError = (-PI/6);
+	}
+
+	// CONVERSION INTO BODY FRAME
+	// Conver the state erorr from the Inertial frame into the Body frame
+	// > Note: the function "convertIntoBodyFrame" is implemented in this file
+	//   and by default does not perform any conversion. The equations to convert
+	//   the state error into the body frame should be implemented in that function
+	//   for successful completion of the PPS exercise
+	convertIntoBodyFrame(stateInertial, bodyFrameError, temp_stateInertial_yaw);
+}
+
+
+
+
+//    ------------------------------------------------------------------------------
+//    N   N  EEEEE  W     W   TTTTT   OOO   N   N        CCCC  M   M  DDDD
+//    NN  N  E      W     W     T    O   O  NN  N       C      MM MM  D   D
+//    N N N  EEE    W     W     T    O   O  N N N  -->  C      M M M  D   D
+//    N  NN  E       W W W      T    O   O  N  NN       C      M   M  D   D
+//    N   N  EEEEE    W W       T     OOO   N   N        CCCC  M   M  DDDD
+//
+//     CCCC   OOO   N   N  V   V  EEEEE  RRRR    SSSS  III   OOO   N   N
+//    C      O   O  NN  N  V   V  E      R   R  S       I   O   O  NN  N
+//    C      O   O  N N N  V   V  EEE    RRRR    SSS    I   O   O  N N N
+//    C      O   O  N  NN   V V   E      R  R       S   I   O   O  N  NN
+//     CCCC   OOO   N   N    V    EEEEE  R   R  SSSS   III   OOO   N   N
+//    ------------------------------------------------------------------------------
+
+// This function DOES NOT NEED TO BE edited for successful completion of the PPS exercise
+float computeMotorPolyBackward(float thrust)
+{
+	// Compute the 16-bit command signal that generates the "thrust" force
+	float cmd = (-motorPoly[1] + sqrt(motorPoly[1] * motorPoly[1] - 4 * motorPoly[2] * (motorPoly[0] - thrust))) / (2 * motorPoly[2]);
+
+	// Saturate the signal to be 0 or in the range [1000,65000]
+	if (cmd < cmd_sixteenbit_min)
+	{
+		cmd = 0;
+	}
+	else if (cmd > cmd_sixteenbit_max)
+	{
+		cmd = cmd_sixteenbit_max;
+	}
+
+    return cmd;
+}
+
+
+
+
+//    ----------------------------------------------------------------------------------
+//    N   N  EEEEE  W     W        SSSS  EEEEE  TTTTT  PPPP    OOO   III  N   N  TTTTT
+//    NN  N  E      W     W       S      E        T    P   P  O   O   I   NN  N    T
+//    N N N  EEE    W     W        SSS   EEE      T    PPPP   O   O   I   N N N    T
+//    N  NN  E       W W W            S  E        T    P      O   O   I   N  NN    T
+//    N   N  EEEEE    W W         SSSS   EEEEE    T    P       OOO   III  N   N    T
+//
+//     GGG   U   U  III        CCCC    A    L      L      BBBB     A     CCCC  K   K
+//    G   G  U   U   I        C       A A   L      L      B   B   A A   C      K  K
+//    G      U   U   I        C      A   A  L      L      BBBB   A   A  C      KKK
+//    G   G  U   U   I        C      AAAAA  L      L      B   B  AAAAA  C      K  K
+//     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)
+{
+    setpoint[0] = newSetpoint.x;
+    setpoint[1] = newSetpoint.y;
+    setpoint[2] = newSetpoint.z;
+    setpoint[3] = newSetpoint.yaw;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//    ----------------------------------------------------------------------------------
+//    L       OOO     A    DDDD
+//    L      O   O   A A   D   D
+//    L      O   O  A   A  D   D
+//    L      O   O  AAAAA  D   D
+//    LLLLL   OOO   A   A  DDDD
+//
+//    PPPP     A    RRRR     A    M   M  EEEEE  TTTTT  EEEEE  RRRR    SSSS
+//    P   P   A A   R   R   A A   MM MM  E        T    E      R   R  S
+//    PPPP   A   A  RRRR   A   A  M M M  EEE      T    EEE    RRRR    SSS
+//    P      AAAAA  R  R   AAAAA  M   M  E        T    E      R  R       S
+//    P      A   A  R   R  A   A  M   M  EEEEE    T    EEEEE  R   R  SSSS
+//    ----------------------------------------------------------------------------------
+
+
+// This function DOES NOT NEED TO BE edited for successful completion of the PPS exercise
+void yamlReadyForFetchCallback(const std_msgs::Int32& msg)
+{
+	// Extract from the "msg" for which controller the and from where to fetch the YAML
+	// parameters
+	int controller_to_fetch_yaml = msg.data;
+
+	// Switch between fetching for the different controllers and from different locations
+	switch(controller_to_fetch_yaml)
+	{
+
+		// > FOR FETCHING FROM THE AGENT'S OWN PARAMETER SERVICE
+		case FETCH_YAML_TUNING_CONTROLLER_FROM_OWN_AGENT:
+		{
+			// Let the user know that this message was received
+			ROS_INFO("[TUNING 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_TUNING_CONTROLLER_FROM_COORDINATOR:
+		{
+			// Let the user know that this message was received
+			ROS_INFO("[TUNING 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;
+		}
+
+		default:
+		{
+			// Let the user know that the command was not relevant
+			//ROS_INFO("The CustomControllerService 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;
+		}
+	}
+}
+
+
+// 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)
+{
+	// Here we load the parameters that are specified in the CustomController.yaml file
+
+	// Add the "CustomController" namespace to the "nodeHandle"
+	ros::NodeHandle nodeHandle_for_TuningController(nodeHandle, "TuningController");
+
+
+	// ******************************************************************************* //
+	// PARAMETERS SPECIFIC TO THE TUNING CONTROL FEATURE
+
+	/// Setpoint for the HORIZONTAL test
+	getParameterFloatVector(nodeHandle_for_TuningController, "test_horizontal_setpoint1", test_horizontal_setpoint1, 4);
+	getParameterFloatVector(nodeHandle_for_TuningController, "test_horizontal_setpoint2", test_horizontal_setpoint2, 4);
+
+	// Setpoint for the VERTICAL test
+	getParameterFloatVector(nodeHandle_for_TuningController, "test_vertical_setpoint1", test_vertical_setpoint1, 4);
+	getParameterFloatVector(nodeHandle_for_TuningController, "test_vertical_setpoint2", test_vertical_setpoint2, 4);
+
+	// Setpoint for the HEADING test
+	getParameterFloatVector(nodeHandle_for_TuningController, "test_heading_setpoint1", test_heading_setpoint1, 4);
+	getParameterFloatVector(nodeHandle_for_TuningController, "test_heading_setpoint2", test_heading_setpoint2, 4);
+
+	// Setpoint for the ALL test
+	getParameterFloatVector(nodeHandle_for_TuningController, "test_all_setpoint1", test_all_setpoint1, 4);
+	getParameterFloatVector(nodeHandle_for_TuningController, "test_all_setpoint2", test_all_setpoint2, 4);
+
+	// // DEBUGGING: Print out one of the parameters that was loaded
+	// ROS_INFO_STREAM("[REMOTE CONTROLLER] DEBUGGING: the fetched RemoteController/default_viconObjectName_forRemote = " << default_viconObjectName_forRemote);
+
+	// ******************************************************************************* //
+
+
+
+	// > The mass of the crazyflie
+	cf_mass = getParameterFloat(nodeHandle_for_TuningController , "mass");
+
+	// Display one of the YAML parameters to debug if it is working correctly
+	//ROS_INFO_STREAM("DEBUGGING: mass leaded from loacl file = " << cf_mass );
+
+	// > The frequency at which the "computeControlOutput" is being called, as determined
+	//   by the frequency at which the Vicon system provides position and attitude data
+	vicon_frequency = getParameterFloat(nodeHandle_for_TuningController, "vicon_frequency");
+
+	// > 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_TuningController, "control_frequency");
+
+	// > The co-efficients of the quadratic conversation from 16-bit motor command to
+	//   thrust force in Newtons
+	getParameterFloatVector(nodeHandle_for_TuningController, "motorPoly", motorPoly, 3);
+
+	// > The boolean for whether to execute the convert into body frame function
+	shouldPerformConvertIntoBodyFrame = getParameterBool(nodeHandle_for_TuningController, "shouldPerformConvertIntoBodyFrame");
+
+	// Boolean indiciating whether the "Debug Message" of this agent should be published or not
+	shouldPublishDebugMessage = getParameterBool(nodeHandle_for_TuningController, "shouldPublishDebugMessage");
+
+	// Boolean indiciating whether the debugging ROS_INFO_STREAM should be displayed or not
+	shouldDisplayDebugInfo = getParameterBool(nodeHandle_for_TuningController, "shouldDisplayDebugInfo");
+
+
+	// THE CONTROLLER GAINS:
+
+	// A flag for which controller to use:
+	controller_mode = getParameterInt( nodeHandle_for_TuningController , "controller_mode" );
+
+	// A flag for which estimator to use:
+	estimator_method = getParameterInt( nodeHandle_for_TuningController , "estimator_method" );
+
+	// The LQR Controller parameters for "LQR_MODE_RATE"
+	getParameterFloatVector(nodeHandle_for_TuningController, "gainMatrixThrust_NineStateVector", gainMatrixThrust_NineStateVector, 9);
+	getParameterFloatVector(nodeHandle_for_TuningController, "gainMatrixRollRate",               gainMatrixRollRate,               9);
+	getParameterFloatVector(nodeHandle_for_TuningController, "gainMatrixPitchRate",              gainMatrixPitchRate,              9);
+	getParameterFloatVector(nodeHandle_for_TuningController, "gainMatrixYawRate",                gainMatrixYawRate,                9);
+	
+	// The LQR Controller parameters for "LQR_MODE_ANGLE"
+	getParameterFloatVector(nodeHandle_for_TuningController, "gainMatrixThrust_SixStateVector",  gainMatrixThrust_SixStateVector,  6);
+	getParameterFloatVector(nodeHandle_for_TuningController, "gainMatrixRollAngle",              gainMatrixRollAngle,              6);
+	getParameterFloatVector(nodeHandle_for_TuningController, "gainMatrixPitchAngle",             gainMatrixPitchAngle,             6);
+	
+	// The LQR Controller parameters for "LQR_MODE_ANGLE_RATE_NESTED"
+	getParameterFloatVector(nodeHandle_for_TuningController, "gainMatrixThrust_SixStateVector_50Hz",  gainMatrixThrust_SixStateVector_50Hz,  6);
+	getParameterFloatVector(nodeHandle_for_TuningController, "gainMatrixRollAngle_50Hz",              gainMatrixRollAngle_50Hz,              6);
+	getParameterFloatVector(nodeHandle_for_TuningController, "gainMatrixPitchAngle_50Hz",             gainMatrixPitchAngle_50Hz,             6);
+
+	getParameterFloatVector(nodeHandle_for_TuningController, "gainMatrixRollRate_Nested",             gainMatrixRollRate_Nested,             3);
+	getParameterFloatVector(nodeHandle_for_TuningController, "gainMatrixPitchRate_Nested",            gainMatrixPitchRate_Nested,            3);
+	getParameterFloatVector(nodeHandle_for_TuningController, "gainMatrixYawRate_Nested",              gainMatrixYawRate_Nested,              3);
+
+	
+	// 16-BIT COMMAND LIMITS
+	cmd_sixteenbit_min = getParameterFloat(nodeHandle_for_TuningController, "command_sixteenbit_min");
+	cmd_sixteenbit_max = getParameterFloat(nodeHandle_for_TuningController, "command_sixteenbit_max");
+
+
+	// THE POINT MASS KALMAN FILTER (PMKF) GAINS AND ERROR EVOLUATION
+	// > For the (x,y,z) position
+	getParameterFloatVector(nodeHandle_for_TuningController, "PMKF_Ahat_row1_for_positions",  PMKF_Ahat_row1_for_positions,  2);
+	getParameterFloatVector(nodeHandle_for_TuningController, "PMKF_Ahat_row2_for_positions",  PMKF_Ahat_row2_for_positions,  2);
+	getParameterFloatVector(nodeHandle_for_TuningController, "PMKF_Kinf_for_positions"     ,  PMKF_Kinf_for_positions     ,  2);
+	// > For the (roll,pitch,yaw) angles
+	getParameterFloatVector(nodeHandle_for_TuningController, "PMKF_Ahat_row1_for_angles",  PMKF_Ahat_row1_for_angles,  2);
+	getParameterFloatVector(nodeHandle_for_TuningController, "PMKF_Ahat_row2_for_angles",  PMKF_Ahat_row2_for_angles,  2);
+	getParameterFloatVector(nodeHandle_for_TuningController, "PMKF_Kinf_for_angles"     ,  PMKF_Kinf_for_angles     ,  2);
+
+
+	// DEBUGGING: Print out one of the parameters that was loaded
+	//ROS_INFO_STREAM("[TUNING CONTROLLER] DEBUGGING: the fetched TuningController/mass = " << cf_mass);
+
+
+	// 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()
+{
+	// Compute the feed-forward force that we need to counteract gravity (i.e., mg)
+	// > in units of [Newtons]
+	gravity_force         = cf_mass * 9.81/(1000);
+	gravity_force_quarter = cf_mass * 9.81/(1000*4);
+
+	// Set that the estimator frequency is the same as the control frequency
+	estimator_frequency = vicon_frequency;
+
+
+	// // Roll and pitch limit (in degrees for angles)
+	// remoteControlLimit_roll  = remoteControlLimit_roll_degrees * PI / 180.0;
+	// remoteControlLimit_pitch = remoteControlLimit_pitch_degrees * PI / 180.0;
+
+
+	// // Use the Remote name if the variable is currently empty
+	// if (viconObjectName_forRemote == "empty")
+	// {
+	// 	viconObjectName_forRemote = default_viconObjectName_forRemote;
+	// }
+
+
+	// DEBUGGING: Print out one of the computed quantities
+	//ROS_INFO_STREAM("[REMOTE CONTROLLER] DEBUGGING: after processing the viconObjectName_forRemote = " << viconObjectName_forRemote);
+}
+
+
+
+//    ----------------------------------------------------------------------------------
+//     GGGG  EEEEE  TTTTT  PPPP     A    RRRR     A    M   M   ( )
+//    G      E        T    P   P   A A   R   R   A A   MM MM  (   )
+//    G      EEE      T    PPPP   A   A  RRRR   A   A  M M M  (   )
+//    G   G  E        T    P      AAAAA  R  R   AAAAA  M   M  (   )
+//     GGGG  EEEEE    T    P      A   A  R   R  A   A  M   M   ( )
+//    ----------------------------------------------------------------------------------
+
+
+// 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
+std::string getParameterString(ros::NodeHandle& nodeHandle, std::string name)
+{
+	std::string val;
+	if(!nodeHandle.getParam(name, val)){
+        ROS_ERROR_STREAM("missing parameter '" << name << "'");
+    }
+    return val;
+}    
+
+
+
+
+
+//    ----------------------------------------------------------------------------------
+//    M   M    A    III  N   N
+//    MM MM   A A    I   NN  N
+//    M M M  A   A   I   N N N
+//    M   M  AAAAA   I   N  NN
+//    M   M  A   A  III  N   N
+//    ----------------------------------------------------------------------------------
+
+// This function DOES NOT NEED TO BE edited for successful completion of the PPS exercise
+int main(int argc, char* argv[]) {
+    
+    // Starting the ROS-node
+    ros::init(argc, argv, "TuningControllerService");
+
+    // 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 "StudentControllerService" node
+    // > This should be something like: "/dfall/agentXXX"
+    std::string m_namespace = ros::this_node::getNamespace();
+    ROS_INFO_STREAM("[TUNING 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("[TUNING CONTROLLER] Failed to get agentID from PPSClient");
+	}
+
+
+	// *********************************************************************************
+	// EVERYTHING THAT RELATES TO FETCHING PARAMETERS FROM A YAML FILE
+
+
+	// EVERYTHING FOR THE CONNECTION TO THIS AGENT's OWN PARAMETER SERVICE:
+
+	// 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";
+
+    // 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);
+
+    // 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);
+
+
+    // 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);
+
+
+    // PRINT OUT SOME INFORMATION
+
+    // Let the user know what namespaces are being used for linking to the parameter service
+    ROS_INFO_STREAM("[TUNING CONTROLLER] The namespace string for accessing the Paramter Services are:");
+    ROS_INFO_STREAM("[TUNING CONTROLLER] namespace_to_own_agent_parameter_service    =  " << namespace_to_own_agent_parameter_service);
+    ROS_INFO_STREAM("[TUNING CONTROLLER] namespace_to_coordinator_parameter_service  =  " << namespace_to_coordinator_parameter_service);
+
+
+    // FINALLY, FETCH ANY PARAMETERS REQUIRED FROM THESE "PARAMETER SERVICES"
+
+	// Call the class function that loads the parameters for this class.
+    fetchYamlParameters(nodeHandle_to_own_agent_parameter_service);
+
+    // *********************************************************************************
+
+
+
+    // Subscribe to the message that activates the tests
+	ros::Subscriber tuningActivateTestSubscriber = nodeHandle.subscribe("ActivateTest", 1, activateTestCallback);
+
+	// Subscribe to the message that changes the gains
+	ros::Subscriber tuningHorizontalGainSubscriber = nodeHandle.subscribe("HorizontalGain", 1, horizontalGainCallback);
+	ros::Subscriber tuningVerticalGainSubscriber   = nodeHandle.subscribe("VerticalGain",   1, verticalGainCallback);
+	ros::Subscriber tuningHeadingGainSubscriber    = nodeHandle.subscribe("HeadingGain",    1, headingGainCallback);
+
+
+
+    // 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 "CustomController". This service has
+    // the input-output behaviour defined in the "Controller.srv" file (located in the
+    // "srv" folder). This service, when called, is provided with the most recent
+    // measurement of the Crazyflie and is expected to respond with the control action
+    // that should be sent via the Crazyradio and requested from the Crazyflie, i.e.,
+    // this is where the "outer loop" controller function starts. When a request is made
+    // of this service the "calculateControlOutput" function is called.
+    ros::ServiceServer service = nodeHandle.advertiseService("TuningController", calculateControlOutput);
+
+    // Create a "ros::NodeHandle" type local variable "namespace_nodeHandle" that points
+    // 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());
+
+    // Print out some information to the user.
+    ROS_INFO("[TUNING CONTROLLER] Service ready :-)");
+
+    // Enter an endless while loop to keep the node alive.
+    ros::spin();
+
+    // Return zero if the "ross::spin" is cancelled.
+    return 0;
+}