path_planning_custom.cpp
Go to the documentation of this file.
00001 /*
00002  *  This file is part of ucl_drone 2016.
00003  *  For more information, refer
00004  *  to the corresponding header file.
00005  *
00006  * This file receives information from Strategy and the Pose_estimation and publishes to the
00007  * Controller.
00008  * It tells the controller where the drone must go as function of the strategy and the position of
00009  * the drone.
00010  *
00011  *  \authors Julien Gérardy & Félicien Schiltz
00012  *  \date 2016
00013  *
00014  */
00015 
00016 #include "ucl_drone/path_planning.h"
00017 
00018 PathPlanning::PathPlanning()
00019 {
00020   // drone prefix from the launch file.
00021   std::string drone_prefix;
00022   ros::param::get("~drone_prefix", drone_prefix);
00023 
00024   // List of subscribers and publishers. This node subscribes to pose_estimation to get the
00025   // real-time
00026   // position of the drone. It also subsribes to Stragegy in order to know in what the drone must do
00027   // and so where it has to go.
00028   // This node publishes in the node path_planning that communicates with the controller and to the
00029   // node mapcell that is just used to export data from tests.
00030 
00031   // Subscribers
00032   pose_channel = nh.resolveName("pose_estimation");
00033   pose_sub = nh.subscribe(pose_channel, 10, &PathPlanning::poseCb, this);
00034 
00035   strategy_channel = nh.resolveName("strategy");
00036   strategy_sub = nh.subscribe(strategy_channel, 10, &PathPlanning::strategyCb, this);
00037 
00038   // Publishers
00039   poseref_channel = nh.resolveName("path_planning");
00040   poseref_pub = nh.advertise< ucl_drone::PoseRef >(poseref_channel, 1);
00041 
00042   // Just for some tests
00043   mapcell_channel = nh.resolveName("mapcell");
00044   mapcell_pub = nh.advertise< ucl_drone::cellUpdate >(mapcell_channel, 500);
00045 
00046   // instruction_publishing = false;
00047 }
00048 
00049 // Destructor
00050 
00051 PathPlanning::~PathPlanning()
00052 {
00053 }
00054 
00055 // Function to reset the desired pose sent to the controller
00056 void PathPlanning::reset()
00057 {
00058   next_x = 0;
00059   next_y = 0;
00060   next_z = 1.1;
00061   next_rotZ = 0;
00062   i = 0;
00063   landing = false;
00064   takeoff = false;
00065   gridInitialized = false;
00066 
00067   // XMax and YMax are the half of the distance between the horizontal and vertical border lines of
00068   // the vision of the drone. Those values come from bottom camera data and 0.8 is used as a
00069   // security factor in the case of the drone is not well oriented.
00070 
00071   XMax = next_z * 0.435 * 0.8 * 0.5;
00072   YMax = next_z * 0.326 * 0.8 * 0.5;
00073 }
00074 
00075 // This function publish the position where the drone has to get. It is used as pose_ref in the
00076 // controller node.
00077 void PathPlanning::publish_poseref()
00078 {
00079   // instantiate the poseref message
00080   ucl_drone::PoseRef poseref_msg;
00081 
00082   poseref_msg.x = next_x;
00083   poseref_msg.y = next_y;
00084   poseref_msg.z = next_z;
00085   poseref_msg.rotZ = next_rotZ;
00086   poseref_msg.landAndStop = landing;
00087   poseref_msg.takeoffAndStart = takeoff;
00088 
00089   poseref_pub.publish(poseref_msg);
00090 }
00091 
00092 // This function is called when this node receives a message from the topic "pose_estimation". So it
00093 // takes this message and put it in a variable where it will be used in the other functions.
00094 void PathPlanning::poseCb(const ucl_drone::Pose3D::ConstPtr posePtr)
00095 {
00096   lastPoseReceived = *posePtr;
00097 }
00098 
00099 // This function is called when this node receives a message from the topic "strategy". So it
00100 // takes this message and put it in a variable where it will be used in the other functions.
00101 void PathPlanning::strategyCb(const ucl_drone::StrategyMsg::ConstPtr strategyPtr)
00102 {
00103   lastStrategyReceived = *strategyPtr;
00104 }
00105 
00106 template < typename T >
00107 int sgn(T val)
00108 {
00109   return (T(0) < val) - (val < T(0));
00110 }
00111 
00112 // First approach to explore a map. The drones makes a kind of labyrinth
00113 bool PathPlanning::xy_desired()
00114 {
00115   // The drone is considered as "arrived on poseref if it in a radius of 0.35m"
00116   if (sqrt((lastPoseReceived.x - next_x) * (lastPoseReceived.x - next_x) +
00117            (lastPoseReceived.y - next_y) * (lastPoseReceived.y - next_y) +
00118            (lastPoseReceived.z - next_z) * (lastPoseReceived.z - next_z)) < 0.25)
00119   {
00120     printf("i: %d\n", i);
00121     // square
00122     //     double labyrinth_x[] = {0, 1.6, 1.6, 0, 0};  //{0, 1, 2, 2, 2, 1, 0, 0, 0};
00123     //     double labyrinth_y[] = {0, 0, 1.3, 1.3, 0};  //{0, 0, 0, 0.65, 1.3, 1.3, 1.3, 0.65, 0};
00124 
00125     // ligne droite
00126     // double labyrinth_x[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
00127     // double labyrinth_y[] = {0, -1, -2, -3, -4, -3, -2, -1, 0};
00128 
00129     // sur place
00130     double labyrinth_x[] = {0};
00131     double labyrinth_y[] = {0};
00132 
00133     if (i >= sizeof(labyrinth_x) / sizeof(labyrinth_x[0]))
00134     {
00135       int j = i - sizeof(labyrinth_x) / sizeof(labyrinth_x[0]);
00136 
00137       double descente_z[] = {1.1};  //{0.9};
00138 
00139       if (j >= sizeof(descente_z) / sizeof(descente_z[0]))
00140       {
00141         // landing = true;
00142         return true;
00143       }
00144 
00145       next_z = descente_z[j];
00146     }
00147     else
00148     {
00149       next_x = labyrinth_x[i];
00150       next_y = labyrinth_y[i];
00151     }
00152     i++;
00153 
00154     return true;
00155   }
00156   else
00157   {
00158     return false;
00159   }
00160 }
00161 
00162 // In our final approach to expore the map, the pathplanning creates a grid. This grid is made of
00163 // 0.10*0.10 m² cells that can be in 3 different states :
00164 // 0 means unseen/unexplored
00165 // 1 means seen/explored
00166 // 2 means border cell explored (there is cells behind but we haven't seen them yet)
00167 // 3 means wall cell detected
00168 void PathPlanning::InitializeGrid()
00169 {
00170   // Set all the cells to "unexplored"
00171   for (i = 0; i < SIDE * 10; i++)
00172   {
00173     for (j = 0; j < SIDE * 10; j++)
00174     {
00175       myGrid[i][j] = 0;
00176     }
00177   }
00178   gridInitialized = true;
00179 }
00180 
00181 // This function creates a virtual wall. It returns true if the cell (i,j) contains a wall. This
00182 // function has to be replaced by a true wall identification function via a camera and image process
00183 // (for example). This function has been made in order where it can easily be replaced by something
00184 // real and with more performances.
00185 bool PathPlanning::ThereIsAWallCell(int i, int j)  // modified
00186 {
00187   yfromcell2 = -((j / 10.0) - SIDE / 2.0);
00188   xfromcell2 = SIDE - (i / 10.0);
00189 
00190   // ROS_INFO("i is :  %d    , j is : %d \n", i, j);
00191   // ROS_INFO("xfromcell2 is : %lf    , yfromcell2 is : %lf \n", xfromcell2, yfromcell2);
00192 
00193   if (yfromcell2 >= (SIDE / 2.0 - 0.2) || yfromcell2 <= -(SIDE - 0.4) / 2.0)
00194   {
00195     return true;
00196   }
00197   else if (xfromcell2 >= SIDE - 0.2 || xfromcell2 <= 0.2)
00198   {
00199     return true;
00200   }
00201   else
00202   {
00203     return false;
00204   }
00205 }
00206 
00207 // This function trasnforms the XMax and Ymax into the panel of cells that are seen by the drone in
00208 // function of its position.
00209 // !! abscisse = I and ordoonee = J
00210 void PathPlanning::AbsOrdMinMax(double x, double y, int* iMin, int* iMax, int* jMin, int* jMax)
00211 {
00212   printf("I'm calculating AbsOrdMinMax\n");
00213   *jMin = fmax(0, (int)(10 * SIDE / 2.0 - (y + YMax) * 10));
00214   *jMax = fmin((int)(10 * SIDE / 2.0 - (y - YMax) * 10), SIDE * 10);
00215   *iMin = fmax(0, (int)(10 * SIDE - (x + XMax) * 10));
00216   *iMax = fmin((int)(10 * SIDE - (x - XMax) * 10), SIDE * 10);
00217 }
00218 
00219 // This function transforms i and j coordinates to x and y position in the real playground.
00220 void PathPlanning::CellToXY(int i, int j, double* xfromcell, double* yfromcell)
00221 {
00222   *yfromcell = (double)(SIDE / 2.0 - j / 10.0);
00223   *xfromcell = (double)SIDE - (i / 10.0);
00224 }
00225 
00226 // This function is the main one of the grid. It checks all the cells that the drone is seeing and
00227 // modify their value in regard with the previous grid and the "ThereIsAWallCell" function.
00228 void PathPlanning::UpdateMap(double x, double y)
00229 {
00230   ROS_INFO("I'm in the updatemap function");
00231   AbsOrdMinMax(x, y, &myAbsMin, &myAbsMax, &myOrdMin, &myOrdMax);
00232   ROS_INFO("I'm in the updatemap function after absOrdMinMax function");
00233   printf("myOrdMin: %d     myOrdMax: %d      myAbsMin: %d    myAbsMax: %d   \n", myOrdMin, myOrdMax,
00234          myAbsMin, myAbsMax);
00235 
00236   for (i = myAbsMin; i < myAbsMax; i++)
00237   {
00238     for (j = myOrdMin; j < myOrdMax; j++)
00239     {
00240       // ROS_INFO("I'm in the updatemap loop for (i,j) %d, %d \n", i, j);
00241 
00242       if (myGrid[i][j] == 0 || myGrid[i][j] == 2)
00243       {
00244         if (!ThereIsAWallCell(i, j))
00245         {
00246           if (i == myAbsMin || i == myAbsMax - 1 || j == myOrdMin || j == myOrdMax - 1)
00247           {
00248             if (myGrid[i][j] == 2)
00249             {
00250               printf("I put a border cell\n");
00251             }
00252             else
00253             {
00254               printf("I put a NEW border cell\n");
00255               cellUpdateMsg.i = i;
00256               cellUpdateMsg.j = j;
00257               cellUpdateMsg.type = 2;
00258               mapcell_pub.publish(cellUpdateMsg);
00259             }
00260             myGrid[i][j] = 2;
00261           }
00262           else
00263           {
00264             myGrid[i][j] = 1;
00265             printf("I put an explored cell\n");
00266             cellUpdateMsg.i = i;
00267             cellUpdateMsg.j = j;
00268             cellUpdateMsg.type = 1;
00269             mapcell_pub.publish(cellUpdateMsg);
00270           }
00271         }
00272         else
00273         {
00274           myGrid[i][j] = 3;
00275           printf("I put a wall cell\n");
00276           cellUpdateMsg.i = i;
00277           cellUpdateMsg.j = j;
00278           cellUpdateMsg.type = 3;
00279           mapcell_pub.publish(cellUpdateMsg);
00280         }
00281       }
00282     }
00283   }
00284 }
00285 
00286 // This function returns the distance between two cells.
00287 double PathPlanning::distance(int i, int j, int k, int l)
00288 {
00289   return sqrt((i - k) * (i - k) + (j - l) * (j - l));
00290 }
00291 
00292 // This function replaced the labyrtinth one. It takes as argument the position of the drone and
00293 // gives back the best cell where the drone must go. In order to do that, it compares all the border
00294 // cells of the map and tell the drone to go to the nearrest one.
00295 void PathPlanning::advanced_xy_desired(double x, double y, double* k, double* l)
00296 {
00297   int absc = (int)(SIDE - x) * 10;
00298   int ord = (int)(SIDE / 2.0 - y) * 10;
00299   bestDist = 1000000.0;
00300   closestJ = SIDE * 10 / 2.0;
00301   closestI = SIDE * 10;
00302   for (i = 0; i < SIDE * 10; i++)
00303   {
00304     for (j = 0; j < SIDE * 10; j++)
00305     {
00306       if (myGrid[i][j] == 2 && distance(absc, ord, i, j) < bestDist)
00307       {
00308         bestDist = distance(absc, ord, i, j);
00309         closestJ = j;
00310         closestI = i;
00311       }
00312     }
00313   }
00314   if (bestDist == 1000000.0)
00315   {
00316     ROS_INFO("The map was explored completely, there are no more border cells!");
00317   }
00318   // printf("closestI should be  50 and is: %d \n", closestI);
00319   CellToXY(closestI, closestJ, k, l);
00320 }
00321 
00322 // This function give to the object variable the computed next reference position.
00323 void PathPlanning::SetRef(double x_ref, double y_ref, double z_ref, double rotZ_ref)
00324 {
00325   this->next_x = x_ref;
00326   this->next_y = y_ref;
00327   this->next_z = z_ref;
00328   this->next_rotZ = rotZ_ref;
00329 }
00330 
00331 // Main function, will publish pose_ref with regard to the selected strategy comming from the
00332 // Strategy node.
00333 int main(int argc, char** argv)
00334 {
00335   ROS_INFO_STREAM("poseref_sending started!");
00336   ros::init(argc, argv, "path_planning");
00337   PathPlanning myPath;
00338   ros::Rate r(20);  // Refresh every 1/20 second.
00339   printf("Pathplanning launched");
00340   ROS_DEBUG("path planning initialized");
00341 
00342   myPath.reset();
00343   myPath.publish_poseref();
00344   ros::spinOnce();
00345   r.sleep();
00346   ROS_INFO_STREAM("poseref initialized and launched");
00347   while (ros::ok())
00348   {
00349     TIC(path);
00350     if (myPath.lastStrategyReceived.type == 1.0)
00351     {
00352       myPath.takeoff = true;
00353       myPath.publish_poseref();
00354     }
00355 
00356     // Strategy == 7.0 and == 8.0 are never true. Those numbers are just used to change the response
00357     // we want from the pathplanning between 3 different functions. (test - labyrinth - grid). We
00358     // just have to put 2.0 to the one we want and other numbers to the others.
00359 
00360     // This function calls the labyrinth pathplanning.
00361     else if (myPath.lastStrategyReceived.type == 2.0)
00362     {
00363       if (myPath.xy_desired() == true)
00364       {
00365         myPath.takeoff = true;
00366         ros::Duration(1.5).sleep();
00367         myPath.publish_poseref();
00368       }
00369     }
00370 
00371     // Strategy = GOTO, the drone goes directly to the position writed in the message from the
00372     // strategy.
00373     else if (myPath.lastStrategyReceived.type == 3.0)
00374     {
00375       myPath.takeoff = true;
00376       myPath.SetRef(myPath.lastStrategyReceived.x, myPath.lastStrategyReceived.y + 0.5,
00377                     myPath.next_z,
00378                     myPath.next_rotZ);  // Pas correct, ne tient pas compte de la
00379                                         // position du drone maitre
00380       myPath.publish_poseref();
00381     }
00382 
00383     // Strategy = Land, the drone lands.
00384     else if (myPath.lastStrategyReceived.type == 4.0)
00385     {
00386       myPath.takeoff = false;
00387       myPath.landing = true;
00388       myPath.publish_poseref();
00389     }
00390 
00391     // Strategy = Follow, the drone goes to the coordinates writed in the message from the strategy.
00392     // Those ones come from the target_detected channel in the strategy node.
00393     else if (myPath.lastStrategyReceived.type == 5.0)
00394     {
00395       myPath.takeoff = true;
00396       myPath.SetRef(myPath.lastStrategyReceived.x, myPath.lastStrategyReceived.y, myPath.next_z,
00397                     myPath.next_rotZ);
00398       myPath.publish_poseref();
00399     }
00400 
00401     // Strategy = BackToBase, the drone rises up to 2m in order to avoid the other drone coming to
00402     // replace him. Then it goes back to the base and land when it is in a radius of 0.15m from
00403     // where it took off.
00404     else if (myPath.lastStrategyReceived.type == 6.0)
00405     {
00406       myPath.next_z = 2;
00407       if (sqrt((myPath.lastPoseReceived.x) * (myPath.lastPoseReceived.x) +
00408                (myPath.lastPoseReceived.y) * (myPath.lastPoseReceived.y)) < 0.15)
00409       {
00410         myPath.takeoff = false;
00411         myPath.landing = true;
00412       }
00413       else if (!myPath.landing)
00414       {
00415         myPath.takeoff = true;
00416         myPath.SetRef(0, 0, myPath.next_z, myPath.next_rotZ);
00417       }
00418       myPath.publish_poseref();
00419     }
00420 
00421     // Strategy = Seek (explore), the drone initializes the grid. Then this is the
00422     // advanced_xy_desired function that tells the drone where to go.
00423     else if (myPath.lastStrategyReceived.type == 7.0)
00424     {
00425       if (!myPath.gridInitialized)
00426       {
00427         ROS_INFO("I am initializing the grid");
00428 
00429         myPath.InitializeGrid();
00430       }
00431 
00432       myPath.takeoff = true;
00433       myPath.UpdateMap(myPath.lastPoseReceived.x, myPath.lastPoseReceived.y);
00434       ROS_INFO("I have updated the map");
00435 
00436       myPath.advanced_xy_desired(myPath.lastPoseReceived.x, myPath.lastPoseReceived.y,
00437                                  &myPath.poseRefX, &myPath.poseRefY);
00438       myPath.SetRef(myPath.poseRefX, myPath.poseRefY, myPath.next_z, myPath.next_rotZ);
00439       ROS_INFO("poseref is : (%lf, %lf)", myPath.poseRefX, myPath.poseRefY);
00440       ros::Duration(1).sleep();
00441       myPath.publish_poseref();
00442     }
00443 
00444     // Test of command for the report.
00445     else if (myPath.lastStrategyReceived.type == 8.0)
00446     {
00447       myPath.takeoff = true;
00448       myPath.SetRef(0.0, 0.0, 1.0, 0.0);
00449       myPath.publish_poseref();
00450       ros::Duration(15).sleep();
00451       myPath.SetRef(2.0, 0.0, 1.0, 0.0);
00452       myPath.publish_poseref();
00453       ros::Duration(35).sleep();
00454       myPath.SetRef(0.0, 0.0, 1.0, 0.0);
00455       myPath.publish_poseref();
00456       ros::Duration(35).sleep();
00457       myPath.SetRef(-2.0, 0.0, 1.0, 0.0);
00458       myPath.publish_poseref();
00459       ros::Duration(35).sleep();
00460     }
00461 
00462     TOC(path, "path planning");
00463     ros::spinOnce();
00464     r.sleep();
00465   }
00466   return 0;
00467 }
00468 
00469 // Function that gives a yaw angle in order to always face to the direction to go. We don't use it
00470 // at this moment.
00471 
00472 /*void PathPlanning::yaw_desired()
00473 {
00474   double delta_x=next_x-lastPoseReceived.x;
00475   double delta_y=next_y-lastPoseReceived.y;
00476   if(sqrt(delta_x*delta_x+delta_y*delta_y)<1.5)
00477   {
00478   next_yaw=old_next_yaw;
00479   }
00480   else
00481   {
00482   double theta;
00483   if(delta_x!=0)
00484   {
00485   theta=atan(delta_y/delta_x);
00486   }
00487   else
00488   {
00489   theta=3.14159;
00490   }
00491   if(delta_y<0 && delta_x<0)
00492   {
00493   theta+=3.14159;
00494       if(theta>3.14159)
00495       {
00496           theta=theta-2*3.14159;
00497       }
00498   }
00499   else if(delta_y>0 && delta_x<0)
00500   {
00501   theta=abs(theta);
00502   }
00503   old_next_yaw=next_yaw;
00504   next_yaw=theta;
00505   }
00506 
00507 }
00508 */


ucl_drone
Author(s): dronesinma
autogenerated on Sat Jun 8 2019 20:51:53