35 #include "dwb_critics/oscillation.hpp"
40 #include "nav2_ros_common/node_utils.hpp"
41 #include "dwb_core/exceptions.hpp"
42 #include "pluginlib/class_list_macros.hpp"
43 #include "angles/angles.h"
51 OscillationCritic::CommandTrend::CommandTrend()
56 void OscillationCritic::CommandTrend::reset()
59 positive_only_ =
false;
60 negative_only_ =
false;
63 bool OscillationCritic::CommandTrend::update(
double velocity)
65 bool flag_set =
false;
67 if (sign_ == Sign::POSITIVE) {
68 negative_only_ =
true;
71 sign_ = Sign::NEGATIVE;
72 }
else if (velocity > 0.0) {
73 if (sign_ == Sign::NEGATIVE) {
74 positive_only_ =
true;
77 sign_ = Sign::POSITIVE;
82 bool OscillationCritic::CommandTrend::isOscillating(
double velocity)
84 return (positive_only_ && velocity < 0.0) || (negative_only_ && velocity > 0.0);
87 bool OscillationCritic::CommandTrend::hasSignFlipped()
89 return positive_only_ || negative_only_;
94 auto node = node_.lock();
96 throw std::runtime_error{
"Failed to lock node"};
99 clock_ = node->get_clock();
101 oscillation_reset_dist_ = node->declare_or_get_parameter(dwb_plugin_name_ +
"." + name_ +
102 ".oscillation_reset_dist", 0.05);
103 oscillation_reset_dist_sq_ = oscillation_reset_dist_ * oscillation_reset_dist_;
104 oscillation_reset_angle_ = node->declare_or_get_parameter(
105 dwb_plugin_name_ +
"." + name_ +
".oscillation_reset_angle", 0.2);
106 oscillation_reset_time_ = rclcpp::Duration::from_seconds(
107 node->declare_or_get_parameter(
108 dwb_plugin_name_ +
"." + name_ +
".oscillation_reset_time", -1.0));
110 nav2::declare_parameter_if_not_declared(
112 dwb_plugin_name_ +
"." + name_ +
".x_only_threshold", rclcpp::ParameterValue(0.05));
121 node->get_parameter(dwb_plugin_name_ +
"." + name_ +
".x_only_threshold", x_only_threshold_);
148 const geometry_msgs::msg::Pose & pose,
149 const nav_2d_msgs::msg::Twist2D &,
150 const geometry_msgs::msg::Pose &,
151 const nav_msgs::msg::Path &)
159 if (setOscillationFlags(cmd_vel)) {
160 prev_stationary_pose_ = pose_;
161 prev_reset_time_ = clock_->now();
165 if (x_trend_.hasSignFlipped() || y_trend_.hasSignFlipped() || theta_trend_.hasSignFlipped()) {
167 if (resetAvailable()) {
172 bool OscillationCritic::resetAvailable()
174 if (oscillation_reset_dist_ >= 0.0) {
175 double x_diff = pose_.position.x - prev_stationary_pose_.position.x;
176 double y_diff = pose_.position.y - prev_stationary_pose_.position.y;
177 double sq_dist = x_diff * x_diff + y_diff * y_diff;
178 if (sq_dist > oscillation_reset_dist_sq_) {
182 if (oscillation_reset_angle_ >= 0.0) {
183 tf2::Quaternion pose_q, prev_stationary_pose_q;
184 tf2::fromMsg(pose_.orientation, pose_q);
185 tf2::fromMsg(prev_stationary_pose_.orientation, prev_stationary_pose_q);
187 double th_diff = angles::shortest_angular_distance(
188 tf2::getYaw(pose_q), tf2::getYaw(prev_stationary_pose_q));
190 if (fabs(th_diff) > oscillation_reset_angle_) {
194 if (oscillation_reset_time_ >= rclcpp::Duration::from_seconds(0.0)) {
195 auto t_diff = (clock_->now() - prev_reset_time_);
196 if (t_diff > oscillation_reset_time_) {
207 theta_trend_.reset();
210 bool OscillationCritic::setOscillationFlags(
const nav_2d_msgs::msg::Twist2D & cmd_vel)
212 bool flag_set =
false;
214 flag_set |= x_trend_.update(cmd_vel.x);
217 if (x_only_threshold_ < 0.0 || fabs(cmd_vel.x) <= x_only_threshold_) {
218 flag_set |= y_trend_.update(cmd_vel.y);
219 flag_set |= theta_trend_.update(cmd_vel.theta);
226 if (x_trend_.isOscillating(traj.velocity.x) ||
227 y_trend_.isOscillating(traj.velocity.y) ||
228 theta_trend_.isOscillating(traj.velocity.theta))
231 IllegalTrajectoryException(name_,
"Trajectory is oscillating.");
Evaluates a Trajectory2D to produce a score.
Checks to see whether the sign of the commanded velocity flips frequently.
void debrief(const nav_2d_msgs::msg::Twist2D &cmd_vel) override
debrief informs the critic what the chosen cmd_vel was (if it cares)
bool prepare(const geometry_msgs::msg::Pose &pose, const nav_2d_msgs::msg::Twist2D &vel, const geometry_msgs::msg::Pose &goal, const nav_msgs::msg::Path &global_plan) override
Prior to evaluating any trajectories, look at contextual information constant across all trajectories...
double scoreTrajectory(const dwb_msgs::msg::Trajectory2D &traj) override
Return a raw score for the given trajectory.
void reset() override
Reset the state of the critic.