SMACC2
Loading...
Searching...
No Matches
cl_nav2z::backward_local_planner::BackwardLocalPlanner Class Reference

#include <backward_local_planner.hpp>

Inheritance diagram for cl_nav2z::backward_local_planner::BackwardLocalPlanner:
Inheritance graph
Collaboration diagram for cl_nav2z::backward_local_planner::BackwardLocalPlanner:
Collaboration graph

Public Member Functions

 BackwardLocalPlanner ()
 
virtual ~BackwardLocalPlanner ()
 
void configure (const rclcpp_lifecycle::LifecycleNode::WeakPtr &parent, std::string name, const std::shared_ptr< tf2_ros::Buffer > tf, const std::shared_ptr< nav2_costmap_2d::Costmap2DROS > costmap_ros) override
 
void activate () override
 
void deactivate () override
 
void cleanup () override
 
void setPlan (const nav_msgs::msg::Path &path) override
 nav2_core setPlan - Sets the global plan
 
virtual geometry_msgs::msg::TwistStamped computeVelocityCommands (const geometry_msgs::msg::PoseStamped &pose, const geometry_msgs::msg::Twist &velocity, nav2_core::GoalChecker *goal_checker) override
 nav2_core computeVelocityCommands - calculates the best command given the current pose and velocity
 
bool isGoalReached ()
 
virtual void setSpeedLimit (const double &speed_limit, const bool &percentage) override
 

Private Member Functions

void updateParameters ()
 
bool findInitialCarrotGoal (geometry_msgs::msg::PoseStamped &pose)
 
bool updateCarrotGoal (const geometry_msgs::msg::PoseStamped &pose)
 
bool resamplePrecisePlan ()
 
void straightBackwardsAndPureSpinCmd (const geometry_msgs::msg::PoseStamped &pose, double &vetta, double &gamma, double alpha_error, double betta_error, double rho_error)
 
void clearMarkers ()
 
void publishGoalMarker (double x, double y, double phi)
 
void computeCurrentEuclideanAndAngularErrorsToCarrotGoal (const geometry_msgs::msg::PoseStamped &pose, double &dist, double &angular_error)
 
bool checkGoalReached (const geometry_msgs::msg::PoseStamped &pose, double vetta, double gamma, double alpha_error, geometry_msgs::msg::Twist &cmd_vel)
 
bool checkCurrentPoseInGoalRange (const geometry_msgs::msg::PoseStamped &tfpose, const geometry_msgs::msg::Twist &currentTwist, double angle_error, bool &linearGoalReached, nav2_core::GoalChecker *goalChecker)
 
bool resetDivergenceDetection ()
 
bool divergenceDetectionUpdate (const geometry_msgs::msg::PoseStamped &pose)
 
bool checkCarrotHalfPlainConstraint (const geometry_msgs::msg::PoseStamped &pose)
 
void generateTrajectory (const Eigen::Vector3f &pos, const Eigen::Vector3f &vel, float maxdist, float maxangle, float maxtime, float dt, std::vector< Eigen::Vector3f > &outtraj)
 
Eigen::Vector3f computeNewPositions (const Eigen::Vector3f &pos, const Eigen::Vector3f &vel, double dt)
 

Private Attributes

rclcpp_lifecycle::LifecycleNode::SharedPtr nh_
 
std::string name_
 
std::vector< geometry_msgs::msg::PoseStamped > backwardsPlanPath_
 
std::shared_ptr< nav2_costmap_2d::Costmap2DROS > costmapRos_
 
std::shared_ptr< tf2_ros::Buffer > tf_
 
std::shared_ptr< rclcpp_lifecycle::LifecyclePublisher< visualization_msgs::msg::MarkerArray > > goalMarkerPublisher_
 
std::shared_ptr< rclcpp_lifecycle::LifecyclePublisher< nav_msgs::msg::Path > > planPub_
 
double k_rho_
 
double k_alpha_
 
double k_betta_
 
double pure_spinning_allowed_betta_error_
 
double linear_mode_rho_error_threshold_
 
double initial_rotation_alpha_error_threshold_
 
const double alpha_offset_ = M_PI
 
const double betta_offset_ = 0
 
double max_linear_x_speed_
 
double max_angular_z_speed_
 
double yaw_goal_tolerance_
 
double xy_goal_tolerance_
 
meter carrot_distance_
 
rad carrot_angular_distance_
 
meter divergenceDetectionLastCarrotLinearDistance_
 
double transform_tolerance_
 
rclcpp::Duration waitingTimeout_
 
rclcpp::Time waitingStamp_
 
bool goalReached_
 
bool initialPureSpinningStage_
 
bool straightBackwardsAndPureSpinningMode_ = false
 
bool enable_obstacle_checking_ = true
 
bool inGoalPureSpinningState_ = false
 
bool waiting_
 
int currentCarrotPoseIndex_
 

Detailed Description

Definition at line 38 of file backward_local_planner.hpp.

Constructor & Destructor Documentation

◆ BackwardLocalPlanner()

cl_nav2z::backward_local_planner::BackwardLocalPlanner::BackwardLocalPlanner ( )

◆ ~BackwardLocalPlanner()

cl_nav2z::backward_local_planner::BackwardLocalPlanner::~BackwardLocalPlanner ( )
virtual

~BackwardLocalPlanner()

Definition at line 53 of file backward_local_planner.cpp.

53{}

Member Function Documentation

◆ activate()

void cl_nav2z::backward_local_planner::BackwardLocalPlanner::activate ( )
override

Definition at line 55 of file backward_local_planner.cpp.

56{
57 RCLCPP_INFO_STREAM(nh_->get_logger(), "activating controller BackwardLocalPlanner");
59
60 goalMarkerPublisher_->on_activate();
61 planPub_->on_activate();
62 backwardsPlanPath_.clear();
63}
std::vector< geometry_msgs::msg::PoseStamped > backwardsPlanPath_
std::shared_ptr< rclcpp_lifecycle::LifecyclePublisher< visualization_msgs::msg::MarkerArray > > goalMarkerPublisher_
std::shared_ptr< rclcpp_lifecycle::LifecyclePublisher< nav_msgs::msg::Path > > planPub_

References backwardsPlanPath_, goalMarkerPublisher_, nh_, planPub_, and updateParameters().

Here is the call graph for this function:

◆ checkCarrotHalfPlainConstraint()

bool cl_nav2z::backward_local_planner::BackwardLocalPlanner::checkCarrotHalfPlainConstraint ( const geometry_msgs::msg::PoseStamped & pose)
private

Definition at line 397 of file backward_local_planner.cpp.

399{
400 // this function is specially useful when we want to reach the goal with a lot
401 // of precision. We may pass the goal and then the controller enters in some
402 // unstable state. With this, we are able to detect when stop moving.
403
404 // only apply if the carrot is in goal position and also if we are not in a pure spinning behavior v!=0
405
406 auto & carrot_pose = backwardsPlanPath_[currentCarrotPoseIndex_];
407 const geometry_msgs::msg::Point & carrot_point = carrot_pose.pose.position;
408 double yaw = tf2::getYaw(carrot_pose.pose.orientation);
409
410 // direction vector
411 double vx = cos(yaw);
412 double vy = sin(yaw);
413
414 // line implicit equation
415 // ax + by + c = 0
416 double c = -vx * carrot_point.x - vy * carrot_point.y;
417 const double C_OFFSET_METERS = 0.05; // 5 cm
418 double check = vx * tfpose.pose.position.x + vy * tfpose.pose.position.y + c + C_OFFSET_METERS;
419
420 RCLCPP_INFO_STREAM(
421 nh_->get_logger(),
422 "[BackwardLocalPlanner] half plane constraint:" << vx << "*" << carrot_point.x << " + " << vy
423 << "*" << carrot_point.y << " + " << c);
424 RCLCPP_INFO_STREAM(
425 nh_->get_logger(), "[BackwardLocalPlanner] constraint evaluation: "
426 << vx << "*" << tfpose.pose.position.x << " + " << vy << "*"
427 << tfpose.pose.position.y << " + " << c << " = " << check);
428
429 return check < 0;
430}

References backwardsPlanPath_, currentCarrotPoseIndex_, and nh_.

Referenced by computeVelocityCommands().

Here is the caller graph for this function:

◆ checkCurrentPoseInGoalRange()

bool cl_nav2z::backward_local_planner::BackwardLocalPlanner::checkCurrentPoseInGoalRange ( const geometry_msgs::msg::PoseStamped & tfpose,
const geometry_msgs::msg::Twist & currentTwist,
double angle_error,
bool & linearGoalReached,
nav2_core::GoalChecker * goalChecker )
private

Definition at line 432 of file backward_local_planner.cpp.

