-
Notifications
You must be signed in to change notification settings - Fork 0
FSF-8582 Perception filter #419
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
21ef3d1
aca1ab7
805276e
37cce64
a332674
aaa8644
7cd6b00
7dace8b
2930995
e719df7
7f61c65
b986ec9
b7741a1
805544f
fbfb793
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
#pragma once | ||
#include <Eigen/Dense> | ||
#include <memory> | ||
#include <vector> | ||
|
||
#include "perception_sensor_lib/data_association/base_data_association.hpp" | ||
#include "perception_sensor_lib/landmark_filter/parameters.hpp" | ||
|
||
/** | ||
* @brief This class is meant to filter observations from perception to try to reduce the presence | ||
* of outliers | ||
* | ||
*/ | ||
class LandmarkFilter { | ||
protected: | ||
LandmarkFilterParameters _params_; | ||
std::shared_ptr<DataAssociationModel> _data_association_; | ||
|
||
public: | ||
LandmarkFilter() = default; | ||
LandmarkFilter(LandmarkFilterParameters params, | ||
std::shared_ptr<DataAssociationModel> data_association) | ||
: _params_(params), _data_association_(data_association) {} | ||
virtual ~LandmarkFilter() = default; | ||
/** | ||
* @brief This function receives a new set of observations and returns a filtered set of landmarks | ||
* in global coordinates that are ready to be added to be added to the map | ||
* | ||
* @param observations Observations in the form of [x1, y1, x2, y2, ...] in the global frame | ||
* @param observation_confidences Confidence in the observations in the same order as the | ||
* observations | ||
* @return Eigen::VectorXd the filtered observations in the form of [x1, y1, x2, y2, ...] in the | ||
* global frame | ||
*/ | ||
virtual Eigen::VectorXd filter(const Eigen::VectorXd& new_observations, | ||
const Eigen::VectorXd& new_observation_confidences) = 0; | ||
/** | ||
* @brief Used by SLAM to signal to the filter that the landmarks are already in SLAM's map, and | ||
* they should no longer be returned by the filter as new. | ||
* | ||
* @param some_landmarks landmarks to be deleted in the form of [x1, y1, x2, y2, ...] in the | ||
* global frame | ||
*/ | ||
virtual void delete_landmarks(const Eigen::VectorXd& some_landmarks) = 0; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
#include <set> | ||
|
||
#include "perception_sensor_lib/landmark_filter/base_landmark_filter.hpp" | ||
#define EQUALITY_TOLERANCE 1e-3 | ||
|
||
class ConsecutiveCounterFilter : public LandmarkFilter { | ||
private: | ||
Eigen::VectorXd map; | ||
Eigen::VectorXi counter; | ||
|
||
public: | ||
ConsecutiveCounterFilter(LandmarkFilterParameters params, | ||
std::shared_ptr<DataAssociationModel> data_association) | ||
: LandmarkFilter(params, data_association), map(Eigen::VectorXd::Zero(0)) {} | ||
|
||
Eigen::VectorXd filter(const Eigen::VectorXd& new_observations, | ||
const Eigen::VectorXd& new_observation_confidences) override; | ||
|
||
void delete_landmarks(const Eigen::VectorXd& some_landmarks) override; | ||
friend class ConsecutiveCounterFilter_TestCase1_Test; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#pragma once | ||
|
||
#include <map> | ||
#include <memory> | ||
#include <string> | ||
|
||
#include "perception_sensor_lib/data_association/base_data_association.hpp" | ||
#include "perception_sensor_lib/landmark_filter/consecutive_counter_filter.hpp" | ||
|
||
/** | ||
* @brief Map of landmark filters, with the key being the name of the landmark filter | ||
* and the value being a lambda function that returns a shared pointer to the corresponding | ||
* LandmarkFilter object. | ||
*/ | ||
const std::map<std::string, | ||
std::function<std::shared_ptr<LandmarkFilter>( | ||
const LandmarkFilterParameters&, std::shared_ptr<DataAssociationModel>)>, | ||
std::less<>> | ||
landmark_filters_map = { | ||
{"consecutive_count", | ||
[](const LandmarkFilterParameters& params, | ||
std::shared_ptr<DataAssociationModel> data_association) | ||
-> std::shared_ptr<LandmarkFilter> { | ||
return std::make_shared<ConsecutiveCounterFilter>(params, data_association); | ||
}}, | ||
}; |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,13 @@ | ||||||||||||||||||||||||||||
#pragma once | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
struct LandmarkFilterParameters { | ||||||||||||||||||||||||||||
int minimum_observation_count_ = 3; | ||||||||||||||||||||||||||||
double minimum_frequency_of_detections_ = 5; | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
LandmarkFilterParameters() = default; | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
LandmarkFilterParameters(const int minimum_observation_count, | ||||||||||||||||||||||||||||
const double minimum_frequency_of_detections) | ||||||||||||||||||||||||||||
: minimum_observation_count_(minimum_observation_count), | ||||||||||||||||||||||||||||
minimum_frequency_of_detections_(minimum_frequency_of_detections) {} | ||||||||||||||||||||||||||||
Comment on lines
+5
to
+12
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nitpick]
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||||||||||||||||||||||||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,51 +4,35 @@ | |
#include <limits> | ||
#include <vector> | ||
|
||
#define INFINITESIMAL 1e-9 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nitpick] Consider replacing this macro with a Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||
|
||
Eigen::VectorXi MaximumLikelihoodMD::associate( | ||
const Eigen::VectorXd& state, const Eigen::MatrixXd& covariance, | ||
const Eigen::VectorXd& observations, const Eigen::VectorXd& observation_confidences) const { | ||
int num_observations = observations.size() / 2; | ||
const Eigen::VectorXd& landmarks, const Eigen::VectorXd& observations, | ||
const Eigen::MatrixXd& covariance, const Eigen::VectorXd& observation_confidences) const { | ||
const int num_observations = observations.size() / 2; | ||
const int num_landmarks = landmarks.size() / 2; | ||
Eigen::VectorXi associations = | ||
Eigen::VectorXi::Constant(num_observations, -2); // Default: not associated (-2) | ||
|
||
double car_x = state(0); | ||
double car_y = state(1); | ||
double car_theta = state(2); | ||
double cos_theta = std::cos(car_theta); | ||
double sin_theta = std::sin(car_theta); | ||
|
||
// Get coordinates of all landmarks in local frame | ||
Eigen::VectorXd landmarks_local_coordinates = common_lib::maths::global_to_local_coordinates( | ||
state.segment(0, 3), state.segment(3, state.size() - 3)); | ||
|
||
for (int i = 0; i < num_observations; ++i) { | ||
Eigen::Vector2d obs; | ||
obs << observations(2 * i), observations(2 * i + 1); | ||
|
||
double best_cost = std::numeric_limits<double>::max(); | ||
int best_landmark_index = -1; | ||
|
||
for (int j = 3; j < state.size(); j += 2) { | ||
// Check if the landmark is within a valid distance from the car | ||
double distance = | ||
std::hypot(landmarks_local_coordinates(j - 3), landmarks_local_coordinates(j - 2)); | ||
if (distance > this->_params_.max_landmark_distance) continue; | ||
|
||
// Extract landmark global coordinates | ||
double lx = state(j); | ||
double ly = state(j + 1); | ||
double dx = lx - car_x; | ||
double dy = ly - car_y; | ||
|
||
for (int j = 0; j < num_landmarks; j++) { | ||
// Innovation: difference between actual and predicted observation | ||
Eigen::Vector2d innovation = obs - landmarks_local_coordinates.segment(j - 3, 2); | ||
Eigen::Vector2d innovation = obs - landmarks.segment(2 * j, 2); | ||
|
||
Eigen::Matrix2d innovation_covariance = covariance.block(j, j, 2, 2); | ||
Eigen::Matrix2d innovation_covariance = | ||
covariance.block(2 * j, 2 * j, 2, 2) + this->observation_noise_covariance_matrix_; | ||
// Guard against non-invertible innovation_covariance | ||
double det = innovation_covariance.determinant(); | ||
if (det == 0) { | ||
if (std::abs(det) <= INFINITESIMAL) { | ||
RCLCPP_WARN(rclcpp::get_logger("data_association"), | ||
"Non-invertible innovation covariance matrix"); | ||
"Non-invertible innovation covariance matrix for landmark at : [%f, %f]", | ||
landmarks(2 * j), landmarks(2 * j + 1)); | ||
continue; | ||
} | ||
double normalized_innovation_squared = | ||
|
@@ -57,7 +41,7 @@ Eigen::VectorXi MaximumLikelihoodMD::associate( | |
// Check if this landmark is a good candidate for association | ||
if (normalized_innovation_squared < best_cost) { | ||
best_cost = normalized_innovation_squared; | ||
best_landmark_index = j; | ||
best_landmark_index = 2 * j; | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Using a macro for a tolerance value can lead to unexpected name collisions; consider using a
constexpr double kEqualityTolerance = 1e-3;
instead.Copilot uses AI. Check for mistakes.