Skip to content

Commit 0764311

Browse files
author
Patricio Palma
committed
In reference to #562
Parameters for expected standard deviation x, y and yaw were added. Added compute_quality function.
1 parent b06f906 commit 0764311

2 files changed

Lines changed: 65 additions & 1 deletion

File tree

beluga_ros/include/beluga_ros/amcl.hpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,15 @@ struct AmclParams {
9595

9696
/// \brief Spatial resolution around the z-axis to create buckets for KLD resampling.
9797
double spatial_resolution_theta = 10 * Sophus::Constants<double>::pi() / 180;
98+
99+
/// \brief Expected standard deviation of x in a healthy particle distribution, used for quality estimation [m].
100+
double expected_pose_x_stddev = 0.1;
101+
102+
/// \brief Expected standard deviation of y in a healthy particle distribution, used for quality estimation [m].
103+
double expected_pose_y_stddev = 0.1;
104+
105+
/// \brief Expected standard deviation of yaw in a healthy particle distribution, used for quality estimation [rad].
106+
double expected_pose_yaw_stddev = 0.05;
98107
};
99108

100109
/// Implementation of the 2D Adaptive Monte Carlo Localization (AMCL) algorithm.
@@ -262,6 +271,14 @@ class Amcl {
262271
/// Force a manual update of the particles on the next iteration of the filter.
263272
void force_update() { force_update_ = true; }
264273

274+
/// Returns the localization quality score from the last filter update.
275+
/**
276+
* The score is in [0, 1], where close to 1 means the filter covariance is within the expected
277+
* and values approaching 0 indicate the filter may be diverging.
278+
* Returns 1.0 before the first successful update.
279+
*/
280+
[[nodiscard]] double quality() const { return last_quality_; }
281+
265282
private:
266283
beluga::TupleVector<particle_type> particles_;
267284

@@ -279,6 +296,9 @@ class Amcl {
279296
beluga::RollingWindow<Sophus::SE2d, 2> control_action_window_;
280297

281298
bool force_update_{true};
299+
double last_quality_{1.0};
300+
301+
double compute_quality(const Sophus::Matrix3d& actual_covariance);
282302
};
283303

284304
} // namespace beluga_ros

beluga_ros/src/amcl.cpp

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@
2121
#include <beluga/algorithm/cluster_based_estimation.hpp>
2222
#include <beluga/views/random_intersperse.hpp>
2323
#include <beluga/views/take_while_kld.hpp>
24+
#include <algorithm>
2425
#include <cmath>
26+
#include <limits>
27+
#include <random>
28+
#include <vector>
2529

2630
namespace beluga_ros {
2731

@@ -122,7 +126,47 @@ auto Amcl::update(
122126
}
123127

124128
force_update_ = false;
125-
return beluga::cluster_based_estimate(beluga::views::states(particles_), beluga::views::weights(particles_));
129+
auto estimate =
130+
beluga::cluster_based_estimate(beluga::views::states(particles_), beluga::views::weights(particles_));
131+
last_quality_ = compute_quality(estimate.second);
132+
return estimate;
133+
}
134+
135+
double Amcl::compute_quality(const Sophus::Matrix3d& actual_covariance) {
136+
const std::size_t N = params_.min_particles;
137+
138+
// a known seed is required to provide the exact same reference each time quality is computed.
139+
std::mt19937 gen{42};
140+
std::normal_distribution<double> dx{0.0, params_.expected_pose_x_stddev};
141+
std::normal_distribution<double> dy{0.0, params_.expected_pose_y_stddev};
142+
std::normal_distribution<double> dyaw{0.0, params_.expected_pose_yaw_stddev};
143+
144+
std::vector<Sophus::SE2d> ref_states;
145+
ref_states.reserve(N);
146+
for (std::size_t i = 0; i < N; ++i) {
147+
ref_states.emplace_back(Sophus::SO2d{dyaw(gen)}, Sophus::Vector2d{dx(gen), dy(gen)});
148+
}
149+
150+
std::visit(
151+
[&](const auto& motion_model) {
152+
auto sampling_fn = motion_model(control_action_window_);
153+
for (auto& state : ref_states) {
154+
state = sampling_fn(state, gen);
155+
}
156+
},
157+
motion_model_);
158+
159+
const std::vector<double> uniform_weights(N, 1.0);
160+
const auto [ref_mean, ref_covariance] = beluga::estimate(ref_states, uniform_weights);
161+
162+
double quality = 1.0;
163+
for (int i = 0; i < 3; ++i) {
164+
const double actual = actual_covariance.coeff(i, i);
165+
if (actual > std::numeric_limits<double>::epsilon()) {
166+
quality = std::min(quality, ref_covariance.coeff(i, i) / actual);
167+
}
168+
}
169+
return std::clamp(quality, 0.0, 1.0);
126170
}
127171

128172
} // namespace beluga_ros

0 commit comments

Comments
 (0)