no_collision_alg.cpp
Go to the documentation of this file.
00001 #include "no_collision_alg.h"
00002 
00003 #include<math.h>
00004 #include<tf/tf.h>
00005 #include<algorithm>
00006 
00007 NoCollisionAlgorithm::NoCollisionAlgorithm(void)
00008 {
00009   // node configuration attributes
00010   this->MIN_SAFE_DISTANCE_ = 0.4;  // [m]
00011   this->LASER_SAFE_DIST_   = 0.8;  // [m]
00012   this->VT_MAX_            = 0.7;  // [m/s]
00013   this->T_ACC_             = 0.5;  // [m/s2]
00014   this->DIST_TOL_          = 0.01; // [rad]
00015 
00016   this->MIN_SAFE_ANGLE_    = 10.0*M_PI/180.0;  // [rad]
00017   this->VR_MAX_            = 1.0;              // [rad/s]
00018   this->R_ACC_             = 30.0;              // [rad/s2]
00019   this->ANGLE_TOL_         = 0.1;              // [rad]
00020 
00021   this->OA_CONE_ANGLE_     = 100.0*M_PI/180.0; // [rad]
00022   this->MAX_ANGLE_TO_STOP_ = 60.0*M_PI/180.0;  // [rad]
00023   // translational parameters
00024   this->current_vt_        = 0.0;              // [m/s]
00025   this->target_vt_         = this->VT_MAX_;    // [m/s]
00026   this->desired_vt_        = this->VT_MAX_;    // [m/s]
00027   this->acc_dist_          = 0.0;              // [m]
00028   this->deacc_dist_        = 0.0;              // [m]
00029   this->target_dist_       = 0.0;              // [m]
00030   this->current_dist_      = 0.0;              // [m]
00031   this->vt_state_          = traj_idle;
00032 
00033   // rotational parameters
00034   this->current_vr_        = 0.0;              // [rad/s]
00035   this->target_vr_         = this->VR_MAX_;    // [rad/s]
00036   this->desired_vr_        = this->VR_MAX_;    // [rad/s]
00037   this->acc_angle_         = 0.0;              // [rad]
00038   this->deacc_angle_       = 0.0;              // [rad]
00039   this->target_angle_      = 0.0;              // rad]
00040   this->current_angle_     = 0.0;              // [rad]
00041   this->vr_state_          = traj_idle;
00042   this->heading            = 0.0;
00043 }
00044 
00045 NoCollisionAlgorithm::~NoCollisionAlgorithm(void)
00046 {
00047 }
00048 
00049 void NoCollisionAlgorithm::fromCartesian2Polar(const geometry_msgs::Point & p, float & module, float & angle)
00050 {
00051   module = sqrt( p.x*p.x + p.y*p.y );
00052   angle  = atan2( p.y, p.x );
00053 }
00054 
00055 void NoCollisionAlgorithm::fromPolar2Cartesian(const float & module,const float & angle,geometry_msgs::Point & p)
00056 {
00057   p.x=module*cos(angle); 
00058   p.y=module*sin(angle);
00059 }
00060 
00061 void NoCollisionAlgorithm::updateTranslationTrajParams(void)
00062 {
00063   float total_dist;
00064 
00065   // compute the tranlational parameters
00066   this->acc_dist_=fabs((this->desired_vt_-this->current_vt_)*(this->desired_vt_-this->current_vt_)/(2*this->T_ACC_)+this->current_vt_*(this->desired_vt_-this->current_vt_)/(this->T_ACC_));
00067   this->deacc_dist_=fabs(this->desired_vt_*this->desired_vt_/(2*this->T_ACC_));
00068   total_dist=this->acc_dist_+this->deacc_dist_;
00069   if(fabs(total_dist)>fabs(this->current_dist_))
00070     this->target_vt_=sqrt(this->T_ACC_*fabs(this->current_dist_)+this->current_vt_*this->current_vt_/2);
00071   else
00072     this->target_vt_=this->desired_vt_;
00073   ROS_INFO("Target translational speed: %f, Acceleration distance: %f, Deceleration distance: %f",this->target_vt_,this->acc_dist_,this->deacc_dist_);
00074 }
00075 
00076 void NoCollisionAlgorithm::updateRotationTrajParams(void)
00077 {
00078   float total_angle;
00079   int dir=0;
00080 
00081   // compute the rotational parameters
00082   if(this->target_angle_>=0) dir=1;
00083   else dir=-1;
00084   this->acc_angle_=fabs((dir*this->desired_vr_-this->current_vr_)*(dir*this->desired_vr_-this->current_vr_)/(2*this->R_ACC_)+this->current_vr_*(dir*this->desired_vr_-this->current_vr_)/(this->R_ACC_));
00085   this->deacc_angle_=fabs(this->desired_vr_*this->desired_vr_/(2*this->R_ACC_));
00086   total_angle=this->acc_angle_+this->deacc_angle_;
00087   if(fabs(total_angle)>fabs(this->current_angle_))
00088     this->target_vr_=dir*sqrt(this->R_ACC_*fabs(this->current_angle_)+this->current_vr_*this->current_vr_/2);
00089   else
00090     this->target_vr_=dir*this->desired_vr_;
00091   ROS_INFO("Target rotational speed: %f, Acceleration angle: %f, Deceleration angle: %f",this->target_vr_,this->acc_angle_,this->deacc_angle_);
00092 }
00093 
00094 void NoCollisionAlgorithm::config_update(const Config& new_cfg, uint32_t level)
00095 {
00096   this->lock();
00097     // save the current configuration
00098     MIN_SAFE_DISTANCE_ = new_cfg.min_safety_dist;
00099     MIN_SAFE_ANGLE_    = new_cfg.min_safety_angle*M_PI/180.0;
00100     LASER_SAFE_DIST_   = new_cfg.laser_safe_dist;
00101     VT_MAX_            = new_cfg.vT_max;
00102     VR_MAX_            = new_cfg.vR_max;
00103     R_ACC_             = new_cfg.r_acc;
00104     T_ACC_             = new_cfg.t_acc;
00105     OA_CONE_ANGLE_     = new_cfg.oa_cone_aperture*M_PI/180.0;
00106     MAX_ANGLE_TO_STOP_ = new_cfg.max_angle2stop*M_PI/180.0;
00107 
00108     this->config_=new_cfg;
00109   this->unlock();
00110 }
00111 
00112 // NoCollisionAlgorithm Public API
00113 void NoCollisionAlgorithm::setGoal(const geometry_msgs::Pose & local_goal)
00114 {
00115   this->lock();
00116   ROS_WARN("NoCollisionAlgorithm::setGoal");
00117 
00118   // get the new target angle and distance
00119   fromCartesian2Polar(local_goal.position,this->target_dist_,this->target_angle_);
00120   // remove the safety distance 
00121   this->target_dist_-=LASER_SAFE_DIST_+MIN_SAFE_DISTANCE_;
00122   if(this->target_dist_<0) this->target_dist_=0;
00123   this->current_dist_=this->target_dist_;
00124   this->current_angle_=this->target_angle_;
00125   this->target_vt_=this->desired_vt_;
00126   this->target_vr_=this->desired_vr_;
00127   // remove the target angle from the desired heading
00128   this->heading=local_goal.orientation.z-this->target_angle_;
00129   ROS_INFO("NoCollisionAlgorithm::Distance: %f Angle: %f",this->target_dist_,this->target_angle_);
00130   this->updateTranslationTrajParams();
00131   this->updateRotationTrajParams();
00132   // set the initial time
00133   this->current_time_ = ros::Time::now();
00134   this->unlock();
00135 }
00136 
00137 bool NoCollisionAlgorithm::isGoalReached()
00138 {
00139   if(this->vt_state_>=traj_deacc && this->vr_state_>=traj_deacc)
00140     return true;
00141   else
00142     return false;
00143 }
00144 
00145 void NoCollisionAlgorithm::setTranslationalSpeed(const double vt)
00146 {
00147   double speed;
00148 
00149   this->lock();
00150   if(vt>this->VT_MAX_)
00151     speed=this->VT_MAX_;
00152   else
00153     speed=vt;
00154 
00155   this->desired_vt_=speed;
00156   // update the current trajectory parameters
00157   if(this->vt_state_!=traj_deacc)
00158   {
00159     this->updateTranslationTrajParams();
00160     this->updateRotationTrajParams();
00161   }
00162   this->unlock();
00163 }
00164 
00165 void NoCollisionAlgorithm::setRotationalSpeed(const double vr)
00166 {
00167   double speed;
00168 
00169   this->lock();
00170   if(vr>this->VR_MAX_)
00171     speed=this->VR_MAX_;
00172   else
00173     speed=vr;
00174 
00175   this->desired_vr_=speed;
00176   // update the current trajectory parameters
00177   if(this->vr_state_!=traj_deacc)
00178   {
00179     this->updateTranslationTrajParams();
00180     this->updateRotationTrajParams();
00181   }
00182   this->unlock();
00183 }
00184 
00185 void NoCollisionAlgorithm::getDistance2Goal(geometry_msgs::Pose &current_goal)
00186 {
00187   fromPolar2Cartesian(fabs(this->target_dist_-this->current_dist_),this->target_angle_-this->current_angle_,current_goal.position);
00188   std::cout << fabs(this->target_dist_-this->current_dist_) << "," << this->target_angle_-this->current_angle_ << std::endl;
00189 }
00190 
00191 bool NoCollisionAlgorithm::movePlatform(const sensor_msgs::LaserScan & laser,const geometry_msgs::Pose & local_goal, geometry_msgs::Twist &twist)
00192 {
00193   ros::Time prev_time  = current_time_;
00194   current_time_ = ros::Time::now();
00195   double dist_error,angle_error;
00196   double dt = current_time_.toSec() - prev_time.toSec();
00197 
00198   this->lock();
00199     ROS_WARN("NoCollisionAlgorithm::movePlatform::MOVE!");
00200     // compute the current distance to goal
00201     fromCartesian2Polar(local_goal.position,this->current_dist_,this->current_angle_);
00202     this->current_dist_-=LASER_SAFE_DIST_+MIN_SAFE_DISTANCE_;
00203     if(this->current_dist_<0) 
00204       this->current_dist_=0;
00205     ROS_WARN("NoCollisionAlgorithm::Current dist: %f Current angle: %f",this->current_dist_,this->current_angle_);
00206     // always rotate
00207     angle_error=fabs(this->current_angle_);
00208     if(angle_error>=this->ANGLE_TOL_)// still far from the target position
00209     {
00210       if(this->vr_state_==traj_idle)// not a new goal but the error has increased.
00211       {
00212         this->target_vr_=this->desired_vr_;
00213         this->target_angle_=this->current_angle_;
00214         this->updateRotationTrajParams();
00215       }
00216       if(this->current_vr_!=this->target_vr_)// it is necessary to change the current speed
00217       {
00218         if(this->current_vr_<this->target_vr_)
00219         {
00220           this->current_vr_+=this->R_ACC_*dt;
00221           if(this->current_vr_>this->target_vr_)
00222             this->current_vr_=this->target_vr_;
00223         }
00224         else
00225         {
00226           this->current_vr_-=this->R_ACC_*dt;
00227           if(this->current_vr_<this->target_vr_)
00228             this->current_vr_=this->target_vr_;
00229         }
00230         this->vr_state_=traj_acc;
00231       }
00232       else
00233       {
00234         if(angle_error>=this->deacc_angle_)
00235         {
00236           // keep the current speed
00237           this->vr_state_=traj_speed;
00238         }
00239         else
00240         {
00241           if(this->current_vr_>0)
00242           {
00243             this->current_vr_-=this->R_ACC_*dt;
00244             if(this->current_vr_<=0)
00245               this->current_vr_=0;
00246             this->target_vr_=this->current_vr_;
00247           }
00248           else
00249           {
00250             this->current_vr_+=this->R_ACC_*dt;
00251             if(this->current_vr_>=0)
00252               this->current_vr_=0;
00253             this->target_vr_=this->current_vr_;
00254           }
00255           this->vr_state_=traj_deacc;
00256         }
00257       }
00258     }
00259     else
00260     {
00261       this->current_vr_=0;
00262       this->vr_state_=traj_idle;
00263     }
00264     // if the angle error is small, start moving forward
00265     if(angle_error<(MAX_ANGLE_TO_STOP_))
00266     {
00267       // check weather the goal is traversable or not
00268       if(isGoalTraversable(laser,local_goal.position))
00269       {
00270         dist_error=fabs(this->current_dist_);
00271         if(dist_error>=this->DIST_TOL_)// still far from the target position
00272         {
00273           if(this->vt_state_==traj_idle)// not a new goal but the error has increased.
00274           {
00275             this->target_vt_=this->desired_vt_;
00276             this->target_dist_=this->current_dist_;
00277             this->updateTranslationTrajParams();
00278           }
00279           if(this->current_vt_!=this->target_vt_)// it is necessary to change the current speed
00280           {
00281             if(this->current_vt_<this->target_vt_)
00282             {
00283               this->current_vt_+=this->T_ACC_*dt;
00284               if(this->current_vt_>this->target_vt_)
00285                 this->current_vt_=this->target_vt_;
00286             }
00287             else
00288             { 
00289               this->current_vt_-=this->T_ACC_*dt;
00290               if(this->current_vt_<this->target_vt_)
00291                 this->current_vt_=this->target_vt_;
00292             }
00293             this->vt_state_=traj_acc;
00294           }
00295           else
00296           {
00297             if(dist_error>=this->deacc_dist_)
00298             {
00299               // keep the current speed
00300               this->vt_state_=traj_speed;
00301             }
00302             else
00303             {
00304               if(this->current_vt_>0)
00305               {
00306                 this->current_vt_-=this->T_ACC_*dt;
00307                 if(this->current_vt_<=0)
00308                   this->current_vt_=0;
00309                 this->target_vt_=this->current_vt_;
00310               }
00311               else
00312               {
00313                 this->current_vt_+=this->T_ACC_*dt;
00314                 if(this->current_vt_>=0)
00315                   this->current_vt_=0;
00316                 this->target_vt_=this->current_vt_;
00317               }
00318               this->vt_state_=traj_deacc;
00319             }
00320           }
00321         }
00322         else
00323         {
00324           this->current_vt_=0;
00325           this->vt_state_=traj_idle;
00326         }
00327       }
00328       else// there is an obstacle in the path
00329       {
00330         ROS_WARN("NoCollisionAlgorithm::movePlatform::STOP!");
00331         // start decelerating ??
00332         this->current_vt_=0;
00333       }
00334     }
00335     else// decelerate if the angle error increases
00336     {
00337       if(this->current_vt_==0)
00338         this->vt_state_=traj_idle;
00339       else
00340       {
00341         if(this->current_vt_>0)
00342         {
00343           this->current_vt_-=this->T_ACC_*dt;
00344           if(this->current_vt_<=0)
00345           this->current_vt_=0;
00346           this->target_vt_=this->current_vt_;
00347         }
00348         else
00349         {
00350           this->current_vt_+=this->T_ACC_*dt;
00351           if(this->current_vt_>=0)
00352             this->current_vt_=0;
00353           this->target_vt_=this->current_vt_;
00354         }
00355         this->vt_state_=traj_deacc;
00356       }
00357     }
00358     twist.linear.x=this->current_vt_;
00359     twist.angular.z=this->current_vr_;
00360     ROS_INFO("vT=%f\t\tvR=%f,state=%d", twist.linear.x, twist.angular.z,this->vr_state_);
00361   this->unlock();
00362   if(this->vt_state_==traj_idle && this->vr_state_==traj_idle)
00363     return true;
00364   else
00365     return false;
00366 }
00367 
00368 bool NoCollisionAlgorithm::isGoalTraversable(const sensor_msgs::LaserScan & laser, 
00369                                              const geometry_msgs::Point & goal)
00370 {
00371   // convert goal from cartesian to polar coordinates
00372   float module_goal, angle_goal;
00373   fromCartesian2Polar(goal, module_goal, angle_goal);
00374 
00375   // index of the laser range corresponding to robot orientation
00376   const unsigned int central_index_range = round(laser.ranges.size()/2);
00377 
00378   // transform angle goal from robot coordinates to laser ranges
00379   const unsigned int goal_index_range = round(angle_goal/laser.angle_increment) + central_index_range;
00380 
00381   // total aperture angle in radians
00382   const double cone_aperture = OA_CONE_ANGLE_; //*M_PI/180.f;
00383   const unsigned int half_index_cone = abs(round(cone_aperture/(laser.angle_increment*2)));
00384 
00385   // for all cone indexes inside laser scan
00386   for(unsigned int ii=std::max(goal_index_range-half_index_cone,(unsigned int)0);
00387                    ii<std::min(goal_index_range+half_index_cone,(unsigned int)laser.ranges.size());
00388                    ii++)
00389   {
00390     // if there is an obstacle
00391     if ( laser.ranges[ii] > MIN_LASER_RANGE_ && laser.ranges[ii] <= this->LASER_SAFE_DIST_ )
00392     {
00393       ROS_DEBUG("NoCollisionAlgorithm::isGoalTraversable::FALSE");
00394       return false;
00395     }
00396   }
00397 
00398   ROS_DEBUG("NoCollisionAlgorithm::isGoalTraversable::TRUE");
00399   return true;
00400 }


iri_no_collision
Author(s):
autogenerated on Fri Dec 6 2013 21:10:48