eband_local_planner.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  *
00003  * Software License Agreement (BSD License)
00004  *
00005  *  Copyright (c) 2010, Willow Garage, Inc.
00006  *  All rights reserved.
00007  *
00008  *  Redistribution and use in source and binary forms, with or without
00009  *  modification, are permitted provided that the following conditions
00010  *  are met:
00011  *
00012  *   * Redistributions of source code must retain the above copyright
00013  *     notice, this list of conditions and the following disclaimer.
00014  *   * Redistributions in binary form must reproduce the above
00015  *     copyright notice, this list of conditions and the following
00016  *     disclaimer in the documentation and/or other materials provided
00017  *     with the distribution.
00018  *   * Neither the name of Willow Garage, Inc. nor the names of its
00019  *     contributors may be used to endorse or promote products derived
00020  *     from this software without specific prior written permission.
00021  *
00022  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033  *  POSSIBILITY OF SUCH DAMAGE.
00034  *
00035  * Author: Christian Connette
00036  *********************************************************************/
00037 
00038 #include <eband_local_planner/eband_local_planner.h>
00039 
00040 
00041 namespace eband_local_planner{
00042 
00043 
00044   EBandPlanner::EBandPlanner() : costmap_ros_(NULL), initialized_(false) {}
00045 
00046 
00047   EBandPlanner::EBandPlanner(std::string name, costmap_2d::Costmap2DROS* costmap_ros)
00048     : costmap_ros_(NULL), initialized_(false)
00049   {
00050     // initialize planner
00051     initialize(name, costmap_ros);
00052   }
00053 
00054 
00055   EBandPlanner::~EBandPlanner()
00056   {
00057     delete world_model_;
00058   }
00059 
00060 
00061   void EBandPlanner::initialize(std::string name, costmap_2d::Costmap2DROS* costmap_ros)
00062   {
00063     // check if the plugin is already initialized
00064     if(!initialized_)
00065     {
00066       // copy adress of costmap (handed over from move_base via eband wrapper)
00067       costmap_ros_ = costmap_ros;
00068 
00069       // get a pointer to the underlying costmap
00070       costmap_ = costmap_ros_->getCostmap();
00071 
00072       // create world model from costmap
00073       world_model_ = new base_local_planner::CostmapModel(*costmap_);
00074 
00075       // get footprint of the robot
00076       footprint_spec_ = costmap_ros_->getRobotFootprint();
00077 
00078 
00079       // create Node Handle with name of plugin (as used in move_base for loading)
00080       ros::NodeHandle pn("~/" + name);
00081 
00082       // read parameters from parameter server
00083       // connectivity checking
00084       pn.param("eband_min_relative_bubble_overlap_", min_bubble_overlap_, 0.7);
00085 
00086       // bubble geometric bounds
00087       pn.param("eband_tiny_bubble_distance", tiny_bubble_distance_, 0.01);
00088       pn.param("eband_tiny_bubble_expansion", tiny_bubble_expansion_, 0.01);
00089 
00090       // optimization - force calculation
00091       pn.param("eband_internal_force_gain", internal_force_gain_, 1.0);
00092       pn.param("eband_external_force_gain", external_force_gain_, 2.0);
00093       pn.param("num_iterations_eband_optimization", num_optim_iterations_, 3);
00094 
00095       // recursive approximation of bubble equilibrium position based
00096       pn.param("eband_equilibrium_approx_max_recursion_depth", max_recursion_depth_approx_equi_, 4);
00097       pn.param("eband_equilibrium_relative_overshoot", equilibrium_relative_overshoot_, 0.75);
00098       pn.param("eband_significant_force_lower_bound", significant_force_, 0.15);
00099 
00100       // use this parameter if a different weight is supplied to the costmap in dyn reconfigure
00101       pn.param("costmap_weight", costmap_weight_, 10.0);
00102 
00103       // clean up band
00104       elastic_band_.clear();
00105 
00106       // set initialized flag
00107       initialized_ = true;
00108 
00109       // set flag whether visualization availlable to false by default
00110       visualization_ = false;
00111     }
00112     else
00113     {
00114       ROS_WARN("This planner has already been initialized, doing nothing.");
00115     }
00116   }
00117 
00118   void EBandPlanner::setVisualization(boost::shared_ptr<EBandVisualization> eband_visual)
00119   {
00120     eband_visual_ = eband_visual;
00121 
00122     visualization_ = true;
00123   }
00124 
00125 
00126   bool EBandPlanner::setPlan(const std::vector<geometry_msgs::PoseStamped>& global_plan)
00127   {
00128     // check if plugin initialized
00129     if(!initialized_)
00130     {
00131       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
00132       return false;
00133     }
00134 
00135 
00136     // check if plan valid (minimum 2 frames)
00137     if(global_plan.size() < 2)
00138     {
00139       ROS_ERROR("Attempt to pass empty path to optimization. Valid path needs to have at least 2 Frames. This one has %d.", ((int) global_plan.size()) );
00140       return false;
00141     }
00142     // copy plan to local member variable
00143     global_plan_ = global_plan;
00144 
00145 
00146     // check whether plan and costmap are in the same frame
00147     if(global_plan.front().header.frame_id != costmap_ros_->getGlobalFrameID())
00148     {
00149       ROS_ERROR("Elastic Band expects plan for optimization in the %s frame, the plan was sent in the %s frame.",
00150           costmap_ros_->getGlobalFrameID().c_str(), global_plan.front().header.frame_id.c_str());
00151       return false;
00152     }
00153 
00154 
00155     // convert frames in path into bubbles in band -> sets center of bubbles and calculates expansion
00156     ROS_DEBUG("Converting Plan to Band");
00157     if(!convertPlanToBand(global_plan_, elastic_band_))
00158     {
00159       ROS_WARN("Conversion from plan to elastic band failed. Plan probably not collision free. Plan not set for optimization");
00160       // TODO try to do local repairs of band
00161       return false;
00162     }
00163 
00164 
00165     // close gaps and remove redundant bubbles
00166     ROS_DEBUG("Refining Band");
00167     if(!refineBand(elastic_band_))
00168     {
00169       ROS_WARN("Band is broken. Could not close gaps in converted path. Path not set. Global replanning needed");
00170       return false;
00171     }
00172 
00173 
00174     ROS_DEBUG("Refinement done - Band set.");
00175     return true;
00176   }
00177 
00178 
00179   bool EBandPlanner::getPlan(std::vector<geometry_msgs::PoseStamped>& global_plan)
00180   {
00181     // check if plugin initialized
00182     if(!initialized_)
00183     {
00184       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
00185       return false;
00186     }
00187 
00188     // check if there is a band
00189     if(elastic_band_.empty())
00190     {
00191       ROS_WARN("Band is empty. There was no path successfully set so far.");
00192       return false;
00193     }
00194 
00195     // convert band to plan
00196     if(!convertBandToPlan(global_plan, elastic_band_))
00197     {
00198       ROS_WARN("Conversion from Elastic Band to path failed.");
00199       return false;
00200     }
00201 
00202     return true;
00203   }
00204 
00205 
00206   bool EBandPlanner::getBand(std::vector<Bubble>& elastic_band)
00207   {
00208     // check if plugin initialized
00209     if(!initialized_)
00210     {
00211       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
00212       return false;
00213     }
00214 
00215     elastic_band = elastic_band_;
00216 
00217     // check if there is a band
00218     if(elastic_band_.empty())
00219     {
00220       ROS_WARN("Band is empty.");
00221       return false;
00222     }
00223 
00224     return true;
00225   }
00226 
00227 
00228   bool EBandPlanner::addFrames(const std::vector<geometry_msgs::PoseStamped>& plan_to_add, const AddAtPosition& add_frames_at)
00229   {
00230     // check if plugin initialized
00231     if(!initialized_)
00232     {
00233       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
00234       return false;
00235     }
00236 
00237     // check that there is a plan at all (minimum 1 frame in this case, as robot + goal = plan)
00238     if(elastic_band_.size() < 1)
00239     {
00240       ROS_WARN("Attempt to connect path to empty band. path not connected. Use SetPath instead");
00241       return false;
00242     }
00243 
00244     //check that plan which shall be added is not empty
00245     if(plan_to_add.empty())
00246     {
00247       ROS_WARN("Attempt to connect empty path to band. Nothing to do here.");
00248       return false;
00249     }
00250 
00251     // check whether plan and costmap are in the same frame
00252     if(plan_to_add.at(0).header.frame_id != costmap_ros_->getGlobalFrameID())
00253     {
00254       ROS_ERROR("Elastic Band expects robot pose for optimization in the %s frame, the pose was sent in the %s frame.",
00255           costmap_ros_->getGlobalFrameID().c_str(), plan_to_add.at(0).header.frame_id.c_str());
00256       return false;
00257     }
00258 
00259 
00260     // convert plan to band
00261     std::vector<Bubble> band_to_add;
00262     if(!convertPlanToBand(plan_to_add, band_to_add))
00263     {
00264       ROS_DEBUG("Conversion from plan to elastic band failed. Plan not appended");
00265       // TODO try to do local repairs of band
00266       return false;
00267     }
00268 
00269 
00270     // connect frames to existing band
00271     ROS_DEBUG("Checking for connections between current band and new bubbles");
00272     bool connected = false;
00273     int bubble_connect = -1;
00274     if(add_frames_at == add_front)
00275     {
00276       // add frames at the front of the current band
00277       // - for instance to connect band and current robot position
00278       for(int i = ((int) elastic_band_.size() - 1); i >= 0; i--)
00279       {
00280         // cycle over bubbles from End - connect to bubble furthest away but overlapping
00281         if(checkOverlap(band_to_add.back(), elastic_band_.at(i)))
00282         {
00283           bubble_connect = i;
00284           connected = true;
00285           break;
00286         }
00287       }
00288     }
00289     else
00290     {
00291       // add frames at the end of the current band
00292       // - for instance to connect new frames entering the moving window
00293       for(int i = 0; i < ((int) elastic_band_.size() - 1); i++)
00294       {
00295         // cycle over bubbles from Start - connect to bubble furthest away but overlapping
00296         if(checkOverlap(band_to_add.front(), elastic_band_.at(i)))
00297         {
00298           bubble_connect = i;
00299           connected = true;
00300           break;
00301         }
00302       }
00303     }
00304 
00305     // intanstiate local copy of band
00306     std::vector<Bubble> tmp_band;
00307     std::vector<Bubble>::iterator tmp_iter1, tmp_iter2;
00308     // copy new frames to tmp_band
00309     tmp_band.assign(band_to_add.begin(), band_to_add.end());
00310 
00311     if(connected)
00312     {
00313       ROS_DEBUG("Connections found - composing new band by connecting new frames to bubble %d", bubble_connect);
00314       if(add_frames_at == add_front)
00315       {
00316         // compose new vector by appending elastic_band to new frames
00317         tmp_iter1 = elastic_band_.begin() + bubble_connect;
00318         ROS_ASSERT( (tmp_iter1 >= elastic_band_.begin()) && (tmp_iter1 < elastic_band_.end()) );
00319         tmp_band.insert(tmp_band.end(), tmp_iter1, elastic_band_.end());
00320       }
00321       else
00322       {
00323         // compose new vector by pre-appending elastic_band to new frames
00324         tmp_iter1 = elastic_band_.begin() + bubble_connect + 1; // +1 - as insert only appends [start, end)
00325         ROS_ASSERT( (tmp_iter1 > elastic_band_.begin()) && (tmp_iter1 <= elastic_band_.end()) );
00326         tmp_band.insert(tmp_band.begin(), elastic_band_.begin(), tmp_iter1);
00327       }
00328 
00329       // done
00330       elastic_band_ = tmp_band;
00331       return true;
00332     }
00333 
00334     // otherwise, we need to do some more work - add complete band to tmp_band
00335     ROS_DEBUG("No direct connection found - Composing tmp band and trying to fill gap");
00336     if(add_frames_at == add_front)
00337     {
00338       // compose new vector by appending elastic_band to new frames
00339       tmp_band.insert(tmp_band.end(), elastic_band_.begin(), elastic_band_.end());
00340       // and get iterators to connecting bubbles
00341       tmp_iter1 = tmp_band.begin() + ((int) band_to_add.size()) - 1;
00342       tmp_iter2 = tmp_iter1 + 1;
00343     }
00344     else
00345     {
00346       // compose new vector by pre-appending elastic_band to new frames
00347       tmp_band.insert(tmp_band.begin(), elastic_band_.begin(), elastic_band_.end());
00348       // and get iterators to connecting bubbles
00349       tmp_iter1 = tmp_band.begin() + ((int) elastic_band_.size()) - 1;
00350       tmp_iter2 = tmp_iter1 + 1;
00351     }
00352 
00353     // just in case
00354     ROS_ASSERT( tmp_iter1 >= tmp_band.begin() );
00355     ROS_ASSERT( tmp_iter2 < tmp_band.end() );
00356     ROS_ASSERT( tmp_iter1 < tmp_iter2 );
00357     if(!fillGap(tmp_band, tmp_iter1, tmp_iter2))
00358     {
00359       // we could not connect band and robot at its current position
00360       ROS_DEBUG("Could not connect robot pose to band - Failed to fill gap.");
00361       return false;
00362     }
00363 
00364     // otherwise - done
00365     elastic_band_ = tmp_band;
00366 
00367     return true;
00368   }
00369 
00370 
00371   bool EBandPlanner::optimizeBand()
00372   {
00373     // check if plugin initialized
00374     if(!initialized_)
00375     {
00376       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
00377       return false;
00378     }
00379 
00380     // check if there is a band
00381     if(elastic_band_.empty())
00382     {
00383       ROS_ERROR("Band is empty. Probably Band has not been set yet");
00384       return false;
00385     }
00386 
00387     // call optimization with member elastic_band_
00388     ROS_DEBUG("Starting optimization of band");
00389     if(!optimizeBand(elastic_band_))
00390     {
00391       ROS_DEBUG("Aborting Optimization. Changes discarded.");
00392       return false;
00393     }
00394 
00395     ROS_DEBUG("Elastic Band - Optimization successfull!");
00396     return true;
00397   }
00398 
00399 
00400   bool EBandPlanner::optimizeBand(std::vector<Bubble>& band)
00401   {
00402     // check if plugin initialized
00403     if(!initialized_)
00404     {
00405       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
00406       return false;
00407     }
00408 
00409     // check whether band and costmap are in the same frame
00410     if(band.front().center.header.frame_id != costmap_ros_->getGlobalFrameID())
00411     {
00412       ROS_ERROR("Elastic Band expects plan for optimization in the %s frame, the plan was sent in the %s frame.",
00413           costmap_ros_->getGlobalFrameID().c_str(), band.front().center.header.frame_id.c_str());
00414       return false;
00415     }
00416 
00417     double distance;
00418     for(int i = 0; i < ((int) band.size()); i++)
00419     {
00420       // update Size of Bubbles in band by calculating Dist to nearest Obstacle [depends kinematic, environment]
00421       if(!calcObstacleKinematicDistance(band.at(i).center.pose, distance))
00422       {
00423         ROS_DEBUG("Optimization (Elastic Band) - Calculation of Distance failed. Frame %d of %d Probably outside map coordinates.",
00424             i, ((int) band.size()) );
00425         return false;
00426       }
00427 
00428       if(distance == 0.0)
00429       {
00430         // frame must not be immediately in collision -> otherwise calculation of gradient will later be invalid
00431         ROS_DEBUG("Optimization (Elastic Band) - Calculation of Distance failed. Frame %d of %d in collision. Plan invalid. Trying to refine band.",
00432             i, ((int) band.size()) );
00433         // TODO if frame in collision try to repair band instead of aborting everything
00434         return false;
00435       }
00436 
00437       band.at(i).expansion = distance;
00438     }
00439 
00440     // close gaps and remove redundant bubbles
00441     if(!refineBand(band))
00442     {
00443       ROS_DEBUG("Elastic Band is broken. Could not close gaps in band. Global replanning needed.");
00444       return false;
00445     }
00446 
00447     // get a copy of current (valid) band
00448     std::vector<Bubble> tmp_band = band;
00449 
00450     // now optimize iteratively (for instance by miminizing the energy-function of the full system)
00451     for(int i = 0; i < num_optim_iterations_; i++)
00452     {
00453       ROS_DEBUG("Inside optimization: Cycle no %d", i);
00454 
00455       // calculate forces and apply changes
00456       if(!modifyBandArtificialForce(tmp_band))
00457       {
00458         ROS_DEBUG("Optimization failed while trying to modify Band.");
00459         // something went wrong -> discard changes and stop process
00460         return false;
00461       }
00462 
00463       // check whether band still valid - refine if neccesarry
00464       if(!refineBand(tmp_band))
00465       {
00466         ROS_DEBUG("Optimization failed while trying to refine modified band");
00467         // modified band is not valid anymore -> discard changes and stop process
00468         return false;
00469       }
00470     }
00471 
00472     // copy changes back to band
00473     band = tmp_band;
00474     return true;
00475   }
00476 
00477 
00478   // private methods
00479 
00480   bool EBandPlanner::refineBand(std::vector<Bubble>& band)
00481   {
00482     // check if plugin initialized
00483     if(!initialized_)
00484     {
00485       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
00486       return false;
00487     }
00488 
00489     // check if band valid (minimum 2 bubbles)
00490     if(band.size() < 2)
00491     {
00492       ROS_WARN("Attempt to convert empty band to plan. Valid band needs to have at least 2 Frames. This one has %d.", ((int) band.size()) );
00493       return false;
00494     }
00495 
00496     // instantiate local variables
00497     bool success;
00498     std::vector<Bubble> tmp_band;
00499     std::vector<Bubble>::iterator start_iter, end_iter;
00500 
00501     // remove redundant Bubbles and fill gabs recursively
00502     tmp_band = band;
00503     start_iter = tmp_band.begin();
00504     end_iter = (tmp_band.end() - 1); // -1 because .end() points "past the end"!
00505 
00506     success = removeAndFill(tmp_band, start_iter, end_iter);
00507 
00508     if(!success)
00509       ROS_DEBUG("Band is broken. Could not close gaps.");
00510     else
00511     {
00512 #ifdef DEBUG_EBAND_
00513       ROS_DEBUG("Recursive filling and removing DONE");
00514 #endif
00515       band = tmp_band;
00516     }
00517 
00518     return success;
00519   }
00520 
00521 
00522   bool EBandPlanner::removeAndFill(std::vector<Bubble>& band, std::vector<Bubble>::iterator& start_iter,std::vector<Bubble>::iterator& end_iter)
00523   {
00524     // instantiate local variables
00525     bool overlap;
00526     std::vector<Bubble>::iterator tmp_iter;
00527     int mid_int, diff_int;
00528 
00529 #ifdef DEBUG_EBAND_
00530     int debug_dist_start, debug_dist_iters;
00531     debug_dist_start = std::distance(band.begin(), start_iter);
00532     debug_dist_iters = std::distance(start_iter, end_iter);
00533     ROS_DEBUG("Refining Recursive - Check if Bubbles %d and %d overlapp. Total size of band %d.", debug_dist_start, (debug_dist_start + debug_dist_iters), ((int) band.size()) );
00534 #endif
00535 
00536     // check that iterators are still valid
00537     ROS_ASSERT( start_iter >= band.begin() );
00538     ROS_ASSERT( end_iter < band.end() ); // "<" because .end() points _behind_ last element of vector
00539     ROS_ASSERT( start_iter < end_iter );
00540 
00541     // check whether start and end bubbles of this intervall overlap
00542     overlap = checkOverlap(*start_iter, *end_iter);
00543 
00544     if(overlap)
00545     {
00546 
00547 #ifdef DEBUG_EBAND_
00548       ROS_DEBUG("Refining Recursive - Bubbles overlapp, check for redundancies");
00549 #endif
00550 
00551       // if there are bubbles between start and end of intervall remove them (they are redundant as start and end of intervall do overlap)
00552       if((start_iter + 1) < end_iter)
00553       {
00554 #ifdef DEBUG_EBAND_
00555         ROS_DEBUG("Refining Recursive - Bubbles overlapp, removing Bubbles %d to %d.", (debug_dist_start + 1), (debug_dist_start + debug_dist_iters -1));
00556 #endif
00557 
00558         // erase bubbles between start and end (but not start and end themself) and get new iterator to end (old one is invalid)
00559         tmp_iter = band.erase((start_iter+1), end_iter);
00560 
00561         // write back changed iterator pointing to the end of the intervall
00562         end_iter = tmp_iter;
00563       }
00564 
00565 #ifdef DEBUG_EBAND_
00566       ROS_DEBUG("Refining Recursive - Bubbles overlapp - DONE");
00567 #endif
00568 
00569       // we are done here (leaf of this branch is reached)
00570       return true;
00571     }
00572 
00573 
00574     // if bubbles do not overlap -> check whether there are still bubbles between start and end
00575     if((start_iter + 1) < end_iter)
00576     {
00577 #ifdef DEBUG_EBAND_
00578       ROS_DEBUG("Refining Recursive - Bubbles do not overlapp, go one recursion deeper");
00579 #endif
00580 
00581       // split remaining sequence of bubbles
00582       // get distance between start and end iterator for this intervall
00583       mid_int = std::distance(start_iter, end_iter);
00584       mid_int = mid_int/2; // division by integer implies floor (round down)
00585 
00586       // now get iterator pointing to the middle (roughly)
00587       tmp_iter = start_iter + mid_int;
00588       // and realative position of end_iter to tmp_iter
00589       diff_int = (int) std::distance(tmp_iter, end_iter);
00590 
00591       // after all this arithmetics - check that iterators are still valid
00592       ROS_ASSERT( start_iter >= band.begin() );
00593       ROS_ASSERT( end_iter < band.end() ); // "<" because .end() points _behind_ last element of vector
00594       ROS_ASSERT( start_iter < end_iter );
00595 
00596 
00597       // and call removeAndFill recursively for the left intervall
00598       if(!removeAndFill(band, start_iter, tmp_iter))
00599       {
00600         // band is broken in this intervall and could not be fixed
00601         return false;
00602       }
00603 
00604       // carefull at this point!!! if we filled in or removed bubbles end_iter is not valid anymore
00605       // but the relative position towards tmp_iter is still the same and tmp_iter was kept valid in the lower recursion steps
00606       end_iter = tmp_iter + diff_int;
00607 
00608       // check that iterators are still valid - one more time
00609       ROS_ASSERT( start_iter >= band.begin() );
00610       ROS_ASSERT( end_iter < band.end() ); // "<" because .end() points _behind_ last element of vector
00611       ROS_ASSERT( (start_iter < tmp_iter) && (tmp_iter < end_iter) );
00612 
00613 
00614       // o.k. we are done with left hand intervall now do the same for the right hand intervall
00615       // but first get relative position of start and tmp iter
00616       diff_int = (int) std::distance(start_iter, tmp_iter);
00617       if(!removeAndFill(band, tmp_iter, end_iter))
00618       {
00619         // band is broken in this intervall and could not be fixed
00620         return false;
00621       }
00622 
00623       // if we filled in bubbles vector might have been reallocated -> start_iter might be invalid
00624       start_iter = tmp_iter - diff_int;
00625 
00626       // check that iterators are still valid - almost done
00627       ROS_ASSERT( start_iter >= band.begin() );
00628       ROS_ASSERT( end_iter < band.end() ); // "<" because .end() points _behind_ last element of vector
00629       ROS_ASSERT( (start_iter < tmp_iter) && (tmp_iter < end_iter) );
00630 
00631 
00632       // we reached the leaf but we are not yet done
00633       // -> we know that there are no redundant elements in the left intervall taken on its own
00634       // -> and we know the same holds for the right intervall
00635       // but the middle bubble itself might be redundant -> check it
00636       if(checkOverlap(*(tmp_iter-1), *(tmp_iter+1)))
00637       {
00638 #ifdef DEBUG_EBAND_
00639         ROS_DEBUG("Refining Recursive - Removing middle bubble");
00640 #endif
00641 
00642         // again: get distance between (tmp_iter + 1) and end_iter, (+1 because we will erase tmp_iter itself)
00643         diff_int = (int) std::distance((tmp_iter + 1), end_iter);
00644 
00645         // remove middle bubble and correct end_iter
00646         tmp_iter = band.erase(tmp_iter);
00647         end_iter = tmp_iter + diff_int;
00648       }
00649 
00650       // check that iterators are still valid - almost almost
00651       ROS_ASSERT( start_iter >= band.begin() );
00652       ROS_ASSERT( end_iter < band.end() ); // "<" because .end() points _behind_ last element of vector
00653       ROS_ASSERT( start_iter < end_iter );
00654 
00655 #ifdef DEBUG_EBAND_
00656       ROS_DEBUG("Refining Recursive - Bubbles do not overlapp, go one recursion deeper DONE");
00657 #endif
00658 
00659       //now we are done with this case
00660       return true;
00661     }
00662 
00663 
00664 #ifdef DEBUG_EBAND_
00665     ROS_DEBUG("Refining Recursive - Gap detected, fill recursive");
00666 #endif
00667 
00668     // last possible case -> bubbles do not overlap AND there are nor bubbles in between -> try to fill gap recursively
00669     if(!fillGap(band, start_iter, end_iter))
00670     {
00671       // band is broken in this intervall and could not be fixed (this should only be called on a leaf, so we put a log_out here;)
00672       ROS_DEBUG("Failed to fill gap between bubble %d and %d.", (int) distance(band.begin(), start_iter), (int) distance(band.begin(), end_iter) );
00673       return false;
00674     }
00675 
00676 #ifdef DEBUG_EBAND_
00677     ROS_DEBUG("Refining Recursive - Gap detected, fill recursive DONE");
00678 #endif
00679 
00680     // we could fill the gap (reached leaf of this branch)
00681     return true;
00682   }
00683 
00684 
00685   bool EBandPlanner::fillGap(std::vector<Bubble>& band, std::vector<Bubble>::iterator& start_iter,std::vector<Bubble>::iterator& end_iter)
00686   {
00687     // insert bubbles in the middle between not-overlapping bubbles (e.g. (Dist > Size Bub1) && (Dist > Size Bub2) )
00688     // repeat until gaps are closed
00689 
00690     // instantiate local variables
00691     double distance = 0.0;
00692     Bubble interpolated_bubble;
00693     geometry_msgs::PoseStamped interpolated_center;
00694     std::vector<Bubble>::iterator tmp_iter;
00695     int diff_int, start_num, end_num;
00696 
00697     // make sure this method was called for a valid element in the forces or bubbles vector
00698     ROS_ASSERT( start_iter >= band.begin() );
00699     ROS_ASSERT( end_iter < band.end() ); // "<" because .end() points _behind_ last element of vector
00700     ROS_ASSERT( start_iter < end_iter );
00701 
00702 
00703 #ifdef DEBUG_EBAND_
00704     ROS_DEBUG("Fill recursive - interpolate");
00705 #endif
00706 
00707     // interpolate between bubbles [depends kinematic]
00708     if(!interpolateBubbles(start_iter->center, end_iter->center, interpolated_center))
00709     {
00710       // interpolation failed (for whatever reason), so return with false
00711       start_num = std::distance(band.begin(), start_iter);
00712       end_num = std::distance(band.begin(), end_iter);
00713       ROS_DEBUG("Interpolation failed while trying to fill gap between bubble %d and %d.", start_num, end_num);
00714       return false;
00715     }
00716 
00717 
00718 #ifdef DEBUG_EBAND_
00719     ROS_DEBUG("Fill recursive - calc expansion of interpolated bubble");
00720 #endif
00721 
00722     // calc Size of Bubbles by calculating Dist to nearest Obstacle [depends kinematic, environment]
00723     if(!calcObstacleKinematicDistance(interpolated_center.pose, distance))
00724     {
00725       // pose probably outside map coordinates
00726       start_num = std::distance(band.begin(), start_iter);
00727       end_num = std::distance(band.begin(), end_iter);
00728       ROS_DEBUG("Calculation of Distance failed for interpolated bubble - failed to fill gap between bubble %d and %d.", start_num, end_num);
00729       return false;
00730     }
00731 
00732     if(distance <= tiny_bubble_expansion_)
00733     {
00734       // band broken! frame must not be immediately in collision -> otherwise calculation of gradient will later be invalid
00735       start_num = std::distance(band.begin(), start_iter);
00736       end_num = std::distance(band.begin(), end_iter);
00737       ROS_DEBUG("Interpolated Bubble in Collision - failed to fill gap between bubble %d and %d.", start_num, end_num);
00738       // TODO this means only that there is an obstacle on the direct interconnection between the bubbles - think about repair or rescue strategies -
00739       return false;
00740     }
00741 
00742 
00743 #ifdef DEBUG_EBAND_
00744     ROS_DEBUG("Fill recursive - inserting interpolated bubble at (%f, %f), with expansion %f", interpolated_center.pose.position.x, interpolated_center.pose.position.y, distance);
00745 #endif
00746 
00747     // insert bubble and assign center and expansion
00748     interpolated_bubble.center = interpolated_center;
00749     interpolated_bubble.expansion = distance;
00750     // insert bubble (vector.insert() inserts elements before given iterator) and get iterator pointing to it
00751     tmp_iter = band.insert(end_iter, interpolated_bubble);
00752     // insert is a little bit more tricky than erase, as it may require reallocation of the vector -> start and end iter could be invalid
00753     start_iter = tmp_iter - 1;
00754     end_iter = tmp_iter + 1;
00755 
00756     // check that iterators are still valid - just in case :)
00757     ROS_ASSERT( start_iter >= band.begin() );
00758     ROS_ASSERT( end_iter < band.end() ); // "<" because .end() points _behind_ last element of vector
00759     ROS_ASSERT( (start_iter < tmp_iter) && (tmp_iter < end_iter) );
00760 
00761 
00762 #ifdef DEBUG_EBAND_
00763     ROS_DEBUG("Fill recursive - check overlap interpolated bubble and first bubble");
00764 #endif
00765 
00766     // we have now two intervalls (left and right of inserted bubble) which need to be checked again and filled if neccessary
00767     if(!checkOverlap(*start_iter, *tmp_iter))
00768     {
00769 
00770 #ifdef DEBUG_EBAND
00771       ROS_DEBUG("Fill recursive - gap btw. interpolated and first bubble - fill recursive");
00772 #endif
00773 
00774       // gap in left intervall -> try to fill
00775       if(!fillGap(band, start_iter, tmp_iter))
00776       {
00777         // band is broken in this intervall and could not be fixed
00778         return false;
00779       }
00780       // bubbles were inserted -> make sure to keep end_iter iterator valid
00781       end_iter = tmp_iter + 1;
00782     }
00783 
00784     // check that iterators are still valid - just in case :)
00785     ROS_ASSERT( start_iter >= band.begin() );
00786     ROS_ASSERT( end_iter < band.end() ); // "<" because .end() points _behind_ last element of vector
00787     ROS_ASSERT( (start_iter < tmp_iter) && (tmp_iter < end_iter) );
00788 
00789 
00790 #ifdef DEBUG_EBAND_
00791     ROS_DEBUG("Fill recursive - check overlap interpolated bubble and second bubble");
00792 #endif
00793 
00794     if(!checkOverlap(*tmp_iter, *end_iter))
00795     {
00796 
00797 #ifdef DEBUG_EBAND_
00798       ROS_DEBUG("Fill recursive - gap btw. interpolated and second bubble - fill recursive");
00799 #endif
00800 
00801       // get distance between start_iter and tmp_iter before filling right intervall (in case of reallocation of vector)
00802       diff_int = (int) std::distance(start_iter, tmp_iter);
00803 
00804       // gap in left intervall -> try to fill
00805       if(!fillGap(band, tmp_iter, end_iter))
00806       {
00807         // band is broken in this intervall and could not be fixed
00808         return false;
00809       }
00810       // bubbles were inserted -> make sure to keep start_iter iterator valid
00811       start_iter = tmp_iter - diff_int;
00812     }
00813 
00814     // check that iterators are still valid - just in case :)
00815     ROS_ASSERT( start_iter >= band.begin() );
00816     ROS_ASSERT( end_iter < band.end() ); // "<" because .end() points _behind_ last element of vector
00817     ROS_ASSERT( (start_iter < tmp_iter) && (tmp_iter < end_iter) );
00818 
00819 
00820 #ifdef DEBUG_EBAND_
00821     ROS_DEBUG("Fill recursive - gap closed");
00822 #endif
00823 
00824     // bubbles overlap, iterators are kept valid -> done
00825     return true;
00826   }
00827 
00828 
00829   // optimization
00830 
00831   bool EBandPlanner::modifyBandArtificialForce(std::vector<Bubble>& band)
00832   {
00833     if(band.empty())
00834     {
00835       ROS_ERROR("Trying to modify an empty band.");
00836       return false;
00837     }
00838 
00839     if(band.size() <= 2)
00840     {
00841       // nothing to do here -> we can stop right away
00842       return true;
00843     }
00844 
00845     std::vector<geometry_msgs::WrenchStamped> internal_forces, external_forces, forces;
00846     geometry_msgs::WrenchStamped wrench;
00847 
00848 #ifdef DEBUG_EBAND_
00849     //publish original band
00850     if(visualization_)
00851       eband_visual_->publishBand("bubbles", band);
00852 #endif
00853 
00854     // init variables to calm down debug warnings
00855     wrench.header.stamp = ros::Time::now();
00856     wrench.header.frame_id = band[0].center.header.frame_id;
00857     wrench.wrench.force.x = 0.0;
00858     wrench.wrench.force.y = 0.0;
00859     wrench.wrench.force.z = 0.0;
00860     wrench.wrench.torque.x = 0.0;
00861     wrench.wrench.torque.y = 0.0;
00862     wrench.wrench.torque.z = 0.0;
00863     internal_forces.assign(band.size(), wrench);
00864     external_forces = internal_forces;
00865     forces = internal_forces;
00866 
00867     // TODO log timigs of planner
00868     // instantiate variables for timing
00869     //ros::Time time_stamp1, time_stamp2;
00870     //ros::Duration duration;
00871     //time_stamp1 = ros::Time::now();
00872 
00873     // due to refinement band might change its size -> use while loop
00874     int i = 1;
00875     bool forward = true; // cycle 1xforwards and 1xbackwards through band
00876     while( (i>0) && (i < ((int) band.size() - 1)) )
00877     {
00878       ROS_DEBUG("Modifying bubble %d.", i);
00879 
00880 
00881 #ifdef DEBUG_EBAND_
00882       ROS_DEBUG("Calculating internal force for bubble %d.", i);
00883 #endif
00884 
00885       if(!calcInternalForces(i, band, band.at(i), internal_forces.at(i)))
00886       {
00887         // calculation of internal forces failed - stopping optimization
00888         ROS_DEBUG("Calculation of internal forces failed");
00889         return false;
00890       }
00891 
00892 #ifdef DEBUG_EBAND_
00893       if(visualization_)
00894         // publish internal forces
00895         eband_visual_->publishForce("internal_forces", i, eband_visual_->blue, internal_forces[i], band[i]);
00896       // Log out debug info about next step
00897       ROS_DEBUG("Calculating external force for bubble %d.", i);
00898 #endif
00899 
00900 
00901       //if(!calcExternalForces(i, band, external_forces))
00902       if(!calcExternalForces(i, band.at(i), external_forces.at(i)))
00903       {
00904         // calculation of External Forces failed - stopping optimization
00905         ROS_DEBUG("Calculation of external forces failed");
00906         return false;
00907       }
00908 
00909 #ifdef DEBUG_EBAND_
00910       if(visualization_)
00911         //publish external forces
00912         eband_visual_->publishForce("external_forces", i, eband_visual_->red, external_forces[i], band[i]);
00913       // Log out debug info about next step
00914       ROS_DEBUG("Superposing internal and external forces");
00915 #endif
00916 
00917 
00918       // sum up external and internal forces over all bubbles
00919       forces.at(i).wrench.force.x = internal_forces.at(i).wrench.force.x + external_forces.at(i).wrench.force.x;
00920       forces.at(i).wrench.force.y = internal_forces.at(i).wrench.force.y + external_forces.at(i).wrench.force.y;
00921       forces.at(i).wrench.force.z = internal_forces.at(i).wrench.force.z + external_forces.at(i).wrench.force.z;
00922 
00923       forces.at(i).wrench.torque.x = internal_forces.at(i).wrench.torque.x + external_forces.at(i).wrench.torque.x;
00924       forces.at(i).wrench.torque.y = internal_forces.at(i).wrench.torque.y + external_forces.at(i).wrench.torque.y;
00925       forces.at(i).wrench.torque.z = internal_forces.at(i).wrench.torque.z + external_forces.at(i).wrench.torque.z;
00926 
00927 #ifdef DEBUG_EBAND_
00928       ROS_DEBUG("Superpose forces: (x, y, theta) = (%f, %f, %f)", forces.at(i).wrench.force.x, forces.at(i).wrench.force.y, forces.at(i).wrench.torque.z);
00929       ROS_DEBUG("Supressing tangential forces");
00930 #endif
00931 
00932       if(!suppressTangentialForces(i, band, forces.at(i)))
00933       {
00934         // suppression of tangential forces failed
00935         ROS_DEBUG("Supression of tangential forces failed");
00936         return false;
00937       }
00938 
00939 #ifdef DEBUG_EBAND_
00940       if(visualization_)
00941         //publish resulting forces
00942         eband_visual_->publishForce("resulting_forces", i, eband_visual_->green, forces[i], band[i]);
00943 #endif
00944 
00945 
00946       ROS_DEBUG("Applying forces to modify band");
00947       if(!applyForces(i, band, forces))
00948       {
00949         // band invalid
00950         ROS_DEBUG("Band is invalid - Stopping Modification");
00951         return false;
00952       }
00953 
00954 #ifdef DEBUG_EBAND_
00955       if(visualization_)
00956       {
00957         // publish band with changed bubble at resulting position
00958         eband_visual_->publishBand("bubbles", band);
00959         ros::Duration(0.01).sleep();
00960       }
00961 #endif
00962 
00963 
00964       //next bubble
00965       if(forward)
00966       {
00967         i++;
00968         if(i == ((int) band.size() - 1))
00969         {
00970           // reached end of band - start backwards cycle until at start again - then stop
00971           forward = false;
00972           i--;
00973           ROS_DEBUG("Optimization Elastic Band - Forward cycle done, starting backward cycle");
00974         }
00975       }
00976       else
00977       {
00978         i--;
00979       }
00980     }
00981 
00982     return true;
00983   }
00984 
00985 
00986   bool EBandPlanner::applyForces(int bubble_num, std::vector<Bubble>& band, std::vector<geometry_msgs::WrenchStamped> forces)
00987   {
00988     //cycle over all bubbles except first and last (these are fixed)
00989     if(band.size() <= 2)
00990     {
00991       // nothing to do here -> we can stop right away - no forces calculated
00992       return true;
00993     }
00994 
00995     geometry_msgs::Pose2D bubble_pose2D, new_bubble_pose2D;
00996     geometry_msgs::Pose bubble_pose, new_bubble_pose;
00997     geometry_msgs::Twist bubble_jump;
00998     Bubble new_bubble = band.at(bubble_num);
00999     double distance;
01000 
01001 
01002     // move bubble
01003     bubble_pose = band.at(bubble_num).center.pose;
01004     PoseToPose2D(bubble_pose, bubble_pose2D);
01005 
01006     // move according to bubble_new = bubble_old + alpha*force -> we choose alpha to be the current expansion of the modified bubble
01007     bubble_jump.linear.x = band.at(bubble_num).expansion*forces.at(bubble_num).wrench.force.x;
01008     bubble_jump.linear.y = band.at(bubble_num).expansion*forces.at(bubble_num).wrench.force.y;
01009     bubble_jump.linear.z = 0.0;
01010     bubble_jump.angular.x = 0.0;
01011     bubble_jump.angular.y = 0.0;
01012     bubble_jump.angular.z = band.at(bubble_num).expansion/getCircumscribedRadius(*costmap_ros_) * forces.at(bubble_num).wrench.torque.z;
01013     bubble_jump.angular.z = angles::normalize_angle(bubble_jump.angular.z);
01014 
01015     // apply changes to calc tmp bubble position
01016     new_bubble_pose2D.x = bubble_pose2D.x + bubble_jump.linear.x;
01017     new_bubble_pose2D.y = bubble_pose2D.y + bubble_jump.linear.y;
01018     new_bubble_pose2D.theta = bubble_pose2D.theta + bubble_jump.angular.z;
01019     new_bubble_pose2D.theta = angles::normalize_angle(new_bubble_pose2D.theta);
01020 
01021     // apply changes to local copy
01022     Pose2DToPose(new_bubble_pose, new_bubble_pose2D);
01023     new_bubble.center.pose = new_bubble_pose;
01024 
01025 #ifdef DEBUG_EBAND_
01026     ROS_DEBUG("Try moving bubble %d at (%f, %f, %f) by (%f, %f, %f).", bubble_num, bubble_pose2D.x, bubble_pose2D.y, bubble_pose2D.theta,
01027         bubble_jump.linear.x, bubble_jump.linear.y, bubble_jump.angular.z);
01028 #endif
01029 
01030 
01031     // check validity of moved bubble
01032 
01033     // recalc expansion of bubble -> calc Size of Bubbles by calculating Dist to nearest Obstacle [depends kinematic, environment]
01034     if(!calcObstacleKinematicDistance(new_bubble_pose, distance))
01035     {
01036       ROS_DEBUG("Calculation of Distance failed. Frame %d of %d Probably outside map. Discarding Changes", bubble_num, ((int) band.size()) );
01037 
01038 #ifdef DEBUG_EBAND_
01039       if(visualization_)
01040         eband_visual_->publishBubble("bubble_hypo", bubble_num, eband_visual_->red, new_bubble);
01041 #endif
01042 
01043       // this bubble must not be changed, but band is still valid -> continue with other bubbles
01044       return true;
01045     }
01046 
01047     if(distance <= tiny_bubble_expansion_)
01048     {
01049       // frame must not be immediately in collision -> otherwise calculation of gradient will later be invalid
01050       ROS_DEBUG("Calculation of Distance failed. Frame %d of %d in collision. Plan invalid. Discarding Changes", bubble_num, ((int) band.size()) );
01051 
01052 #ifdef DEBUG_EBAND_
01053       if(visualization_)
01054         eband_visual_->publishBubble("bubble_hypo", bubble_num, eband_visual_->red, new_bubble);
01055 #endif
01056 
01057       // this bubble must not be changed, but band is still valid -> continue with other bubbles
01058       return true;
01059     }
01060 
01061     // so far o.k. -> assign distance to new bubble
01062     new_bubble.expansion = distance;
01063 
01064 
01065     // check whether step was reasonable
01066 
01067     geometry_msgs::WrenchStamped new_bubble_force = forces.at(bubble_num);
01068 
01069     // check whether we get a valid force calculation here
01070     if(!getForcesAt(bubble_num, band, new_bubble, new_bubble_force))
01071     {
01072       // error during calculation of forces for the new position - discard changes
01073       ROS_DEBUG("Cannot calculate forces on bubble %d at new position - discarding changes", bubble_num);
01074       return true;
01075     }
01076 
01077 #ifdef DEBUG_EBAND_
01078     ROS_DEBUG("Check for zero-crossings in force on bubble %d", bubble_num);
01079 #endif
01080 
01081     // check for zero-crossings in the force-vector
01082     double checksum_zero, abs_new_force, abs_old_force;
01083 
01084     // project force-vectors onto each other
01085     checksum_zero = (new_bubble_force.wrench.force.x * forces.at(bubble_num).wrench.force.x) +
01086       (new_bubble_force.wrench.force.y * forces.at(bubble_num).wrench.force.y) +
01087       (new_bubble_force.wrench.torque.z * forces.at(bubble_num).wrench.torque.z);
01088 
01089     // if sign changes and ...
01090     if(checksum_zero < 0.0)
01091     {
01092       ROS_DEBUG("Detected zero-crossings in force on bubble %d. Checking total change in force.", bubble_num);
01093       // check the absolute values of the two vectors
01094       abs_new_force = sqrt( (new_bubble_force.wrench.force.x * new_bubble_force.wrench.force.x) +
01095           (new_bubble_force.wrench.force.y * new_bubble_force.wrench.force.y) +
01096           (new_bubble_force.wrench.torque.z * new_bubble_force.wrench.torque.z) );
01097       abs_old_force = sqrt( (forces.at(bubble_num).wrench.force.x * forces.at(bubble_num).wrench.force.x) +
01098           (forces.at(bubble_num).wrench.force.x * forces.at(bubble_num).wrench.force.x) +
01099           (forces.at(bubble_num).wrench.torque.z * forces.at(bubble_num).wrench.torque.z) );
01100 
01101       // force still has a significant high value (> ~75% of old force by default)
01102       if( (abs_new_force > equilibrium_relative_overshoot_ * abs_old_force) && (abs_new_force > significant_force_) )
01103       {
01104         ROS_DEBUG("Detected significante change in force (%f to %f) on bubble %d. Entering Recursive Approximation.", abs_old_force, abs_new_force, bubble_num);
01105         // o.k. now we really have to take a closer look -> start recursive approximation to equilibrium-point
01106         int curr_recursion_depth = 0;
01107         geometry_msgs::Twist new_step_width;
01108         Bubble curr_bubble = band.at(bubble_num);
01109         geometry_msgs::WrenchStamped curr_bubble_force = forces.at(bubble_num);
01110 
01111         // half step size
01112         new_step_width.linear.x = 0.5*bubble_jump.linear.x;
01113         new_step_width.linear.y = 0.5*bubble_jump.linear.y;
01114         new_step_width.linear.z = 0.5*bubble_jump.linear.z;
01115         new_step_width.angular.x = 0.5*bubble_jump.angular.x;
01116         new_step_width.angular.y = 0.5*bubble_jump.angular.y;
01117         new_step_width.angular.z = 0.5*bubble_jump.angular.z;
01118 
01119         // one step deeper into the recursion
01120         if(moveApproximateEquilibrium(bubble_num, band, curr_bubble, curr_bubble_force, new_step_width, curr_recursion_depth))
01121         {
01122           // done with recursion - change bubble and hand it back
01123           new_bubble = curr_bubble;
01124 
01125 #ifdef DEBUG_EBAND_
01126           geometry_msgs::Pose2D curr_bubble_pose2D;
01127           PoseToPose2D(curr_bubble.center.pose, curr_bubble_pose2D);
01128           ROS_DEBUG("Instead - Try moving bubble %d at (%f, %f, %f) by (%f, %f, %f) to (%f, %f, %f).",
01129               bubble_num, bubble_pose2D.x, bubble_pose2D.y, bubble_pose2D.theta,
01130               new_step_width.linear.x, new_step_width.linear.y, new_step_width.angular.z,
01131               curr_bubble_pose2D.x, curr_bubble_pose2D.y, curr_bubble_pose2D.theta);
01132 #endif
01133         }
01134       }
01135     }
01136 
01137 
01138     // check validity of resulting band (given the moved bubble)
01139 
01140     // TODO use this routine not only to check whether gap can be filled but also to fill gap (if possible)
01141     // get local copy of band, set new position of moved bubble and init iterators
01142     std::vector<Bubble> tmp_band = band;
01143     std::vector<Bubble>::iterator start_iter, end_iter;
01144     tmp_band.at(bubble_num) = new_bubble;
01145     start_iter = tmp_band.begin();
01146 
01147     // check left connection (bubble and bubble-1)
01148     start_iter = start_iter + bubble_num - 1;
01149     end_iter = start_iter + 1;
01150 
01151     // check Overlap - if bubbles do not overlap try to fill gap
01152     if(!checkOverlap(*start_iter, *end_iter))
01153     {
01154       if(!fillGap(tmp_band, start_iter, end_iter))
01155       {
01156         ROS_DEBUG("Bubble at new position cannot be connected to neighbour. Discarding changes.");
01157         // this bubble must not be changed, but band is still valid -> continue with other bubbles
01158         return true;
01159       }
01160     }
01161 
01162 
01163     // get fresh copy of band, set new position of bubble again and reinit iterators
01164     tmp_band = band;
01165     tmp_band.at(bubble_num) = new_bubble;
01166     start_iter = tmp_band.begin();
01167 
01168     // check right connection (bubble and bubble +1)
01169     start_iter = start_iter + bubble_num;
01170     end_iter = start_iter + 1;
01171 
01172     // check Overlap - if bubbles do not overlap try to fill gap
01173     if(!checkOverlap(*start_iter, *end_iter))
01174     {
01175       if(!fillGap(tmp_band, start_iter, end_iter))
01176       {
01177         ROS_DEBUG("Bubble at new position cannot be connected to neighbour. Discarding changes.");
01178         // this bubble must not be changed, but band is still valid -> continue with other bubbles
01179         return true;
01180       }
01181     }
01182 
01183 
01184     // check successful - bubble and band valid apply changes
01185 
01186 #ifdef DEBUG_EBAND_
01187     ROS_DEBUG("Frame %d of %d: Check successful - bubble and band valid. Applying Changes", bubble_num, ((int) band.size()) );
01188 #endif
01189 
01190     band.at(bubble_num) = new_bubble;
01191 
01192     return true;
01193   }
01194 
01195 
01196   bool EBandPlanner::moveApproximateEquilibrium(const int& bubble_num, const std::vector<Bubble>& band, Bubble& curr_bubble,
01197       const geometry_msgs::WrenchStamped& curr_bubble_force, geometry_msgs::Twist& curr_step_width, const int& curr_recursion_depth)
01198   {
01199 
01200     double distance;
01201     Bubble new_bubble = curr_bubble;
01202     geometry_msgs::Pose2D new_bubble_pose2D, curr_bubble_pose2D;
01203     geometry_msgs::WrenchStamped new_bubble_force = curr_bubble_force;
01204 
01205     // move bubble
01206     PoseToPose2D(curr_bubble.center.pose, curr_bubble_pose2D);
01207     PoseToPose2D(new_bubble.center.pose, new_bubble_pose2D);
01208 
01209     // apply changes to calculate tmp bubble position
01210     new_bubble_pose2D.x = curr_bubble_pose2D.x + curr_step_width.linear.x;
01211     new_bubble_pose2D.y = curr_bubble_pose2D.y + curr_step_width.linear.y;
01212     new_bubble_pose2D.theta = curr_bubble_pose2D.theta + curr_step_width.angular.z;
01213     new_bubble_pose2D.theta = angles::normalize_angle(new_bubble_pose2D.theta);
01214 
01215     // apply changes to local copy
01216     Pose2DToPose(new_bubble.center.pose, new_bubble_pose2D);
01217 
01218 
01219     // check validity of moved bubble
01220 
01221     // recalc expansion of bubble -> calc Size of Bubbles by calculating Dist to nearest Obstacle [depends kinematic, environment]
01222     if(!calcObstacleKinematicDistance(new_bubble.center.pose, distance))
01223       return false;
01224 
01225     // we wont be able to calculate forces later on
01226     if(distance == 0.0)
01227       return false;
01228 
01229 
01230     // so far o.k. -> assign distance to new bubble
01231     new_bubble.expansion = distance;
01232 
01233     // check whether we get a valid force calculation here
01234     if(!getForcesAt(bubble_num, band, new_bubble, new_bubble_force))
01235       return false;
01236 
01237     // great - lets store this - this is better then what we had so far
01238     curr_bubble = new_bubble;
01239 
01240     // if everything is fine and we reached our maximum recursion depth
01241     if(curr_recursion_depth >= max_recursion_depth_approx_equi_)
01242       // break recursion at this point
01243       return true;
01244 
01245 
01246     // now - let's check for zero-crossing
01247 
01248 #ifdef DEBUG_EBAND_
01249     ROS_DEBUG("Check for zero-crossings in force on bubble %d - Recursion %d", bubble_num, curr_recursion_depth);
01250 #endif
01251 
01252     double checksum_zero, abs_new_force, abs_old_force;
01253     int new_recursion_depth;
01254     geometry_msgs::Twist new_step_width;
01255 
01256     // check zero-crossing by projecting force-vectors onto each other
01257     checksum_zero = (new_bubble_force.wrench.force.x * curr_bubble_force.wrench.force.x) +
01258       (new_bubble_force.wrench.force.y * curr_bubble_force.wrench.force.y) +
01259       (new_bubble_force.wrench.torque.z * curr_bubble_force.wrench.torque.z);
01260 
01261     if(checksum_zero < 0.0)
01262     {
01263 #ifdef DEBUG_EBAND_
01264       ROS_DEBUG("Detected zero-crossings in force on bubble %d - Recursion %d. Checking total change in force.", bubble_num, curr_recursion_depth);
01265 #endif
01266 
01267       // check the absolute values of the two vectors
01268       abs_new_force = sqrt( (new_bubble_force.wrench.force.x * new_bubble_force.wrench.force.x) +
01269           (new_bubble_force.wrench.force.y * new_bubble_force.wrench.force.y) +
01270           (new_bubble_force.wrench.torque.z * new_bubble_force.wrench.torque.z) );
01271       abs_old_force = sqrt( (curr_bubble_force.wrench.force.x * curr_bubble_force.wrench.force.x) +
01272           (curr_bubble_force.wrench.force.x * curr_bubble_force.wrench.force.x) +
01273           (curr_bubble_force.wrench.torque.z * curr_bubble_force.wrench.torque.z) );
01274 
01275       if( (abs_new_force > equilibrium_relative_overshoot_ * abs_old_force) && (abs_new_force > significant_force_) )
01276       {
01277 #ifdef DEBUG_EBAND_
01278         ROS_DEBUG("Detected significant change in force (%f to %f) on bubble %d - Recursion %d. Going one Recursion deeper.", abs_old_force, abs_new_force, bubble_num, curr_recursion_depth);
01279 #endif
01280 
01281         // o.k. now we really have to take a closer look -> start recursive approximation to equilibrium-point
01282         new_recursion_depth = curr_recursion_depth + 1;
01283         // half step size - backward direction
01284         new_step_width.linear.x = -0.5*curr_step_width.linear.x;
01285         new_step_width.linear.y = -0.5*curr_step_width.linear.y;
01286         new_step_width.linear.z = -0.5*curr_step_width.linear.z;
01287         new_step_width.angular.x = -0.5*curr_step_width.angular.x;
01288         new_step_width.angular.y = -0.5*curr_step_width.angular.y;
01289         new_step_width.angular.z = -0.5*curr_step_width.angular.z;
01290 
01291         // one step deeper into the recursion
01292         if(moveApproximateEquilibrium(bubble_num, band, new_bubble, new_bubble_force, new_step_width, new_recursion_depth))
01293           // done with recursion - change bubble and hand it back
01294           curr_bubble = new_bubble;
01295 
01296         // otherwise - could not get a better value - return without change (curr_bubble as asigned above)
01297       }
01298 
01299       // otherwise - this is good enough for us - return with this value (curr_bubble as asigned above)
01300     }
01301     else
01302     {
01303 #ifdef DEBUG_EBAND_
01304       ROS_DEBUG("No zero-crossings in force on bubble %d - Recursion %d. Continue walk in same direction. Going one recursion deeper.", bubble_num, curr_recursion_depth);
01305 #endif
01306 
01307       // continue walk in same direction
01308       new_recursion_depth = curr_recursion_depth + 1;
01309       // half step size - backward direction
01310       new_step_width.linear.x = 0.5*curr_step_width.linear.x;
01311       new_step_width.linear.y = 0.5*curr_step_width.linear.y;
01312       new_step_width.linear.z = 0.5*curr_step_width.linear.z;
01313       new_step_width.angular.x = 0.5*curr_step_width.angular.x;
01314       new_step_width.angular.y = 0.5*curr_step_width.angular.y;
01315       new_step_width.angular.z = 0.5*curr_step_width.angular.z;
01316 
01317       // one step deeper into the recursion
01318       if(moveApproximateEquilibrium(bubble_num, band, new_bubble, new_bubble_force, new_step_width, new_recursion_depth))
01319         // done with recursion - change bubble and hand it back
01320         curr_bubble = new_bubble;
01321 
01322       // otherwise - could not get a better value - return without change (curr_bubble as asigned above)
01323     }
01324 
01325     // done
01326     return true;
01327   }
01328 
01329 
01330   bool EBandPlanner::getForcesAt(int bubble_num, std::vector<Bubble> band, Bubble curr_bubble, geometry_msgs::WrenchStamped& forces)
01331   {
01332     geometry_msgs::WrenchStamped internal_force, external_force;
01333 
01334     if(!calcInternalForces(bubble_num, band, curr_bubble, internal_force))
01335     {
01336       // calculation of internal forces failed - stopping optimization
01337       ROS_DEBUG("Calculation of internal forces failed");
01338       return false;
01339     }
01340 
01341     if(!calcExternalForces(bubble_num, curr_bubble, external_force))
01342     {
01343       // calculation of External Forces failed - stopping optimization
01344       ROS_DEBUG("Calculation of external forces failed");
01345       return false;
01346     }
01347 
01348     // sum up external and internal forces over all bubbles
01349     forces.wrench.force.x = internal_force.wrench.force.x + external_force.wrench.force.x;
01350     forces.wrench.force.y = internal_force.wrench.force.y + external_force.wrench.force.y;
01351     forces.wrench.force.z = internal_force.wrench.force.z + external_force.wrench.force.z;
01352 
01353     forces.wrench.torque.x = internal_force.wrench.torque.x + external_force.wrench.torque.x;
01354     forces.wrench.torque.y = internal_force.wrench.torque.y + external_force.wrench.torque.y;
01355     forces.wrench.torque.z = internal_force.wrench.torque.z + external_force.wrench.torque.z;
01356 
01357     if(!suppressTangentialForces(bubble_num, band, forces))
01358     {
01359       // suppression of tangential forces failed
01360       ROS_DEBUG("Supression of tangential forces failed");
01361       return false;
01362     }
01363 
01364     return true;
01365   }
01366 
01367 
01368   bool EBandPlanner::calcInternalForces(int bubble_num, std::vector<Bubble> band, Bubble curr_bubble, geometry_msgs::WrenchStamped& forces)
01369   {
01370     // check if plugin initialized
01371     if(!initialized_)
01372     {
01373       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
01374       return false;
01375     }
01376 
01377     //cycle over all bubbles except first and last (these are fixed)
01378     if(band.size() <= 2)
01379     {
01380       // nothing to do here -> we can stop right away - no forces calculated
01381       return true;
01382     }
01383 
01384     // init tmp variables
01385     double distance1, distance2;
01386     geometry_msgs::Twist difference1, difference2;
01387     geometry_msgs::Wrench wrench;
01388 
01389     // make sure this method was called for a valid element in the forces or bubbles vector
01390     ROS_ASSERT( bubble_num > 0 );
01391     ROS_ASSERT( bubble_num < ((int) band.size() - 1) );
01392 
01393 
01394     // get distance between bubbles
01395     if(!calcBubbleDistance(curr_bubble.center.pose, band[bubble_num-1].center.pose, distance1))
01396     {
01397       ROS_ERROR("Failed to calculate Distance between two bubbles. Aborting calculation of internal forces!");
01398       return false;
01399     }
01400 
01401     if(!calcBubbleDistance(curr_bubble.center.pose, band[bubble_num+1].center.pose, distance2))
01402     {
01403       ROS_ERROR("Failed to calculate Distance between two bubbles. Aborting calculation of internal forces!");
01404       return false;
01405     }
01406 
01407     // get (elementwise) difference bewtween bubbles
01408     if(!calcBubbleDifference(curr_bubble.center.pose, band[bubble_num-1].center.pose, difference1))
01409     {
01410       ROS_ERROR("Failed to calculate Difference between two bubbles. Aborting calculation of internal forces!");
01411       return false;
01412     }
01413 
01414     if(!calcBubbleDifference(curr_bubble.center.pose, band[bubble_num+1].center.pose, difference2))
01415     {
01416       ROS_ERROR("Failed to calculate Difference between two bubbles. Aborting calculation of internal forces!");
01417       return false;
01418     }
01419 
01420     // make sure to avoid division by  (almost) zero during force calculation (avoid numerical problems)
01421     // -> if difference/distance is (close to) zero then the force in this direction should be zero as well
01422     if(distance1 <= tiny_bubble_distance_)
01423       distance1 = 1000000.0;
01424     if(distance2 <= tiny_bubble_distance_)
01425       distance2 = 1000000.0;
01426 
01427     // now calculate wrench - forces model an elastic band and are normed (distance) to render forces for small and large bubbles the same
01428     wrench.force.x = internal_force_gain_*(difference1.linear.x/distance1 + difference2.linear.x/distance2);
01429     wrench.force.y = internal_force_gain_*(difference1.linear.y/distance1 + difference2.linear.y/distance2);
01430     wrench.force.z = internal_force_gain_*(difference1.linear.z/distance1 + difference2.linear.z/distance2);
01431     wrench.torque.x = internal_force_gain_*(difference1.angular.x/distance1 + difference2.angular.x/distance2);
01432     wrench.torque.y = internal_force_gain_*(difference1.angular.y/distance1 + difference2.angular.y/distance2);
01433     wrench.torque.z = internal_force_gain_*(difference1.angular.z/distance1 + difference2.angular.z/distance2);
01434 
01435 #ifdef DEBUG_EBAND_
01436     ROS_DEBUG("Calculating internal forces: (x, y, theta) = (%f, %f, %f)", wrench.force.x, wrench.force.y, wrench.torque.z);
01437 #endif
01438 
01439     // store wrench in vector
01440     forces.wrench = wrench;
01441 
01442     return true;
01443   }
01444 
01445 
01446   bool EBandPlanner::calcExternalForces(int bubble_num, Bubble curr_bubble, geometry_msgs::WrenchStamped& forces)
01447   {
01448     // check if plugin initialized
01449     if(!initialized_)
01450     {
01451       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
01452       return false;
01453     }
01454 
01455     // init tmp variables
01456     double distance1, distance2;
01457     geometry_msgs::Pose edge;
01458     geometry_msgs::Pose2D edge_pose2D;
01459     geometry_msgs::Wrench wrench;
01460 
01461 
01462     // calculate delta-poses (on upper edge of bubble) for x-direction
01463     edge = curr_bubble.center.pose;
01464     edge.position.x = edge.position.x + curr_bubble.expansion;
01465     // get expansion on bubble at this point
01466     if(!calcObstacleKinematicDistance(edge, distance1))
01467     {
01468       ROS_DEBUG("Bubble %d probably at edge of map - cannot retrieve distance information to calculate external forces", bubble_num);
01469       // we cannot calculate external forces for this bubble - but still continue for the other bubbles
01470       return true;
01471     }
01472     // calculate delta-poses (on lower edge of bubble) for x-direction
01473     edge.position.x = edge.position.x - 2.0*curr_bubble.expansion;
01474     // get expansion on bubble at this point
01475     if(!calcObstacleKinematicDistance(edge, distance2))
01476     {
01477       ROS_DEBUG("Bubble %d probably at edge of map - cannot retrieve distance information to calculate external forces", bubble_num);
01478       // we cannot calculate external forces for this bubble - but still continue for the other bubbles
01479       return true;
01480     }
01481 
01482     // calculate difference-quotient (approx. of derivative) in x-direction
01483     if(curr_bubble.expansion <= tiny_bubble_expansion_)
01484     {
01485       // avoid division by (almost) zero to avoid numerical problems
01486       wrench.force.x = -external_force_gain_*(distance2 - distance1)/(2.0*tiny_bubble_expansion_);
01487       // actually we should never end up here - band should have been considered as broken
01488       ROS_DEBUG("Calculating external forces on broken band. Bubble should have been removed. Local Planner probably ill configured");
01489     }
01490     else
01491       wrench.force.x = -external_force_gain_*(distance2 - distance1)/(2.0*curr_bubble.expansion);
01492     // TODO above equations skip term to make forces continuous at end of influence region - test to add corresponding term
01493 
01494 
01495     // calculate delta-poses (on upper edge of bubble) for y-direction
01496     edge = curr_bubble.center.pose;
01497     edge.position.y = edge.position.y + curr_bubble.expansion;
01498     // get expansion on bubble at this point
01499     if(!calcObstacleKinematicDistance(edge, distance1))
01500     {
01501       ROS_DEBUG("Bubble %d probably at edge of map - cannot retrieve distance information to calculate external forces", bubble_num);
01502       // we cannot calculate external forces for this bubble - but still continue for the other bubbles
01503       return true;
01504     }
01505     // calculate delta-poses (on lower edge of bubble) for x-direction
01506     edge.position.y = edge.position.y - 2.0*curr_bubble.expansion;
01507     // get expansion on bubble at this point
01508     if(!calcObstacleKinematicDistance(edge, distance2))
01509     {
01510       ROS_DEBUG("Bubble %d probably at edge of map - cannot retrieve distance information to calculate external forces", bubble_num);
01511       // we cannot calculate external forces for this bubble - but still continue for the other bubbles
01512       return true;
01513     }
01514 
01515     // calculate difference-quotient (approx. of derivative) in x-direction
01516     if(curr_bubble.expansion <= tiny_bubble_expansion_)
01517     {
01518       // avoid division by (almost) zero to avoid numerical problems
01519       wrench.force.y = -external_force_gain_*(distance2 - distance1)/(2.0*tiny_bubble_expansion_);
01520       // actually we should never end up here - band should have been considered as broken
01521       ROS_DEBUG("Calculating external forces on broken band. Bubble should have been removed. Local Planner probably ill configured");
01522     }
01523     else
01524       wrench.force.y = -external_force_gain_*(distance2 - distance1)/(2.0*curr_bubble.expansion);
01525     // TODO above equations skip term to make forces continuous at end of influence region - test to add corresponsing term
01526 
01527 
01528     // no force in z-direction
01529     wrench.force.z = 0.0;
01530 
01531 
01532     // no torque around x and y axis
01533     wrench.torque.x = 0.0;
01534     wrench.torque.y = 0.0;
01535 
01536 
01537     // calculate delta-poses (on upper edge of bubble) for x-direction
01538     PoseToPose2D(curr_bubble.center.pose, edge_pose2D);
01539     edge_pose2D.theta = edge_pose2D.theta + (curr_bubble.expansion/getCircumscribedRadius(*costmap_ros_));
01540     edge_pose2D.theta = angles::normalize_angle(edge_pose2D.theta);
01541     PoseToPose2D(edge, edge_pose2D);
01542     // get expansion on bubble at this point
01543     if(!calcObstacleKinematicDistance(edge, distance1))
01544     {
01545       ROS_DEBUG("Bubble %d probably at edge of map - cannot retrieve distance information to calculate external forces", bubble_num);
01546       // we cannot calculate external forces for this bubble - but still continue for the other bubbles
01547       return true;
01548     }
01549     // calculate delta-poses (on lower edge of bubble) for x-direction
01550     edge_pose2D.theta = edge_pose2D.theta - 2.0*(curr_bubble.expansion/getCircumscribedRadius(*costmap_ros_));
01551     edge_pose2D.theta = angles::normalize_angle(edge_pose2D.theta);
01552     PoseToPose2D(edge, edge_pose2D);
01553     // get expansion on bubble at this point
01554     if(!calcObstacleKinematicDistance(edge, distance2))
01555     {
01556       ROS_DEBUG("Bubble %d probably at edge of map - cannot retrieve distance information to calculate external forces", bubble_num);
01557       // we cannot calculate external forces for this bubble - but still continue for the other bubbles
01558       return true;
01559     }
01560 
01561     // calculate difference-quotient (approx. of derivative) in x-direction
01562     if(curr_bubble.expansion <= tiny_bubble_expansion_)
01563     {
01564       // avoid division by (almost) zero to avoid numerical problems
01565       wrench.torque.z = -external_force_gain_*(distance2 - distance1)/(2.0*tiny_bubble_expansion_);
01566       // actually we should never end up here - band should have been considered as broken
01567       ROS_DEBUG("Calculating external forces on broken band. Bubble should have been removed. Local Planner probably ill configured");
01568     }
01569     else
01570       wrench.torque.z = -external_force_gain_*(distance2 - distance1)/(2.0*curr_bubble.expansion);
01571     // TODO above equations skip term to make forces continuous at end of influence region - test to add corresponsing term
01572 
01573 
01574 #ifdef DEBUG_EBAND_
01575     ROS_DEBUG("Calculating external forces: (x, y, theta) = (%f, %f, %f)", wrench.force.x, wrench.force.y, wrench.torque.z);
01576 #endif
01577 
01578     // assign wrench to forces vector
01579     forces.wrench = wrench;
01580 
01581     return true;
01582   }
01583 
01584 
01585   bool EBandPlanner::suppressTangentialForces(int bubble_num, std::vector<Bubble> band, geometry_msgs::WrenchStamped& forces)
01586   {
01587     //cycle over all bubbles except first and last (these are fixed)
01588     if(band.size() <= 2)
01589     {
01590       // nothing to do here -> we can stop right away - no forces calculated
01591       return true;
01592     }
01593 
01594     double scalar_fd, scalar_dd;
01595     geometry_msgs::Twist difference;
01596 
01597     // make sure this method was called for a valid element in the forces or bubbles vector
01598     ROS_ASSERT( bubble_num > 0 );
01599     ROS_ASSERT( bubble_num < ((int) band.size() - 1) );
01600 
01601 
01602     // get pose-difference from following to preceding bubble -> "direction of the band in this bubble"
01603     if(!calcBubbleDifference(band[bubble_num+1].center.pose, band[bubble_num-1].center.pose, difference))
01604       return false;
01605 
01606     // "project wrench" in middle bubble onto connecting vector
01607     // scalar wrench*difference
01608     scalar_fd = forces.wrench.force.x*difference.linear.x + forces.wrench.force.y*difference.linear.y +
01609       forces.wrench.force.z*difference.linear.z + forces.wrench.torque.x*difference.angular.x +
01610       forces.wrench.torque.y*difference.angular.y + forces.wrench.torque.z*difference.angular.z;
01611 
01612     // abs of difference-vector: scalar difference*difference
01613     scalar_dd = difference.linear.x*difference.linear.x + difference.linear.y*difference.linear.y + difference.linear.z*difference.linear.z +
01614       difference.angular.x*difference.angular.x + difference.angular.y*difference.angular.y + difference.angular.z*difference.angular.z;
01615 
01616     // avoid division by (almost) zero -> check if bubbles have (almost) same center-pose
01617     if(scalar_dd <= tiny_bubble_distance_)
01618     {
01619       // there are redundant bubbles, this should normally not hapen -> probably error in band refinement
01620       ROS_DEBUG("Calculating tangential forces for redundant bubbles. Bubble should have been removed. Local Planner probably ill configured");
01621     }
01622 
01623     // calculate orthogonal components
01624     forces.wrench.force.x = forces.wrench.force.x - scalar_fd/scalar_dd * difference.linear.x;
01625     forces.wrench.force.y = forces.wrench.force.y - scalar_fd/scalar_dd * difference.linear.y;
01626     forces.wrench.force.z = forces.wrench.force.z - scalar_fd/scalar_dd * difference.linear.z;
01627     forces.wrench.torque.x = forces.wrench.torque.x - scalar_fd/scalar_dd * difference.angular.x;
01628     forces.wrench.torque.y = forces.wrench.torque.y - scalar_fd/scalar_dd * difference.angular.y;
01629     forces.wrench.torque.z = forces.wrench.torque.z - scalar_fd/scalar_dd * difference.angular.z;
01630 
01631 #ifdef DEBUG_EBAND_
01632     ROS_DEBUG("Supressing tangential forces: (x, y, theta) = (%f, %f, %f)",
01633         forces.wrench.force.x, forces.wrench.force.y, forces.wrench.torque.z);
01634 #endif
01635 
01636     return true;
01637   }
01638 
01639 
01640   // problem (geometry) dependant functions
01641 
01642   bool EBandPlanner::interpolateBubbles(geometry_msgs::PoseStamped start_center, geometry_msgs::PoseStamped end_center, geometry_msgs::PoseStamped& interpolated_center)
01643   {
01644     // check if plugin initialized
01645     if(!initialized_)
01646     {
01647       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
01648       return false;
01649     }
01650 
01651     // instantiate local variables
01652     geometry_msgs::Pose2D start_pose2D, end_pose2D, interpolated_pose2D;
01653     double delta_theta;
01654 
01655     // copy header
01656     interpolated_center.header = start_center.header;
01657 
01658     // interpolate angles
01659     // TODO make this in a better way
01660     // - for instance use "slerp" to interpolate directly between quaternions
01661     // - or work with pose2D right from the beginnning
01662     // convert quaternions to euler angles - at this point this no longer works in 3D !!
01663     PoseToPose2D(start_center.pose, start_pose2D);
01664     PoseToPose2D(end_center.pose, end_pose2D);
01665     // calc mean of theta angle
01666     delta_theta = end_pose2D.theta - start_pose2D.theta;
01667     delta_theta = angles::normalize_angle(delta_theta) / 2.0;
01668     interpolated_pose2D.theta = start_pose2D.theta + delta_theta;
01669     interpolated_pose2D.theta = angles::normalize_angle(interpolated_pose2D.theta);
01670     // convert back to quaternion
01671     interpolated_pose2D.x = 0.0;
01672     interpolated_pose2D.y = 0.0;
01673     Pose2DToPose(interpolated_center.pose, interpolated_pose2D);
01674 
01675     // interpolate positions
01676     interpolated_center.pose.position.x = (end_center.pose.position.x + start_center.pose.position.x)/2.0;
01677     interpolated_center.pose.position.y = (end_center.pose.position.y + start_center.pose.position.y)/2.0;
01678     interpolated_center.pose.position.z = (end_center.pose.position.z + start_center.pose.position.z)/2.0;
01679 
01680     // TODO ideally this would take into account kinematics of the robot and for instance use splines
01681 
01682     return true;
01683   }
01684 
01685 
01686   bool EBandPlanner::checkOverlap(Bubble bubble1, Bubble bubble2)
01687   {
01688     // check if plugin initialized
01689     if(!initialized_)
01690     {
01691       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
01692       return false;
01693     }
01694 
01695     // calc (kinematic) Distance between bubbles
01696     double distance = 0.0;
01697     if(!calcBubbleDistance(bubble1.center.pose, bubble2.center.pose, distance))
01698     {
01699       ROS_ERROR("failed to calculate Distance between two bubbles. Aborting check for overlap!");
01700       return false;
01701     }
01702 
01703     // compare with size of the two bubbles
01704     if(distance >= min_bubble_overlap_ * (bubble1.expansion + bubble2.expansion))
01705       return false;
01706 
01707     // TODO this does not account for kinematic properties -> improve
01708 
01709     // everything fine - bubbles overlap
01710     return true;
01711   }
01712 
01713 
01714   bool EBandPlanner::calcBubbleDistance(geometry_msgs::Pose start_center_pose, geometry_msgs::Pose end_center_pose, double& distance)
01715   {
01716     // check if plugin initialized
01717     if(!initialized_)
01718     {
01719       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
01720       return false;
01721     }
01722 
01723     geometry_msgs::Pose2D start_pose2D, end_pose2D, diff_pose2D;
01724 
01725     // TODO make this in a better way
01726     // - or work with pose2D right from the beginnning
01727     // convert quaternions to euler angles - at this point this no longer works in 3D !!
01728     PoseToPose2D(start_center_pose, start_pose2D);
01729     PoseToPose2D(end_center_pose, end_pose2D);
01730 
01731     // get rotational difference
01732     diff_pose2D.theta = end_pose2D.theta - start_pose2D.theta;
01733     diff_pose2D.theta = angles::normalize_angle(diff_pose2D.theta);
01734     // get translational difference
01735     diff_pose2D.x = end_pose2D.x - start_pose2D.x;
01736     diff_pose2D.y = end_pose2D.y - start_pose2D.y;
01737 
01738     // calc distance
01739     double angle_to_pseudo_vel = diff_pose2D.theta * getCircumscribedRadius(*costmap_ros_);
01740     //distance = sqrt( (diff_pose2D.x * diff_pose2D.x) + (diff_pose2D.y * diff_pose2D.y) + (angle_to_pseudo_vel * angle_to_pseudo_vel) );
01741     distance = sqrt( (diff_pose2D.x * diff_pose2D.x) + (diff_pose2D.y * diff_pose2D.y));
01742 
01743     // TODO take into account kinematic properties of body
01744 
01745     return true;
01746   }
01747 
01748 
01749   bool EBandPlanner::calcBubbleDifference(geometry_msgs::Pose start_center_pose, geometry_msgs::Pose end_center_pose, geometry_msgs::Twist& difference)
01750   {
01751     // check if plugin initialized
01752     if(!initialized_)
01753     {
01754       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
01755       return false;
01756     }
01757 
01758     geometry_msgs::Pose2D start_pose2D, end_pose2D, diff_pose2D;
01759 
01760     // TODO make this in a better way
01761     // - or work with pose2D right from the beginnning
01762     // convert quaternions to euler angles - at this point this no longer works in 3D !!
01763     PoseToPose2D(start_center_pose, start_pose2D);
01764     PoseToPose2D(end_center_pose, end_pose2D);
01765 
01766     // get rotational difference
01767     diff_pose2D.theta = end_pose2D.theta - start_pose2D.theta;
01768     diff_pose2D.theta = angles::normalize_angle(diff_pose2D.theta);
01769     // get translational difference
01770     diff_pose2D.x = end_pose2D.x - start_pose2D.x;
01771     diff_pose2D.y = end_pose2D.y - start_pose2D.y;
01772 
01773     difference.linear.x = diff_pose2D.x;
01774     difference.linear.y = diff_pose2D.y;
01775     difference.linear.z = 0.0;
01776     // multiply by inscribed radius to math calculation of distance
01777     difference.angular.x = 0.0;
01778     difference.angular.y = 0.0;
01779     difference.angular.z = diff_pose2D.theta*getCircumscribedRadius(*costmap_ros_);
01780 
01781     // TODO take into account kinematic properties of body
01782 
01783     return true;
01784   }
01785 
01786 
01787   bool EBandPlanner::calcObstacleKinematicDistance(geometry_msgs::Pose center_pose, double& distance)
01788   {
01789     // calculate distance to nearest obstacle [depends kinematic, shape, environment]
01790 
01791     // check if plugin initialized
01792     if(!initialized_)
01793     {
01794       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
01795       return false;
01796     }
01797 
01798     unsigned int cell_x, cell_y;
01799     unsigned char disc_cost;
01800     double weight = costmap_weight_;
01801 
01802     // read distance to nearest obstacle directly from costmap
01803     // (does not take into account shape and kinematic properties)
01804     // get cell for coordinates of bubble center
01805     if(!costmap_->worldToMap(center_pose.position.x, center_pose.position.y, cell_x, cell_y)) {
01806       // probably at the edge of the costmap - this value should be recovered soon
01807       disc_cost = 1;
01808     } else {
01809       // get cost for this cell
01810       disc_cost = costmap_->getCost(cell_x, cell_y);
01811     }
01812 
01813     // calculate distance to nearest obstacel from this cost (see costmap_2d in wiki for details)
01814 
01815     // For reference: here comes an excerpt of the cost calculation within the costmap function
01816     /*if(distance == 0)
01817       cost = LETHAL_OBSTACLE;
01818       else if(distance <= cell_inscribed_radius_)
01819       cost = INSCRIBED_INFLATED_OBSTACLE;
01820       else {
01821     //make sure cost falls off by Euclidean distance
01822     double euclidean_distance = distance * resolution_;
01823     double factor = exp(-1.0 * weight_ * (euclidean_distance - inscribed_radius_));
01824     cost = (unsigned char) ((INSCRIBED_INFLATED_OBSTACLE - 1) * factor);
01825     }*/
01826 
01827     if (disc_cost == costmap_2d::LETHAL_OBSTACLE) {
01828       // pose is inside an obstacle - very bad
01829       distance = 0.0;
01830     }   else if (disc_cost == costmap_2d::INSCRIBED_INFLATED_OBSTACLE) {
01831       // footprint is definitely inside an obstacle - still bad
01832       distance = 0.0;
01833     } else {
01834       if (disc_cost == 0) { // freespace, no estimate of distance
01835         disc_cost = 1; // lowest non freespace cost
01836       } else if (disc_cost == 255) { // unknown space, we should never be here
01837         disc_cost = 1;
01838       }
01839       double factor = ((double) disc_cost) / (costmap_2d::INSCRIBED_INFLATED_OBSTACLE - 1);
01840       distance = -log(factor) / weight;
01841     }
01842 
01843     return true;
01844   }
01845 
01846 
01847   // type conversions
01848 
01849   bool EBandPlanner::convertPlanToBand(std::vector<geometry_msgs::PoseStamped> plan, std::vector<Bubble>& band)
01850   {
01851     // check if plugin initialized
01852     if(!initialized_)
01853     {
01854       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
01855       return false;
01856     }
01857 
01858     // create local variables
01859     double distance = 0.0;
01860     std::vector<Bubble> tmp_band;
01861 
01862     ROS_DEBUG("Copying plan to band - Conversion started: %d frames to convert.", ((int) plan.size()) );
01863 
01864     // get local copy of referenced variable
01865     tmp_band = band;
01866 
01867     // adapt band to plan
01868     tmp_band.resize(plan.size());
01869     for(int i = 0; i < ((int) plan.size()); i++)
01870     {
01871 #ifdef DEBUG_EBAND_
01872       ROS_DEBUG("Checking Frame %d of %d", i, ((int) plan.size()) );
01873 #endif
01874 
01875       // set poses in plan as centers of bubbles
01876       tmp_band[i].center = plan[i];
01877 
01878       // calc Size of Bubbles by calculating Dist to nearest Obstacle [depends kinematic, environment]
01879       if(!calcObstacleKinematicDistance(tmp_band[i].center.pose, distance))
01880       {
01881         // frame must not be immediately in collision -> otherwise calculation of gradient will later be invalid
01882         ROS_WARN("Calculation of Distance between bubble and nearest obstacle failed. Frame %d of %d outside map", i, ((int) plan.size()) );
01883         return false;
01884       }
01885 
01886       if(distance <= 0.0)
01887       {
01888         // frame must not be immediately in collision -> otherwise calculation of gradient will later be invalid
01889         ROS_WARN("Calculation of Distance between bubble and nearest obstacle failed. Frame %d of %d in collision. Plan invalid", i, ((int) plan.size()) );
01890         // TODO if frame in collision try to repair band instaed of aborting averything
01891         return false;
01892       }
01893 
01894 
01895       // assign to expansion of bubble
01896       tmp_band[i].expansion = distance;
01897     }
01898 
01899     // write to referenced variable
01900     band = tmp_band;
01901 
01902     ROS_DEBUG("Successfully converted plan to band");
01903     return true;
01904   }
01905 
01906 
01907   bool EBandPlanner::convertBandToPlan(std::vector<geometry_msgs::PoseStamped>& plan, std::vector<Bubble> band)
01908   {
01909     // check if plugin initialized
01910     if(!initialized_)
01911     {
01912       ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
01913       return false;
01914     }
01915 
01916     // create local variables
01917     std::vector<geometry_msgs::PoseStamped> tmp_plan;
01918 
01919     // adapt plan to band
01920     tmp_plan.resize(band.size());
01921     for(int i = 0; i < ((int) band.size()); i++)
01922     {
01923       // set centers of bubbles to StampedPose in plan
01924       tmp_plan[i] = band[i].center;
01925     }
01926 
01927     //write to referenced variable and done
01928     plan = tmp_plan;
01929 
01930     return true;
01931   }
01932 
01933 
01934 }


eband_local_planner
Author(s): Christian Connette, Bhaskara Marthi, Piyush Khandelwal
autogenerated on Fri Aug 28 2015 10:35:46