diff --git a/pps_ws/src/d_fall_pps/CMakeLists.txt b/pps_ws/src/d_fall_pps/CMakeLists.txt
index 08a1abf807c90cebdc13b201025a4d0d94cfa34d..3e92c2eb1509ae3176e774a68ff1bbbff0bb5dc5 100755
--- a/pps_ws/src/d_fall_pps/CMakeLists.txt
+++ b/pps_ws/src/d_fall_pps/CMakeLists.txt
@@ -134,6 +134,8 @@ add_message_files(
   CrazyflieDB.msg
   #----------------------------------------------------------------------
   DebugMsg.msg
+  CustomControllerYAML.msg
+  CustomButton.msg
 )
 
 ## Generate services in the 'srv' folder
@@ -238,6 +240,7 @@ add_executable(PPSClient src/PPSClient.cpp)
 add_executable(SafeControllerService src/SafeControllerService.cpp)
 add_executable(CustomControllerService src/CustomControllerService.cpp)
 add_executable(CentralManagerService src/CentralManagerService.cpp src/CrazyflieIO.cpp)
+add_executable(ParameterService src/ParameterService.cpp)
 add_executable(CircleControllerService src/CircleControllerService.cpp)
 add_executable(FollowCrazyflieService src/FollowCrazyflieService.cpp)
 add_executable(FollowN_1Service src/FollowN_1Service.cpp)
@@ -286,6 +289,7 @@ add_dependencies(PPSClient d_fall_pps_generate_messages_cpp ${catkin_EXPORTED_TA
 add_dependencies(SafeControllerService d_fall_pps_generate_messages_cpp ${catkin_EXPORTED_TARGETS})
 add_dependencies(CustomControllerService 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})
 add_dependencies(CircleControllerService d_fall_pps_generate_messages_cpp ${catkin_EXPORTED_TARGETS})
 add_dependencies(FollowCrazyflieService d_fall_pps_generate_messages_cpp ${catkin_EXPORTED_TARGETS})
 add_dependencies(FollowN_1Service d_fall_pps_generate_messages_cpp ${catkin_EXPORTED_TARGETS})
@@ -324,6 +328,8 @@ target_link_libraries(CustomControllerService ${catkin_LIBRARIES})
 
 target_link_libraries(CentralManagerService ${catkin_LIBRARIES})
 
+target_link_libraries(ParameterService ${catkin_LIBRARIES})
+
 target_link_libraries(CircleControllerService ${catkin_LIBRARIES})
 
 target_link_libraries(FollowCrazyflieService ${catkin_LIBRARIES})
diff --git a/pps_ws/src/d_fall_pps/GUI_Qt/CrazyFlyGUI/CrazyFlyGUI.pro.user b/pps_ws/src/d_fall_pps/GUI_Qt/CrazyFlyGUI/CrazyFlyGUI.pro.user
index 13d53214d559b938f2acc8a24ac64a7286603676..c3bd5196277cff69c0be75d8070cd6cb7bc53467 100755
--- a/pps_ws/src/d_fall_pps/GUI_Qt/CrazyFlyGUI/CrazyFlyGUI.pro.user
+++ b/pps_ws/src/d_fall_pps/GUI_Qt/CrazyFlyGUI/CrazyFlyGUI.pro.user
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE QtCreatorProject>
-<!-- Written by QtCreator 3.5.1, 2017-09-08T11:50:18. -->
+<!-- Written by QtCreator 3.5.1, 2017-12-05T07:54:15. -->
 <qtcreator>
  <data>
   <variable>EnvironmentId</variable>
diff --git a/pps_ws/src/d_fall_pps/GUI_Qt/CrazyFlyGUI/include/mainguiwindow.h b/pps_ws/src/d_fall_pps/GUI_Qt/CrazyFlyGUI/include/mainguiwindow.h
index 9e2fd35149985a824038b533c13d41a2210786ec..e9a8b5b6a268bc1c44a44732109aa870bbeb6d90 100755
--- a/pps_ws/src/d_fall_pps/GUI_Qt/CrazyFlyGUI/include/mainguiwindow.h
+++ b/pps_ws/src/d_fall_pps/GUI_Qt/CrazyFlyGUI/include/mainguiwindow.h
@@ -1,4 +1,4 @@
-//    Copyright (C) 2017, ETH Zurich, D-ITET, Angel Romero
+//    Copyright (C) 2017, ETH Zurich, D-ITET, Paul Beuchat, Angel Romero
 //
 //    This file is part of D-FaLL-System.
 //    
@@ -48,11 +48,31 @@
 
 #include "d_fall_pps/CrazyflieDB.h"
 #include "d_fall_pps/CrazyflieEntry.h"
+#include "d_fall_pps/CustomControllerYAML.h"
 
 #include <std_msgs/Int32.h>
 
 
+// The constants that are sent to the agents in order to
+// "command" changes in their operation state
+#define CMD_USE_SAFE_CONTROLLER   1
+#define CMD_USE_CUSTOM_CONTROLLER 2
+#define CMD_CRAZYFLY_TAKE_OFF     3
+#define CMD_CRAZYFLY_LAND         4
 #define CMD_CRAZYFLY_MOTORS_OFF   5
+
+// The constants that are sent to the agents in order to
+// adjust their radio connection
+#define CMD_RECONNECT  0
+#define CMD_DISCONNECT 1
+
+// For which controller parameters to load
+#define LOAD_YAML_SAFE_CONTROLLER_AGENT          1
+#define LOAD_YAML_CUSTOM_CONTROLLER_AGENT        2
+#define LOAD_YAML_SAFE_CONTROLLER_COORDINATOR    3
+#define LOAD_YAML_CUSTOM_CONTROLLER_COORDINATOR  4
+
+
 using namespace d_fall_pps;
 
 #endif
@@ -166,14 +186,47 @@ private slots:
 
     void on_comboBoxCFs_currentTextChanged(const QString &arg1);
 
+    
+    // For the buttons that "command" all of the agent nodes
+    // > For the radio connection
+    void on_all_connect_button_clicked();
+    void on_all_disconnect_button_clicked();
+    // > For changing the operation state
+    void on_all_take_off_button_clicked();
+    void on_all_land_button_clicked();
     void on_all_motors_off_button_clicked();
+    void on_all_enable_safe_controller_button_clicked();
+    void on_all_enable_custom_controller_button_clicked();
+    // > For loading the parameter
+    void on_all_load_safe_controller_yaml_own_agent_button_clicked();
+    void on_all_load_custom_controller_yaml_own_agent_button_clicked();
+    // > For sending a message with updated parameters
+    void on_all_load_safe_controller_yaml_coordinator_button_clicked();
+    void on_all_load_custom_controller_yaml_coordinator_button_clicked();
+    
 
 private:
 
     Ui::MainGUIWindow *ui;
     myGraphicsScene* scene;
+
+    ros::Timer m_timer_yaml_file_for_safe_controller;
+    ros::Timer m_timer_yaml_file_for_custom_controller;
+
     void _init();
 
+    void safeYamlFileTimerCallback(const ros::TimerEvent&);
+    void customYamlFileTimerCallback(const ros::TimerEvent&);
+
+    void customSendYamlAsMessageTimerCallback(const ros::TimerEvent&);
+    
+    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);
+
 
     #ifdef CATKIN_MAKE
     rosNodeThread* _rosNodeThread;
@@ -181,8 +234,29 @@ private:
     std::vector<crazyFly*> crazyflies_vector;
     CFLinker* cf_linker;
 
+    std::string ros_namespace;
+
     ros::Publisher DBChangedPublisher;
     ros::Publisher emergencyStopPublisher;
+
+    // Publsher for sending "commands" from here (the master) to all
+    // of the agent nodes (where a "command" is the integer that
+    // gives the directive to "take-off", "land, "motors-off", etc...)
+    ros::Publisher commandAllAgentsPublisher;
+
+    // Publisher for sending a request from here (the master) to all "Parameter Service" nodes
+    // that it should re-load parameters from the YAML file for the controllers.
+    // > This is recieved and acted on by both Coordinate and Agent type "Parameter Services",
+    // > A coordinator type "Parameter Service" will subsequently request the agents to fetch
+    //   the parameters from itself.
+    // > A agent type "Parameter Service" will subsequently request its own agent to fetch
+    //   the parameters from itself.
+    ros::Publisher requestLoadControllerYamlPublisher;
+
+    // Publisher for sending a request from here (the master) to all
+    // of the agents nodes that they should (re/dis)-connect from
+    // the Crazy-Radio
+    ros::Publisher crazyRadioCommandAllAgentsPublisher;
     #endif
 
     void updateComboBoxesCFs();
diff --git a/pps_ws/src/d_fall_pps/GUI_Qt/CrazyFlyGUI/src/mainguiwindow.cpp b/pps_ws/src/d_fall_pps/GUI_Qt/CrazyFlyGUI/src/mainguiwindow.cpp
index cc48cdca6537d2c679139890f4d7eb5e3eca5f69..7bb024784a2180f2d788138a63eacab83475ffe2 100755
--- a/pps_ws/src/d_fall_pps/GUI_Qt/CrazyFlyGUI/src/mainguiwindow.cpp
+++ b/pps_ws/src/d_fall_pps/GUI_Qt/CrazyFlyGUI/src/mainguiwindow.cpp
@@ -1,4 +1,4 @@
-//    Copyright (C) 2017, ETH Zurich, D-ITET, Angel Romero
+//    Copyright (C) 2017, ETH Zurich, D-ITET, Paul Beuchat, Angel Romero
 //
 //    This file is part of D-FaLL-System.
 //    
@@ -229,9 +229,30 @@ void MainGUIWindow::_init()
     QObject::connect(_rosNodeThread, SIGNAL(newViconData(const ptrToMessage&)), this, SLOT(updateNewViconData(const ptrToMessage&)));
     QObject::connect(cf_linker, SIGNAL(updateComboBoxes()), this, SLOT(updateComboBoxes()));
 
+
+    ros_namespace = ros::this_node::getNamespace();
+
     ros::NodeHandle nodeHandle("~");
     DBChangedPublisher = nodeHandle.advertise<std_msgs::Int32>("DBChanged", 1);
     emergencyStopPublisher = nodeHandle.advertise<std_msgs::Int32>("emergencyStop", 1);
+
+    // Initialise the publisher for sending "commands" from here (the master)
+    // to all of the agent nodes
+    commandAllAgentsPublisher = nodeHandle.advertise<std_msgs::Int32>("commandAllAgents", 1);
+
+    // Publisher for sending a request from here (the master) to all "Parameter Service" nodes
+    // that it should re-load parameters from the YAML file for the controllers.
+    // > This is recieved and acted on by both Coordinate and Agent type "Parameter Services",
+    // > A coordinator type "Parameter Service" will subsequently request the agents to fetch
+    //   the parameters from itself.
+    // > A agent type "Parameter Service" will subsequently request its own agent to fetch
+    //   the parameters from itself.
+    requestLoadControllerYamlPublisher = nodeHandle.advertise<std_msgs::Int32>("requestLoadControllerYaml", 1);
+    
+    // Initialise the publisher for sending a request from here (the master)
+    // to all of the agents nodes that they should (re/dis)-connect from
+    // the Crazy-Radio
+    crazyRadioCommandAllAgentsPublisher = nodeHandle.advertise<std_msgs::Int32>("crazyRadioCommandAllAgents", 1);
     #endif
 }
 
@@ -962,9 +983,316 @@ void MainGUIWindow::on_comboBoxCFs_currentTextChanged(const QString &arg1)
 }
 
 
+
+
+
+//    ----------------------------------------------------------------------------------
+//     CCCC   OOO   M   M  M   M    A    N   N  DDDD          A    L      L
+//    C      O   O  MM MM  MM MM   A A   NN  N  D   D        A A   L      L
+//    C      O   O  M M M  M M M  A   A  N N N  D   D       A   A  L      L
+//    C      O   O  M   M  M   M  AAAAA  N  NN  D   D       AAAAA  L      L
+//     CCCC   OOO   M   M  M   M  A   A  N   N  DDDD        A   A  LLLLL  LLLLL
+//
+//    BBBB   U   U  TTTTT  TTTTT   OOO   N   N   SSSS
+//    B   B  U   U    T      T    O   O  NN  N  S
+//    BBBB   U   U    T      T    O   O  N N N   SSS
+//    B   B  U   U    T      T    O   O  N  NN      S
+//    BBBB    UUU     T      T     OOO   N   N  SSSS
+//    ----------------------------------------------------------------------------------
+
+
+// For the buttons that commands all of the agent nodes to:
+// > (RE)CONNECT THE RADIO
+void MainGUIWindow::on_all_connect_button_clicked()
+{
+    std_msgs::Int32 msg;
+    msg.data = CMD_RECONNECT;
+    crazyRadioCommandAllAgentsPublisher.publish(msg);
+}
+// > DISCONNECT THE RADIO
+void MainGUIWindow::on_all_disconnect_button_clicked()
+{
+    std_msgs::Int32 msg;
+    msg.data = CMD_DISCONNECT;
+    crazyRadioCommandAllAgentsPublisher.publish(msg);
+}
+// > TAKE-OFF
+void MainGUIWindow::on_all_take_off_button_clicked()
+{
+    std_msgs::Int32 msg;
+    msg.data = CMD_CRAZYFLY_TAKE_OFF;
+    commandAllAgentsPublisher.publish(msg);
+}
+// > LAND
+void MainGUIWindow::on_all_land_button_clicked()
+{
+    std_msgs::Int32 msg;
+    msg.data = CMD_CRAZYFLY_LAND;
+    commandAllAgentsPublisher.publish(msg);
+}
+// > MOTORS OFF
 void MainGUIWindow::on_all_motors_off_button_clicked()
 {
     std_msgs::Int32 msg;
     msg.data = CMD_CRAZYFLY_MOTORS_OFF;
-    emergencyStopPublisher.publish(msg);
+    commandAllAgentsPublisher.publish(msg);
+    //emergencyStopPublisher.publish(msg);
+}
+// > ENABLE SAFE CONTROLLER
+void MainGUIWindow::on_all_enable_safe_controller_button_clicked()
+{
+    std_msgs::Int32 msg;
+    msg.data = CMD_USE_SAFE_CONTROLLER;
+    commandAllAgentsPublisher.publish(msg);
+}
+// > ENABLE SAFE CONTROLLER
+void MainGUIWindow::on_all_enable_custom_controller_button_clicked()
+{
+    std_msgs::Int32 msg;
+    msg.data = CMD_USE_CUSTOM_CONTROLLER;
+    commandAllAgentsPublisher.publish(msg);
+}
+// > LOAD THE YAML PARAMETERS FOR THE SAFE CONTROLLER
+void MainGUIWindow::on_all_load_safe_controller_yaml_own_agent_button_clicked()
+{
+	// Disable the button
+	ui->all_load_safe_controller_yaml_own_agent_button->setEnabled(false);
+	ui->all_load_safe_controller_yaml_coordinator_button->setEnabled(false);
+
+	// Send the message that the YAML paremters should be loaded
+    std_msgs::Int32 msg;
+    msg.data = LOAD_YAML_SAFE_CONTROLLER_AGENT;
+    requestLoadControllerYamlPublisher.publish(msg);
+
+    // 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_safe_controller = nodeHandle.createTimer(ros::Duration(1.5), &MainGUIWindow::safeYamlFileTimerCallback, this, true);
+}
+// > LOAD THE YAML PARAMETERS FOR THE CUSTOM CONTROLLER
+void MainGUIWindow::on_all_load_custom_controller_yaml_own_agent_button_clicked()
+{
+	// Disable the button
+	ui->all_load_custom_controller_yaml_own_agent_button->setEnabled(false);
+	ui->all_load_custom_controller_yaml_coordinator_button->setEnabled(false);
+
+	// Send the message that the YAML paremters should be loaded
+    std_msgs::Int32 msg;
+    msg.data = LOAD_YAML_CUSTOM_CONTROLLER_AGENT;
+    requestLoadControllerYamlPublisher.publish(msg);
+
+    // 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_custom_controller = nodeHandle.createTimer(ros::Duration(1.5), &MainGUIWindow::customYamlFileTimerCallback, this, true);
+
+}
+// > SEND THE YAML PARAMETERS FOR THE SAFE CONTROLLER
+void MainGUIWindow::on_all_load_safe_controller_yaml_coordinator_button_clicked()
+{
+	// Disable the button
+	ui->all_load_safe_controller_yaml_own_agent_button->setEnabled(false);
+	ui->all_load_safe_controller_yaml_coordinator_button->setEnabled(false);
+
+	// Send the message that the YAML paremters should be loaded
+    // by the coordinator (and then the agent informed)
+    std_msgs::Int32 msg;
+    msg.data = LOAD_YAML_SAFE_CONTROLLER_COORDINATOR;
+    requestLoadControllerYamlPublisher.publish(msg);
+
+    // 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_safe_controller = nodeHandle.createTimer(ros::Duration(1.5), &MainGUIWindow::safeYamlFileTimerCallback, this, true);
+}
+// > SEND THE YAML PARAMETERS FOR THE CUSTOM CONTROLLER
+void MainGUIWindow::on_all_load_custom_controller_yaml_coordinator_button_clicked()
+{
+	// Disable the button
+	ui->all_load_custom_controller_yaml_own_agent_button->setEnabled(false);
+	ui->all_load_custom_controller_yaml_coordinator_button->setEnabled(false);
+
+    // Send the message that the YAML paremters should be loaded
+    // by the coordinator (and then the agent informed)
+    std_msgs::Int32 msg;
+    msg.data = LOAD_YAML_CUSTOM_CONTROLLER_COORDINATOR;
+    requestLoadControllerYamlPublisher.publish(msg);
+
+    // 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_custom_controller = nodeHandle.createTimer(ros::Duration(1.5), &MainGUIWindow::customYamlFileTimerCallback, this, true);
+
+}
+// > CALLBACK TO RE-ENABLE THE SAFE CONTROLLER YAML BUTTONS
+void MainGUIWindow::safeYamlFileTimerCallback(const ros::TimerEvent&)
+{
+    // Enble the "load" and the "send" safe controller YAML button again
+    ui->all_load_safe_controller_yaml_own_agent_button->setEnabled(true);
+	ui->all_load_safe_controller_yaml_coordinator_button->setEnabled(true);
+}
+// > CALLBACK TO RE-ENABLE THE CUSTOM CONTROLLER YAML BUTTONS
+void MainGUIWindow::customYamlFileTimerCallback(const ros::TimerEvent&)
+{
+    // Enble the "load" and the "send" custom controller YAML button again
+    ui->all_load_custom_controller_yaml_own_agent_button->setEnabled(true);
+	ui->all_load_custom_controller_yaml_coordinator_button->setEnabled(true);
+}
+
+/*
+// > CALLBACK TO SEND THE CUSTOM CONTROLLER YAML PARAMETERS AS A MESSAGE
+void MainGUIWindow::customSendYamlAsMessageTimerCallback(const ros::TimerEvent&)
+{
+	// Load the CUSTOM controller YAML parameters from file into a message for
+	// sending directly to the "CustonControllerService" node of every agent
+
+	ros::NodeHandle nodeHandle("~");
+
+	// Instaniate a local variable of the message type
+	CustomControllerYAML customControllerYamlMessage;
+
+	// Load the data directly from the YAML file into the message
+
+	// > For the mass
+	customControllerYamlMessage.mass = MainGUIWindow::getParameterFloat(nodeHandle, "mass");
+
+    // Debugging this this works
+    ROS_INFO_STREAM("DEBUGGING: mass loaded from the custom controller YAML = " << customControllerYamlMessage.mass );
+
+	// > For the control_frequency
+	customControllerYamlMessage.control_frequency = MainGUIWindow::getParameterFloat(nodeHandle, "control_frequency");
+
+	// > For the motorPoly coefficients
+    std::vector<float> temp_motorPoly(3);
+	MainGUIWindow::getParameterFloatVector(nodeHandle, "motorPoly", temp_motorPoly, 3);
+    // Copy the loaded data into the message
+    for ( int i=0 ; i<3 ; i++ )
+    {
+        customControllerYamlMessage.motorPoly.push_back( temp_motorPoly[i] );
+    }
+
+    // > For the boolean about whether to execute the convert into body frame function
+    customControllerYamlMessage.shouldPerformConvertIntoBodyFrame = MainGUIWindow::getParameterBool(nodeHandle, "shouldPerformConvertIntoBodyFrame");
+
+    // > For the boolean about publishing the agents current position
+	customControllerYamlMessage.shouldPublishCurrent_xyz_yaw = MainGUIWindow::getParameterBool(nodeHandle, "shouldPublishCurrent_xyz_yaw");
+
+	// > For the boolean about following another agent
+	customControllerYamlMessage.shouldFollowAnotherAgent = MainGUIWindow::getParameterBool(nodeHandle, "shouldFollowAnotherAgent");
+
+	// > For the ordered agent ID's for following eachother in a line
+    std::vector<int> temp_follow_in_a_line_agentIDs(100);
+	int temp_number_of_agents_in_a_line = MainGUIWindow::getParameterIntVectorWithUnknownLength(nodeHandle, "follow_in_a_line_agentIDs", temp_follow_in_a_line_agentIDs);
+	// > Double check that the sizes agree
+    if ( temp_number_of_agents_in_a_line != temp_follow_in_a_line_agentIDs.size() )
+    {
+    	// Update the user if the sizes don't agree
+    	ROS_ERROR_STREAM("parameter 'follow_in_a_line_agentIDs' was loaded with two different lengths, " << temp_number_of_agents_in_a_line << " versus " << temp_follow_in_a_line_agentIDs.size() );
+    }
+    // Copy the loaded data into the message
+    for ( int i=0 ; i<temp_number_of_agents_in_a_line ; i++ )
+    {
+        customControllerYamlMessage.follow_in_a_line_agentIDs.push_back( temp_follow_in_a_line_agentIDs[i] );
+    }    
+
+    // Publish the message containing the loaded YAML parameters
+    customYAMLasMessagePublisher.publish(customControllerYamlMessage);
+
+	// Start a timer which will enable the button in its callback
+    m_timer_yaml_file_for_custom_controller = nodeHandle.createTimer(ros::Duration(0.5), &MainGUIWindow::customYamlFileTimerCallback, this, true);
+}
+*/
+
+
+
+
+//    ----------------------------------------------------------------------------------
+//    L       OOO     A    DDDD        Y   Y    A    M   M  L
+//    L      O   O   A A   D   D        Y Y    A A   MM MM  L
+//    L      O   O  A   A  D   D         Y    A   A  M M M  L
+//    L      O   O  AAAAA  D   D         Y    AAAAA  M   M  L
+//    LLLLL   OOO   A   A  DDDD          Y    A   A  M   M  LLLLL
+//
+//    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
+//    ----------------------------------------------------------------------------------
+
+// load parameters from corresponding YAML file
+//
+// This function DOES NOT NEED TO BE edited for successful completion of the PPS exercise
+float MainGUIWindow::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 MainGUIWindow::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 MainGUIWindow::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 MainGUIWindow::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 MainGUIWindow::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 MainGUIWindow::getParameterBool(ros::NodeHandle& nodeHandle, std::string name)
+{
+    bool val;
+    if(!nodeHandle.getParam(name, val))
+    {
+        ROS_ERROR_STREAM("missing parameter '" << name << "'");
+    }
+    return val;
 }
