00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <angles/angles.h>
00012
00013 #include "navigator_internal.h"
00014 #include "Controller.h"
00015 #include "course.h"
00016 #include "obstacle.h"
00017 #include "uturn.h"
00018
00019 #include "stop.h"
00020
00021 #include <art_map/coordinates.h>
00022 using namespace Coordinates;
00023 #include <art_map/rotate_translate_transform.h>
00024 #include <art_msgs/ArtVehicle.h>
00025 using art_msgs::ArtVehicle;
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 static const char *state_name[] =
00042 {
00043 "Backward",
00044 "Forward",
00045 "Wait",
00046 };
00047
00048 Uturn::Uturn(Navigator *navptr, int _verbose):
00049 Controller(navptr, _verbose)
00050 {
00051 ROS_INFO("vehicle turn radius %.3fm, front, rear wheel radii %.3fm, %.3f",
00052 ArtVehicle::turn_radius,
00053 ArtVehicle::front_outer_wheel_turn_radius,
00054 ArtVehicle::rear_outer_wheel_turn_radius);
00055
00056 stop = new Stop(navptr, _verbose);
00057 reset_me();
00058 }
00059
00060 Uturn::~Uturn()
00061 {
00062
00063 delete stop;
00064 }
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120 bool Uturn::circle_and_line_intersect(MapXY c, float r,
00121 MapXY point1, MapXY point2,
00122 MapXY &meetpt)
00123 {
00124 bool intersects = false;
00125 bool have_roots = false;
00126 MapXY root1, root2;
00127
00128
00129 MapXY p1 = point1 - c;
00130 MapXY p2 = point2 - c;
00131
00132
00133 if (Epsilon::equal(p1.x, p2.x))
00134 {
00135 if (Epsilon::equal(p1.y, p2.y))
00136 {
00137
00138 if (verbose >= 4)
00139 ART_MSG(8, "line segment is a point");
00140 if (Epsilon::equal(r*r, p1.x*p1.x + p1.y*p1.y))
00141 {
00142 have_roots = true;
00143 root1 = p1;
00144 root2 = p1;
00145 }
00146 }
00147 else
00148 {
00149
00150 if (verbose >= 4)
00151 ART_MSG(8, "line segment is vertical");
00152
00153 root1.x = root2.x = p1.x;
00154
00155
00156 float y2 = r*r - root1.x*root1.x;
00157 if (y2 >= 0.0)
00158 {
00159 have_roots = true;
00160 root1.y = sqrtf(y2);
00161 root2.y = -root1.y;
00162 }
00163 }
00164 }
00165 else
00166 {
00167
00168 float s = (p2.y - p1.y) / (p2.x - p1.x);
00169 float k = p1.y - s*p1.x;
00170 float discriminant = 4.0 * (s*s * r*r + r*r - k*k);
00171
00172 if (verbose >= 6)
00173 ART_MSG(8, "discriminant of circle and line y = (%.3f * x + %.3f)"
00174 " is %.3f", s, k, discriminant);
00175
00176
00177 if (discriminant >= 0.0)
00178 {
00179
00180 float a = s*s + 1.0f;
00181 float b = 2.0f * s * k;
00182 float c = k*k - r*r;
00183
00184 if (verbose >= 6)
00185 ART_MSG(8, "y = (%.3f * x^2 + %.3f * x + %.3f)"
00186 " has at least one root", a, b, c);
00187
00188 if (discriminant >= Epsilon::float_value
00189 && fabsf(b) >= Epsilon::float_value)
00190 {
00191
00192
00193
00194
00195
00196
00197 float t = (-(1.0f/2.0f) * (b + sign(b) * sqrtf(discriminant)));
00198 root1.x = t/a;
00199 root2.x = c/t;
00200 }
00201 else
00202 {
00203
00204 root1.x = (-b - sqrtf(discriminant)) / 2 * a;
00205 root2.x = (-b + sqrtf(discriminant)) / 2 * a;
00206 }
00207
00208
00209 root1.y = s*root1.x + k;
00210 root2.y = s*root2.x + k;
00211 have_roots = true;
00212 }
00213 }
00214
00215 if (have_roots)
00216 {
00217 if (verbose >= 6)
00218 ART_MSG(8, "circle intersects (%.3f,%.3f), (%.3f,%.3f) at (%.3f,%.3f)"
00219 " and (%.3f,%.3f)",
00220 p1.x, p1.y, p2.x, p2.y,
00221 root1.x, root1.y, root2.x, root2.y);
00222
00223
00224 bool r1_valid = Euclidean::point_in_line_segment(root1, p1, p2);
00225 bool r2_valid = Euclidean::point_in_line_segment(root2, p1, p2);
00226
00227 intersects = (r1_valid || r2_valid);
00228
00229
00230 if (r1_valid && r2_valid)
00231 {
00232
00233 if (Euclidean::DistanceTo(root1, p1)
00234 <= Euclidean::DistanceTo(root2, p1))
00235 meetpt = root1 + c;
00236 else
00237 meetpt = root2 + c;
00238 }
00239 else if (r1_valid)
00240 {
00241 meetpt = root1 + c;
00242 }
00243 else if (r2_valid)
00244 {
00245 meetpt = root2 + c;
00246 }
00247 }
00248
00249 if (intersects)
00250 {
00251 if (verbose >= 4)
00252 ART_MSG(8, "U-turn intersects (%.3f,%.3f), (%.3f,%.3f) at (%.3f,%.3f)",
00253 point1.x, point1.y, point2.x, point2.y,
00254 meetpt.x, meetpt.y);
00255 }
00256 else if (verbose >= 5)
00257 ART_MSG(8, "U-turn does not intersect (%.3f,%.3f), (%.3f,%.3f)",
00258 point1.x, point1.y, point2.x, point2.y);
00259
00260 return intersects;
00261 }
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279 Controller::result_t Uturn::control(pilot_command_t &pcmd)
00280 {
00281
00282
00283 course->no_waypoint_reached();
00284
00285 result_t result = OK;
00286 if (do_init)
00287 {
00288 result = initialize();
00289 if (result == NotApplicable)
00290 return result;
00291 }
00292
00293 if (verbose >= 2)
00294 {
00295
00296 ART_MSG(5, "U-turn from near waypoint %s to %s, state is %s",
00297 uturn_exit.start_way.name().str,
00298 uturn_entry.start_way.name().str,
00299 state_name[state]);
00300 }
00301
00302
00303 pcmd.velocity = fminf(pcmd.velocity, config_->uturn_speed);
00304 pcmd.yawRate = config_->uturn_yaw_rate;
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314 float remaining_angle = normalize(goal_heading
00315 - MapPose(estimate->pose.pose).yaw);
00316 if (remaining_angle < -HALFPI)
00317 remaining_angle += TWOPI;
00318
00319 float desired_arc_length = remaining_angle * ArtVehicle::turn_radius;
00320 ROS_DEBUG("%.3f radians (%.f degrees) remain for U-turn, %.3fm arc",
00321 remaining_angle, angles::to_degrees(remaining_angle),
00322 desired_arc_length);
00323
00324 switch (state)
00325 {
00326 case Wait:
00327
00328 if (obstacle->observer_clear(Observation::Adjacent_left))
00329 {
00330 if (verbose)
00331 ART_MSG(1, "U-turn entry lane clear");
00332 set_state(Forward);
00333 }
00334 else
00335 {
00336
00337 if (verbose)
00338 ART_MSG(2, "U-turn entry lane blocked");
00339 }
00340 pcmd.velocity = 0.0;
00341 break;
00342
00343 case Forward:
00344 {
00345 if (outside_lanes_front())
00346 {
00347 if (navdata->stopped)
00348 {
00349 set_state(Backward);
00350 navdata->reverse = true;
00351 }
00352 pcmd.velocity = 0.0;
00353 break;
00354 }
00355
00356 float arc_length = estimate_uturn_distance(true, desired_arc_length);
00357 #if 0
00358 if (remaining_angle <= config_->uturn_stop_heading
00359 || arc_length > desired_arc_length)
00360 #else // Pat's way (Pat want to make sure we are catching this on
00361
00362 if (fabs(Coordinates::normalize(remaining_angle)) <= config_->uturn_stop_heading)
00363 #endif
00364 {
00365
00366
00367
00368
00369 result = Finished;
00370 break;
00371 }
00372
00373 if (stop->control(pcmd, arc_length,
00374 config_->uturn_threshold, config_->uturn_speed) == Finished)
00375 {
00376 set_state(Backward);
00377 navdata->reverse = true;
00378 }
00379 }
00380 break;
00381
00382 case Backward:
00383 if (outside_lanes_rear()
00384 || (!outside_lanes_front()
00385 && (estimate_uturn_distance(true, desired_arc_length)
00386 > desired_arc_length)))
00387 {
00388
00389
00390
00391 if (navdata->stopped)
00392 {
00393 set_state(Forward);
00394 navdata->reverse = false;
00395 }
00396 pcmd.velocity = 0.0;
00397 }
00398 else
00399 {
00400
00401 float arc_length = estimate_uturn_distance(false,
00402 desired_arc_length);
00403
00404
00405 if (stop->control(pcmd, arc_length, config_->uturn_threshold) == Finished)
00406 {
00407
00408 set_state(Forward);
00409 navdata->reverse = false;
00410 }
00411 }
00412 break;
00413 };
00414
00415 #if 0 // not using safety controller yet
00416
00417 result_t sresult = safety->control(pcmd);
00418 if (result != Finished)
00419 result = sresult;
00420
00421
00422 if (sresult == Blocked)
00423 switch (state) {
00424 case Forward:
00425 set_state(Backward);
00426 navdata->reverse = true;
00427 break;
00428 case Backward:
00429 set_state(Forward);
00430 navdata->reverse = false;
00431 break;
00432 default:
00433 break;
00434 }
00435 #endif // not using safety controller yet
00436
00437 trace("uturn controller", pcmd, result);
00438
00439 return result;
00440 };
00441
00442 float Uturn::calculate_arc_length(bool forward,
00443 const MapXY& center,
00444 float safety_radius,
00445 const MapXY& p1,
00446 const MapXY& p2)
00447 {
00448 MapXY curb_point;
00449
00450 float arc_length=Infinite::distance;
00451
00452
00453
00454
00455
00456
00457
00458 if (circle_and_line_intersect(center, safety_radius, p1, p2, curb_point))
00459 {
00460
00461 float curb_bearing = bearing(center, curb_point);
00462 float car_bearing;
00463 if (forward)
00464 {
00465
00466 Polar front_axle(0.0, ArtVehicle::wheelbase);
00467 car_bearing =
00468 bearing(center,
00469 Polar_to_MapXY(front_axle,
00470 MapPose(estimate->pose.pose)));
00471 }
00472 else
00473 {
00474
00475 car_bearing = bearing(center, MapXY(estimate->pose.pose.position));
00476 }
00477
00478
00479
00480 float arc = curb_bearing - car_bearing;
00481 while (arc < 0.0)
00482 arc += TWOPI;
00483
00484
00485 arc_length = arc * ArtVehicle::turn_radius;
00486
00487 if (verbose >= 5)
00488 ART_MSG(5, "U-turn arc length %.3fm, bearing radians [%.3f,%.3f]",
00489 arc_length, car_bearing, curb_bearing);
00490 }
00491 return arc_length;
00492 }
00493
00494
00495
00496
00497
00498
00499
00500 float Uturn::estimate_uturn_distance(bool forward, float desired_arc_length)
00501 {
00502
00503 MapXY center;
00504 float safety_radius;
00505 if (forward)
00506 {
00507
00508 center = Polar_to_MapXY(Polar(HALFPI, ArtVehicle::turn_radius),
00509 MapPose(estimate->pose.pose));
00510 safety_radius = ArtVehicle::front_outer_wheel_turn_radius;
00511 }
00512 else
00513 {
00514
00515 center = Polar_to_MapXY(Polar(-HALFPI, ArtVehicle::turn_radius),
00516 MapPose(estimate->pose.pose));
00517 safety_radius = ArtVehicle::rear_outer_wheel_turn_radius;
00518 }
00519
00520 if (verbose >= 2)
00521 ART_MSG(5, "U-turn circle center going %s is (%.3f,%.3f)",
00522 (forward? "forward": "backward"), center.x, center.y);
00523
00524 float min_arc_length = Infinite::distance;
00525
00526
00527 for (unsigned pidx = 0; pidx < uturn_polys.size(); ++pidx)
00528 {
00529 MapXY p1 = uturn_polys.at(pidx).p4;
00530 MapXY p2 = uturn_polys.at(pidx).p3;
00531
00532 float arc_length =
00533 calculate_arc_length(forward,center,safety_radius,p1,p2);
00534 min_arc_length = fminf(arc_length, min_arc_length);
00535 }
00536
00537 if (min_arc_length < desired_arc_length)
00538 {
00539 if (verbose >= 4)
00540 ART_MSG(5, "U-turn %s arc intersects in %.3fm",
00541 (forward? "forward": "backward"), min_arc_length);
00542 return min_arc_length;
00543 }
00544
00545 int index=pops->getClosestPoly(uturn_polys,uturn_entry.midpoint);
00546 if (index >= 0)
00547 {
00548 MapXY p1 = uturn_polys.at(index).p4;
00549 MapXY p2 = uturn_polys.at(index).p3;
00550
00551 MapXY mid=pops->midpoint(p1,p2);
00552 posetype origin(0,0,0);
00553 posetype origin_abs(mid.x,mid.y,bearing(p1,p2));
00554
00555 posetype far(300,0,0);
00556
00557 rotate_translate_transform long_trans;
00558 long_trans.find_transform(origin, origin_abs);
00559 posetype far_abs=long_trans.apply_transform(far);
00560 far.x*=-1;
00561 posetype nfar_abs=long_trans.apply_transform(far);
00562
00563 p2.x=far_abs.x;
00564 p2.y=far_abs.y;
00565 p1.x=nfar_abs.x;
00566 p1.y=nfar_abs.y;
00567
00568
00569 float arc_length =
00570 calculate_arc_length(forward,center,safety_radius,p1,p2);
00571 min_arc_length = fminf(arc_length, min_arc_length);
00572 }
00573
00574 index=pops->getClosestPoly(uturn_polys,uturn_exit.midpoint);
00575 if (index >= 0)
00576 {
00577 MapXY p1 = uturn_polys.at(index).p4;
00578 MapXY p2 = uturn_polys.at(index).p3;
00579
00580 MapXY mid=pops->midpoint(p1,p2);
00581 posetype origin(0,0,0);
00582 posetype origin_abs(mid.x,mid.y,bearing(p1,p2));
00583
00584 posetype far(300,0,0);
00585
00586 rotate_translate_transform long_trans;
00587 long_trans.find_transform(origin, origin_abs);
00588 posetype far_abs=long_trans.apply_transform(far);
00589 far.x*=-1;
00590 posetype nfar_abs=long_trans.apply_transform(far);
00591
00592 p2.x=far_abs.x;
00593 p2.y=far_abs.y;
00594 p1.x=nfar_abs.x;
00595 p1.y=nfar_abs.y;
00596
00597 float arc_length =
00598 calculate_arc_length(forward,center,safety_radius,p1,p2);
00599 min_arc_length = fminf(arc_length, min_arc_length);
00600 }
00601
00602 if (min_arc_length < Infinite::distance)
00603 {
00604 if (verbose >= 4)
00605 ART_MSG(5, "U-turn %s arc intersects in %.3fm",
00606 (forward? "forward": "backward"), min_arc_length);
00607 }
00608 else
00609 {
00610 if (verbose >= 5)
00611 ART_MSG(2, "U-turn %s arc does not intersect curb locally",
00612 (forward? "forward": "backward"));
00613 }
00614
00615 return min_arc_length;
00616 }
00617
00618
00619 Controller::result_t Uturn::initialize(void)
00620 {
00621 poly_list_t current_lane_polys, left_lane_polys;
00622
00623
00624 pops->AddLanePolys(course->polygons, current_lane_polys,
00625 order->waypt[0].id);
00626
00627 int uturn_exit_index =
00628 pops->getClosestPoly(current_lane_polys,
00629 MapPose(estimate->pose.pose));
00630
00631 int uturn_entry_index=-1;
00632
00633 if (uturn_exit_index >= 0)
00634 {
00635 MapXY exit_pose;
00636 exit_pose = current_lane_polys.at(uturn_exit_index).midpoint;
00637 pops->AddLanePolys(course->polygons, left_lane_polys,
00638 order->waypt[1].id);
00639 uturn_entry_index = pops->getClosestPoly(left_lane_polys, exit_pose);
00640 }
00641
00642 if (uturn_exit_index < 0 || uturn_entry_index < 0)
00643 {
00644 ROS_ERROR("no U-turn according to polygons: %d %d",
00645 uturn_exit_index, uturn_entry_index);
00646 return NotApplicable;
00647 }
00648
00649 do_init = false;
00650
00651 uturn_exit = current_lane_polys.at(uturn_exit_index);
00652 uturn_entry = left_lane_polys.at(uturn_entry_index);
00653
00654 for (uint i=0; i<current_lane_polys.size();i++)
00655 if (Euclidean::DistanceTo(current_lane_polys[i].midpoint,
00656 uturn_exit.midpoint) <= 15.0)
00657 uturn_polys.push_back(current_lane_polys[i]);
00658
00659 for (uint i=0; i<left_lane_polys.size();i++)
00660 if (Euclidean::DistanceTo(left_lane_polys[i].midpoint,
00661 uturn_entry.midpoint) <= 15.0)
00662 uturn_polys.push_back(left_lane_polys[i]);
00663
00664
00665
00666
00667 course->log("U-turn", uturn_polys);
00668
00669 if (uturn_polys.empty())
00670 return NotApplicable;
00671
00672
00673 int p_index = pops->getContainingPoly(uturn_polys, uturn_entry.midpoint);
00674 if (p_index < 0)
00675 {
00676 ART_ERROR("no polygon for U-turn entry waypoint.");
00677 return NotApplicable;
00678 }
00679
00680
00681 goal_heading = pops->PolyHeading(uturn_polys.at(p_index));
00682
00683 return OK;
00684 }
00685
00686
00687 bool Uturn::outside_lanes_front(void)
00688 {
00689 if (point_outside_lanes(wheel_location(ArtVehicle::front_right_wheel_px,
00690 ArtVehicle::front_right_wheel_py)))
00691 {
00692 if (verbose >= 3)
00693 ART_MSG(6, "right front wheel is outside the U-turn lanes");
00694 return true;
00695 }
00696
00697 if (point_outside_lanes(wheel_location(ArtVehicle::front_left_wheel_px,
00698 ArtVehicle::front_left_wheel_py)))
00699 {
00700 if (verbose >= 3)
00701 ART_MSG(6, "left front wheel is outside the U-turn lanes");
00702 return true;
00703 }
00704
00705 return false;
00706 }
00707
00708
00709 bool Uturn::outside_lanes_rear(void)
00710 {
00711 if (point_outside_lanes(wheel_location(ArtVehicle::rear_right_wheel_px,
00712 ArtVehicle::rear_right_wheel_py)))
00713 {
00714 if (verbose >= 3)
00715 ART_MSG(6, "right rear wheel is outside the U-turn lanes");
00716 return true;
00717 }
00718
00719 if (point_outside_lanes(wheel_location(ArtVehicle::rear_left_wheel_px,
00720 ArtVehicle::rear_left_wheel_py)))
00721 {
00722 if (verbose >= 3)
00723 ART_MSG(6, "left rear wheel is outside the U-turn lanes");
00724 return true;
00725 }
00726
00727 return false;
00728 }
00729
00730
00731 bool Uturn::point_outside_lanes(MapXY point)
00732 {
00733 int pindex = pops->getClosestPoly(uturn_polys, point);
00734 if (pindex < 0)
00735 return true;
00736
00737 poly nearest = uturn_polys.at(pindex);
00738
00739
00740 float point_bearing = normalize(bearing(nearest.p4, point)
00741 - bearing(nearest.p4, nearest.p3));
00742
00743 if (point_bearing >= 0.0)
00744 return false;
00745
00746 if (verbose >= 4)
00747 ART_MSG(7, "point (%.3f %.3f) is outside nearest polygon, %d",
00748 point.x, point.y, nearest.poly_id);
00749
00750 return true;
00751 }
00752
00753
00754 void Uturn::reset(void)
00755 {
00756 trace_reset("Uturn");
00757 reset_me();
00758
00759 stop->reset();
00760 }
00761
00762
00763 void Uturn::reset_me(void)
00764 {
00765 navdata->reverse = false;
00766 state = Wait;
00767 do_init = true;
00768 uturn_polys.clear();
00769 }
00770
00771
00772 void Uturn::set_state(state_t newstate)
00773 {
00774 if (state != newstate)
00775 {
00776 if (verbose)
00777 ART_MSG(4, "U-turn state changing from %s to %s",
00778 state_name[state], state_name[newstate]);
00779 state = newstate;
00780 }
00781 }
00782
00783
00784 MapXY Uturn::wheel_location(float x, float y)
00785 {
00786 posetype vehicle_relative(0, 0, 0);
00787 posetype wheel_relative(x, y, 0);
00788 MapPose pose2d(estimate->pose.pose);
00789 posetype vehicle_map(pose2d.map.x, pose2d.map.y, pose2d.yaw);
00790 rotate_translate_transform trans;
00791 trans.find_transform(vehicle_relative, vehicle_map);
00792 posetype wheel_map = trans.apply_transform(wheel_relative);
00793 return MapXY(wheel_map.x, wheel_map.y);
00794 }