00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include <costmap_2d/costmap_2d.h>
00038 #include <cstdio>
00039
00040 #include <costmap_2d/Costmap2DConfig.h>
00041
00042 using namespace std;
00043
00044 namespace costmap_2d{
00045 Costmap2D::Costmap2D(unsigned int cells_size_x, unsigned int cells_size_y,
00046 double resolution, double origin_x, double origin_y, double inscribed_radius,
00047 double circumscribed_radius, double inflation_radius, double max_obstacle_range,
00048 double max_obstacle_height, double max_raytrace_range, double weight,
00049 const std::vector<unsigned char>& static_data, unsigned char lethal_threshold, bool track_unknown_space, unsigned char unknown_cost_value) : size_x_(cells_size_x),
00050 size_y_(cells_size_y), resolution_(resolution), origin_x_(origin_x), origin_y_(origin_y), static_map_(NULL),
00051 costmap_(NULL), markers_(NULL), max_obstacle_range_(max_obstacle_range),
00052 max_obstacle_height_(max_obstacle_height), max_raytrace_range_(max_raytrace_range), cached_costs_(NULL), cached_distances_(NULL),
00053 inscribed_radius_(inscribed_radius), circumscribed_radius_(circumscribed_radius), inflation_radius_(inflation_radius),
00054 weight_(weight), lethal_threshold_(lethal_threshold), track_unknown_space_(track_unknown_space), unknown_cost_value_(unknown_cost_value), inflation_queue_(){
00055
00056 costmap_ = new unsigned char[size_x_ * size_y_];
00057 static_map_ = new unsigned char[size_x_ * size_y_];
00058 markers_ = new unsigned char[size_x_ * size_y_];
00059 memset(markers_, 0, size_x_ * size_y_ * sizeof(unsigned char));
00060
00061
00062 cell_inscribed_radius_ = cellDistance(inscribed_radius);
00063 cell_circumscribed_radius_ = cellDistance(circumscribed_radius);
00064 cell_inflation_radius_ = cellDistance(inflation_radius);
00065
00066
00067 circumscribed_cost_lb_ = computeCost(cell_circumscribed_radius_);
00068
00069 computeCaches();
00070
00071 if(!static_data.empty()){
00072 ROS_ASSERT_MSG(size_x_ * size_y_ == static_data.size(), "If you want to initialize a costmap with static data, their sizes must match.");
00073
00074
00075 ROS_ASSERT_MSG(inflation_queue_.empty(), "The inflation queue must be empty at the beginning of inflation");
00076
00077 unsigned int index = 0;
00078 unsigned char* costmap_index = costmap_;
00079 std::vector<unsigned char>::const_iterator static_data_index = static_data.begin();
00080
00081
00082 for(unsigned int i = 0; i < size_y_; ++i){
00083 for(unsigned int j = 0; j < size_x_; ++j){
00084
00085 if(track_unknown_space_ && unknown_cost_value_ > 0 && *static_data_index == unknown_cost_value_)
00086 *costmap_index = NO_INFORMATION;
00087 else if(*static_data_index >= lethal_threshold_)
00088 *costmap_index = LETHAL_OBSTACLE;
00089 else
00090 *costmap_index = FREE_SPACE;
00091
00092 if(*costmap_index == LETHAL_OBSTACLE){
00093 unsigned int mx, my;
00094 indexToCells(index, mx, my);
00095 enqueue(index, mx, my, mx, my, inflation_queue_);
00096 }
00097
00098 ++costmap_index;
00099 ++static_data_index;
00100 ++index;
00101 }
00102 }
00103
00104
00105 inflateObstacles(inflation_queue_);
00106
00107
00108 memcpy(static_map_, costmap_, size_x_ * size_y_ * sizeof(unsigned char));
00109 }
00110 else{
00111
00112 resetMaps();
00113 }
00114 }
00115
00116 void Costmap2D::reconfigure(Costmap2DConfig &config, const Costmap2DConfig &last_config) {
00117 boost::recursive_mutex::scoped_lock rel(configuration_mutex_);
00118
00119 max_obstacle_height_ = config.max_obstacle_height;
00120 max_obstacle_range_ = config.max_obstacle_range;
00121 max_raytrace_range_ = config.raytrace_range;
00122
00123 if(last_config.inflation_radius != config.inflation_radius)
00124 {
00125 inflation_radius_ = config.inflation_radius;
00126 cell_inflation_radius_ = cellDistance(inflation_radius_);
00127 computeCaches();
00128 }
00129
00130
00131 if(!config.static_map && (last_config.origin_x != config.origin_x || last_config.origin_y != config.origin_y))
00132 updateOrigin(config.origin_x, config.origin_y);
00133
00134 unknown_cost_value_ = config.unknown_cost_value;
00135 lethal_threshold_ = config.lethal_cost_threshold;
00136
00137 weight_ = config.cost_scaling_factor;
00138
00139 if((config.footprint == "" || config.footprint == "[]") && config.robot_radius > 0) {
00140 inscribed_radius_ = config.robot_radius;
00141 circumscribed_radius_ = inscribed_radius_;
00142 }
00143
00144 finishConfiguration(config);
00145 }
00146
00147 void Costmap2D::finishConfiguration(costmap_2d::Costmap2DConfig &config) {
00148 }
00149
00150 void Costmap2D::replaceFullMap(double win_origin_x, double win_origin_y,
00151 unsigned int data_size_x, unsigned int data_size_y,
00152 const std::vector<unsigned char>& static_data){
00153 boost::recursive_mutex::scoped_lock rfml(configuration_mutex_);
00154
00155
00156 deleteMaps();
00157
00158
00159 size_x_ = data_size_x;
00160 size_y_ = data_size_y;
00161 origin_x_ = win_origin_x;
00162 origin_y_ = win_origin_y;
00163
00164
00165 initMaps(size_x_, size_y_);
00166
00167
00168 ROS_ASSERT_MSG(inflation_queue_.empty(), "The inflation queue must be empty at the beginning of inflation");
00169
00170 unsigned int index = 0;
00171 unsigned char* costmap_index = costmap_;
00172 std::vector<unsigned char>::const_iterator static_data_index = static_data.begin();
00173
00174
00175 for(unsigned int i = 0; i < size_y_; ++i){
00176 for(unsigned int j = 0; j < size_x_; ++j){
00177
00178 if(track_unknown_space_ && unknown_cost_value_ > 0 && *static_data_index == unknown_cost_value_)
00179 *costmap_index = NO_INFORMATION;
00180 else if(*static_data_index >= lethal_threshold_)
00181 *costmap_index = LETHAL_OBSTACLE;
00182 else
00183 *costmap_index = FREE_SPACE;
00184
00185 if(*costmap_index == LETHAL_OBSTACLE){
00186 unsigned int mx, my;
00187 indexToCells(index, mx, my);
00188 enqueue(index, mx, my, mx, my, inflation_queue_);
00189 }
00190 ++costmap_index;
00191 ++static_data_index;
00192 ++index;
00193 }
00194 }
00195
00196
00197 inflateObstacles(inflation_queue_);
00198
00199
00200 memcpy(static_map_, costmap_, size_x_ * size_y_ * sizeof(unsigned char));
00201 }
00202
00203 void Costmap2D::replaceStaticMapWindow(double win_origin_x, double win_origin_y,
00204 unsigned int data_size_x, unsigned int data_size_y,
00205 const std::vector<unsigned char>& static_data){
00206 boost::recursive_mutex::scoped_lock stwl(configuration_mutex_);
00207
00208 unsigned int start_x, start_y;
00209 if(!worldToMap(win_origin_x, win_origin_y, start_x, start_y) || (start_x + data_size_x) > size_x_ || (start_y + data_size_y) > size_y_){
00210 ROS_ERROR("You must call replaceStaticMapWindow with a window origin and size that is contained within the map");
00211 return;
00212 }
00213
00214
00215
00216 unsigned int max_inflation_change = 2 * cell_inflation_radius_;
00217
00218
00219
00220
00221 unsigned int copy_sx = std::min(std::max(0, (int)start_x - (int)max_inflation_change), (int)size_x_);
00222 unsigned int copy_sy = std::min(std::max(0, (int)start_y - (int)max_inflation_change), (int)size_x_);
00223 unsigned int copy_ex = std::max(std::min((int)size_x_, (int)start_x + (int)data_size_x + (int)max_inflation_change), 0);
00224 unsigned int copy_ey = std::max(std::min((int)size_y_, (int)start_y + (int)data_size_y + (int)max_inflation_change), 0);
00225
00226 unsigned int copy_size_x = copy_ex - copy_sx;
00227 unsigned int copy_size_y = copy_ey - copy_sy;
00228
00229
00230 double ll_x, ll_y, ur_x, ur_y;
00231 mapToWorld(copy_sx, copy_sy, ll_x, ll_y);
00232 mapToWorld(copy_ex, copy_ey, ur_x, ur_y);
00233 double mid_x = (ll_x + ur_x) / 2;
00234 double mid_y = (ll_y + ur_y) / 2;
00235 double size_x = ur_x - ll_x;
00236 double size_y = ur_y - ll_y;
00237
00238
00239
00240 clearNonLethal(mid_x, mid_y, size_x, size_y);
00241
00242
00243 unsigned int start_index = start_y * size_x_ + start_x;
00244 unsigned char* costmap_index = costmap_ + start_index;
00245 std::vector<unsigned char>::const_iterator static_data_index = static_data.begin();
00246 for(unsigned int i = 0; i < data_size_y; ++i){
00247 for(unsigned int j = 0; j < data_size_x; ++j){
00248
00249 if(track_unknown_space_ && unknown_cost_value_ > 0 && *static_data_index == unknown_cost_value_)
00250 *costmap_index = NO_INFORMATION;
00251 else if(*static_data_index >= lethal_threshold_)
00252 *costmap_index = LETHAL_OBSTACLE;
00253 else
00254 *costmap_index = FREE_SPACE;
00255
00256 ++costmap_index;
00257 ++static_data_index;
00258 }
00259 costmap_index += size_x_ - data_size_x;
00260 }
00261
00262
00263
00264
00265 reinflateWindow(mid_x, mid_y, size_x, size_y, false);
00266
00267
00268
00269 copyMapRegion(costmap_, copy_sx, copy_sy, size_x_, static_map_, copy_sx, copy_sy, size_x_, copy_size_x, copy_size_y);
00270
00271 }
00272
00273 void Costmap2D::reshapeStaticMap(double win_origin_x, double win_origin_y,
00274 unsigned int data_size_x, unsigned int data_size_y, const std::vector<unsigned char>& static_data){
00275 int m_ox, m_oy;
00276 worldToMapNoBounds(win_origin_x, win_origin_y, m_ox, m_oy);
00277
00278
00279 int bl_x = std::min(m_ox, 0);
00280 int bl_y = std::min(m_oy, 0);
00281 int ur_x = std::max(m_ox + data_size_x, size_x_);
00282 int ur_y = std::max(m_oy + data_size_y, size_y_);
00283
00284
00285 unsigned char* static_map_copy = new unsigned char[size_x_ * size_y_];
00286 memcpy(static_map_copy, static_map_, size_x_ * size_y_ * sizeof(unsigned char));
00287
00288
00289
00290 deleteMaps();
00291
00292
00293 double old_origin_x = origin_x_;
00294 double old_origin_y = origin_y_;
00295 unsigned int old_size_x = size_x_;
00296 unsigned int old_size_y = size_y_;
00297
00298 size_x_ = ur_x - bl_x;
00299 size_y_ = ur_y - bl_y;
00300 origin_x_ = std::min(origin_x_, win_origin_x);
00301 origin_y_ = std::min(origin_y_, win_origin_y);
00302
00303
00304 initMaps(size_x_, size_y_);
00305
00306
00307 resetMaps();
00308
00309
00310 unsigned int start_x, start_y;
00311 worldToMap(old_origin_x, old_origin_y, start_x, start_y);
00312 copyMapRegion(static_map_copy, 0, 0, old_size_x, costmap_, start_x, start_y, size_x_, old_size_x, old_size_y);
00313
00314 delete[] static_map_copy;
00315
00316
00317 replaceStaticMapWindow(win_origin_x, win_origin_y, data_size_x, data_size_y, static_data);
00318 }
00319
00320 void Costmap2D::updateStaticMapWindow(double win_origin_x, double win_origin_y,
00321 unsigned int data_size_x, unsigned int data_size_y,
00322 const std::vector<unsigned char>& static_data){
00323
00324 if(data_size_x * data_size_y != static_data.size()){
00325 ROS_ERROR("The sizes passed in are incorrect for the size of the static data char array. Doing nothing.");
00326 return;
00327 }
00328
00329
00330 int m_ox, m_oy;
00331 worldToMapNoBounds(win_origin_x, win_origin_y, m_ox, m_oy);
00332
00333
00334 if(m_ox <= 0 && m_oy <= 0 && (m_ox + data_size_x) >= size_x_ && (m_oy + data_size_y) >= size_y_){
00335 replaceFullMap(win_origin_x, win_origin_y, data_size_x, data_size_y, static_data);
00336 }
00337
00338 else if(m_ox < 0 || m_oy < 0 || (m_ox + data_size_x) > size_x_ || (m_oy + data_size_y) > size_y_){
00339 reshapeStaticMap(win_origin_x, win_origin_y, data_size_x, data_size_y, static_data);
00340 }
00341
00342 else{
00343 replaceStaticMapWindow(win_origin_x, win_origin_y, data_size_x, data_size_y, static_data);
00344 }
00345 }
00346
00347 void Costmap2D::deleteMaps(){
00348
00349 delete[] costmap_;
00350 delete[] static_map_;
00351 delete[] markers_;
00352 }
00353
00354 void Costmap2D::deleteKernels(){
00355 if(cached_distances_ != NULL){
00356 for(unsigned int i = 0; i <= cell_inflation_radius_ + 1; ++i){
00357 delete[] cached_distances_[i];
00358 }
00359 delete[] cached_distances_;
00360 }
00361
00362 if(cached_costs_ != NULL){
00363 for(unsigned int i = 0; i <= cell_inflation_radius_ + 1; ++i){
00364 delete[] cached_costs_[i];
00365 }
00366 delete[] cached_costs_;
00367 }
00368 }
00369
00370 void Costmap2D::initMaps(unsigned int size_x, unsigned int size_y){
00371 costmap_ = new unsigned char[size_x * size_y];
00372 static_map_ = new unsigned char[size_x * size_y];
00373 markers_ = new unsigned char[size_x * size_y];
00374
00375
00376 memset(markers_, 0, size_x_ * size_y_ * sizeof(unsigned char));
00377 }
00378
00379 void Costmap2D::resetMaps(){
00380
00381 if(track_unknown_space_){
00382 memset(static_map_, NO_INFORMATION, size_x_ * size_y_ * sizeof(unsigned char));
00383 memset(costmap_, NO_INFORMATION, size_x_ * size_y_ * sizeof(unsigned char));
00384 }
00385 else{
00386 memset(static_map_, FREE_SPACE, size_x_ * size_y_ * sizeof(unsigned char));
00387 memset(costmap_, FREE_SPACE, size_x_ * size_y_ * sizeof(unsigned char));
00388 }
00389 }
00390
00391 void Costmap2D::copyKernels(const Costmap2D& map, unsigned int cell_inflation_radius){
00392 cached_costs_ = new unsigned char*[cell_inflation_radius + 2];
00393 cached_distances_ = new double*[cell_inflation_radius + 2];
00394 for(unsigned int i = 0; i <= cell_inflation_radius + 1; ++i){
00395 cached_costs_[i] = new unsigned char[cell_inflation_radius + 2];
00396 cached_distances_[i] = new double[cell_inflation_radius + 2];
00397 for(unsigned int j = 0; j <= cell_inflation_radius + 1; ++j){
00398 cached_distances_[i][j] = map.cached_distances_[i][j];
00399 cached_costs_[i][j] = map.cached_costs_[i][j];
00400 }
00401 }
00402 }
00403
00404 void Costmap2D::copyCostmapWindow(const Costmap2D& map, double win_origin_x, double win_origin_y, double win_size_x, double win_size_y){
00405 boost::recursive_mutex::scoped_lock cpl(configuration_mutex_);
00406
00407
00408 if(this == &map){
00409 ROS_ERROR("Cannot convert this costmap into a window of itself");
00410 return;
00411 }
00412
00413
00414 deleteMaps();
00415 deleteKernels();
00416
00417
00418 unsigned int lower_left_x, lower_left_y, upper_right_x, upper_right_y;
00419 if(!map.worldToMap(win_origin_x, win_origin_y, lower_left_x, lower_left_y)
00420 || ! map.worldToMap(win_origin_x + win_size_x, win_origin_y + win_size_y, upper_right_x, upper_right_y)){
00421 ROS_ERROR("Cannot window a map that the window bounds don't fit inside of");
00422 return;
00423 }
00424
00425 size_x_ = upper_right_x - lower_left_x;
00426 size_y_ = upper_right_y - lower_left_y;
00427 resolution_ = map.resolution_;
00428 origin_x_ = win_origin_x;
00429 origin_y_ = win_origin_y;
00430
00431 ROS_DEBUG("ll(%d, %d), ur(%d, %d), size(%d, %d), origin(%.2f, %.2f)",
00432 lower_left_x, lower_left_y, upper_right_x, upper_right_y, size_x_, size_y_, origin_x_, origin_y_);
00433
00434
00435
00436 initMaps(size_x_, size_y_);
00437
00438
00439 copyMapRegion(map.costmap_, lower_left_x, lower_left_y, map.size_x_, costmap_, 0, 0, size_x_, size_x_, size_y_);
00440 copyMapRegion(map.static_map_, lower_left_x, lower_left_y, map.size_x_, static_map_, 0, 0, size_x_, size_x_, size_y_);
00441
00442 max_obstacle_range_ = map.max_obstacle_range_;
00443 max_obstacle_height_ = map.max_obstacle_height_;
00444 max_raytrace_range_ = map.max_raytrace_range_;
00445
00446 inscribed_radius_ = map.inscribed_radius_;
00447 circumscribed_radius_ = map.circumscribed_radius_;
00448 inflation_radius_ = map.inflation_radius_;
00449
00450 cell_inscribed_radius_ = map.cell_inscribed_radius_;
00451 cell_circumscribed_radius_ = map.cell_circumscribed_radius_;
00452 cell_inflation_radius_ = map.cell_inflation_radius_;
00453
00454
00455 circumscribed_cost_lb_ = map.circumscribed_cost_lb_;
00456
00457 weight_ = map.weight_;
00458
00459
00460 copyKernels(map, cell_inflation_radius_);
00461 }
00462
00463 Costmap2D& Costmap2D::operator=(const Costmap2D& map) {
00464
00465
00466 if(this == &map)
00467 return *this;
00468
00469
00470 deleteMaps();
00471 deleteKernels();
00472
00473 size_x_ = map.size_x_;
00474 size_y_ = map.size_y_;
00475 resolution_ = map.resolution_;
00476 origin_x_ = map.origin_x_;
00477 origin_y_ = map.origin_y_;
00478
00479
00480 initMaps(size_x_, size_y_);
00481
00482
00483 memcpy(static_map_, map.static_map_, size_x_ * size_y_ * sizeof(unsigned char));
00484
00485
00486 memcpy(costmap_, map.costmap_, size_x_ * size_y_ * sizeof(unsigned char));
00487
00488 max_obstacle_range_ = map.max_obstacle_range_;
00489 max_obstacle_height_ = map.max_obstacle_height_;
00490 max_raytrace_range_ = map.max_raytrace_range_;
00491
00492 inscribed_radius_ = map.inscribed_radius_;
00493 circumscribed_radius_ = map.circumscribed_radius_;
00494 inflation_radius_ = map.inflation_radius_;
00495
00496 cell_inscribed_radius_ = map.cell_inscribed_radius_;
00497 cell_circumscribed_radius_ = map.cell_circumscribed_radius_;
00498 cell_inflation_radius_ = map.cell_inflation_radius_;
00499
00500
00501 circumscribed_cost_lb_ = map.circumscribed_cost_lb_;
00502
00503 weight_ = map.weight_;
00504
00505
00506 copyKernels(map, cell_inflation_radius_);
00507
00508 return *this;
00509 }
00510
00511 Costmap2D::Costmap2D(const Costmap2D& map) : static_map_(NULL), costmap_(NULL), markers_(NULL), cached_costs_(NULL), cached_distances_(NULL) {
00512 *this = map;
00513 }
00514
00515
00516 Costmap2D::Costmap2D() : size_x_(0), size_y_(0), resolution_(0.0), origin_x_(0.0), origin_y_(0.0), static_map_(NULL),
00517 costmap_(NULL), markers_(NULL), cached_costs_(NULL), cached_distances_(NULL) {}
00518
00519 Costmap2D::~Costmap2D(){
00520 deleteMaps();
00521 deleteKernels();
00522 }
00523
00524 unsigned int Costmap2D::cellDistance(double world_dist){
00525 double cells_dist = max(0.0, ceil(world_dist / resolution_));
00526 return (unsigned int) cells_dist;
00527 }
00528
00529 const unsigned char* Costmap2D::getCharMap() const {
00530 return costmap_;
00531 }
00532
00533 unsigned char Costmap2D::getCost(unsigned int mx, unsigned int my) const {
00534 ROS_ASSERT_MSG(mx < size_x_ && my < size_y_, "You cannot get the cost of a cell that is outside the bounds of the costmap");
00535 return costmap_[getIndex(mx, my)];
00536 }
00537
00538 void Costmap2D::setCost(unsigned int mx, unsigned int my, unsigned char cost) {
00539 ROS_ASSERT_MSG(mx < size_x_ && my < size_y_, "You cannot set the cost of a cell that is outside the bounds of the costmap");
00540 costmap_[getIndex(mx, my)] = cost;
00541 }
00542
00543 void Costmap2D::mapToWorld(unsigned int mx, unsigned int my, double& wx, double& wy) const {
00544 wx = origin_x_ + (mx + 0.5) * resolution_;
00545 wy = origin_y_ + (my + 0.5) * resolution_;
00546 }
00547
00548 bool Costmap2D::worldToMap(double wx, double wy, unsigned int& mx, unsigned int& my) const {
00549 if(wx < origin_x_ || wy < origin_y_)
00550 return false;
00551
00552 mx = (int) ((wx - origin_x_) / resolution_);
00553 my = (int) ((wy - origin_y_) / resolution_);
00554
00555 if(mx < size_x_ && my < size_y_)
00556 return true;
00557
00558 return false;
00559 }
00560
00561 void Costmap2D::worldToMapNoBounds(double wx, double wy, int& mx, int& my) const {
00562 mx = (int) ((wx - origin_x_) / resolution_);
00563 my = (int) ((wy - origin_y_) / resolution_);
00564 }
00565
00566 void Costmap2D::resetMapOutsideWindow(double wx, double wy, double w_size_x, double w_size_y){
00567 ROS_ASSERT_MSG(w_size_x >= 0 && w_size_y >= 0, "You cannot specify a negative size window");
00568
00569 double start_point_x = wx - w_size_x / 2;
00570 double start_point_y = wy - w_size_y / 2;
00571 double end_point_x = start_point_x + w_size_x;
00572 double end_point_y = start_point_y + w_size_y;
00573
00574
00575 start_point_x = max(origin_x_, start_point_x);
00576 start_point_y = max(origin_y_, start_point_y);
00577
00578
00579 end_point_x = min(origin_x_ + getSizeInMetersX(), end_point_x);
00580 end_point_y = min(origin_y_ + getSizeInMetersY(), end_point_y);
00581
00582 unsigned int start_x, start_y, end_x, end_y;
00583
00584
00585 if(!worldToMap(start_point_x, start_point_y, start_x, start_y) || !worldToMap(end_point_x, end_point_y, end_x, end_y))
00586 return;
00587
00588 ROS_ASSERT(end_x >= start_x && end_y >= start_y);
00589 unsigned int cell_size_x = end_x - start_x;
00590 unsigned int cell_size_y = end_y - start_y;
00591
00592
00593 unsigned char* local_map = new unsigned char[cell_size_x * cell_size_y];
00594
00595
00596 copyMapRegion(costmap_, start_x, start_y, size_x_, local_map, 0, 0, cell_size_x, cell_size_x, cell_size_y);
00597
00598
00599 memcpy(costmap_, static_map_, size_x_ * size_y_ * sizeof(unsigned char));
00600
00601
00602 copyMapRegion(local_map, 0, 0, cell_size_x, costmap_, start_x, start_y, size_x_, cell_size_x, cell_size_y);
00603
00604
00605 delete[] local_map;
00606 }
00607
00608 void Costmap2D::updateWorld(double robot_x, double robot_y,
00609 const vector<Observation>& observations, const vector<Observation>& clearing_observations){
00610 boost::recursive_mutex::scoped_lock uwl(configuration_mutex_);
00611
00612
00613 memset(markers_, 0, size_x_ * size_y_ * sizeof(unsigned char));
00614
00615
00616 ROS_ASSERT_MSG(inflation_queue_.empty(), "The inflation queue must be empty at the beginning of inflation");
00617
00618
00619 raytraceFreespace(clearing_observations);
00620
00621
00622 double inflation_window_size = 2 * (max_raytrace_range_ + inflation_radius_);
00623
00624
00625 clearNonLethal(robot_x, robot_y, inflation_window_size, inflation_window_size);
00626
00627
00628 resetInflationWindow(robot_x, robot_y, inflation_window_size + 2 * inflation_radius_, inflation_window_size + 2 * inflation_radius_, inflation_queue_, false);
00629
00630
00631 updateObstacles(observations, inflation_queue_);
00632
00633 inflateObstacles(inflation_queue_);
00634 }
00635
00636 void Costmap2D::reinflateWindow(double wx, double wy, double w_size_x, double w_size_y, bool clear){
00637 boost::recursive_mutex::scoped_lock rwl(configuration_mutex_);
00638
00639 memset(markers_, 0, size_x_ * size_y_ * sizeof(unsigned char));
00640
00641
00642 ROS_ASSERT_MSG(inflation_queue_.empty(), "The inflation queue must be empty at the beginning of inflation");
00643
00644
00645 resetInflationWindow(wx, wy, w_size_x, w_size_y, inflation_queue_, clear);
00646
00647
00648 inflateObstacles(inflation_queue_);
00649
00650 }
00651
00652 void Costmap2D::updateObstacles(const vector<Observation>& observations, priority_queue<CellData>& inflation_queue){
00653
00654 for(vector<Observation>::const_iterator it = observations.begin(); it != observations.end(); ++it){
00655 const Observation& obs = *it;
00656
00657 const pcl::PointCloud<pcl::PointXYZ>& cloud =obs.cloud_;
00658
00659 double sq_obstacle_range = obs.obstacle_range_ * obs.obstacle_range_;
00660
00661
00662 for(unsigned int i = 0; i < cloud.points.size(); ++i){
00663
00664 if(cloud.points[i].z > max_obstacle_height_){
00665 ROS_DEBUG("The point is too high");
00666 continue;
00667 }
00668
00669
00670 double sq_dist = (cloud.points[i].x - obs.origin_.x) * (cloud.points[i].x - obs.origin_.x)
00671 + (cloud.points[i].y - obs.origin_.y) * (cloud.points[i].y - obs.origin_.y)
00672 + (cloud.points[i].z - obs.origin_.z) * (cloud.points[i].z - obs.origin_.z);
00673
00674
00675 if(sq_dist >= sq_obstacle_range){
00676 ROS_DEBUG("The point is too far away");
00677 continue;
00678 }
00679
00680
00681 unsigned int mx, my;
00682 if(!worldToMap(cloud.points[i].x, cloud.points[i].y, mx, my)){
00683 ROS_DEBUG("Computing map coords failed");
00684 continue;
00685 }
00686
00687 unsigned int index = getIndex(mx, my);
00688
00689
00690 enqueue(index, mx, my, mx, my, inflation_queue);
00691 }
00692 }
00693 }
00694
00695 void Costmap2D::inflateObstacles(priority_queue<CellData>& inflation_queue){
00696 while(!inflation_queue.empty()){
00697
00698 const CellData& current_cell = inflation_queue.top();
00699
00700 unsigned int index = current_cell.index_;
00701 unsigned int mx = current_cell.x_;
00702 unsigned int my = current_cell.y_;
00703 unsigned int sx = current_cell.src_x_;
00704 unsigned int sy = current_cell.src_y_;
00705
00706
00707 if(mx > 0)
00708 enqueue(index - 1, mx - 1, my, sx, sy, inflation_queue);
00709 if(my > 0)
00710 enqueue(index - size_x_, mx, my - 1, sx, sy, inflation_queue);
00711 if(mx < size_x_ - 1)
00712 enqueue(index + 1, mx + 1, my, sx, sy, inflation_queue);
00713 if(my < size_y_ - 1)
00714 enqueue(index + size_x_, mx, my + 1, sx, sy, inflation_queue);
00715
00716
00717 inflation_queue.pop();
00718 }
00719 }
00720
00721
00722 void Costmap2D::raytraceFreespace(const std::vector<Observation>& clearing_observations){
00723 for(unsigned int i = 0; i < clearing_observations.size(); ++i){
00724 raytraceFreespace(clearing_observations[i]);
00725 }
00726 }
00727
00728 void Costmap2D::raytraceFreespace(const Observation& clearing_observation){
00729
00730 ClearCell clearer(costmap_);
00731
00732 double ox = clearing_observation.origin_.x;
00733 double oy = clearing_observation.origin_.y;
00734 pcl::PointCloud<pcl::PointXYZ> cloud = clearing_observation.cloud_;
00735
00736
00737 unsigned int x0, y0;
00738 if(!worldToMap(ox, oy, x0, y0)){
00739 ROS_WARN_THROTTLE(1.0, "The origin for the sensor at (%.2f, %.2f) is out of map bounds. So, the costmap cannot raytrace for it.", ox, oy);
00740 return;
00741 }
00742
00743
00744 double map_end_x = origin_x_ + getSizeInMetersX();
00745 double map_end_y = origin_y_ + getSizeInMetersY();
00746
00747
00748 for(unsigned int i = 0; i < cloud.points.size(); ++i){
00749 double wx = cloud.points[i].x;
00750 double wy = cloud.points[i].y;
00751
00752
00753
00754 double a = wx - ox;
00755 double b = wy - oy;
00756
00757
00758 if(wx < origin_x_){
00759 double t = (origin_x_ - ox) / a;
00760 wx = origin_x_;
00761 wy = oy + b * t;
00762 }
00763 if(wy < origin_y_){
00764 double t = (origin_y_ - oy) / b;
00765 wx = ox + a * t;
00766 wy = origin_y_;
00767 }
00768
00769
00770 if(wx > map_end_x){
00771 double t = (map_end_x - ox) / a;
00772 wx = map_end_x;
00773 wy = oy + b * t;
00774 }
00775 if(wy > map_end_y){
00776 double t = (map_end_y - oy) / b;
00777 wx = ox + a * t;
00778 wy = map_end_y;
00779 }
00780
00781
00782 unsigned int x1, y1;
00783
00784
00785 if(!worldToMap(wx, wy, x1, y1))
00786 continue;
00787
00788 unsigned int cell_raytrace_range = cellDistance(clearing_observation.raytrace_range_);
00789
00790
00791 raytraceLine(clearer, x0, y0, x1, y1, cell_raytrace_range);
00792 }
00793 }
00794
00795 void Costmap2D::clearNonLethal(double wx, double wy, double w_size_x, double w_size_y, bool clear_no_info){
00796
00797 unsigned int mx, my;
00798 if(!worldToMap(wx, wy, mx, my))
00799 return;
00800
00801
00802 double start_x = wx - w_size_x / 2;
00803 double start_y = wy - w_size_y / 2;
00804 double end_x = start_x + w_size_x;
00805 double end_y = start_y + w_size_y;
00806
00807
00808 start_x = max(origin_x_, start_x);
00809 start_y = max(origin_y_, start_y);
00810
00811 end_x = min(origin_x_ + getSizeInMetersX(), end_x);
00812 end_y = min(origin_y_ + getSizeInMetersY(), end_y);
00813
00814
00815 unsigned int map_sx, map_sy, map_ex, map_ey;
00816
00817
00818 if(!worldToMap(start_x, start_y, map_sx, map_sy) || !worldToMap(end_x, end_y, map_ex, map_ey))
00819 return;
00820
00821
00822 unsigned int index = getIndex(map_sx, map_sy);
00823 unsigned char* current = &costmap_[index];
00824 for(unsigned int j = map_sy; j <= map_ey; ++j){
00825 for(unsigned int i = map_sx; i <= map_ex; ++i){
00826
00827 if(*current != LETHAL_OBSTACLE){
00828 if(clear_no_info || *current != NO_INFORMATION)
00829 *current = FREE_SPACE;
00830 }
00831 current++;
00832 index++;
00833 }
00834 current += size_x_ - (map_ex - map_sx) - 1;
00835 index += size_x_ - (map_ex - map_sx) - 1;
00836 }
00837 }
00838
00839 void Costmap2D::resetInflationWindow(double wx, double wy, double w_size_x, double w_size_y,
00840 priority_queue<CellData>& inflation_queue, bool clear){
00841
00842 unsigned int mx, my;
00843 if(!worldToMap(wx, wy, mx, my))
00844 return;
00845
00846
00847 double start_x = wx - w_size_x / 2;
00848 double start_y = wy - w_size_y / 2;
00849 double end_x = start_x + w_size_x;
00850 double end_y = start_y + w_size_y;
00851
00852
00853 start_x = max(origin_x_, start_x);
00854 start_y = max(origin_y_, start_y);
00855
00856 end_x = min(origin_x_ + getSizeInMetersX(), end_x);
00857 end_y = min(origin_y_ + getSizeInMetersY(), end_y);
00858
00859
00860 unsigned int map_sx, map_sy, map_ex, map_ey;
00861
00862
00863 if(!worldToMap(start_x, start_y, map_sx, map_sy) || !worldToMap(end_x, end_y, map_ex, map_ey)){
00864 ROS_ERROR("Bounds not legal for reset window. Doing nothing.");
00865 return;
00866 }
00867
00868
00869 unsigned int index = getIndex(map_sx, map_sy);
00870 unsigned char* current = &costmap_[index];
00871 for(unsigned int j = map_sy; j <= map_ey; ++j){
00872 for(unsigned int i = map_sx; i <= map_ex; ++i){
00873
00874 if(*current == LETHAL_OBSTACLE)
00875 enqueue(index, i, j, i, j, inflation_queue);
00876 else if(clear && *current != NO_INFORMATION)
00877 *current = FREE_SPACE;
00878 current++;
00879 index++;
00880 }
00881 current += size_x_ - (map_ex - map_sx) - 1;
00882 index += size_x_ - (map_ex - map_sx) - 1;
00883 }
00884 }
00885
00886 void Costmap2D::computeCaches() {
00887
00888 cached_costs_ = new unsigned char*[cell_inflation_radius_ + 2];
00889 cached_distances_ = new double*[cell_inflation_radius_ + 2];
00890 for(unsigned int i = 0; i <= cell_inflation_radius_ + 1; ++i){
00891 cached_costs_[i] = new unsigned char[cell_inflation_radius_ + 2];
00892 cached_distances_[i] = new double[cell_inflation_radius_ + 2];
00893 for(unsigned int j = 0; j <= cell_inflation_radius_ + 1; ++j){
00894 cached_distances_[i][j] = sqrt(i*i + j*j);
00895 cached_costs_[i][j] = computeCost(cached_distances_[i][j]);
00896 }
00897 }
00898 }
00899
00900 void Costmap2D::updateOrigin(double new_origin_x, double new_origin_y){
00901
00902 int cell_ox, cell_oy;
00903 cell_ox = int((new_origin_x - origin_x_) / resolution_);
00904 cell_oy = int((new_origin_y - origin_y_) / resolution_);
00905
00906
00907
00908 double new_grid_ox, new_grid_oy;
00909 new_grid_ox = origin_x_ + cell_ox * resolution_;
00910 new_grid_oy = origin_y_ + cell_oy * resolution_;
00911
00912
00913 int size_x = size_x_;
00914 int size_y = size_y_;
00915
00916
00917 int lower_left_x, lower_left_y, upper_right_x, upper_right_y;
00918 lower_left_x = min(max(cell_ox, 0), size_x);
00919 lower_left_y = min(max(cell_oy, 0), size_y);
00920 upper_right_x = min(max(cell_ox + size_x, 0), size_x);
00921 upper_right_y = min(max(cell_oy + size_y, 0), size_y);
00922
00923 unsigned int cell_size_x = upper_right_x - lower_left_x;
00924 unsigned int cell_size_y = upper_right_y - lower_left_y;
00925
00926
00927 unsigned char* local_map = new unsigned char[cell_size_x * cell_size_y];
00928
00929
00930 copyMapRegion(costmap_, lower_left_x, lower_left_y, size_x_, local_map, 0, 0, cell_size_x, cell_size_x, cell_size_y);
00931
00932
00933 resetMaps();
00934
00935
00936 origin_x_ = new_grid_ox;
00937 origin_y_ = new_grid_oy;
00938
00939
00940 int start_x = lower_left_x - cell_ox;
00941 int start_y = lower_left_y - cell_oy;
00942
00943
00944 copyMapRegion(local_map, 0, 0, cell_size_x, costmap_, start_x, start_y, size_x_, cell_size_x, cell_size_y);
00945
00946
00947 delete[] local_map;
00948 }
00949
00950 bool Costmap2D::setConvexPolygonCost(const std::vector<geometry_msgs::Point>& polygon, unsigned char cost_value) {
00951
00952 std::vector<MapLocation> map_polygon;
00953 for(unsigned int i = 0; i < polygon.size(); ++i){
00954 MapLocation loc;
00955 if(!worldToMap(polygon[i].x, polygon[i].y, loc.x, loc.y)){
00956 ROS_DEBUG("Polygon lies outside map bounds, so we can't fill it");
00957 return false;
00958 }
00959 map_polygon.push_back(loc);
00960 }
00961
00962 std::vector<MapLocation> polygon_cells;
00963
00964
00965 convexFillCells(map_polygon, polygon_cells);
00966
00967
00968 for(unsigned int i = 0; i < polygon_cells.size(); ++i){
00969 unsigned int index = getIndex(polygon_cells[i].x, polygon_cells[i].y);
00970 costmap_[index] = cost_value;
00971 }
00972 return true;
00973 }
00974
00975 void Costmap2D::polygonOutlineCells(const std::vector<MapLocation>& polygon, std::vector<MapLocation>& polygon_cells){
00976 PolygonOutlineCells cell_gatherer(*this, costmap_, polygon_cells);
00977 for(unsigned int i = 0; i < polygon.size() - 1; ++i){
00978 raytraceLine(cell_gatherer, polygon[i].x, polygon[i].y, polygon[i + 1].x, polygon[i + 1].y);
00979 }
00980 if(!polygon.empty()){
00981 unsigned int last_index = polygon.size() - 1;
00982
00983 raytraceLine(cell_gatherer, polygon[last_index].x, polygon[last_index].y, polygon[0].x, polygon[0].y);
00984 }
00985 }
00986
00987 void Costmap2D::convexFillCells(const std::vector<MapLocation>& polygon, std::vector<MapLocation>& polygon_cells){
00988
00989 if(polygon.size() < 3)
00990 return;
00991
00992
00993 polygonOutlineCells(polygon, polygon_cells);
00994
00995
00996 MapLocation swap;
00997 unsigned int i = 0;
00998 while(i < polygon_cells.size() - 1){
00999 if(polygon_cells[i].x > polygon_cells[i + 1].x){
01000 swap = polygon_cells[i];
01001 polygon_cells[i] = polygon_cells[i + 1];
01002 polygon_cells[i + 1] = swap;
01003
01004 if(i > 0)
01005 --i;
01006 }
01007 else
01008 ++i;
01009 }
01010
01011 i = 0;
01012 MapLocation min_pt;
01013 MapLocation max_pt;
01014 unsigned int min_x = polygon_cells[0].x;
01015 unsigned int max_x = polygon_cells[polygon_cells.size() -1].x;
01016
01017
01018 for(unsigned int x = min_x; x <= max_x; ++x){
01019 if(i >= polygon_cells.size() - 1)
01020 break;
01021
01022 if(polygon_cells[i].y < polygon_cells[i + 1].y){
01023 min_pt = polygon_cells[i];
01024 max_pt = polygon_cells[i + 1];
01025 }
01026 else{
01027 min_pt = polygon_cells[i + 1];
01028 max_pt = polygon_cells[i];
01029 }
01030
01031 i += 2;
01032 while(i < polygon_cells.size() && polygon_cells[i].x == x){
01033 if(polygon_cells[i].y < min_pt.y)
01034 min_pt = polygon_cells[i];
01035 else if(polygon_cells[i].y > max_pt.y)
01036 max_pt = polygon_cells[i];
01037 ++i;
01038 }
01039
01040 MapLocation pt;
01041
01042 for(unsigned int y = min_pt.y; y < max_pt.y; ++y){
01043 pt.x = x;
01044 pt.y = y;
01045 polygon_cells.push_back(pt);
01046
01047 }
01048 }
01049 }
01050
01051 unsigned int Costmap2D::getSizeInCellsX() const{
01052 return size_x_;
01053 }
01054
01055 unsigned int Costmap2D::getSizeInCellsY() const{
01056 return size_y_;
01057 }
01058
01059 double Costmap2D::getSizeInMetersX() const{
01060 return (size_x_ - 1 + 0.5) * resolution_;
01061 }
01062
01063 double Costmap2D::getSizeInMetersY() const{
01064 return (size_y_ - 1 + 0.5) * resolution_;
01065 }
01066
01067 double Costmap2D::getOriginX() const{
01068 return origin_x_;
01069 }
01070
01071 double Costmap2D::getOriginY() const{
01072 return origin_y_;
01073 }
01074
01075 double Costmap2D::getResolution() const{
01076 return resolution_;
01077 }
01078
01079 bool Costmap2D::isCircumscribedCell(unsigned int x, unsigned int y) const {
01080 unsigned char cost = getCost(x, y);
01081 if(cost < INSCRIBED_INFLATED_OBSTACLE && cost >= circumscribed_cost_lb_)
01082 return true;
01083 return false;
01084 }
01085
01086 void Costmap2D::saveMap(std::string file_name){
01087 FILE *fp = fopen(file_name.c_str(), "w");
01088
01089 if(!fp){
01090 ROS_WARN("Can't open file %s", file_name.c_str());
01091 return;
01092 }
01093
01094 fprintf(fp, "P2\n%d\n%d\n%d\n", size_x_, size_y_, 0xff);
01095 for(unsigned int iy = 0; iy < size_y_; iy++) {
01096 for(unsigned int ix = 0; ix < size_x_; ix++) {
01097 unsigned char cost = getCost(ix,iy);
01098 if (cost == LETHAL_OBSTACLE) {
01099 fprintf(fp, "255 ");
01100 }
01101 else if (cost == NO_INFORMATION){
01102 fprintf(fp, "180 ");
01103 }
01104 else if (cost == INSCRIBED_INFLATED_OBSTACLE ) {
01105 fprintf(fp, "128 ");
01106 }
01107 else if (cost > 0){
01108 fprintf(fp, "50 ");
01109 }
01110 else {
01111 fprintf(fp, "0 ");
01112 }
01113 }
01114 fprintf(fp, "\n");
01115 }
01116 fclose(fp);
01117 }
01118
01119 };