diff --git a/pps_ws/src/d_fall_pps/GUI_Qt/CrazyFlyGUI/src/mainguiwindow.ui b/pps_ws/src/d_fall_pps/GUI_Qt/CrazyFlyGUI/src/mainguiwindow.ui
index 725dbd1e12d9720528e67b6643f4fbd65ff6c58d..128a1cb90506437117454638422083c2831abe9a 100755
--- a/pps_ws/src/d_fall_pps/GUI_Qt/CrazyFlyGUI/src/mainguiwindow.ui
+++ b/pps_ws/src/d_fall_pps/GUI_Qt/CrazyFlyGUI/src/mainguiwindow.ui
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>866</width>
-    <height>820</height>
+    <width>1176</width>
+    <height>1180</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -250,6 +250,24 @@
       <layout class="QVBoxLayout" name="verticalLayout_2">
        <item>
         <widget class="QPushButton" name="all_motors_off_button">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>50</height>
+          </size>
+         </property>
+         <property name="maximumSize">
+          <size>
+           <width>16777215</width>
+           <height>100</height>
+          </size>
+         </property>
          <property name="text">
           <string>All motors OFF</string>
          </property>
@@ -452,6 +470,316 @@
            </item>
           </layout>
          </widget>
+         <widget class="QWidget" name="tab">
+          <attribute name="title">
+           <string>Command all</string>
+          </attribute>
+          <layout class="QGridLayout" name="gridLayout_2">
+           <item row="1" column="0">
+            <widget class="QPushButton" name="all_disconnect_button">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>50</height>
+              </size>
+             </property>
+             <property name="maximumSize">
+              <size>
+               <width>16777215</width>
+               <height>100</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>Disconnect</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="1">
+            <widget class="QPushButton" name="all_connect_button">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>50</height>
+              </size>
+             </property>
+             <property name="maximumSize">
+              <size>
+               <width>16777215</width>
+               <height>100</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>Reconnect</string>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="0" colspan="2">
+            <widget class="QLabel" name="all_flying_state_label">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>20</height>
+              </size>
+             </property>
+             <property name="maximumSize">
+              <size>
+               <width>16777215</width>
+               <height>40</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>FLYING STATE</string>
+             </property>
+             <property name="alignment">
+              <set>Qt::AlignBottom|Qt::AlignHCenter</set>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="0">
+            <widget class="QPushButton" name="all_take_off_button">
+             <property name="sizePolicy">
+              <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+               <horstretch>0</horstretch>
+               <verstretch>0</verstretch>
+              </sizepolicy>
+             </property>
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>50</height>
+              </size>
+             </property>
+             <property name="maximumSize">
+              <size>
+               <width>16777215</width>
+               <height>100</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>Take off</string>
+             </property>
+            </widget>
+           </item>
+           <item row="5" column="0">
+            <widget class="QPushButton" name="all_enable_safe_controller_button">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>50</height>
+              </size>
+             </property>
+             <property name="maximumSize">
+              <size>
+               <width>16777215</width>
+               <height>100</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>Enable Safe</string>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="1">
+            <widget class="QPushButton" name="all_land_button">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>50</height>
+              </size>
+             </property>
+             <property name="maximumSize">
+              <size>
+               <width>16777215</width>
+               <height>100</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>Land</string>
+             </property>
+            </widget>
+           </item>
+           <item row="5" column="1">
+            <widget class="QPushButton" name="all_enable_custom_controller_button">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>50</height>
+              </size>
+             </property>
+             <property name="maximumSize">
+              <size>
+               <width>16777215</width>
+               <height>100</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>Enable Custom</string>
+             </property>
+            </widget>
+           </item>
+           <item row="8" column="1">
+            <widget class="QPushButton" name="all_load_custom_controller_yaml_own_agent_button">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>50</height>
+              </size>
+             </property>
+             <property name="maximumSize">
+              <size>
+               <width>16777215</width>
+               <height>100</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>Load Custom YAML</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="0" colspan="2">
+            <widget class="QLabel" name="all_radio_label">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>20</height>
+              </size>
+             </property>
+             <property name="maximumSize">
+              <size>
+               <width>16777215</width>
+               <height>40</height>
+              </size>
+             </property>
+             <property name="lineWidth">
+              <number>1</number>
+             </property>
+             <property name="text">
+              <string>CRAZYRADIO</string>
+             </property>
+             <property name="alignment">
+              <set>Qt::AlignBottom|Qt::AlignHCenter</set>
+             </property>
+            </widget>
+           </item>
+           <item row="6" column="0" colspan="2">
+            <widget class="QLabel" name="all_yaml_label">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>20</height>
+              </size>
+             </property>
+             <property name="maximumSize">
+              <size>
+               <width>16777215</width>
+               <height>40</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>LOAD YAML PARAMETERS</string>
+             </property>
+             <property name="alignment">
+              <set>Qt::AlignBottom|Qt::AlignHCenter</set>
+             </property>
+            </widget>
+           </item>
+           <item row="10" column="0">
+            <widget class="QPushButton" name="all_load_safe_controller_yaml_coordinator_button">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>50</height>
+              </size>
+             </property>
+             <property name="maximumSize">
+              <size>
+               <width>16777215</width>
+               <height>100</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>Load Safe YAML</string>
+             </property>
+            </widget>
+           </item>
+           <item row="10" column="1">
+            <widget class="QPushButton" name="all_load_custom_controller_yaml_coordinator_button">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>50</height>
+              </size>
+             </property>
+             <property name="maximumSize">
+              <size>
+               <width>16777215</width>
+               <height>100</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>Load Custom YAML</string>
+             </property>
+            </widget>
+           </item>
+           <item row="7" column="0" colspan="2">
+            <widget class="QLabel" name="all_yaml_agent_label">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>30</height>
+              </size>
+             </property>
+             <property name="maximumSize">
+              <size>
+               <width>16777215</width>
+               <height>30</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>&gt; From agenet's local file</string>
+             </property>
+            </widget>
+           </item>
+           <item row="9" column="0" colspan="2">
+            <widget class="QLabel" name="all_yaml_coordinator_label">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>30</height>
+              </size>
+             </property>
+             <property name="maximumSize">
+              <size>
+               <width>16777215</width>
+               <height>30</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>&gt; From coordinator's file</string>
+             </property>
+            </widget>
+           </item>
+           <item row="8" column="0">
+            <widget class="QPushButton" name="all_load_safe_controller_yaml_own_agent_button">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>50</height>
+              </size>
+             </property>
+             <property name="maximumSize">
+              <size>
+               <width>16777215</width>
+               <height>100</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>Load Safe YAML</string>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
         </widget>
        </item>
       </layout>
@@ -501,7 +829,7 @@
     <rect>
      <x>0</x>
      <y>0</y>
-     <width>866</width>
+     <width>1176</width>
      <height>25</height>
     </rect>
    </property>
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 13a572c9e5dbfc39b98351a4836f371400ecb678..be4888a000e4ac892adc5da572790d1404c9a286 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
@@ -1,4 +1,4 @@
-//    Copyright (C) 2017, ETH Zurich, D-ITET, Angel Romero
+//    Copyright (C) 2017, ETH Zurich, D-ITET, Paul Beuchat, Angel Romero
 //
 //    This file is part of D-FaLL-System.
 //    
@@ -45,21 +45,23 @@
 #include "d_fall_pps/Setpoint.h"
 
 
-// tipes of controllers being used:
+// Types of controllers being used:
 #define SAFE_CONTROLLER   0
 #define CUSTOM_CONTROLLER 1
 
-// commands for CrazyRadio
+// Commands for CrazyRadio
 #define CMD_RECONNECT  0
 #define CMD_DISCONNECT 1
 
-
 // CrazyRadio states:
 #define CONNECTED        0
 #define CONNECTING       1
 #define DISCONNECTED     2
 
-// Commands for PPSClient
+// The constants that "command" changes in the
+// operation state of this agent. These "commands"
+// are sent from this GUI node to the "PPSClient"
+// node where the command is enacted
 #define CMD_USE_SAFE_CONTROLLER   1
 #define CMD_USE_CUSTOM_CONTROLLER 2
 #define CMD_CRAZYFLY_TAKE_OFF     3
@@ -72,12 +74,17 @@
 #define STATE_FLYING     3
 #define STATE_LAND       4
 
-// battery states
-
+// Battery states
 #define BATTERY_STATE_NORMAL 0
 #define BATTERY_STATE_LOW    1
 
+// For which controller parameters to load
+#define LOAD_YAML_SAFE_CONTROLLER_AGENT           1
+#define LOAD_YAML_CUSTOM_CONTROLLER_AGENT         2
+#define LOAD_YAML_SAFE_CONTROLLER_COORDINATOR     3
+#define LOAD_YAML_CUSTOM_CONTROLLER_COORDINATOR   4
 
+// Universal constants
 #define PI 3.141592653589
 
 #define RAD2DEG 180.0/PI
@@ -117,6 +124,9 @@ private slots:
 
     void on_en_safe_controller_clicked();
 
+    void on_customButton_1_clicked();
+    void on_customButton_2_clicked();
+    void on_customButton_3_clicked();
 private:
     Ui::MainWindow *ui;
 
@@ -127,7 +137,8 @@ private:
 
     std::string m_ros_namespace;
 
-    ros::Timer m_custom_timer_yaml_file;
+    ros::Timer m_timer_yaml_file_for_safe_controller;
+    ros::Timer m_timer_yaml_file_for_custom_controlller;
 
     int m_student_id;
     CrazyflieContext m_context;
@@ -150,10 +161,22 @@ private:
     ros::Publisher customSetpointPublisher;
     ros::Subscriber customSetpointSubscriber;
 
+    ros::Publisher PPSClientStudentCustomButtonPublisher;
+
     ros::Subscriber DBChangedSubscriber;
 
-    ros::Publisher customYAMLloadedPublisher;
-    ros::Publisher safeYAMLloadedPublisher;
+
+
+    // > For publishing a message that requests the
+    //   YAML parameters to be re-loaded from file
+    // > The message contents specify which controller
+    //   the parameters should be re-loaded for
+    ros::Publisher requestLoadControllerYamlPublisher;
+
+    // Subscriber for locking the load the controller YAML
+    // parameters when the Coordintor GUI requests a load
+    ros::Subscriber requestLoadControllerYaml_from_my_GUI_Subscriber;
+
 
     ros::Subscriber controllerUsedSubscriber;
 
@@ -168,6 +191,7 @@ private:
     void DBChangedCallback(const std_msgs::Int32& msg);
     void customYamlFileTimerCallback(const ros::TimerEvent&);
     void safeYamlFileTimerCallback(const ros::TimerEvent&);
+    void requestLoadControllerYaml_from_my_GUI_Callback(const std_msgs::Int32& msg);
     void controllerUsedChangedCallback(const std_msgs::Int32& msg);
     void batteryStateChangedCallback(const std_msgs::Int32& msg);
 
@@ -184,6 +208,9 @@ private:
     void highlightSafeControllerTab();
     void highlightCustomControllerTab();
 
+    bool setpointInsideBox(Setpoint setpoint, CrazyflieContext context);
+    Setpoint correctSetpointBox(Setpoint setpoint, CrazyflieContext context);
+
     const std::vector<float> m_cutoff_voltages {3.1966,        3.2711,        3.3061,        3.3229,        3.3423,        3.3592,        3.3694,        3.385,        3.4006,        3.4044,        3.4228,        3.4228,        3.4301,        3.4445,        3.4531,        3.4677,        3.4705,        3.4712,        3.4756,        3.483,        3.4944,        3.5008,        3.5008,        3.5084,        3.511,        3.5122,        3.5243,        3.5329,        3.5412,        3.5529,        3.5609,        3.5625,        3.5638,        3.5848,        3.6016,        3.6089,        3.6223,        3.628,        3.6299,        3.6436,        3.6649,        3.6878,        3.6983,        3.7171,        3.7231,        3.7464,        3.7664,        3.7938,        3.8008,        3.816,        3.8313,        3.8482,        3.866,        3.8857,        3.8984,        3.9159,        3.9302,        3.9691,        3.997,        4.14    };
 };
 
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 2fc1e60f5fdf52141bded27293b286c33d8f250e..d86a3dd007e7c682d4b1049f6f46d01f54b9a2a1 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
@@ -1,4 +1,4 @@
-//    Copyright (C) 2017, ETH Zurich, D-ITET, Angel Romero
+//    Copyright (C) 2017, ETH Zurich, D-ITET, Paul Beuchat, Angel Romero
 //
 //    This file is part of D-FaLL-System.
 //    
@@ -42,6 +42,8 @@
 
 #include "d_fall_pps/ViconData.h"
 
+#include "d_fall_pps/CustomButton.h"
+
 MainWindow::MainWindow(int argc, char **argv, QWidget *parent) :
     QMainWindow(parent),
     ui(new Ui::MainWindow),
@@ -56,7 +58,7 @@ MainWindow::MainWindow(int argc, char **argv, QWidget *parent) :
     setCrazyRadioStatus(DISCONNECTED);
 
     m_ros_namespace = ros::this_node::getNamespace();
-    ROS_INFO("namespace: %s", m_ros_namespace.c_str());
+    ROS_INFO("Student GUI node namespace: %s", m_ros_namespace.c_str());
 
     qRegisterMetaType<ptrToMessage>("ptrToMessage");
     QObject::connect(m_rosNodeThread, SIGNAL(newViconData(const ptrToMessage&)), this, SLOT(updateNewViconData(const ptrToMessage&)));
@@ -83,15 +85,27 @@ MainWindow::MainWindow(int argc, char **argv, QWidget *parent) :
 
     ros::NodeHandle my_nodeHandle("~");
     controllerSetpointPublisher = my_nodeHandle.advertise<Setpoint>("ControllerSetpoint", 1);
-    customYAMLloadedPublisher = my_nodeHandle.advertise<std_msgs::Int32>("customYAMLloaded", 1);
-    safeYAMLloadedPublisher = my_nodeHandle.advertise<std_msgs::Int32>("safeYAMLloaded", 1);
 
 
     // communication with PPS Client, just to make it possible to communicate through terminal also we use PPSClient's name
-    ros::NodeHandle nh_PPSClient(m_ros_namespace + "/PPSClient");
+    //ros::NodeHandle nh_PPSClient(m_ros_namespace + "/PPSClient");
+    ros::NodeHandle nh_PPSClient("PPSClient");
     crazyRadioCommandPublisher = nh_PPSClient.advertise<std_msgs::Int32>("crazyRadioCommand", 1);
     PPSClientCommandPublisher = nh_PPSClient.advertise<std_msgs::Int32>("Command", 1);
 
+    PPSClientStudentCustomButtonPublisher = nh_PPSClient.advertise<CustomButton>("StudentCustomButton", 1);
+
+
+    // > For publishing a message that requests the
+    //   YAML parameters to be re-loaded from file
+    // > The message contents specify which controller
+    //   the parameters should be re-loaded for
+    requestLoadControllerYamlPublisher = nh_PPSClient.advertise<std_msgs::Int32>("requestLoadControllerYaml", 1);
+
+
+    // Subscriber for locking the load the controller YAML
+    // parameters when the Coordintor GUI requests a load
+    requestLoadControllerYaml_from_my_GUI_Subscriber = nodeHandle.subscribe("/my_GUI/requestLoadControllerYaml", 1, &MainWindow::requestLoadControllerYaml_from_my_GUI_Callback, this);
 
     // First get student ID
     if(!nh_PPSClient.getParam("studentID", m_student_id))
@@ -105,27 +119,32 @@ MainWindow::MainWindow(int argc, char **argv, QWidget *parent) :
 
 
 
-    std::vector<float> default_setpoint(4);
-    ros::NodeHandle nh_safeControllerService(m_ros_namespace + "/SafeControllerService");
 
-    ROS_INFO_STREAM(m_ros_namespace << "/SafeControllerService");
+    // Load default setpoint from the "SafeController" namespace of the "ParameterService"
+    std::vector<float> default_setpoint(4);
+    ros::NodeHandle nodeHandle_to_own_agent_parameter_service("ParameterService");
+    ros::NodeHandle nodeHandle_for_safeController(nodeHandle_to_own_agent_parameter_service, "SafeController");
 
-    if(!nh_safeControllerService.getParam("defaultSetpoint", default_setpoint))
+    if(!nodeHandle_for_safeController.getParam("defaultSetpoint", default_setpoint))
     {
-        ROS_ERROR_STREAM("couldn't find parameter 'defaultSetpoint'");
+        ROS_ERROR_STREAM("The StudentGUI could not find parameter 'defaultSetpoint', as called from main(...)");
     }
 
-
+    // Copy the default setpoint into respective text fields of the GUI
     ui->current_setpoint_x->setText(QString::number(default_setpoint[0]));
     ui->current_setpoint_y->setText(QString::number(default_setpoint[1]));
     ui->current_setpoint_z->setText(QString::number(default_setpoint[2]));
     ui->current_setpoint_yaw->setText(QString::number(default_setpoint[3]));
 
+
     disableGUI();
     highlightSafeControllerTab();
     ui->label_battery->setStyleSheet("QLabel { color : red; }");
     m_battery_state = BATTERY_STATE_NORMAL;
 
+    ui->error_label->setStyleSheet("QLabel { color : red; }");
+    ui->error_label->clear();
+
     initialize_custom_setpoint();
 }
 
@@ -445,12 +464,43 @@ void MainWindow::on_motors_OFF_button_clicked()
 void MainWindow::on_set_setpoint_button_clicked()
 {
     Setpoint msg_setpoint;
-    msg_setpoint.x = (ui->new_setpoint_x->text()).toFloat();
-    msg_setpoint.y = (ui->new_setpoint_y->text()).toFloat();
-    msg_setpoint.z = (ui->new_setpoint_z->text()).toFloat();
-    msg_setpoint.yaw = (ui->new_setpoint_yaw->text()).toFloat() * DEG2RAD;
+
+    // initialize setpoint to previous one
+
+    msg_setpoint.x = (ui->current_setpoint_x->text()).toFloat();
+    msg_setpoint.y = (ui->current_setpoint_y->text()).toFloat();
+    msg_setpoint.z = (ui->current_setpoint_z->text()).toFloat();
+    msg_setpoint.yaw = (ui->current_setpoint_yaw->text()).toFloat();
+
+    if(!ui->new_setpoint_x->text().isEmpty())
+        msg_setpoint.x = (ui->new_setpoint_x->text()).toFloat();
+
+    if(!ui->new_setpoint_y->text().isEmpty())
+        msg_setpoint.y = (ui->new_setpoint_y->text()).toFloat();
+
+    if(!ui->new_setpoint_z->text().isEmpty())
+        msg_setpoint.z = (ui->new_setpoint_z->text()).toFloat();
+
+    if(!ui->new_setpoint_yaw->text().isEmpty())
+        msg_setpoint.yaw = (ui->new_setpoint_yaw->text()).toFloat() * DEG2RAD;
+
+
+    if(!setpointInsideBox(msg_setpoint, m_context))
+    {
+        ROS_INFO("Corrected setpoint, was out of bounds");
+
+        // correct the setpoint given the box size
+        msg_setpoint = correctSetpointBox(msg_setpoint, m_context);
+        ui->error_label->setText("Setpoint is outside safety box");
+    }
+    else
+    {
+        ui->error_label->clear();
+    }
 
     this->controllerSetpointPublisher.publish(msg_setpoint);
+
+    ROS_INFO_STREAM("Setpoint change clicked with:" << msg_setpoint.x << ", "<< msg_setpoint.y << ", "<< msg_setpoint.z << ", "<< msg_setpoint.yaw);
 }
 
 void MainWindow::initialize_custom_setpoint()
@@ -467,12 +517,24 @@ void MainWindow::initialize_custom_setpoint()
 void MainWindow::on_set_setpoint_button_2_clicked()
 {
     Setpoint msg_setpoint;
-    msg_setpoint.x = (ui->new_setpoint_x_2->text()).toFloat();
-    msg_setpoint.y = (ui->new_setpoint_y_2->text()).toFloat();
-    msg_setpoint.z = (ui->new_setpoint_z_2->text()).toFloat();
-    msg_setpoint.yaw = (ui->new_setpoint_yaw_2->text()).toFloat() * DEG2RAD;
+
+    msg_setpoint.x = (ui->current_setpoint_x_2->text()).toFloat();
+    msg_setpoint.y = (ui->current_setpoint_y_2->text()).toFloat();
+    msg_setpoint.z = (ui->current_setpoint_z_2->text()).toFloat();
+    msg_setpoint.yaw = (ui->current_setpoint_yaw_2->text()).toFloat();
+
+    if(!ui->new_setpoint_x_2->text().isEmpty())
+        msg_setpoint.x = (ui->new_setpoint_x_2->text()).toFloat();
+    if(!ui->new_setpoint_y_2->text().isEmpty())
+        msg_setpoint.y = (ui->new_setpoint_y_2->text()).toFloat();
+    if(!ui->new_setpoint_z_2->text().isEmpty())
+        msg_setpoint.z = (ui->new_setpoint_z_2->text()).toFloat();
+    if(!ui->new_setpoint_yaw_2->text().isEmpty())
+        msg_setpoint.yaw = (ui->new_setpoint_yaw_2->text()).toFloat() * DEG2RAD;
 
     this->customSetpointPublisher.publish(msg_setpoint);
+
+    ROS_INFO_STREAM("Setpoint change clicked with:" << msg_setpoint.x << ", "<< msg_setpoint.y << ", "<< msg_setpoint.z << ", "<< msg_setpoint.yaw);
 }
 
 void MainWindow::on_RF_disconnect_button_clicked()
