00001
00010 #include <string.h>
00011 #include <vector>
00012 #include <queue>
00013 #include <stdint.h>
00014 #include <ros/ros.h>
00015 #include <math.h>
00016 #include <cstdlib>
00017
00018 #include <purepursuit_planner/Component.h>
00019 #include <ackermann_msgs/AckermannDriveStamped.h>
00020 #include <nav_msgs/Odometry.h>
00021 #include <tf/transform_broadcaster.h>
00022 #include <tf/transform_listener.h>
00023 #include "diagnostic_msgs/DiagnosticStatus.h"
00024 #include "diagnostic_updater/diagnostic_updater.h"
00025 #include "diagnostic_updater/update_functions.h"
00026 #include "diagnostic_updater/DiagnosticStatusWrapper.h"
00027 #include "diagnostic_updater/publisher.h"
00028 #include <actionlib/server/simple_action_server.h>
00029 #include <planner_msgs/GoToAction.h>
00030 #include <planner_msgs/goal.h>
00031 #include <geometry_msgs/Pose2D.h>
00032
00033
00034
00035 #define ODOM_TIMEOUT_ERROR 0.2 // max num. of seconds without receiving odom values
00036 #define MAP_TIMEOUT_ERROR 0.2 // max num. of seconds without receiving map transformations
00037 #define AGVS_TURN_RADIUS 0.20 // distancia en la que empieza a girar el robot cuando llega a una esquina
00038 #define MIN_ANGLE_BEZIER 0.261799388 // ángulo (radianes) mínimo entre segmentos de la recta para los que ajustaremos a una curva de BEZIER
00039 #define BEZIER_CONTROL_POINTS 5
00040
00041 #define D_LOOKAHEAD_MIN 0.3 // Minima distancia del punto objetivo en m (PurePursuit con lookahead dinámico)
00042 #define D_LOOKAHEAD_MAX 1.1 // Maxima distancia del punto objetivo
00043 #define D_WHEEL_ROBOT_CENTER 0.478 // Distance from the motor wheel to the robot center
00044
00045 #define MAX_SPEED_LVL1 0.5
00046 #define MAX_SPEED_LVL2 0.3
00047 #define MAX_SPEED 1.2
00048
00049 #define WAYPOINT_POP_DISTANCE_M 0.10 //Distancia mínima para alcanzar punto objetivo m (PurePursuit)
00050
00051 #define AGVS_FIRST_DECELERATION_DISTANCE 0.5 // meters -> when the vehicle is arriving to the goal, it has to decelarate at this distance
00052 #define AGVS_FIRST_DECELERATION_MAXSPEED 0.15 // m/s
00053 #define AGVS_SECOND_DECELERATION_DISTANCE 0.25 // meters -> when the vehicle is arriving to the goal, it has to decelarate another time at this distance
00054 #define AGVS_SECOND_DECELERATION_MAXSPEED 0.1 // m/s
00055 #define AGVS_DEFAULT_KR 0.20 //
00056
00057 enum{
00058 ODOM_SOURCE = 1,
00059 MAP_SOURCE = 2
00060 };
00061
00062 using namespace std;
00063
00065 typedef struct MagnetStruct{
00067 int iID;
00069 double dX;
00071 double dY;
00072 }MagnetStruct;
00073
00075 typedef struct Waypoint{
00077 int iID;
00079 double dX;
00081 double dY;
00083 double dA;
00085 double dSpeed;
00086 }Waypoint;
00087
00089 class Path{
00090 public:
00092 int iCurrentWaypoint;
00094 int iCurrentMagnet;
00095
00096 private:
00098 pthread_mutex_t mutexPath;
00100 vector <Waypoint> vPoints;
00102 vector <MagnetStruct> vMagnets;
00104 bool bOptimized;
00105
00106 public:
00107
00109 Path(){
00110 iCurrentWaypoint = iCurrentMagnet = -1;
00111 pthread_mutex_init(&mutexPath, NULL);
00112 bOptimized = false;
00113 }
00114
00116 ~Path(){
00117 pthread_mutex_destroy(&mutexPath);
00118 }
00119
00121 ReturnValue AddWaypoint(Waypoint point){
00122 Waypoint aux;
00123
00124 pthread_mutex_lock(&mutexPath);
00125 if(vPoints.size() > 0){
00126 aux = vPoints.back();
00127
00128 if( (aux.dX != point.dX) || (aux.dY != point.dY) )
00129 vPoints.push_back(point);
00130 } else {
00131 if(iCurrentWaypoint < 0){
00132 iCurrentWaypoint = 0;
00133 }
00134
00135 vPoints.push_back(point);
00136 }
00137
00138 pthread_mutex_unlock(&mutexPath);
00139
00140 return OK;
00141 }
00142
00144 ReturnValue AddWaypoint(vector <Waypoint> po){
00145 pthread_mutex_lock(&mutexPath);
00146 if(iCurrentWaypoint < 0){
00147 iCurrentWaypoint = 0;
00148 }
00149 for(int i = 0; i < po.size(); i++){
00150 vPoints.push_back(po[i]);
00151 }
00152 pthread_mutex_unlock(&mutexPath);
00153 }
00154
00156 ReturnValue AddMagnet(MagnetStruct magnet){
00157 pthread_mutex_lock(&mutexPath);
00158 if(iCurrentMagnet < 0){
00159 iCurrentMagnet = 0;
00160 }
00161 vMagnets.push_back(magnet);
00162 pthread_mutex_unlock(&mutexPath);
00163
00164 return OK;
00165 }
00166
00168 ReturnValue AddMagnet(vector <MagnetStruct> po){
00169 pthread_mutex_lock(&mutexPath);
00170 if(iCurrentMagnet < 0){
00171 iCurrentMagnet = 0;
00172 }
00173 for(int i = 0; i < po.size(); i++){
00174 vMagnets.push_back(po[i]);
00175 }
00176 pthread_mutex_unlock(&mutexPath);
00177 }
00178
00180 void Clear(){
00181 pthread_mutex_lock(&mutexPath);
00182 iCurrentWaypoint = -1;
00183 iCurrentMagnet = -1;
00184 bOptimized = false;
00185 vPoints.clear();
00186 vMagnets.clear();
00187 pthread_mutex_unlock(&mutexPath);
00188 }
00189
00191 unsigned int Size(){
00192 return vPoints.size();
00193 }
00194
00196 ReturnValue GetNextWaypoint(Waypoint *wp){
00197 ReturnValue ret = ERROR;
00198
00199 pthread_mutex_lock(&mutexPath);
00200
00201 if( (iCurrentWaypoint >= 0) && (iCurrentWaypoint < (vPoints.size() - 1)) ){
00202 *wp = vPoints[iCurrentWaypoint + 1];
00203 ret = OK;
00204 }
00205
00206 pthread_mutex_unlock(&mutexPath);
00207
00208 return ret;
00209 }
00210
00212 ReturnValue BackWaypoint(Waypoint *wp){
00213 ReturnValue ret = ERROR;
00214
00215 pthread_mutex_lock(&mutexPath);
00216 if( vPoints.size() > 0){
00217 *wp = vPoints.back();
00218 ret = OK;
00219 }
00220 pthread_mutex_unlock(&mutexPath);
00221
00222 return ret;
00223 }
00224
00226 ReturnValue GetCurrentWaypoint(Waypoint *wp){
00227 ReturnValue ret = ERROR;
00228
00229 pthread_mutex_lock(&mutexPath);
00230 if( (iCurrentWaypoint >= 0) && (iCurrentWaypoint < vPoints.size()) ){
00231 *wp = vPoints[iCurrentWaypoint];
00232 ret = OK;
00233 }
00234 pthread_mutex_unlock(&mutexPath);
00235
00236 return ret;
00237 }
00238
00240 ReturnValue GetWaypoint(int index, Waypoint *wp){
00241 ReturnValue ret = ERROR;
00242
00243 pthread_mutex_lock(&mutexPath);
00244 if( (index >= 0) && ( index< vPoints.size() ) ){
00245 *wp = vPoints[index];
00246 ret = OK;
00247 }
00248 pthread_mutex_unlock(&mutexPath);
00249
00250 return ret;
00251 }
00252
00254 int GetCurrentWaypointIndex(){
00255 return iCurrentWaypoint;
00256 }
00257
00259 ReturnValue SetCurrentWaypoint(int index){
00260 ReturnValue ret = ERROR;
00261
00262 if(index < (vPoints.size() - 1)){
00263 pthread_mutex_lock(&mutexPath);
00264 iCurrentWaypoint = index;
00265 pthread_mutex_unlock(&mutexPath);
00266 ret = OK;
00267 }
00268
00269 return ret;
00270 }
00271
00273 void NextWaypoint(){
00274 pthread_mutex_lock(&mutexPath);
00275 iCurrentWaypoint++;
00276 pthread_mutex_unlock(&mutexPath);
00277 }
00278
00280 int NumOfWaypoints(){
00281 return vPoints.size();
00282 }
00283
00285 ReturnValue GetNextMagnet(MagnetStruct *mg){
00286 ReturnValue ret = ERROR;
00287 pthread_mutex_lock(&mutexPath);
00288
00289 if( (iCurrentMagnet >= 0) && (iCurrentMagnet < (vMagnets.size() - 1)) ){
00290 *mg = vMagnets[iCurrentMagnet + 1];
00291 ret = OK;
00292 }
00293
00294 pthread_mutex_unlock(&mutexPath);
00295
00296
00297 return ret;
00298 }
00299
00301 ReturnValue BackMagnet(MagnetStruct * mg){
00302 ReturnValue ret = ERROR;
00303
00304 pthread_mutex_lock(&mutexPath);
00305 if( vMagnets.size() > 0){
00306 *mg = vMagnets.back();
00307 ret = OK;
00308 }
00309 pthread_mutex_unlock(&mutexPath);
00310
00311 return ret;
00312 }
00313
00315 ReturnValue GetCurrentMagnet( MagnetStruct * mg ){
00316 ReturnValue ret = ERROR;
00317
00318 pthread_mutex_lock(&mutexPath);
00319 if( (iCurrentMagnet >= 0) && (iCurrentMagnet < vMagnets.size()) ){
00320 *mg = vMagnets[iCurrentMagnet];
00321 ret = OK;
00322 }
00323 pthread_mutex_unlock(&mutexPath);
00324
00325 return ret;
00326 }
00327
00329 ReturnValue GetPreviousMagnet( MagnetStruct * mg ){
00330 ReturnValue ret = ERROR;
00331
00332 pthread_mutex_lock(&mutexPath);
00333 if( (iCurrentMagnet > 0) && (iCurrentMagnet <= vMagnets.size()) ){
00334 *mg = vMagnets[iCurrentMagnet-1];
00335 ret = OK;
00336 }
00337 pthread_mutex_unlock(&mutexPath);
00338
00339 return ret;
00340 }
00341
00343 int GetCurrentMagnetIndex(){
00344 return iCurrentMagnet;
00345 }
00346
00348 ReturnValue SetCurrentMagnet(int index){
00349 ReturnValue ret = ERROR;
00350
00351 if(index < (vMagnets.size() - 1)){
00352 pthread_mutex_lock(&mutexPath);
00353 iCurrentMagnet = index;
00354 pthread_mutex_unlock(&mutexPath);
00355 ret = OK;
00356 }
00357 return ret;
00358 }
00359
00361 void NextMagnet(){
00362 pthread_mutex_lock(&mutexPath);
00363 iCurrentMagnet++;
00364 pthread_mutex_unlock(&mutexPath);
00365 }
00366
00368 ReturnValue GetLastMagnet( MagnetStruct * mg ){
00369 ReturnValue ret = ERROR;
00370
00371 pthread_mutex_lock(&mutexPath);
00372 if( (iCurrentMagnet > 0) && (iCurrentMagnet <= vMagnets.size() ) ){
00373 *mg = vMagnets[iCurrentMagnet - 1];
00374 ret = OK;
00375 }
00376 pthread_mutex_unlock(&mutexPath);
00377
00378 return ret;
00379 }
00380
00382 int NumOfMagnets(){
00383 return vMagnets.size();
00384 }
00385
00387 Path &operator+=(const Path &a){
00388 AddWaypoint(a.vPoints);
00389 AddMagnet(a.vMagnets);
00390 return *this;
00391 }
00392
00394 double dot2( Waypoint w, Waypoint v) {
00395 return (w.dX*v.dX + w.dY*v.dY);
00396 }
00397
00404 Waypoint PosOnQuadraticBezier(Waypoint cp0, Waypoint cp1, Waypoint cp2, float t){
00405 Waypoint aux;
00406
00407
00408
00409 aux.dX = (1.0-t)*(1.0-t)*cp0.dX + 2*t*(1.0-t)*cp1.dX + t*t*cp2.dX;
00410
00411 aux.dY = (1.0-t)*(1.0-t)*cp0.dY + 2*t*(1.0-t)*cp1.dY + t*t*cp2.dY;
00412
00413 return aux;
00414 }
00415
00419 double DistForSpeed(double target_speed){
00420 if(target_speed > 1.0)
00421 return 2.0;
00422 else if(target_speed > 0.8)
00423 return 1.5;
00424 else return
00425 1.0;
00426
00427 }
00428
00433 ReturnValue Optimize(double distance){
00434 int i, j=0;
00435 int a, b, c;
00436 int x = 0, y = 1, speed = 2;
00437 double mod_ab, mod_bc;
00438 double dAngle;
00439 Waypoint ab, bc, ba;
00440 double K= 0.0;
00441 vector <Waypoint> new_points;
00442 Waypoint aux;
00443 double Ax = 0.0, Ay = 0.0, Bx = 0.0, By = 0.0, Cx = 0.0, Cy = 0.0;
00444 Waypoint A, B, C;
00445 double Kt = 1.0 / BEZIER_CONTROL_POINTS;
00446 double dAuxSpeed = 0.0;
00447 double dMinDist = 0.0;
00448
00449 if(bOptimized){
00450 return OK;
00451 }
00452
00453 if((vPoints.size() < 2) || (distance <= 0.0)){
00454
00455 return ERROR;
00456 }
00457 pthread_mutex_lock(&mutexPath);
00458
00459
00460 if(vPoints.size() == 2){
00461 aux = vPoints[1];
00462 vPoints.push_back(aux);
00463 if((vPoints[0].dX - aux.dX) == 0.0){
00464 vPoints[1].dX = vPoints[0].dX;
00465 vPoints[1].dY = vPoints[0].dY + (aux.dY - vPoints[0].dY) / 2.0;
00466 }else if((vPoints[0].dY - aux.dY) == 0.0){
00467 vPoints[1].dX = vPoints[0].dX + (aux.dX - vPoints[0].dX) / 2.0;
00468 vPoints[1].dY = vPoints[0].dY;
00469 }else{
00470 vPoints[1].dX = vPoints[0].dX + (aux.dX - vPoints[0].dX) / 2.0;
00471 vPoints[1].dY = vPoints[0].dY + (aux.dY - vPoints[0].dY) / 2.0;
00472 }
00473 }
00474
00475 new_points.push_back(vPoints[0]);
00476 new_points.push_back(vPoints[1]);
00477
00478 for(i=2; i < vPoints.size(); i++){
00479
00480 a = i-2;
00481 b = i-1;
00482 c = i;
00483
00484 Ax = vPoints[a].dX;
00485 Ay = vPoints[a].dY;
00486 Bx = vPoints[b].dX;
00487 By = vPoints[b].dY;
00488 Cx = vPoints[c].dX;
00489 Cy = vPoints[c].dY;
00490
00491 ab.dX = Bx - Ax;
00492 ab.dY = By - Ay;
00493 mod_ab = sqrt(ab.dX * ab.dX + ab.dY * ab.dY);
00494
00495 bc.dX = Cx - Bx;
00496 bc.dY = Cy - By;
00497 mod_bc = sqrt(bc.dX * bc.dX + bc.dY * bc.dY);
00498
00499 dAngle= acos(dot2(ab,bc)/(mod_ab*mod_bc));
00500
00501 if(fabs(dAngle) >= MIN_ANGLE_BEZIER){
00502
00503
00504
00505
00506 new_points.pop_back();
00507
00508
00509 if(fabs(dAngle) >= (Pi/4)){
00510 dAuxSpeed = MAX_SPEED_LVL2;
00511 }else
00512 dAuxSpeed = MAX_SPEED_LVL1;
00513
00514
00515 if(fabs(vPoints[b].dSpeed) > dAuxSpeed){
00516
00517 if(vPoints[b].dSpeed < 0.0)
00518 dAuxSpeed = -dAuxSpeed;
00519
00520 dMinDist = DistForSpeed(fabs(vPoints[b].dSpeed));
00521
00522
00523 if( mod_ab > dMinDist){
00524
00525 ba.dX = -ab.dX;
00526 ba.dY = -ab.dY;
00527 K = dMinDist / sqrt(ba.dX * ba.dX + ba.dY * ba.dY);
00528
00529 aux.dX = Bx + K * ba.dX;
00530 aux.dY = By + K * ba.dY;
00531 aux.dSpeed = vPoints[b].dSpeed;
00532
00533 new_points.push_back(aux);
00534 }
00535
00536 vPoints[b].dSpeed = dAuxSpeed;
00537
00538 }
00539
00540 if(mod_ab > distance){
00541
00542 ba.dX = -ab.dX;
00543 ba.dY = -ab.dY;
00544 K = distance / sqrt(ba.dX * ba.dX + ba.dY * ba.dY);
00545
00546 aux.dX = Bx + K * ba.dX;
00547 aux.dY = By + K * ba.dY;
00548 aux.dSpeed = vPoints[b].dSpeed;
00549
00550 new_points.push_back(aux);
00551
00552 }
00553
00554 new_points.push_back(vPoints[b]);
00555
00556 if(mod_bc > distance){
00557
00558 K = distance / sqrt(bc.dX * bc.dX + bc.dY * bc.dY);
00559 aux.dX = Bx + K * bc.dX;
00560 aux.dY = By + K * bc.dY;
00561 aux.dSpeed = vPoints[b].dSpeed;
00562
00563
00564 new_points.push_back(aux);
00565 }
00566
00567
00568 if(dMinDist > 0.0) {
00569 if(mod_bc > 1.0){
00570
00571
00572 K = 1.0 / sqrt(bc.dX * bc.dX + bc.dY * bc.dY);
00573 aux.dX = Bx + K * bc.dX;
00574 aux.dY = By + K * bc.dY;
00575 aux.dSpeed = vPoints[b].dSpeed;
00576 new_points.push_back(aux);
00577 }else{
00578
00579 vPoints[c].dSpeed = vPoints[b].dSpeed;
00580 }
00581 }
00582
00583
00584 new_points.push_back(vPoints[c]);
00585
00586 }else{
00587
00588 new_points.push_back(vPoints[c]);
00589
00590 }
00591 }
00592
00593
00594 vPoints.clear();
00595
00596
00597 vPoints.push_back(new_points[0]);
00598 vPoints.push_back(new_points[1]);
00599 for(i=2; i < new_points.size(); i++){
00600 a = i-2;
00601 b = i-1;
00602 c = i;
00603
00604 Ax = new_points[a].dX;
00605 Ay = new_points[a].dY;
00606 Bx = new_points[b].dX;
00607 By = new_points[b].dY;
00608 Cx = new_points[c].dX;
00609 Cy = new_points[c].dY;
00610
00611 ab.dX = Bx - Ax;
00612 ab.dY = By - Ay;
00613 mod_ab = sqrt(ab.dX * ab.dX + ab.dY * ab.dY);
00614
00615 bc.dX = Cx - Bx;
00616 bc.dY = Cy - By;
00617 mod_bc = sqrt(bc.dX * bc.dX + bc.dY * bc.dY);
00618
00619 dAngle= acos(dot2(ab,bc)/(mod_ab*mod_bc));
00620
00621 if(fabs(dAngle) >= MIN_ANGLE_BEZIER){
00622
00623
00624 Waypoint aux_wp;
00625 double t, aux_speed;
00626
00627 A = new_points[a];
00628 B = new_points[b];
00629 C = new_points[c];
00630
00631 aux_speed = new_points[b].dSpeed;
00632 vPoints.pop_back();
00633
00634 for(int j=1; j <= BEZIER_CONTROL_POINTS; j++) {
00635 t = (double) j * Kt;
00636 aux_wp = PosOnQuadraticBezier(A, B, C, t);
00637 aux_wp.dSpeed = aux_speed;
00638 vPoints.push_back(aux_wp);
00639
00640
00641 }
00642 }else{
00643
00644 vPoints.push_back(new_points[c]);
00645 }
00646 }
00647
00648 iCurrentWaypoint = 0;
00649
00650
00651
00652
00653
00654 pthread_mutex_unlock(&mutexPath);
00655
00656 bOptimized = true;
00657 new_points.clear();
00658
00659 return OK;
00660 }
00662 void Print(){
00663 cout << "Path::Print: Printing all the waypoints..." << endl;
00664 if(vPoints.size() > 0){
00665 for(int i = 0; i < vPoints.size(); i++){
00666 cout << "(" << i << ")\t " << vPoints[i].dX << ", " << vPoints[i].dY << endl;
00667 }
00668 }else
00669 cout << "Path::Print: No waypoints..." << endl;
00670 }
00671
00672 };
00673
00674
00675 class purepursuit_planner_node: public Component
00676 {
00677
00678 private:
00679 ros::NodeHandle node_handle_;
00680 ros::NodeHandle private_node_handle_;
00681 double desired_freq_;
00683 double Kr;
00684
00686 double dLookAhead;
00688 Path pathCurrent;
00690 Path pathFilling;
00692 queue <Path> qPath;
00694 geometry_msgs::Pose2D pose2d_robot;
00696 nav_msgs::Odometry odometry_robot;
00698 double dLinearSpeed;
00700 double d_lookahear_min_, d_lookahear_max_;
00702 double d_dist_wheel_to_center_;
00704 double max_speed_;
00706 bool bEnabled;
00708 bool bCancel;
00710 std::string position_source_;
00712 unsigned int ui_position_source;
00713
00716 ros::Publisher status_pub_;
00719 ros::Publisher vel_pub_;
00721 ros::Publisher tranform_map_pub_;
00723 ros::Subscriber odom_sub_;
00725 std::string odom_topic_;
00727 std::string cmd_topic_vel_;
00728
00730 diagnostic_updater::TopicDiagnostic *updater_diagnostic_odom;
00732 diagnostic_updater::Updater updater_diagnostic;
00734 double min_odom_freq, max_odom_freq;
00736 ros::Time last_command_time, last_map_time;
00737
00738 actionlib::SimpleActionServer<planner_msgs::GoToAction> action_server_goto;
00739 planner_msgs::GoToFeedback goto_feedback;
00740 planner_msgs::GoToResult goto_result;
00741 planner_msgs::GoToGoal goto_goal;
00742
00743 tf::TransformListener listener;
00744 tf::StampedTransform transform;
00745
00747 std::string name_sc_enable_front_laser_, name_sc_enable_back_laser_;
00749 ros::ServiceClient sc_enable_front_laser_;
00751 ros::ServiceClient sc_enable_back_laser_;
00752
00753 public:
00754
00758 purepursuit_planner_node(ros::NodeHandle h) : node_handle_(h), private_node_handle_("~"),
00759 desired_freq_(100.0),Component(desired_freq_),action_server_goto(node_handle_, ros::this_node::getName(), false)
00760
00761 {
00762 bRunning = false;
00763
00764 ROSSetup();
00765
00766 dLookAhead = d_lookahear_min_;
00767 dLinearSpeed = 0;
00768 pose2d_robot.x = pose2d_robot.y = pose2d_robot.theta = 0.0;
00769 bEnabled = true;
00770 bCancel = false;
00771
00772 sComponentName.assign("purepursuit_planner_node");
00773 iState = INIT_STATE;
00774 }
00775
00779 ~purepursuit_planner_node(){
00780
00781 }
00782
00786 void ROSSetup(){
00787 private_node_handle_.param<std::string>("odom_topic", odom_topic_, "/odom");
00788 private_node_handle_.param("cmd_topic_vel", cmd_topic_vel_, std::string("/agvs_controller/command"));
00789 private_node_handle_.param("d_lookahear_min", d_lookahear_min_, D_LOOKAHEAD_MIN);
00790 private_node_handle_.param("d_lookahear_max", d_lookahear_max_, D_LOOKAHEAD_MAX);
00791 private_node_handle_.param("d_dist_wheel_to_center", d_dist_wheel_to_center_, D_WHEEL_ROBOT_CENTER);
00792 private_node_handle_.param("max_speed", max_speed_, MAX_SPEED);
00793 private_node_handle_.param("kr", Kr, AGVS_DEFAULT_KR);
00794 private_node_handle_.param<std::string>("position_source", position_source_, "ODOM");
00795 private_node_handle_.param("desired_freq", desired_freq_, desired_freq_);
00796
00797
00798
00799
00800
00801 threadData.dDesiredHz = desired_freq_;
00802
00803 if(position_source_ == "MAP")
00804 ui_position_source = MAP_SOURCE;
00805 else
00806 ui_position_source = ODOM_SOURCE;
00807
00808
00809
00810 vel_pub_ = private_node_handle_.advertise<ackermann_msgs::AckermannDriveStamped>(cmd_topic_vel_, 1);
00811
00812 if(ui_position_source == MAP_SOURCE)
00813 tranform_map_pub_ = private_node_handle_.advertise<geometry_msgs::TransformStamped>("map_location", 100);
00814
00815 odom_sub_ = private_node_handle_.subscribe<nav_msgs::Odometry>(odom_topic_, 1, &purepursuit_planner_node::OdomCallback, this );
00816
00817
00818
00819 updater_diagnostic.setHardwareID("PurePursuit-Planner");
00820
00821 min_odom_freq = 5.0;
00822 max_odom_freq = 100.0;
00823 updater_diagnostic_odom = new diagnostic_updater::TopicDiagnostic(odom_topic_, updater_diagnostic,
00824 diagnostic_updater::FrequencyStatusParam(&min_odom_freq, &max_odom_freq, 0.1, 10),
00825 diagnostic_updater::TimeStampStatusParam(0.001, 0.1));
00826
00827
00828
00829 action_server_goto.registerGoalCallback(boost::bind(&purepursuit_planner_node::GoalCB, this));
00830 action_server_goto.registerPreemptCallback(boost::bind(&purepursuit_planner_node::PreemptCB, this));
00831
00832
00833
00834
00835
00836 ROS_INFO("%s::ROSSetup(): odom_topic = %s, command_topic_vel = %s, position source = %s, desired_hz=%.1lf, min_lookahead = %.1lf, max_lookahead = %.1lf, kr = %.2lf", sComponentName.c_str(), odom_topic_.c_str(),
00837 cmd_topic_vel_.c_str(), position_source_.c_str(), desired_freq_, d_lookahear_min_, d_lookahear_max_, Kr);
00838
00839
00840
00841
00842 }
00843
00844
00848 ReturnValue Setup(){
00849
00850 if(bInitialized){
00851 ROS_INFO("purepursuit_planner::Setup: Already initialized");
00852 return INITIALIZED;
00853 }
00854
00855
00856 action_server_goto.start();
00857
00858 bInitialized = true;
00859
00860 return OK;
00861 }
00862
00863
00867 int ReadAndPublish()
00868 {
00869
00870 updater_diagnostic.update();
00871 return(0);
00872 }
00873
00877 ReturnValue Start(){
00878
00879 if(bRunning){
00880 ROS_INFO("agvs_controller::Start: the component's thread is already running");
00881 return THREAD_RUNNING;
00882 }
00883
00884
00885 bRunning = true;
00886 return OK;
00887 }
00888
00892 ReturnValue Stop(){
00893
00894 if(!bRunning){
00895 ROS_INFO("agvs_controller::Stop: Thread not running");
00896
00897 return THREAD_NOT_RUNNING;
00898 }
00899
00900 bRunning = false;
00901
00902 return OK;
00903 }
00904
00905
00908 void ControlThread()
00909 {
00910 ROS_INFO("purepursuit_planner::ControlThread(): Init");
00911 ros::Rate r(desired_freq_);
00912
00913
00914
00915 while(ros::ok()) {
00916
00917 switch(iState){
00918
00919 case INIT_STATE:
00920 InitState();
00921 break;
00922
00923 case STANDBY_STATE:
00924 StandbyState();
00925 break;
00926
00927 case READY_STATE:
00928 ReadyState();
00929 break;
00930
00931 case SHUTDOWN_STATE:
00932 ShutDownState();
00933 break;
00934
00935 case EMERGENCY_STATE:
00936 EmergencyState();
00937 break;
00938
00939 case FAILURE_STATE:
00940 FailureState();
00941 break;
00942
00943 }
00944
00945 AllState();
00946
00947 ros::spinOnce();
00948 r.sleep();
00949 }
00950 ShutDownState();
00951
00952 ROS_INFO("purepursuit_planner::ControlThread(): End");
00953
00954 }
00955
00956
00959 void InitState(){
00960
00961 if(bInitialized && bRunning){
00962 if(CheckOdomReceive() == 0)
00963 SwitchToState(STANDBY_STATE);
00964 }else{
00965 if(!bInitialized)
00966 Setup();
00967 if(!bRunning)
00968 Start();
00969 }
00970
00971 }
00972
00975 void StandbyState(){
00976 if(CheckOdomReceive() == -1)
00977 SwitchToState(EMERGENCY_STATE);
00978 else{
00979 if(bEnabled && !bCancel ){
00980
00981 if(pathCurrent.Size() > 0 || MergePath() == OK){
00982 ROS_INFO("%s::StandbyState: route available", sComponentName.c_str());
00983 SwitchToState(READY_STATE);
00984 }
00985 }
00986
00987 }
00988 }
00989
00992 void ReadyState(){
00993 if(CheckOdomReceive() == -1){
00994 SetRobotSpeed(0.0, 0.0);
00995 SwitchToState(EMERGENCY_STATE);
00996 return;
00997 }
00998 if(!bEnabled){
00999 ROS_INFO("%s::ReadyState: Motion is disabled", sComponentName.c_str());
01000 SetRobotSpeed(0.0, 0.0);
01001 SwitchToState(STANDBY_STATE);
01002 return;
01003 }
01004 if(bCancel){
01005 ROS_INFO("%s::ReadyState: Cancel requested", sComponentName.c_str());
01006 SetRobotSpeed(0.0, 0.0);
01007 SwitchToState(STANDBY_STATE);
01008 return;
01009 }
01010
01011 int ret = PurePursuit();
01012
01013 if(ret == -1){
01014 ROS_ERROR("%s::ReadyState: Error on PurePursuit", sComponentName.c_str());
01015 bCancel = true;
01016 SetRobotSpeed(0.0, 0.0);
01017 goto_result.route_result = -1;
01018 goto_feedback.percent_complete = 100.0;
01019
01020 SwitchToState(STANDBY_STATE);
01021
01022 }else if(ret == 1){
01023 ROS_INFO("%s::ReadyState: Route finished", sComponentName.c_str());
01024 SetRobotSpeed(0.0, 0.0);
01025 goto_result.route_result = 0;
01026 goto_feedback.percent_complete = 100.0;
01027 SwitchToState(STANDBY_STATE);
01028 }
01029
01030
01031 }
01032
01033
01037 void UpdateLookAhead(){
01038 double aux_lookahead = fabs(dLinearSpeed);
01039 double desired_lookahead = 0.0;
01040 double inc = 0.01;
01041
01042 if(aux_lookahead < d_lookahear_min_)
01043 desired_lookahead = d_lookahear_min_;
01044 else if(aux_lookahead > d_lookahear_max_)
01045 desired_lookahead = d_lookahear_max_;
01046 else{
01047 desired_lookahead = aux_lookahead;
01048 }
01049
01050 if((desired_lookahead - 0.001) > dLookAhead){
01051 dLookAhead+= inc;
01052 }else if((desired_lookahead + 0.001) < dLookAhead)
01053 dLookAhead-= inc;
01054 }
01055
01056
01061 double Dot2( double x1, double y1, double x2, double y2) {
01062 return (x1*x2 + y1*y2);
01063 }
01064
01065
01069 double Dist(double x1, double y1, double x2, double y2) {
01070 double diff_x = (x2 - x1);
01071 double diff_y = (y2 - y1);
01072 return sqrt( diff_x*diff_x + diff_y*diff_y );
01073 }
01074
01080 double DistP2S( geometry_msgs::Pose2D current_position, Waypoint s0, Waypoint s1, Waypoint *Pb){
01081 double vx,vy, wx, wy;
01082
01083 double c1, c2, di, b;
01084
01085 vx = s1.dX - s0.dX;
01086 vy = s1.dY - s0.dY;
01087
01088 wx = current_position.x - s0.dX;
01089 wy = current_position.y - s0.dY;
01090
01091 c1 = Dot2( wx, wy, vx, vy );
01092
01093 if ( c1 <= 0.0 ) {
01094 di = Dist(current_position.x, current_position.y, s0.dX, s0.dY);
01095 Pb->dX = s0.dX;
01096 Pb->dY = s0.dY;
01097 return di;
01098 }
01099
01100 c2 = Dot2(vx,vy, vx, vy);
01101
01102 if ( c2 <= c1 ) {
01103
01104 di = Dist(current_position.x, current_position.y, s1.dX, s1.dY);
01105 Pb->dX = s1.dY;
01106 Pb->dY = s1.dY;
01107 return di;
01108 }
01109
01110 b = c1 / c2;
01111 Pb->dX = s0.dX + b * vx;
01112 Pb->dY = s0.dY + b * vy;
01113
01114 di = Dist(current_position.x, current_position.y, Pb->dX, Pb->dY);
01115
01116 return di;
01117 }
01118
01119
01125 ReturnValue PointDlh(geometry_msgs::Pose2D current_position, geometry_msgs::Pose2D *wp) {
01126 int i,j=0,k;
01127 double dmin, d, d1, d2, *d_seg;
01128 double t;
01129 geometry_msgs::Pose2D target_position;
01130 Waypoint s0, s1, Pb, Pb1;
01131
01132 int size = pathCurrent.NumOfWaypoints();
01133
01134 d_seg = new double[size];
01135
01136
01137 dmin = 100000000;
01138
01139 for(i = pathCurrent.GetCurrentWaypointIndex(); i < (size -1); i++) {
01140 if( (pathCurrent.GetWaypoint(i, &s0) == OK) && (pathCurrent.GetWaypoint(i+1, &s1) == OK) ){
01141 d_seg[i] = Dist(s0.dX, s0.dY, s1.dX, s1.dY);
01142
01143 d = DistP2S(current_position, s0, s1, &Pb1);
01144
01145 if (d < dmin) {
01146 Pb.dX = Pb1.dX;
01147 Pb.dY = Pb1.dY;
01148 dmin = d;
01149 j = i;
01150 }
01151
01152
01153 }else{
01154 ROS_ERROR("%s::PointDlh: Error Getting waypoints", sComponentName.c_str());
01155 return ERROR;
01156 }
01157 }
01158
01159
01160
01161
01162 if(pathCurrent.GetCurrentWaypointIndex() != j){
01163
01164 if(pathCurrent.SetCurrentWaypoint(j) == ERROR){
01165 ROS_ERROR("%s::PointDlh: Error setting current waypoint to %d", sComponentName.c_str(), j);
01166 return ERROR;
01167 }else{
01168
01169 if(j == (size - 2)){
01170 Waypoint w_last, w_before_last;
01171 pathCurrent.GetCurrentWaypoint(&w_before_last);
01172 pathCurrent.BackWaypoint(&w_last);
01173
01174
01175
01176 }
01177
01178 }
01179 }
01180
01181
01182 if( pathCurrent.GetNextWaypoint(&s1) != OK ){
01183 ROS_ERROR("%s::PointDlh: Error getting next waypoint %d", sComponentName.c_str(), j);
01184 return ERROR;
01185 }
01186
01187 d1 = Dist(Pb.dX, Pb.dY, s1.dX, s1.dY);
01188
01189 k = j;
01190 while ( (d1 < dLookAhead) && ( (k+1) < (size - 1) ) ) {
01191
01192 k = k + 1;
01193 d1 = d1 + d_seg[k];
01194 }
01195
01196
01197 d2 = ( d1 - dLookAhead );
01198 t = (d_seg[k] - d2) / d_seg[k];
01199
01200
01201 if( (pathCurrent.GetWaypoint(k, &s0) == OK) && (pathCurrent.GetWaypoint(k + 1, &s1) == OK) ) {
01202
01203 target_position.x = s0.dX + ( s1.dX - s0.dX )*t;
01204 target_position.y = s0.dY + ( s1.dY - s0.dY )*t;
01205 double angle_segment = atan2(s1.dY - s0.dY, s1.dX - s0.dX);
01206
01207 radnorm(&angle_segment);
01208
01209 target_position.theta = angle_segment;
01210 *wp = target_position;
01211
01212 delete d_seg;
01213
01214 return OK;
01215 }else{
01216 ROS_ERROR("%s::PointDlh: Error getting next waypoint %d", sComponentName.c_str(), j);
01217 return ERROR;
01218 }
01219
01220 }
01221
01222
01231 int PurePursuit(){
01232 double dx, dy, x1, y1;
01233 double curv, yaw;
01234 double wref;
01235
01236 double Kd = 1.1;
01237 Waypoint last_waypoint, next_waypoint;
01238
01239 double dAuxSpeed = 0.0;
01240 double dth;
01241 double aux = 0.0, dDistCovered = 0.0;
01242 int ret = 0;
01243
01244 geometry_msgs::Pose2D current_position = this->pose2d_robot;
01245 geometry_msgs::Pose2D next_position;
01246
01247 if(pathCurrent.NumOfWaypoints() < 2) {
01248 ROS_ERROR("%s::PurePursuit: not enought waypoints", sComponentName.c_str());
01249 return -1 ;
01250 }
01251
01252 yaw = current_position.theta;
01253
01254
01255
01256 UpdateLookAhead();
01257
01258
01259
01260 if(PointDlh(current_position, &next_position) != OK){
01261 ROS_ERROR("%s::PurePursuit: Error getting next point in the route", sComponentName.c_str());
01262 return -1;
01263 }
01264
01265
01266 dx = current_position.x - next_position.x;
01267 dy = current_position.y - next_position.y;
01268 x1 = cos(yaw)*dx + sin(yaw)*dy;
01269 y1 = -sin(yaw)*dx + cos(yaw)*dy;
01270
01271 if ((x1*x1 + y1*y1) == 0)
01272 curv = 0;
01273 else
01274 curv = (2.0 / (x1*x1 + y1*y1)) * -y1;
01275
01276
01277 wref = atan(d_dist_wheel_to_center_/(1.0/curv));
01278
01279
01280 if(pathCurrent.BackWaypoint(&last_waypoint) == ERROR){
01281 ROS_ERROR("%s::PurePursuit: Error getting the last point in the path", sComponentName.c_str());
01282 return -1;
01283 }
01284
01285 double dAuxDist = Dist(current_position.x, current_position.y, last_waypoint.dX, last_waypoint.dY);
01286
01287 if(pathCurrent.GetNextWaypoint(&next_waypoint) == ERROR){
01288 ROS_ERROR("%s::PurePursuit: Error getting next waypoint in the path", sComponentName.c_str());
01289 return -1;
01290 }
01291
01292 dAuxSpeed = next_waypoint.dSpeed;
01293
01294 if (dAuxSpeed >= 0)
01295 dth = next_position.theta - current_position.theta;
01296 else
01297 dth = -(next_position.theta + Pi - current_position.theta);
01298
01299
01300 radnorm(&dth);
01301 double aux_wref = wref;
01302 wref += Kr * dth;
01303
01304
01305
01306
01307
01310
01311 if(fabs(dAuxSpeed) > max_speed_){
01312 if(dAuxSpeed > 0)
01313 dAuxSpeed = max_speed_;
01314 else
01315 dAuxSpeed = -max_speed_;
01316 }
01317
01318
01319 if(dAuxDist <= AGVS_SECOND_DECELERATION_DISTANCE) {
01320 if( (dAuxSpeed < 0.0) && (dAuxSpeed < -AGVS_SECOND_DECELERATION_MAXSPEED) )
01321 dAuxSpeed = -AGVS_SECOND_DECELERATION_MAXSPEED;
01322 else if( (dAuxSpeed > 0.0) && (dAuxSpeed > AGVS_SECOND_DECELERATION_MAXSPEED) )
01323 dAuxSpeed = AGVS_SECOND_DECELERATION_MAXSPEED;
01324
01325 }else if(dAuxDist <= AGVS_FIRST_DECELERATION_DISTANCE) {
01326 if( (dAuxSpeed < 0.0) && (dAuxSpeed < AGVS_FIRST_DECELERATION_MAXSPEED))
01327 dAuxSpeed = -AGVS_FIRST_DECELERATION_MAXSPEED;
01328 else if( (dAuxSpeed > 0.0) && (dAuxSpeed > AGVS_FIRST_DECELERATION_MAXSPEED) )
01329 dAuxSpeed = AGVS_FIRST_DECELERATION_MAXSPEED;
01330 }
01331
01332 SetRobotSpeed(dAuxSpeed, wref);
01333
01334
01335
01336 if( pathCurrent.GetCurrentWaypointIndex() >= (pathCurrent.NumOfWaypoints() - 2) ){
01337 ret = -10;
01338 double ddist2 = Dist( current_position.x, current_position.y, last_waypoint.dX, last_waypoint.dY);
01339
01340
01341 if (ddist2 < WAYPOINT_POP_DISTANCE_M) {
01342 SetRobotSpeed(0.0, 0.0);
01343
01344 ROS_INFO("%s::PurePursuit: target position reached (%lf, %lf, %lf). Ending current path", sComponentName.c_str(), current_position.x, current_position.x, current_position.theta*180.0/Pi);
01345
01346 pathCurrent.Clear();
01347 return 1;
01348 }
01349 }
01350
01351 return 0;
01352 }
01353
01357 void CancelPath(){
01358
01359 pathCurrent.Clear();
01360 pathFilling.Clear();
01361 while(!qPath.empty())
01362 qPath.pop();
01363
01364 bCancel = false;
01365
01366 ROS_INFO("%s::CancelPath: action server preempted", sComponentName.c_str());
01367 action_server_goto.setPreempted();
01368 }
01369
01372 void SetRobotSpeed(double speed, double angle){
01373 ackermann_msgs::AckermannDriveStamped ref_msg;
01374
01375 ref_msg.header.stamp = ros::Time::now();
01376 ref_msg.drive.jerk = 0.0;
01377 ref_msg.drive.acceleration = 0.0;
01378 ref_msg.drive.steering_angle_velocity = 0.0;
01379 ref_msg.drive.steering_angle = angle;
01380 ref_msg.drive.speed = speed;
01381
01382 vel_pub_.publish(ref_msg);
01383 }
01384
01385
01388 void ShutDownState(){
01389 if(bRunning)
01390 Stop();
01391 else if(bInitialized)
01392 ShutDown();
01393
01394 }
01395
01398 void EmergencyState(){
01399 if(CheckOdomReceive() == 0){
01400 SwitchToState(STANDBY_STATE);
01401 return;
01402 }
01403
01404 }
01405
01408 void FailureState(){
01409
01410 }
01411
01414 void AllState(){
01415
01416
01417 if(ui_position_source == MAP_SOURCE){
01418 try{
01419 listener.lookupTransform("/map", "/base_link", ros::Time(0), transform);
01420 geometry_msgs::TransformStamped msg;
01421 tf::transformStampedTFToMsg(transform, msg);
01422 pose2d_robot.x = msg.transform.translation.x;
01423 pose2d_robot.y = msg.transform.translation.y;
01424 pose2d_robot.theta = tf::getYaw(msg.transform.rotation);
01425
01426 last_map_time = ros::Time::now();
01427 msg.header.stamp = last_map_time;
01428 tranform_map_pub_.publish(msg);
01429 }catch (tf::TransformException ex){
01430
01431 }
01432 }
01433
01434 AnalyseCB();
01435
01436 ReadAndPublish();
01437
01438 if(bCancel)
01439 CancelPath();
01440 }
01441
01445 void OdomCallback(const nav_msgs::Odometry::ConstPtr& odom_value)
01446 {
01447
01448 last_command_time = ros::Time::now();
01449
01450
01451 if(ui_position_source == ODOM_SOURCE){
01452
01453 pose2d_robot.x = odom_value->pose.pose.position.x;
01454 pose2d_robot.y = odom_value->pose.pose.position.y;
01455 pose2d_robot.theta = tf::getYaw(odom_value->pose.pose.orientation);
01456 }
01457
01458
01459 odometry_robot = *odom_value;
01460
01461 dLinearSpeed = odometry_robot.twist.twist.linear.x;
01462 }
01463
01469 int CheckOdomReceive()
01470 {
01471
01472 if((ros::Time::now() - last_command_time).toSec() > ODOM_TIMEOUT_ERROR)
01473 return -1;
01474 else{
01475 if( ui_position_source == MAP_SOURCE and ((ros::Time::now() - last_map_time).toSec() > MAP_TIMEOUT_ERROR))
01476 return -1;
01477 else return 0;
01478 }
01479
01480 }
01481
01482
01483 void executeCB(const planner_msgs::GoToGoalConstPtr &goal)
01484 {
01485
01486 }
01487
01493 int CalculateDirectionSpeed(Waypoint target_position){
01494 int ret = 1;
01495 double alpha = pose2d_robot.theta;
01496 double x = pose2d_robot.x, y = pose2d_robot.y;
01497 double ux, uy, vx, vy;
01498 double beta = 0.0;
01499 static int last_direction = 0;
01500 static double pi_medios = M_PI / 2.0, max_diff = 5.0 * M_PI / 180.0;
01501 int iCase = 0;
01502
01503
01504
01505 if( (target_position.dX == x) && (target_position.dY == y) ){
01506 return 0;
01507 }
01508
01509 ux = cos(alpha);
01510 uy = sin(alpha);
01511
01512 vx = target_position.dX - x;
01513 vy = target_position.dY - y;
01514
01515
01516 beta = acos( (ux * vx + uy * vy) / ( sqrt(ux*ux + uy*uy) * sqrt(vx*vx + vy*vy) ) );
01517
01518
01519
01520 if(fabs(beta) <= pi_medios){
01521
01522 if(last_direction == 0)
01523 ret = 1;
01524 else {
01525 ret = 1;
01526
01527 if( fabs(beta - pi_medios) <= max_diff){
01528 if(last_direction != ret){
01529 iCase = 1;
01530 ret = -1;
01531
01532 }else {
01533 iCase = 2;
01534 }
01535 }
01536
01537 }
01538 }else{
01539
01540 if(last_direction == 0)
01541 ret = -1;
01542 else {
01543 ret = -1;
01544 if(fabs(beta - pi_medios) <= max_diff){
01545 if(last_direction != ret){
01546 ret = 1;
01547 iCase = 3;
01548 }else{
01549 iCase = 4;
01550 }
01551 }
01552
01553 }
01554 }
01555
01556 ROS_INFO("%s:CalculateDirectionSpeed: case %d. Beta = %.2lf. Diff = %.2lf. Last direction = %d, new direction = %d", sComponentName.c_str(),
01557 iCase, beta*180.0/M_PI, (beta - pi_medios)*180.0/M_PI, last_direction, ret);
01558
01559 last_direction = ret;
01560 return ret;
01561 }
01562
01568 int CalculateDirectionSpeed(geometry_msgs::Pose2D target_position){
01569 int ret = 1;
01570 double alpha = pose2d_robot.theta;
01571 double x = pose2d_robot.x, y = pose2d_robot.y;
01572 double ux, uy, vx, vy;
01573 double beta = 0.0;
01574 static int last_direction = 0;
01575 static double pi_medios = M_PI / 2.0, max_diff = 5.0 * M_PI / 180.0;
01576 int iCase = 0;
01577
01578
01579
01580 if( (target_position.x == x) && (target_position.y == y) ){
01581 return 0;
01582 }
01583
01584 ux = cos(alpha);
01585 uy = sin(alpha);
01586
01587 vx = target_position.x - x;
01588 vy = target_position.y - y;
01589
01590
01591 beta = acos( (ux * vx + uy * vy) / ( sqrt(ux*ux + uy*uy) * sqrt(vx*vx + vy*vy) ) );
01592
01593
01594
01595 if(fabs(beta) <= pi_medios){
01596
01597 if(last_direction == 0)
01598 ret = 1;
01599 else {
01600 ret = 1;
01601
01602 if( fabs(beta - pi_medios) <= max_diff){
01603 if(last_direction != ret){
01604 iCase = 1;
01605 ret = -1;
01606
01607 }else {
01608 iCase = 2;
01609 }
01610 }
01611
01612 }
01613 }else{
01614
01615 if(last_direction == 0)
01616 ret = -1;
01617 else {
01618 ret = -1;
01619 if(fabs(beta - pi_medios) <= max_diff){
01620 if(last_direction != ret){
01621 ret = 1;
01622 iCase = 3;
01623 }else{
01624 iCase = 4;
01625 }
01626 }
01627
01628 }
01629 }
01630
01631 ROS_INFO("%s:CalculateDirectionSpeed: case %d. Beta = %.2lf. Diff = %.2lf. Last direction = %d, new direction = %d", sComponentName.c_str(),
01632 iCase, beta*180.0/M_PI, (beta - pi_medios)*180.0/M_PI, last_direction, ret);
01633
01634 last_direction = ret;
01635 return ret;
01636 }
01637
01641 ReturnValue MergePath(){
01642 Waypoint new_waypoint, wFirst, wLast;
01643 Path aux;
01644 int direction = 0;
01645
01646 if(action_server_goto.isNewGoalAvailable()){
01647 goto_goal.target = action_server_goto.acceptNewGoal()->target;
01648 if(goto_goal.target.size() > 0){
01649 if(goto_goal.target.size() > 1){
01650 direction = CalculateDirectionSpeed(goto_goal.target[1].pose);
01651 }else{
01652 direction = CalculateDirectionSpeed(goto_goal.target[0].pose);
01653 }
01654
01655 if(direction == 1){
01656 SetLaserFront();
01657 }else{
01658 SetLaserBack();
01659 }
01660
01661 for(int i = 0; i < goto_goal.target.size(); i++){
01662 ROS_INFO("%s::MergePath: Point %d (%.3lf, %.3lf, %.3lf) speed = %.3lf", sComponentName.c_str(), i, goto_goal.target[i].pose.x,
01663 goto_goal.target[i].pose.y, goto_goal.target[i].pose.theta, goto_goal.target[i].speed );
01664
01665 new_waypoint.dX = goto_goal.target[i].pose.x;
01666 new_waypoint.dY = goto_goal.target[i].pose.y;
01667 new_waypoint.dA = goto_goal.target[i].pose.theta;
01668
01669 if(direction == 1){
01670 new_waypoint.dSpeed = fabs(goto_goal.target[i].speed);
01671 }else{
01672 new_waypoint.dSpeed = -fabs(goto_goal.target[i].speed);
01673 }
01674
01675 pathFilling.AddWaypoint(new_waypoint);
01676 }
01677 if(pathFilling.Optimize(AGVS_TURN_RADIUS) != OK)
01678 ROS_ERROR("%s::GoalCB: Error optimizing the path", sComponentName.c_str());
01679
01680
01681
01682 qPath.push(pathFilling);
01683
01684 pathFilling.Clear();
01685
01686 goto_feedback.percent_complete = 0.0;
01687
01688
01689 if(qPath.size() > 0){
01690 aux = qPath.front();
01691 aux.GetWaypoint(0, &wFirst);
01692 aux.BackWaypoint(&wLast);
01693 ROS_INFO("%s::MergePath: Adding new %d points from (%.2lf, %.2lf) to (%.2lf, %.2lf) and %d magnets", sComponentName.c_str(), aux.NumOfWaypoints() ,wFirst.dX, wFirst.dY, wLast.dX, wLast.dY, aux.NumOfMagnets());
01694 ROS_INFO("%s::MergePath: Current number of points = %d and magnets = %d", sComponentName.c_str(), pathCurrent.NumOfWaypoints() , pathCurrent.NumOfMagnets());
01695
01696
01697 pathCurrent+=qPath.front();
01698
01699 ROS_INFO("%s::MergePath: New number of points = %d and magnets = %d", sComponentName.c_str(), pathCurrent.NumOfWaypoints() , pathCurrent.NumOfMagnets());
01700
01701 qPath.pop();
01702
01703 goto_goal.target.clear();
01704
01705 return OK;
01706 }
01707 }
01708
01709 }
01710
01711 return ERROR;
01712 }
01713
01717 void GoalCB()
01718 {
01719
01720
01721
01722 }
01723
01727 void PreemptCB()
01728 {
01729 bCancel = true;
01730 }
01731
01735 void AnalyseCB(){
01736 if (!action_server_goto.isActive()){
01737
01738 return;
01739 }
01740
01741
01742 action_server_goto.publishFeedback(goto_feedback);
01743
01744 if(goto_feedback.percent_complete == 100.0){
01745
01746 action_server_goto.setAborted(goto_result);
01747 ROS_INFO("%s::AnalyseCB: Action finished", sComponentName.c_str());
01748 }
01749 }
01750
01754 bool SetLaserFront(){
01755
01756
01757
01758
01759
01760
01761
01762
01763
01764 }
01765
01769 bool SetLaserBack(){
01770
01771
01772
01773
01774
01775
01776
01777
01778
01779 }
01780
01781 };
01782
01783
01784 int main(int argc, char** argv)
01785 {
01786 ros::init(argc, argv, "purepursuit_planner_node");
01787
01788 ros::NodeHandle n;
01789 purepursuit_planner_node planner(n);
01790
01791 planner.ControlThread();
01792
01793 return (0);
01794 }
01795