00001 #include <safe_teleop_base/safe_trajectory_planner.h>
00002
00003 using namespace std;
00004 using namespace costmap_2d;
00005 using namespace base_local_planner;
00006
00007 namespace safe_teleop {
00008 SafeTrajectoryPlanner::SafeTrajectoryPlanner(WorldModel& world_model,
00009 const Costmap2D& costmap,
00010 std::vector<geometry_msgs::Point> footprint_spec,
00011 double inscribed_radius, double circumscribed_radius,
00012 double acc_lim_x, double acc_lim_y, double acc_lim_theta,
00013 double sim_time, double sim_granularity,
00014 int vx_samples, int vy_samples, int vtheta_samples,
00015 double userdist_scale, double occdist_scale,
00016 double max_vel_x, double min_vel_x,
00017 double max_vel_y, double min_vel_y,
00018 double max_vel_th, double min_vel_th,
00019 bool holonomic_robot, bool dwa)
00020 : map_(costmap.getSizeInCellsX(), costmap.getSizeInCellsY()), costmap_(costmap),
00021 world_model_(world_model), footprint_spec_(footprint_spec),
00022 inscribed_radius_(inscribed_radius), circumscribed_radius_(circumscribed_radius),
00023 sim_time_(sim_time), sim_granularity_(sim_granularity),
00024 vx_samples_(vx_samples), vy_samples_(vy_samples), vtheta_samples_(vtheta_samples),
00025 userdist_scale_(userdist_scale), occdist_scale_(occdist_scale),
00026 acc_lim_x_(acc_lim_x), acc_lim_y_(acc_lim_y), acc_lim_theta_(acc_lim_theta),
00027 max_vel_x_(max_vel_x), min_vel_x_(min_vel_x),
00028 max_vel_y_(max_vel_y), min_vel_y_(min_vel_y),
00029 max_vel_th_(max_vel_th), min_vel_th_(min_vel_th),
00030 holonomic_robot_(holonomic_robot), dwa_(dwa)
00031 {
00032 }
00033
00034 SafeTrajectoryPlanner::~SafeTrajectoryPlanner(){}
00035
00036
00037 void SafeTrajectoryPlanner::generateTrajectory(
00038 double x, double y, double theta,
00039 double vx, double vy, double vtheta,
00040 double vx_samp, double vy_samp, double vtheta_samp,
00041 double acc_x, double acc_y, double acc_theta,
00042 double impossible_cost,
00043 double dx, double dy, double dtheta,
00044 Trajectory& traj){
00045 double x_i = x;
00046 double y_i = y;
00047 double theta_i = theta;
00048
00049 double vx_i, vy_i, vtheta_i;
00050
00051 vx_i = vx;
00052 vy_i = vy;
00053 vtheta_i = vtheta;
00054
00055
00056
00057
00058
00059 int num_steps = int(sim_time_ / sim_granularity_ + 0.5);
00060
00061 double dt = sim_time_ / num_steps;
00062 double time = 0.0;
00063
00064
00065 traj.resetPoints();
00066 traj.xv_ = vx_samp;
00067 traj.yv_ = vy_samp;
00068 traj.thetav_ = vtheta_samp;
00069 traj.cost_ = -1.0;
00070
00071 if(num_steps == 0)
00072 return;
00073
00074
00075 double user_dist = 0.0;
00076 double occ_cost = 0.0;
00077
00078 for(int i = 0; i < num_steps; ++i){
00079
00080 unsigned int cell_x, cell_y;
00081
00082
00083 if(!costmap_.worldToMap(x_i, y_i, cell_x, cell_y)){
00084 traj.cost_ = -1.0;
00085 return;
00086 }
00087
00088
00089 double footprint_cost = footprintCost(x_i, y_i, theta_i);
00090
00091
00092 if(footprint_cost < 0){
00093 traj.cost_ = -1.0;
00094 return;
00095 }
00096
00097 occ_cost = std::max(std::max(occ_cost, footprint_cost), double(costmap_.getCost(cell_x, cell_y)));
00098
00099 time += dt;
00100
00101
00102 traj.addPoint(x_i, y_i, theta_i);
00103
00104
00105 vx_i = computeNewVelocity(vx_samp, vx_i, acc_x, dt);
00106 vy_i = computeNewVelocity(vy_samp, vy_i, acc_y, dt);
00107 vtheta_i = computeNewVelocity(vtheta_samp, vtheta_i, acc_theta, dt);
00108
00109
00110 x_i = computeNewXPosition(x_i, vx_i, vy_i, theta_i, dt);
00111 y_i = computeNewYPosition(y_i, vx_i, vy_i, theta_i, dt);
00112 theta_i = computeNewThetaPosition(theta_i, vtheta_i, dt);
00113
00114 }
00115
00116 user_dist = sqrt((vx_samp - dx) * (vx_samp - dx) +
00117 (vy_samp - dy) * (vy_samp - dy) +
00118 (vtheta_samp - dtheta) * (vtheta_samp - dtheta));
00119
00120 traj.cost_ = user_dist * userdist_scale_ + occdist_scale_ * occ_cost;
00121 }
00122
00123
00124 double SafeTrajectoryPlanner::lineCost(int x0, int x1,
00125 int y0, int y1){
00126
00127 int deltax = abs(x1 - x0);
00128 int deltay = abs(y1 - y0);
00129 int x = x0;
00130 int y = y0;
00131
00132 int xinc1, xinc2, yinc1, yinc2;
00133 int den, num, numadd, numpixels;
00134
00135 double line_cost = 0.0;
00136 double point_cost = -1.0;
00137
00138 if (x1 >= x0)
00139 {
00140 xinc1 = 1;
00141 xinc2 = 1;
00142 }
00143 else
00144 {
00145 xinc1 = -1;
00146 xinc2 = -1;
00147 }
00148
00149 if (y1 >= y0)
00150 {
00151 yinc1 = 1;
00152 yinc2 = 1;
00153 }
00154 else
00155 {
00156 yinc1 = -1;
00157 yinc2 = -1;
00158 }
00159
00160 if (deltax >= deltay)
00161 {
00162 xinc1 = 0;
00163 yinc2 = 0;
00164 den = deltax;
00165 num = deltax / 2;
00166 numadd = deltay;
00167 numpixels = deltax;
00168 }
00169 else
00170 {
00171 xinc2 = 0;
00172 yinc1 = 0;
00173 den = deltay;
00174 num = deltay / 2;
00175 numadd = deltax;
00176 numpixels = deltay;
00177 }
00178
00179 for (int curpixel = 0; curpixel <= numpixels; curpixel++)
00180 {
00181 point_cost = pointCost(x, y);
00182
00183 if(point_cost < 0)
00184 return -1;
00185
00186 if(line_cost < point_cost)
00187 line_cost = point_cost;
00188
00189 num += numadd;
00190 if (num >= den)
00191 {
00192 num -= den;
00193 x += xinc1;
00194 y += yinc1;
00195 }
00196 x += xinc2;
00197 y += yinc2;
00198 }
00199
00200 return line_cost;
00201 }
00202
00203 double SafeTrajectoryPlanner::pointCost(int x, int y){
00204 unsigned char cost = costmap_.getCost(x, y);
00205
00206 if(cost == LETHAL_OBSTACLE || cost == INSCRIBED_INFLATED_OBSTACLE || cost == NO_INFORMATION){
00207 return -1;
00208 }
00209
00210 return cost;
00211 }
00212
00213
00214 Trajectory SafeTrajectoryPlanner::createTrajectories(double x, double y, double theta,
00215 double vx, double vy, double vtheta,
00216 double acc_x, double acc_y, double acc_theta,
00217 double dx, double dy, double dtheta){
00218
00219 double max_vel_x, max_vel_y, max_vel_theta;
00220 double min_vel_x, min_vel_y, min_vel_theta;
00221
00222
00223 if(dwa_){
00224 max_vel_x = min(max_vel_x_, vx + acc_x * .1);
00225 min_vel_x = max(min_vel_x_, vx - acc_x * .1);
00226
00227 max_vel_y = min(max_vel_y_, vy + acc_y * .1);
00228 min_vel_y = max(min_vel_y_, vy - acc_y * .1);
00229
00230 max_vel_theta = min(max_vel_th_, vtheta + acc_theta * .1);
00231 min_vel_theta = max(min_vel_th_, vtheta - acc_theta * .1);
00232 } else {
00233 max_vel_x = min(max_vel_x_, vx + acc_x * sim_time_);
00234 min_vel_x = max(min_vel_x_, vx - acc_x * sim_time_);
00235
00236 max_vel_y = min(max_vel_y_, vy + acc_y * sim_time_);
00237 min_vel_y = max(min_vel_y_, vy - acc_y * sim_time_);
00238
00239 max_vel_theta = min(max_vel_th_, vtheta + acc_theta * sim_time_);
00240 min_vel_theta = max(min_vel_th_, vtheta - acc_theta * sim_time_);
00241 }
00242
00243
00244 Trajectory* best_traj = &traj_one;
00245 best_traj->cost_ = -1.0;
00246
00247 Trajectory* comp_traj = &traj_two;
00248 comp_traj->cost_ = -1.0;
00249
00250 Trajectory* swap = NULL;
00251
00252
00253 double impossible_cost = map_.obstacleCosts();
00254
00255
00256 generateTrajectory(x, y, theta, vx, vy, vtheta, dx, dy, dtheta, acc_x, acc_y, acc_theta, impossible_cost, dx, dy, dtheta, *comp_traj);
00257
00258
00259 if(comp_traj->cost_ >= 0 && (comp_traj->cost_ < best_traj->cost_ || best_traj->cost_ < 0)){
00260 swap = best_traj;
00261 best_traj = comp_traj;
00262 comp_traj = swap;
00263 }
00264
00265
00266 double dvx = (max_vel_x - min_vel_x) / (vx_samples_ - 1);
00267 double dvy = (max_vel_y - min_vel_y) / (vy_samples_ - 1);
00268 double dvtheta = (max_vel_theta - min_vel_theta) / (vtheta_samples_ - 1);
00269
00270 double vx_samp = 0.0;
00271 double vy_samp = 0.0;
00272 double vtheta_samp = 0.0;
00273
00274 if (holonomic_robot_) {
00275
00276 vx_samp = min_vel_x;
00277 for(int i = 0; i < vx_samples_; ++i){
00278 vy_samp = 0;
00279 vtheta_samp = 0;
00280
00281 generateTrajectory(x, y, theta, vx, vy, vtheta, vx_samp, vy_samp, vtheta_samp, acc_x, acc_y, acc_theta, impossible_cost, dx, dy, dtheta, *comp_traj);
00282
00283
00284 if(comp_traj->cost_ >= 0 && (comp_traj->cost_ < best_traj->cost_ || best_traj->cost_ < 0)){
00285 swap = best_traj;
00286 best_traj = comp_traj;
00287 comp_traj = swap;
00288 }
00289
00290 vy_samp = min_vel_y;
00291 for (int k = 0; k < vy_samples_; k++) {
00292 vtheta_samp = 0;
00293
00294 generateTrajectory(x, y, theta, vx, vy, vtheta, vx_samp, vy_samp, vtheta_samp, acc_x, acc_y, acc_theta, impossible_cost, dx, dy, dtheta, *comp_traj);
00295
00296
00297 if(comp_traj->cost_ >= 0 && (comp_traj->cost_ < best_traj->cost_ || best_traj->cost_ < 0)){
00298 swap = best_traj;
00299 best_traj = comp_traj;
00300 comp_traj = swap;
00301 }
00302
00303
00304 vtheta_samp = min_vel_theta;
00305
00306 for(int j = 0; j < vtheta_samples_ - 1; ++j){
00307 generateTrajectory(x, y, theta, vx, vy, vtheta, vx_samp, vy_samp, vtheta_samp, acc_x, acc_y, acc_theta, impossible_cost, dx, dy, dtheta, *comp_traj);
00308
00309
00310 if(comp_traj->cost_ >= 0 && (comp_traj->cost_ < best_traj->cost_ || best_traj->cost_ < 0)){
00311 swap = best_traj;
00312 best_traj = comp_traj;
00313 comp_traj = swap;
00314 }
00315 vtheta_samp += dvtheta;
00316 }
00317 vy_samp += dvy;
00318 }
00319 vx_samp += dvx;
00320 }
00321 } else {
00322 vy_samp = 0.0;
00323
00324 vx_samp = min_vel_x;
00325 for(int i = 0; i < vx_samples_; ++i){
00326 vtheta_samp = 0;
00327
00328 generateTrajectory(x, y, theta, vx, vy, vtheta, vx_samp, vy_samp, vtheta_samp, acc_x, acc_y, acc_theta, impossible_cost, dx, dy, dtheta, *comp_traj);
00329
00330
00331 if(comp_traj->cost_ >= 0 && (comp_traj->cost_ < best_traj->cost_ || best_traj->cost_ < 0)){
00332 swap = best_traj;
00333 best_traj = comp_traj;
00334 comp_traj = swap;
00335 }
00336
00337 vtheta_samp = min_vel_theta;
00338
00339 for(int j = 0; j < vtheta_samples_ - 1; ++j){
00340 generateTrajectory(x, y, theta, vx, vy, vtheta, vx_samp, vy_samp, vtheta_samp, acc_x, acc_y, acc_theta, impossible_cost, dx, dy, dtheta, *comp_traj);
00341
00342
00343 if(comp_traj->cost_ >= 0 && (comp_traj->cost_ < best_traj->cost_ || best_traj->cost_ < 0)){
00344 swap = best_traj;
00345 best_traj = comp_traj;
00346 comp_traj = swap;
00347 }
00348 vtheta_samp += dvtheta;
00349
00350 }
00351 vx_samp += dvx;
00352 }
00353 }
00354
00355
00356
00357 return *best_traj;
00358 }
00359
00360
00361 Trajectory SafeTrajectoryPlanner::findBestPath(tf::Stamped<tf::Pose> global_pose, tf::Stamped<tf::Pose> global_vel,
00362 tf::Stamped<tf::Pose> user_vel, tf::Stamped<tf::Pose>& drive_velocities){
00363
00364 double yaw = tf::getYaw(global_pose.getRotation());
00365 double vel_yaw = tf::getYaw(global_vel.getRotation());
00366 double dyaw = tf::getYaw(user_vel.getRotation());
00367
00368 double x = global_pose.getOrigin().getX();
00369 double y = global_pose.getOrigin().getY();
00370 double theta = yaw;
00371
00372 double vx = global_vel.getOrigin().getX();
00373 double vy = global_vel.getOrigin().getY();
00374 double vtheta = vel_yaw;
00375
00376 double dx = user_vel.getOrigin().getX();
00377 double dy = user_vel.getOrigin().getY();
00378 double dtheta = dyaw;
00379
00380
00381 map_.resetPathDist();
00382
00383
00384 vector<base_local_planner::Position2DInt> footprint_list = getFootprintCells(x, y, theta, true);
00385
00386
00387 for(unsigned int i = 0; i < footprint_list.size(); ++i){
00388 map_(footprint_list[i].x, footprint_list[i].y).within_robot = true;
00389 }
00390
00391
00392 Trajectory best = createTrajectories(x, y, theta, vx, vy, vtheta, acc_lim_x_, acc_lim_y_, acc_lim_theta_, dx, dy, dtheta);
00393 ROS_DEBUG("Trajectories created");
00394
00395 if(best.cost_ < 0) {
00396 drive_velocities.setIdentity();
00397 ROS_INFO("No safe trajectory found");
00398 }
00399 else {
00400 tf::Vector3 start(best.xv_, best.yv_, 0);
00401 drive_velocities.setOrigin(start);
00402 tf::Matrix3x3 matrix;
00403 matrix.setRotation(tf::createQuaternionFromYaw(best.thetav_));
00404 drive_velocities.setBasis(matrix);
00405 }
00406
00407 return best;
00408 }
00409
00410 Trajectory SafeTrajectoryPlanner::findPath(tf::Stamped<tf::Pose> global_pose, tf::Stamped<tf::Pose> global_vel,
00411 tf::Stamped<tf::Pose> user_vel){
00412
00413 double yaw = tf::getYaw(global_pose.getRotation());
00414 double vel_yaw = tf::getYaw(global_vel.getRotation());
00415 double dyaw = tf::getYaw(user_vel.getRotation());
00416
00417 double x = global_pose.getOrigin().getX();
00418 double y = global_pose.getOrigin().getY();
00419 double theta = yaw;
00420
00421 double vx = global_vel.getOrigin().getX();
00422 double vy = global_vel.getOrigin().getY();
00423 double vtheta = vel_yaw;
00424
00425 double dx = user_vel.getOrigin().getX();
00426 double dy = user_vel.getOrigin().getY();
00427 double dtheta = dyaw;
00428
00429
00430 map_.resetPathDist();
00431
00432
00433 vector<base_local_planner::Position2DInt> footprint_list = getFootprintCells(x, y, theta, true);
00434
00435
00436 for(unsigned int i = 0; i < footprint_list.size(); ++i){
00437 map_(footprint_list[i].x, footprint_list[i].y).within_robot = true;
00438 }
00439
00440 Trajectory traj;
00441 double impossible_cost = map_.obstacleCosts();
00442 generateTrajectory(x, y, theta, vx, vy, vtheta, dx, dy, dtheta,
00443 acc_lim_x_, acc_lim_y_, acc_lim_theta_, impossible_cost, dx, dy, dtheta, traj);
00444
00445 return traj;
00446 }
00447
00448
00449 double SafeTrajectoryPlanner::footprintCost(double x_i, double y_i, double theta_i){
00450
00451 double cos_th = cos(theta_i);
00452 double sin_th = sin(theta_i);
00453 vector<geometry_msgs::Point> oriented_footprint;
00454 for(unsigned int i = 0; i < footprint_spec_.size(); ++i){
00455 geometry_msgs::Point new_pt;
00456 new_pt.x = x_i + (footprint_spec_[i].x * cos_th - footprint_spec_[i].y * sin_th);
00457 new_pt.y = y_i + (footprint_spec_[i].x * sin_th + footprint_spec_[i].y * cos_th);
00458 oriented_footprint.push_back(new_pt);
00459 }
00460
00461 geometry_msgs::Point robot_position;
00462 robot_position.x = x_i;
00463 robot_position.y = y_i;
00464
00465
00466 double footprint_cost = world_model_.footprintCost(robot_position, oriented_footprint, inscribed_radius_, circumscribed_radius_);
00467
00468 return footprint_cost;
00469 }
00470
00471 void SafeTrajectoryPlanner::getLineCells(int x0, int x1, int y0, int y1, vector<base_local_planner::Position2DInt>& pts){
00472
00473 int deltax = abs(x1 - x0);
00474 int deltay = abs(y1 - y0);
00475 int x = x0;
00476 int y = y0;
00477
00478 int xinc1, xinc2, yinc1, yinc2;
00479 int den, num, numadd, numpixels;
00480
00481 base_local_planner::Position2DInt pt;
00482
00483 if (x1 >= x0)
00484 {
00485 xinc1 = 1;
00486 xinc2 = 1;
00487 }
00488 else
00489 {
00490 xinc1 = -1;
00491 xinc2 = -1;
00492 }
00493
00494 if (y1 >= y0)
00495 {
00496 yinc1 = 1;
00497 yinc2 = 1;
00498 }
00499 else
00500 {
00501 yinc1 = -1;
00502 yinc2 = -1;
00503 }
00504
00505 if (deltax >= deltay)
00506 {
00507 xinc1 = 0;
00508 yinc2 = 0;
00509 den = deltax;
00510 num = deltax / 2;
00511 numadd = deltay;
00512 numpixels = deltax;
00513 }
00514 else
00515 {
00516 xinc2 = 0;
00517 yinc1 = 0;
00518 den = deltay;
00519 num = deltay / 2;
00520 numadd = deltax;
00521 numpixels = deltay;
00522 }
00523
00524 for (int curpixel = 0; curpixel <= numpixels; curpixel++)
00525 {
00526 pt.x = x;
00527 pt.y = y;
00528 pts.push_back(pt);
00529
00530 num += numadd;
00531 if (num >= den)
00532 {
00533 num -= den;
00534 x += xinc1;
00535 y += yinc1;
00536 }
00537 x += xinc2;
00538 y += yinc2;
00539 }
00540 }
00541
00542
00543 vector<base_local_planner::Position2DInt> SafeTrajectoryPlanner::getFootprintCells(double x_i, double y_i, double theta_i, bool fill){
00544 vector<base_local_planner::Position2DInt> footprint_cells;
00545
00546
00547 if(footprint_spec_.size() <= 1){
00548 unsigned int mx, my;
00549 if(costmap_.worldToMap(x_i, y_i, mx, my)){
00550 Position2DInt center;
00551 center.x = mx;
00552 center.y = my;
00553 footprint_cells.push_back(center);
00554 }
00555 return footprint_cells;
00556 }
00557
00558
00559 double cos_th = cos(theta_i);
00560 double sin_th = sin(theta_i);
00561 double new_x, new_y;
00562 unsigned int x0, y0, x1, y1;
00563 unsigned int last_index = footprint_spec_.size() - 1;
00564
00565 for(unsigned int i = 0; i < last_index; ++i){
00566
00567 new_x = x_i + (footprint_spec_[i].x * cos_th - footprint_spec_[i].y * sin_th);
00568 new_y = y_i + (footprint_spec_[i].x * sin_th + footprint_spec_[i].y * cos_th);
00569 if(!costmap_.worldToMap(new_x, new_y, x0, y0))
00570 return footprint_cells;
00571
00572
00573 new_x = x_i + (footprint_spec_[i + 1].x * cos_th - footprint_spec_[i + 1].y * sin_th);
00574 new_y = y_i + (footprint_spec_[i + 1].x * sin_th + footprint_spec_[i + 1].y * cos_th);
00575 if(!costmap_.worldToMap(new_x, new_y, x1, y1))
00576 return footprint_cells;
00577
00578 getLineCells(x0, x1, y0, y1, footprint_cells);
00579 }
00580
00581
00582 new_x = x_i + (footprint_spec_[last_index].x * cos_th - footprint_spec_[last_index].y * sin_th);
00583 new_y = y_i + (footprint_spec_[last_index].x * sin_th + footprint_spec_[last_index].y * cos_th);
00584 if(!costmap_.worldToMap(new_x, new_y, x0, y0))
00585 return footprint_cells;
00586
00587 new_x = x_i + (footprint_spec_[0].x * cos_th - footprint_spec_[0].y * sin_th);
00588 new_y = y_i + (footprint_spec_[0].x * sin_th + footprint_spec_[0].y * cos_th);
00589 if(!costmap_.worldToMap(new_x, new_y, x1, y1))
00590 return footprint_cells;
00591
00592 getLineCells(x0, x1, y0, y1, footprint_cells);
00593
00594 if(fill)
00595 getFillCells(footprint_cells);
00596
00597 return footprint_cells;
00598 }
00599
00600 void SafeTrajectoryPlanner::getFillCells(vector<base_local_planner::Position2DInt>& footprint){
00601
00602 base_local_planner::Position2DInt swap, pt;
00603 unsigned int i = 0;
00604 while(i < footprint.size() - 1){
00605 if(footprint[i].x > footprint[i + 1].x){
00606 swap = footprint[i];
00607 footprint[i] = footprint[i + 1];
00608 footprint[i + 1] = swap;
00609 if(i > 0)
00610 --i;
00611 }
00612 else
00613 ++i;
00614 }
00615
00616 i = 0;
00617 base_local_planner::Position2DInt min_pt;
00618 base_local_planner::Position2DInt max_pt;
00619 unsigned int min_x = footprint[0].x;
00620 unsigned int max_x = footprint[footprint.size() -1].x;
00621
00622 for(unsigned int x = min_x; x <= max_x; ++x){
00623 if(i >= footprint.size() - 1)
00624 break;
00625
00626 if(footprint[i].y < footprint[i + 1].y){
00627 min_pt = footprint[i];
00628 max_pt = footprint[i + 1];
00629 }
00630 else{
00631 min_pt = footprint[i + 1];
00632 max_pt = footprint[i];
00633 }
00634
00635 i += 2;
00636 while(i < footprint.size() && footprint[i].x == x){
00637 if(footprint[i].y < min_pt.y)
00638 min_pt = footprint[i];
00639 else if(footprint[i].y > max_pt.y)
00640 max_pt = footprint[i];
00641 ++i;
00642 }
00643
00644
00645 for(unsigned int y = min_pt.y; y < max_pt.y; ++y){
00646 pt.x = x;
00647 pt.y = y;
00648 footprint.push_back(pt);
00649 }
00650 }
00651 }
00652
00653 };
00654
00655