@@ -483,68 +545,124 @@ void MainWindow::on_RF_disconnect_button_clicked()
     ROS_INFO("command disconnect published");
 }
 
-void MainWindow::safeYamlFileTimerCallback(const ros::TimerEvent&)
-{
-    // send msg that says that parameters have changed in YAML file
-    std_msgs::Int32 msg;
-    msg.data = 1;
-    this->safeYAMLloadedPublisher.publish(msg);
-    ROS_INFO("YALMloaded published");
-    ui->load_safe_yaml_button->setEnabled(true);
-}
+
+
 
 void MainWindow::on_load_safe_yaml_button_clicked()
 {
+    // Set the "load safe yaml" button to be disabled
     ui->load_safe_yaml_button->setEnabled(false);
+
+    // Send a message requesting the parameters from the YAML
+    // file to be reloaded for the safe controller
+    std_msgs::Int32 msg;
+    msg.data = LOAD_YAML_SAFE_CONTROLLER_AGENT;
+    this->requestLoadControllerYamlPublisher.publish(msg);
+    ROS_INFO("Request load of safe 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_custom_timer_yaml_file = nodeHandle.createTimer(ros::Duration(1), &MainWindow::safeYamlFileTimerCallback, this, true);
+    m_timer_yaml_file_for_safe_controller = nodeHandle.createTimer(ros::Duration(1.5), &MainWindow::safeYamlFileTimerCallback, this, true);
+}
 
-    std::string d_fall_pps_path = ros::package::getPath("d_fall_pps");
-    ROS_INFO_STREAM(d_fall_pps_path);
+void MainWindow::safeYamlFileTimerCallback(const ros::TimerEvent&)
+{
+    // Enble the "load safe yaml" button again
+    ui->load_safe_yaml_button->setEnabled(true);
+}
 
-    // first, reload the name of the custom controller:
-    std::string cmd = "rosparam load " + d_fall_pps_path + "/param/ClientConfig.yaml " + m_ros_namespace + "/PPSClient";
-    system(cmd.c_str());
-    ROS_INFO_STREAM(cmd);
 
-    // then, reload the parameters of the custom controller:
-    cmd = "rosparam load " + d_fall_pps_path + "/param/SafeController.yaml " + m_ros_namespace + "/SafeControllerService";
-    system(cmd.c_str());
-    ROS_INFO_STREAM(cmd);
-}
 
 
 
-void MainWindow::customYamlFileTimerCallback(const ros::TimerEvent&)
+void MainWindow::on_load_custom_yaml_button_clicked()
 {
-    // send msg that says that parameters have changed in YAML file
+    // Set the "load custom yaml" button to be disabled
+    ui->load_custom_yaml_button->setEnabled(false);
+
+    // Send a message requesting the parameters from the YAML
+    // file to be reloaded for the custom controller
     std_msgs::Int32 msg;
-    msg.data = 1;
-    this->customYAMLloadedPublisher.publish(msg);
-    ROS_INFO("YALMloaded published");
+    msg.data = LOAD_YAML_CUSTOM_CONTROLLER_AGENT;
+    this->requestLoadControllerYamlPublisher.publish(msg);
+    ROS_INFO("Request load of custom 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_custom_controlller = nodeHandle.createTimer(ros::Duration(1.5), &MainWindow::customYamlFileTimerCallback, this, true);    
+}
+
+void MainWindow::customYamlFileTimerCallback(const ros::TimerEvent&)
+{
+    // Enble the "load custom yaml" button again
     ui->load_custom_yaml_button->setEnabled(true);
 }
 
-void MainWindow::on_load_custom_yaml_button_clicked()
+
+
+
+
+void MainWindow::requestLoadControllerYaml_from_my_GUI_Callback(const std_msgs::Int32& msg)
 {
-    ui->load_custom_yaml_button->setEnabled(false);
+    // Extract from the "msg" for which controller the YAML
+    // parameters should be loaded
+    int controller_to_load_yaml = msg.data;
+
+    // Create the "nodeHandle" needed in the switch cases below
     ros::NodeHandle nodeHandle("~");
-    m_custom_timer_yaml_file = nodeHandle.createTimer(ros::Duration(1), &MainWindow::customYamlFileTimerCallback, this, true);
 
-    std::string d_fall_pps_path = ros::package::getPath("d_fall_pps");
-    ROS_INFO_STREAM(d_fall_pps_path);
+    // Switch between loading for the different controllers
+    switch(controller_to_load_yaml)
+    {
+        case LOAD_YAML_SAFE_CONTROLLER_AGENT:
+        case LOAD_YAML_SAFE_CONTROLLER_COORDINATOR:
+            // Set the "load safe yaml" button to be disabled
+            ui->load_safe_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_safe_controller = nodeHandle.createTimer(ros::Duration(1.5), &MainWindow::safeYamlFileTimerCallback, this, true);
+
+            break;
+
+        case LOAD_YAML_CUSTOM_CONTROLLER_AGENT:
+        case LOAD_YAML_CUSTOM_CONTROLLER_COORDINATOR:
+            // Set the "load custom yaml" button to be disabled
+            ui->load_custom_yaml_button->setEnabled(false);
 
-    // first, reload the name of the custom controller:
-    std::string cmd = "rosparam load " + d_fall_pps_path + "/param/ClientConfig.yaml " + m_ros_namespace + "/PPSClient";
-    system(cmd.c_str());
-    ROS_INFO_STREAM(cmd);
+            // 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_custom_controlller = nodeHandle.createTimer(ros::Duration(1.5), &MainWindow::customYamlFileTimerCallback, this, true);    
 
-    // then, reload the parameters of the custom controller:
-    cmd = "rosparam load " + d_fall_pps_path + "/param/CustomController.yaml " + m_ros_namespace + "/CustomControllerService";
-    system(cmd.c_str());
-    ROS_INFO_STREAM(cmd);
+            break;
+
+        default:
+            ROS_INFO("Unknown 'all controllers to load yaml' command, thus nothing will be disabled");
+            break;
+    }
 }
 
+
+
+
 void MainWindow::on_en_custom_controller_clicked()
 {
     std_msgs::Int32 msg;
@@ -559,3 +677,80 @@ void MainWindow::on_en_safe_controller_clicked()
     msg.data = CMD_USE_SAFE_CONTROLLER;
     this->PPSClientCommandPublisher.publish(msg);
 }
+
+void MainWindow::on_customButton_1_clicked()
+{
+    CustomButton msg_custom_button;
+    msg_custom_button.button_index = 1;
+    msg_custom_button.command_code = 0;
+    this->PPSClientStudentCustomButtonPublisher.publish(msg_custom_button);
+
+    ROS_INFO("Custom button 1 pressed");
+}
+
+void MainWindow::on_customButton_2_clicked()
+{
+    CustomButton msg_custom_button;
+    msg_custom_button.button_index = 2;
+    msg_custom_button.command_code = 0;
+    this->PPSClientStudentCustomButtonPublisher.publish(msg_custom_button);
+    ROS_INFO("Custom button 2 pressed");
+}
+
+void MainWindow::on_customButton_3_clicked()
+{
+    CustomButton msg_custom_button;
+    msg_custom_button.button_index = 3;
+    msg_custom_button.command_code = (ui->custom_command_3->text()).toFloat();
+    this->PPSClientStudentCustomButtonPublisher.publish(msg_custom_button);
+    ROS_INFO("Custom button 3 pressed");
+}
+
+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;
+}
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 3dd33614610632ae4c773e1caccc487d664b5765..88cf08e5ce445fe31c88bde317df0329f9d9a7f2 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
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>1027</width>
-    <height>619</height>
+    <width>1042</width>
+    <height>701</height>
    </rect>
   </property>
   <property name="sizePolicy">
@@ -33,10 +33,145 @@
        <string/>
       </property>
       <layout class="QGridLayout" name="gridLayout_10">
+       <item row="3" column="1">
+        <widget class="QGroupBox" name="groupBox_4">
+         <property name="title">
+          <string/>
+         </property>
+         <layout class="QVBoxLayout" name="verticalLayout">
+          <item>
+           <widget class="QPushButton" name="motors_OFF_button">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="text">
+             <string>Motors OFF</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QPushButton" name="take_off_button">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="text">
+             <string>Take Off</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QPushButton" name="land_button">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="text">
+             <string>Land</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QLabel" name="label_battery">
+            <property name="font">
+             <font>
+              <pointsize>9</pointsize>
+              <italic>true</italic>
+             </font>
+            </property>
+            <property name="text">
+             <string/>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item row="1" column="0">
+        <widget class="QGroupBox" name="groupBox">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="font">
+          <font>
+           <pointsize>18</pointsize>
+          </font>
+         </property>
+         <property name="title">
+          <string>StudentID # connected to CF #</string>
+         </property>
+         <layout class="QGridLayout" name="gridLayout_2">
+          <item row="1" column="0">
+           <widget class="QLabel" name="raw_voltage_label">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="font">
+             <font>
+              <pointsize>18</pointsize>
+              <italic>false</italic>
+             </font>
+            </property>
+            <property name="text">
+             <string>Raw voltage: </string>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="1">
+           <widget class="QLineEdit" name="voltage_field">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="maximumSize">
+             <size>
+              <width>80</width>
+              <height>16777215</height>
+             </size>
+            </property>
+            <property name="readOnly">
+             <bool>true</bool>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item row="1" column="1">
+        <widget class="QLabel" name="flying_state_label">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="text">
+          <string>FlyingState</string>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignCenter</set>
+         </property>
+        </widget>
+       </item>
        <item row="3" column="0">
         <widget class="QTabWidget" name="tabWidget">
          <property name="currentIndex">
-          <number>1</number>
+          <number>0</number>
          </property>
          <widget class="QWidget" name="tab_3">
           <attribute name="title">
@@ -401,6 +536,19 @@
                 </property>
                </widget>
               </item>
+              <item row="3" column="1">
+               <widget class="QLineEdit" name="current_setpoint_z">
+                <property name="sizePolicy">
+                 <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+                  <horstretch>0</horstretch>
+                  <verstretch>0</verstretch>
+                 </sizepolicy>
+                </property>
+                <property name="readOnly">
+                 <bool>true</bool>
+                </property>
+               </widget>
+              </item>
               <item row="3" column="0">
                <widget class="QLabel" name="label_9">
                 <property name="sizePolicy">
@@ -427,8 +575,8 @@
                 </property>
                </widget>
               </item>
-              <item row="3" column="1">
-               <widget class="QLineEdit" name="current_setpoint_z">
+              <item row="4" column="1">
+               <widget class="QLineEdit" name="current_setpoint_yaw">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
                   <horstretch>0</horstretch>
@@ -458,19 +606,6 @@
                 </property>
                </widget>
               </item>
-              <item row="4" column="1">
-               <widget class="QLineEdit" name="current_setpoint_yaw">
-                <property name="sizePolicy">
-                 <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
-                  <horstretch>0</horstretch>
-                  <verstretch>0</verstretch>
-                 </sizepolicy>
-                </property>
-                <property name="readOnly">
-                 <bool>true</bool>
-                </property>
-               </widget>
-              </item>
               <item row="3" column="2">
                <widget class="QLineEdit" name="new_setpoint_z">
                 <property name="sizePolicy">
@@ -515,6 +650,13 @@
                 </property>
                </widget>
               </item>
+              <item row="5" column="1">
+               <widget class="QLabel" name="error_label">
+                <property name="text">
+                 <string/>
+                </property>
+               </widget>
+              </item>
              </layout>
             </widget>
            </item>
@@ -563,6 +705,27 @@
            <string>Custom Controller</string>
           </attribute>
           <layout class="QGridLayout" name="gridLayout_9">
+           <item row="2" column="1">
+            <widget class="QPushButton" name="customButton_2">
+             <property name="text">
+              <string>Custom Command 2</string>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="1">
+            <widget class="QPushButton" name="customButton_3">
+             <property name="text">
+              <string>Custom Command 3</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="1">
+            <widget class="QPushButton" name="customButton_1">
+             <property name="text">
+              <string>Custom Command 1</string>
+             </property>
+            </widget>
+           </item>
            <item row="0" column="0">
             <widget class="QGroupBox" name="groupBox_5">
              <property name="title">
@@ -1032,7 +1195,7 @@
              </layout>
             </widget>
            </item>
-           <item row="1" column="1">
+           <item row="4" column="1">
             <widget class="QPushButton" name="en_custom_controller">
              <property name="sizePolicy">
               <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
@@ -1051,7 +1214,7 @@
              </property>
             </widget>
            </item>
-           <item row="1" column="0">
+           <item row="4" column="0">
             <widget class="QPushButton" name="load_custom_yaml_button">
              <property name="sizePolicy">
               <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
@@ -1070,145 +1233,13 @@
              </property>
             </widget>
            </item>
+           <item row="3" column="2">
+            <widget class="QLineEdit" name="custom_command_3"/>
+           </item>
           </layout>
          </widget>
         </widget>
        </item>
-       <item row="3" column="1">
-        <widget class="QGroupBox" name="groupBox_4">
-         <property name="title">
-          <string/>
-         </property>
-         <layout class="QVBoxLayout" name="verticalLayout">
-          <item>
-           <widget class="QPushButton" name="motors_OFF_button">
-            <property name="sizePolicy">
-             <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
-              <horstretch>0</horstretch>
-              <verstretch>0</verstretch>
-             </sizepolicy>
-            </property>
-            <property name="text">
-             <string>Motors OFF</string>
-            </property>
-           </widget>
-          </item>
-          <item>
-           <widget class="QPushButton" name="take_off_button">
-            <property name="sizePolicy">
-             <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
-              <horstretch>0</horstretch>
-              <verstretch>0</verstretch>
-             </sizepolicy>
-            </property>
-            <property name="text">
-             <string>Take Off</string>
-            </property>
-           </widget>
-          </item>
-          <item>
-           <widget class="QPushButton" name="land_button">
-            <property name="sizePolicy">
-             <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
-              <horstretch>0</horstretch>
-              <verstretch>0</verstretch>
-             </sizepolicy>
-            </property>
-            <property name="text">
-             <string>Land</string>
-            </property>
-           </widget>
-          </item>
-          <item>
-           <widget class="QLabel" name="label_battery">
-            <property name="font">
-             <font>
-              <pointsize>9</pointsize>
-              <italic>true</italic>
-             </font>
-            </property>
-            <property name="text">
-             <string/>
-            </property>
-           </widget>
-          </item>
-         </layout>
-        </widget>
-       </item>
-       <item row="1" column="0">
-        <widget class="QGroupBox" name="groupBox">
-         <property name="sizePolicy">
-          <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
-           <horstretch>0</horstretch>
-           <verstretch>0</verstretch>
-          </sizepolicy>
-         </property>
-         <property name="font">
-          <font>
-           <pointsize>18</pointsize>
-          </font>
-         </property>
-         <property name="title">
-          <string>StudentID # connected to CF #</string>
-         </property>
-         <layout class="QGridLayout" name="gridLayout_2">
-          <item row="1" column="0">
-           <widget class="QLabel" name="raw_voltage_label">
-            <property name="sizePolicy">
-             <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
-              <horstretch>0</horstretch>
-              <verstretch>0</verstretch>
-             </sizepolicy>
-            </property>
-            <property name="font">
-             <font>
-              <pointsize>18</pointsize>
-              <italic>false</italic>
-             </font>
-            </property>
-            <property name="text">
-             <string>Raw voltage: </string>
-            </property>
-           </widget>
-          </item>
-          <item row="1" column="1">
-           <widget class="QLineEdit" name="voltage_field">
-            <property name="sizePolicy">
-             <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
-              <horstretch>0</horstretch>
-              <verstretch>0</verstretch>
-             </sizepolicy>
-            </property>
-            <property name="maximumSize">
-             <size>
-              <width>80</width>
-              <height>16777215</height>
-             </size>
-            </property>
-            <property name="readOnly">
-             <bool>true</bool>
-            </property>
-           </widget>
-          </item>
-         </layout>
-        </widget>
-       </item>
-       <item row="1" column="1">
-        <widget class="QLabel" name="flying_state_label">
-         <property name="sizePolicy">
-          <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
-           <horstretch>0</horstretch>
-           <verstretch>0</verstretch>
-          </sizepolicy>
-         </property>
-         <property name="text">
-          <string>FlyingState</string>
-         </property>
-         <property name="alignment">
-          <set>Qt::AlignCenter</set>
-         </property>
-        </widget>
-       </item>
       </layout>
      </widget>
     </item>
@@ -1270,7 +1301,7 @@
     <rect>
      <x>0</x>
      <y>0</y>
-     <width>1027</width>
+     <width>1042</width>
      <height>25</height>
     </rect>
    </property>
diff --git a/pps_ws/src/d_fall_pps/launch/Student.launch b/pps_ws/src/d_fall_pps/launch/Student.launch
index c2480b38a9fc1fa1a78315189a943f3576ec8a25..918c01067471dccce718677c983b50457b531112 100755
--- a/pps_ws/src/d_fall_pps/launch/Student.launch
+++ b/pps_ws/src/d_fall_pps/launch/Student.launch
@@ -1,27 +1,34 @@
 <launch>
 
+	<!-- CRAZY RADIO -->
 	<node pkg="d_fall_pps" name="CrazyRadio" output="screen" type="CrazyRadio.py">
 		<rosparam command="load" file="$(find d_fall_pps)/param/ClientConfig.yaml" />
 	</node>
 
+	<!-- PPS CLIENT -->
 	<node pkg="d_fall_pps" name="PPSClient" output="screen" type="PPSClient">
 		<rosparam command="load" file="$(find d_fall_pps)/param/ClientConfig.yaml" />
 		<param name="studentID" value="$(optenv ROS_NAMESPACE)" />
 	</node>
 
+	<!-- SAFE CONTROLLER -->
 	<node pkg="d_fall_pps" name="SafeControllerService" output="screen" type="SafeControllerService">
-		<rosparam command="load" file="$(find d_fall_pps)/param/SafeController.yaml" />
 	</node>
 
+	<!-- CUSTOM CONTROLLER -->
 	<node pkg="d_fall_pps" name="CustomControllerService" output="screen" type="CustomControllerService">
-		<rosparam command="load" file="$(find d_fall_pps)/param/CustomController.yaml" />
 	</node>
 
-    <!-- When we have a GUI, this has to be adapted and included -->
-	<node pkg="d_fall_pps" name="student_GUI" output="screen" type="student_GUI">
-		<!-- <rosparam command="load" file="$(find d_fall_pps)/launch/ControlParams.yaml" /> -->
+	<!-- PARAMETER SERVICE -->
+	<node pkg="d_fall_pps" name="ParameterService" output="screen" type="ParameterService">
+		<param name="type" type="str" value="agent" />
+		<param name="agentID" value="$(optenv ROS_NAMESPACE)" />
+		<rosparam command="load" file="$(find d_fall_pps)/param/SafeController.yaml" ns="SafeController" />
+		<rosparam command="load" file="$(find d_fall_pps)/param/CustomController.yaml" ns="CustomController" />
 	</node>
 
-
+	<!-- AGENT GUI (aka. the "student GUI") -->
+    <node pkg="d_fall_pps" name="student_GUI" output="screen" type="student_GUI">
+	</node>
 
 </launch>
diff --git a/pps_ws/src/d_fall_pps/launch/Teacher.launch b/pps_ws/src/d_fall_pps/launch/Teacher.launch
index 9193b7896c16f8f081e35e489e487093883155aa..1c2e6a9d63045b3969339f7f17d3ac0faf18e2b8 100755
--- a/pps_ws/src/d_fall_pps/launch/Teacher.launch
+++ b/pps_ws/src/d_fall_pps/launch/Teacher.launch
@@ -8,7 +8,14 @@
 
 	<!-- When we have a GUI, this has to be adapted and included -->
 	<node pkg="d_fall_pps" name="my_GUI" output="screen" type="my_GUI">
-		<!-- <rosparam command="load" file="$(find d_fall_pps)/launch/ControlParams.yaml" /> -->
+	</node>
+
+	<!-- PARAMETER SERVICE -->
+	<node pkg="d_fall_pps" name="ParameterService" output="screen" type="ParameterService">
+		<param name="type" type="str" value="coordinator" />
+		<param name="agentID" value="0" />
+		<rosparam command="load" file="$(find d_fall_pps)/param/SafeController.yaml" ns="SafeController" />
+		<rosparam command="load" file="$(find d_fall_pps)/param/CustomController.yaml" ns="CustomController" />
 	</node>
 
 </launch>
diff --git a/pps_ws/src/d_fall_pps/msg/CustomButton.msg b/pps_ws/src/d_fall_pps/msg/CustomButton.msg
new file mode 100644
index 0000000000000000000000000000000000000000..7ba9d563c0d308337be9aa2aa691581a6ec9b6c9
--- /dev/null
+++ b/pps_ws/src/d_fall_pps/msg/CustomButton.msg
@@ -0,0 +1,2 @@
+uint32 button_index
+float64 command_code
\ No newline at end of file
diff --git a/pps_ws/src/d_fall_pps/msg/CustomControllerYAML.msg b/pps_ws/src/d_fall_pps/msg/CustomControllerYAML.msg
new file mode 100644
index 0000000000000000000000000000000000000000..ebe1dee883ffcd744fe81b94023e395d099775fc
--- /dev/null
+++ b/pps_ws/src/d_fall_pps/msg/CustomControllerYAML.msg
@@ -0,0 +1,7 @@
+float64 mass
+float64 control_frequency
+float64[] motorPoly
+bool shouldPerformConvertIntoBodyFrame
+bool shouldPublishCurrent_xyz_yaw
+bool shouldFollowAnotherAgent
+uint32[] follow_in_a_line_agentIDs
diff --git a/pps_ws/src/d_fall_pps/param/Crazyflie.db b/pps_ws/src/d_fall_pps/param/Crazyflie.db
index 766bf5b586942ff2988a44b49199070c024a24e1..5e0a39201708c4aae0f2b97c1f3510773788f738 100644
--- a/pps_ws/src/d_fall_pps/param/Crazyflie.db
+++ b/pps_ws/src/d_fall_pps/param/Crazyflie.db
@@ -1 +1 @@
-3,PPS_CF01,0/0/2M/E7E7E7E701,0,0.918398,-0.0405601,-0.2,2.27427,0.860455,1.2
+7,PPS_CF01,0/0/2M/E7E7E7E701,0,1.56976,-0.10861,-0.2,2.79907,0.808677,1.2
diff --git a/pps_ws/src/d_fall_pps/param/CustomController.yaml b/pps_ws/src/d_fall_pps/param/CustomController.yaml
index 8f59bc1539c5c13ded4c40c38cf1c0583dc5a2a1..29b9df5e92950cb77a05d44787430a4cac3c6388 100644
--- a/pps_ws/src/d_fall_pps/param/CustomController.yaml
+++ b/pps_ws/src/d_fall_pps/param/CustomController.yaml
@@ -1,8 +1,46 @@
-# mass of the crazyflie
-mass : 30
+# Mass of the crazyflie
+mass : 31
 