436{
437 auto & finalgoal = backwardsPlanPath_.back();
438 double gdx = finalgoal.pose.position.x - tfpose.pose.position.x;
439 double gdy = finalgoal.pose.position.y - tfpose.pose.position.y;
440 double goaldist = sqrt(gdx * gdx + gdy * gdy);
441
442 auto abs_angle_error = fabs(angle_error);
443 RCLCPP_INFO_STREAM(
444 nh_->get_logger(), "[BackwardLocalPlanner] goal check. linear dist: "
445 << goaldist << "(" << this->xy_goal_tolerance_ << ")" << ", angular dist: "
446 << abs_angle_error << "(" << this->yaw_goal_tolerance_ << ")");
447
448 linearGoalReached = goaldist < this->xy_goal_tolerance_;
449
450 return linearGoalReached && abs_angle_error < this->yaw_goal_tolerance_;
451}

References backwardsPlanPath_, nh_, xy_goal_tolerance_, and yaw_goal_tolerance_.

Referenced by computeVelocityCommands().

Here is the caller graph for this function:

◆ checkGoalReached()

bool cl_nav2z::backward_local_planner::BackwardLocalPlanner::checkGoalReached ( const geometry_msgs::msg::PoseStamped & pose,
double vetta,
double gamma,
double alpha_error,
geometry_msgs::msg::Twist & cmd_vel )
private

◆ cleanup()

void cl_nav2z::backward_local_planner::BackwardLocalPlanner::cleanup ( )
override

Definition at line 73 of file backward_local_planner.cpp.

74{
75 this->clearMarkers();
76 RCLCPP_WARN_STREAM(nh_->get_logger(), "[BackwardLocalPlanner] cleanup");
77 this->backwardsPlanPath_.clear();
79}

References backwardsPlanPath_, clearMarkers(), currentCarrotPoseIndex_, and nh_.

Here is the call graph for this function:

◆ clearMarkers()

void cl_nav2z::backward_local_planner::BackwardLocalPlanner::clearMarkers ( )
private

Definition at line 1161 of file backward_local_planner.cpp.

1162{
1163 visualization_msgs::msg::Marker marker;
1164 marker.header.frame_id = this->costmapRos_->getGlobalFrameID();
1165 marker.header.stamp = nh_->now();
1166
1167 marker.ns = "my_namespace2";
1168 marker.id = 0;
1169 marker.type = visualization_msgs::msg::Marker::ARROW;
1170 marker.action = visualization_msgs::msg::Marker::DELETEALL;
1171
1172 visualization_msgs::msg::MarkerArray ma;
1173 ma.markers.push_back(marker);
1174
1175 goalMarkerPublisher_->publish(ma);
1176}
std::shared_ptr< nav2_costmap_2d::Costmap2DROS > costmapRos_

References costmapRos_, goalMarkerPublisher_, and nh_.

Referenced by cleanup(), and deactivate().

Here is the caller graph for this function:

◆ computeCurrentEuclideanAndAngularErrorsToCarrotGoal()

void cl_nav2z::backward_local_planner::BackwardLocalPlanner::computeCurrentEuclideanAndAngularErrorsToCarrotGoal ( const geometry_msgs::msg::PoseStamped & tfpose,
double & dist,
double & angular_error )
private

auxiliary functions

Definition at line 257 of file backward_local_planner.cpp.

259{
260 double angle = tf2::getYaw(tfpose.pose.orientation);
261 auto & carrot_pose = backwardsPlanPath_[currentCarrotPoseIndex_];
262 const geometry_msgs::msg::Point & carrot_point = carrot_pose.pose.position;
263
264 tf2::Quaternion carrot_orientation;
265 tf2::convert(carrot_pose.pose.orientation, carrot_orientation);
266 geometry_msgs::msg::Pose currentPoseDebugMsg = tfpose.pose;
267
268 // take error from the current position to the path point
269 double dx = carrot_point.x - tfpose.pose.position.x;
270 double dy = carrot_point.y - tfpose.pose.position.y;
271
272 dist = sqrt(dx * dx + dy * dy);
273
274 double pangle = tf2::getYaw(carrot_orientation);
275 angular_error = fabs(angles::shortest_angular_distance(pangle, angle));
276
277 RCLCPP_INFO_STREAM(
278 nh_->get_logger(), "[BackwardLocalPlanner] Compute carrot errors from current pose. (linear "
279 << dist << ")(angular " << angular_error << ")" << std::endl
280 << "Current carrot pose: " << std::endl
281 << carrot_pose << std::endl
282 << "Current actual pose:" << std::endl
283 << currentPoseDebugMsg);
284}

References backwardsPlanPath_, currentCarrotPoseIndex_, and nh_.

Referenced by divergenceDetectionUpdate(), findInitialCarrotGoal(), and updateCarrotGoal().

Here is the caller graph for this function:

◆ computeNewPositions()

Eigen::Vector3f cl_nav2z::backward_local_planner::BackwardLocalPlanner::computeNewPositions ( const Eigen::Vector3f & pos,
const Eigen::Vector3f & vel,
double dt )
private

Definition at line 1147 of file backward_local_planner.cpp.

1149{
1150 Eigen::Vector3f new_pos = Eigen::Vector3f::Zero();
1151 new_pos[0] = pos[0] + (static_cast<double>(vel[0]) * cos(pos[2]) +
1152 static_cast<double>(vel[1]) * cos(M_PI_2 + pos[2])) *
1153 dt;
1154 new_pos[1] = pos[1] + (static_cast<double>(vel[0]) * sin(pos[2]) +
1155 static_cast<double>(vel[1]) * sin(M_PI_2 + pos[2])) *
1156 dt;
1157 new_pos[2] = pos[2] + vel[2] * dt;
1158 return new_pos;
1159}

Referenced by generateTrajectory().

Here is the caller graph for this function:

◆ computeVelocityCommands()

geometry_msgs::msg::TwistStamped cl_nav2z::backward_local_planner::BackwardLocalPlanner::computeVelocityCommands ( const geometry_msgs::msg::PoseStamped & pose,
const geometry_msgs::msg::Twist & velocity,
nav2_core::GoalChecker * goal_checker )
overridevirtual

nav2_core computeVelocityCommands - calculates the best command given the current pose and velocity

It is presumed that the global plan is already set.

This is mostly a wrapper for the protected computeVelocityCommands function which has additional debugging info.

Parameters
poseCurrent robot pose
velocityCurrent robot velocity
Returns
The best command for the robot to drive

computeVelocityCommands()

Definition at line 492 of file backward_local_planner.cpp.

