purepursuit_planner.cpp
Go to the documentation of this file.
00001 
00010 #include <string.h>
00011 #include <vector>
00012 #include <queue>
00013 #include <stdint.h>
00014 #include <ros/ros.h>
00015 #include <math.h>
00016 #include <cstdlib>
00017 
00018 #include <purepursuit_planner/Component.h>
00019 #include <ackermann_msgs/AckermannDriveStamped.h>
00020 #include <nav_msgs/Odometry.h>
00021 #include <tf/transform_broadcaster.h>
00022 #include <tf/transform_listener.h>
00023 #include "diagnostic_msgs/DiagnosticStatus.h"
00024 #include "diagnostic_updater/diagnostic_updater.h"
00025 #include "diagnostic_updater/update_functions.h"
00026 #include "diagnostic_updater/DiagnosticStatusWrapper.h"
00027 #include "diagnostic_updater/publisher.h"
00028 #include <actionlib/server/simple_action_server.h>
00029 #include <planner_msgs/GoToAction.h>
00030 #include <planner_msgs/goal.h>
00031 #include <geometry_msgs/Pose2D.h>
00032 //#include <s3000_laser/enable_disable.h>
00033 
00034 
00035 #define ODOM_TIMEOUT_ERROR                      0.2                             // max num. of seconds without receiving odom values
00036 #define MAP_TIMEOUT_ERROR                       0.2                             // max num. of seconds without receiving map transformations
00037 #define AGVS_TURN_RADIUS                        0.20                    // distancia en la que empieza a girar el robot cuando llega a una esquina
00038 #define MIN_ANGLE_BEZIER                        0.261799388             // ángulo (radianes) mínimo entre segmentos de la recta para los que ajustaremos a una curva de BEZIER
00039 #define BEZIER_CONTROL_POINTS           5
00040 
00041 #define D_LOOKAHEAD_MIN                         0.3             // Minima distancia del punto objetivo en m (PurePursuit con lookahead dinámico)
00042 #define D_LOOKAHEAD_MAX                         1.1             // Maxima distancia del punto objetivo
00043 #define D_WHEEL_ROBOT_CENTER            0.478   // Distance from the motor wheel to the robot center
00044 
00045 #define MAX_SPEED_LVL1                          0.5
00046 #define MAX_SPEED_LVL2                          0.3
00047 #define MAX_SPEED                                       1.2
00048 
00049 #define WAYPOINT_POP_DISTANCE_M         0.10            //Distancia mínima para alcanzar punto objetivo m (PurePursuit)
00050 
00051 #define AGVS_FIRST_DECELERATION_DISTANCE        0.5     // meters -> when the vehicle is arriving to the goal, it has to decelarate at this distance
00052 #define AGVS_FIRST_DECELERATION_MAXSPEED        0.15    // m/s
00053 #define AGVS_SECOND_DECELERATION_DISTANCE   0.25        // meters -> when the vehicle is arriving to the goal, it has to decelarate another time at this distance
00054 #define AGVS_SECOND_DECELERATION_MAXSPEED       0.1     // m/s
00055 #define AGVS_DEFAULT_KR 0.20                            // 
00056 
00057 enum{
00058         ODOM_SOURCE = 1,
00059         MAP_SOURCE = 2
00060 };
00061 
00062 using namespace std;
00063 
00065 typedef struct MagnetStruct{
00067     int iID;
00069     double dX;
00071     double dY;
00072 }MagnetStruct;
00073 
00075 typedef struct Waypoint{
00077     int iID;
00079     double dX;
00081     double dY;
00083     double dA;
00085     double dSpeed;
00086 }Waypoint;
00087 
00089 class Path{
00090         public:
00092         int iCurrentWaypoint;
00094         int iCurrentMagnet;
00095 
00096         private:
00098         pthread_mutex_t mutexPath;
00100         vector <Waypoint> vPoints;
00102         vector <MagnetStruct> vMagnets;
00104         bool bOptimized;
00105 
00106         public:
00107 
00109         Path(){
00110                 iCurrentWaypoint = iCurrentMagnet = -1;
00111                 pthread_mutex_init(&mutexPath, NULL);//Initialization for WaypointRoutes' mutex
00112                 bOptimized = false;
00113         }
00114 
00116         ~Path(){
00117                 pthread_mutex_destroy(&mutexPath);
00118         }
00119 
00121         ReturnValue AddWaypoint(Waypoint point){
00122                 Waypoint aux;
00123 
00124                 pthread_mutex_lock(&mutexPath);
00125                         if(vPoints.size() > 0){
00126                                 aux = vPoints.back();
00127                                 // Only adds the waypoint if it's different from waypoint before
00128                                 if( (aux.dX != point.dX) || (aux.dY != point.dY) )
00129                                         vPoints.push_back(point);
00130                         } else { // First point
00131                                 if(iCurrentWaypoint < 0){ //First point
00132                                         iCurrentWaypoint = 0;
00133                                 }
00134 
00135                                 vPoints.push_back(point);
00136                         }
00137 
00138                 pthread_mutex_unlock(&mutexPath);
00139 
00140                 return OK;
00141         }
00142 
00144         ReturnValue AddWaypoint(vector <Waypoint> po){
00145                 pthread_mutex_lock(&mutexPath);
00146                         if(iCurrentWaypoint < 0){ //First point
00147                                 iCurrentWaypoint = 0;
00148                         }
00149                         for(int i = 0; i < po.size(); i++){
00150                                 vPoints.push_back(po[i]);
00151                         }
00152                 pthread_mutex_unlock(&mutexPath);
00153         }
00154 
00156         ReturnValue AddMagnet(MagnetStruct magnet){
00157                 pthread_mutex_lock(&mutexPath);
00158                         if(iCurrentMagnet < 0){ //First point
00159                                 iCurrentMagnet = 0;
00160                         }
00161                         vMagnets.push_back(magnet);
00162                 pthread_mutex_unlock(&mutexPath);
00163 
00164                 return OK;
00165         }
00166 
00168         ReturnValue AddMagnet(vector <MagnetStruct> po){
00169                 pthread_mutex_lock(&mutexPath);
00170                         if(iCurrentMagnet < 0){ //First point
00171                                 iCurrentMagnet = 0;
00172                         }
00173                         for(int i = 0; i < po.size(); i++){
00174                                 vMagnets.push_back(po[i]);
00175                         }
00176                 pthread_mutex_unlock(&mutexPath);
00177         }
00178 
00180         void Clear(){
00181                 pthread_mutex_lock(&mutexPath);
00182                         iCurrentWaypoint = -1;
00183                         iCurrentMagnet = -1;
00184                         bOptimized = false;
00185                         vPoints.clear();
00186                         vMagnets.clear();
00187                 pthread_mutex_unlock(&mutexPath);
00188         }
00189         
00191         unsigned int Size(){
00192                 return vPoints.size();
00193         }
00194 
00196         ReturnValue GetNextWaypoint(Waypoint *wp){
00197                 ReturnValue ret = ERROR;
00198 
00199                 pthread_mutex_lock(&mutexPath);
00200 
00201                         if( (iCurrentWaypoint >= 0) && (iCurrentWaypoint < (vPoints.size() - 1)) ){
00202                                 *wp = vPoints[iCurrentWaypoint + 1];
00203                                 ret = OK;
00204                         }
00205 
00206                 pthread_mutex_unlock(&mutexPath);
00207 
00208                 return ret;
00209         }
00210 
00212         ReturnValue BackWaypoint(Waypoint *wp){
00213                 ReturnValue ret = ERROR;
00214 
00215                 pthread_mutex_lock(&mutexPath);
00216                         if( vPoints.size() > 0){
00217                                 *wp = vPoints.back();
00218                                 ret = OK;
00219                         }
00220                 pthread_mutex_unlock(&mutexPath);
00221 
00222                 return ret;
00223         }
00224 
00226         ReturnValue GetCurrentWaypoint(Waypoint *wp){
00227                 ReturnValue ret = ERROR;
00228 
00229                 pthread_mutex_lock(&mutexPath);
00230                         if( (iCurrentWaypoint >= 0) && (iCurrentWaypoint < vPoints.size()) ){
00231                                 *wp = vPoints[iCurrentWaypoint];
00232                                 ret = OK;
00233                         }
00234                 pthread_mutex_unlock(&mutexPath);
00235 
00236                 return ret;
00237         }
00238 
00240         ReturnValue GetWaypoint(int index, Waypoint *wp){
00241                 ReturnValue ret = ERROR;
00242 
00243                 pthread_mutex_lock(&mutexPath);
00244                         if( (index >= 0) && ( index< vPoints.size() ) ){
00245                                 *wp = vPoints[index];
00246                                 ret = OK;
00247                         }
00248                 pthread_mutex_unlock(&mutexPath);
00249 
00250                 return ret;
00251         }
00252 
00254         int GetCurrentWaypointIndex(){
00255                 return iCurrentWaypoint;
00256         }
00257 
00259         ReturnValue SetCurrentWaypoint(int index){
00260                 ReturnValue ret = ERROR;
00261 
00262                 if(index < (vPoints.size() - 1)){
00263                         pthread_mutex_lock(&mutexPath);
00264                                 iCurrentWaypoint = index;
00265                         pthread_mutex_unlock(&mutexPath);
00266                         ret = OK;
00267                 }
00268 
00269                 return ret;
00270         }
00271 
00273         void NextWaypoint(){
00274                 pthread_mutex_lock(&mutexPath);
00275                         iCurrentWaypoint++;
00276                 pthread_mutex_unlock(&mutexPath);
00277         }
00278 
00280         int NumOfWaypoints(){
00281                 return vPoints.size();
00282         }
00283 
00285         ReturnValue GetNextMagnet(MagnetStruct *mg){
00286                 ReturnValue ret = ERROR;
00287                 pthread_mutex_lock(&mutexPath);
00288 
00289                         if( (iCurrentMagnet >= 0) && (iCurrentMagnet < (vMagnets.size() - 1)) ){
00290                                 *mg = vMagnets[iCurrentMagnet + 1];
00291                                 ret = OK;
00292                         }
00293 
00294                 pthread_mutex_unlock(&mutexPath);
00295 
00296 
00297                 return ret;
00298         }
00299 
00301         ReturnValue BackMagnet(MagnetStruct * mg){
00302                 ReturnValue ret = ERROR;
00303 
00304                  pthread_mutex_lock(&mutexPath);
00305                         if( vMagnets.size() > 0){
00306                                 *mg = vMagnets.back();
00307                                 ret = OK;
00308                         }
00309                 pthread_mutex_unlock(&mutexPath);
00310 
00311                 return ret;
00312         }
00313 
00315         ReturnValue GetCurrentMagnet( MagnetStruct * mg ){
00316                 ReturnValue ret = ERROR;
00317 
00318                 pthread_mutex_lock(&mutexPath);
00319                         if( (iCurrentMagnet >= 0) && (iCurrentMagnet < vMagnets.size()) ){
00320                                 *mg = vMagnets[iCurrentMagnet];
00321                                 ret = OK;
00322                         }
00323                 pthread_mutex_unlock(&mutexPath);
00324 
00325                 return ret;
00326         }
00327 
00329         ReturnValue GetPreviousMagnet( MagnetStruct * mg ){
00330                 ReturnValue ret = ERROR;
00331 
00332                 pthread_mutex_lock(&mutexPath);
00333                         if( (iCurrentMagnet > 0) && (iCurrentMagnet <= vMagnets.size()) ){
00334                                 *mg = vMagnets[iCurrentMagnet-1];
00335                                 ret = OK;
00336                         }
00337                 pthread_mutex_unlock(&mutexPath);
00338 
00339                 return ret;
00340         }
00341 
00343         int GetCurrentMagnetIndex(){
00344                 return iCurrentMagnet;
00345         }
00346 
00348         ReturnValue SetCurrentMagnet(int index){
00349                 ReturnValue ret = ERROR;
00350 
00351                 if(index < (vMagnets.size() - 1)){
00352                         pthread_mutex_lock(&mutexPath);
00353                                 iCurrentMagnet = index;
00354                         pthread_mutex_unlock(&mutexPath);
00355                         ret = OK;
00356                 }
00357                 return ret;
00358         }
00359 
00361         void NextMagnet(){
00362                 pthread_mutex_lock(&mutexPath);
00363                         iCurrentMagnet++;
00364                 pthread_mutex_unlock(&mutexPath);
00365         }
00366 
00368         ReturnValue GetLastMagnet( MagnetStruct * mg ){
00369                 ReturnValue ret = ERROR;
00370 
00371                 pthread_mutex_lock(&mutexPath);
00372                         if( (iCurrentMagnet > 0) && (iCurrentMagnet <= vMagnets.size() ) ){
00373                                 *mg = vMagnets[iCurrentMagnet - 1];
00374                                 ret = OK;
00375                         }
00376                 pthread_mutex_unlock(&mutexPath);
00377 
00378                 return ret;
00379         }
00380 
00382         int NumOfMagnets(){
00383                 return vMagnets.size();
00384         }
00385 
00387         Path &operator+=(const Path &a){
00388                 AddWaypoint(a.vPoints);
00389                 AddMagnet(a.vMagnets);
00390                 return *this;
00391         }
00392 
00394         double dot2( Waypoint w, Waypoint v) {
00395                 return (w.dX*v.dX + w.dY*v.dY);
00396         }
00397 
00404         Waypoint PosOnQuadraticBezier(Waypoint cp0, Waypoint cp1, Waypoint cp2, float t){
00405                 Waypoint aux;
00406 
00407                 //B(t)= (1-t)^2 * cp0 + 2*t*(1-t)*cp1 + t^2 * cp2;
00408                 //Bx(t)
00409                 aux.dX = (1.0-t)*(1.0-t)*cp0.dX + 2*t*(1.0-t)*cp1.dX + t*t*cp2.dX;
00410                 //By(t)
00411                 aux.dY = (1.0-t)*(1.0-t)*cp0.dY + 2*t*(1.0-t)*cp1.dY + t*t*cp2.dY;
00412 
00413                 return aux;
00414         }
00415 
00419         double DistForSpeed(double target_speed){
00420                 if(target_speed > 1.0)
00421                         return 2.0;
00422                 else if(target_speed > 0.8)
00423                         return 1.5;
00424                 else return
00425                         1.0;
00426 
00427         }
00428 
00433         ReturnValue Optimize(double distance){
00434                 int i, j=0;
00435                 int a, b, c;
00436                 int x = 0, y = 1, speed = 2;
00437                 double mod_ab, mod_bc;
00438                 double dAngle;
00439                 Waypoint ab, bc, ba;
00440                 double K= 0.0;
00441                 vector <Waypoint> new_points;
00442                 Waypoint aux;
00443                 double Ax = 0.0, Ay = 0.0, Bx = 0.0, By = 0.0, Cx = 0.0, Cy = 0.0;
00444                 Waypoint A, B, C;
00445                 double Kt = 1.0 / BEZIER_CONTROL_POINTS;
00446                 double dAuxSpeed = 0.0;
00447                 double dMinDist = 0.0;  // Minica distancia a la que hay q frenar en funcion de la velocidad
00448 
00449                 if(bOptimized){ //Already optimized
00450                         return OK;
00451                 }
00452 
00453                 if((vPoints.size() < 2) || (distance <= 0.0)){  //Minimo 3 puntos en la ruta
00454                         //printf("WaypointRoute::Optimize: Error: not enought points (%d)\n",Size());
00455                         return ERROR;
00456                 }
00457                 pthread_mutex_lock(&mutexPath);
00458                         //
00459                         // Si solo hay dos puntos, interpolamos y creamos un punto intermedio
00460                         if(vPoints.size() == 2){
00461                                 aux = vPoints[1];
00462                                 vPoints.push_back(aux); // Añadimos un punto al final y modificamos el del medio
00463                                 if((vPoints[0].dX - aux.dX) == 0.0){// Punto en el mismo eje X
00464                                         vPoints[1].dX = vPoints[0].dX;    // Mantenemos la coordenada en X
00465                                         vPoints[1].dY = vPoints[0].dY + (aux.dY - vPoints[0].dY) / 2.0; // La coordenada en Y será igual a la del primer punto más la mitada de distancia entre el punto final e inicial
00466                                 }else if((vPoints[0].dY - aux.dY) == 0.0){ // Punto en el mismo eje Y
00467                                         vPoints[1].dX = vPoints[0].dX + (aux.dX - vPoints[0].dX) / 2.0; // La coordenada en X será igual a la del primer punto más la mitada de distancia entre el punto final e inicial
00468                                         vPoints[1].dY = vPoints[0].dY;    // Mantenemos la coordenada en Y
00469                                 }else{ // Punto en eje X, Y distinto
00470                                         vPoints[1].dX = vPoints[0].dX + (aux.dX - vPoints[0].dX) / 2.0; // La coordenada en X será igual a la del primer punto más la mitada de distancia entre el punto final e inicial
00471                                         vPoints[1].dY = vPoints[0].dY + (aux.dY - vPoints[0].dY) / 2.0; // La coordenada en Y será igual a la del primer punto más la mitada de distancia entre el punto final e inicial
00472                                 }
00473                         }
00474                 
00475                         new_points.push_back(vPoints[0]);
00476                         new_points.push_back(vPoints[1]);
00477 
00478                         for(i=2; i < vPoints.size(); i++){      // Primera pasada, añadimos puntos para los giros en curvas
00479                                 //cout << " Partiendo de punto " << i << endl;
00480                                 a = i-2;
00481                                 b = i-1;
00482                                 c = i;
00483 
00484                                 Ax = vPoints[a].dX;
00485                                 Ay = vPoints[a].dY;
00486                                 Bx = vPoints[b].dX;
00487                                 By = vPoints[b].dY;
00488                                 Cx = vPoints[c].dX;
00489                                 Cy = vPoints[c].dY;
00490 
00491                                 ab.dX = Bx - Ax;
00492                                 ab.dY = By - Ay;
00493                                 mod_ab = sqrt(ab.dX * ab.dX + ab.dY * ab.dY);
00494 
00495                                 bc.dX = Cx - Bx;
00496                                 bc.dY = Cy - By;
00497                                 mod_bc = sqrt(bc.dX * bc.dX + bc.dY * bc.dY);
00498 
00499                                 dAngle= acos(dot2(ab,bc)/(mod_ab*mod_bc));
00500                                 //cout <<  i << " Angle =  "<< dAngle << endl;
00501                                 if(fabs(dAngle) >= MIN_ANGLE_BEZIER){ // en caso del angulo que forman los segmentos sea menor, entonces generaremos puntos para aproximar mjor la curva
00502                                         // siendo ba vector director de b->a y bc el vector director b->c
00503                                         // Calculamos un punto a una distancia 'd' desde 'b' hacia 'a' y otro punto desde 'b' hacia 'c'
00504                                         // Estos puntos serán los que se añadirán a la lista de waypoints para poder trazar una curva de bezier
00505 
00506                                         new_points.pop_back();
00507 
00508                                         // Calcula velocidad maxima en funcion del giro de la curva
00509                                         if(fabs(dAngle) >= (Pi/4)){
00510                                                 dAuxSpeed = MAX_SPEED_LVL2;
00511                                         }else
00512                                                 dAuxSpeed = MAX_SPEED_LVL1;
00513                                         //cout << "Aux speed = " << dAuxSpeed << ", Next speed =  " << vPoints[b].dSpeed << endl;
00514                                         // Si la velocidad en ese waypoint supera el máximo establecido para un giro así
00515                                         if(fabs(vPoints[b].dSpeed) > dAuxSpeed){
00516 
00517                                                 if(vPoints[b].dSpeed < 0.0)     // Cambiamos sentido de avance
00518                                                         dAuxSpeed = -dAuxSpeed;
00519 
00520                                                 dMinDist = DistForSpeed(fabs(vPoints[b].dSpeed));
00521                                                 //cout << "Min dist = " << dMinDist  << endl;
00522                                                 // Si el punto antes del giro esta a una distancia menor a la mínima, añadimos nuevo punto a un metro
00523                                                 if( mod_ab > dMinDist){
00524                                                         //Lo creamos
00525                                                         ba.dX = -ab.dX;
00526                                                         ba.dY = -ab.dY;
00527                                                         K = dMinDist / sqrt(ba.dX * ba.dX + ba.dY * ba.dY);
00528 
00529                                                         aux.dX = Bx + K * ba.dX;        // x = x' + K*Vx
00530                                                         aux.dY = By + K * ba.dY;        // y = y' + K*Vy        //(Vx, Vy) vector director
00531                                                         aux.dSpeed = vPoints[b].dSpeed;
00532                                                         //cout << "Nuevo punto en " << aux.dX << ", " << aux.dY << endl;
00533                                                         new_points.push_back(aux);
00534                                                 }
00535 
00536                                                 vPoints[b].dSpeed = dAuxSpeed;
00537 
00538                                         }
00539                                         // El primer waypoint no se modifica
00540                                         if(mod_ab > distance){ // si la distancia entre ab es MAYOR a la distancia del punto que pretendemos crear, creamos un punto intermedio
00541                                                 //Lo creamos
00542                                                 ba.dX = -ab.dX;
00543                                                 ba.dY = -ab.dY;
00544                                                 K = distance / sqrt(ba.dX * ba.dX + ba.dY * ba.dY);
00545 
00546                                                 aux.dX = Bx + K * ba.dX;        // x = x' + K*Vx
00547                                                 aux.dY = By + K * ba.dY;        // y = y' + K*Vy        //(Vx, Vy) vector director
00548                                                 aux.dSpeed = vPoints[b].dSpeed;
00549                                                 //cout << "Nuevo punto en " << aux.dX << ", " << aux.dY << endl;
00550                                                 new_points.push_back(aux);
00551                                                 //j++;
00552                                         }
00553 
00554                                         new_points.push_back(vPoints[b]);
00555 
00556                                         if(mod_bc > distance){ // si la distancia entre ab es menor a la distancia del punto que pretendemos crear, lo dejamos como está
00557                                                 //Lo creamos
00558                                                 K = distance / sqrt(bc.dX * bc.dX + bc.dY * bc.dY);
00559                                                 aux.dX = Bx + K * bc.dX;        // x = x' + K*Vx
00560                                                 aux.dY = By + K * bc.dY;        // y = y' + K*Vy        //(Vx, Vy) vector director
00561                                                 aux.dSpeed = vPoints[b].dSpeed;
00562                                                 //j++;
00563                                                 //cout << "Nuevo punto en " << aux.dX << ", " << aux.dY << endl;
00564                                                 new_points.push_back(aux);
00565                                         }
00566 
00567                                         // Creamos punto para después del giro
00568                                         if(dMinDist > 0.0) {
00569                                                 if(mod_bc > 1.0){       // si la distancia al punto C es mayor que 1 metro, después del giro
00570                                                         // Creamos un nuevo punto
00571                                                         //Lo creamos
00572                                                         K = 1.0 / sqrt(bc.dX * bc.dX + bc.dY * bc.dY);
00573                                                         aux.dX = Bx + K * bc.dX;        // x = x' + K*Vx
00574                                                         aux.dY = By + K * bc.dY;        // y = y' + K*Vy        //(Vx, Vy) vector director
00575                                                         aux.dSpeed = vPoints[b].dSpeed;
00576                                                         new_points.push_back(aux);
00577                                                 }else{
00578                                                         // Si no, establecemos una velocidad máxima
00579                                                         vPoints[c].dSpeed = vPoints[b].dSpeed;
00580                                                 }
00581                                         }
00582 
00583 
00584                                         new_points.push_back(vPoints[c]);
00585                                         //j++;
00586                                 }else{  //Se queda como está
00587 
00588                                         new_points.push_back(vPoints[c]);
00589 
00590                                 }
00591                         }
00592 
00593                         // Borramos antiguos waypoints e insertamos los nuevos
00594                         vPoints.clear();
00595 
00596                         // BEZIER
00597                         vPoints.push_back(new_points[0]);
00598                         vPoints.push_back(new_points[1]);
00599                         for(i=2; i < new_points.size(); i++){   // Segunda pasada, aproximamos los giros a curvas de Bezier
00600                                 a = i-2;
00601                                 b = i-1;
00602                                 c = i;
00603 
00604                                 Ax = new_points[a].dX;
00605                                 Ay = new_points[a].dY;
00606                                 Bx = new_points[b].dX;
00607                                 By = new_points[b].dY;
00608                                 Cx = new_points[c].dX;
00609                                 Cy = new_points[c].dY;
00610 
00611                                 ab.dX = Bx - Ax;
00612                                 ab.dY = By - Ay;
00613                                 mod_ab = sqrt(ab.dX * ab.dX + ab.dY * ab.dY);
00614 
00615                                 bc.dX = Cx - Bx;
00616                                 bc.dY = Cy - By;
00617                                 mod_bc = sqrt(bc.dX * bc.dX + bc.dY * bc.dY);
00618 
00619                                 dAngle= acos(dot2(ab,bc)/(mod_ab*mod_bc));
00620 
00621                                 if(fabs(dAngle) >= MIN_ANGLE_BEZIER){ // en caso del angulo que forman los segmentos sea menor, entonces generaremos puntos, siguiendo una curva de Bezier, para aproximar mjor la curva
00622                                         // siendo ba vector director de b->a y bc el vector director b->c
00623 
00624                                         Waypoint aux_wp;
00625                                         double t, aux_speed;
00626 
00627                                         A = new_points[a];
00628                                         B = new_points[b];
00629                                         C = new_points[c];
00630 
00631                                         aux_speed = new_points[b].dSpeed; //takes speed of the waypoint in the middle
00632                                         vPoints.pop_back();                     // Eliminamos el waypoint del medio. El primer waypoint no se modifica
00633 
00634                                         for(int j=1; j <= BEZIER_CONTROL_POINTS; j++) {
00635                                                 t = (double) j * Kt;
00636                                                 aux_wp = PosOnQuadraticBezier(A, B, C,  t);
00637                                                 aux_wp.dSpeed = aux_speed;
00638                                                 vPoints.push_back(aux_wp);
00639                                         //      std::cout << "\tWaypointRoute::Optimize: (Bezier) Waypoint,X= " << aux_wp.dX << " Y= " << aux_wp.dY
00640                                         //                              << " size= " << (int)points.size() << endl;
00641                                         }
00642                                 }else{  //Se queda como está
00643 
00644                                         vPoints.push_back(new_points[c]);
00645                                 }
00646                         }
00647 
00648                         iCurrentWaypoint = 0;
00649 
00650                 //      for(int i = 0; i < new_points.size(); i++){
00651                 //      points.push_back(new_points[i]);
00652                 //      }
00653 
00654                 pthread_mutex_unlock(&mutexPath);
00655 
00656                 bOptimized  = true;
00657                 new_points.clear();
00658 
00659                 return OK;
00660         }
00662         void Print(){
00663                 cout << "Path::Print: Printing all the waypoints..." << endl;
00664                 if(vPoints.size() > 0){
00665                         for(int i = 0; i < vPoints.size(); i++){
00666                                 cout << "(" << i << ")\t " << vPoints[i].dX << ", " << vPoints[i].dY << endl;
00667                         }
00668                 }else
00669                         cout << "Path::Print: No waypoints..." << endl;
00670         }
00671 
00672 };
00673 
00674 
00675 class purepursuit_planner_node: public Component
00676 {
00677 
00678 private:        
00679         ros::NodeHandle node_handle_;
00680         ros::NodeHandle private_node_handle_;
00681         double desired_freq_;
00683         double Kr;
00684         
00686     double dLookAhead;
00688     Path pathCurrent;
00690     Path pathFilling;
00692     queue <Path> qPath;
00694     geometry_msgs::Pose2D pose2d_robot;
00696     nav_msgs::Odometry odometry_robot;
00698     double dLinearSpeed;
00700     double d_lookahear_min_, d_lookahear_max_;
00702     double d_dist_wheel_to_center_;
00704     double max_speed_;
00706     bool bEnabled;
00708     bool bCancel;
00710     std::string position_source_;
00712     unsigned int ui_position_source;
00713     
00716         ros::Publisher status_pub_;
00719         ros::Publisher vel_pub_;
00721         ros::Publisher tranform_map_pub_;
00723         ros::Subscriber odom_sub_;
00725         std::string odom_topic_;
00727         std::string cmd_topic_vel_;
00728         // DIAGNOSTICS
00730         diagnostic_updater::TopicDiagnostic *updater_diagnostic_odom; 
00732         diagnostic_updater::Updater updater_diagnostic; 
00734         double min_odom_freq, max_odom_freq; 
00736         ros::Time last_command_time, last_map_time;
00737         // ACTIONLIB
00738         actionlib::SimpleActionServer<planner_msgs::GoToAction> action_server_goto;
00739         planner_msgs::GoToFeedback goto_feedback;
00740         planner_msgs::GoToResult goto_result;
00741         planner_msgs::GoToGoal goto_goal;
00742         // TFs
00743         tf::TransformListener listener;
00744         tf::StampedTransform transform;
00745         // SERVICES
00747         std::string name_sc_enable_front_laser_, name_sc_enable_back_laser_;
00749         ros::ServiceClient sc_enable_front_laser_;
00751         ros::ServiceClient sc_enable_back_laser_;
00752         
00753 public:
00754         
00758         purepursuit_planner_node(ros::NodeHandle h) : node_handle_(h), private_node_handle_("~"),
00759         desired_freq_(100.0),Component(desired_freq_),action_server_goto(node_handle_, ros::this_node::getName(), false)
00760         // boost::bind(&purepursuit_planner_node::executeCB, this, _1), false)
00761         {
00762                 bRunning = false;
00763                 
00764                 ROSSetup();
00765                 
00766                 dLookAhead = d_lookahear_min_;
00767                 dLinearSpeed = 0;
00768                 pose2d_robot.x = pose2d_robot.y = pose2d_robot.theta = 0.0;
00769                 bEnabled = true;
00770                 bCancel = false;
00771                 
00772                 sComponentName.assign("purepursuit_planner_node");
00773                 iState = INIT_STATE;
00774         }
00775 
00779         ~purepursuit_planner_node(){    
00780                 
00781         }
00782 
00786         void ROSSetup(){
00787                 private_node_handle_.param<std::string>("odom_topic", odom_topic_, "/odom");
00788                 private_node_handle_.param("cmd_topic_vel", cmd_topic_vel_, std::string("/agvs_controller/command"));
00789                 private_node_handle_.param("d_lookahear_min", d_lookahear_min_, D_LOOKAHEAD_MIN);
00790                 private_node_handle_.param("d_lookahear_max", d_lookahear_max_, D_LOOKAHEAD_MAX);
00791                 private_node_handle_.param("d_dist_wheel_to_center", d_dist_wheel_to_center_, D_WHEEL_ROBOT_CENTER);
00792                 private_node_handle_.param("max_speed", max_speed_, MAX_SPEED);
00793                 private_node_handle_.param("kr", Kr, AGVS_DEFAULT_KR);
00794                 private_node_handle_.param<std::string>("position_source", position_source_, "ODOM");
00795                 private_node_handle_.param("desired_freq", desired_freq_, desired_freq_);
00796                 //private_node_handle_.param<std::string>("name_sc_enable_frot_laser_", name_sc_enable_front_laser_, "/s3000_laser_front/enable_disable");
00797                 //private_node_handle_.param<std::string>("name_sc_enable_back_laser", name_sc_enable_back_laser_, "/s3000_laser_back/enable_disable"   );
00798                 
00799         
00800                 // From Component class
00801                 threadData.dDesiredHz = desired_freq_;
00802                 
00803                 if(position_source_ == "MAP")
00804                         ui_position_source = MAP_SOURCE;
00805                 else 
00806                         ui_position_source = ODOM_SOURCE;
00807                         
00808                 //
00809                 // Publish through the node handle Twist type messages to the guardian_controller/command topic
00810                 vel_pub_ = private_node_handle_.advertise<ackermann_msgs::AckermannDriveStamped>(cmd_topic_vel_, 1);
00811                 //
00812                 if(ui_position_source == MAP_SOURCE)
00813                         tranform_map_pub_ = private_node_handle_.advertise<geometry_msgs::TransformStamped>("map_location", 100);
00814                 //status_pub_ = private_node_handle_.advertise<purepursuit_planner::ControllerStatus>("status", 1);
00815                 odom_sub_ = private_node_handle_.subscribe<nav_msgs::Odometry>(odom_topic_, 1, &purepursuit_planner_node::OdomCallback, this ); 
00816                 //cmd_vel_sub_ = private_node_handle_.subscribe<purepursuit_planner::AckermannDriveStamped>("command", 1, &purepursuit_planner_node::CmdVelCallback, this ); 
00817                 
00818                 // Diagnostics
00819                 updater_diagnostic.setHardwareID("PurePursuit-Planner");
00820                 // Topics freq control 
00821                 min_odom_freq = 5.0;
00822                 max_odom_freq = 100.0;
00823                 updater_diagnostic_odom = new diagnostic_updater::TopicDiagnostic(odom_topic_, updater_diagnostic,
00824                                                         diagnostic_updater::FrequencyStatusParam(&min_odom_freq, &max_odom_freq, 0.1, 10),
00825                                                         diagnostic_updater::TimeStampStatusParam(0.001, 0.1));
00826                 
00827                 
00828                 // Action server 
00829                 action_server_goto.registerGoalCallback(boost::bind(&purepursuit_planner_node::GoalCB, this));
00830         action_server_goto.registerPreemptCallback(boost::bind(&purepursuit_planner_node::PreemptCB, this));
00831         
00832         // Services
00833         //sc_enable_front_laser_ = private_node_handle_.serviceClient<s3000_laser::enable_disable>(name_sc_enable_front_laser_);
00834         //sc_enable_back_laser_ = private_node_handle_.serviceClient<s3000_laser::enable_disable>(name_sc_enable_back_laser_);
00835         
00836                 ROS_INFO("%s::ROSSetup(): odom_topic = %s, command_topic_vel = %s, position source = %s, desired_hz=%.1lf, min_lookahead = %.1lf, max_lookahead = %.1lf, kr = %.2lf", sComponentName.c_str(), odom_topic_.c_str(),
00837                  cmd_topic_vel_.c_str(), position_source_.c_str(), desired_freq_, d_lookahear_min_, d_lookahear_max_, Kr);
00838                 
00839                 //ROS_INFO("%s::ROSSetup(): laser_topics: front -> %s, back -> %s", sComponentName.c_str(), name_sc_enable_front_laser_.c_str(), name_sc_enable_back_laser_.c_str());
00840                 
00841                 //last_command_time = ros::Time::now();
00842         }
00843         
00844         
00848         ReturnValue Setup(){
00849                 // Checks if has been initialized
00850                 if(bInitialized){
00851                         ROS_INFO("purepursuit_planner::Setup: Already initialized");    
00852                         return INITIALIZED;
00853                 }
00854                 
00855                 // Starts action server 
00856                 action_server_goto.start();
00857                 
00858                 bInitialized = true;
00859                 
00860                 return OK;
00861         }
00862         
00863 
00867         int ReadAndPublish()
00868         {
00869                 //updater_diagnostic_odom->tick(ros::Time::now());
00870                 updater_diagnostic.update();
00871                 return(0);
00872         }
00873         
00877         ReturnValue Start(){
00878 
00879                 if(bRunning){
00880                         ROS_INFO("agvs_controller::Start: the component's thread is already running");
00881                         return THREAD_RUNNING;
00882                 }
00883                 
00884                 
00885                 bRunning = true;
00886                 return OK;
00887         }
00888 
00892         ReturnValue Stop(){
00893                 
00894                 if(!bRunning){
00895                         ROS_INFO("agvs_controller::Stop: Thread not running");
00896                 
00897                         return THREAD_NOT_RUNNING;
00898                 }
00899                 
00900                 bRunning = false;
00901                 
00902                 return OK;
00903         }
00904 
00905         
00908         void ControlThread()
00909         {
00910                 ROS_INFO("purepursuit_planner::ControlThread(): Init");
00911                 ros::Rate r(desired_freq_);  // 50.0 
00912 
00913                         
00914                 // while(node_handle_.ok()) {
00915                 while(ros::ok()) {
00916                         
00917                         switch(iState){
00918                                 
00919                                 case INIT_STATE:
00920                                         InitState();
00921                                 break;
00922                                 
00923                                 case STANDBY_STATE:
00924                                         StandbyState();
00925                                 break;
00926                                 
00927                                 case READY_STATE:
00928                                         ReadyState();
00929                                 break;
00930                                 
00931                                 case SHUTDOWN_STATE:
00932                                         ShutDownState();
00933                                 break;
00934                                 
00935                                 case EMERGENCY_STATE:
00936                                         EmergencyState();
00937                                 break;
00938                                 
00939                                 case FAILURE_STATE:
00940                                         FailureState();
00941                                 break;
00942                         
00943                         }
00944                         
00945                         AllState();
00946                         
00947                         ros::spinOnce();
00948                         r.sleep();
00949                 }
00950                 ShutDownState();
00951 
00952                 ROS_INFO("purepursuit_planner::ControlThread(): End");
00953                 
00954         }
00955         
00956         
00959         void InitState(){
00960                 //ROS_INFO("purepursuit_planner::InitSate:");
00961                 if(bInitialized && bRunning){
00962                         if(CheckOdomReceive() == 0)
00963                                 SwitchToState(STANDBY_STATE);
00964                 }else{
00965                         if(!bInitialized)
00966                                 Setup();
00967                         if(!bRunning)
00968                                 Start();
00969                 }               
00970                 
00971         }
00972         
00975         void StandbyState(){
00976                 if(CheckOdomReceive() == -1)
00977                         SwitchToState(EMERGENCY_STATE);
00978                 else{
00979                         if(bEnabled && !bCancel ){
00980                                 
00981                                 if(pathCurrent.Size() > 0 || MergePath() == OK){
00982                                         ROS_INFO("%s::StandbyState: route available", sComponentName.c_str());
00983                                         SwitchToState(READY_STATE);
00984                                 }
00985                         }
00986                                 
00987                 }
00988         }
00989         
00992         void ReadyState(){
00993                 if(CheckOdomReceive() == -1){
00994                         SetRobotSpeed(0.0, 0.0);
00995                         SwitchToState(EMERGENCY_STATE);
00996                         return;
00997                 }
00998                 if(!bEnabled){
00999                         ROS_INFO("%s::ReadyState: Motion is disabled", sComponentName.c_str());
01000                         SetRobotSpeed(0.0, 0.0);
01001                         SwitchToState(STANDBY_STATE);
01002                         return;
01003                 }
01004                 if(bCancel){
01005                         ROS_INFO("%s::ReadyState: Cancel requested", sComponentName.c_str());
01006                         SetRobotSpeed(0.0, 0.0);
01007                         SwitchToState(STANDBY_STATE);
01008                         return;
01009                 }
01010                 
01011                 int ret = PurePursuit();
01012                 
01013                 if(ret == -1){
01014                         ROS_ERROR("%s::ReadyState: Error on PurePursuit", sComponentName.c_str());
01015                         bCancel = true; //Activates the flag to cancel the mision
01016                         SetRobotSpeed(0.0, 0.0);
01017                         goto_result.route_result = -1;
01018                         goto_feedback.percent_complete = 100.0; // Set the percent to 100% to complete the action
01019                         
01020                         SwitchToState(STANDBY_STATE);
01021                         
01022                 }else if(ret == 1){
01023                         ROS_INFO("%s::ReadyState: Route finished", sComponentName.c_str());
01024                         SetRobotSpeed(0.0, 0.0);
01025                         goto_result.route_result = 0;
01026                         goto_feedback.percent_complete = 100.0; // Set the percent to 100% to complete the action
01027                         SwitchToState(STANDBY_STATE);
01028                 }
01029                 // We have to update the percent while the mision is ongoing
01030                 
01031         }
01032         
01033         
01037         void UpdateLookAhead(){
01038                 double aux_lookahead = fabs(dLinearSpeed);
01039                 double desired_lookahead = 0.0;
01040                 double inc = 0.01;      // incremento del lookahead
01041                 
01042                 if(aux_lookahead < d_lookahear_min_)
01043                         desired_lookahead = d_lookahear_min_;
01044                 else if(aux_lookahead > d_lookahear_max_)
01045                         desired_lookahead = d_lookahear_max_;
01046                 else{
01047                         desired_lookahead = aux_lookahead;
01048                 }
01049 
01050                 if((desired_lookahead - 0.001) > dLookAhead){
01051                         dLookAhead+= inc;
01052                 }else if((desired_lookahead + 0.001) < dLookAhead)
01053                         dLookAhead-= inc;
01054         }
01055         
01056         
01061         double Dot2( double x1, double y1, double x2, double y2) {
01062                 return (x1*x2 + y1*y2); // cross product
01063         }
01064 
01065 
01069         double Dist(double x1, double y1, double x2, double y2) {
01070                 double diff_x = (x2 - x1);
01071                 double diff_y = (y2 - y1);
01072                 return sqrt( diff_x*diff_x + diff_y*diff_y );
01073         }
01074 
01080         double DistP2S( geometry_msgs::Pose2D current_position, Waypoint s0, Waypoint s1, Waypoint *Pb){
01081                 double vx,vy, wx, wy;
01082 
01083                 double c1, c2, di, b;
01084 
01085                 vx = s1.dX - s0.dX;
01086                 vy = s1.dY - s0.dY;
01087 
01088                 wx = current_position.x - s0.dX;
01089                 wy = current_position.y - s0.dY;
01090 
01091                 c1 = Dot2( wx, wy, vx, vy );
01092 
01093                 if ( c1 <= 0.0 ) {
01094                         di = Dist(current_position.x, current_position.y, s0.dX, s0.dY);
01095                         Pb->dX = s0.dX;
01096                         Pb->dY = s0.dY;
01097                         return di;
01098                 }
01099 
01100                 c2 = Dot2(vx,vy, vx, vy);
01101 
01102                 if ( c2 <= c1 ) {
01103                         //printf("kanban::DistP2S: c2 <= c1\n");
01104                         di = Dist(current_position.x, current_position.y, s1.dX, s1.dY);
01105                         Pb->dX = s1.dY;
01106                         Pb->dY = s1.dY;
01107                         return di;
01108                 }
01109 
01110                 b = c1 / c2;
01111                 Pb->dX = s0.dX + b * vx;
01112                 Pb->dY = s0.dY + b * vy;
01113 
01114                 di = Dist(current_position.x, current_position.y, Pb->dX, Pb->dY);
01115 
01116                 return di;
01117         }
01118         
01119 
01125         ReturnValue PointDlh(geometry_msgs::Pose2D current_position, geometry_msgs::Pose2D *wp) {
01126                 int i,j=0,k;
01127                 double dmin, d, d1, d2, *d_seg;
01128                 double t;
01129                 geometry_msgs::Pose2D target_position;
01130                 Waypoint s0, s1, Pb, Pb1;
01131 
01132                 int size = pathCurrent.NumOfWaypoints();
01133 
01134                 d_seg = new double[size]; //array con la distancia entre puntos consecutivos en la ruta
01135 
01136                 // 1- Find closest segment
01137                 dmin = 100000000;
01138 
01139                 for(i = pathCurrent.GetCurrentWaypointIndex(); i < (size -1); i++) {
01140                         if( (pathCurrent.GetWaypoint(i, &s0) == OK) &&  (pathCurrent.GetWaypoint(i+1, &s1) == OK) ){
01141                                 d_seg[i] = Dist(s0.dX, s0.dY, s1.dX, s1.dY);
01142 
01143                                 d = DistP2S(current_position, s0, s1, &Pb1);            // Pb1 closest point on segment
01144                                 
01145                                 if (d < dmin) {
01146                                         Pb.dX = Pb1.dX;  // not the same as Pb=Pb1 !
01147                                         Pb.dY = Pb1.dY;
01148                                         dmin = d;
01149                                         j = i;      // j : index to closest segment                                     
01150                                 }
01151                                 //ROS_INFO("PointDlh. Distance to segment %d(%.2lf, %2.lf)->%d(%.2lf, %2.lf) = %.3lf,point (%.3lf, %.3lf) (DMIN = %.3lf)", i,
01152                                 //s0.dX, s0.dY, i+1, s1.dX, s1.dY, d, Pb1.dX, Pb1.dY, dmin);
01153                         }else{
01154                                 ROS_ERROR("%s::PointDlh: Error Getting waypoints", sComponentName.c_str());
01155                                 return ERROR;
01156                         }
01157                 }
01158                 
01159                 //ROS_INFO("PointDlh:: Current waypoint index %d, next %d",pathCurrent.GetCurrentWaypointIndex(), j);
01160                                 
01161                 // Si cambiamos de waypoint
01162                 if(pathCurrent.GetCurrentWaypointIndex() != j){
01163                         // Sets the waypoint where the robot is at the moment
01164                         if(pathCurrent.SetCurrentWaypoint(j) == ERROR){
01165                                 ROS_ERROR("%s::PointDlh: Error setting current waypoint to %d", sComponentName.c_str(), j);
01166                                 return ERROR;
01167                         }else{ // OK
01168                                 //ROS_INFO("PointDlh:: Changing waypoint to %d", j);
01169                                 if(j == (size - 2)){    // Penultimo waypoint
01170                                         Waypoint w_last, w_before_last;
01171                                         pathCurrent.GetCurrentWaypoint(&w_before_last); // Penultimo waypoint
01172                                         pathCurrent.BackWaypoint(&w_last);                              // Ultimo waypoint
01173                                         // Distancia maxima = distancia entre el punto actual y el penultimo punto + más la distancia entre los dos ultimos puntos + un valor constante
01174                                         //dMaxDistance = Dist(w_before_last.dX, w_before_last.dY, odomWhenLastWaypoint.px, odomWhenLastWaypoint.py) + Dist(w_last.dX, w_last.dY, w_before_last.dX, w_before_last.dY) + 0.1;
01175                                         //ROS_INFO("%s::PointDlh: Penultimo punto. Robot en (%.3lf, %.3lf, %.3lf). Distancia máxima a recorrer = %.3lf m ", sComponentName.c_str(), odomWhenLastWaypoint.px, odomWhenLastWaypoint.py, odomWhenLastWaypoint.pa, dMaxDistance);
01176                                 }
01177 
01178                         }
01179                 }
01180 
01181                 // 2-Find segment ahead in dlookahead
01182                 if( pathCurrent.GetNextWaypoint(&s1) != OK ){
01183                         ROS_ERROR("%s::PointDlh: Error getting next waypoint %d", sComponentName.c_str(), j);
01184                         return ERROR;
01185                 }
01186 
01187                 d1 = Dist(Pb.dX, Pb.dY, s1.dX, s1.dY);
01188 
01189                 k = j;              // k : index of D_LOOKAHEAD point segment
01190                 while ( (d1 < dLookAhead) && ( (k+1) < (size - 1) ) ) {
01191                         // searched point on this segment
01192                         k = k + 1;
01193                         d1 = d1 + d_seg[k];
01194                 }
01195 
01196                 // 3- Obtain t parameter in the segment
01197                 d2 = ( d1 - dLookAhead );       // t parameter of segment k
01198                 t = (d_seg[k] - d2) / d_seg[k]; // Pendiente avoid div/0. En teoria no puede producirse pq dos waypoints consecutivos serán diferentes
01199                 
01200                 // 4- Obtain point with t parameter
01201                 if( (pathCurrent.GetWaypoint(k, &s0) == OK) && (pathCurrent.GetWaypoint(k + 1, &s1) == OK) ) {
01202 
01203                         target_position.x = s0.dX + ( s1.dX - s0.dX )*t; 
01204                         target_position.y = s0.dY + ( s1.dY - s0.dY )*t;
01205                         double angle_segment = atan2(s1.dY - s0.dY, s1.dX - s0.dX);
01206 
01207                         radnorm(&angle_segment);
01208 
01209                         target_position.theta = angle_segment;
01210                         *wp = target_position;
01211                         
01212                         delete d_seg;
01213 
01214                         return OK;
01215                 }else{
01216                         ROS_ERROR("%s::PointDlh: Error getting next waypoint %d", sComponentName.c_str(), j);
01217                         return ERROR;
01218                 }
01219 
01220         }
01221 
01222 
01231         int PurePursuit(){
01232                 double dx, dy, x1, y1;
01233                 double curv, yaw;
01234                 double wref;//, epw, uw;
01235                 //double d = D_WHEEL_ROBOT_CENTER;   // Length in m (equiv to curv radius)
01236                 double Kd = 1.1; // don't increase! 250
01237                 Waypoint last_waypoint, next_waypoint;
01238                 
01239                 double dAuxSpeed = 0.0;
01240                 double dth;
01241                 double aux = 0.0, dDistCovered = 0.0;
01242                 int ret = 0;
01243                 
01244                 geometry_msgs::Pose2D current_position = this->pose2d_robot;            
01245                 geometry_msgs::Pose2D next_position;            
01246                 
01247                 if(pathCurrent.NumOfWaypoints() < 2)    {
01248                         ROS_ERROR("%s::PurePursuit: not enought waypoints", sComponentName.c_str());                    
01249                         return -1 ;
01250                 }
01251 
01252                 yaw = current_position.theta;
01253                 
01254                 //
01255                 //Updates the lookahead depending of the current velocity
01256                 UpdateLookAhead();
01257                 
01258                 //
01259                 // Get next point in cartesian coordinates
01260                 if(PointDlh(current_position, &next_position) != OK){
01261                         ROS_ERROR("%s::PurePursuit: Error getting next point in the route", sComponentName.c_str());
01262                         return -1;
01263                 }
01264                 //
01265                 // Curvature
01266                 dx = current_position.x - next_position.x;
01267                 dy = current_position.y - next_position.y;
01268                 x1 = cos(yaw)*dx + sin(yaw)*dy; //Original
01269                 y1 = -sin(yaw)*dx + cos(yaw)*dy;
01270 
01271                 if ((x1*x1 + y1*y1) == 0)
01272                         curv = 0;
01273                 else
01274                         curv = (2.0 / (x1*x1 + y1*y1)) * -y1;           //Original
01275 
01276                 // Obtenemos alfa_ref en bucle abierto segun curvatura
01277                 wref = atan(d_dist_wheel_to_center_/(1.0/curv));                
01278                 
01279                 
01280                 if(pathCurrent.BackWaypoint(&last_waypoint) == ERROR){
01281                         ROS_ERROR("%s::PurePursuit: Error getting the last point in the path", sComponentName.c_str());
01282                         return -1;
01283                 }
01284 
01285                 double dAuxDist = Dist(current_position.x, current_position.y, last_waypoint.dX, last_waypoint.dY);     //dist(waypoints.back().pos, current_position);
01286 
01287                 if(pathCurrent.GetNextWaypoint(&next_waypoint) == ERROR){
01288                         ROS_ERROR("%s::PurePursuit: Error getting next waypoint in the path", sComponentName.c_str());
01289                         return -1;
01290                 }
01291 
01292                 dAuxSpeed = next_waypoint.dSpeed;
01293 
01294                 if (dAuxSpeed >= 0)
01295                    dth = next_position.theta - current_position.theta;
01296                 else
01297                    dth = -(next_position.theta + Pi - current_position.theta);
01298 
01299                 // normalize
01300                 radnorm(&dth);
01301                 double aux_wref = wref;
01302                 wref += Kr * dth;
01303                 
01304                 //ROS_INFO("Purepursuit: current pos (%.2lf, %.2lf), next pos (%.2lf, %.2lf), lookahead %.2lf, yaw = %.3lf, curv = %.3lf, dth = %.3lf, wref = %.3lf(%.3lf), speed=%.3lf", current_position.x, current_position.y, next_position.x, next_position.y, dLookAhead, yaw, curv, dth, wref, aux_wref, dAuxSpeed);
01305                 //ROS_INFO("Purepursuit: yaw = %.3lf, curv = %.3lf, dth = %.3lf, wref = %.3lf", yaw, curv, dth, wref);
01306                 
01307                 
01310                 // Controls the max allowed using first restriction
01311                 if(fabs(dAuxSpeed) > max_speed_){ 
01312                         if(dAuxSpeed > 0)
01313                                 dAuxSpeed = max_speed_;
01314                         else
01315                                 dAuxSpeed = -max_speed_;
01316                 }
01317                         
01318                 
01319                 if(dAuxDist <= AGVS_SECOND_DECELERATION_DISTANCE)       {
01320                         if( (dAuxSpeed < 0.0) && (dAuxSpeed < -AGVS_SECOND_DECELERATION_MAXSPEED) )
01321                                 dAuxSpeed = -AGVS_SECOND_DECELERATION_MAXSPEED;
01322                         else if( (dAuxSpeed > 0.0) && (dAuxSpeed > AGVS_SECOND_DECELERATION_MAXSPEED) )
01323                                 dAuxSpeed = AGVS_SECOND_DECELERATION_MAXSPEED;
01324 
01325                 }else if(dAuxDist <= AGVS_FIRST_DECELERATION_DISTANCE) {
01326                         if( (dAuxSpeed < 0.0) && (dAuxSpeed < AGVS_FIRST_DECELERATION_MAXSPEED))
01327                                 dAuxSpeed = -AGVS_FIRST_DECELERATION_MAXSPEED;
01328                         else if( (dAuxSpeed > 0.0) && (dAuxSpeed > AGVS_FIRST_DECELERATION_MAXSPEED) )
01329                                 dAuxSpeed = AGVS_FIRST_DECELERATION_MAXSPEED;
01330                 }
01331                 
01332                 SetRobotSpeed(dAuxSpeed, wref); 
01333                 
01334                 //
01335                 // When the robot is on the last waypoint, checks the distance to the end
01336                 if( pathCurrent.GetCurrentWaypointIndex() >= (pathCurrent.NumOfWaypoints() - 2) ){
01337                         ret = -10;
01338                         double ddist2 = Dist( current_position.x, current_position.y, last_waypoint.dX, last_waypoint.dY);
01339                         // Distancia recorrida
01340                         //dDistCovered = Dist( current_position.px, current_position.py, odomWhenLastWaypoint.px, odomWhenLastWaypoint.py);
01341                         if (ddist2 < WAYPOINT_POP_DISTANCE_M) {
01342                                 SetRobotSpeed(0.0, 0.0);
01343                                 
01344                                 ROS_INFO("%s::PurePursuit: target position reached (%lf, %lf, %lf). Ending current path", sComponentName.c_str(), current_position.x, current_position.x, current_position.theta*180.0/Pi);
01345                                 
01346                                 pathCurrent.Clear();
01347                                 return 1;
01348                         }
01349                 }
01350 
01351                 return 0;
01352         }
01353         
01357         void CancelPath(){
01358                 
01359                 pathCurrent.Clear();    // Clears current path
01360                 pathFilling.Clear();    // Clears the auxiliary path
01361                 while(!qPath.empty())   // Clears the queue of paths
01362                         qPath.pop();
01363                 
01364                 bCancel = false;
01365                 // Cancels current action
01366                 ROS_INFO("%s::CancelPath: action server preempted", sComponentName.c_str());
01367                 action_server_goto.setPreempted();
01368         }
01369         
01372         void SetRobotSpeed(double speed, double angle){
01373                 ackermann_msgs::AckermannDriveStamped ref_msg;
01374                 
01375                 ref_msg.header.stamp = ros::Time::now();
01376                 ref_msg.drive.jerk = 0.0; 
01377                 ref_msg.drive.acceleration = 0.0; 
01378                 ref_msg.drive.steering_angle_velocity = 0.0;
01379                 ref_msg.drive.steering_angle = angle;
01380                 ref_msg.drive.speed = speed;
01381                 
01382                 vel_pub_.publish(ref_msg);
01383         }
01384         
01385         
01388         void ShutDownState(){
01389                 if(bRunning)
01390                         Stop();
01391                 else if(bInitialized)
01392                         ShutDown();
01393                         
01394         }
01395         
01398         void EmergencyState(){
01399                 if(CheckOdomReceive() == 0){
01400                         SwitchToState(STANDBY_STATE);
01401                         return;
01402                 }
01403                 
01404         }
01405         
01408         void FailureState(){
01409         
01410         }
01411         
01414         void AllState(){
01415                 
01416                 // Only if we use the map as source for positioning
01417                 if(ui_position_source == MAP_SOURCE){           
01418                         try{
01419                                 listener.lookupTransform("/map", "/base_link", ros::Time(0), transform);
01420                                 geometry_msgs::TransformStamped msg;
01421                                 tf::transformStampedTFToMsg(transform, msg);
01422                                 pose2d_robot.x = msg.transform.translation.x;
01423                                 pose2d_robot.y = msg.transform.translation.y;
01424                                 pose2d_robot.theta = tf::getYaw(msg.transform.rotation);  
01425                                 // Safety check
01426                                 last_map_time = ros::Time::now();
01427                                 msg.header.stamp = last_map_time;
01428                                 tranform_map_pub_.publish(msg);
01429                         }catch (tf::TransformException ex){
01430                                 //ROS_ERROR("%s::AllState: %s", sComponentName.c_str(), ex.what());
01431                         }
01432                 }
01433                 
01434                 AnalyseCB();    // Checks action server state
01435                 
01436                 ReadAndPublish();       // Reads and publish into configured topics
01437                 
01438                 if(bCancel)             // Performs the cancel in case of required
01439                         CancelPath();
01440         }
01441         
01445         void OdomCallback(const nav_msgs::Odometry::ConstPtr& odom_value)
01446         {
01447                 // Safety check
01448                 last_command_time = ros::Time::now();
01449                 
01450                 // If we want to use the odom source, subscribes to odom topic
01451                 if(ui_position_source == ODOM_SOURCE){          
01452                         // converts the odom to pose 2d
01453                         pose2d_robot.x = odom_value->pose.pose.position.x;
01454                         pose2d_robot.y = odom_value->pose.pose.position.y;
01455                         pose2d_robot.theta = tf::getYaw(odom_value->pose.pose.orientation);
01456                 }
01457                 
01458                 // Copies the current odom
01459                 odometry_robot = *odom_value;
01460                 // Gets the linear speed
01461                 dLinearSpeed = odometry_robot.twist.twist.linear.x;
01462         }
01463         
01469         int CheckOdomReceive()
01470         {               
01471                 // Safety check
01472                 if((ros::Time::now() - last_command_time).toSec() > ODOM_TIMEOUT_ERROR)
01473                         return -1;
01474                 else{
01475                         if( ui_position_source == MAP_SOURCE and ((ros::Time::now() - last_map_time).toSec() > MAP_TIMEOUT_ERROR))
01476                                 return -1;
01477                         else return 0;
01478                 }
01479                 
01480         }
01481         
01482         
01483         void executeCB(const planner_msgs::GoToGoalConstPtr &goal)
01484         {
01485                 
01486         }
01487         
01493         int CalculateDirectionSpeed(Waypoint target_position){
01494                 int ret = 1;
01495                 double alpha = pose2d_robot.theta;
01496                 double x =      pose2d_robot.x, y = pose2d_robot.y;
01497                 double ux, uy, vx, vy;
01498                 double beta = 0.0;
01499                 static int last_direction = 0;
01500                 static double pi_medios = M_PI / 2.0, max_diff = 5.0 * M_PI / 180.0;
01501                 int iCase = 0;
01502 
01503                 //
01504                 // si la posicion objetivo es la misma del robot, devolvemos 0
01505                 if( (target_position.dX == x) && (target_position.dY == y) ){
01506                         return 0;
01507                 }
01508                 // Cálculo del vector director del robot respecto al sistema de coordenadas del robot
01509                 ux = cos(alpha);
01510                 uy = sin(alpha);
01511                 // Cálculo del vector entre el punto objetivo y el robot
01512                 vx = target_position.dX - x;
01513                 vy = target_position.dY - y;
01514 
01515                 // Cálculo del ángulo entre el vector director y el vector al punto objetivo
01516                 beta = acos( (ux * vx + uy * vy) / ( sqrt(ux*ux + uy*uy) * sqrt(vx*vx + vy*vy) ) );
01517 
01518                 // Devolvemos valor dependiendo del ángulo entre la orientación del robot y la posición objetivo (radianes)
01519                 // Tendremos en cuenta el valor del sentido de avance de la última ruta.
01520                 if(fabs(beta) <= pi_medios){
01521                         // Calculo inicial de direccion
01522                         if(last_direction == 0)
01523                                 ret = 1;
01524                         else {
01525                                 ret = 1;
01526 
01527                                 if( fabs(beta - pi_medios) <= max_diff){
01528                                         if(last_direction != ret){
01529                                                 iCase = 1;
01530                                                 ret = -1;
01531 
01532                                         }else {
01533                                                 iCase = 2;
01534                                         }
01535                                 }
01536 
01537                         }
01538                 }else{
01539                         // Calculo inicial de direccion
01540                         if(last_direction == 0)
01541                                 ret = -1;
01542                         else {
01543                                 ret = -1;
01544                                 if(fabs(beta - pi_medios) <= max_diff){
01545                                         if(last_direction != ret){
01546                                                 ret = 1;
01547                                                 iCase = 3;
01548                                         }else{
01549                                                 iCase = 4;
01550                                         }
01551                                 }
01552 
01553                         }
01554                 }
01555 
01556                 ROS_INFO("%s:CalculateDirectionSpeed:  case %d. Beta = %.2lf. Diff = %.2lf. Last direction = %d, new direction = %d", sComponentName.c_str(),
01557                                  iCase, beta*180.0/M_PI, (beta - pi_medios)*180.0/M_PI, last_direction, ret);
01558 
01559                 last_direction = ret;
01560                 return ret;
01561         }
01562         
01568         int CalculateDirectionSpeed(geometry_msgs::Pose2D target_position){
01569                 int ret = 1;
01570                 double alpha = pose2d_robot.theta;
01571                 double x =      pose2d_robot.x, y = pose2d_robot.y;
01572                 double ux, uy, vx, vy;
01573                 double beta = 0.0;
01574                 static int last_direction = 0;
01575                 static double pi_medios = M_PI / 2.0, max_diff = 5.0 * M_PI / 180.0;
01576                 int iCase = 0;
01577 
01578                 //
01579                 // si la posicion objetivo es la misma del robot, devolvemos 0
01580                 if( (target_position.x == x) && (target_position.y == y) ){
01581                         return 0;
01582                 }
01583                 // Cálculo del vector director del robot respecto al sistema de coordenadas del robot
01584                 ux = cos(alpha);
01585                 uy = sin(alpha);
01586                 // Cálculo del vector entre el punto objetivo y el robot
01587                 vx = target_position.x - x;
01588                 vy = target_position.y - y;
01589 
01590                 // Cálculo del ángulo entre el vector director y el vector al punto objetivo
01591                 beta = acos( (ux * vx + uy * vy) / ( sqrt(ux*ux + uy*uy) * sqrt(vx*vx + vy*vy) ) );
01592 
01593                 // Devolvemos valor dependiendo del ángulo entre la orientación del robot y la posición objetivo (radianes)
01594                 // Tendremos en cuenta el valor del sentido de avance de la última ruta.
01595                 if(fabs(beta) <= pi_medios){
01596                         // Calculo inicial de direccion
01597                         if(last_direction == 0)
01598                                 ret = 1;
01599                         else {
01600                                 ret = 1;
01601 
01602                                 if( fabs(beta - pi_medios) <= max_diff){
01603                                         if(last_direction != ret){
01604                                                 iCase = 1;
01605                                                 ret = -1;
01606 
01607                                         }else {
01608                                                 iCase = 2;
01609                                         }
01610                                 }
01611 
01612                         }
01613                 }else{
01614                         // Calculo inicial de direccion
01615                         if(last_direction == 0)
01616                                 ret = -1;
01617                         else {
01618                                 ret = -1;
01619                                 if(fabs(beta - pi_medios) <= max_diff){
01620                                         if(last_direction != ret){
01621                                                 ret = 1;
01622                                                 iCase = 3;
01623                                         }else{
01624                                                 iCase = 4;
01625                                         }
01626                                 }
01627 
01628                         }
01629                 }
01630 
01631                 ROS_INFO("%s:CalculateDirectionSpeed:  case %d. Beta = %.2lf. Diff = %.2lf. Last direction = %d, new direction = %d", sComponentName.c_str(),
01632                                  iCase, beta*180.0/M_PI, (beta - pi_medios)*180.0/M_PI, last_direction, ret);
01633 
01634                 last_direction = ret;
01635                 return ret;
01636         }
01637         
01641         ReturnValue MergePath(){
01642                 Waypoint new_waypoint, wFirst, wLast;
01643                 Path aux;
01644                 int direction = 0;
01645                 
01646                 if(action_server_goto.isNewGoalAvailable()){
01647                         goto_goal.target = action_server_goto.acceptNewGoal()->target; // Reads points from action server
01648                         if(goto_goal.target.size() > 0){
01649                                 if(goto_goal.target.size() > 1){        // Tries to use the second point of the route
01650                                         direction = CalculateDirectionSpeed(goto_goal.target[1].pose);
01651                                 }else{
01652                                         direction = CalculateDirectionSpeed(goto_goal.target[0].pose);
01653                                 }
01654                                 
01655                                 if(direction == 1){     // Uses only front laser
01656                                         SetLaserFront();
01657                                 }else{  // Uses only back laser
01658                                         SetLaserBack();
01659                                 }
01660                                 
01661                                 for(int i = 0; i < goto_goal.target.size(); i++){
01662                                         ROS_INFO("%s::MergePath: Point %d (%.3lf, %.3lf, %.3lf) speed = %.3lf", sComponentName.c_str(), i,  goto_goal.target[i].pose.x, 
01663                                         goto_goal.target[i].pose.y, goto_goal.target[i].pose.theta, goto_goal.target[i].speed  );
01664                                         
01665                                         new_waypoint.dX = goto_goal.target[i].pose.x;
01666                                         new_waypoint.dY = goto_goal.target[i].pose.y;
01667                                         new_waypoint.dA = goto_goal.target[i].pose.theta;
01668                                         // Depending on the calculated motion direction, applies positive or negative speed
01669                                         if(direction == 1){
01670                                                 new_waypoint.dSpeed = fabs(goto_goal.target[i].speed);
01671                                         }else{
01672                                                 new_waypoint.dSpeed = -fabs(goto_goal.target[i].speed);
01673                                         }
01674                                         
01675                                         pathFilling.AddWaypoint(new_waypoint);                                                  
01676                                 }
01677                                 if(pathFilling.Optimize(AGVS_TURN_RADIUS) != OK)
01678                                         ROS_ERROR("%s::GoalCB: Error optimizing the path", sComponentName.c_str());
01679 
01680                                 //pathFilling.Print();
01681                                 // Adds the new path to the queue
01682                                 qPath.push(pathFilling);
01683                                 // Clears temporary path object
01684                                 pathFilling.Clear();
01685                                 
01686                                 goto_feedback.percent_complete = 0.0;   // Inits the feedback percentage
01687                                 
01688                                 // Only if exists any path into the queue
01689                                 if(qPath.size() > 0){                                   
01690                                         aux = qPath.front();
01691                                         aux.GetWaypoint(0, &wFirst);
01692                                         aux.BackWaypoint(&wLast);
01693                                         ROS_INFO("%s::MergePath: Adding new %d points from (%.2lf, %.2lf) to (%.2lf, %.2lf) and %d magnets", sComponentName.c_str(), aux.NumOfWaypoints() ,wFirst.dX, wFirst.dY, wLast.dX, wLast.dY, aux.NumOfMagnets());
01694                                         ROS_INFO("%s::MergePath: Current number of points = %d and magnets = %d", sComponentName.c_str(), pathCurrent.NumOfWaypoints() , pathCurrent.NumOfMagnets());
01695                                         
01696                                         // Adds the first path in the queue to the current path
01697                                         pathCurrent+=qPath.front();
01698                                         
01699                                         ROS_INFO("%s::MergePath: New number of points = %d and magnets = %d", sComponentName.c_str(), pathCurrent.NumOfWaypoints() , pathCurrent.NumOfMagnets());
01700                                         // Pops the extracted path
01701                                         qPath.pop();
01702                                         
01703                                         goto_goal.target.clear();       // removes current goals
01704                                         
01705                                         return OK;
01706                                 }
01707                         }
01708                 
01709                 }
01710                 
01711                 return ERROR;
01712         }
01713         
01717         void GoalCB()
01718         {       
01719                 
01720                 
01721                                 
01722         }
01723         
01727         void PreemptCB()
01728         {       
01729                 bCancel = true; 
01730         }
01731         
01735         void AnalyseCB(){
01736                 if (!action_server_goto.isActive()){
01737                         //ROS_INFO("%s::AnalyseCB: Not active", sComponentName.c_str());
01738                         return;
01739                 }
01740                 //goto_feedback.percent_complete+=1.0;
01741                 
01742                 action_server_goto.publishFeedback(goto_feedback);
01743                 
01744                 if(goto_feedback.percent_complete == 100.0){
01745                         //action_server_goto.setSucceeded(goto_result);
01746                         action_server_goto.setAborted(goto_result);
01747                         ROS_INFO("%s::AnalyseCB: Action finished", sComponentName.c_str());
01748                 }
01749         }
01750         
01754         bool SetLaserFront(){
01755                 /*s3000_laser::enable_disable srv;
01756                 
01757                 srv.request.value = false;
01758                 sc_enable_back_laser_.call(srv);
01759                 ROS_INFO("%s::SetLaserFront: Setting laser back to false, ret = %d", sComponentName.c_str(), srv.response.ret);
01760                 
01761                 srv.request.value = true;
01762                 sc_enable_front_laser_.call(srv);
01763                 ROS_INFO("%s::SetLaserFront: Setting laser front to true, ret = %d", sComponentName.c_str(), srv.response.ret);*/
01764         }
01765         
01769         bool SetLaserBack(){
01770                 /*s3000_laser::enable_disable srv;
01771                 
01772                 srv.request.value = false;
01773                 sc_enable_front_laser_.call(srv);
01774                 ROS_INFO("%s::SetLaserBack: Setting laser front to false, ret = %d", sComponentName.c_str(), srv.response.ret);
01775                 
01776                 srv.request.value = true;
01777                 sc_enable_back_laser_.call(srv);
01778                 ROS_INFO("%s::SetLaserBack: Setting laser back to true, ret = %d", sComponentName.c_str(), srv.response.ret);*/
01779         }
01780 
01781 }; // class purepursuit_planner_node
01782 
01783 // MAIN
01784 int main(int argc, char** argv)
01785 {
01786     ros::init(argc, argv, "purepursuit_planner_node");
01787         
01788         ros::NodeHandle n;              
01789         purepursuit_planner_node planner(n);
01790         
01791         planner.ControlThread();
01792 
01793         return (0);
01794 }
01795 // EOF


purepursuit_planner
Author(s): Román Navarro
autogenerated on Thu Aug 27 2015 12:08:42