From c84a23ecb138416b92247f3cd0bf9ccfe4805ae8 Mon Sep 17 00:00:00 2001
From: Stevedan Ogochukwu Omodolor <stevedan.o.omodolor@gmail.com>
Date: Sun, 15 May 2022 11:51:11 +0200
Subject: [PATCH] mission controller finished,remaining swamcontroller
 implementation

---
 .../CMakeLists.txt                            |   7 +-
 .../cfg/missionController.cfg                 |   7 +
 .../config/missionConfig.yaml                 |   7 +
 .../include/mission_controller.h              |   9 +-
 .../src/mission_controller.cpp                | 191 ++++++++++++++++--
 5 files changed, 205 insertions(+), 16 deletions(-)

diff --git a/real_robot/coordination_formation_control_pkg/CMakeLists.txt b/real_robot/coordination_formation_control_pkg/CMakeLists.txt
index cc3cc07..eacdbb6 100644
--- a/real_robot/coordination_formation_control_pkg/CMakeLists.txt
+++ b/real_robot/coordination_formation_control_pkg/CMakeLists.txt
@@ -19,6 +19,7 @@ find_package(catkin)
 ## System dependencies are found with CMake's conventions
 #find_package(Boost REQUIRED COMPONENTS system)
 find_package (Eigen3 REQUIRED)
+find_package(OpenCV REQUIRED)
 
 
 ## Generate dynamic reconfigure parameters in the 'cfg' folder