495{
496 RCLCPP_INFO(
497 nh_->get_logger(),
498 "[BackwardLocalPlanner] ------------------- LOCAL PLANNER LOOP -----------------");
499 this->updateParameters();
500
501 // consistency check
502 if (this->backwardsPlanPath_.size() > 0)
503 {
504 RCLCPP_INFO_STREAM(
505 nh_->get_logger(), "[BackwardLocalPlanner] Current pose frame id: "
506 << backwardsPlanPath_.front().header.frame_id
507 << ", path pose frame id: " << pose.header.frame_id);
508
509 if (backwardsPlanPath_.front().header.frame_id != pose.header.frame_id)
510 {
511 RCLCPP_ERROR_STREAM(nh_->get_logger(), "[BackwardLocalPlanner] Inconsistent frames");
512 }
513 }
514
515 // xy_goal_tolerance and yaw_goal_tolerance are just used for logging proposes and clamping the carrot
516 // goal distance (parameter safety)
517 if (xy_goal_tolerance_ == -1 || yaw_goal_tolerance_ == -1)
518 {
519 geometry_msgs::msg::Pose posetol;
520 geometry_msgs::msg::Twist twistol;
521 if (goal_checker->getTolerances(posetol, twistol))
522 {
523 xy_goal_tolerance_ = posetol.position.x;
524 yaw_goal_tolerance_ = tf2::getYaw(posetol.orientation);
525
526 RCLCPP_INFO_STREAM(
527 nh_->get_logger(), "[BackwardLocalPlanner] xy_goal_tolerance_: "
529 << ", yaw_goal_tolerance_: " << yaw_goal_tolerance_);
530 }
531 else
532 {
533 RCLCPP_INFO_STREAM(
534 nh_->get_logger(), "[BackwardLocalPlanner] could not get tolerances from goal checker");
535 }
536 }
537
538 RCLCPP_INFO(
539 nh_->get_logger(),
540 "[BackwardLocalPlanner] ------------------- LOCAL PLANNER LOOP -----------------");
541
542 geometry_msgs::msg::TwistStamped cmd_vel;
543 RCLCPP_INFO(nh_->get_logger(), "[BackwardLocalPlanner] LOCAL PLANNER LOOP");
544 geometry_msgs::msg::PoseStamped paux;
545 geometry_msgs::msg::PoseStamped tfpose;
546
547 if (!costmapRos_->getRobotPose(tfpose))
548 {
549 RCLCPP_ERROR(
550 nh_->get_logger(),
551 "[BackwardLocalPlanner] missing robot pose, canceling compute Velocity Command");
552 } // it is not working in the pure spinning reel example, maybe the hyperplane check is enough
553 bool divergenceDetected = false;
554
555 bool emergency_stop = false;
556 if (divergenceDetected)
557 {
558 RCLCPP_ERROR(
559 nh_->get_logger(), "[BackwardLocalPlanner] Divergence detected. Sending emergency stop.");
560 emergency_stop = true;
561 }
562
563 bool carrotInLinearGoalRange = updateCarrotGoal(tfpose);
564 RCLCPP_INFO_STREAM(nh_->get_logger(), "[BackwardLocalPlanner] carrot goal created");
565
566 if (emergency_stop)
567 {
568 cmd_vel.twist.linear.x = 0;
569 cmd_vel.twist.angular.z = 0;
570 RCLCPP_INFO_STREAM(
571 nh_->get_logger(), "[BackwardLocalPlanner] emergency stop, exit compute commands");
572 return cmd_vel;
573 }
574
575 // ------ Evaluate the current context ----
576 double rho_error, betta_error, alpha_error;
577
578 // getting carrot goal information
579 tf2::Quaternion q;
580 tf2::convert(tfpose.pose.orientation, q);
581
582 RCLCPP_INFO_STREAM(
583 nh_->get_logger(), "[BackwardLocalPlanner] carrot goal: " << currentCarrotPoseIndex_ << "/"
584 << backwardsPlanPath_.size());
585 const geometry_msgs::msg::PoseStamped & carrotgoalpose =
587 RCLCPP_INFO_STREAM(
588 nh_->get_logger(), "[BackwardLocalPlanner] carrot goal pose current index: "
589 << currentCarrotPoseIndex_ << "/" << backwardsPlanPath_.size() << ": "
590 << carrotgoalpose);
591 const geometry_msgs::msg::Point & carrotGoalPosition = carrotgoalpose.pose.position;
592
593 tf2::Quaternion goalQ;
594 tf2::fromMsg(carrotgoalpose.pose.orientation, goalQ);
595 RCLCPP_INFO_STREAM(nh_->get_logger(), "[BackwardLocalPlanner] -- Control Policy --");
596 // goal orientation (global frame)
597 double betta = tf2::getYaw(goalQ);
598 RCLCPP_INFO_STREAM(nh_->get_logger(), "[BackwardLocalPlanner] goal orientation: " << betta);
599 betta = betta + betta_offset_;
600
601 double dx = carrotGoalPosition.x - tfpose.pose.position.x;
602 double dy = carrotGoalPosition.y - tfpose.pose.position.y;
603
604 // distance error to the targetpoint
605 rho_error = sqrt(dx * dx + dy * dy);
606
607 // heading to goal angle
608 double theta = tf2::getYaw(q);
609 double alpha = atan2(dy, dx);
610 alpha = alpha + alpha_offset_;
611
612 alpha_error = angles::shortest_angular_distance(alpha, theta);
613 betta_error = angles::shortest_angular_distance(betta, theta);
614 //------------- END CONTEXT EVAL ----------
615
616 bool linearGoalReached;
617 bool currentPoseInGoal =
618 checkCurrentPoseInGoalRange(tfpose, velocity, betta_error, linearGoalReached, goal_checker);
619
620 // Make sure the robot is very close to the goal and it is really in the the last goal point.
621 bool carrotInFinalGoalIndex = currentCarrotPoseIndex_ == (int)backwardsPlanPath_.size() - 1;
622
623 // checking if we are really in the end goal pose
624 if (currentPoseInGoal && carrotInFinalGoalIndex)
625 {
626 goalReached_ = true;
627 RCLCPP_INFO_STREAM(
628 nh_->get_logger(),
629 "[BackwardLocalPlanner] GOAL REACHED. Send stop command and skipping trajectory collision: "
630 << cmd_vel.twist);
631 cmd_vel.twist.linear.x = 0;
632 cmd_vel.twist.angular.z = 0;
633 return cmd_vel;
634 }
635 else if (
636 carrotInLinearGoalRange &&
637 linearGoalReached) // checking if we are in the end goal point but with incorrect
638 // orientation
639 {
640 // this means that we are not in the final angular distance, and we may even not be in the last carrot index
641 // (several intermediate angular poses until the last goal pose)
643 }
644
645 // --------------------
646 // zero-initialized: straightBackwardsAndPureSpinCmd leaves them untouched when the
647 // robot is within both the linear threshold and the yaw tolerance (safe stop)
648 double vetta = 0;
649 double gamma = 0;
651 {
652 // decorated control rule for this mode
654 tfpose, vetta, gamma, alpha_error, betta_error, rho_error);
655 }
656 else // default free navigation backward motion mode
657 {
658 // regular control rule
659 vetta = k_rho_ * rho_error;
660 gamma = k_alpha_ * alpha_error + k_betta_ * betta_error;
661
662 // Even if we are in free navigation, we can enter in the pure spinning state.
663 // then, the linear motion is deactivated.
665 {
666 RCLCPP_INFO(
667 nh_->get_logger(),
668 "[BackwardLocalPlanner] we entered in a pure spinning state even in not pure-spining "
669 "configuration, "
670 "carrotDistanceGoalReached: %d",
671 carrotInLinearGoalRange);
672 gamma = k_betta_ * betta_error;
673 vetta = 0;
674 }
675
676 // classical control to reach a goal backwards
677 }
678
679 // Apply command and Clamp to limits
680 cmd_vel.twist.linear.x = vetta;
681 cmd_vel.twist.angular.z = gamma;
682
683 if (cmd_vel.twist.linear.x > max_linear_x_speed_)
684 {
685 cmd_vel.twist.linear.x = max_linear_x_speed_;
686 }
687 else if (cmd_vel.twist.linear.x < -max_linear_x_speed_)
688 {
689 cmd_vel.twist.linear.x = -max_linear_x_speed_;
690 }
691
692 if (cmd_vel.twist.angular.z > max_angular_z_speed_)
693 {
694 cmd_vel.twist.angular.z = max_angular_z_speed_;
695 }
696 else if (cmd_vel.twist.angular.z < -max_angular_z_speed_)
697 {
698 cmd_vel.twist.angular.z = -max_angular_z_speed_;
699 }
700
701 publishGoalMarker(carrotGoalPosition.x, carrotGoalPosition.y, betta);
702
703 RCLCPP_INFO_STREAM(
704 nh_->get_logger(), "[BackwardLocalPlanner] local planner,"
705 << std::endl
706 << " current pose in goal: " << currentPoseInGoal << std::endl
707 << " carrot in final goal index: " << carrotInFinalGoalIndex << std::endl
708 << " carrot in linear goal range: " << carrotInLinearGoalRange << std::endl
709 << " straightAnPureSpiningMode: " << straightBackwardsAndPureSpinningMode_
710 << std::endl
711 << " inGoalPureSpinningState: " << inGoalPureSpinningState_ << std::endl
712 << " theta: " << theta << std::endl
713 << " betta: " << theta << std::endl
714 << " err_x: " << dx << std::endl
715 << " err_y:" << dy << std::endl
716 << " rho_error:" << rho_error << std::endl
717 << " alpha_error:" << alpha_error << std::endl
718 << " betta_error:" << betta_error << std::endl
719 << " vetta:" << vetta << std::endl
720 << " gamma:" << gamma << std::endl
721 << " cmd_vel.lin.x:" << cmd_vel.twist.linear.x << std::endl
722 << " cmd_vel.ang.z:" << cmd_vel.twist.angular.z);
723
725 {
726 bool carrotHalfPlaneConstraintFailure = checkCarrotHalfPlainConstraint(tfpose);
727
728 if (carrotHalfPlaneConstraintFailure)
729 {
730 RCLCPP_ERROR(
731 nh_->get_logger(),
732 "[BackwardLocalPlanner] CarrotHalfPlaneConstraintFailure detected. Sending "
733 "emergency stop and success to the planner.");
734 cmd_vel.twist.linear.x = 0;
735 }
736 }
737
738 // ---------------------- TRAJECTORY PREDICTION AND COLLISION AVOIDANCE ---------------------
739 geometry_msgs::msg::PoseStamped global_pose;
740 costmapRos_->getRobotPose(global_pose);
741
742 auto * costmap2d = costmapRos_->getCostmap();
743 auto yaw = tf2::getYaw(global_pose.pose.orientation);
744
745 auto & pos = global_pose.pose.position;
746
747 Eigen::Vector3f currentpose(pos.x, pos.y, yaw);
748 Eigen::Vector3f currentvel(
749 cmd_vel.twist.linear.x, cmd_vel.twist.linear.y, cmd_vel.twist.angular.z);
750 std::vector<Eigen::Vector3f> trajectory;
751 this->generateTrajectory(
752 currentpose, currentvel, 0.8 /*meters*/, M_PI / 8 /*rads*/, 3.0 /*seconds*/, 0.05 /*seconds*/,
753 trajectory);
754
755 // check plan rejection
756 bool acceptedLocalTrajectoryFreeOfObstacles = true;
757
758 unsigned int mx, my;
759
761 {
762 if (backwardsPlanPath_.size() > 0)
763 {
764 auto & finalgoalpose = backwardsPlanPath_.back();
765
766 int i = 0;
767 // RCLCPP_INFO_STREAM(nh_->get_logger(), "lplanner goal: " << finalgoalpose.pose.position);
768 geometry_msgs::msg::Twist mockzerospeed;
769
770 for (auto & p : trajectory)
771 {
772 float dx = p[0] - finalgoalpose.pose.position.x;
773 float dy = p[1] - finalgoalpose.pose.position.y;
774
775 float dst = sqrt(dx * dx + dy * dy);
776 if (dst < xy_goal_tolerance_)
777 {
778 RCLCPP_INFO(
779 nh_->get_logger(),
780 "[BackwardLocalPlanner] trajectory simulation for collision checking: goal "
781 "reached with no collision");
782 break;
783 }
784
785 costmap2d->worldToMap(p[0], p[1], mx, my);
786
787 if (costmap2d->getCost(mx, my) >= nav2_costmap_2d::INSCRIBED_INFLATED_OBSTACLE)
788 {
789 acceptedLocalTrajectoryFreeOfObstacles = false;
790 RCLCPP_WARN_STREAM(
791 nh_->get_logger(),
792 "[BackwardLocalPlanner] ABORTED LOCAL PLAN BECAUSE OBSTACLE DETEDTED at point "
793 << i << "/" << trajectory.size() << std::endl
794 << p[0] << ", " << p[1]);
795 break;
796 }
797 i++;
798 }
799 }
800 else
801 {
802 RCLCPP_WARN(
803 nh_->get_logger(), "[BackwardLocalPlanner] Abort local - Backwards global plan size: %ld",
804 backwardsPlanPath_.size());
805 cmd_vel.twist.angular.z = 0;
806 cmd_vel.twist.linear.x = 0;
807 }
808 }
809
810 if (acceptedLocalTrajectoryFreeOfObstacles)
811 {
812 waiting_ = false;
813 RCLCPP_INFO(
814 nh_->get_logger(),
815 "[BackwardLocalPlanner] accepted local trajectory free of obstacle. Local planner "
816 "continues.");
817 return cmd_vel;
818 }
819 else // that is not appceted because existence of obstacles
820 {
821 // emergency stop for collision: waiting a while before sending error
822 cmd_vel.twist.linear.x = 0;
823 cmd_vel.twist.angular.z = 0;
824
825 if (waiting_ == false)
826 {
827 waiting_ = true;
828 waitingStamp_ = nh_->now();
829 RCLCPP_WARN(
830 nh_->get_logger(), "[BackwardLocalPlanner][Not accepted local plan] starting countdown");
831 }
832 else
833 {
834 auto waitingduration = nh_->now() - waitingStamp_;
835
836 if (waitingduration > this->waitingTimeout_)
837 {
838 RCLCPP_WARN(
839 nh_->get_logger(), "[BackwardLocalPlanner][Abort local] timeout! duration %lf/%f",
840 waitingduration.seconds(), waitingTimeout_.seconds());
841 cmd_vel.twist.linear.x = 0;
842 cmd_vel.twist.angular.z = 0;
843 return cmd_vel;
844 }
845 }
846
847 return cmd_vel;
848 }
849}
bool updateCarrotGoal(const geometry_msgs::msg::PoseStamped &pose)
bool checkCarrotHalfPlainConstraint(const geometry_msgs::msg::PoseStamped &pose)
void straightBackwardsAndPureSpinCmd(const geometry_msgs::msg::PoseStamped &pose, double &vetta, double &gamma, double alpha_error, double betta_error, double rho_error)
void generateTrajectory(const Eigen::Vector3f &pos, const Eigen::Vector3f &vel, float maxdist, float maxangle, float maxtime, float dt, std::vector< Eigen::Vector3f > &outtraj)
bool checkCurrentPoseInGoalRange(const geometry_msgs::msg::PoseStamped &tfpose, const geometry_msgs::msg::Twist &currentTwist, double angle_error, bool &linearGoalReached, nav2_core::GoalChecker *goalChecker)

