Formula Student Autonomous Systems
The code for the main driverless system
Loading...
Searching...
No Matches
graph_slam_solver_test.cpp
Go to the documentation of this file.
2
3#include <gmock/gmock.h>
4#include <gtest/gtest.h>
5#include <yaml-cpp/yaml.h>
6
8public:
9 MOCK_METHOD(Eigen::VectorXi, associate,
10 (const Eigen::VectorXd& state, const Eigen::VectorXd& observations,
11 const Eigen::MatrixXd& covariance, const Eigen::VectorXd& observation_confidences),
12 (const, override));
13};
14
16public:
17 MOCK_METHOD(Eigen::VectorXd, filter,
18 (const Eigen::VectorXd& observations, const Eigen::VectorXd& observation_confidences,
19 Eigen::VectorXi& associations),
20 (override));
21 MOCK_METHOD(void, delete_landmarks, (const Eigen::VectorXd& some_landmarks), (override));
22};
23
25public:
27 (const Eigen::Vector3d& previous_pose, const Eigen::VectorXd& motion_data,
28 double delta_t),
29 (override));
30
32 (const Eigen::Vector3d& previous_pose, const Eigen::VectorXd& motion_data,
33 const double delta_t),
34 (override));
35
37 (const Eigen::Vector3d& previous_pose, const Eigen::VectorXd& motion_data,
38 const double delta_t),
39 (override));
40};
41
43public:
45 (const Eigen::Vector3d& current_pose, const Eigen::VectorXd& map_cones,
46 const Eigen::VectorXi& associations, const Eigen::VectorXd& observations),
47 (const, override));
48};
49
53class GraphSlamSolverTest : public testing::Test {
54public:
56 mock_motion_model_ptr = std::make_shared<MockV2PModel>();
57 mock_data_association_ptr = std::make_shared<MockDataAssociationModel>();
58 mock_landmark_filter_ptr = std::make_shared<MockLandmarkFilter>();
59 mock_loop_closure_ptr = std::make_shared<MockLoopClosure>();
64 solver = std::make_shared<GraphSLAMSolver>(params, data_association_ptr, motion_model_ptr,
67 this->solver->set_mission(common_lib::competition_logic::Mission::AUTOCROSS);
68 }
69
71 std::shared_ptr<MockV2PModel> mock_motion_model_ptr;
72 std::shared_ptr<MockDataAssociationModel> mock_data_association_ptr;
73 std::shared_ptr<MockLandmarkFilter> mock_landmark_filter_ptr;
74 std::shared_ptr<MockLoopClosure> mock_loop_closure_ptr;
75 std::shared_ptr<V2PMotionModel> motion_model_ptr;
76 std::shared_ptr<LandmarkFilter> landmark_filter_ptr;
77 std::shared_ptr<DataAssociationModel> data_association_ptr;
78 std::shared_ptr<LoopClosure> loop_closure_ptr;
79 std::shared_ptr<GraphSLAMSolver> solver;
80};
81
85TEST_F(GraphSlamSolverTest, MotionAndObservation) {
86 // Arrange
87 Eigen::VectorXi associations_first = Eigen::VectorXi::Ones(4) * -1;
88 Eigen::VectorXi associations_second = Eigen::VectorXi::Ones(4) * -1;
89 EXPECT_CALL(*mock_motion_model_ptr, get_pose_difference)
90 .Times(4)
91 .WillRepeatedly(testing::Return(Eigen::Vector3d(1.1, 0.0, 0.0)));
92 EXPECT_CALL(*mock_motion_model_ptr, get_jacobian_motion_data)
93 .Times(4)
94 .WillRepeatedly(testing::Return(Eigen::Matrix3d::Identity() * 0.1));
95
96 EXPECT_CALL(*mock_data_association_ptr, associate)
97 .Times(2)
98 .WillOnce(testing::Return(associations_first))
99 .WillOnce(testing::Return(associations_second));
100
101 Eigen::VectorXd eigen_cones_start(8);
102 eigen_cones_start << 3.0, 1.0, 3.0, -1.0, 6.0, 1.0, 6.0, -1.0;
103 Eigen::VectorXd eigen_cones_end(8);
104 eigen_cones_end << -1.0, 1.0, -1.0, -1.0, 2.0, 1.0, 2.0, -1.0;
105
106 EXPECT_CALL(*mock_landmark_filter_ptr, filter)
107 .Times(2)
108 .WillOnce(testing::Return(eigen_cones_start))
109 .WillOnce(testing::Return(eigen_cones_end));
110 EXPECT_CALL(*mock_landmark_filter_ptr, delete_landmarks).Times(2);
111
112 EXPECT_CALL(*mock_loop_closure_ptr, detect)
113 .Times(2)
114 .WillRepeatedly(testing::Return(LoopClosure::Result{false, 0.0}));
115
117 velocities.timestamp_ = solver->_last_pose_update_ + rclcpp::Duration(1, 0);
118 velocities.velocity_x = 1.1;
119 velocities.velocity_y = 0.0;
120 velocities.rotational_velocity = 0.0;
121
122 std::vector<common_lib::structures::Cone> cones_start, cones_end;
123 cones_start.push_back(common_lib::structures::Cone(3.0, 1.0, "blue", 1.0, rclcpp::Clock().now()));
124 cones_start.push_back(
125 common_lib::structures::Cone(3.0, -1.0, "yellow", 1.0, rclcpp::Clock().now()));
126 cones_start.push_back(common_lib::structures::Cone(6.0, 1.0, "blue", 1.0, rclcpp::Clock().now()));
127 cones_start.push_back(
128 common_lib::structures::Cone(6.0, -1.0, "yellow", 1.0, rclcpp::Clock().now()));
129
130 cones_end.push_back(common_lib::structures::Cone(-1.0, 1.0, "blue", 1.0, rclcpp::Clock().now()));
131 cones_end.push_back(
132 common_lib::structures::Cone(-1.0, -1.0, "yellow", 1.0, rclcpp::Clock().now()));
133 cones_end.push_back(common_lib::structures::Cone(2.0, 1.0, "blue", 1.0, rclcpp::Clock().now()));
134 cones_end.push_back(
135 common_lib::structures::Cone(2.0, -1.0, "yellow", 1.0, rclcpp::Clock().now()));
136
137 // Act
138 solver->add_observations(cones_start, rclcpp::Clock().now());
139 solver->add_velocities(velocities);
140 velocities.timestamp_ += rclcpp::Duration(1, 0);
141 solver->add_velocities(velocities);
142 velocities.timestamp_ += rclcpp::Duration(1, 0);
143 solver->add_velocities(velocities);
144 velocities.timestamp_ += rclcpp::Duration(1, 0);
145 solver->add_velocities(velocities);
146 velocities.timestamp_ += rclcpp::Duration(1, 0);
147 solver->add_velocities(velocities);
148 const common_lib::structures::Pose pose_before_observations = solver->get_pose_estimate();
149 const std::vector<common_lib::structures::Cone> map_before_observations =
150 solver->get_map_estimate();
151
152 solver->add_observations(cones_end, rclcpp::Clock().now());
153 const common_lib::structures::Pose pose_after_observations = solver->get_pose_estimate();
154 const std::vector<common_lib::structures::Cone> map_after_observations =
155 solver->get_map_estimate();
156
157 // Assert
158 EXPECT_NEAR(pose_before_observations.position.x, 4.4, 0.5);
159 EXPECT_NEAR(pose_after_observations.position.x, 4.4, 0.2);
160 EXPECT_EQ(map_before_observations.size(), 4);
161 EXPECT_EQ(map_after_observations.size(), 8);
162 EXPECT_NEAR(map_before_observations[0].position.x, 3.0, 0.2);
163 EXPECT_NEAR(map_before_observations[1].position.x, 3.0, 0.2);
164 EXPECT_NEAR(map_before_observations[2].position.x, 6.0, 0.2);
165 EXPECT_NEAR(map_before_observations[3].position.x, 6.0, 0.2);
166 EXPECT_NEAR(map_after_observations[0].position.x, 3.0, 0.2);
167 EXPECT_NEAR(map_after_observations[1].position.x, 3.0, 0.2);
168 EXPECT_NEAR(map_after_observations[2].position.x, 6.0, 0.2);
169 EXPECT_NEAR(map_after_observations[3].position.x, 6.0, 0.2);
170 EXPECT_NEAR(map_before_observations[0].position.y, 1.0, 0.2);
171 EXPECT_NEAR(map_before_observations[1].position.y, -1.0, 0.2);
172 EXPECT_NEAR(map_before_observations[2].position.y, 1.0, 0.2);
173 EXPECT_NEAR(map_before_observations[3].position.y, -1.0, 0.2);
174 EXPECT_NEAR(map_after_observations[0].position.y, 1.0, 0.2);
175 EXPECT_NEAR(map_after_observations[1].position.y, -1.0, 0.2);
176 EXPECT_NEAR(map_after_observations[2].position.y, 1.0, 0.2);
177 EXPECT_NEAR(map_after_observations[3].position.y, -1.0, 0.2);
178}
Data Association Method class, used to match observations to landmarks in the map.
virtual Eigen::VectorXi associate(const Eigen::VectorXd &landmarks, const Eigen::VectorXd &observations, const Eigen::MatrixXd &covariance, const Eigen::VectorXd &observation_confidences) const =0
This function associates the landmarks with the observations.
Whitebox integration test for the GraphSLAMSolver.
std::shared_ptr< MockLoopClosure > mock_loop_closure_ptr
std::shared_ptr< GraphSLAMSolver > solver
std::shared_ptr< MockDataAssociationModel > mock_data_association_ptr
std::shared_ptr< LoopClosure > loop_closure_ptr
std::shared_ptr< DataAssociationModel > data_association_ptr
std::shared_ptr< LandmarkFilter > landmark_filter_ptr
std::shared_ptr< V2PMotionModel > motion_model_ptr
std::shared_ptr< MockV2PModel > mock_motion_model_ptr
std::shared_ptr< MockLandmarkFilter > mock_landmark_filter_ptr
This class is meant to filter observations from perception to try to reduce the presence of outliers.
virtual void delete_landmarks(const Eigen::VectorXd &some_landmarks)=0
Used by SLAM to signal to the filter that the landmarks are already in SLAM's map,...
virtual Eigen::VectorXd filter(const Eigen::VectorXd &observations, const Eigen::VectorXd &observation_confidences, Eigen::VectorXi &associations)=0
This function receives a new set of observations and returns a filtered set of landmarks in global co...
Interface for detecting loop closures.
virtual Result detect(const Eigen::Vector3d &current_pose, const Eigen::VectorXd &map_cones, const Eigen::VectorXi &associations, const Eigen::VectorXd &observations) const =0
Call every time you have new observations.
MOCK_METHOD(Eigen::VectorXi, associate,(const Eigen::VectorXd &state, const Eigen::VectorXd &observations, const Eigen::MatrixXd &covariance, const Eigen::VectorXd &observation_confidences),(const, override))
MOCK_METHOD(void, delete_landmarks,(const Eigen::VectorXd &some_landmarks),(override))
MOCK_METHOD(Eigen::VectorXd, filter,(const Eigen::VectorXd &observations, const Eigen::VectorXd &observation_confidences, Eigen::VectorXi &associations),(override))
MOCK_METHOD(LoopClosure::Result, detect,(const Eigen::Vector3d &current_pose, const Eigen::VectorXd &map_cones, const Eigen::VectorXi &associations, const Eigen::VectorXd &observations),(const, override))
MOCK_METHOD(Eigen::Vector3d, get_pose_difference,(const Eigen::Vector3d &previous_pose, const Eigen::VectorXd &motion_data, double delta_t),(override))
MOCK_METHOD(Eigen::Matrix3d, get_jacobian_pose,(const Eigen::Vector3d &previous_pose, const Eigen::VectorXd &motion_data, const double delta_t),(override))
MOCK_METHOD(Eigen::MatrixXd, get_jacobian_motion_data,(const Eigen::Vector3d &previous_pose, const Eigen::VectorXd &motion_data, const double delta_t),(override))
Base class for the 'vehicle to pose' (more in interal background review) motion models.
virtual Eigen::Matrix3d get_jacobian_pose(const Eigen::Vector3d &previous_pose, const Eigen::VectorXd &motion_data, const double delta_t)=0
Get the Jacobian matrix of the motion model in relation to the pose (state)
virtual Eigen::Vector3d get_pose_difference(const Eigen::Vector3d &previous_pose, const Eigen::VectorXd &motion_data, const double delta_t)=0
Gives the increments to the pose instead of the next pose.
virtual Eigen::MatrixXd get_jacobian_motion_data(const Eigen::Vector3d &previous_pose, const Eigen::VectorXd &motion_data, const double delta_t)=0
Get the Jacobian matrix of the motion model in relation to motion data (commands)
TEST_F(GraphSlamSolverTest, MotionAndObservation)
Test the GraphSLAMSolver in one iteration of inputs.
Result of loop closure detection.
Parameters for the SLAM node.
double slam_optimization_period_
Struct for pose representation.
Definition pose.hpp:13