-# frequency of the controller, in hertz
+# Frequency of the controller, in hertz
 control_frequency : 200
 
-#quadratic motor regression equation (a0, a1, a2)
-motorPoly: [5.484560e-4, 1.032633e-6, 2.130295e-11]
+# 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 (x,y,z,yaw) of this agent should be published or not
+shouldPublishCurrent_xyz_yaw : false
+
+# Boolean indicating whether the (x,y,z,yaw) setpoint of this agent should adapted in
+# an attempt to follow the "my_current_xyz_yaw_topic" from another agent
+shouldFollowAnotherAgent : false
+
+# The order in which agents should follow eachother
+# > This parameter is a vector of integers that specifies  agent ID's
+# > The order of the agent ID's is the ordering of the line formation
+# > i.e., the first ID is the leader, the second ID should follow the first ID, and so on
+follow_in_a_line_agentIDs : [1, 2, 3]
+
+# 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 to use, defined as:
+# 1  -  LQR controller based on the state vector: [position,velocity,angles]
+# 2  -  LQR controller based on the state vector: [position,velocity]
+controller_type : 1
+
+# The LQR Controller parameters for "mode = 1"
+gainMatrixRollRate                :  [ 0.00,-1.72, 0.00, 0.00,-1.34, 0.00, 5.12, 0.00, 0.00]
+gainMatrixPitchRate               :  [ 1.72, 0.00, 0.00, 1.34, 0.00, 0.00, 0.00, 5.12, 0.00]
+gainMatrixYawRate                 :  [ 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 2.84]
+gainMatrixThrust_NineStateVector  :  [ 0.00, 0.00, 0.25, 0.00, 0.00, 0.14, 0.00, 0.00, 0.00]
+
+# The LQR Controller parameters for "mode = 2"
+gainMatrixRollAngle               :  [ 0.00,-0.20, 0.00, 0.00,-0.20, 0.00]
+gainMatrixPitchAngle              :  [ 0.20, 0.00, 0.00, 0.20, 0.00, 0.00]
+gainMatrixThrust_SixStateVector   :  [ 0.00, 0.00, 0.31, 0.00, 0.00, 0.14]
\ No newline at end of file
diff --git a/pps_ws/src/d_fall_pps/src/CentralManagerService.cpp b/pps_ws/src/d_fall_pps/src/CentralManagerService.cpp
index 9fd5332f33c9026d5580a32ecc3a50d73775cc4f..4a0e58a8ebbe3a75bbbc05ec619dbad05ac2211e 100755
--- a/pps_ws/src/d_fall_pps/src/CentralManagerService.cpp
+++ b/pps_ws/src/d_fall_pps/src/CentralManagerService.cpp
@@ -30,6 +30,17 @@
 //    ----------------------------------------------------------------------------------
 
 
+
+
+
+//    ----------------------------------------------------------------------------------
+//    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
+//    ----------------------------------------------------------------------------------
+
 #include <stdlib.h>
 #include <ros/ros.h>
 #include "d_fall_pps/CrazyflieContext.h"
@@ -43,55 +54,181 @@
 
 #include "CrazyflieIO.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
+//    ----------------------------------------------------------------------------------
+
+
+// For which controller parameters to load
+#define LOAD_YAML_SAFE_CONTROLLER_AGENT          1
+#define LOAD_YAML_CUSTOM_CONTROLLER_AGENT        2
+#define LOAD_YAML_SAFE_CONTROLLER_COORDINATOR    3
+#define LOAD_YAML_CUSTOM_CONTROLLER_COORDINATOR  4
+
+// For which controller parameters and from where to fetch
+#define FETCH_YAML_SAFE_CONTROLLER_FROM_OWN_AGENT        1
+#define FETCH_YAML_CUSTOM_CONTROLLER_FROM_OWN_AGENT      2
+#define FETCH_YAML_SAFE_CONTROLLER_FROM_COORDINATOR      3
+#define FETCH_YAML_CUSTOM_CONTROLLER_FROM_COORDINATOR    4
+
+
 using namespace d_fall_pps;
 using namespace std;
 
+
+
+
+
+//    ----------------------------------------------------------------------------------
+//    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
+//    ----------------------------------------------------------------------------------
+
 CrazyflieDB crazyflieDB;
 