References alpha_offset_, backwardsPlanPath_, betta_offset_, checkCarrotHalfPlainConstraint(), checkCurrentPoseInGoalRange(), costmapRos_, currentCarrotPoseIndex_, enable_obstacle_checking_, generateTrajectory(), goalReached_, inGoalPureSpinningState_, k_alpha_, k_betta_, k_rho_, max_angular_z_speed_, max_linear_x_speed_, nh_, publishGoalMarker(), straightBackwardsAndPureSpinCmd(), straightBackwardsAndPureSpinningMode_, updateCarrotGoal(), updateParameters(), waiting_, waitingStamp_, waitingTimeout_, xy_goal_tolerance_, and yaw_goal_tolerance_.

Here is the call graph for this function:

◆ configure()

void cl_nav2z::backward_local_planner::BackwardLocalPlanner::configure ( const rclcpp_lifecycle::LifecycleNode::WeakPtr & parent,
std::string name,
const std::shared_ptr< tf2_ros::Buffer > tf,
const std::shared_ptr< nav2_costmap_2d::Costmap2DROS > costmap_ros )
override

Definition at line 96 of file backward_local_planner.cpp.

100{
101 this->costmapRos_ = costmap_ros;
102 this->nh_ = parent.lock();
103 this->name_ = name;
104 this->tf_ = tf;
105
106 k_rho_ = -1.0;
107 k_alpha_ = 0.5;
108 k_betta_ = -1.0; // set to zero means that orientation is not important
109 carrot_distance_ = 0.4;
119 waitingTimeout_ = rclcpp::Duration(10s);
120
121 this->currentCarrotPoseIndex_ = 0;
122
124 nh_, name_ + ".pure_spinning_straight_line_mode", straightBackwardsAndPureSpinningMode_);
125
126 declareOrSet(nh_, name_ + ".k_rho", k_rho_);
127 declareOrSet(nh_, name_ + ".k_alpha", k_alpha_);
128 declareOrSet(nh_, name_ + ".k_betta", k_betta_);
129 declareOrSet(nh_, name_ + ".linear_mode_rho_error_threshold", linear_mode_rho_error_threshold_);
131 nh_, name_ + ".initial_rotation_alpha_error_threshold",
133
134 declareOrSet(nh_, name_ + ".carrot_distance", carrot_distance_);
135 declareOrSet(nh_, name_ + ".carrot_angular_distance", carrot_angular_distance_);
136 declareOrSet(nh_, name_ + ".enable_obstacle_checking", enable_obstacle_checking_);
137
138 declareOrSet(nh_, name_ + ".max_linear_x_speed", max_linear_x_speed_);
139 declareOrSet(nh_, name_ + ".max_angular_z_speed", max_angular_z_speed_);
140 declareOrSet(nh_, name_ + ".transform_tolerance", transform_tolerance_);
141
142 // we have to do this, for example for the case we are refining the final orientation.
143 // check at some point if the carrot is reached in "goal linear distance", then we go into
144 // some automatic pure-spinning mode where we only update the orientation
145 // This means that if we reach the carrot with precision we go into pure spinning mode but we cannot
146 // leave that point (maybe this could be improved)
147
149 {
150 RCLCPP_WARN_STREAM(
151 nh_->get_logger(), "[BackwardLocalPlanner] carrot_angular_distance ("
153 << ") cannot be lower than yaw_goal_tolerance (" << yaw_goal_tolerance_
154 << ") setting carrot_angular_distance = " << yaw_goal_tolerance_);
156 }
157
159 {
160 RCLCPP_WARN_STREAM(
161 nh_->get_logger(), "[BackwardLocalPlanner] carrot_linear_distance ("
162 << carrot_distance_ << ") cannot be lower than xy_goal_tolerance_ ("
164 << ") setting carrot_angular_distance = " << xy_goal_tolerance_);
166 }
167
168 goalMarkerPublisher_ = nh_->create_publisher<visualization_msgs::msg::MarkerArray>(
169 "backward_local_planner/goal_marker", rclcpp::QoS(1));
170
171 planPub_ =
172 nh_->create_publisher<nav_msgs::msg::Path>("backward_local_planner/path", rclcpp::QoS(1));
173}
void declareOrSet(rclcpp_lifecycle::LifecycleNode::SharedPtr &node, std::string param, T &value)
Definition common.hpp:34

