35 #include "dwb_critics/oscillation.hpp"
40 #include "dwb_core/exceptions.hpp"
41 #include "pluginlib/class_list_macros.hpp"
42 #include "angles/angles.h"
50 OscillationCritic::CommandTrend::CommandTrend()
55 void OscillationCritic::CommandTrend::reset()
58 positive_only_ =
false;
59 negative_only_ =
false;
62 bool OscillationCritic::CommandTrend::update(
double velocity)
64 bool flag_set =
false;
66 if (sign_ == Sign::POSITIVE) {
67 negative_only_ =
true;
70 sign_ = Sign::NEGATIVE;
71 }
else if (velocity > 0.0) {
72 if (sign_ == Sign::NEGATIVE) {
73 positive_only_ =
true;
76 sign_ = Sign::POSITIVE;
81 bool OscillationCritic::CommandTrend::isOscillating(
double velocity)
83 return (positive_only_ && velocity < 0.0) || (negative_only_ && velocity > 0.0);
86 bool OscillationCritic::CommandTrend::hasSignFlipped()
88 return positive_only_ || negative_only_;
91 void OscillationCritic::onInit()
93 auto node = node_.lock();
95 throw std::runtime_error{
"Failed to lock node"};
98 clock_ = node->get_clock();
100 oscillation_reset_dist_ = node->declare_or_get_parameter(
101 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 x_only_threshold_ = node->declare_or_get_parameter(
111 dwb_plugin_name_ +
"." + name_ +
".x_only_threshold", 0.05);
117 const geometry_msgs::msg::Pose & pose,
118 const nav_2d_msgs::msg::Twist2D &,
119 const geometry_msgs::msg::Pose &,
120 const nav_msgs::msg::Path &)
128 if (setOscillationFlags(cmd_vel)) {
129 prev_stationary_pose_ = pose_;
130 prev_reset_time_ = clock_->now();
134 if (x_trend_.hasSignFlipped() || y_trend_.hasSignFlipped() || theta_trend_.hasSignFlipped()) {
136 if (resetAvailable()) {
141 bool OscillationCritic::resetAvailable()
143 if (oscillation_reset_dist_ >= 0.0) {
144 double x_diff = pose_.position.x - prev_stationary_pose_.position.x;
145 double y_diff = pose_.position.y - prev_stationary_pose_.position.y;
146 double sq_dist = x_diff * x_diff + y_diff * y_diff;
147 if (sq_dist > oscillation_reset_dist_sq_) {
151 if (oscillation_reset_angle_ >= 0.0) {
152 tf2::Quaternion pose_q, prev_stationary_pose_q;
153 tf2::fromMsg(pose_.orientation, pose_q);
154 tf2::fromMsg(prev_stationary_pose_.orientation, prev_stationary_pose_q);
156 double th_diff = angles::shortest_angular_distance(
157 tf2::getYaw(pose_q), tf2::getYaw(prev_stationary_pose_q));
159 if (fabs(th_diff) > oscillation_reset_angle_) {
163 if (oscillation_reset_time_ >= rclcpp::Duration::from_seconds(0.0)) {
164 auto t_diff = (clock_->now() - prev_reset_time_);
165 if (t_diff > oscillation_reset_time_) {
176 theta_trend_.reset();
179 bool OscillationCritic::setOscillationFlags(
const nav_2d_msgs::msg::Twist2D & cmd_vel)
181 bool flag_set =
false;
183 flag_set |= x_trend_.update(cmd_vel.x);
186 if (x_only_threshold_ < 0.0 || fabs(cmd_vel.x) <= x_only_threshold_) {
187 flag_set |= y_trend_.update(cmd_vel.y);
188 flag_set |= theta_trend_.update(cmd_vel.theta);
195 if (x_trend_.isOscillating(traj.velocity.x) ||
196 y_trend_.isOscillating(traj.velocity.y) ||
197 theta_trend_.isOscillating(traj.velocity.theta))
200 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.