tedusar_daf_path_follower.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  *
00003  *  Software License Agreement (BSD License)
00004  *
00005  *  Copyright (c) 2014, Peter Lepej,
00006  *                      Faculty of Electrical Engineerign anc Computer Scienece,
00007  *                      University of Maribor
00008  *  All rights reserved.
00009  *
00010  *  Redistribution and use in source and binary forms, with or without
00011  *  modification, are permitted provided that the following conditions
00012  *  are met:
00013  *
00014  *   * Redistributions of source code must retain the above copyright
00015  *     notice, this list of conditions and the following disclaimer.
00016  *   * Redistributions in binary form must reproduce the above
00017  *     copyright notice, this list of conditions and the following
00018  *     disclaimer in the documentation and/or other materials provided
00019  *     with the distribution.
00020  *   * Neither the name of Graz University of Technology nor the names of
00021  *     its contributors may be used to endorse or promote products derived
00022  *     from this software without specific prior written permission.
00023  *
00024  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00025  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00026  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00027  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00028  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00029  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00030  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00031  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00032  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00033  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00034  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00035  *  POSSIBILITY OF SUCH DAMAGE.
00036  *
00037  *********************************************************************/
00038 
00039 #include <tedusar_daf_path_follower/tedusar_daf_path_follower.hpp>
00040 
00041 namespace tedusar_path_follower
00042 {
00043     tedusar_path_follower::tedusar_path_follower(ros::NodeHandle nh) 
00044     : nh_(nh),
00045       execute_path_action_server_(nh_, "execute_path", boost::bind(&tedusar_path_follower::executePathCB, this, _1), false)
00046     {
00047 
00048         ros::NodeHandle private_nh("~");
00049 
00050         private_nh.param<double>("pub_cmd_hz", pub_cmd_hz, 10);
00051         private_nh.param<std::string>("path_topic", path_topic, string("/exploration_path"));
00052         private_nh.param<std::string>("pose_update_topic", pose_update_topic, string("/odom"));
00053         private_nh.param<std::string>("imu_data", imu_topic, string("/imu_data"));
00054         private_nh.param<std::string>("out_cmd_vel", cmd_vel_out, string("/cmd_vel"));
00055         private_nh.param<std::string>("map_link", map_link, string("/map"));
00056         private_nh.param<std::string>("base_link", base_link, string("/base_footprint"));
00057         private_nh.param<double>("max_lin_vel", max_lin_speed, 0.4);
00058         private_nh.param<double>("min_lin_vel", min_lin_speed, 0.1);
00059         private_nh.param<double>("max_rot_vel", max_rot_speed, 0.8);
00060         private_nh.param<double>("min_rot_vel", min_rot_speed, 0.4);
00061         private_nh.param<double>("rot_correction_factor", rot_correction_factor, 1);
00062         private_nh.param<double>("execution_period", execution_period, 1.0); 
00063         private_nh.param<double>("update_skip_until_vel_increase", update_skip, 5);
00064         private_nh.param<double>("global_goal_tolerance", global_goal_tolerance, 0.2);
00065         private_nh.param<double>("lower_al_angle", lower_al_angle, 0.2);              //this angle determine when angle correction is executed
00066         private_nh.param<double>("upper_al_angle", upper_al_angle, 0.6);              //this angle determine middle robot correction wich is compensate in linear movment
00067                                                                                       //smaller correction angle means better fiting of trajectories
00068         private_nh.param<bool>("enable_angle_compensation", enable_angle_compensation, true);
00069         private_nh.param<bool>("enable_ground_compensation", enable_ground_compensation, true);
00070         private_nh.param<bool>("enable_velocity_encrease", enable_velocity_encrease, true);
00071         private_nh.param<bool>("show_trajectory_planing", show_trajectory_planing, true);
00072         private_nh.param<double>("stability_angle", stability_angle, 1.0);
00073     }
00074     /****************************************************************
00075      *
00076      */
00077     tedusar_path_follower::~tedusar_path_follower()
00078     {
00079     }
00080     /*****************************************************************************************************************
00081      * Initialization
00082      */
00083     void tedusar_path_follower::init()
00084     {
00085         //path_3d_sub = nh_.subscribe<nav_msgs::Path>(path_topic,50 , &tedusar_path_follower::path_cb, this);
00086         pose_update_sub = nh_.subscribe<nav_msgs::Odometry>(pose_update_topic ,10 , &tedusar_path_follower::pose_update, this);
00087         cmd_vel_pub = nh_.advertise<geometry_msgs::Twist>(cmd_vel_out, 1);
00088         imu_data_sub = nh_.subscribe<sensor_msgs::Imu>(imu_topic, 1, &tedusar_path_follower::imuCallback, this);
00089 
00090         //path following visualization
00091         if(show_trajectory_planing)
00092         {
00093             path_pub = nh_.advertise<nav_msgs::Path>("/calc_path", 1);
00094             local_path_pub = nh_.advertise<nav_msgs::Path>("/local_calc_path", 1);
00095             marker_pub = nh_.advertise<visualization_msgs::Marker>("visualization_marker", 1);
00096         }
00097 
00098         //reset initial settings
00099         resetPathFollowing();
00100 
00101         //start  action server
00102         execute_path_action_server_.start();
00103     }
00104     /*****************************************************************************************************************
00105      * Resets Path Following
00106      */
00107     void tedusar_path_follower::resetPathFollowing()
00108     {
00109         alignment_finished = false;
00110         co_unchanged = 0;
00111         st_point = 0;
00112         path_po_lenght = 0;
00113         lin_vel = max_lin_speed/2;
00114 
00115         //save reference for linar velocity
00116         lin_vel_ref = lin_vel;
00117 
00118         //rot_vel_dir = 1;
00119         //rot_dir_opti = 1;
00120         imu_yaw = 0;
00121         imu_pitch = 0;
00122         imu_roll = 0;
00123         old_pos_x = 0;
00124         old_pos_y = 0;
00125         rad = 0;
00126         err_cont = 0;
00127         oscilation_rotation = 1;
00128 
00129         move_robot = false;
00130         cmd.linear.x = 0.0;
00131         cmd.angular.z = 0.0;
00132         cmd_vel_pub.publish(cmd);
00133     }
00134     /****************************************************************
00135      * Imu Data Callback
00136      */
00137     void tedusar_path_follower::imuCallback(const sensor_msgs::ImuConstPtr &imu_msg)
00138     {
00139         tf::Quaternion imu_quaternion;
00140         tf::quaternionMsgToTF(imu_msg->orientation, imu_quaternion);
00141         tf::Transform imu_orientation(imu_quaternion, tf::Vector3(0,0,0));
00142         imu_orientation.getBasis().getEulerYPR(imu_yaw, imu_pitch, imu_roll);
00143      }
00144     /*****************************************************************************************************************
00145      * Pose update
00146      */
00147     void tedusar_path_follower::pose_update(const nav_msgs::Odometry pose)
00148     {
00149         //check if transformation is avaliable
00150         if(move_robot)
00151         {
00152             //if path is received calculate path
00153             if(listener.canTransform(map_link, base_link, ros::Time(0)))
00154             {
00155                 now = ros::Time::now();
00156                 listener.lookupTransform(map_link, base_link, ros::Time(0), transform);   //daj ven na params
00157                 origin = transform.getOrigin();
00158                 rotation = transform.getRotation();
00159                 axis = rotation.getAxis();
00160                 odom.pose.pose.position.x = origin.x();
00161                 odom.pose.pose.position.y = origin.y();
00162                 odom.pose.pose.position.z = origin.z();
00163                 tf::Quaternion q(transform.getRotation().x(), transform.getRotation().y(), transform.getRotation().z(), transform.getRotation().w());
00164                 tf::Matrix3x3 m(q);
00165                 m.getRPY(roll, pitch, yaw);
00166 
00167                 //calculate local path
00168                 calc_local_path();
00169 
00170                 //increase velocity if robot dose not move
00171                 velocity_increase();
00172             }else
00173             {
00174                 ROS_WARN("There is no transfrmationa avaliable from %s to %s", map_link.c_str(), base_link.c_str());
00175             }
00176         }
00177     }
00178     /*****************************************************************************************************************
00179      * Path Callback From Topic
00180      */
00181     void tedusar_path_follower::path_cb(const nav_msgs::Path::ConstPtr&  path)
00182     {
00183         curr_path = *path;
00184         psize = (int)curr_path.poses.size();
00185         dist = abs(execution_period*max_lin_speed);
00186 
00187         if(psize > 0) {
00188             move_robot = true;
00189         }else{
00190             move_robot = false;}
00191 
00192         ROS_INFO("New Path Received from topic. Path seq: %i size: %i distance to plan path: %f", curr_path.header.seq, psize, dist);
00193     }
00194     /*****************************************************************************************************************
00195      * calculate Fitter Circular Path
00196      */
00197     void tedusar_path_follower::calc_local_path()
00198     {
00199         path_po_lenght = 0;
00200         //calculate path_po_lenght
00201         for(int i=0; i < psize; i++)
00202         {
00203             double curr_dist_x = abs(odom.pose.pose.position.x - curr_path.poses[i].pose.position.x);
00204             double curr_dist_y = abs(odom.pose.pose.position.y - curr_path.poses[i].pose.position.y);
00205             double curr_dist = sqrt(curr_dist_x*curr_dist_x + curr_dist_y*curr_dist_y);
00206 
00207             if(abs(curr_dist) > dist) //search for points
00208             {
00209                 continue;
00210             }
00211             path_po_lenght = path_po_lenght + 1;
00212         }
00213 
00214         double min_dif = 10.0;
00215 
00216         //start point from robot current pose
00217         points[0][0] = odom.pose.pose.position.x;
00218         points[0][1] = odom.pose.pose.position.y;
00219 
00220         //search for closest point to path
00221         for(int i=0; i < psize; i++)
00222         {
00223             double po_dist = sqrt((curr_path.poses[i].pose.position.x - points[0][0])*(curr_path.poses[i].pose.position.x - points[0][0]) + (curr_path.poses[i].pose.position.y - points[0][1])*(curr_path.poses[i].pose.position.y - points[0][1]));
00224             if(abs(po_dist) < min_dif)
00225             {
00226                 min_dif = abs(po_dist);
00227                 st_point = i;
00228             }
00229         }
00230         //ROS_INFO("Founded closest point on path: x: %f y: %f at postition: %i", curr_path.poses[st_point].pose.position.x, curr_path.poses[st_point].pose.position.x, st_point);
00231 
00232         //calculate execution path distance
00233         co_points = 0;
00234         for(int i=st_point; i < (st_point+path_po_lenght); i++)
00235         {
00236             if(i > (psize-2))
00237             {
00238                 co_points = co_points +1;
00239                 points[co_points][0] = curr_path.poses[i].pose.position.x;
00240                 points[co_points][1] = curr_path.poses[i].pose.position.y;
00241                 i = (st_point+path_po_lenght)+1;
00242             }else
00243             {
00244                 co_points = co_points +1;
00245                 points[co_points][0] = curr_path.poses[i].pose.position.x;
00246                 points[co_points][1] = curr_path.poses[i].pose.position.y;
00247             }
00248         }
00249 
00250         th_po_x = 0; th_po_y = 0; fi_po_x = 0; fi_po_y = 0;
00251         se_po_x = 0; se_po_y = 0; dirx = 1; diry = -1; max_H = 0;
00252 
00253         //calculate triangle height height
00254         for(int i=0; i < co_points; i++)
00255         {
00256                                            //p1            p2              p3
00257             //ROS_INFO("Points X: %f %f %f", points[0][0], points[i][0], points[co_points][0]);
00258             //ROS_INFO("Points Y: %f %f %f", points[0][1], points[i][1], points[co_points][1]);
00259             sideA = sqrt(((points[0][0] - points[i][0])*(points[0][0] - points[i][0])) + (points[0][1] - points[i][1])*(points[0][1] - points[i][1]));
00260             sideB = sqrt(((points[i][0] - points[co_points][0])*(points[i][0] - points[co_points][0])) + (points[i][1] - points[co_points][1])*(points[i][1] - points[co_points][1]));
00261             sideC = sqrt(((points[co_points][0] - points[0][0])*(points[co_points][0] - points[0][0])) + (points[co_points][1] - points[0][1])*(points[co_points][1] - points[0][1]));
00262             //ROS_INFO("triangle sides: %f %f %f", sideA, sideB, sideC);
00263             ss = (sideA + sideB + sideC)/2;
00264             area = sqrt(ss*(ss-sideA)*(ss-sideB)*(ss-sideC));
00265             //determine params for radius calculation
00266             tmp_H = (area*2)/sideC;
00267 
00268             if(tmp_H > max_H)
00269             {
00270                 max_H = tmp_H;
00271                 float det_dir = (points[co_points][0] - points[1][0])*(points[i][1] - points[0][1]) - (points[co_points][1] - points[0][1])*(points[i][0]- points[0][0]);
00272                 se_po_x = points[i][0];
00273                 se_po_y = points[i][1];
00274 
00275                 if(det_dir > 0)
00276                 {
00277                     dirx = -1;
00278                     diry = 1;
00279                     rot_vel_dir = -1;
00280                 }else
00281                 {
00282                     dirx = 1;
00283                     diry = -1;
00284                     rot_vel_dir = 1;
00285                 }
00286             }
00287             Wid = sideC;
00288         }
00289 
00290         //if local path is too short
00291         if(co_points < 3)
00292         {
00293             max_H = 0.001;
00294         }
00295         //smooth local path
00296         //max_H = max_H/2;
00297 
00298         //calculate ground compensation, which modifiy max_H and W
00299         calc_ground_compensation();
00300 
00301         fi_po_x = points[0][0];
00302         fi_po_y = points[0][1];
00303         th_po_x = points[co_points][0];
00304         th_po_y = points[co_points][1];
00305 
00306         //calculate radious
00307         rad = max_H/2 + (Wid*Wid)/(8*max_H);
00308         //ROS_INFO("Fitted circle radius: %f", rad);
00309 
00310         //calculating circle center
00311         midX = (points[0][0] + points[co_points][0])/2;
00312         midY = (points[0][1] + points[co_points][1])/2;
00313         dx = (points[0][0] - points[co_points][0])/2;
00314         dy = (points[0][1] - points[co_points][1])/2;
00315         distt = sqrt(dx*dx + dy*dy);
00316         pdist = sqrt(rad*rad - distt*distt);
00317         mDx = dirx*dy*pdist/distt;
00318         mDy = diry*dx*pdist/distt;
00319 
00320         //calculate alignemnt angle
00321         double curr_dist_x = points[0][0] -  (midX + mDx);
00322         double curr_dist_y = points[0][1] - (midY + mDy);
00323 
00324         //correct angle directions
00325         if((curr_dist_x < 0)&&(curr_dist_y < 0))
00326         {
00327             alignment_angle = atan2(curr_dist_y,curr_dist_x) + rot_vel_dir*PI/2;
00328         }
00329         else if((curr_dist_x > 0)&&(curr_dist_y > 0))
00330         {
00331             alignment_angle = atan2(curr_dist_y,curr_dist_x) + rot_vel_dir*PI/2;
00332         }
00333         else if((curr_dist_x < 0)&&(curr_dist_y > 0))
00334         {
00335             alignment_angle = atan2(curr_dist_y,curr_dist_x) + rot_vel_dir*PI/2;
00336         }
00337         else if((curr_dist_x > 0)&&(curr_dist_y < 0))
00338         {
00339             alignment_angle = atan2(curr_dist_y,curr_dist_x) + rot_vel_dir*PI/2;
00340         }
00341 
00342         //reduce angle on -PI to +PI
00343         if(alignment_angle > PI)
00344         {
00345             alignment_angle = alignment_angle - 2*PI;
00346         }
00347         if(alignment_angle < -PI)
00348         {
00349             alignment_angle = alignment_angle + 2*PI;
00350         }
00351 
00352         if(isnan(alignment_angle))
00353         {
00354             ROS_WARN("Alignment Angle can not be computed!");
00355         }
00356 
00357         //ROS_INFO("Alignment angle is: %f", alignment_angle);
00358         if(isnan(alignment_angle))
00359         {
00360             ROS_INFO("Alignment angle is nan - return to calc_local_path");
00361             calc_local_path();
00362         }
00363 
00364         //send feedback
00365         feedback.feedback = (int)round((100*st_point)/psize); //calculated progress relative to given path
00366         execute_path_action_server_.publishFeedback(feedback);
00367 
00368         //display of all lines to plan a path
00369         if(show_trajectory_planing == true)
00370         {
00371             uint32_t shape = visualization_msgs::Marker::CUBE;
00372 
00373             local_calc_path.header.frame_id = map_link;
00374             local_calc_path.poses.resize(360);
00375 
00376             for(int d= 0; d < 360; d++)
00377             {
00378                 double xp = sin(d*0.0174532925)*rad + (midX + mDx);
00379                 double yp = cos(d*0.0174532925)*rad + (midY + mDy);
00380                 local_calc_path.poses[d].pose.position.x = xp;
00381                 local_calc_path.poses[d].pose.position.y = yp;
00382                 local_calc_path.poses[d].pose.position.z = 0;
00383             }
00384             //publish circle
00385             local_path_pub.publish(local_calc_path);
00386 
00387             //pub triangle
00388             calc_path.header.frame_id = map_link;
00389             calc_path.poses.resize(4);
00390 
00391             //pub path
00392             calc_path.poses[0].pose.position.x = points[0][0];
00393             calc_path.poses[0].pose.position.y = points[0][1];
00394             calc_path.poses[0].pose.position.z = 0;
00395             calc_path.poses[1].pose.position.x = se_po_x;
00396             calc_path.poses[1].pose.position.y = se_po_y;
00397             calc_path.poses[1].pose.position.z = 0;
00398             calc_path.poses[2].pose.position.x = points[co_points][0];
00399             calc_path.poses[2].pose.position.y = points[co_points][1];
00400             calc_path.poses[2].pose.position.z = 0;
00401             calc_path.poses[3].pose.position.x = points[0][0];
00402             calc_path.poses[3].pose.position.y = points[0][1];
00403             calc_path.poses[3].pose.position.z = 0;
00404             calc_path.poses.resize(4);
00405             path_pub.publish(calc_path);
00406 
00407             //start point
00408             visualization_msgs::Marker marker;
00409             marker.header.frame_id = map_link;
00410             marker.header.stamp = ros::Time::now();
00411 
00412             marker.ns = "first_point";
00413             marker.id = 0;
00414             marker.type = shape;
00415             marker.action = visualization_msgs::Marker::ADD;
00416             marker.pose.position.x = fi_po_x;
00417             marker.pose.position.y = fi_po_y;
00418             marker.pose.position.z = 0;
00419             marker.pose.orientation.x = 0.0;
00420             marker.pose.orientation.y = 0.0;
00421             marker.pose.orientation.z = 0.0;
00422             marker.pose.orientation.w = 1.0;
00423             // Set the scale of the marker -- 1x1x1 here means 1m on a side
00424             marker.scale.x = 0.02;
00425             marker.scale.y = 0.02;
00426             marker.scale.z = 0.02;
00427             // Set the color -- be sure to set alpha to something non-zero!
00428             marker.color.r = 1;
00429             marker.color.g = 0;
00430             marker.color.b = 0;
00431             marker.color.a = 1.0;
00432             marker.lifetime = ros::Duration();
00433             // Publish the marker
00434             marker_pub.publish(marker);
00435 
00436             marker.ns = "second_point";
00437             marker.id = 2;
00438             marker.type = shape;
00439             marker.action = visualization_msgs::Marker::ADD;
00440             marker.pose.position.x = se_po_x;
00441             marker.pose.position.y = se_po_y;
00442             marker.pose.position.z = 0;
00443             marker.pose.orientation.x = 0.0;
00444             marker.pose.orientation.y = 0.0;
00445             marker.pose.orientation.z = 0.0;
00446             marker.pose.orientation.w = 1.0;
00447             // Set the scale of the marker -- 1x1x1 here means 1m on a side
00448             marker.scale.x = 0.02;
00449             marker.scale.y = 0.02;
00450             marker.scale.z = 0.02;
00451             // Set the color -- be sure to set alpha to something non-zero!
00452             marker.color.r = 0;
00453             marker.color.g = 1;
00454             marker.color.b = 0;
00455             marker.color.a = 1.0;
00456             marker.lifetime = ros::Duration();
00457             // Publish the marker
00458             marker_pub.publish(marker);
00459 
00460             //end point
00461             marker.ns = "third_point";
00462             marker.id = 4;
00463             marker.type = shape;
00464             marker.action = visualization_msgs::Marker::ADD;
00465             marker.pose.position.x = th_po_x;
00466             marker.pose.position.y = th_po_y;
00467             marker.pose.position.z = 0;
00468             marker.pose.orientation.x = 0.0;
00469             marker.pose.orientation.y = 0.0;
00470             marker.pose.orientation.z = 0.0;
00471             marker.pose.orientation.w = 1.0;
00472             // Set the scale of the marker -- 1x1x1 here means 1m on a side
00473             marker.scale.x = 0.02;
00474             marker.scale.y = 0.02;
00475             marker.scale.z = 0.02;
00476             // Set the color -- be sure to set alpha to something non-zero!
00477             marker.color.r = 0;
00478             marker.color.g = 0;
00479             marker.color.b = 1;
00480             marker.color.a = 1.0;
00481             marker.lifetime = ros::Duration();
00482             // Publish the marker
00483             marker_pub.publish(marker);
00484         }
00485     }
00486     /*****************************************************************************************************************
00487      * Compensate Ground Inclinations
00488      */
00489     void tedusar_path_follower::calc_ground_compensation()
00490     {
00491         if(enable_ground_compensation == true)
00492         {
00493             //ROS_INFO("Distances before ground compensation: max_H: %f and W: %f", max_H, Wid);
00494             double dh = abs((max_H/cos(imu_roll))-max_H);
00495             double dw = abs((Wid/cos(imu_pitch))-Wid);
00496             //ROS_INFO("Angle compensation diferences: dh: %f, dw: %f", dh, dw);
00497             max_H = max_H + dh;
00498             Wid = Wid + dw;
00499             //ROS_INFO("Distances after ground compensation: max_H: %f and W: %f", max_H, Wid);
00500         }
00501     }
00502     /*****************************************************************************************************************
00503      * Check robot current stability
00504      */
00505     void tedusar_path_follower::check_robot_stability()
00506     {
00507         //if robot reaches treshodl of its stability angle it responds with error
00508         if((imu_roll > stability_angle)||(imu_pitch > stability_angle))
00509         {
00510                 action_result.result = 1;
00511                 execute_path_action_server_.setAborted(action_result, std::string("Robot has exceeded angle of stability!"));
00512                 resetPathFollowing();
00513                 ROS_WARN("Robot has exceeded angle of stability!");
00514         }
00515     }
00516     /*****************************************************************************************************************
00517      * calculate Current Alignment Rotation
00518      */
00519     void tedusar_path_follower::calculate_al_rot()
00520     {
00521         //define rotation direction
00522         angle_diff = alignment_angle - yaw;
00523 
00524         if(fabs(angle_diff) > M_PI)
00525         {
00526             if(angle_diff > 0)
00527             {
00528                  angle_diff = -2 * M_PI + fabs(angle_diff);
00529             }
00530             else
00531             {
00532                 angle_diff = 2 * M_PI - fabs(angle_diff);
00533             }
00534         }
00535 
00536         if(angle_diff > 0){rot_dir_opti = 1;}
00537         else{ rot_dir_opti = -1;}
00538     }
00539     /*****************************************************************************************************************
00540      * Action Callback for Path from Exploration Controller
00541      */
00542     void tedusar_path_follower::executePathCB(const ExecutePathGoalConstPtr &goal)
00543     {
00544         resetPathFollowing();
00545 
00546         curr_path = goal->path;
00547 
00548         psize = (int)curr_path.poses.size();
00549         dist = abs(execution_period*max_lin_speed);
00550 
00551         if(psize > 0)
00552         {
00553             ROS_INFO("New Path Received from Action. Path seq: %i size: %i distance to plan path: %f", curr_path.header.seq, psize, dist);
00554             move_robot = true;
00555 
00556             ros::Rate r(pub_cmd_hz);
00557             while(ros::ok())
00558             {
00559                 if(execute_path_action_server_.isPreemptRequested() || !move_robot)
00560                 {
00561                     move_robot = false;
00562                     resetPathFollowing();
00563                     execute_path_action_server_.setPreempted();
00564                     ROS_INFO("path execution is preempted");
00565                     return;
00566                 }
00567                 calculate_cmd();
00568                 r.sleep();
00569             }
00570         }else{
00571             move_robot = false;
00572 
00573             //sends aborted feedback
00574             action_result.result = 1;
00575             execute_path_action_server_.setAborted(action_result, std::string("Path size is 0"));
00576         }
00577     }
00578     /*****************************************************************************************************************
00579      * Compensate Current Angle Difreence
00580      */
00581     void tedusar_path_follower::calc_angel_compensation()
00582     {
00583         if(enable_angle_compensation == true)
00584         {
00585             //cosider space
00586             angle_diff = alignment_angle - yaw;
00587 
00588             if(fabs(angle_diff) > M_PI)
00589             {
00590                 if(angle_diff > 0)
00591                 {
00592                      angle_diff = -2 * M_PI + fabs(angle_diff);
00593                 }
00594                 else
00595                 {
00596                     angle_diff = 2 * M_PI - fabs(angle_diff);
00597                 }
00598             }
00599 
00600             double add_al_rot = abs(angle_diff/(execution_period));
00601             //ROS_INFO("Additional Alignment Rotation: %f", add_al_rot);
00602 
00603             rot_vel = rot_vel_dir * lin_vel/rad*rot_correction_factor + rot_dir_opti*add_al_rot;
00604         }else
00605         {
00606             rot_vel = rot_vel_dir * lin_vel/rad*rot_correction_factor;
00607            //upper and lower angle treshods are same
00608            lower_al_angle = upper_al_angle;
00609         }
00610     }
00611     /*****************************************************************************************************************
00612      * Increase Velocity if Robot Dose not Move
00613      */
00614     void tedusar_path_follower::velocity_increase()
00615     {
00616 
00617         //check if there is no change in position it increase linear speed
00618         double pose_diff_x = fabs(odom.pose.pose.position.x - old_pos_x);
00619         double pose_diff_y = fabs(odom.pose.pose.position.y - old_pos_y);
00620 
00621         if((pose_diff_x <= std::numeric_limits<double>::epsilon()) && (pose_diff_y <= std::numeric_limits<double>::epsilon()))
00622         {
00623             ++co_unchanged;
00624 
00625             if (co_unchanged > update_skip)
00626             {
00627                 co_unchanged = 0;
00628 
00629                 if(enable_velocity_encrease == true)
00630                 {
00631 
00632                     lin_vel = lin_vel + max_lin_speed/10;
00633 
00634                     if(lin_vel >= max_lin_speed)
00635                     {
00636                         lin_vel = max_lin_speed;
00637 
00638                         //goal reach reporting
00639                         action_result.result = 1;
00640                         execute_path_action_server_.setAborted(action_result, std::string("Robot cannot move, maximum speed reached!"));
00641                         resetPathFollowing();
00642                         ROS_WARN("Robot cannot move! Maximum speed reached!");
00643                     }
00644                 }else
00645                 {
00646                     action_result.result = 1;
00647                     execute_path_action_server_.setAborted(action_result, std::string("Robot cannot move!"));
00648                     resetPathFollowing();
00649                     ROS_WARN("Robot cannot move!");
00650                 }
00651             }
00652         }
00653         else
00654         {
00655             //else reference linear velocity is used
00656             old_pos_x = odom.pose.pose.position.x;
00657             old_pos_y = odom.pose.pose.position.y;
00658             co_unchanged = 0;
00659             lin_vel = lin_vel_ref;
00660         }
00661     }
00662 
00663     /*****************************************************************************************************************
00664      * calculate and Publish Velocity Commands
00665      */
00666     void tedusar_path_follower::calculate_cmd()
00667     {
00668         if(move_robot == true)
00669         {
00670             //check if robot has reached a treshod for inclination
00671             check_robot_stability();
00672 
00673             ROS_INFO_ONCE("Start calculating cmd velocity!");
00674             //do algnment if angle is too large do alignment
00675             al_an_diff = alignment_angle - yaw;
00676 
00677             if(al_an_diff > M_PI)
00678             {
00679                 al_an_diff = 2 * M_PI - al_an_diff;
00680             }
00681 
00682             calculate_al_rot();
00683 
00684              // if difference is larger thatn both tresholds angle_correction and middle al_offset
00685             if((fabs(al_an_diff) > (lower_al_angle + upper_al_angle))||(alignment_finished == false))
00686             {
00687                 // turn in place
00688                 //ROS_INFO("ROBOT IS ALIGNING || yaw: %f angle: %f", yaw*57.2957795, alignment_angle*57.2957795);
00689                 if (yaw > alignment_angle)
00690                 {
00691                     cmd.linear.x = 0.0;
00692                     cmd.angular.z = rot_dir_opti*max_rot_speed/2;
00693                 }
00694                 else if (yaw < alignment_angle)
00695                 {
00696                     cmd.linear.x = 0.0;
00697                     cmd.angular.z = rot_dir_opti*max_rot_speed/2;
00698                 }
00699 
00700                 if(fabs(al_an_diff) < lower_al_angle/2)
00701                 {
00702                     alignment_finished = true;
00703                     ROS_INFO("Alignment completed!");
00704                     err_cont = 0;
00705                 }else
00706                 {
00707                     alignment_finished = false;
00708 
00709                     //if robot misses alignment angle
00710                     ++err_cont;
00711                     if(err_cont > pub_cmd_hz*8) //second for delay
00712                     {
00713                        action_result.result = 1;
00714                        execute_path_action_server_.setAborted(action_result, std::string("Robot cannot move, maximum speed reached!"));
00715                        resetPathFollowing();
00716                        ROS_WARN("If your robot is oscilating, please increase lower_al_angle and upper_al_angle parameter (recommended: lower_al_angle=0.6, upper_al_angle=1.0)");
00717                        ROS_WARN("Requesting new path!");
00718 
00719                     }
00720                 }
00721             }
00722             // else if difference is between lower treshold (angle correction) and upper treshold (middle_al_offset) the angle compensation is used
00723             else if((fabs(al_an_diff) > lower_al_angle)&&((fabs(al_an_diff) < (lower_al_angle + upper_al_angle))))  //||(alignment_finished == false)
00724             {
00725                 //ROS_INFO("DRIVE ROBOT MIDDLE STAGE || yaw: %f al_angle: %f", yaw*57.2957795, alignment_angle*57.2957795);
00726 
00727                 calculate_al_rot();
00728 
00729                 //add additional rotation speed based on ground
00730                 calc_angel_compensation();
00731 
00732                 cmd.linear.x = lin_vel;
00733                 cmd.angular.z = rot_vel;
00734 
00735                 //check for global goal proximitiy
00736                 glo_pos_diff_x = abs(odom.pose.pose.position.x - curr_path.poses[psize-1].pose.position.x);
00737                 glo_pos_diff_y = abs(odom.pose.pose.position.y - curr_path.poses[psize-1].pose.position.y);
00738                 if((glo_pos_diff_x < global_goal_tolerance)&&(glo_pos_diff_y < global_goal_tolerance))
00739                 {
00740                     ROS_INFO("GLOBAL GOAL REACHED");
00741                     cmd.linear.x = 0;
00742                     cmd.angular.z = 0;
00743                     //goal reach reporting
00744                     action_result.result = 0;
00745                     execute_path_action_server_.setSucceeded(action_result);
00746                     move_robot = false;
00747                 }
00748             }
00749             //if difference is below lower treshold ()
00750             else
00751             {
00752                 //ROS_INFO("DRIVE ROBOT || yaw: %f al_angle: %f", yaw*57.2957795, alignment_angle*57.2957795);
00753 
00754                 calculate_al_rot();
00755 
00756                 rot_vel = rot_vel_dir * lin_vel/rad*rot_correction_factor;  //pazi za meso je dva krat
00757 
00758                 cmd.linear.x = lin_vel;
00759                 cmd.angular.z = rot_vel;
00760 
00761                 //check for global goal proximitiy
00762                 glo_pos_diff_x = fabs(odom.pose.pose.position.x - curr_path.poses[psize-1].pose.position.x);
00763                 glo_pos_diff_y = fabs(odom.pose.pose.position.y - curr_path.poses[psize-1].pose.position.y);
00764                 if((glo_pos_diff_x < global_goal_tolerance)&&(glo_pos_diff_y < global_goal_tolerance))
00765                 {
00766                     ROS_INFO("GLOBAL GOAL REACHED");
00767                     cmd.linear.x = 0;
00768                     cmd.angular.z = 0;
00769                     //goal reach reporting
00770                     action_result.result = 0;
00771                     execute_path_action_server_.setSucceeded(action_result);
00772                     move_robot = false;
00773 
00774                 }
00775              }
00776 
00777             //publish commad
00778             cmd_vel_pub.publish(cmd);
00779             //ROS_INFO("published velocity: lin: %f rot: %f", cmd.linear.x, cmd.angular.z);
00780         }
00781     }
00782 }
00783 
00784 int main (int argc, char** argv)
00785 {
00786     // Initialize ROS
00787     ros::init (argc, argv, "tedusar_path_follower");
00788     ros::NodeHandle nh;
00789 
00790     //for registering the node
00791     tedusar_path_follower::tedusar_path_follower tedusar_path_follower_handler(nh);
00792 
00793     tedusar_path_follower_handler.init();                     //initize
00794 
00795     ros::spin();
00796     return 0;
00797 }


tedusar_daf_path_follower
Author(s): Peter Lepej , Johannes Maurer
autogenerated on Mon Oct 6 2014 07:51:50