References carrot_angular_distance_, carrot_distance_, costmapRos_, currentCarrotPoseIndex_, declareOrSet(), enable_obstacle_checking_, goalMarkerPublisher_, initial_rotation_alpha_error_threshold_, k_alpha_, k_betta_, k_rho_, linear_mode_rho_error_threshold_, max_angular_z_speed_, max_linear_x_speed_, name_, nh_, planPub_, straightBackwardsAndPureSpinningMode_, tf_, transform_tolerance_, waitingTimeout_, xy_goal_tolerance_, and yaw_goal_tolerance_.

Here is the call graph for this function:

◆ deactivate()

void cl_nav2z::backward_local_planner::BackwardLocalPlanner::deactivate ( )
override

Definition at line 65 of file backward_local_planner.cpp.

66{
67 this->clearMarkers();
68 RCLCPP_WARN_STREAM(nh_->get_logger(), "[BackwardLocalPlanner] deactivated");
69 planPub_->on_deactivate();
70 goalMarkerPublisher_->on_deactivate();
71}

References clearMarkers(), goalMarkerPublisher_, nh_, and planPub_.

Here is the call graph for this function:

◆ divergenceDetectionUpdate()

bool cl_nav2z::backward_local_planner::BackwardLocalPlanner::divergenceDetectionUpdate ( const geometry_msgs::msg::PoseStamped & pose)
private

Definition at line 360 of file backward_local_planner.cpp.

361{
362 double disterr = 0, angleerr = 0;
364
365 RCLCPP_INFO_STREAM(
366 nh_->get_logger(), "[BackwardLocalPlanner] Divergence check. carrot goal distance. was: "
368 << ", now it is: " << disterr);
370 {
371 // candidate of divergence, we do not throw the divergence alarm yet
372 // but we neither update the distance since it is worse than the one
373 // we had previously with the same carrot.
374 const double MARGIN_FACTOR = 1.2;
375 if (disterr > MARGIN_FACTOR * divergenceDetectionLastCarrotLinearDistance_)
376 {
377 RCLCPP_ERROR_STREAM(
378 nh_->get_logger(),
379 "[BackwardLocalPlanner] Divergence detected. The same carrot goal distance was previously: "
380 << divergenceDetectionLastCarrotLinearDistance_ << "but now it is: " << disterr);
381 return true;
382 }
383 else
384 {
385 // divergence candidate
386 return false;
387 }
388 }
389 else
390 {
391 // update:
393 return false;
394 }
395}
void computeCurrentEuclideanAndAngularErrorsToCarrotGoal(const geometry_msgs::msg::PoseStamped &pose, double &dist, double &angular_error)

References computeCurrentEuclideanAndAngularErrorsToCarrotGoal(), divergenceDetectionLastCarrotLinearDistance_, and nh_.

Referenced by setPlan().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ findInitialCarrotGoal()

bool cl_nav2z::backward_local_planner::BackwardLocalPlanner::findInitialCarrotGoal ( geometry_msgs::msg::PoseStamped & pose)
private

Definition at line 862 of file backward_local_planner.cpp.