@@ -56,13 +57,13 @@ include_directories(
 ## The recommended prefix ensures that target names across packages don't collide
 add_executable(mission_controller src/mission_controller.cpp src/robot_state.cpp)
 add_dependencies(mission_controller ${PROJECT_NAME}_gencfg)
-target_link_libraries(mission_controller ${catkin_LIBRARIES} ${Eigen_LIBRARIES})
+target_link_libraries(mission_controller ${catkin_LIBRARIES} ${Eigen_LIBRARIES}   ${OpenCV_LIBS})
 
 add_executable(drone_node src/drone_node.cpp src/robot_state.cpp src/swamControllerAlg.cpp)
-target_link_libraries(drone_node ${catkin_LIBRARIES} ${Eigen_LIBRARIES})
+target_link_libraries(drone_node ${catkin_LIBRARIES} ${Eigen_LIBRARIES}   ${OpenCV_LIBS})
 
 add_executable(omniwheel_node src/omniwheel_node.cpp src/robot_state.cpp src/swamControllerAlg.cpp)
-target_link_libraries(omniwheel_node ${catkin_LIBRARIES} ${Eigen_LIBRARIES})
+target_link_libraries(omniwheel_node ${catkin_LIBRARIES} ${Eigen_LIBRARIES}   ${OpenCV_LIBS})
 
 
 install(DIRECTORY
diff --git a/real_robot/coordination_formation_control_pkg/cfg/missionController.cfg b/real_robot/coordination_formation_control_pkg/cfg/missionController.cfg
index 9e16cab..153ee98 100644
--- a/real_robot/coordination_formation_control_pkg/cfg/missionController.cfg
+++ b/real_robot/coordination_formation_control_pkg/cfg/missionController.cfg
@@ -9,6 +9,13 @@ demo.add("shut_down",                   bool_t,    0,
 demo.add("initialize_all_robot",                   bool_t,    0,                               "start all robot",      False)
 demo.add("start_formation",                   bool_t,    0,                               "Start formation controller",      False)
 demo.add("stop",                   bool_t,    0,                               "stop formation ",      False)
+demo.add("mantain_position",                   bool_t,    0,                               "mantain goal centroid",      False)
+demo.add("update_waypoint",                   bool_t,    0,                               "update waypoint",      False)
+demo.add("x",       double_t,  0,                               "desired goal",               0.0,     -3,-3)
+demo.add("y",       double_t,  0,                               "desired goal",               0.0,     -3,-3)
+demo.add("vx",         double_t,   0,                              "desired goal",                     0.0,-3,-3)
+demo.add("vy",         double_t,   0,                              "desired goal",                     0.0, -3,-3)
+demo.add("orientation",         double_t,   0,                              "desired goal",                     0, 0,360)
 
 
 exit(gen.generate(PACKAGE, "coordination_formation_control_pkg", "missionController"))
diff --git a/real_robot/coordination_formation_control_pkg/config/missionConfig.yaml b/real_robot/coordination_formation_control_pkg/config/missionConfig.yaml
index 177b3db..3c5843c 100644
--- a/real_robot/coordination_formation_control_pkg/config/missionConfig.yaml
+++ b/real_robot/coordination_formation_control_pkg/config/missionConfig.yaml
@@ -4,3 +4,10 @@ hz_freq: 50 # controller frquency
 include_obstacle: false
 include_orientation: false
 n_obs: 0
+
+# waypoint
+# x: 0
+# y: 0
+# orienation: 0
+# vx: 0
+# vy: 0
diff --git a/real_robot/coordination_formation_control_pkg/include/mission_controller.h b/real_robot/coordination_formation_control_pkg/include/mission_controller.h
index 3e8a40b..1a5005a 100644
--- a/real_robot/coordination_formation_control_pkg/include/mission_controller.h
+++ b/real_robot/coordination_formation_control_pkg/include/mission_controller.h
@@ -7,7 +7,11 @@
 #include <coordination_formation_control_pkg/missionControllerConfig.h>
 #include <coordination_formation_control_pkg/coordination.h>
 #include <coordination_formation_control_pkg/waypoint.h>
-
+#include "opencv2/highgui.hpp"
+#include "opencv2/core.hpp"
+#include "opencv2/imgproc.hpp"
+using namespace cv;
+using namespace cv;
 
 #define ENABLE_LATCH true
 /* state machine mission_controller*/
@@ -30,6 +34,7 @@ class missionController
     /* execute main process*/
     void executeMainProcess();
     void updateCofig(coordination_formation_control_pkg::missionControllerConfig &config, uint32_t level);
+    Eigen::MatrixXf compute_cluster(Eigen::MatrixXf uav_q, Eigen::MatrixXf ugv_q,int num_ugvs, int num_uavs);
 
   private:
     fsm_mc_t state;
@@ -37,6 +42,8 @@ class missionController
     bool initialize_all_robot;
     bool start_formation;
     bool stop;
+    bool mantain_position;
+    bool start_publishing_waypoint;
     ros::NodeHandle nh;
 
       /*dynamic reconfigure*/
diff --git a/real_robot/coordination_formation_control_pkg/src/mission_controller.cpp b/real_robot/coordination_formation_control_pkg/src/mission_controller.cpp
index a1db334..d59a890 100644
--- a/real_robot/coordination_formation_control_pkg/src/mission_controller.cpp
+++ b/real_robot/coordination_formation_control_pkg/src/mission_controller.cpp
@@ -10,6 +10,7 @@ nh(nh)
   this->initialize_all_robot = false;
   this->start_formation = false;
   this->stop = false;
+  this->mantain_position = true;
 
   /*publisher*/
   this->coordination_publisher = this->nh.advertise<coordination_formation_control_pkg::coordination>("coordination_config",1);
@@ -17,10 +18,9 @@ nh(nh)
   this->current_configuration.init_formation = false;
   this->current_configuration.initialize_robot = false;
   this->waypoint_publisher = this->nh.advertise<coordination_formation_control_pkg::waypoint>("goal_waypoint",1);
-  /* initialize drone list subscirbers*/
-
-  /* initialize ugv list*/
-
+  this->current_waypoint.vel[0] = 0;
+  this->current_waypoint.vel[1] = 0;
+  this->start_publishing_waypoint = false;
 
 
   /*dynamic_reconfigure*/
@@ -41,8 +41,11 @@ void missionController::executeMainProcess()
 {
   ros::Rate loop_rate(100);
   /* create a list of drones*/
-  int n_drones;
+  int n_drones, n_ugvs;
   this->nh.getParam("/n_drones", n_drones);
+  this->nh.getParam("/n_ugvs", n_ugvs);
+
+
   std::vector<robotState *> uavs;
   robot_ind_t uav_def;
   bool sucess_initialization;
@@ -61,18 +64,56 @@ void missionController::executeMainProcess()
       EXIT_FAILURE;
     }
   }
+  /* create a list of ugvs*/
+  std::vector<robotState *> ugvs;
+  robot_ind_t ugv_def;
+  for (int i = 1; i <= n_ugvs; i++)
+  {
+    ugv_def.robot_name = "omniwheel";
+    ugv_def.t = OMNIWHEELS;
+    ugv_def.id = i;
+    sucess_initialization = false;
+    auto * ugv = new robotState(ugv_def, nh, sucess_initialization);
+    ugvs.push_back(ugv);
+    if (sucess_initialization == false)
+    {
+      ROS_ERROR("Initialization: ugv  %d produced an error in mission controller", ugv_def.id);
+      EXIT_FAILURE;
+    }
+  }
+
+  Eigen::MatrixXf current_cluster(2,n_ugvs);
+  row_vector_2d_t current_centroid_vel,goal_centroid,current_centroid, error;
+  float dist;
 
   while(ros::ok())
   {
 
-    // test print all the drones states
-    // for(int i = 1; i <=n_drones; i++)
-    // {
-    //   robot_state_t current_state;
-    //   current_state = uavs[i-1]->get_state();
-    //   std::cout << "id: " << uavs[i-1]->id << "state: " << current_state.q << std::endl;
-    // }
+    Eigen::MatrixXf uav_state_q(2,n_drones);
+    Eigen::MatrixXf uav_state_p(2,n_drones);
+    Eigen::MatrixXf ugv_state_q(2,n_ugvs);
+    Eigen::MatrixXf ugv_state_p(2,n_ugvs);
+    for(int i = 1; i <=n_drones; i++)
+    {
+      robot_state_t current_state;
+      current_state = uavs[i-1]->get_state();
+      uav_state_q(0, i-1) =current_state.q(0);
+      uav_state_q(1, i-1) =current_state.q(1);
+      uav_state_p(0, i-1) = current_state.p(0);
+      uav_state_p(1, i-1) = current_state.p(1);
+    }
 
+    /*get current state of all the ugv*/
+    for(int i = 1; i <=n_ugvs; i++)
+    {
+      robot_state_t current_state;
+      current_state = ugvs[i-1]->get_state();
+      ugv_state_q(0, i-1) =current_state.q(0);
+      ugv_state_q(1, i-1) =current_state.q(1);
+      ugv_state_p(0, i-1) = current_state.p(0);
+      ugv_state_p(1, i-1) = current_state.p(1);
+
+    }
 
     if(this->shut_down)
     {
@@ -107,6 +148,9 @@ void missionController::executeMainProcess()
             this->current_configuration.stop_demo = false;
 
             ROS_INFO("Mission_controller State: START_FORMATION");
+            /*make sure that we mantain current entroid if no centorid has been sent*/
+            // this->current_waypoint.pos[0] = uav_state_q.row(0).mean();
+            // this->current_waypoint.pos[1]  = uav_state_q.row(1).mean();
 
 
             this->state = START_FORMATION;
@@ -130,13 +174,53 @@ void missionController::executeMainProcess()
         case START_FORMATION:
 
         /* compute waypoint formation*/
+        /* initial waypoint will be the centorid of the current configuration*/
+        current_centroid_vel(0) = uav_state_p.row(0).mean();
+        current_centroid_vel(1) = uav_state_p.row(1).mean();
+        current_centroid(0) = uav_state_q.row(0).mean();
+        current_centroid(1) = uav_state_q.row(1).mean();
+        goal_centroid(0) = current_waypoint.pos[0];
+        goal_centroid(1) = current_waypoint.pos[1];
+
+        error = (goal_centroid-current_centroid);
+        dist = error.norm();
 
 
         /* compute cluster*/
+        current_cluster = this->compute_cluster(uav_state_q, ugv_state_q, n_ugvs,n_drones);
+
+        /* assign clusters*/
+        for(int i = 0; i < n_ugvs; i++)
+        {
+          this->current_waypoint.cluster_pos.push_back(current_cluster(0,i));
+          this->current_waypoint.cluster_pos.push_back(current_cluster(1,i));
+        }
+        this->current_waypoint.cluster_vel[0] = current_centroid_vel(0);
+        this->current_waypoint.cluster_vel[1] = current_centroid_vel(1);
+
 
         /* send goals*/
+        if (dist < 0.1) // waypoint reached TODO, this is hard coded, not a good idea
+        {
+          if(this->mantain_position == false)
+          {
+            this->current_waypoint.stop = true;
+          }
+          else
+          {
+            this->current_waypoint.stop = false;
+            /* if we want to mantain centroid, vel to 0*/
+            this->current_waypoint.vel[0] = 0;
+            this->current_waypoint.vel[1] = 0;
+
+          }
+        }
 
         /* update waypoints*/
+        if (start_publishing_waypoint)
+        {
+          waypoint_publisher.publish(this->current_waypoint);
+        }
 
         if(this->stop)
         {
@@ -193,8 +277,91 @@ void missionController::updateCofig(coordination_formation_control_pkg::missionC
     this->shut_down = true;
     config.shut_down = false;
   }
+  if(config.update_waypoint)
+  {
+    config.update_waypoint = false;
+    current_waypoint.pos[0] = config.x;
+    current_waypoint.pos[1] = config.y;
+    current_waypoint.orientation = config.orientation;
+    current_waypoint.vel[0] = config.vx;
+    current_waypoint.vel[1] = config.vy;
+    this->mantain_position = config.mantain_position;
+    this->start_publishing_waypoint = true;
+
+
+  }
 }
 
+Eigen::MatrixXf missionController::compute_cluster(Eigen::MatrixXf uav_q, Eigen::MatrixXf ugv_q,int num_ugvs, int num_uavs)
+{
+  /* only implemented for two ugv*/
+  if(num_ugvs > 2)
+  {
+    ROS_INFO("n_ugv is only implemented for 2 ugv, should modify for more ugvs");
+
+    this->stop = true;
+
+  }
+  else
+  {
+    std::vector<Point2f> centers;
+    for (int i = 0; i <2; i++)
+    {
+      /* make intial ugv be the centroid */
+      Point2f center;
+      center.x = ugv_q(0,i);
+      center.y =  ugv_q(1,i);
+      centers.push_back(center);
+    }
+    /* points*/
+    std::vector<Point2f> points;
+
+    for(int t = 0; t < num_uavs; t++)
+    {
+      Point2f point;
+      point.x = uav_q(0,t);
+      point.y =  uav_q(1,t);
+      points.push_back(point);
+    }
+    Mat labels;
+    int cluster_cout = num_ugvs;
+    double compactness = kmeans(points, cluster_cout, labels,
+            TermCriteria( TermCriteria::EPS+TermCriteria::COUNT, 10, 1.0),
+               10,  KMEANS_PP_CENTERS, centers);
+
+    /* decide to change or not*/
+    /* we calculate the enegy to mantain the current confguration or change*/
+    Eigen::MatrixXf centroids(2,num_ugvs);
+    for(int p = 0; p <num_ugvs; p++)
+    {
+      centroids(0,p) = centers[p].x;
+      centroids(1,p) = centers[p].y;
+    }
+
+    float man1 = (centroids.col(0) - ugv_q.col(0)).norm();
+    float man2 = (centroids.col(1) - ugv_q.col(0)).norm();
+    float cha1 = (centroids.col(1) - ugv_q.col(1)).norm();
+    float cha2 = (centroids.col(0) - ugv_q.col(1)).norm();
+
+    if( cha1 < man1)
+    {
+      if(cha2 <man2)
+      {
+        Eigen::MatrixXf dummy_centroid(2,num_ugvs);
+        dummy_centroid = centroids;
+        /* switch centroids*/
+        centroids.col(0) = dummy_centroid.col(1);
+        centroids.col(1) = dummy_centroid.col(0);
+
+
+      }
+    }
+
+    return centroids;
+
+  }
+
+}
 
 int main(int argc, char **argv)
 {
-- 
GitLab