1#include <angles/angles.h>
2#include <pluginlib/class_list_macros.h>
4#include <visualization_msgs/MarkerArray.h>
5#include <boost/intrusive_ptr.hpp>
12 namespace backward_local_planner
21 : paramServer_(ros::NodeHandle(
"~BackwardLocalPlanner"))
52 ros::NodeHandle nh(
"~/BackwardLocalPlanner");
101 double angle = tf::getYaw(tfpose.getRotation());
103 const geometry_msgs::Point &carrot_point = carrot_pose.pose.position;
105 tf::Quaternion carrot_orientation;
106 tf::quaternionMsgToTF(carrot_pose.pose.orientation, carrot_orientation);
108 geometry_msgs::Pose currentPoseDebugMsg;
109 tf::poseTFToMsg(tfpose, currentPoseDebugMsg);
112 double dx = carrot_point.x - tfpose.getOrigin().x();
113 double dy = carrot_point.y - tfpose.getOrigin().y();
114 dist = sqrt(dx * dx + dy * dy);
116 double pangle = tf::getYaw(carrot_orientation);
117 angular_error = fabs(angles::shortest_angular_distance(pangle, angle));
119 ROS_DEBUG_STREAM(
"[BackwardLocalPlanner] Compute carrot errors. (linear " << dist <<
")(angular " << angular_error <<
")" << std::endl
120 <<
"Current carrot pose: " << std::endl
121 << carrot_pose << std::endl
122 <<
"Current actual pose:" << std::endl
123 << currentPoseDebugMsg);
133 ROS_DEBUG(
"[BackwardsLocalPlanner] --- Computing carrot pose ---");
134 double disterr = 0, angleerr = 0;
143 ROS_DEBUG(
"[BackwardsLocalPlanner] update carrot goal: linear error %lf, angular error: %lf", disterr, angleerr);
165 ROS_DEBUG(
"[BackwardsLocalPlanner] Update carrot goal: linear error %lf, angular error: %lf", disterr, angleerr);
167 ROS_DEBUG(
"[BackwardsLocalPlanner] carrot in goal radius: %d", carrotInGoalLinear);
169 ROS_DEBUG(
"[BackwardsLocalPlanner] --- Computing carrot pose ---");
171 return carrotInGoalLinear;
183 double disterr = 0, angleerr = 0;
192 const double MARGIN_FACTOR = 1.2;
221 const geometry_msgs::Point &carrot_point = carrot_pose.pose.position;
222 double yaw = tf::getYaw(carrot_pose.pose.orientation);
225 double vx = cos(yaw);
226 double vy = sin(yaw);
230 double c = -vx * carrot_point.x - vy * carrot_point.y;
231 const double C_OFFSET_METERS = 0.05;
232 double check = vx * tfpose.getOrigin().x() + vy * tfpose.getOrigin().y() + c + C_OFFSET_METERS;
234 ROS_DEBUG_STREAM(
"[BackwardLocalPlanner] half plane constraint:" << vx <<
"*" << carrot_point.x <<
" + " << vy <<
"*" << carrot_point.y <<
" + " << c);
235 ROS_DEBUG_STREAM(
"[BackwardLocalPlanner] constraint evaluation: " << vx <<
"*" << tfpose.getOrigin().x() <<
" + " << vy <<
"*" << tfpose.getOrigin().y() <<
" + " << c <<
" = " << check);
243 double gdx = finalgoal.pose.position.x - tfpose.getOrigin().x();
244 double gdy = finalgoal.pose.position.y - tfpose.getOrigin().y();
245 double goaldist = sqrt(gdx * gdx + gdy * gdy);
247 auto abs_angle_error = fabs(angle_error);
249 ROS_DEBUG_STREAM(
"[BackwardLocalPlanner] goal check. linear dist: " << goaldist <<
"(" << this->
xy_goal_tolerance_ <<
")"
268 cmd_vel.linear.x = vetta;
269 cmd_vel.angular.z = gamma;
280 vetta =
k_rho_ * rho_error;
301 cmd_vel.linear.x = vetta;
302 cmd_vel.angular.z = gamma;
306#if ROS_VERSION_MINIMUM(1, 13, 0)
309 geometry_msgs::PoseStamped paux;
310 costmapRos->getRobotPose(paux);
311 tf::Stamped<tf::Pose> tfpose;
312 tf::poseStampedMsgToTF(paux, tfpose);
319 tf::Stamped<tf::Pose> tfpose;
320 costmapRos->getRobotPose(tfpose);
333 ROS_DEBUG(
"[BackwardLocalPlanner] ------------------- LOCAL PLANNER LOOP -----------------");
334 geometry_msgs::PoseStamped paux;
339 bool divergenceDetected =
false;
341 bool emergency_stop =
false;
342 if (divergenceDetected)
344 ROS_ERROR(
"[BackwardLocalPlanner] Divergence detected. Sending emergency stop.");
345 emergency_stop =
true;
349 ROS_DEBUG_STREAM(
"[BackwardLocalPlanner] carrot goal created");
353 cmd_vel.linear.x = 0;
354 cmd_vel.angular.z = 0;
355 ROS_DEBUG_STREAM(
"[BackwardLocalPlanner] emergency stop, exit compute commands");
360 double rho_error, betta_error, alpha_error;
364 tf::Quaternion q = tfpose.getRotation();
368 const geometry_msgs::Point &carrotGoalPosition = carrotgoalpose.pose.position;
370 tf::Quaternion goalQ;
371 tf::quaternionMsgToTF(carrotgoalpose.pose.orientation, goalQ);
372 ROS_DEBUG_STREAM(
"[BackwardLocalPlanner] goal orientation: " << goalQ);
375 double betta = tf::getYaw(goalQ);
378 double dx = carrotGoalPosition.x - tfpose.getOrigin().x();
379 double dy = carrotGoalPosition.y - tfpose.getOrigin().y();
382 rho_error = sqrt(dx * dx + dy * dy);
385 double theta = tf::getYaw(q);
386 double alpha = atan2(dy, dx);
389 alpha_error = angles::shortest_angular_distance(alpha, theta);
390 betta_error = angles::shortest_angular_distance(betta, theta);
393 bool linearGoalReached;
398 if(currentPoseInGoal && carrotInFinalGoal)
402 ROS_INFO_STREAM(
" [BackwardLocalPlanner] GOAL REACHED. Send stop command and skipping trajectory collision: " << cmd_vel);
404 cmd_vel.angular.z = 0;
408 if (carrotInLinearGoalRange && linearGoalReached)
414 double vetta =
k_rho_ * rho_error;
427 ROS_DEBUG(
"[BackwardLocalPlanner] we entered in a pure spinning state even in not pure-spining configuration, carrotDistanceGoalReached: %d", carrotInLinearGoalRange);
456 ROS_DEBUG_STREAM(
"[BackwardLocalPlanner] local planner," << std::endl
459 <<
"carrotInLinearGoalRange: " << carrotInLinearGoalRange << std::endl
460 <<
" theta: " << theta << std::endl
461 <<
" betta: " << theta << std::endl
462 <<
" err_x: " << dx << std::endl
463 <<
" err_y:" << dy << std::endl
464 <<
" rho_error:" << rho_error << std::endl
465 <<
" alpha_error:" << alpha_error << std::endl
466 <<
" betta_error:" << betta_error << std::endl
467 <<
" vetta:" << vetta << std::endl
468 <<
" gamma:" << gamma << std::endl
469 <<
" cmd_vel.lin.x:" << cmd_vel.linear.x << std::endl
470 <<
" cmd_vel.ang.z:" << cmd_vel.angular.z);
476 if (carrotHalfPlaneConstraintFailure)
478 ROS_ERROR(
"[BackwardLocalPlanner] CarrotHalfPlaneConstraintFailure detected. Sending emergency stop and success to the planner.");
479 cmd_vel.linear.x = 0;
490 auto yaw = tf::getYaw(global_pose.getRotation());
492 auto &pos = global_pose.getOrigin();
494 Eigen::Vector3f currentpose(pos.x(), pos.y(), yaw);
495 Eigen::Vector3f currentvel(cmd_vel.linear.x, cmd_vel.linear.y, cmd_vel.angular.z);
496 std::vector<Eigen::Vector3f> trajectory;
497 this->
generateTrajectory(currentpose, currentvel, 0.8 , M_PI / 8 , 3.0 , 0.05 , trajectory);
500 bool acceptedLocalTrajectoryFreeOfObstacles =
true;
512 for (
auto &p : trajectory)
514 float dx = p[0] - finalgoalpose.pose.position.x;
515 float dy = p[1] - finalgoalpose.pose.position.y;
517 float dst = sqrt(dx * dx + dy * dy);
520 ROS_DEBUG(
"[BackwardLocalPlanner] trajectory simulation for collision checking: goal reached with no collision");
524 costmap2d->worldToMap(p[0], p[1], mx, my);
525 costmap2d->getCost(mx, my);
535 if (costmap2d->getCost(mx, my) >= costmap_2d::INSCRIBED_INFLATED_OBSTACLE)
537 acceptedLocalTrajectoryFreeOfObstacles =
false;
538 ROS_WARN_STREAM(
"[BackwardLocalPlanner] ABORTED LOCAL PLAN BECAUSE OBSTACLE DETEDTED at point " << i <<
"/" << trajectory.size() << std::endl
539 << p[0] <<
", " << p[1]);
547 ROS_WARN(
"[BackwardLocalPlanner] Abort local - Backwards global plan size: %ld",
backwardsPlanPath_.size());
552 if (acceptedLocalTrajectoryFreeOfObstacles)
555 ROS_DEBUG(
"[BackwardLocalPlanner] accepted local trajectory free of obstacle. Local planner continues.");
561 cmd_vel.linear.x = 0;
562 cmd_vel.angular.z = 0;
568 ROS_WARN(
"[BackwardLocalPlanner][Not accepted local plan] starting countdown");
576 ROS_WARN(
"[BackwardLocalPlanner][Abort local] timeout! duration %lf/%f", waitingduration.toSec(),
waitingTimeout_.toSec());
592 ROS_INFO(
"[BackwardLocalPlanner] reconfigure Request");
629 ROS_DEBUG_STREAM(
"[BackwardLocalPlanner] isGoalReached call: " <<
goalReached_);
635 double lineardisterr, angleerr;
636 bool inCarrotRange =
false;
654 ROS_DEBUG(
"[BackwardLocalPlanner] Finding initial carrot goal i=%ld - in carrot Range",
currentCarrotPoseIndex_);
655 inCarrotRange =
true;
669 ROS_DEBUG(
"[BackwardLocalPlanner] Finding initial carrot goal i=%ld - carrot out of range, searching coincidence...",
currentCarrotPoseIndex_);
678 return inCarrotRange;
686 ROS_DEBUG(
"[BackwardLocalPlanner] resample precise");
689 ROS_DEBUG_STREAM(
"[BackwardLocalPlanner] resample precise skipping, size: " <<
backwardsPlanPath_.size());
699 ROS_DEBUG_STREAM(
"[BackwardLocalPlanner] resample precise, check: " << i);
703 tf::Quaternion qCurrent, qNext;
704 tf::quaternionMsgToTF(currpose.pose.orientation, qCurrent);
705 tf::quaternionMsgToTF(nextpose.pose.orientation, qNext);
707 double dx = nextpose.pose.position.x - currpose.pose.position.x;
708 double dy = nextpose.pose.position.y - currpose.pose.position.y;
709 double dist = sqrt(dx * dx + dy * dy);
711 bool resample =
false;
712 if (dist > maxallowedLinearError)
714 ROS_DEBUG_STREAM(
"[BackwardLocalPlanner] resampling point, linear distance:" << dist <<
"(" << maxallowedLinearError <<
")" << i);
719 double currentAngle = tf::getYaw(qCurrent);
720 double nextAngle = tf::getYaw(qNext);
722 double angularError = fabs(angles::shortest_angular_distance(currentAngle, nextAngle));
723 if (angularError > maxallowedAngularError)
726 ROS_DEBUG_STREAM(
"[BackwardLocalPlanner] resampling point, angular distance:" << angularError <<
"(" << maxallowedAngularError <<
")" << i);
732 geometry_msgs::PoseStamped pintermediate;
733 auto duration = nextpose.header.stamp - currpose.header.stamp;
734 pintermediate.header.frame_id = currpose.header.frame_id;
735 pintermediate.header.stamp = currpose.header.stamp + duration *0.5;
737 pintermediate.pose.position.x = 0.5 * (currpose.pose.position.x + nextpose.pose.position.x);
738 pintermediate.pose.position.y = 0.5 * (currpose.pose.position.y + nextpose.pose.position.y);
739 pintermediate.pose.position.z = 0.5 * (currpose.pose.position.z + nextpose.pose.position.z);
740 tf::Quaternion intermediateQuat = tf::slerp(qCurrent, qNext, 0.5);
741 tf::quaternionTFToMsg(intermediateQuat, pintermediate.pose.orientation);
751 ROS_DEBUG_STREAM(
"[BackwardLocalPlanner] End resampling. resampled:" << counter <<
" new inserted poses during precise resmapling.");
762 ROS_INFO_STREAM(
"[BackwardLocalPlanner] setPlan: new global plan received (" << plan.size() <<
")");
771 geometry_msgs::PoseStamped posestamped;
772 tf::poseStampedTFToMsg(tfpose,posestamped);
780 if (plan.size() == 0)
782 ROS_WARN(
"[BackwardLocalPlanner] received plan without any pose");
787 if (!foundInitialCarrotGoal)
789 ROS_ERROR(
"[BackwardLocalPlanner] new plan rejected. The initial point in the global path is too much far away from the current state (according to carrot_distance parameter)");
805 Eigen::Vector3f currentpos = pos;
822 auto dx = newpos[0] - currentpos[0];
823 auto dy = newpos[1] - currentpos[1];
824 float dist, angledist;
827 dist = sqrt(dx * dx + dy * dy);
836 angledist = angles::shortest_angular_distance(currentpos[2], newpos[2]);
837 if (angledist > maxanglediff)
844 outtraj.push_back(newpos);
864 Eigen::Vector3f new_pos = Eigen::Vector3f::Zero();
865 new_pos[0] = pos[0] + (vel[0] * cos(pos[2]) + vel[1] * cos(M_PI_2 + pos[2])) * dt;
866 new_pos[1] = pos[1] + (vel[0] * sin(pos[2]) + vel[1] * sin(M_PI_2 + pos[2])) * dt;
867 new_pos[2] = pos[2] + vel[2] * dt;
878 visualization_msgs::Marker marker;
879 marker.header.frame_id = this->
costmapRos_->getGlobalFrameID();
880 marker.header.stamp = ros::Time::now();
882 marker.ns =
"my_namespace2";
884 marker.type = visualization_msgs::Marker::ARROW;
885 marker.action = visualization_msgs::Marker::ADD;
886 marker.pose.orientation.w = 1;
888 marker.scale.x = 0.05;
889 marker.scale.y = 0.15;
890 marker.scale.z = 0.05;
891 marker.color.a = 1.0;
897 geometry_msgs::Point start, end;
901 end.x = x + 0.5 * cos(phi);
902 end.y = y + 0.5 * sin(phi);
904 marker.points.push_back(start);
905 marker.points.push_back(end);
907 visualization_msgs::MarkerArray ma;
908 ma.markers.push_back(marker);
PLUGINLIB_EXPORT_CLASS(cl_move_base_z::backward_global_planner::BackwardGlobalPlanner, nav_core::BaseGlobalPlanner)
bool findInitialCarrotGoal(tf::Stamped< tf::Pose > &pose)
bool straightBackwardsAndPureSpinningMode_
virtual bool isGoalReached() override
Check if the goal pose has been achieved by the local planner.
const double betta_offset_
const double alpha_offset_
ros::Duration waitingTimeout_
Eigen::Vector3f computeNewPositions(const Eigen::Vector3f &pos, const Eigen::Vector3f &vel, double dt)
bool resamplePrecisePlan()
bool enable_obstacle_checking_
bool updateCarrotGoal(const tf::Stamped< tf::Pose > &tfpose)
void defaultBackwardCmd(const tf::Stamped< tf::Pose > &tfpose, double vetta, double gamma, double alpha_error, double betta_error, geometry_msgs::Twist &cmd_vel)
bool checkCarrotHalfPlainConstraint(const tf::Stamped< tf::Pose > &tfpose)
virtual bool computeVelocityCommands(geometry_msgs::Twist &cmd_vel) override
Given the current position, orientation, and velocity of the robot: compute velocity commands to send...
meter divergenceDetectionLastCarrotLinearDistance_
bool resetDivergenceDetection()
costmap_2d::Costmap2DROS * costmapRos_
void straightBackwardsAndPureSpinCmd(const tf::Stamped< tf::Pose > &tfpose, double vetta, double gamma, double alpha_error, double betta_error, double rho_error, geometry_msgs::Twist &cmd_vel)
void reconfigCB(::backward_local_planner::BackwardLocalPlannerConfig &config, uint32_t level)
rad carrot_angular_distance_
virtual ~BackwardLocalPlanner()
void publishGoalMarker(double x, double y, double phi)
uint64_t currentCarrotPoseIndex_
ros::Publisher goalMarkerPublisher_
double linear_mode_rho_error_threshold_
bool checkCurrentPoseInGoalRange(const tf::Stamped< tf::Pose > &tfpose, double angle_error, bool &inLinearGoal)
double yaw_goal_tolerance_
void generateTrajectory(const Eigen::Vector3f &pos, const Eigen::Vector3f &vel, float maxdist, float maxangle, float maxtime, float dt, std::vector< Eigen::Vector3f > &outtraj)
bool initialPureSpinningStage_
double xy_goal_tolerance_
virtual bool setPlan(const std::vector< geometry_msgs::PoseStamped > &plan) override
Set the plan that the local planner is following.
bool divergenceDetectionUpdate(const tf::Stamped< tf::Pose > &tfpose)
void computeCurrentEuclideanAndAngularErrorsToCarrotGoal(const tf::Stamped< tf::Pose > &tfpose, double &dist, double &angular_error)
std::vector< geometry_msgs::PoseStamped > backwardsPlanPath_
double max_linear_x_speed_
bool inGoalPureSpinningState_
dynamic_reconfigure::Server<::backward_local_planner::BackwardLocalPlannerConfig >::CallbackType f
double max_angular_z_speed_
dynamic_reconfigure::Server<::backward_local_planner::BackwardLocalPlannerConfig > paramServer_
tf::Stamped< tf::Pose > optionalRobotPose(costmap_2d::Costmap2DROS *costmapRos)