863{
864 double lineardisterr, angleerr;
865 bool inCarrotRange = false;
866
867 // initial state check
868 computeCurrentEuclideanAndAngularErrorsToCarrotGoal(tfpose, lineardisterr, angleerr);
869
870 // lets set the carrot-goal in the correct place with this loop: advance through the
871 // contiguous in-range poses and stop at the last one before leaving the carrot range
872 while (currentCarrotPoseIndex_ < (int)backwardsPlanPath_.size())
873 {
874 computeCurrentEuclideanAndAngularErrorsToCarrotGoal(tfpose, lineardisterr, angleerr);
875
876 RCLCPP_INFO(
877 nh_->get_logger(),
878 "[BackwardLocalPlanner] Finding initial carrot goal i=%d - error to carrot, linear = %lf "
879 "(%lf), "
880 "angular : %lf (%lf)",
882
883 // current path point is inside the carrot distance range, goal carrot tries to escape!
884 if (lineardisterr < carrot_distance_ && angleerr < carrot_angular_distance_)
885 {
886 RCLCPP_INFO(
887 nh_->get_logger(),
888 "[BackwardLocalPlanner] Finding initial carrot goal i=%d - in carrot Range",
890 inCarrotRange = true;
891 // we are inside the goal range, keep advancing to find the last in-range pose
892 }
893 else if (inCarrotRange)
894 {
895 // we were inside the carrot range but not anymore, now we are just leaving.
896 // rollback last index increment (to go back inside the carrot goal scope) and
897 // start motion with that carrot goal we found
899 break;
900 }
901 else
902 {
903 RCLCPP_INFO(
904 nh_->get_logger(),
905 "[BackwardLocalPlanner] Finding initial carrot goal i=%d - carrot out of range, searching "
906 "coincidence...",
908 }
909
911 RCLCPP_INFO_STREAM(
912 nh_->get_logger(), "[BackwardLocalPlanner] setPlan: fw" << currentCarrotPoseIndex_);
913 }
914
915 // the whole remaining path was in range: the carrot is the final pose
917 {
919 }
920
921 RCLCPP_INFO_STREAM(
922 nh_->get_logger(), "[BackwardLocalPlanner] setPlan: (found first carrot:"
923 << inCarrotRange << ") initial carrot point index: "
924 << currentCarrotPoseIndex_ << "/" << backwardsPlanPath_.size());
925
926 return inCarrotRange;
927}

References backwardsPlanPath_, carrot_angular_distance_, carrot_distance_, computeCurrentEuclideanAndAngularErrorsToCarrotGoal(), currentCarrotPoseIndex_, and nh_.

Referenced by setPlan().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ generateTrajectory()

void cl_nav2z::backward_local_planner::BackwardLocalPlanner::generateTrajectory ( const Eigen::Vector3f & pos,
const Eigen::Vector3f & vel,
float maxdist,
float maxangle,
float maxtime,
float dt,
std::vector< Eigen::Vector3f > & outtraj )
private

Definition at line 1092 of file backward_local_planner.cpp.

1095{
1096 // simulate the trajectory and check for collisions, updating costs along the way
1097 bool end = false;
1098 float time = 0;
1099 Eigen::Vector3f currentpos = pos;
1100 int i = 0;
1101 while (!end)
1102 {
1103 auto loop_vel = vel;
1104 // update the position of the robot using the velocities passed in
1105 auto newpos = computeNewPositions(currentpos, loop_vel, dt);
1106
1107 auto dx = newpos[0] - currentpos[0];
1108 auto dy = newpos[1] - currentpos[1];
1109 float dist, angledist;
1110
1111 // RCLCPP_INFO(nh_->get_logger(), "traj point %d", i);
1112 dist = sqrt(dx * dx + dy * dy);
1113 if (dist > maxdist)
1114 {
1115 end = true;
1116 // RCLCPP_INFO(nh_->get_logger(), "dist break: %f", dist);
1117 }
1118 else
1119 {
1120 // ouble from, double to
1121 angledist = angles::shortest_angular_distance(currentpos[2], newpos[2]);
1122 if (angledist > maxanglediff)
1123 {
1124 end = true;
1125 // RCLCPP_INFO(nh_->get_logger(), "angle dist break: %f", angledist);
1126 }
1127 else
1128 {
1129 outtraj.push_back(newpos);
1130
1131 time += dt;
1132 if (time > maxtime)
1133 {
1134 end = true;
1135 // RCLCPP_INFO(nh_->get_logger(), "time break: %f", time);
1136 }
1137
1138 // RCLCPP_INFO(nh_->get_logger(), "dist: %f, angledist: %f, time: %f", dist, angledist, time);
1139 }
1140 }
1141
1142 currentpos = newpos;
1143 i++;
1144 } // end for simulation steps
1145}
Eigen::Vector3f computeNewPositions(const Eigen::Vector3f &pos, const Eigen::Vector3f &vel, double dt)

References computeNewPositions().

Referenced by computeVelocityCommands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ isGoalReached()

bool cl_nav2z::backward_local_planner::BackwardLocalPlanner::isGoalReached ( )

isGoalReached()

Definition at line 856 of file backward_local_planner.cpp.

857{
858 RCLCPP_INFO(nh_->get_logger(), "[BackwardLocalPlanner] isGoalReached call");
859 return goalReached_;
860}

References goalReached_, and nh_.

◆ publishGoalMarker()

void cl_nav2z::backward_local_planner::BackwardLocalPlanner::publishGoalMarker ( double x,
double y,
double phi )
private

publishGoalMarker()

Definition at line 1183 of file backward_local_planner.cpp.

1184{
1185 visualization_msgs::msg::Marker marker;
1186 marker.header.frame_id = this->costmapRos_->getGlobalFrameID();
1187 marker.header.stamp = nh_->now();
1188
1189 marker.ns = "my_namespace2";
1190 marker.id = 0;
1191 marker.type = visualization_msgs::msg::Marker::ARROW;
1192 marker.action = visualization_msgs::msg::Marker::ADD;
1193 marker.lifetime = rclcpp::Duration(1.0s);
1194
1195 marker.pose.orientation.w = 1;
1196
1197 marker.scale.x = 0.05;
1198 marker.scale.y = 0.15;
1199 marker.scale.z = 0.05;
1200 marker.color.a = 1.0;
1201
1202 // red marker
1203 marker.color.r = 1;
1204 marker.color.g = 0;
1205 marker.color.b = 0;
1206
1207 geometry_msgs::msg::Point start, end;
1208 start.x = x;
1209 start.y = y;
1210
1211 end.x = x + 0.5 * cos(phi);
1212 end.y = y + 0.5 * sin(phi);
1213
1214 marker.points.push_back(start);
1215 marker.points.push_back(end);
1216
1217 visualization_msgs::msg::MarkerArray ma;
1218 ma.markers.push_back(marker);
1219
1220 goalMarkerPublisher_->publish(ma);
1221}

References costmapRos_, goalMarkerPublisher_, and nh_.

Referenced by computeVelocityCommands().

Here is the caller graph for this function:

◆ resamplePrecisePlan()

bool cl_nav2z::backward_local_planner::BackwardLocalPlanner::resamplePrecisePlan ( )
private

Definition at line 929 of file backward_local_planner.cpp.

930{
931 // this algorithm is really important to have a precise carrot (linear or angular)
932 // and not being considered as a divergence from the path
933
934 RCLCPP_INFO(nh_->get_logger(), "[BackwardLocalPlanner] resample precise");
935 if (backwardsPlanPath_.size() <= 1)
936 {
937 RCLCPP_INFO_STREAM(
938 nh_->get_logger(),
939 "[BackwardLocalPlanner] resample precise skipping, size: " << backwardsPlanPath_.size());
940 return false;
941 }
942
943 int counter = 0;
944 double maxallowedAngularError = 0.45 * this->carrot_angular_distance_; // nyquist
945 double maxallowedLinearError = 0.45 * this->carrot_distance_; // nyquist
946
947 for (int i = 0; i < (int)backwardsPlanPath_.size() - 1; i++)
948 {
949 RCLCPP_INFO_STREAM(nh_->get_logger(), "[BackwardLocalPlanner] resample precise, check: " << i);
950 auto & currpose = backwardsPlanPath_[i];
951 auto & nextpose = backwardsPlanPath_[i + 1];
952
953 tf2::Quaternion qCurrent, qNext;
954 tf2::convert(currpose.pose.orientation, qCurrent);
955 tf2::convert(nextpose.pose.orientation, qNext);
956
957 double dx = nextpose.pose.position.x - currpose.pose.position.x;
958 double dy = nextpose.pose.position.y - currpose.pose.position.y;
959 double dist = sqrt(dx * dx + dy * dy);
960
961 bool resample = false;
962 if (dist > maxallowedLinearError)
963 {
964 RCLCPP_INFO_STREAM(
965 nh_->get_logger(), "[BackwardLocalPlanner] resampling point, linear distance:"
966 << dist << "(" << maxallowedLinearError << ")" << i);
967 resample = true;
968 }
969 else
970 {
971 double currentAngle = tf2::getYaw(qCurrent);
972 double nextAngle = tf2::getYaw(qNext);
973
974 double angularError = fabs(angles::shortest_angular_distance(currentAngle, nextAngle));
975 if (angularError > maxallowedAngularError)
976 {
977 resample = true;
978 RCLCPP_INFO_STREAM(
979 nh_->get_logger(), "[BackwardLocalPlanner] resampling point, angular distance:"
980 << angularError << "(" << maxallowedAngularError << ")" << i);
981 }
982 }
983
984 if (resample)
985 {
986 geometry_msgs::msg::PoseStamped pintermediate;
987 auto duration = rclcpp::Time(nextpose.header.stamp) - rclcpp::Time(currpose.header.stamp);
988
989 pintermediate.header.frame_id = currpose.header.frame_id;
990 pintermediate.header.stamp = rclcpp::Time(currpose.header.stamp) + duration * 0.5;
991
992 pintermediate.pose.position.x = 0.5 * (currpose.pose.position.x + nextpose.pose.position.x);
993 pintermediate.pose.position.y = 0.5 * (currpose.pose.position.y + nextpose.pose.position.y);
994 pintermediate.pose.position.z = 0.5 * (currpose.pose.position.z + nextpose.pose.position.z);
995 tf2::Quaternion intermediateQuat = tf2::slerp(qCurrent, qNext, 0.5);
996 pintermediate.pose.orientation = tf2::toMsg(intermediateQuat);
997
998 this->backwardsPlanPath_.insert(this->backwardsPlanPath_.begin() + i + 1, pintermediate);
999
1000 // retry this point
1001 i--;
1002 counter++;
1003 }
1004 }
1005
1006 RCLCPP_INFO_STREAM(
1007 nh_->get_logger(), "[BackwardLocalPlanner] End resampling. resampled:" << counter
1008 << " new inserted poses "
1009 "during precise "
1010 "resmapling.");
1011 return true;
1012}

References backwardsPlanPath_, carrot_angular_distance_, carrot_distance_, and nh_.

Referenced by setPlan().

Here is the caller graph for this function:

◆ resetDivergenceDetection()

bool cl_nav2z::backward_local_planner::BackwardLocalPlanner::resetDivergenceDetection ( )
private

Definition at line 353 of file backward_local_planner.cpp.

354{
355 // this function should be called always the carrot is updated
356 divergenceDetectionLastCarrotLinearDistance_ = std::numeric_limits<double>::max();
357 return true;
358}

References divergenceDetectionLastCarrotLinearDistance_.

Referenced by setPlan(), and updateCarrotGoal().

Here is the caller graph for this function:

◆ setPlan()

void cl_nav2z::backward_local_planner::BackwardLocalPlanner::setPlan ( const nav_msgs::msg::Path & path)
override

nav2_core setPlan - Sets the global plan

Parameters
pathThe global plan

setPlan()

Definition at line 1019 of file backward_local_planner.cpp.

1020{
1021 RCLCPP_INFO_STREAM(
1022 nh_->get_logger(),
1023 "[BackwardLocalPlanner] setPlan: new global plan received ( " << path.poses.size() << ")");
1024
1025 //------------- TRANSFORM TO LOCAL FRAME PATH ---------------------------
1026 nav_msgs::msg::Path transformedPlan;
1027 rclcpp::Duration ttol = rclcpp::Duration::from_seconds(transform_tolerance_);
1028 // transform global plan to the navigation reference frame
1029 for (auto & p : path.poses)
1030 {
1031 geometry_msgs::msg::PoseStamped transformedPose;
1032 nav_2d_utils::transformPose(tf_, costmapRos_->getGlobalFrameID(), p, transformedPose, ttol);
1033 transformedPose.header.frame_id = costmapRos_->getGlobalFrameID();
1034 transformedPlan.poses.push_back(transformedPose);
1035 }
1036
1037 backwardsPlanPath_ = transformedPlan.poses;
1038
1039 // --------- resampling path feature -----------
1040 geometry_msgs::msg::PoseStamped tfpose;
1041 if (!costmapRos_->getRobotPose(tfpose))
1042 {
1043 RCLCPP_ERROR(nh_->get_logger(), "Failure getting pose from Backward local planner");
1044 return;
1045 }
1046
1047 geometry_msgs::msg::PoseStamped posestamped = tfpose;
1048 backwardsPlanPath_.insert(backwardsPlanPath_.begin(), posestamped);
1049 this->resamplePrecisePlan();
1050
1051 nav_msgs::msg::Path planMsg;
1052 planMsg.poses = backwardsPlanPath_;
1053 planMsg.header.frame_id = costmapRos_->getGlobalFrameID();
1054 planMsg.header.stamp = nh_->now();
1055 planPub_->publish(planMsg);
1056
1057 // ------ reset controller state ----------------------
1058 goalReached_ = false;
1061 // re-read the tolerances from the goal checker on the next control cycle: the selected
1062 // goal checker may have changed since the previous navigation (goal_checker_selector)
1063 xy_goal_tolerance_ = -1;
1066
1067 if (path.poses.size() == 0)
1068 {
1069 RCLCPP_INFO_STREAM(nh_->get_logger(), "[BackwardLocalPlanner] received plan without any pose");
1070 return;
1071 }
1072
1073 // -------- initialize carrot ----------------
1074 bool foundInitialCarrotGoal = this->findInitialCarrotGoal(tfpose);
1075 if (!foundInitialCarrotGoal)
1076 {
1077 RCLCPP_ERROR(
1078 nh_->get_logger(),
1079 "[BackwardLocalPlanner] new plan rejected. The initial point in the global path is "
1080 "too much far away from the current state (according to carrot_distance "
1081 "parameter)");
1082 // return false; // in this case, the new plan broke the current execution
1083 return;
1084 }
1085 else
1086 {
1087 this->divergenceDetectionUpdate(tfpose);
1088 return;
1089 }
1090}
bool findInitialCarrotGoal(geometry_msgs::msg::PoseStamped &pose)
bool divergenceDetectionUpdate(const geometry_msgs::msg::PoseStamped &pose)

References backwardsPlanPath_, costmapRos_, currentCarrotPoseIndex_, divergenceDetectionUpdate(), findInitialCarrotGoal(), goalReached_, inGoalPureSpinningState_, nh_, planPub_, resamplePrecisePlan(), resetDivergenceDetection(), tf_, transform_tolerance_, xy_goal_tolerance_, and yaw_goal_tolerance_.

Here is the call graph for this function:

◆ setSpeedLimit()

void cl_nav2z::backward_local_planner::BackwardLocalPlanner::setSpeedLimit ( const double & speed_limit,
const bool & percentage )
overridevirtual

Definition at line 244 of file backward_local_planner.cpp.

246{
247 RCLCPP_WARN_STREAM(
248 nh_->get_logger(),
249 "BackwardLocalPlanner::setSpeedLimit invoked. Ignored, functionality not "
250 "implemented.");
251}

References nh_.

◆ straightBackwardsAndPureSpinCmd()

void cl_nav2z::backward_local_planner::BackwardLocalPlanner::straightBackwardsAndPureSpinCmd ( const geometry_msgs::msg::PoseStamped & pose,
double & vetta,
double & gamma,
double alpha_error,
double betta_error,
double rho_error )
private

pureSpinningCmd()

Definition at line 458 of file backward_local_planner.cpp.

461{
462 if (rho_error > linear_mode_rho_error_threshold_) // works in straight motion mode
463 {
464 if (fabs(alpha_error) > initial_rotation_alpha_error_threshold_)
465 {
466 // backward heading is misaligned with the carrot direction: spin in place to
467 // align before translating. Without this gate the robot orbits the goal on
468 // curved-path endgames: at full backward speed the angular authority
469 // (max_angular_z_speed) yields a minimum turning radius larger than the goal
470 // tolerance, so a misaligned approach can never converge.
471 vetta = 0;
472 gamma = k_alpha_ * alpha_error;
473 }
474 else
475 {
476 vetta = k_rho_ * rho_error;
477 gamma = k_alpha_ * alpha_error;
478 }
479 }
480 else if (fabs(betta_error) >= this->yaw_goal_tolerance_) // works in pure spinning mode
481 {
482 vetta = 0; // disable linear
483 gamma = k_betta_ * betta_error;
484 }
485}

References initial_rotation_alpha_error_threshold_, k_alpha_, k_betta_, k_rho_, linear_mode_rho_error_threshold_, and yaw_goal_tolerance_.

Referenced by computeVelocityCommands().

Here is the caller graph for this function:

◆ updateCarrotGoal()

bool cl_nav2z::backward_local_planner::BackwardLocalPlanner::updateCarrotGoal ( const geometry_msgs::msg::PoseStamped & tfpose)
private

updateCarrotGoal()

Definition at line 291 of file backward_local_planner.cpp.

292{
293 RCLCPP_INFO_STREAM(nh_->get_logger(), "[BackwardsLocalPlanner] --- Carrot update ---");
294 double disterr = 0, angleerr = 0;
295 // iterate the point from the current position and backward until reaching a new goal point in the path
296 // this algorithm among other advantages has that skip the looping with an eager global planner
297 // that recalls the same plan (the already performed part of the plan in the current pose is skipped)
298 while (currentCarrotPoseIndex_ < (long)backwardsPlanPath_.size() - 1)
299 {
301
302 RCLCPP_INFO_STREAM(
303 nh_->get_logger(), "[BackwardsLocalPlanner] update carrot goal: Current index: "
304 << currentCarrotPoseIndex_ << "/" << backwardsPlanPath_.size());
305 RCLCPP_INFO(
306 nh_->get_logger(),
307 "[BackwardsLocalPlanner] update carrot goal: linear error %lf, angular error: %lf", disterr,
308 angleerr);
309
310 // target pose found, goal carrot tries to escape!
311 if (disterr < carrot_distance_ && angleerr < carrot_angular_distance_)
312 {
315 RCLCPP_INFO_STREAM(
316 nh_->get_logger(), "[BackwardsLocalPlanner] move carrot fw "
317 << currentCarrotPoseIndex_ << "/" << backwardsPlanPath_.size());
318 }
319 else
320 {
321 // carrot already escaped
322 break;
323 }
324 }
325 // RCLCPP_INFO(nh_->get_logger(),"[BackwardsLocalPlanner] computing angular error");
326 if (
327 currentCarrotPoseIndex_ >= (long)backwardsPlanPath_.size() - 1 && backwardsPlanPath_.size() > 0)
328 {
330 // reupdated errors
332 }
333
334 RCLCPP_INFO(
335 nh_->get_logger(), "[BackwardsLocalPlanner] Current index carrot goal: %d",
337 RCLCPP_INFO(
338 nh_->get_logger(),
339 "[BackwardsLocalPlanner] Update carrot goal: linear error %lf (xytol: %lf), angular error: "
340 "%lf",
341 disterr, xy_goal_tolerance_, angleerr);
342
343 bool carrotInGoalLinearRange = disterr < xy_goal_tolerance_;
344 RCLCPP_INFO(
345 nh_->get_logger(), "[BackwardsLocalPlanner] carrot in goal radius: %d",
346 carrotInGoalLinearRange);
347
348 RCLCPP_INFO(nh_->get_logger(), "[BackwardsLocalPlanner] ---End carrot update---");
349
350 return carrotInGoalLinearRange;
351}

References backwardsPlanPath_, carrot_angular_distance_, carrot_distance_, computeCurrentEuclideanAndAngularErrorsToCarrotGoal(), currentCarrotPoseIndex_, nh_, resetDivergenceDetection(), and xy_goal_tolerance_.

Referenced by computeVelocityCommands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ updateParameters()

void cl_nav2z::backward_local_planner::BackwardLocalPlanner::updateParameters ( )
private

Definition at line 175 of file backward_local_planner.cpp.

176{
177 RCLCPP_INFO_STREAM(nh_->get_logger(), "--- parameters ---");
178 tryGetOrSet(nh_, name_ + ".k_rho", k_rho_);
179 RCLCPP_INFO_STREAM(nh_->get_logger(), name_ + ".k_rho:" << k_rho_);
180 tryGetOrSet(nh_, name_ + ".k_alpha", k_alpha_);
181 RCLCPP_INFO_STREAM(nh_->get_logger(), name_ + ".k_alpha:" << k_alpha_);
182 tryGetOrSet(nh_, name_ + ".k_betta", k_betta_);
183 RCLCPP_INFO_STREAM(nh_->get_logger(), name_ + ".k_betta:" << k_betta_);
185 nh_, name_ + ".initial_rotation_alpha_error_threshold",
187 RCLCPP_INFO_STREAM(
188 nh_->get_logger(),
189 name_ + ".initial_rotation_alpha_error_threshold: " << initial_rotation_alpha_error_threshold_);
190
191 tryGetOrSet(nh_, name_ + ".enable_obstacle_checking", enable_obstacle_checking_);
192 RCLCPP_INFO_STREAM(
193 nh_->get_logger(), name_ + ".enable_obstacle_checking: " << enable_obstacle_checking_);
194
195 tryGetOrSet(nh_, name_ + ".carrot_distance", carrot_distance_);
196 RCLCPP_INFO_STREAM(nh_->get_logger(), name_ + ".carrot_distance:" << carrot_distance_);
197 tryGetOrSet(nh_, name_ + ".carrot_angular_distance", carrot_angular_distance_);
198 RCLCPP_INFO_STREAM(
199 nh_->get_logger(), name_ + ".carrot_angular_distance: " << carrot_angular_distance_);
200
202 nh_, name_ + ".pure_spinning_straight_line_mode", straightBackwardsAndPureSpinningMode_);
203 RCLCPP_INFO_STREAM(
204 nh_->get_logger(),
205 name_ + ".pure_spinning_straight_line_mode: " << straightBackwardsAndPureSpinningMode_);
206
207 tryGetOrSet(nh_, name_ + ".linear_mode_rho_error_threshold", linear_mode_rho_error_threshold_);
208 RCLCPP_INFO_STREAM(
209 nh_->get_logger(),
210 name_ + ".linear_mode_rho_error_threshold: " << linear_mode_rho_error_threshold_);
211 tryGetOrSet(nh_, name_ + ".max_linear_x_speed", max_linear_x_speed_);
212 RCLCPP_INFO_STREAM(nh_->get_logger(), name_ + ".max_linear_x_speed: " << max_linear_x_speed_);
213 tryGetOrSet(nh_, name_ + ".max_angular_z_speed", max_angular_z_speed_);
214 RCLCPP_INFO_STREAM(nh_->get_logger(), name_ + ".max_angular_z_speed: " << max_angular_z_speed_);
215
217 {
218 RCLCPP_WARN_STREAM(
219 nh_->get_logger(), "[BackwardLocalPlanner] carrot_angular_distance ("
221 << ") cannot be lower than yaw_goal_tolerance (" << yaw_goal_tolerance_
222 << ") setting carrot_angular_distance = " << yaw_goal_tolerance_);
224 nh_->set_parameter(
225 rclcpp::Parameter(name_ + ".carrot_angular_distance", carrot_angular_distance_));
226 }
227 RCLCPP_INFO_STREAM(
228 nh_->get_logger(), name_ + ".carrot_angular_distance: " << carrot_angular_distance_);
229
231 {
232 RCLCPP_WARN_STREAM(
233 nh_->get_logger(), "[BackwardLocalPlanner] carrot_linear_distance ("
234 << carrot_distance_ << ") cannot be lower than xy_goal_tolerance_ ("
236 << ") setting carrot_angular_distance = " << xy_goal_tolerance_);
238 nh_->set_parameter(rclcpp::Parameter(name_ + ".carrot_distance", carrot_distance_));
239 }
240 RCLCPP_INFO_STREAM(nh_->get_logger(), name_ + ".carrot_distance:" << carrot_distance_);
241 RCLCPP_INFO_STREAM(nh_->get_logger(), "--- end params ---");
242}
void tryGetOrSet(rclcpp_lifecycle::LifecycleNode::SharedPtr &node, std::string param, T &value)

References carrot_angular_distance_, carrot_distance_, enable_obstacle_checking_, initial_rotation_alpha_error_threshold_, k_alpha_, k_betta_, k_rho_, linear_mode_rho_error_threshold_, max_angular_z_speed_, max_linear_x_speed_, name_, nh_, straightBackwardsAndPureSpinningMode_, cl_nav2z::backward_local_planner::tryGetOrSet(), xy_goal_tolerance_, and yaw_goal_tolerance_.

Referenced by activate(), and computeVelocityCommands().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ alpha_offset_

const double cl_nav2z::backward_local_planner::BackwardLocalPlanner::alpha_offset_ = M_PI
private

Definition at line 140 of file backward_local_planner.hpp.

Referenced by computeVelocityCommands().

◆ backwardsPlanPath_

std::vector<geometry_msgs::msg::PoseStamped> cl_nav2z::backward_local_planner::BackwardLocalPlanner::backwardsPlanPath_
private

◆ betta_offset_

const double cl_nav2z::backward_local_planner::BackwardLocalPlanner::betta_offset_ = 0
private

Definition at line 141 of file backward_local_planner.hpp.

Referenced by computeVelocityCommands().

◆ carrot_angular_distance_

rad cl_nav2z::backward_local_planner::BackwardLocalPlanner::carrot_angular_distance_
private

◆ carrot_distance_

meter cl_nav2z::backward_local_planner::BackwardLocalPlanner::carrot_distance_
private

◆ costmapRos_

std::shared_ptr<nav2_costmap_2d::Costmap2DROS> cl_nav2z::backward_local_planner::BackwardLocalPlanner::costmapRos_
private

◆ currentCarrotPoseIndex_

int cl_nav2z::backward_local_planner::BackwardLocalPlanner::currentCarrotPoseIndex_
private

◆ divergenceDetectionLastCarrotLinearDistance_

meter cl_nav2z::backward_local_planner::BackwardLocalPlanner::divergenceDetectionLastCarrotLinearDistance_
private

◆ enable_obstacle_checking_

bool cl_nav2z::backward_local_planner::BackwardLocalPlanner::enable_obstacle_checking_ = true
private

◆ goalMarkerPublisher_

std::shared_ptr<rclcpp_lifecycle::LifecyclePublisher<visualization_msgs::msg::MarkerArray> > cl_nav2z::backward_local_planner::BackwardLocalPlanner::goalMarkerPublisher_
private

◆ goalReached_

bool cl_nav2z::backward_local_planner::BackwardLocalPlanner::goalReached_
private

Definition at line 159 of file backward_local_planner.hpp.

Referenced by computeVelocityCommands(), isGoalReached(), and setPlan().

◆ inGoalPureSpinningState_

bool cl_nav2z::backward_local_planner::BackwardLocalPlanner::inGoalPureSpinningState_ = false
private

Definition at line 163 of file backward_local_planner.hpp.

Referenced by computeVelocityCommands(), and setPlan().

◆ initial_rotation_alpha_error_threshold_

double cl_nav2z::backward_local_planner::BackwardLocalPlanner::initial_rotation_alpha_error_threshold_
private

◆ initialPureSpinningStage_

bool cl_nav2z::backward_local_planner::BackwardLocalPlanner::initialPureSpinningStage_
private

Definition at line 160 of file backward_local_planner.hpp.

◆ k_alpha_

double cl_nav2z::backward_local_planner::BackwardLocalPlanner::k_alpha_
private

◆ k_betta_

double cl_nav2z::backward_local_planner::BackwardLocalPlanner::k_betta_
private

◆ k_rho_

double cl_nav2z::backward_local_planner::BackwardLocalPlanner::k_rho_
private

◆ linear_mode_rho_error_threshold_

double cl_nav2z::backward_local_planner::BackwardLocalPlanner::linear_mode_rho_error_threshold_
private

◆ max_angular_z_speed_

double cl_nav2z::backward_local_planner::BackwardLocalPlanner::max_angular_z_speed_
private

◆ max_linear_x_speed_

double cl_nav2z::backward_local_planner::BackwardLocalPlanner::max_linear_x_speed_
private

◆ name_

std::string cl_nav2z::backward_local_planner::BackwardLocalPlanner::name_
private

Definition at line 119 of file backward_local_planner.hpp.

Referenced by configure(), and updateParameters().

◆ nh_

◆ planPub_

std::shared_ptr<rclcpp_lifecycle::LifecyclePublisher<nav_msgs::msg::Path> > cl_nav2z::backward_local_planner::BackwardLocalPlanner::planPub_
private

Definition at line 127 of file backward_local_planner.hpp.

Referenced by activate(), configure(), deactivate(), and setPlan().

◆ pure_spinning_allowed_betta_error_

double cl_nav2z::backward_local_planner::BackwardLocalPlanner::pure_spinning_allowed_betta_error_
private

Definition at line 133 of file backward_local_planner.hpp.

◆ straightBackwardsAndPureSpinningMode_

bool cl_nav2z::backward_local_planner::BackwardLocalPlanner::straightBackwardsAndPureSpinningMode_ = false
private

◆ tf_

std::shared_ptr<tf2_ros::Buffer> cl_nav2z::backward_local_planner::BackwardLocalPlanner::tf_
private

Definition at line 123 of file backward_local_planner.hpp.

Referenced by configure(), and setPlan().

◆ transform_tolerance_

double cl_nav2z::backward_local_planner::BackwardLocalPlanner::transform_tolerance_
private

Definition at line 153 of file backward_local_planner.hpp.

Referenced by configure(), and setPlan().

◆ waiting_

bool cl_nav2z::backward_local_planner::BackwardLocalPlanner::waiting_
private

Definition at line 164 of file backward_local_planner.hpp.

Referenced by computeVelocityCommands().

◆ waitingStamp_

rclcpp::Time cl_nav2z::backward_local_planner::BackwardLocalPlanner::waitingStamp_
private

Definition at line 156 of file backward_local_planner.hpp.

Referenced by computeVelocityCommands().

◆ waitingTimeout_

rclcpp::Duration cl_nav2z::backward_local_planner::BackwardLocalPlanner::waitingTimeout_
private

Definition at line 155 of file backward_local_planner.hpp.

Referenced by computeVelocityCommands(), and configure().

◆ xy_goal_tolerance_

double cl_nav2z::backward_local_planner::BackwardLocalPlanner::xy_goal_tolerance_
private

◆ yaw_goal_tolerance_

double cl_nav2z::backward_local_planner::BackwardLocalPlanner::yaw_goal_tolerance_
private

The documentation for this class was generated from the following files: