|
21 | 21 | #include <beluga/algorithm/cluster_based_estimation.hpp> |
22 | 22 | #include <beluga/views/random_intersperse.hpp> |
23 | 23 | #include <beluga/views/take_while_kld.hpp> |
| 24 | +#include <algorithm> |
24 | 25 | #include <cmath> |
| 26 | +#include <limits> |
| 27 | +#include <random> |
| 28 | +#include <vector> |
25 | 29 |
|
26 | 30 | namespace beluga_ros { |
27 | 31 |
|
@@ -122,7 +126,47 @@ auto Amcl::update( |
122 | 126 | } |
123 | 127 |
|
124 | 128 | 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); |
126 | 170 | } |
127 | 171 |
|
128 | 172 | } // namespace beluga_ros |
0 commit comments