31 #include "glog/logging.h" 32 #include "gmock/gmock.h" 35 namespace mapping_3d {
38 class KalmanLocalTrajectoryBuilderTest :
public ::testing::Test {
40 struct TrajectoryNode {
45 void SetUp()
override { GenerateBubbles(); }
52 scans_per_accumulation = 1, 53 voxel_filter_size = 0.05, 55 high_resolution_adaptive_voxel_filter = { 61 low_resolution_adaptive_voxel_filter = { 67 ceres_scan_matcher = { 68 occupied_space_weight_0 = 5., 69 occupied_space_weight_1 = 20., 70 translation_weight = 0.1, 71 rotation_weight = 0.3, 72 only_optimize_yaw = false, 73 ceres_solver_options = { 74 use_nonmonotonic_steps = true, 75 max_num_iterations = 20, 80 max_time_seconds = 0.2, 81 max_distance_meters = 0.02, 82 max_angle_radians = 0.001, 85 high_resolution = 0.2, 86 high_resolution_max_range = 50., 88 num_range_data = 45000, 89 range_data_inserter = { 90 hit_probability = 0.7, 91 miss_probability = 0.4, 92 num_free_space_voxels = 0, 97 kalman_local_trajectory_builder = { 98 use_online_correlative_scan_matching = false, 99 real_time_correlative_scan_matcher = { 100 linear_search_window = 0.2, 101 angular_search_window = math.rad(1.), 102 translation_delta_cost_weight = 1e-1, 103 rotation_delta_cost_weight = 1., 106 orientation_model_variance = 5e-4, 107 position_model_variance = 0.000654766, 108 velocity_model_variance = 0.053926, 109 imu_gravity_time_constant = 1., 110 imu_gravity_variance = 1e-4, 111 num_odometry_states = 1, 114 scan_matcher_variance = 1e-6, 115 odometer_translational_variance = 1e-7, 116 odometer_rotational_variance = 1e-7, 118 optimizing_local_trajectory_builder = { 119 high_resolution_grid_weight = 5., 120 low_resolution_grid_weight = 15., 121 velocity_weight = 4e1, 122 translation_weight = 1e2, 123 rotation_weight = 1e3, 124 odometry_translation_weight = 1e4, 125 odometry_rotation_weight = 1e4, 132 void GenerateBubbles() {
133 std::mt19937 prng(42);
134 std::uniform_real_distribution<float> distribution(-1.f, 1.f);
136 for (
int i = 0; i != 100; ++i) {
137 const float x = distribution(prng);
138 const float y = distribution(prng);
139 const float z = distribution(prng);
140 bubbles_.push_back(10. * Eigen::Vector3f(x, y, z).normalized());
147 Eigen::Vector3f CollideWithBox(
const Eigen::Vector3f&
from,
148 const Eigen::Vector3f&
to) {
150 if (to.x() > from.x()) {
151 first = std::min(first, (15.f - from.x()) / (to.x() - from.x()));
152 }
else if (to.x() < from.x()) {
153 first = std::min(first, (-15.f - from.x()) / (to.x() - from.x()));
155 if (to.y() > from.y()) {
156 first = std::min(first, (15.f - from.y()) / (to.y() - from.y()));
157 }
else if (to.y() < from.y()) {
158 first = std::min(first, (-15.f - from.y()) / (to.y() - from.y()));
160 if (to.z() > from.z()) {
161 first = std::min(first, (15.f - from.z()) / (to.z() - from.z()));
162 }
else if (to.z() < from.z()) {
163 first = std::min(first, (-15.f - from.z()) / (to.z() - from.z()));
165 return first * (to -
from) + from;
170 Eigen::Vector3f CollideWithBubbles(
const Eigen::Vector3f& from,
171 const Eigen::Vector3f& to) {
173 constexpr
float kBubbleRadius = 0.5f;
174 for (
const Eigen::Vector3f& center :
bubbles_) {
175 const float a = (to -
from).squaredNorm();
176 const float beta = (to -
from).dot(from - center);
178 (from - center).squaredNorm() - kBubbleRadius * kBubbleRadius;
179 const float discriminant = beta * beta - a * c;
180 if (discriminant < 0.f) {
183 const float solution = (-beta - std::sqrt(discriminant)) / a;
184 if (solution < 0.f) {
187 first = std::min(first, solution);
189 return first * (to -
from) + from;
195 for (
int r = -8; r != 8; ++r) {
196 for (
int s = -250; s != 250; ++s) {
197 directions_in_rangefinder_frame.push_back(
198 Eigen::AngleAxisf(M_PI * s / 250., Eigen::Vector3f::UnitZ()) *
199 Eigen::AngleAxisf(M_PI / 12. * r / 8., Eigen::Vector3f::UnitY()) *
200 Eigen::Vector3f::UnitX());
202 directions_in_rangefinder_frame.push_back(
203 Eigen::AngleAxisf(M_PI / 2., Eigen::Vector3f::UnitX()) *
204 Eigen::AngleAxisf(M_PI * s / 250., Eigen::Vector3f::UnitZ()) *
205 Eigen::AngleAxisf(M_PI / 12. * r / 8., Eigen::Vector3f::UnitY()) *
206 Eigen::Vector3f::UnitX());
212 for (
const Eigen::Vector3f& direction_in_world_frame :
214 pose.cast<
float>())) {
215 const Eigen::Vector3f origin =
216 pose.cast<
float>() * Eigen::Vector3f::Zero();
217 returns_in_world_frame.push_back(CollideWithBubbles(
218 origin, CollideWithBox(origin, direction_in_world_frame)));
220 return {Eigen::Vector3f::Zero(),
222 pose.inverse().cast<
float>()),
228 const Eigen::Vector3d gravity =
229 expected_pose.rotation().inverse() * Eigen::Vector3d(0., 0., 9.81);
231 Eigen::Vector3d::Zero());
234 std::vector<TrajectoryNode> GenerateCorkscrewTrajectory() {
235 std::vector<TrajectoryNode> trajectory;
238 for (
int i = 0; i != 5; ++i) {
240 trajectory.push_back(
244 for (
double t = 0.; t <= 0.6; t += 0.006) {
246 trajectory.push_back(TrajectoryNode{
249 std::sin(4. * t), 1. - std::cos(4. * t), 1. * t)) *
251 0.3 * t, Eigen::Vector3d(1., -1., 2.).normalized()))});
256 void VerifyAccuracy(
const std::vector<TrajectoryNode>& expected_trajectory,
257 double expected_accuracy) {
259 for (
const TrajectoryNode& node : expected_trajectory) {
260 AddLinearOnlyImuObservation(node.time, node.pose);
261 const auto range_data = GenerateRangeData(node.pose);
263 node.time, range_data.origin, range_data.returns) !=
nullptr) {
265 EXPECT_THAT(pose_estimate.pose, transform::IsNearly(node.pose, 1e-1));
267 LOG(INFO) <<
"num_poses: " << num_poses;
276 TEST_F(KalmanLocalTrajectoryBuilderTest,
277 MoveInsideCubeUsingOnlyCeresScanMatcher) {
280 VerifyAccuracy(GenerateCorkscrewTrajectory(), 1e-1);
PointCloud TransformPointCloud(const PointCloud &point_cloud, const transform::Rigid3f &transform)
std::vector< Eigen::Vector3f > bubbles_
UniversalTimeScaleClock::time_point Time
std::unique_ptr< LuaParameterDictionary > MakeDictionary(const string &code)
Time FromUniversal(const int64 ticks)
Duration FromSeconds(const double seconds)
proto::TrajectoryBuilderOptions CreateTrajectoryBuilderOptions(common::LuaParameterDictionary *const parameter_dictionary)
proto::LocalTrajectoryBuilderOptions CreateLocalTrajectoryBuilderOptions(common::LuaParameterDictionary *const parameter_dictionary)
std::vector< Eigen::Vector3f > PointCloud
std::unique_ptr< KalmanLocalTrajectoryBuilder > local_trajectory_builder_