-bool cmRead(CMRead::Request &request, CMRead::Response &response) {
+
+
+
+
+//    ----------------------------------------------------------------------------------
+//    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
+//    ----------------------------------------------------------------------------------
+
+bool cmRead(CMRead::Request &request, CMRead::Response &response);
+int findEntryByStudID(unsigned int studID);
+bool cmQuery(CMQuery::Request &request, CMQuery::Response &response);
+int findEntryByCF(string name);
+bool cmUpdate(CMUpdate::Request &request, CMUpdate::Response &response);
+bool cmCommand(CMCommand::Request &request, CMCommand::Response &response);
+
+
+
+//    ----------------------------------------------------------------------------------
+//    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
+//    ----------------------------------------------------------------------------------
+
+
+
+
+
+//    ----------------------------------------------------------------------------------
+//    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
+//    ----------------------------------------------------------------------------------
+
+// The requesting to load parameters is currently handled by the Paramter Service
+
+
+
+//    ----------------------------------------------------------------------------------
+//    DDDD     A    TTTTT    A    BBBB     A     SSSS  EEEEE
+//    D   D   A A     T     A A   B   B   A A   S      E
+//    D   D  A   A    T    A   A  BBBB   A   A   SSS   EEE
+//    D   D  AAAAA    T    AAAAA  B   B  AAAAA      S  E
+//    DDDD   A   A    T    A   A  BBBB   A   A  SSSS   EEEEE
+//    ----------------------------------------------------------------------------------
+
+bool cmRead(CMRead::Request &request, CMRead::Response &response)
+{
     response.crazyflieDB = crazyflieDB;
 	return true;
 }
 
-int findEntryByStudID(unsigned int studID) {
-    for(int i = 0; i < crazyflieDB.crazyflieEntries.size(); i++) {
+int findEntryByStudID(unsigned int studID)
+{
+    for(int i = 0; i < crazyflieDB.crazyflieEntries.size(); i++)
+    {
         CrazyflieEntry entry = crazyflieDB.crazyflieEntries[i];
-        if(entry.studentID == studID) {
+        if(entry.studentID == studID)
+        {
             return i;
         }
     }
     return -1;
 }
 
-bool cmQuery(CMQuery::Request &request, CMQuery::Response &response) {
+bool cmQuery(CMQuery::Request &request, CMQuery::Response &response)
+{
     int cfIndex = findEntryByStudID(request.studentID);
-    if(cfIndex != -1) {
+    if(cfIndex != -1)
+    {
         response.crazyflieContext = crazyflieDB.crazyflieEntries[cfIndex].crazyflieContext;
         return true;
-    } else {
+    }
+    else
+    {
         return false;
     }
 }
 
-int findEntryByCF(string name) {
-    for(int i = 0; i < crazyflieDB.crazyflieEntries.size(); i++) {
+int findEntryByCF(string name)
+{
+    for(int i = 0; i < crazyflieDB.crazyflieEntries.size(); i++)
+    {
         CrazyflieEntry entry = crazyflieDB.crazyflieEntries[i];
         string cfName = entry.crazyflieContext.crazyflieName;
-        if(cfName == name) {
+        if(cfName == name)
+        {
             return i;
         }
     }
     return -1;
 }
 
-bool cmUpdate(CMUpdate::Request &request, CMUpdate::Response &response) {
-    switch(request.mode) {
-        case ENTRY_INSERT_OR_UPDATE: {
+bool cmUpdate(CMUpdate::Request &request, CMUpdate::Response &response)
+{
+    switch(request.mode)
+    {
+        case ENTRY_INSERT_OR_UPDATE:
+        {
             string cfName = request.crazyflieEntry.crazyflieContext.crazyflieName;
             int cfIndex = findEntryByCF(cfName);
-            if(cfIndex == -1) {
+            if(cfIndex == -1)
+            {
                 crazyflieDB.crazyflieEntries.push_back(request.crazyflieEntry);
-            } else {
+            }
+            else
+            {
                 crazyflieDB.crazyflieEntries[cfIndex] = request.crazyflieEntry;
             }
             return true;
@@ -100,9 +237,12 @@ bool cmUpdate(CMUpdate::Request &request, CMUpdate::Response &response) {
         case ENTRY_REMOVE: {
             string cfName = request.crazyflieEntry.crazyflieContext.crazyflieName;
             int cfIndex = findEntryByCF(cfName);
-            if(cfIndex == -1) {
+            if(cfIndex == -1)
+            {
                 return false;
-            } else {
+            }
+            else
+            {
                 crazyflieDB.crazyflieEntries.erase(crazyflieDB.crazyflieEntries.begin() +cfIndex);
                 return true;
             }
@@ -112,14 +252,18 @@ bool cmUpdate(CMUpdate::Request &request, CMUpdate::Response &response) {
     }
 }
 
-bool cmCommand(CMCommand::Request &request, CMCommand::Response &response) {
-    switch(request.command) {
-        case CMD_SAVE: {
+bool cmCommand(CMCommand::Request &request, CMCommand::Response &response)
+{
+    switch(request.command)
+    {
+        case CMD_SAVE:
+        {
             writeCrazyflieDB(crazyflieDB);
             return true;
         }
 
-        case CMD_RELOAD: {
+        case CMD_RELOAD:
+        {
             crazyflieDB.crazyflieEntries.clear();
             readCrazyflieDB(crazyflieDB);
             return true;
@@ -129,7 +273,19 @@ bool cmCommand(CMCommand::Request &request, CMCommand::Response &response) {
     }
 }
 
-int main(int argc, char* argv[]) {
+
+
+
+//    ----------------------------------------------------------------------------------
+//    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
+//    ----------------------------------------------------------------------------------
+
+int main(int argc, char* argv[])
+{
     ros::init(argc, argv, "CentralManagerService");
 
     ros::NodeHandle nodeHandle("~");
@@ -141,6 +297,16 @@ int main(int argc, char* argv[]) {
     ros::ServiceServer updateService = nodeHandle.advertiseService("Update", cmUpdate);
     ros::ServiceServer commandService = nodeHandle.advertiseService("Command", cmCommand);
 
+    // Get the handle to the namespace in which this coordinator is launched
+    //ros::NodeHandle namespaceNodeHandle = ros::NodeHandle();
+
+    // Subscriber for requests that the controller parameters should be re-loaded from
+    // the .YAML files on the coordinators machine, and then all the agents should be
+    // request to fetch the parameters from itself, i.e., fetch parameters from the
+    // coordinator.
+    //ros::Subscriber controllerYamlReadyForFetchSubscriber = namespaceNodeHandle.subscribe("/ParameterService/controllerYamlReadyForFetch", 1, controllerYamlReadyForFetchCallback);
+
+
     ROS_INFO("CentralManagerService ready");
     ros::spin();
 
diff --git a/pps_ws/src/d_fall_pps/src/CrazyflieIO.cpp b/pps_ws/src/d_fall_pps/src/CrazyflieIO.cpp
index 8ef32d752add884b534b2ec4192364fd807423dc..e5e0c03f350623f89d39b19b36556a296ef81ec3 100644
--- a/pps_ws/src/d_fall_pps/src/CrazyflieIO.cpp
+++ b/pps_ws/src/d_fall_pps/src/CrazyflieIO.cpp
@@ -25,7 +25,13 @@
 //
 //
 //    DESCRIPTION:
-//    This manages the Input/Output stream from the Crazyflie
+//    This manages the Input/Output from the text file database that is used to store
+//    and commincate an agent's zone between the coordinator node and the agent's node,
+//    i.e., the details of:
+//    > the linked ( agent ID , Crazyflie ) pair, where the Crazyflie is described by:
+//      - the "name", which matches that used by the localisation system
+//      - the "address", which is needed to establish a radio connection
+//    > the hyper-rectangle area in which the agent is allowed to operate
 //
 //    ----------------------------------------------------------------------------------
 
diff --git a/pps_ws/src/d_fall_pps/src/CustomControllerService.cpp b/pps_ws/src/d_fall_pps/src/CustomControllerService.cpp
index 048b8375ded87f65266e6943268ad00b4badd2a1..7d4889183a77e57fc4897f4e662a627264c0ca3a 100644
--- a/pps_ws/src/d_fall_pps/src/CustomControllerService.cpp
+++ b/pps_ws/src/d_fall_pps/src/CustomControllerService.cpp
@@ -56,6 +56,7 @@
 #include "d_fall_pps/ControlCommand.h"
 #include "d_fall_pps/Controller.h"
 #include "d_fall_pps/DebugMsg.h"
+#include "d_fall_pps/CustomControllerYAML.h"
 
 #include <std_msgs/Int32.h>
 
@@ -73,10 +74,10 @@
 
 // These constants are defined to make the code more readable and adaptable.
 
-// constants
+// Universal constants
 #define PI 3.1415926535
 
-// The constants define the modes that can be used for controller the Crazyflie 2.0,
+// 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:
@@ -91,10 +92,28 @@
 //               body frame roll, pitch, and yaw angles from the PID attitude
 //               controllers implemented in the Crazyflie 2.0 firmware.
 #define MOTOR_MODE 6
-#define RATE_MODE 7
+#define RATE_MODE  7
 #define ANGLE_MODE 8
 
-// namespacing the package
+// 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
+
+// Constants for feching the yaml paramters
+#define FETCH_YAML_SAFE_CONTROLLER_AGENT          1
+#define FETCH_YAML_CUSTOM_CONTROLLER_AGENT        2
+#define FETCH_YAML_SAFE_CONTROLLER_COORDINATOR    3
+#define FETCH_YAML_CUSTOM_CONTROLLER_COORDINATOR  4
+
+// Namespacing the package
 using namespace d_fall_pps;
 
 
@@ -111,27 +130,94 @@ using namespace d_fall_pps;
 
 // Variables for controller
 float cf_mass;                       // Crazyflie mass in grams
-std::vector<float>  motorPoly(3);    // Coefficients of the 16-bit command to thrust conversion
+std::vector<float> motorPoly(3);     // Coefficients of the 16-bit command to thrust conversion
 float control_frequency;             // Frequency at which the controller is running
 float gravity_force;                 // The weight of the Crazyflie in Newtons, i.e., mg
 
-CrazyflieData previous_stateErrorInertial;     // The location error of the Crazyflie at the "previous" time step
+float previous_stateErrorInertial[9];     // The location error of the Crazyflie at the "previous" time step
 
 std::vector<float>  setpoint{0.0,0.0,0.4,0.0};     // The setpoints for (x,y,z) position and yaw angle, in that order
 
-// The LQR Controller parameters
-const float gainMatrixRoll[9] = {0, -1.714330725, 0, 0, -1.337107465, 0, 5.115369735, 0, 0};
-const float gainMatrixPitch[9] = {1.714330725, 0, 0, 1.337107465, 0, 0, 0, 5.115369735, 0};
-const float gainMatrixYaw[9] = {0, 0, 0, 0, 0, 0, 0, 0, 2.843099534};
-const float gainMatrixThrust[9] = {0, 0, 0.22195826, 0, 0, 0.12362477, 0, 0, 0};
+
+// The controller type to run in the "calculateControlOutput" function
+int controller_type = LQR_RATE_MODE;
+
+// The LQR Controller parameters for "LQR_RATE_MODE"
+std::vector<float> gainMatrixRollRate                =  { 0.00,-1.72, 0.00, 0.00,-1.34, 0.00, 5.12, 0.00, 0.00};
+std::vector<float> gainMatrixPitchRate               =  { 1.72, 0.00, 0.00, 1.34, 0.00, 0.00, 0.00, 5.12, 0.00};
+std::vector<float> gainMatrixYawRate                 =  { 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 2.84};
+std::vector<float> gainMatrixThrust_NineStateVector  =  { 0.00, 0.00, 0.25, 0.00, 0.00, 0.14, 0.00, 0.00, 0.00};
 
 
+// The LQR Controller parameters for "LQR_ANGLE_MODE"
+std::vector<float> gainMatrixRollAngle               =  { 0.00,-0.20, 0.00, 0.00,-0.20, 0.00};
+std::vector<float> gainMatrixPitchAngle              =  { 0.20, 0.00, 0.00, 0.20, 0.00, 0.00};
+std::vector<float> gainMatrixThrust_SixStateVector   =  { 0.00, 0.00, 0.31, 0.00, 0.00, 0.14};
+
+// ROS Publisher for debugging variables
 ros::Publisher debugPublisher;
 
 
+// Variable for the namespaces for the paramter 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;
+
+
+
+// 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;
+
+// Boolean indicating whether the (x,y,z,yaw) of this agent should be published or not
+// > The default behaviour is: do not publish,
+// > This varaible is changed based on parameters loaded from the YAML file
+bool shouldPublishCurrent_xyz_yaw = false;
+
+// Boolean indicating whether the (x,y,z,yaw) setpoint of this agent should adapted in
+// an attempt to follow the "my_current_xyz_yaw_topic" from another agent
+// > The default behaviour is: do not follow,
+// > This varaible is changed based on parameters loaded from the YAML file
+bool shouldFollowAnotherAgent = false;
+
+// The order in which agents should follow eachother
+// > This parameter is a vector of integers that specifies  agent ID's
+// > The order of the agent ID's is the ordering of the line formation
+// > i.e., the first ID is the leader, the second ID should follow the first ID, and so on
+std::vector<int> follow_in_a_line_agentIDs(100);
+
+// Integer specifying the ID of the agent that will be followed by this agent
+// > The default behaviour not to follow any agent, indicated by ID zero
+// > This varaible is changed based on parameters loaded from the YAML file
+int agentID_to_follow = 0;
+
+// ROS Publisher for my current (x,y,z,yaw) position
+ros::Publisher my_current_xyz_yaw_publisher;
+
+// ROS Subscriber for my position
+ros::Subscriber xyz_yaw_to_follow_subscriber;
+
 
 // RELEVANT NOTES ABOUT THE VARIABLES DECLARE HERE:
-// The "CrazyflieData" type used for the "previous_stateErrorInertial" variable is a
+// 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
@@ -168,6 +254,11 @@ ros::Publisher debugPublisher;
 // 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
+bool calculateControlOutput(Controller::Request &request, Controller::Response &response);
+void calculateControlOutput_viaLQRforRates(float stateErrorBody[9], Controller::Request &request, Controller::Response &response);
+void calculateControlOutput_viaLQRforAngles(float stateErrorBody[9], Controller::Request &request, Controller::Response &response);
+
 // TRANSFORMATION OF THE (x,y) INERTIAL FRAME ERROR INTO AN (x,y) BODY FRAME ERROR
 void convertIntoBodyFrame(float stateInertial[9], float (&stateBody)[9], float yaw_measured);
 
@@ -176,12 +267,20 @@ float computeMotorPolyBackward(float thrust);
 
 // SETPOINT CHANGE CALLBACK
 void setpointCallback(const Setpoint& newSetpoint);
+void xyz_yaw_to_follow_callback(const Setpoint& newSetpoint);
 
 // LOAD PARAMETERS
-void loadParameterFloatVector(ros::NodeHandle& nodeHandle, std::string name, std::vector<float>& val, int length);
-float getFloatParameter(ros::NodeHandle& nodeHandle, std::string name);
-void loadPPSTemplateParameters(ros::NodeHandle& nodeHandle);
-void customYAMLloadedCallback(const std_msgs::Int32& msg);
+float getParameterFloat(ros::NodeHandle& nodeHandle, std::string name);
+void getParameterFloatVector(ros::NodeHandle& nodeHandle, std::string name, std::vector<float>& val, int length);
+int getParameterInt(ros::NodeHandle& nodeHandle, std::string name);
+void getParameterIntVectorWithKnownLength(ros::NodeHandle& nodeHandle, std::string name, std::vector<int>& val, int length);
+int getParameterIntVectorWithUnknownLength(ros::NodeHandle& nodeHandle, std::string name, std::vector<int>& val);
+bool getParameterBool(ros::NodeHandle& nodeHandle, std::string name);
+
+void yamlReadyForFetchCallback(const std_msgs::Int32& msg);
+void fetchYamlParameters(ros::NodeHandle& nodeHandle);
+void processFetchedParameters();
+//void customYAMLasMessageCallback(const CustomControllerYAML& newCustomControllerParameters);
 
 
 
@@ -304,254 +403,451 @@ void customYAMLloadedCallback(const std_msgs::Int32& msg);
 // (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) {
+bool calculateControlOutput(Controller::Request &request, Controller::Response &response)
+{
 
-    // This is the "start" of the outer loop controller, add all your control
-    // computation here, or you may find it convienient to create functions
-    // to keep you code cleaner
-    
-    
-    // Define a local array to fill in with the state error
-    float stateErrorInertial[9];
-
-    // Fill in the (x,y,z) position error
-    stateErrorInertial[0] = request.ownCrazyflie.x - setpoint[0];
-    stateErrorInertial[1] = request.ownCrazyflie.y - setpoint[1];
-    stateErrorInertial[2] = request.ownCrazyflie.z - setpoint[2];
-
-    // Compute an estimate of the velocity
-    // > As simply the derivative between the current and previous position
-    stateErrorInertial[3] = (stateErrorInertial[0] - previous_stateErrorInertial.x) * control_frequency;
-    stateErrorInertial[4] = (stateErrorInertial[1] - previous_stateErrorInertial.y) * control_frequency;
-    stateErrorInertial[5] = (stateErrorInertial[2] - previous_stateErrorInertial.z) * control_frequency;
-
-    // Fill in the roll and pitch angle measurements directly
-    stateErrorInertial[6] = request.ownCrazyflie.roll;
-    stateErrorInertial[7] = request.ownCrazyflie.pitch;
-
-    // Fill in the yaw angle error
-    // > This error should be "unwrapped" to be in the range
-    //   ( -pi , pi )
-    // > First, get the yaw error into a local variable
-    float yawError = request.ownCrazyflie.yaw - setpoint[3];
-    // > Second, "unwrap" the yaw error to the interval ( -pi , pi )
-    while(yawError > PI) {yawError -= 2 * PI;}
-    while(yawError < -PI) {yawError += 2 * PI;}
-    // > Third, put the "yawError" into the "stateError" variable
-    stateErrorInertial[8] = yawError;
+	// This is the "start" of the outer loop controller, add all your control
+	// computation here, or you may find it convienient to create functions
+	// to keep you code cleaner
+
+
+	// Define a local array to fill in with the state error
+	float stateErrorInertial[9];
+
+	// Fill in the (x,y,z) position error
+	stateErrorInertial[0] = request.ownCrazyflie.x - setpoint[0];
+	stateErrorInertial[1] = request.ownCrazyflie.y - setpoint[1];
+	stateErrorInertial[2] = request.ownCrazyflie.z - setpoint[2];
+
+	// Compute an estimate of the velocity
+	// > As simply the derivative between the current and previous position
+	stateErrorInertial[3] = (stateErrorInertial[0] - previous_stateErrorInertial[0]) * control_frequency;
+	stateErrorInertial[4] = (stateErrorInertial[1] - previous_stateErrorInertial[1]) * control_frequency;
+	stateErrorInertial[5] = (stateErrorInertial[2] - previous_stateErrorInertial[2]) * control_frequency;
+
+	// Fill in the roll and pitch angle measurements directly
+	stateErrorInertial[6] = request.ownCrazyflie.roll;
+	stateErrorInertial[7] = request.ownCrazyflie.pitch;
+
+	// Fill in the yaw angle error
+	// > This error should be "unwrapped" to be in the range
+	//   ( -pi , pi )
+	// > First, get the yaw error into a local variable
+	float yawError = request.ownCrazyflie.yaw - setpoint[3];
+	// > Second, "unwrap" the yaw error to the interval ( -pi , pi )
+	while(yawError > PI) {yawError -= 2 * PI;}
+	while(yawError < -PI) {yawError += 2 * PI;}
+	// > Third, put the "yawError" into the "stateError" variable
+	stateErrorInertial[8] = yawError;
+
+
+	// CONVERSION INTO BODY FRAME
+	// Conver the state erorr from the Inertial frame into the Body frame
+	// > Note: the function "convertIntoBodyFrame" is implemented in this file
+	//   and by default does not perform any conversion. The equations to convert
+	//   the state error into the body frame should be implemented in that function
+	//   for successful completion of the PPS exercise
+	float stateErrorBody[9];
+	convertIntoBodyFrame(stateErrorInertial, stateErrorBody, request.ownCrazyflie.yaw);
+
+
+	// SAVE THE STATE ERROR TO BE USED NEXT TIME THIS FUNCTION IS CALLED
+	// > as we have already used previous error we can now update it update it
+	for(int i = 0; i < 9; ++i)
+	{
+		previous_stateErrorInertial[i] = stateErrorInertial[i];
+	}
+
+
+
+	// SWITCH BETWEEN THE DIFFERENT CONTROLLER TYPES:
+	switch (controller_type)
+	{
+		// LQR controller based on the state vector: [position,velocity,angles]
+		case LQR_RATE_MODE:
+		{
+			// Call the function that performs the control computations for this mode
+			calculateControlOutput_viaLQRforRates(stateErrorBody,request,response);
+			break;
+		}
+
+		// LQR controller based on the state vector: [position,velocity]
+		case LQR_ANGLE_MODE:
+		{
+			// Call the function that performs the control computations for this mode
+			calculateControlOutput_viaLQRforAngles(stateErrorBody,request,response);
+			break;
+		}
+
+		default:
+		{
+			// Display that the "controller_type" was not recognised
+			ROS_INFO_STREAM("ERROR: in the 'calculateControlOutput' function of the 'CustomControllerService': the 'controller_type' 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 = MOTOR_MODE;
+			break;
+		}
+
+
+
+	}
+
+
+
+	
+
+
+
+	//  ************************************************************************************************
+	//  PPPP   U   U  BBBB   L      III   SSSS  H  H       X   X  Y   Y  ZZZZZ     Y   Y    A    W     W
+	//  P   P  U   U  B   B  L       I   S      H  H        X X    Y Y      Z       Y Y    A A   W     W
+	//  PPPP   U   U  BBBB   L       I    SSS   HHHH         X      Y      Z         Y    A   A  W     W
+	//  P      U   U  B   B  L       I       S  H  H        X X     Y     Z          Y    AAAAA   W W W
+	//  P       UUU   BBBB   LLLLL  III  SSSS   H  H       X   X    Y    ZZZZZ       Y    A   A    W W
+
+	// PUBLISH THE CURRENT X,Y,Z, AND YAW (if required)
+	if (shouldPublishCurrent_xyz_yaw)
+	{
+		// publish setpoint for FollowController of another student group
+		Setpoint temp_current_xyz_yaw;
+		// Fill in the x,y,z, and yaw info directly from the data provided to this
+		// function
+		temp_current_xyz_yaw.x   = request.ownCrazyflie.x;
+		temp_current_xyz_yaw.y   = request.ownCrazyflie.y;
+		temp_current_xyz_yaw.z   = request.ownCrazyflie.z;
+		temp_current_xyz_yaw.yaw = request.ownCrazyflie.yaw;
+		my_current_xyz_yaw_publisher.publish(temp_current_xyz_yaw);
+	}
+
+
+
+
+	
+
+	// Return "true" to indicate that the control computation was performed successfully
+	return true;
+}
 
-    
-    // CONVERSION INTO BODY FRAME
-    // Conver the state erorr from the Inertial frame into the Body frame
-    // > Note: the function "convertIntoBodyFrame" is implemented in this file
-    //   and by default does not perform any conversion. The equations to convert
-    //   the state error into the body frame should be implemented in that function
-    //   for successful completion of the PPS exercise
-    float stateErrorBody[9];
-    convertIntoBodyFrame(stateErrorInertial, stateErrorBody, request.ownCrazyflie.yaw);
 
 
 
 
-    //  **********************
-    //  Y   Y    A    W     W
-    //   Y Y    A A   W     W
-    //    Y    A   A  W     W
-    //    Y    AAAAA   W W W
-    //    Y    A   A    W W
-    //
-    // YAW CONTROLLER
+void calculateControlOutput_viaLQRforRates(float stateErrorBody[9], Controller::Request &request, Controller::Response &response)
+{
+	//  **********************
+	//  Y   Y    A    W     W
+	//   Y Y    A A   W     W
+	//    Y    A   A  W     W
+	//    Y    AAAAA   W W W
+	//    Y    A   A    W W
+	//
+	// YAW CONTROLLER
 
-    // Instantiate the local variable for the yaw rate that will be requested
-    // from the Crazyflie's on-baord "inner-loop" controller
-    float yawRate_forResponse = 0;
+	// Instantiate the local variable for the yaw rate that will be requested
+	// from the Crazyflie's on-baord "inner-loop" controller
+	float yawRate_forResponse = 0;
 
-    // Perform the "-Kx" LQR computation for the yaw rate to respoond with
-    for(int i = 0; i < 9; ++i)
-    {
-        yawRate_forResponse -= gainMatrixYaw[i] * stateErrorBody[i];
-    }
+	// Perform the "-Kx" LQR computation for the yaw rate to respoond with
+	for(int i = 0; i < 9; ++i)
+	{
+		yawRate_forResponse -= gainMatrixYawRate[i] * stateErrorBody[i];
+	}
 
-    // Put the computed yaw rate into the "response" variable
-    response.controlOutput.yaw = yawRate_forResponse;
+	// Put the computed yaw rate into the "response" variable
+	response.controlOutput.yaw = yawRate_forResponse;
 
 
 
 
-    //  **************************************
-    //  BBBB    OOO   DDDD   Y   Y       ZZZZZ
-    //  B   B  O   O  D   D   Y Y           Z
-    //  BBBB   O   O  D   D    Y           Z
-    //  B   B  O   O  D   D    Y          Z
-    //  BBBB    OOO   DDDD     Y         ZZZZZ
-    //
-    // ALITUDE CONTROLLER (i.e., z-controller)
+	//  **************************************
+	//  BBBB    OOO   DDDD   Y   Y       ZZZZZ
+	//  B   B  O   O  D   D   Y Y           Z
+	//  BBBB   O   O  D   D    Y           Z
+	//  B   B  O   O  D   D    Y          Z
+	//  BBBB    OOO   DDDD     Y         ZZZZZ
+	//
+	// ALITUDE CONTROLLER (i.e., z-controller)
+
+	// Instantiate the local variable for the thrust adjustment that will be
+	// requested from the Crazyflie's on-baord "inner-loop" controller
+	float thrustAdjustment = 0;
+
+	// Perform the "-Kx" LQR computation for the thrust adjustment to respoond with
+	for(int i = 0; i < 9; ++i)
+	{
+		thrustAdjustment -= gainMatrixThrust_NineStateVector[i] * stateErrorBody[i];
+	}
+
+	// Put the computed thrust adjustment into the "response" variable,
+	// as well as adding 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.
+	// > NOTE: the "gravity_force" value was already divided by 4 when is was
+	//         loaded from the .yaml file via the "fetchYamlParameters"
+	//         class function in this file.
+	response.controlOutput.motorCmd1 = computeMotorPolyBackward(thrustAdjustment + gravity_force);
+	response.controlOutput.motorCmd2 = computeMotorPolyBackward(thrustAdjustment + gravity_force);
+	response.controlOutput.motorCmd3 = computeMotorPolyBackward(thrustAdjustment + gravity_force);
+	response.controlOutput.motorCmd4 = computeMotorPolyBackward(thrustAdjustment + gravity_force);
 
-    // Instantiate the local variable for the thrust adjustment that will be
-    // requested from the Crazyflie's on-baord "inner-loop" controller
-    float thrustAdjustment = 0;
 
-    // Perform the "-Kx" LQR computation for the thrust adjustment to respoond with
-    for(int i = 0; i < 9; ++i)
-    {
-        thrustAdjustment -= gainMatrixThrust[i] * stateErrorBody[i];
-    }
 
-    // Put the computed thrust adjustment into the "response" variable,
-    // as well as adding 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.
-    // > NOTE: the "gravity_force" value was already divided by 4 when is was
-    //         loaded from the .yaml file via the "loadPPSTemplateParameters"
-    //         class function in this file.
-    response.controlOutput.motorCmd1 = computeMotorPolyBackward(thrustAdjustment + gravity_force);
-    response.controlOutput.motorCmd2 = computeMotorPolyBackward(thrustAdjustment + gravity_force);
-    response.controlOutput.motorCmd3 = computeMotorPolyBackward(thrustAdjustment + gravity_force);
-    response.controlOutput.motorCmd4 = computeMotorPolyBackward(thrustAdjustment + gravity_force);
-
-
-
-
-    //  **************************************
-    //  BBBB    OOO   DDDD   Y   Y       X   X
-    //  B   B  O   O  D   D   Y Y         X X
-    //  BBBB   O   O  D   D    Y           X
-    //  B   B  O   O  D   D    Y          X X
-    //  BBBB    OOO   DDDD     Y         X   X
-    //
-    // BODY FRAME X CONTROLLER
-
-    // Instantiate the local variable for the pitch rate that will be requested
-    // from the Crazyflie's on-baord "inner-loop" controller
-    float pitchRate_forResponse = 0;
-    
-    // Perform the "-Kx" LQR computation for the pitch rate to respoond with
-    for(int i = 0; i < 9; ++i)
-    {
-        pitchRate_forResponse -= gainMatrixPitch[i] * stateErrorBody[i];
-    }
 
-    // Put the computed pitch rate into the "response" variable
-    response.controlOutput.pitch = pitchRate_forResponse;
-    
+	//  **************************************
+	//  BBBB    OOO   DDDD   Y   Y       X   X
+	//  B   B  O   O  D   D   Y Y         X X
+	//  BBBB   O   O  D   D    Y           X
+	//  B   B  O   O  D   D    Y          X X
+	//  BBBB    OOO   DDDD     Y         X   X
+	//
+	// BODY FRAME X CONTROLLER
+
+	// Instantiate the local variable for the pitch rate that will be requested
+	// from the Crazyflie's on-baord "inner-loop" controller
+	float pitchRate_forResponse = 0;
+
+	// Perform the "-Kx" LQR computation for the pitch rate to respoond with
+	for(int i = 0; i < 9; ++i)
+	{
+		pitchRate_forResponse -= gainMatrixPitchRate[i] * stateErrorBody[i];
+	}
+
+	// Put the computed pitch rate into the "response" variable
+	response.controlOutput.pitch = pitchRate_forResponse;
+
 
 
 
 	//  **************************************
-    //  BBBB    OOO   DDDD   Y   Y       Y   Y
-    //  B   B  O   O  D   D   Y Y         Y Y
-    //  BBBB   O   O  D   D    Y           Y
-    //  B   B  O   O  D   D    Y           Y
-    //  BBBB    OOO   DDDD     Y           Y
-    //
-    // BODY FRAME Y CONTROLLER
-
-    // Instantiate the local variable for the roll rate that will be requested
-    // from the Crazyflie's on-baord "inner-loop" controller
-    float rollRate_forResponse = 0;
-    
-    // Perform the "-Kx" LQR computation for the roll rate to respoond with
-    for(int i = 0; i < 9; ++i)
-    {
-        rollRate_forResponse -= gainMatrixRoll[i] * stateErrorBody[i];
-    }
+	//  BBBB    OOO   DDDD   Y   Y       Y   Y
+	//  B   B  O   O  D   D   Y Y         Y Y
+	//  BBBB   O   O  D   D    Y           Y
+	//  B   B  O   O  D   D    Y           Y
+	//  BBBB    OOO   DDDD     Y           Y
+	//
+	// BODY FRAME Y CONTROLLER
 
-    // Put the computed roll rate into the "response" variable
-    response.controlOutput.roll = rollRate_forResponse;
-    
-    
+	// Instantiate the local variable for the roll rate that will be requested
+	// from the Crazyflie's on-baord "inner-loop" controller
+	float rollRate_forResponse = 0;
 
+	// Perform the "-Kx" LQR computation for the roll rate to respoond with
+	for(int i = 0; i < 9; ++i)
+	{
+		rollRate_forResponse -= gainMatrixRollRate[i] * stateErrorBody[i];
+	}
 
+	// Put the computed roll rate into the "response" variable
+	response.controlOutput.roll = rollRate_forResponse;
 
-    // PREPARE AND RETURN THE VARIABLE "response"
 
-    /*choosing the Crazyflie onBoard controller type.
-    it can either be Motor, Rate or Angle based */
-    // response.controlOutput.onboardControllerType = MOTOR_MODE;
-    response.controlOutput.onboardControllerType = RATE_MODE;
-    // response.controlOutput.onboardControllerType = ANGLE_MODE;
 
-    
-    // SAVE THE STATE ERROR TO BE USED NEXT TIME THIS FUNCTION IS CALLED
-    previous_stateErrorInertial = request.ownCrazyflie; // we have already used previous location, update it
 
-    // Adjust (x,y,z) for the stepoint
-    previous_stateErrorInertial.x = request.ownCrazyflie.x - setpoint[0];
-    previous_stateErrorInertial.y = request.ownCrazyflie.y - setpoint[1];
-    previous_stateErrorInertial.z = request.ownCrazyflie.z - setpoint[2];
+	// PREPARE AND RETURN THE VARIABLE "response"
 
-    // Adjust yaw for the stepoint
-    previous_stateErrorInertial.yaw = stateErrorInertial[8];
+	/*choosing the Crazyflie onBoard controller type.
+	it can either be Motor, Rate or Angle based */
+	// response.controlOutput.onboardControllerType = MOTOR_MODE;
+	response.controlOutput.onboardControllerType = RATE_MODE;
+	// response.controlOutput.onboardControllerType = ANGLE_MODE;
 
+	//  ***********************************************************
+	//  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
+    if (shouldPublishDebugMessage)
+    {
+		// 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);
+	}
+
+
+	// 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-coordinates: " << request.ownCrazyflie.x);
+		ROS_INFO_STREAM("y-coordinates: " << request.ownCrazyflie.y);
+		ROS_INFO_STREAM("z-coordinates: " << request.ownCrazyflie.z);
+		ROS_INFO_STREAM("roll: " << request.ownCrazyflie.roll);
+		ROS_INFO_STREAM("pitch: " << request.ownCrazyflie.pitch);
+		ROS_INFO_STREAM("yaw: " << request.ownCrazyflie.yaw);
+		ROS_INFO_STREAM("Delta t: " << 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[9], Controller::Request &request, Controller::Response &response)
+{
+	//  **********************
+	//  Y   Y    A    W     W
+	//   Y Y    A A   W     W
+	//    Y    A   A  W     W
+	//    Y    AAAAA   W W W
+	//    Y    A   A    W W
+	//
+	// YAW CONTROLLER
+
+	// Put the yaw setpoint directly as the response
+	response.controlOutput.yaw = setpoint[3];
+
+
+
+
+	//  **************************************
+	//  BBBB    OOO   DDDD   Y   Y       ZZZZZ
+	//  B   B  O   O  D   D   Y Y           Z
+	//  BBBB   O   O  D   D    Y           Z
+	//  B   B  O   O  D   D    Y          Z
+	//  BBBB    OOO   DDDD     Y         ZZZZZ
+	//
+	// ALITUDE CONTROLLER (i.e., z-controller)
+
+	// Instantiate the local variable for the thrust adjustment that will be
+	// requested from the Crazyflie's on-baord "inner-loop" controller
+	float thrustAdjustment = 0;
+
+	// Perform the "-Kx" LQR computation for the thrust adjustment to respoond with
+	for(int i = 0; i < 6; ++i)
+	{
+		thrustAdjustment -= gainMatrixThrust_SixStateVector[i] * stateErrorBody[i];
+	}
+
+	// Put the computed thrust adjustment into the "response" variable,
+	// as well as adding 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.
+	// > NOTE: the "gravity_force" value was already divided by 4 when is was
+	//         loaded from the .yaml file via the "fetchYamlParameters"
+	//         class function in this file.
+	response.controlOutput.motorCmd1 = computeMotorPolyBackward(thrustAdjustment + gravity_force);
+	response.controlOutput.motorCmd2 = computeMotorPolyBackward(thrustAdjustment + gravity_force);
+	response.controlOutput.motorCmd3 = computeMotorPolyBackward(thrustAdjustment + gravity_force);
+	response.controlOutput.motorCmd4 = computeMotorPolyBackward(thrustAdjustment + gravity_force);
+
+
+
+
+	//  **************************************
+	//  BBBB    OOO   DDDD   Y   Y       X   X
+	//  B   B  O   O  D   D   Y Y         X X
+	//  BBBB   O   O  D   D    Y           X
+	//  B   B  O   O  D   D    Y          X X
+	//  BBBB    OOO   DDDD     Y         X   X
+	//
+	// BODY FRAME X CONTROLLER
+
+	// Instantiate the local variable for the pitch angle that will be requested
+	// from the Crazyflie's on-baord "inner-loop" controller
+	float pitchAngle_forResponse = 0;
+
+	// Perform the "-Kx" LQR computation for the pitch angle to respoond with
+	for(int i = 0; i < 6; ++i)
+	{
+		pitchAngle_forResponse -= gainMatrixPitchAngle[i] * stateErrorBody[i];
+	}
+
+	// Put the computed pitch angle into the "response" variable
+	response.controlOutput.pitch = pitchAngle_forResponse;
+
 
-    // 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);
-
-
-    // An alternate debugging technique is to print out data directly to the
-    // command line from which this node was launched.
-
-    // 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-coordinates: " << request.ownCrazyflie.x);
-    // ROS_INFO_STREAM("y-coordinates: " << request.ownCrazyflie.y);
-    // ROS_INFO_STREAM("z-coordinates: " << request.ownCrazyflie.z);
-    // ROS_INFO_STREAM("roll: " << request.ownCrazyflie.roll);
-    // ROS_INFO_STREAM("pitch: " << request.ownCrazyflie.pitch);
-    // ROS_INFO_STREAM("yaw: " << request.ownCrazyflie.yaw);
-    // ROS_INFO_STREAM("Delta t: " << 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);
-
-    // Return "true" to indicate that the control computation was performed successfully
-    return true;
+
+
+	//  **************************************
+	//  BBBB    OOO   DDDD   Y   Y       Y   Y
+	//  B   B  O   O  D   D   Y Y         Y Y
+	//  BBBB   O   O  D   D    Y           Y
+	//  B   B  O   O  D   D    Y           Y
+	//  BBBB    OOO   DDDD     Y           Y
+	//
+	// BODY FRAME Y CONTROLLER
+
+	// Instantiate the local variable for the roll angle that will be requested
+	// from the Crazyflie's on-baord "inner-loop" controller
+	float rollAngle_forResponse = 0;
+
+	// Perform the "-Kx" LQR computation for the roll angle to respoond with
+	for(int i = 0; i < 6; ++i)
+	{
+		rollAngle_forResponse -= gainMatrixRollAngle[i] * stateErrorBody[i];
+	}
+
+	// Put the computed roll angle into the "response" variable
+	response.controlOutput.roll = rollAngle_forResponse;
+
+
+
+
+	// PREPARE AND RETURN THE VARIABLE "response"
+
+	/*choosing the Crazyflie onBoard controller type.
+	it can either be Motor, Rate or Angle based */
+	//response.controlOutput.onboardControllerType = MOTOR_MODE;
+	//response.controlOutput.onboardControllerType = RATE_MODE;
+	response.controlOutput.onboardControllerType = ANGLE_MODE;
 }
 
 
@@ -599,20 +895,43 @@ bool calculateControlOutput(Controller::Request &request, Controller::Response &
 // This function WILL NEED TO BE edited for successful completion of the PPS exercise
 void convertIntoBodyFrame(float stateInertial[9], float (&stateBody)[9], float yaw_measured)
 {
-    // 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];
+	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];
+	}
+	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];
+	}
 }
 
 
@@ -668,6 +987,24 @@ void setpointCallback(const Setpoint& newSetpoint)
 
 
 
+// This function DOES NOT NEED TO BE edited for successful completion of the PPS exercise
+// > This function is called anytime a message is published on the topic to which the
+//   class instance variable "xyz_yaw_to_follow_subscriber" is subscribed
+void xyz_yaw_to_follow_callback(const Setpoint& newSetpoint)
+{
+        //ROS_INFO("DEBUGGING: Received new setpoint from another agent");
+	// The setpoint should only be updated if allow by the respective booelan
+	if (shouldFollowAnotherAgent)
+	{
+	    setpoint[0] = newSetpoint.x;
+	    setpoint[1] = newSetpoint.y;
+	    setpoint[2] = newSetpoint.z;
+	    setpoint[3] = newSetpoint.yaw;
+	}
+}
+
+
+
 
 
 //    ----------------------------------------------------------------------------------
@@ -684,27 +1021,277 @@ void setpointCallback(const Setpoint& newSetpoint)
 //    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_CUSTOM_CONTROLLER_AGENT:
+		{
+			// Let the user know that this message was received
+			ROS_INFO("The CustomControllerService 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_CUSTOM_CONTROLLER_COORDINATOR:
+		{
+			// Let the user know that this message was received
+			ROS_INFO("The CustomControllerService 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_customController(nodeHandle, "CustomController");
+
+	// > The mass of the crazyflie
+	cf_mass = getParameterFloat(nodeHandle_for_customController , "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
+	control_frequency = getParameterFloat(nodeHandle_for_customController, "control_frequency");
+
+	// > The co-efficients of the quadratic conversation from 16-bit motor command to
+	//   thrust force in Newtons
+	getParameterFloatVector(nodeHandle_for_customController, "motorPoly", motorPoly, 3);
+
+	// > The boolean for whether to execute the convert into body frame function
+	shouldPerformConvertIntoBodyFrame = getParameterBool(nodeHandle_for_customController, "shouldPerformConvertIntoBodyFrame");
+
+	// > The boolean indicating whether the (x,y,z,yaw) of this agent should be published
+	//   or not
+	shouldPublishCurrent_xyz_yaw = getParameterBool(nodeHandle_for_customController, "shouldPublishCurrent_xyz_yaw");
+
+	// > The boolean indicating whether the (x,y,z,yaw) setpoint of this agent should adapted in
+	//   an attempt to follow the "my_current_xyz_yaw_topic" from another agent
+	shouldFollowAnotherAgent = getParameterBool(nodeHandle_for_customController, "shouldFollowAnotherAgent");
+
+	// > The ordered vector for ID's that specifies how the agents should follow eachother
+	follow_in_a_line_agentIDs.clear();
+	int temp_number_of_agents_in_a_line = getParameterIntVectorWithUnknownLength(nodeHandle_for_customController, "follow_in_a_line_agentIDs", follow_in_a_line_agentIDs);
+	// > Double check that the sizes agree
+	if ( temp_number_of_agents_in_a_line != follow_in_a_line_agentIDs.size() )
+	{
+		// Update the user if the sizes don't agree
+		ROS_ERROR_STREAM("parameter 'follow_in_a_line_agentIDs' was loaded with two different lengths, " << temp_number_of_agents_in_a_line << " versus " << follow_in_a_line_agentIDs.size() );
+	}
+
+	// Boolean indiciating whether the "Debug Message" of this agent should be published or not
+	shouldPublishDebugMessage = getParameterBool(nodeHandle_for_customController, "shouldPublishDebugMessage");
+
+	// Boolean indiciating whether the debugging ROS_INFO_STREAM should be displayed or not
+	shouldDisplayDebugInfo = getParameterBool(nodeHandle_for_customController, "shouldDisplayDebugInfo");
+
+
+	// THE CONTROLLER GAINS:
+
+	// A flag for which controller to use, defined as:
+	controller_type = getParameterInt( nodeHandle_for_customController , "controller_type" );
+
+	// The LQR Controller parameters for "LQR_RATE_MODE"
+	getParameterFloatVector(nodeHandle_for_customController, "gainMatrixRollRate",               gainMatrixRollRate,               9);
+	getParameterFloatVector(nodeHandle_for_customController, "gainMatrixPitchRate",              gainMatrixPitchRate,              9);
+	getParameterFloatVector(nodeHandle_for_customController, "gainMatrixYawRate",                gainMatrixYawRate,                9);
+	getParameterFloatVector(nodeHandle_for_customController, "gainMatrixThrust_NineStateVector", gainMatrixThrust_NineStateVector, 9);
+
+	// The LQR Controller parameters for "LQR_ANGLE_MODE"
+	getParameterFloatVector(nodeHandle_for_customController, "gainMatrixRollAngle",              gainMatrixRollAngle,              6);
+	getParameterFloatVector(nodeHandle_for_customController, "gainMatrixPitchAngle",             gainMatrixPitchAngle,             6);
+	getParameterFloatVector(nodeHandle_for_customController, "gainMatrixThrust_SixStateVector",  gainMatrixThrust_SixStateVector,  6);
+
+
+	// DEBUGGING: Print out one of the parameters that was loaded
+	ROS_INFO_STREAM("DEBUGGING: the fetched SafeController/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 loadPPSTemplateParameters(ros::NodeHandle& nodeHandle)
+void processFetchedParameters()
 {
-    // here we load the parameters that are in the CustomController.yaml
+    // Compute the feed-forward force that we need to counteract gravity (i.e., mg)
+    // > in units of [Newtons]
+    gravity_force = cf_mass * 9.81/(1000*4);
 
-    cf_mass = getFloatParameter(nodeHandle, "mass");
-    control_frequency = getFloatParameter(nodeHandle, "control_frequency");
-    loadParameterFloatVector(nodeHandle, "motorPoly", motorPoly, 3);
+    // Look-up which agent should be followed
+    if (shouldFollowAnotherAgent)
+    {
+    	// Only bother if the "follow_in_a_line_agentIDs" vector has a non-zero length
+    	if (follow_in_a_line_agentIDs.size() > 0)
+    	{
+    		// Instantiate a local boolean variable for checking whether we found
+    		// our own agent ID in the list
+    		bool foundMyAgentID = false;
+    		// Iterate through the vector of "follow_in_a_line_agentIDs"
+	    	for ( int i=0 ; i<follow_in_a_line_agentIDs.size() ; i++ )
+	    	{
+	    		// Check if the current entry matches the ID of this agent
+	    		if (follow_in_a_line_agentIDs[i] == my_agentID)
+	    		{
+	    			// Set the boolean flag that we have found out own agent ID
+	    			foundMyAgentID = true;
+                    //ROS_INFO_STREAM("DEBUGGING: found my agent ID at index " << i );
+	    			// If it is the first entry, then this agent is the leader
+	    			if (i==0)
+	    			{
+	    				// The leader does not follow anyone else
+	    				shouldFollowAnotherAgent = false;
+    					agentID_to_follow = 0;
+	    			}
+	    			else
+	    			{
+	    				// The agent ID to follow is the previous entry
+	    				agentID_to_follow = follow_in_a_line_agentIDs[i-1];	
+                        shouldFollowAnotherAgent = true;
+	    				// Subscribe to the "my_current_xyz_yaw_topic" of the agent ID
+	    				// that this agent should be following
+	    				ros::NodeHandle nodeHandle("~");
+	    				xyz_yaw_to_follow_subscriber = nodeHandle.subscribe("/" + std::to_string(agentID_to_follow) + "/my_current_xyz_yaw_topic", 1, xyz_yaw_to_follow_callback);
+	    				//ROS_INFO_STREAM("DEBUGGING: subscribed to agent ID = " << agentID_to_follow );
+	    			}
+	    			// Break out of the for loop as the assumption is that each agent ID
+	    			// appears only once in the "follow_in_a_line_agentIDs" vector of ID's
+	    			break;
+	    		}
+	    	}
+	    	// Check whether we found our own agent ID
+	    	if (!foundMyAgentID)
+	    	{
+                //ROS_INFO("DEBUGGING: not following because my ID was not found");
+	    		// Revert to the default of not following any agent
+    			shouldFollowAnotherAgent = false;
+    			agentID_to_follow = 0;
+	    	}
+    	}
+    	else
+    	{
+    		// As the "follow_in_a_line_agentIDs" vector has length zero, revert to the
+    		// default of not following any agent
+    		shouldFollowAnotherAgent = false;
+    		agentID_to_follow = 0;
+    		//ROS_INFO("DEBUGGING: not following because line vector has length zero");
+    	}
+    }
+    else
+    {
+    	// Set to its default value the integer specifying the ID of the agent that will
+    	// be followed by this agent
+		agentID_to_follow = 0;
+		//ROS_INFO("DEBUGGING: not following because I was asked not to follow");
+    }
+
+    if (shouldFollowAnotherAgent)
+    {
+    	ROS_INFO_STREAM("This agent (with ID " << my_agentID << ") will now follow agent ID " << agentID_to_follow );
+    }
+}
 
-    // compute things that we will need after from these parameters
 
-    // force that we need to counteract gravity (mg)
-    gravity_force = cf_mass * 9.81/(1000*4); // in N
+/*
+// This function DOES NOT NEED TO BE edited for successful completion of the PPS exercise
+void customYAMLasMessageCallback(const CustomControllerYAML& newCustomControllerParameters)
+{
+	// This function puts all the same parameters as the "fetchYamlParameters" function
+	// above into the same variables.
+	// The difference is that this function allows us to send all parameters from one
+	// central coordinator node
+	cf_mass = newCustomControllerParameters.mass;
+	control_frequency = newCustomControllerParameters.control_frequency;
+	for (int i=0;i<3;i++)
+	{
+		motorPoly[i] = newCustomControllerParameters.motorPoly[i];
+	}
+
+	// > The boolean for whether to execute the convert into body frame function
+    shouldPerformConvertIntoBodyFrame = newCustomControllerParameters.shouldPerformConvertIntoBodyFrame;
+
+	shouldPublishCurrent_xyz_yaw = newCustomControllerParameters.shouldPublishCurrent_xyz_yaw;
+	shouldFollowAnotherAgent = newCustomControllerParameters.shouldFollowAnotherAgent;
+	follow_in_a_line_agentIDs.clear();
+	for ( int i=0 ; i<newCustomControllerParameters.follow_in_a_line_agentIDs.size() ; i++ )
+	{
+		follow_in_a_line_agentIDs.push_back( newCustomControllerParameters.follow_in_a_line_agentIDs[i] );
+	}
+
+	// Let the user know that the message was received with new YAML parameters
+	ROS_INFO("Received message containing a new set of Custom Controller YAML parameters");
+
+	// Display one of the YAML parameters to debug if it is working correctly
+	ROS_INFO_STREAM("DEBUGGING: mass received in message = " << newCustomControllerParameters.mass );	
+
+	// Call the function that computes details an values that are needed from these
+    // parameters loaded above
+    ros::NodeHandle nodeHandle("~");
+    processFetchedParameters(nodeHandle);
+
 }
+*/
 
-// load parameters from corresponding YAML file
-//
+
+//    ----------------------------------------------------------------------------------
+//     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 loadParameterFloatVector(ros::NodeHandle& nodeHandle, std::string name, std::vector<float>& val, int length)
+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 << "'");
@@ -713,26 +1300,46 @@ void loadParameterFloatVector(ros::NodeHandle& nodeHandle, std::string name, std
         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
-float getFloatParameter(ros::NodeHandle& nodeHandle, std::string name)
+int getParameterInt(ros::NodeHandle& nodeHandle, std::string name)
 {
-
-    float val;
+    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 customYAMLloadedCallback(const std_msgs::Int32& msg)
+void getParameterIntVectorWithKnownLength(ros::NodeHandle& nodeHandle, std::string name, std::vector<int>& val, int length)
 {
-    ros::NodeHandle nodeHandle("~");
-    ROS_INFO("received msg custom loaded YAML");
-    loadPPSTemplateParameters(nodeHandle);
+    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;
 }
+    
+
 
 
 
@@ -755,8 +1362,86 @@ int main(int argc, char* argv[]) {
     // the "~" indcates that "self" is the node handle assigned to this variable.
     ros::NodeHandle nodeHandle("~");
 
-    // Call the class function that loads the parameters for this class.
-    loadPPSTemplateParameters(nodeHandle);
+    // 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 namespace of this "CustomControllerService" node
+    std::string m_namespace = ros::this_node::getNamespace();
+    // 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("studentID", my_agentID))
+    {
+    	// Throw an error if the student ID parameter could not be obtained
+		ROS_ERROR("Failed to get studentID from FollowN_1Service");
+	}
+
+
+	// *********************************************************************************
+	// 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("The namespace string for accessing the Paramter Services are:");
+    ROS_INFO_STREAM("namespace_to_own_agent_parameter_service    =  " << namespace_to_own_agent_parameter_service);
+    ROS_INFO_STREAM("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);
+
+    // *********************************************************************************
+
+
 
     // Instantiate the instance variable "debugPublisher" to be a "ros::Publisher" that
     // advertises under the name "DebugTopic" and is a message with the structure
@@ -785,12 +1470,11 @@ int main(int argc, char* argv[]) {
     // in the "DEFINES" section at the top of this file.
     ros::NodeHandle namespace_nodeHandle(ros::this_node::getNamespace());
 
-    // Instantiate the local variable "customYAMLloadedSubscriber" to be a "ros::Subscriber"
-    // type variable that subscribes to the "student_GUI/customYAMLloaded" topic and calls
-    // the class function "customYAMLloadedCallback" each time a messaged is received on
-    // this topic. Such a message is sent when the button "Load Customcontroller YAML file"
-    // is clicked in the student GUI.
-    ros::Subscriber customYAMLloadedSubscriber = namespace_nodeHandle.subscribe("student_GUI/customYAMLloaded", 1, customYAMLloadedCallback);
+    // Instantiate the instance variable "my_current_xyz_yaw_publisher" to be a "ros::Publisher"
+    // that advertises under the name "<my_agentID>/my_current_xyz_yaw_topic" where <my_agentID>
+    // is filled in with the student ID number of this computer. The messages published will
+    // have the structure defined in the file "Setpoint.msg" (located in the "msg" folder).
+    my_current_xyz_yaw_publisher = nodeHandle.advertise<Setpoint>("/" + std::to_string(my_agentID) + "/my_current_xyz_yaw_topic", 1);
 
     // Print out some information to the user.
     ROS_INFO("CustomControllerService ready");
diff --git a/pps_ws/src/d_fall_pps/src/PPSClient.cpp b/pps_ws/src/d_fall_pps/src/PPSClient.cpp
index 0bdf945820e024a937fdaed560f1f630d1429dcd..8f8d560e75e9fc9a9decdcce1c8bbc6beef8e177 100755
--- a/pps_ws/src/d_fall_pps/src/PPSClient.cpp
+++ b/pps_ws/src/d_fall_pps/src/PPSClient.cpp
@@ -1,4 +1,4 @@
-//    Copyright (C) 2017, ETH Zurich, D-ITET, Angel Romero, Cyrill Burgener, Marco Mueller, Philipp Friedli
+//    Copyright (C) 2017, ETH Zurich, D-ITET, Paul Beuchat, Angel Romero, Cyrill Burgener, Marco Mueller, Philipp Friedli
 //
 //    This file is part of D-FaLL-System.
 //    
@@ -30,10 +30,20 @@
 //    ----------------------------------------------------------------------------------
 
 
+
+
+
+//    ----------------------------------------------------------------------------------
+//    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
+//    ----------------------------------------------------------------------------------
+
 #include "ros/ros.h"
 #include <stdlib.h>
 #include <std_msgs/String.h>
-#include <rosbag/bag.h>
 #include <ros/package.h>
 
 #include "d_fall_pps/Controller.h"
@@ -47,18 +57,33 @@
 #include "std_msgs/Int32.h"
 #include "std_msgs/Float32.h"
 
-
 #include "d_fall_pps/ControlCommand.h"
 
-// types PPS firmware
+// Need for having a ROS "bag" to store data for post-analysis
+//#include <rosbag/bag.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
+//    ----------------------------------------------------------------------------------
+
+// Types PPS firmware
 #define TYPE_PPS_MOTORS 6
-#define TYPE_PPS_RATE 7
-#define TYPE_PPS_ANGLE 8
+#define TYPE_PPS_RATE   7
+#define TYPE_PPS_ANGLE  8
 
-// tipes of controllers being used:
+// Types of controllers being used:
 #define SAFE_CONTROLLER   0
 #define CUSTOM_CONTROLLER 1
 
+// The constants that "command" changes in the
+// operation state of this agent
 #define CMD_USE_SAFE_CONTROLLER   1
 #define CMD_USE_CUSTOM_CONTROLLER 2
 #define CMD_CRAZYFLY_TAKE_OFF     3
@@ -71,12 +96,11 @@
 #define STATE_FLYING     3
 #define STATE_LAND       4
 
-// battery states
-
+// Battery states
 #define BATTERY_STATE_NORMAL 0
 #define BATTERY_STATE_LOW    1
 
-// commands for CrazyRadio
+// Commands for CrazyRadio
 #define CMD_RECONNECT  0
 #define CMD_DISCONNECT 1
 
@@ -86,17 +110,37 @@
 #define CONNECTING       1
 #define DISCONNECTED     2
 
-// parameters for take off and landing. Eventually will go in YAML file
-#define TAKE_OFF_OFFSET  1    //in meters
-#define LANDING_DISTANCE 0.15    //in meters
-#define DURATION_TAKE_OFF  3   // seconds
-#define DURATION_LANDING   3   // seconds
+// For which controller parameters to load
+#define FETCH_YAML_SAFE_CONTROLLER_AGENT          1
+#define FETCH_YAML_CUSTOM_CONTROLLER_AGENT        2
+#define FETCH_YAML_SAFE_CONTROLLER_COORDINATOR    3
+#define FETCH_YAML_CUSTOM_CONTROLLER_COORDINATOR  4
+
 
+// Parameters for take off and landing. Eventually will go in YAML file
+//#define TAKE_OFF_OFFSET  1    //in meters
+//#define LANDING_DISTANCE 0.15    //in meters
+//#define DURATION_TAKE_OFF  3   // seconds
+//#define DURATION_LANDING   3   // seconds
 
+// Universal constants
 #define PI 3.141592653589
 
+// 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
+//    ----------------------------------------------------------------------------------
+
 //studentID, gives namespace and identifier in CentralManagerService
 int studentID;
 
@@ -147,7 +191,13 @@ ros::Publisher commandPublisher;
 // communication with crazyRadio node. Connect and disconnect
 ros::Publisher crazyRadioCommandPublisher;
 
-rosbag::Bag bag;
+
+// Variable for the namespaces for the paramter 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;
+
 
 // variables for the states:
 int flying_state;
@@ -180,6 +230,51 @@ bool finished_land = false;
 ros::Timer timer_takeoff;
 ros::Timer timer_land;
 
+// A ROS "bag" to store data for post-analysis
+//rosbag::Bag bag;
+
+
+
+
+//    ----------------------------------------------------------------------------------
+//    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
+//    ----------------------------------------------------------------------------------
+
+
+// > For the LOAD PARAMETERS
+void yamlReadyForFetchCallback(const std_msgs::Int32& msg);
+void fetchYamlParametersForSafeController(ros::NodeHandle& nodeHandle);
+void fetchClientConfigParameters(ros::NodeHandle& nodeHandle);
+
+
+
+void crazyRadioCommandAllAgentsCallback(const std_msgs::Int32& msg);
+
+
+
+//    ----------------------------------------------------------------------------------
+//    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
+//    ----------------------------------------------------------------------------------
 
 void loadSafeController() {
 	ros::NodeHandle nodeHandle("~");
@@ -374,7 +469,7 @@ void changeFlyingStateTo(int new_state)
     }
     else
     {
-        ROS_INFO("Disconnected and trying to change state. Stays goes to MOTORS OFF");
+        ROS_INFO("Disconnected and trying to change state. State goes to MOTORS OFF");
         flying_state = STATE_MOTORS_OFF;
     }
 
@@ -529,8 +624,9 @@ void viconCallback(const ViconData& viconData) {
 
                     controlCommandPublisher.publish(controllerCall.response.controlOutput);
 
-                    bag.write("ViconData", ros::Time::now(), local);
-                    bag.write("ControlOutput", ros::Time::now(), controllerCall.response.controlOutput);
+                    // Putting data into the ROS "bag" for post-analysis
+                    //bag.write("ViconData", ros::Time::now(), local);
+                    //bag.write("ControlOutput", ros::Time::now(), controllerCall.response.controlOutput);
                 }
             }
             else
@@ -538,63 +634,17 @@ void viconCallback(const ViconData& viconData) {
                 ControlCommand zeroOutput = ControlCommand(); //everything set to zero
                 zeroOutput.onboardControllerType = TYPE_PPS_MOTORS; //set to motor_mode
                 controlCommandPublisher.publish(zeroOutput);
-                bag.write("ViconData", ros::Time::now(), local);
-                bag.write("ControlOutput", ros::Time::now(), zeroOutput);
+
+                // Putting data into the ROS "bag" for post-analysis
+                //bag.write("ViconData", ros::Time::now(), local);
+                //bag.write("ControlOutput", ros::Time::now(), zeroOutput);
             }
         }
 	}
 }
 
-void loadParameters(ros::NodeHandle& nodeHandle) {
-	if(!nodeHandle.getParam("studentID", studentID)) {
-		ROS_ERROR("Failed to get studentID");
-	}
-	if(!nodeHandle.getParam("strictSafety", strictSafety)) {
-		ROS_ERROR("Failed to get strictSafety param");
-		return;
-	}
-	if(!nodeHandle.getParam("angleMargin", angleMargin)) {
-		ROS_ERROR("Failed to get angleMargin param");
-		return;
-	}
-    if(!nodeHandle.getParam("battery_threshold_while_flying", m_battery_threshold_while_flying)) {
-		ROS_ERROR("Failed to get battery_threshold_while_flying param");
-		return;
-	}
-    if(!nodeHandle.getParam("battery_threshold_while_motors_off", m_battery_threshold_while_motors_off)) {
-		ROS_ERROR("Failed to get battery_threshold_while_motors_off param");
-		return;
-	}
-}
-
-void loadSafeControllerParameters()
-{
-    ros::NodeHandle nh_safeControllerService(ros_namespace + "/SafeControllerService");
-    if(!nh_safeControllerService.getParam("takeOffDistance", take_off_distance))
-    {
-		ROS_ERROR("Failed to get takeOffDistance");
-	}
-
-    if(!nh_safeControllerService.getParam("landingDistance", landing_distance))
-    {
-		ROS_ERROR("Failed to get landing_distance");
-	}
-
-    if(!nh_safeControllerService.getParam("durationTakeOff", duration_take_off))
-    {
-		ROS_ERROR("Failed to get duration_take_off");
-	}
 
-    if(!nh_safeControllerService.getParam("durationLanding", duration_landing))
-    {
-		ROS_ERROR("Failed to get duration_landing");
-	}
 
-    if(!nh_safeControllerService.getParam("distanceThreshold", distance_threshold))
-    {
-		ROS_ERROR("Failed to get distance_threshold");
-	}
-}
 
 void loadCrazyflieContext() {
 	CMQuery contextCall;
@@ -686,6 +736,11 @@ void emergencyStopCallback(const std_msgs::Int32& msg)
     commandCallback(msg);
 }
 
+void commandAllAgentsCallback(const std_msgs::Int32& msg)
+{
+    commandCallback(msg);
+}
+
 void crazyRadioStatusCallback(const std_msgs::Int32& msg)
 {
     crazyradio_status = msg.data;
@@ -708,12 +763,147 @@ void safeSetPointCallback(const Setpoint& newSetpoint)
 }
 
 
-void safeYAMLloadedCallback(const std_msgs::Int32& msg)
+
+
+//    ----------------------------------------------------------------------------------
+//    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
+//    ----------------------------------------------------------------------------------
+
+
+void yamlReadyForFetchCallback(const std_msgs::Int32& msg)
 {
-    ROS_INFO("received msg safe loaded YAML");
-    loadSafeControllerParameters();
+    // 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_SAFE_CONTROLLER_AGENT:
+        {
+            // Let the user know that this message was received
+            ROS_INFO("The PPSClient received the message that YAML parameters were (re-)loaded for the Safe Controller. > Now fetching the parameter values from this machine.");
+            // 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
+            fetchYamlParametersForSafeController(nodeHandle_to_own_agent_parameter_service);
+            break;
+        }
+
+        // > FOR FETCHING FROM THE COORDINATOR'S PARAMETER SERVICE
+        case FETCH_YAML_SAFE_CONTROLLER_COORDINATOR:
+        {
+            // Let the user know that this message was received
+            // > and also from where the paramters are being fetched
+            ROS_INFO("The PPSClient received the message that YAML parameters were (re-)loaded for the Safe Controller. > 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
+            fetchYamlParametersForSafeController(nodeHandle_to_coordinator_parameter_service);
+            break;
+        }
+
+        default:
+        {
+            // Let the user know that the command was not relevant
+            //ROS_INFO("The PPSClient received the message that YAML parameters were (re-)loaded.\r> However the parameters do not relate to this service, hence nothing will be fetched.");
+            break;
+        }
+    }
+}
+
+
+
+void fetchYamlParametersForSafeController(ros::NodeHandle& nodeHandle)
+{
+    // Here we load the parameters that are specified in the SafeController.yaml file
+
+    // Add the "CustomController" namespace to the "nodeHandle"
+    ros::NodeHandle nodeHandle_for_safeController(nodeHandle, "SafeController");
+
+    if(!nodeHandle_for_safeController.getParam("takeOffDistance", take_off_distance))
+    {
+        ROS_ERROR("Failed to get takeOffDistance");
+    }
+
+    if(!nodeHandle_for_safeController.getParam("landingDistance", landing_distance))
+    {
+        ROS_ERROR("Failed to get landing_distance");
+    }
+
+    if(!nodeHandle_for_safeController.getParam("durationTakeOff", duration_take_off))
+    {
+        ROS_ERROR("Failed to get duration_take_off");
+    }
+
+    if(!nodeHandle_for_safeController.getParam("durationLanding", duration_landing))
+    {
+        ROS_ERROR("Failed to get duration_landing");
+    }
+
+    if(!nodeHandle_for_safeController.getParam("distanceThreshold", distance_threshold))
+    {
+        ROS_ERROR("Failed to get distance_threshold");
+    }
 }
 
+
+// > Load the paramters from the Client Config YAML file
+void fetchClientConfigParameters(ros::NodeHandle& nodeHandle)
+{
+    if(!nodeHandle.getParam("studentID", studentID)) {
+        ROS_ERROR("Failed to get studentID");
+    }
+    if(!nodeHandle.getParam("strictSafety", strictSafety)) {
+        ROS_ERROR("Failed to get strictSafety param");
+        return;
+    }
+    if(!nodeHandle.getParam("angleMargin", angleMargin)) {
+        ROS_ERROR("Failed to get angleMargin param");
+        return;
+    }
+    if(!nodeHandle.getParam("battery_threshold_while_flying", m_battery_threshold_while_flying)) {
+        ROS_ERROR("Failed to get battery_threshold_while_flying param");
+        return;
+    }
+    if(!nodeHandle.getParam("battery_threshold_while_motors_off", m_battery_threshold_while_motors_off)) {
+        ROS_ERROR("Failed to get battery_threshold_while_motors_off param");
+        return;
+    }
+}
+
+
+
+
+
+
+
+
+void crazyRadioCommandAllAgentsCallback(const std_msgs::Int32& msg)
+{
+    // The "msg" received can be directly published on the "crazyRadioCommandPublisher"
+    // class variable because it is same format message
+    // > NOTE: this may be inefficient to "just" pass on the message,
+    //   the intention is that it is more transparent that the "coordinator"
+    //   node requests all agents to (re/dis)-connect from, and the
+    //   individual agents pass this along to their respective radio node.
+    crazyRadioCommandPublisher.publish(msg);
+}
+
+
+
 int getBatteryState()
 {
     return m_battery_state;
@@ -792,32 +982,92 @@ void CFBatteryCallback(const std_msgs::Float32& msg)
     }
 }
 
+
+//    ----------------------------------------------------------------------------------
+//    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
+//    ----------------------------------------------------------------------------------
+
 int main(int argc, char* argv[])
 {
 	ros::init(argc, argv, "PPSClient");
 	ros::NodeHandle nodeHandle("~");
     ros_namespace = ros::this_node::getNamespace();
 
-    // load default setpoint
-    std::vector<float> default_setpoint(4);
-    ros::NodeHandle nh_safeControllerService(ros_namespace + "/SafeControllerService");
+    // *********************************************************************************
+    // EVERYTHING THAT RELATES TO FETCHING PARAMETERS FROM A YAML FILE
+
+    // > Load the paramters from the Client Config YAML file
+    fetchClientConfigParameters(nodeHandle);
 
-    ROS_INFO_STREAM(ros_namespace << "/SafeControllerService");
+    // Get the namespace of this "SafeControllerService" node
+    std::string m_namespace = ros::this_node::getNamespace();
 
-    if(!nh_safeControllerService.getParam("defaultSetpoint", default_setpoint))
+
+    // 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 = "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("/ParameterService/controllerYamlReadyForFetch", 1, yamlReadyForFetchCallback);
+
+
+    // FINALLY, FETCH ANY PARAMETERS REQUIRED FROM THESE "PARAMETER SERVICES"
+
+    // Call the class function that loads the parameters for this class.
+    fetchYamlParametersForSafeController(nodeHandle_to_own_agent_parameter_service);
+
+    // *********************************************************************************
+
+
+    // Load default setpoint from the "SafeController" namespace of the "ParameterService"
+    std::vector<float> default_setpoint(4);
+    ros::NodeHandle nodeHandle_for_safeController(nodeHandle_to_own_agent_parameter_service, "SafeController");
+
+    if(!nodeHandle_for_safeController.getParam("defaultSetpoint", default_setpoint))
     {
-        ROS_ERROR_STREAM("couldn't find parameter 'defaultSetpoint'");
+        ROS_ERROR_STREAM("The PPSClient could not find parameter 'defaultSetpoint', as called from main(...)");
     }
 
+    // Copy the default setpoint into the class variable
     controller_setpoint.x = default_setpoint[0];
     controller_setpoint.y = default_setpoint[1];
     controller_setpoint.z = default_setpoint[2];
     controller_setpoint.yaw = default_setpoint[3];
 
-    // load context parameters
-	loadParameters(nodeHandle);
-    loadSafeControllerParameters();
-
 	//ros::service::waitForService("/CentralManagerService/CentralManager");
 	centralManager = nodeHandle.serviceClient<CMQuery>("/CentralManagerService/Query", false);
 	loadCrazyflieContext();
@@ -864,10 +1114,14 @@ int main(int argc, char* argv[])
     // subscriber for emergencyStop
     ros::Subscriber emergencyStopSubscriber = namespaceNodeHandle.subscribe("/my_GUI/emergencyStop", 1, emergencyStopCallback);
 
+    // Subscriber for "commandAllAgents" commands that are sent from the coordinator node
+    ros::Subscriber commandAllAgentsSubscriber = namespaceNodeHandle.subscribe("/my_GUI/commandAllAgents", 1, commandAllAgentsCallback);
+
     // crazyradio status. Connected, connecting or disconnected
     ros::Subscriber crazyRadioStatusSubscriber = namespaceNodeHandle.subscribe("CrazyRadio/CrazyRadioStatus", 1, crazyRadioStatusCallback);
 
-    ros::Subscriber safeYAMloadedSubscriber = namespaceNodeHandle.subscribe("student_GUI/safeYAMLloaded", 1, safeYAMLloadedCallback);
+    // Subscriber for "crazyRadioCommandAllAgents" commands that are sent from the coordinator node
+    ros::Subscriber crazyRadioCommandAllAgentsSubscriber = namespaceNodeHandle.subscribe("/my_GUI/crazyRadioCommandAllAgents", 1, crazyRadioCommandAllAgentsCallback);
 
     // know the battery level of the CF
     ros::Subscriber CFBatterySubscriber = namespaceNodeHandle.subscribe("CrazyRadio/CFBattery", 1, CFBatteryCallback);
@@ -879,13 +1133,17 @@ int main(int argc, char* argv[])
 
     setBatteryStateTo(BATTERY_STATE_NORMAL); //initialize battery state
 
-	std::string package_path;
-	package_path = ros::package::getPath("d_fall_pps") + "/";
-	ROS_INFO_STREAM(package_path);
-	std::string record_file = package_path + "LoggingPPSClient.bag";
-	bag.open(record_file, rosbag::bagmode::Write);
+    // Open a ROS "bag" to store data for post-analysis
+	// std::string package_path;
+	// package_path = ros::package::getPath("d_fall_pps") + "/";
+	// ROS_INFO_STREAM(package_path);
+	// std::string record_file = package_path + "LoggingPPSClient.bag";
+	// bag.open(record_file, rosbag::bagmode::Write);
 
     ros::spin();
-	bag.close();
+
+    // Close the ROS "bag" that was opened to store data for post-analysis
+	//bag.close();
+
     return 0;
 }
diff --git a/pps_ws/src/d_fall_pps/src/ParameterService.cpp b/pps_ws/src/d_fall_pps/src/ParameterService.cpp
new file mode 100755
index 0000000000000000000000000000000000000000..cf9c361e14e6fc22ef9ff49c17b7cde5a0071981
--- /dev/null
+++ b/pps_ws/src/d_fall_pps/src/ParameterService.cpp
@@ -0,0 +1,424 @@
+//    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:
+//    The service that manages the loading of YAML parameters
+//
+//    ----------------------------------------------------------------------------------
+
+
+
+
+
+//    ----------------------------------------------------------------------------------
+//    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
+//    ----------------------------------------------------------------------------------
+
+#include <stdlib.h>
+#include <string>
+
+#include <ros/ros.h>
+#include <ros/package.h>
+#include <ros/network.h>
+#include "std_msgs/Int32.h"
+//#include "std_msgs/Float32.h"
+//#include <std_msgs/String.h>
+
+#include "d_fall_pps/Controller.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
+//    ----------------------------------------------------------------------------------
+
+
+// For which controller parameters to load
+#define LOAD_YAML_SAFE_CONTROLLER_AGENT           1
+#define LOAD_YAML_CUSTOM_CONTROLLER_AGENT         2
+#define LOAD_YAML_SAFE_CONTROLLER_COORDINATOR     3
+#define LOAD_YAML_CUSTOM_CONTROLLER_COORDINATOR   4
+
+#define FETCH_YAML_SAFE_CONTROLLER_FROM_OWN_AGENT      1
+#define FETCH_YAML_CUSTOM_CONTROLLER_FROM_OWN_AGENT    2
+#define FETCH_YAML_SAFE_CONTROLLER_FROM_COORDINATOR    3
+#define FETCH_YAML_CUSTOM_CONTROLLER_FROM_COORDINATOR  4
+
+#define TYPE_INVALID      -1
+#define TYPE_COORDINATOR   1
+#define TYPE_AGENT         2
+
+
+// Namespacing the package
+using namespace d_fall_pps;
+//using namespace std;
+
+
+
+
+//    ----------------------------------------------------------------------------------
+//    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
+//    ----------------------------------------------------------------------------------
+
+// The type of this node, i.e., agent or a coordinator, specified as a parameter in the
+// "*.launch" file
+int my_type = 0;
+
+// The ID of this agent, i.e., the ID of this computer in the case that this computer is
+// and agent
+int my_agentID = 0;
+
+// Publisher that notifies the relevant nodes when the YAML paramters have been loaded
+// from file into ram/cache, and hence are ready to be fetched
+ros::Publisher controllerYamlReadyForFetchPublihser;
+
+
+std::string m_ros_namespace;
+
+ros::Subscriber requestLoadControllerYamlSubscriber_agent_to_self;
+
+
+//    ----------------------------------------------------------------------------------
+//    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
+//    ----------------------------------------------------------------------------------
+
+void requestLoadControllerYamlCallback(const std_msgs::Int32& msg);
+
+
+
+//    ----------------------------------------------------------------------------------
+//    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
+//    ----------------------------------------------------------------------------------
+
+
+
+
+
+//    ----------------------------------------------------------------------------------
+//    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
+//    ----------------------------------------------------------------------------------
+
+
+
+
+void requestLoadControllerYamlCallback(const std_msgs::Int32& msg)
+{
+    // Extract from the "msg" for which controller the YAML
+    // parameters should be loaded
+    int controller_to_load_yaml = msg.data;
+
+    ROS_INFO_STREAM("The Parameter Service node received the message to load YAML parameters from file into cache");
+
+
+    // Instantiate a local varaible to confirm that something can actually be loaded
+    // from a YAML file
+    bool isValidToAttemptLoad = true;
+
+    // Instantiate a local variable for the string that will be passed to the "system"
+    std::string cmd;
+
+    // Get the abolute path to "d_fall_pps"
+    std::string d_fall_pps_path = ros::package::getPath("d_fall_pps");
+
+    // Switch between loading for the different controllers
+    if ( (controller_to_load_yaml==LOAD_YAML_SAFE_CONTROLLER_COORDINATOR) && (my_type==TYPE_COORDINATOR) )
+    {
+        // Re-load the parameters of the safe controller:
+        cmd = "rosparam load " + d_fall_pps_path + "/param/SafeController.yaml " + m_ros_namespace + "/SafeController";
+    }
+    else if ( (controller_to_load_yaml==LOAD_YAML_SAFE_CONTROLLER_AGENT) && (my_type==TYPE_AGENT) )
+    {
+        // Re-load the parameters of the safe controller:
+        cmd = "rosparam load " + d_fall_pps_path + "/param/SafeController.yaml " + m_ros_namespace + "/SafeController";
+    }
+    else if ( (controller_to_load_yaml==LOAD_YAML_CUSTOM_CONTROLLER_COORDINATOR) && (my_type==TYPE_COORDINATOR) )
+    {
+        // Re-load the parameters of the custom controller:
+        cmd = "rosparam load " + d_fall_pps_path + "/param/CustomController.yaml " + m_ros_namespace + "/CustomController";
+    }
+    else if ( (controller_to_load_yaml==LOAD_YAML_CUSTOM_CONTROLLER_AGENT) && (my_type==TYPE_AGENT) )
+    {
+        // Re-load the parameters of the custom controller:
+        cmd = "rosparam load " + d_fall_pps_path + "/param/CustomController.yaml " + m_ros_namespace + "/CustomController";
+    }
+    else
+    {
+        // Let the user know that the command was not recognised
+        ROS_INFO_STREAM("> Nothing to load for this parameter service with.");
+        ROS_INFO_STREAM("> The message received has 'controller_to_load_yaml'   =  " << controller_to_load_yaml);
+        ROS_INFO_STREAM("> And the type of this Parameter Service is 'my_type'  =  " << my_type);
+        // Set the boolean that prevents the fetch message from being sent
+        isValidToAttemptLoad = false;
+    }
+
+
+    // Only bother with ttempting to loaded the .yaml file, and subseuently send the "ready for fetch"
+    // message if something can actually be loaded from a YAML file
+    if (isValidToAttemptLoad)
+    {
+        // Let the user know what is about to happen
+        ROS_INFO_STREAM("> The following path will be used for locating the .yaml file: " << d_fall_pps_path  << " The comand line string sent to the 'system' is: " << cmd );
+
+        // Re-load the parameters by pass the command line string via a "system" call
+        // > i.e., this replicates pasting this string in a new terminal window and pressing enter
+        system(cmd.c_str());
+
+        // Pause breifly to ensure that the yaml file is fully loaded
+        ros::Duration(0.5).sleep();
+
+        // Instantiate a local varaible to confirm that something was actually loaded from
+        // a YAML file
+        bool isReadyForFetch = true;
+    
+        // Instantiate a local variable for the fetch message
+        std_msgs::Int32 fetch_msg;
+        // Fill in the data of the fetch message
+        switch(controller_to_load_yaml)
+        {
+            case (LOAD_YAML_SAFE_CONTROLLER_COORDINATOR):
+                fetch_msg.data = FETCH_YAML_SAFE_CONTROLLER_FROM_COORDINATOR;
+                break;
+            case (LOAD_YAML_CUSTOM_CONTROLLER_COORDINATOR):
+                fetch_msg.data = FETCH_YAML_CUSTOM_CONTROLLER_FROM_COORDINATOR;
+                break;
+            case (LOAD_YAML_SAFE_CONTROLLER_AGENT):
+                fetch_msg.data = FETCH_YAML_SAFE_CONTROLLER_FROM_OWN_AGENT;
+                break;
+            case (LOAD_YAML_CUSTOM_CONTROLLER_AGENT):
+                fetch_msg.data = FETCH_YAML_CUSTOM_CONTROLLER_FROM_OWN_AGENT;
+                break;
+            default:
+                // Let the user know that the command was not recognised
+                ROS_INFO("Unknown 'controller to load yaml' command, thus a 'ready to fetch' message will NOT be published.");
+                // Set the boolean that prevents the fetch message from being sent
+                isReadyForFetch = false;
+                break;
+        }
+        // Send a message that the YAML parameter have been loaded and hence are
+        // ready to be fetched (i.e., using getparam())
+        if (isReadyForFetch)
+        {
+            controllerYamlReadyForFetchPublihser.publish(fetch_msg);
+        }
+    }
+}
+
+
+
+
+
+
+
+//    ----------------------------------------------------------------------------------
+//    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
+//    ----------------------------------------------------------------------------------
+
+int main(int argc, char* argv[])
+{
+    // Starting the ROS-node
+    ros::init(argc, argv, "ParameterService");
+
+    // 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 value of the "type" parameter into a local string variable
+    std::string type_string;
+    if(!nodeHandle.getParam("type", type_string))
+    {
+        // Throw an error if the agent ID parameter could not be obtained
+        ROS_ERROR("Failed to get type from ParameterService");
+    }
+
+    // Set the "my_type" instance variable based on this string loaded
+    if ((!type_string.compare("coordinator")))
+    {
+        my_type = TYPE_COORDINATOR;
+    }
+    else if ((!type_string.compare("agent")))
+    {
+        my_type = TYPE_AGENT;
+    }
+    else
+    {
+        // Set "my_type" to the value indicating that it is invlid
+        my_type = TYPE_INVALID;
+        ROS_ERROR("The retrieve type parameter was no recognised.");
+    }
+
+
+    // Get the value of the "agentID" parameter into the instance variable "my_agentID"
+    if(!nodeHandle.getParam("agentID", my_agentID))
+    {
+        // Throw an error if the agent ID parameter could not be obtained
+        ROS_ERROR("Failed to get agentID from ParameterService");
+    }
+
+
+    // Publisher that notifies the relevant nodes when the YAML paramters have been loaded
+    // from file into ram/cache, and hence are ready to be fetched
+    controllerYamlReadyForFetchPublihser = nodeHandle.advertise<std_msgs::Int32>("controllerYamlReadyForFetch", 1);
+    
+
+    // Construct the string to the namespace of this Paramater Service
+    switch (my_type)
+    {
+        case TYPE_AGENT:
+        {
+            //m_ros_namespace = ros::this_node::getNamespace();
+            m_ros_namespace = "/" + std::to_string(my_agentID) + '/' + "ParameterService";
+            ROS_INFO_STREAM("This Paramter Sercice will load .yaml file parameters into the 'base' namespace: " << m_ros_namespace);
+            break;
+        }
+
+        // A COORDINATOR TYPE PARAMETER SERVICE IS REQUESTED FROM:
+        // > The master GUI
+        case TYPE_COORDINATOR:
+        {
+            //m_ros_namespace = ros::this_node::getNamespace();
+            m_ros_namespace = "/ParameterService";
+            ROS_INFO_STREAM("This Paramter Sercice will load .yaml file parameters into the 'base' namespace: " << m_ros_namespace);
+            break;
+        }
+
+        default:
+        {
+            ROS_ERROR("The 'my_type' type parameter was not recognised.");
+            break;
+        }
+    }
+
+    
+
+
+    // SUBSCRIBE TO THE APPROPRIATE "request" MESSAGES DEPENDING ON THE "my_type"
+    // Delare the subscribers as local variables here so that they persist for the life
+    // time of this main() function. The varaibles will be assigned in the switch case below
+    // > Subscribers for when this Parameter Service node is: TYPE_AGENT
+    ros::Subscriber requestLoadControllerYamlSubscriber_agent_to_self;
+    ros::Subscriber requestLoadControllerYamlSubscriber_agent_to_coordinator;
+    // > Subscribers for when this Parameter Service node is: TYPE_COORDINATOR
+    ros::Subscriber requestLoadControllerYamlSubscriber_coordinator_to_self;
+
+    // SUBSCRIBE TO THE APPROPRIATE "request" MESSAGES DEPENDING ON THE "my_type"
+    switch (my_type)
+    {
+        // AN AGENT TYPE PARAMETER SERVICE IS REQUESTED FROM:
+        // > The master GUI
+        // > The agent's own "PPSClient" node
+        case TYPE_AGENT:
+        {
+            // Subscribing to the agent's own PPSclient
+            // > First: Construct a node handle to the PPSclient
+            ros::NodeHandle nh_PPSClient_for_this_agent("PPSClient");
+            // > Second: Subscribe to the "requestLoadControllerYaml" topic
+            requestLoadControllerYamlSubscriber_agent_to_self = nh_PPSClient_for_this_agent.subscribe("requestLoadControllerYaml", 1, requestLoadControllerYamlCallback);
+
+            // Subscribing to the coordinator
+            // > First: construct a node handle to the coordinator
+            ros::NodeHandle nh_coordinator_for_this_agent = ros::NodeHandle();
+            // > Second: Subscribe to the "requestLoadControllerYaml" topic
+            requestLoadControllerYamlSubscriber_agent_to_coordinator = nh_coordinator_for_this_agent.subscribe("/my_GUI/requestLoadControllerYaml", 1, requestLoadControllerYamlCallback);            
+
+            // Inform the user what was subscribed to:
+            ROS_INFO_STREAM("This Parameter Service has subscribed to 'requestLoadControllerYaml' messages from both the 'my_GUI' and the 'PPSClient'");
+            break;
+        }
+
+        // A COORDINATOR TYPE PARAMETER SERVICE IS REQUESTED FROM:
+        // > The master GUI
+        case TYPE_COORDINATOR:
+        {
+            // Subscribing to the coordinator's own "my_GUI" 
+            // > First: Get the node handle required
+            ros::NodeHandle nh_coordinator_for_this_coordinator = ros::NodeHandle();
+            // > Second: Subscribe to requests from: the master GUI
+            requestLoadControllerYamlSubscriber_coordinator_to_self = nh_coordinator_for_this_coordinator.subscribe("/my_GUI/requestLoadControllerYaml", 1, requestLoadControllerYamlCallback);
+
+            // Inform the user what was subscribed to:
+            ROS_INFO_STREAM("This Parameter Service has subscribed to 'requestLoadControllerYaml' messages from 'my_GUI'");
+            break;
+        }
+
+        default:
+        {
+            ROS_ERROR("The 'my_type' type parameter was not recognised.");
+            break;
+        }
+    }
+
+
+    ROS_INFO("CentralManagerService ready");
+    ros::spin();
+
+    return 0;
+}
diff --git a/pps_ws/src/d_fall_pps/src/SafeControllerService.cpp b/pps_ws/src/d_fall_pps/src/SafeControllerService.cpp
index 5b6e14fc093eaf818345c17017e0b61590d41a09..e409c2619935291d8a33af8c6906de1de9c86074 100755
--- a/pps_ws/src/d_fall_pps/src/SafeControllerService.cpp
+++ b/pps_ws/src/d_fall_pps/src/SafeControllerService.cpp
@@ -1,4 +1,4 @@
-//    Copyright (C) 2017, ETH Zurich, D-ITET, Cyrill Burgener, Marco Mueller, Philipp Friedli
+//    Copyright (C) 2017, ETH Zurich, D-ITET, Paul Beuchat, Cyrill Burgener, Marco Mueller, Philipp Friedli
 //
 //    This file is part of D-FaLL-System.
 //    
@@ -30,11 +30,23 @@
 //    ----------------------------------------------------------------------------------
 
 
+
+
+//    ----------------------------------------------------------------------------------
+//    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.
+
 #include <math.h>
 #include <stdlib.h>
 #include "ros/ros.h"
 #include <std_msgs/String.h>
-#include <rosbag/bag.h>
 #include <ros/package.h>
 #include "std_msgs/Float32.h"
 
@@ -42,15 +54,63 @@
 #include "d_fall_pps/Setpoint.h"
 #include "d_fall_pps/ControlCommand.h"
 #include "d_fall_pps/Controller.h"
-// #include "d_fall_pps/Debugging.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
-#define RATE_CONTROLLER 7
 
+// The 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 MOTOR_MODE 6
+#define RATE_MODE  7
+#define ANGLE_MODE 8
+
+// Constants for feching the yaml paramters
+#define FETCH_YAML_SAFE_CONTROLLER_AGENT          1
+#define FETCH_YAML_CUSTOM_CONTROLLER_AGENT        2
+#define FETCH_YAML_SAFE_CONTROLLER_COORDINATOR    3
+#define FETCH_YAML_CUSTOM_CONTROLLER_COORDINATOR  4
+
+// 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
+//    ----------------------------------------------------------------------------------
+
 std::vector<float>  ffThrust(4);
 std::vector<float>  feedforwardMotor(4);
 float cf_mass;
@@ -74,87 +134,80 @@ float saturationThrust;
 
 CrazyflieData previousLocation;
 
-rosbag::Bag bag;
 
-// This function DOES NOT NEED TO BE edited for successful completion of the PPS exercise
-float getFloatParameter(ros::NodeHandle& nodeHandle, std::string name)
-{
-
-    float val;
-    if(!nodeHandle.getParam(name, val))
-    {
-        ROS_ERROR_STREAM("missing parameter '" << name << "'");
-    }
-    return val;
-}
+// Variable for the namespaces for the paramter 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;
 
 
 
-void loadParameterFloatVector(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");
-    }
-}
+//    ----------------------------------------------------------------------------------
+//    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
+//    ----------------------------------------------------------------------------------
 
-void loadSafeParameters(ros::NodeHandle& nodeHandle) {
-    loadParameterFloatVector(nodeHandle, "motorPoly", motorPoly, 3);
-    cf_mass = getFloatParameter(nodeHandle, "mass");
-    // force that we need to counteract gravity (mg)
-    gravity_force = cf_mass * 9.81/(1000*4); // in N
-    saturationThrust = motorPoly[2] * 12000 * 12000 + motorPoly[1] * 12000 + motorPoly[0];
+// 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.
 
-    loadParameterFloatVector(nodeHandle, "gainMatrixRoll", gainMatrixRoll, 9);
-    loadParameterFloatVector(nodeHandle, "gainMatrixPitch", gainMatrixPitch, 9);
-    loadParameterFloatVector(nodeHandle, "gainMatrixYaw", gainMatrixYaw, 9);
-    loadParameterFloatVector(nodeHandle, "gainMatrixThrust", gainMatrixThrust, 9);
+// > For the CONTROL LOOP
+bool calculateControlOutput(Controller::Request &request, Controller::Response &response);
+void convertIntoBodyFrame(float est[9], float (&state)[9], float yaw_measured);
+float computeMotorPolyBackward(float thrust);
+void estimateState(Controller::Request &request, float (&est)[9]);
 
-    loadParameterFloatVector(nodeHandle, "filterGain", filterGain, 6);
-    loadParameterFloatVector(nodeHandle, "estimatorMatrix", estimatorMatrix, 2);
+// > For the LOAD PARAMETERS
+void yamlReadyForFetchCallback(const std_msgs::Int32& msg);
+void fetchYamlParameters(ros::NodeHandle& nodeHandle);
+void processFetchedParameters();
 
-    loadParameterFloatVector(nodeHandle, "defaultSetpoint", defaultSetpoint, 4);
-}
+// > For the GETPARAM()
+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);
 
-float computeMotorPolyBackward(float thrust) {
-    return (-motorPoly[1] + sqrt(motorPoly[1] * motorPoly[1] - 4 * motorPoly[2] * (motorPoly[0] - thrust))) / (2 * motorPoly[2]);
-}
 
 
-//Kalman
-void estimateState(Controller::Request &request, float (&est)[9]) {
-    // attitude
-    est[6] = request.ownCrazyflie.roll;
-    est[7] = request.ownCrazyflie.pitch;
-    est[8] = request.ownCrazyflie.yaw;
+//    ----------------------------------------------------------------------------------
+//    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
+//    ----------------------------------------------------------------------------------
 
-    //velocity & filtering
-    float ahat_x[6]; //estimator matrix times state (x, y, z, vx, vy, vz)
-    ahat_x[0] = 0; ahat_x[1]=0; ahat_x[2]=0;
-    ahat_x[3] = estimatorMatrix[0] * prevEstimate[0] + estimatorMatrix[1] * prevEstimate[3];
-    ahat_x[4] = estimatorMatrix[0] * prevEstimate[1] + estimatorMatrix[1] * prevEstimate[4];
-    ahat_x[5] = estimatorMatrix[0] * prevEstimate[2] + estimatorMatrix[1] * prevEstimate[5];
 
-    
-    float k_x[6]; //filterGain times state
-    k_x[0] = request.ownCrazyflie.x * filterGain[0];
-    k_x[1] = request.ownCrazyflie.y * filterGain[1];
-    k_x[2] = request.ownCrazyflie.z * filterGain[2];
-    k_x[3] = request.ownCrazyflie.x * filterGain[3];
-    k_x[4] = request.ownCrazyflie.y * filterGain[4];
-    k_x[5] = request.ownCrazyflie.z * filterGain[5];
-   
-    est[0] = ahat_x[0] + k_x[0];
-    est[1] = ahat_x[1] + k_x[1];
-	est[2] = ahat_x[2] + k_x[2];
-    est[3] = ahat_x[3] + k_x[3];
-    est[4] = ahat_x[4] + k_x[4];
-    est[5] = ahat_x[5] + k_x[5];
 
-    memcpy(prevEstimate, est, 9 * sizeof(float));
-}
 
+//    ------------------------------------------------------------------------------
+//     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
+//    ----------------------------------------------------------------------------------
 
 //simple derivative
 /*
@@ -173,29 +226,10 @@ void estimateState(Controller::Request &request, float (&est)[9]) {
 }
 */
 
-void convertIntoBodyFrame(float est[9], float (&state)[9], float yaw_measured) {
-	float sinYaw = sin(yaw_measured);
-    float cosYaw = cos(yaw_measured);
-
-    state[0] = est[0] * cosYaw + est[1] * sinYaw;
-    state[1] = -est[0] * sinYaw + est[1] * cosYaw;
-    state[2] = est[2];
-
-    state[3] = est[3] * cosYaw + est[4] * sinYaw;
-    state[4] = -est[3] * sinYaw + est[4] * cosYaw;
-    state[5] = est[5];
-
-    state[6] = est[6];
-    state[7] = est[7];
-    state[8] = est[8];
-}
 
 bool calculateControlOutput(Controller::Request &request, Controller::Response &response)
 {
-    // ros::NodeHandle nodeHandle("~");
-    // loadSafeParameters(nodeHandle);  // do not put this here, cannot control anymore
-
-	
+    
     float yaw_measured = request.ownCrazyflie.yaw;
 
     //move coordinate system to make setpoint origin
@@ -204,7 +238,7 @@ bool calculateControlOutput(Controller::Request &request, Controller::Response &
     request.ownCrazyflie.z -= setpoint[2];
     float yaw = request.ownCrazyflie.yaw - setpoint[3];
 
-	
+    
     //bag.write("Offset", ros::Time::now(), request.ownCrazyflie);
 
     while(yaw > PI) {yaw -= 2 * PI;}
@@ -213,23 +247,19 @@ bool calculateControlOutput(Controller::Request &request, Controller::Response &
 
     float est[9]; //px, py, pz, vx, vy, vz, roll, pitch, yaw
     estimateState(request, est);
-
     float state[9]; //px, py, pz, vx, vy, vz, roll, pitch, yaw
     convertIntoBodyFrame(est, state, yaw_measured);
 
-    std_msgs::Float32 f32;
-    f32.data = yaw_measured;
-
     //calculate feedback
     float outRoll = 0;
     float outPitch = 0;
     float outYaw = 0;
     float thrustIntermediate = 0;
     for(int i = 0; i < 9; ++i) {
-    	outRoll -= gainMatrixRoll[i] * state[i];
-    	outPitch -= gainMatrixPitch[i] * state[i];
-    	outYaw -= gainMatrixYaw[i] * state[i];
-    	thrustIntermediate -= gainMatrixThrust[i] * state[i];
+        outRoll -= gainMatrixRoll[i] * state[i];
+        outPitch -= gainMatrixPitch[i] * state[i];
+        outYaw -= gainMatrixYaw[i] * state[i];
+        thrustIntermediate -= gainMatrixThrust[i] * state[i];
     }
     // ROS_INFO_STREAM("thrustIntermediate = " << thrustIntermediate);
     //INFORMATION: this ugly fix was needed for the older firmware
@@ -255,15 +285,272 @@ bool calculateControlOutput(Controller::Request &request, Controller::Response &
     // ROS_INFO_STREAM("controlOutput.cmd2 = " << response.controlOutput.motorCmd3);
     // ROS_INFO_STREAM("controlOutput.cmd4 = " << response.controlOutput.motorCmd4);
 
-    response.controlOutput.onboardControllerType = RATE_CONTROLLER;
+    response.controlOutput.onboardControllerType = RATE_MODE;
 
     previousLocation = request.ownCrazyflie;
 
-	bag.write("ControlOutput", ros::Time::now(), response.controlOutput);
+    return true;
+}
+
+void convertIntoBodyFrame(float est[9], float (&state)[9], float yaw_measured)
+{
+    float sinYaw = sin(yaw_measured);
+    float cosYaw = cos(yaw_measured);
+
+    state[0] = est[0] * cosYaw + est[1] * sinYaw;
+    state[1] = -est[0] * sinYaw + est[1] * cosYaw;
+    state[2] = est[2];
+
+    state[3] = est[3] * cosYaw + est[4] * sinYaw;
+    state[4] = -est[3] * sinYaw + est[4] * cosYaw;
+    state[5] = est[5];
+
+    state[6] = est[6];
+    state[7] = est[7];
+    state[8] = est[8];
+}
+
+
+
+float computeMotorPolyBackward(float thrust)
+{
+    return (-motorPoly[1] + sqrt(motorPoly[1] * motorPoly[1] - 4 * motorPoly[2] * (motorPoly[0] - thrust))) / (2 * motorPoly[2]);
+}
+
+
+//Kalman
+void estimateState(Controller::Request &request, float (&est)[9])
+{
+    // attitude
+    est[6] = request.ownCrazyflie.roll;
+    est[7] = request.ownCrazyflie.pitch;
+    est[8] = request.ownCrazyflie.yaw;
+
+    //velocity & filtering
+    float ahat_x[6]; //estimator matrix times state (x, y, z, vx, vy, vz)
+    ahat_x[0] = 0; ahat_x[1]=0; ahat_x[2]=0;
+    ahat_x[3] = estimatorMatrix[0] * prevEstimate[0] + estimatorMatrix[1] * prevEstimate[3];
+    ahat_x[4] = estimatorMatrix[0] * prevEstimate[1] + estimatorMatrix[1] * prevEstimate[4];
+    ahat_x[5] = estimatorMatrix[0] * prevEstimate[2] + estimatorMatrix[1] * prevEstimate[5];
+
+    
+    float k_x[6]; //filterGain times state
+    k_x[0] = request.ownCrazyflie.x * filterGain[0];
+    k_x[1] = request.ownCrazyflie.y * filterGain[1];
+    k_x[2] = request.ownCrazyflie.z * filterGain[2];
+    k_x[3] = request.ownCrazyflie.x * filterGain[3];
+    k_x[4] = request.ownCrazyflie.y * filterGain[4];
+    k_x[5] = request.ownCrazyflie.z * filterGain[5];
+   
+    est[0] = ahat_x[0] + k_x[0];
+    est[1] = ahat_x[1] + k_x[1];
+    est[2] = ahat_x[2] + k_x[2];
+    est[3] = ahat_x[3] + k_x[3];
+    est[4] = ahat_x[4] + k_x[4];
+    est[5] = ahat_x[5] + k_x[5];
+
+    memcpy(prevEstimate, est, 9 * sizeof(float));
+}
+
+
+
+
+
+//    ----------------------------------------------------------------------------------
+//    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_SAFE_CONTROLLER_AGENT:
+        {
+            // Let the user know that this message was received
+            ROS_INFO("The SafeControllerService received the message that YAML parameters were (re-)loaded. > Now fetching the parameter values from this machine.");
+            // 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_SAFE_CONTROLLER_COORDINATOR:
+        {
+            // Let the user know that this message was received
+            ROS_INFO("The SafeControllerService 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 SafeControllerService received the message that YAML parameters were (re-)loaded.\r> However the parameters do not relate to this controller, hence nothing will be fetched.");
+            break;
+        }
+    }
+}
+
+void fetchYamlParameters(ros::NodeHandle& nodeHandle)
+{
+
+    // Here we load the parameters that are specified in the SafeController.yaml file
+
+    // Add the "CustomController" namespace to the "nodeHandle"
+    ros::NodeHandle nodeHandle_for_safeController(nodeHandle, "SafeController");
+
+    // > The mass of the crazyflie
+    cf_mass = getParameterFloat(nodeHandle_for_safeController, "mass");
+
+    // > The co-efficients of the quadratic conversation from 16-bit motor command to
+    //   thrust force in Newtons
+    getParameterFloatVector(nodeHandle_for_safeController, "motorPoly", motorPoly, 3);
+    
+    
+    // > The row of the LQR matrix that commands body frame roll rate
+    getParameterFloatVector(nodeHandle_for_safeController, "gainMatrixRoll", gainMatrixRoll, 9);
+    // > The row of the LQR matrix that commands body frame pitch rate
+    getParameterFloatVector(nodeHandle_for_safeController, "gainMatrixPitch", gainMatrixPitch, 9);
+    // > The row of the LQR matrix that commands body frame yaw rate
+    getParameterFloatVector(nodeHandle_for_safeController, "gainMatrixYaw", gainMatrixYaw, 9);
+    // > The row of the LQR matrix that commands thrust adjustment
+    getParameterFloatVector(nodeHandle_for_safeController, "gainMatrixThrust", gainMatrixThrust, 9);
+
+    // > The gains for the point-mass Kalman filter
+    getParameterFloatVector(nodeHandle_for_safeController, "filterGain", filterGain, 6);
+    getParameterFloatVector(nodeHandle_for_safeController, "estimatorMatrix", estimatorMatrix, 2);
+
+    // > The defailt setpoint of the controller
+    getParameterFloatVector(nodeHandle_for_safeController, "defaultSetpoint", defaultSetpoint, 4);
+
+    // DEBUGGING: Print out one of the parameters that was loaded
+    ROS_INFO_STREAM("DEBUGGING: the fetched SafeController/mass = " << cf_mass);
+
+    // Call the function that computes details an values that are needed from these
+    // parameters loaded above
+    processFetchedParameters();
+}
+
+void processFetchedParameters()
+{
+    // force that we need to counteract gravity (mg)
+    gravity_force = cf_mass * 9.81/(1000*4); // in N
+    // The maximum possible thrust
+    saturationThrust = motorPoly[2] * 12000 * 12000 + motorPoly[1] * 12000 + motorPoly[0];
+}
+
+
+
+
+//    ----------------------------------------------------------------------------------
+//     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   ( )
+//    ----------------------------------------------------------------------------------
+
+
+float getParameterFloat(ros::NodeHandle& nodeHandle, std::string name)
+{
+    float val;
+    if(!nodeHandle.getParam(name, val))
+    {
+        ROS_ERROR_STREAM("missing parameter '" << name << "'");
+    }
+    return val;
+}
+
+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");
+    }
+}
+
+int getParameterInt(ros::NodeHandle& nodeHandle, std::string name)
+{
+    int val;
+    if(!nodeHandle.getParam(name, val))
+    {
+        ROS_ERROR_STREAM("missing parameter '" << name << "'");
+    }
+    return val;
+}
 
-	return true;
+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");
+    }
 }
 
+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();
+}
+
+bool getParameterBool(ros::NodeHandle& nodeHandle, std::string name)
+{
+    bool val;
+    if(!nodeHandle.getParam(name, val))
+    {
+        ROS_ERROR_STREAM("missing parameter '" << name << "'");
+    }
+    return val;
+}
+
+
+
+
+
+//    ----------------------------------------------------------------------------------
+//    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
+//    ----------------------------------------------------------------------------------
+
 void setpointCallback(const Setpoint& newSetpoint) {
     setpoint[0] = newSetpoint.x;
     setpoint[1] = newSetpoint.y;
@@ -271,41 +558,108 @@ void setpointCallback(const Setpoint& newSetpoint) {
     setpoint[3] = newSetpoint.yaw;
 }
 
-void safeYAMLloadedCallback(const std_msgs::Int32& msg)
-{
-    ros::NodeHandle nodeHandle("~");
-    ROS_INFO("received msg safe loaded YAML");
-    loadSafeParameters(nodeHandle);
-}
 
 
-//ros::Publisher pub;
+
+
+//    ----------------------------------------------------------------------------------
+//    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
+//    ----------------------------------------------------------------------------------
 
 int main(int argc, char* argv[]) {
     ros::init(argc, argv, "SafeControllerService");
 
     ros::NodeHandle nodeHandle("~");
-    loadSafeParameters(nodeHandle);
+
+
+    // *********************************************************************************
+    // EVERYTHING THAT RELATES TO FETCHING PARAMETERS FROM A YAML FILE
+
+
+    // EVERYTHING FOR THE CONNECTION TO THIS AGENT's OWN PARAMETER SERVICE:
+
+    // Get the namespace of this "SafeControllerService" node
+    std::string m_namespace = ros::this_node::getNamespace();
+
+    // 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("The namespace string for accessing the Paramter Services are:");
+    ROS_INFO_STREAM("namespace_to_own_agent_parameter_service    =  " << namespace_to_own_agent_parameter_service);
+    ROS_INFO_STREAM("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);
+
+    // *********************************************************************************
+
+    
+    
+
     setpoint = defaultSetpoint; // only first time setpoint is equal to default setpoint
 
     ros::Subscriber setpointSubscriber = nodeHandle.subscribe("Setpoint", 1, setpointCallback);
 
     ros::NodeHandle namespace_nodeHandle(ros::this_node::getNamespace());
 
-    ros::Subscriber safeYAMloadedSubscriber = namespace_nodeHandle.subscribe("student_GUI/safeYAMLloaded", 1, safeYAMLloadedCallback);
 
     ros::ServiceServer service = nodeHandle.advertiseService("RateController", calculateControlOutput);
     ROS_INFO("SafeControllerService ready");
     
-	std::string package_path;
-	package_path = ros::package::getPath("d_fall_pps") + "/";
-	ROS_INFO_STREAM(package_path);
-	std::string record_file = package_path + "LoggingSafeController.bag";
-	bag.open(record_file, rosbag::bagmode::Write);
+	// std::string package_path;
+	// package_path = ros::package::getPath("d_fall_pps") + "/";
+	// ROS_INFO_STREAM(package_path);
+	// std::string record_file = package_path + "LoggingSafeController.bag";
+	// bag.open(record_file, rosbag::bagmode::Write);
 
 
     ros::spin();
-	bag.close();
+	// bag.close();