client_server_test.cc
Go to the documentation of this file.
1 /*
2  * Copyright 2017 The Cartographer Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <condition_variable>
18 #include <mutex>
19 
28 #include "glog/logging.h"
29 #include "gmock/gmock.h"
30 #include "gtest/gtest.h"
31 
32 using ::cartographer::mapping::MapBuilder;
33 using ::cartographer::mapping::MapBuilderInterface;
34 using ::cartographer::mapping::PoseGraphInterface;
35 using ::cartographer::mapping::TrajectoryBuilderInterface;
36 using ::cartographer::mapping::testing::MockMapBuilder;
37 using ::cartographer::mapping::testing::MockPoseGraph;
38 using ::cartographer::mapping::testing::MockTrajectoryBuilder;
39 using ::testing::_;
41 
42 namespace cartographer {
43 namespace cloud {
44 namespace {
45 
46 const SensorId kImuSensorId{SensorId::SensorType::IMU, "imu"};
47 const SensorId kRangeSensorId{SensorId::SensorType::RANGE, "range"};
48 constexpr double kDuration = 4.; // Seconds.
49 constexpr double kTimeStep = 0.1; // Seconds.
50 constexpr double kTravelDistance = 1.2; // Meters.
51 
52 class ClientServerTest : public ::testing::Test {
53  protected:
54  void SetUp() override {
55  // TODO(cschuet): Due to the hard-coded addresses these tests will become
56  // flaky when run in parallel.
57  const std::string kMapBuilderServerLua = R"text(
58  include "map_builder_server.lua"
59  MAP_BUILDER.use_trajectory_builder_2d = true
60  MAP_BUILDER.pose_graph.optimize_every_n_nodes = 0
61  MAP_BUILDER_SERVER.num_event_threads = 1
62  MAP_BUILDER_SERVER.num_grpc_threads = 1
63  MAP_BUILDER_SERVER.uplink_server_address = ""
64  MAP_BUILDER_SERVER.server_address = "0.0.0.0:50051"
65  return MAP_BUILDER_SERVER)text";
66  auto map_builder_server_parameters =
67  mapping::test::ResolveLuaParameters(kMapBuilderServerLua);
69  CreateMapBuilderServerOptions(map_builder_server_parameters.get());
70 
71  const std::string kUploadingMapBuilderServerLua = R"text(
72  include "map_builder_server.lua"
73  MAP_BUILDER.use_trajectory_builder_2d = true
74  MAP_BUILDER.pose_graph.optimize_every_n_nodes = 0
75  MAP_BUILDER_SERVER.num_event_threads = 1
76  MAP_BUILDER_SERVER.num_grpc_threads = 1
77  MAP_BUILDER_SERVER.uplink_server_address = "localhost:50051"
78  MAP_BUILDER_SERVER.server_address = "0.0.0.0:50052"
79  MAP_BUILDER_SERVER.upload_batch_size = 1
80  return MAP_BUILDER_SERVER)text";
81  auto uploading_map_builder_server_parameters =
82  mapping::test::ResolveLuaParameters(kUploadingMapBuilderServerLua);
84  uploading_map_builder_server_parameters.get());
85 
86  const std::string kTrajectoryBuilderLua = R"text(
87  include "trajectory_builder.lua"
88  TRAJECTORY_BUILDER.trajectory_builder_2d.use_imu_data = false
89  TRAJECTORY_BUILDER.trajectory_builder_2d.submaps.num_range_data = 4
90  return TRAJECTORY_BUILDER)text";
91  auto trajectory_builder_parameters =
92  mapping::test::ResolveLuaParameters(kTrajectoryBuilderLua);
94  trajectory_builder_parameters.get());
97  [this](int, common::Time, transform::Rigid3d local_pose,
98  sensor::RangeData,
99  std::unique_ptr<
100  const mapping::TrajectoryBuilderInterface::InsertionResult>
101  insertion_result) {
102  std::unique_lock<std::mutex> lock(local_slam_result_mutex_);
103  if (insertion_result) {
105  }
106  local_slam_result_poses_.push_back(local_pose);
107  lock.unlock();
108  local_slam_result_condition_.notify_all();
109  };
110  }
111 
112  void InitializeRealServer() {
113  auto map_builder = common::make_unique<MapBuilder>(
114  map_builder_server_options_.map_builder_options());
115  server_ = common::make_unique<MapBuilderServer>(map_builder_server_options_,
116  std::move(map_builder));
117  EXPECT_TRUE(server_ != nullptr);
118  }
119 
120  void InitializeRealUploadingServer() {
121  auto map_builder = common::make_unique<MapBuilder>(
122  uploading_map_builder_server_options_.map_builder_options());
123  uploading_server_ = common::make_unique<MapBuilderServer>(
124  uploading_map_builder_server_options_, std::move(map_builder));
125  EXPECT_TRUE(uploading_server_ != nullptr);
126  }
127 
128  void InitializeServerWithMockMapBuilder() {
129  auto mock_map_builder = common::make_unique<MockMapBuilder>();
130  mock_map_builder_ = mock_map_builder.get();
131  mock_pose_graph_ = common::make_unique<MockPoseGraph>();
132  EXPECT_CALL(*mock_map_builder_, pose_graph())
133  .WillOnce(::testing::Return(mock_pose_graph_.get()));
134  EXPECT_CALL(*mock_pose_graph_, SetGlobalSlamOptimizationCallback(_));
135  server_ = common::make_unique<MapBuilderServer>(
136  map_builder_server_options_, std::move(mock_map_builder));
137  EXPECT_TRUE(server_ != nullptr);
138  mock_trajectory_builder_ = common::make_unique<MockTrajectoryBuilder>();
139  }
140 
141  void InitializeStub() {
142  stub_ = common::make_unique<MapBuilderStub>(
143  map_builder_server_options_.server_address());
144  EXPECT_TRUE(stub_ != nullptr);
145  }
146 
147  void InitializeStubForUploadingServer() {
148  stub_for_uploading_server_ = common::make_unique<MapBuilderStub>(
149  uploading_map_builder_server_options_.server_address());
150  EXPECT_TRUE(stub_for_uploading_server_ != nullptr);
151  }
152 
153  void WaitForLocalSlamResults(size_t size) {
154  std::unique_lock<std::mutex> lock(local_slam_result_mutex_);
156  lock, [&] { return local_slam_result_poses_.size() >= size; });
157  }
158 
159  void WaitForLocalSlamResultUploads(size_t size) {
160  std::unique_lock<std::mutex> lock(local_slam_result_upload_mutex_);
161  local_slam_result_upload_condition_.wait(lock, [&] {
162  return stub_->pose_graph()->GetTrajectoryNodePoses().size() >= size;
163  });
164  }
165 
166  proto::MapBuilderServerOptions map_builder_server_options_;
167  proto::MapBuilderServerOptions uploading_map_builder_server_options_;
168  MockMapBuilder* mock_map_builder_;
169  std::unique_ptr<MockPoseGraph> mock_pose_graph_;
170  std::unique_ptr<MockTrajectoryBuilder> mock_trajectory_builder_;
171  ::cartographer::mapping::proto::TrajectoryBuilderOptions
173  std::unique_ptr<MapBuilderServer> server_;
174  std::unique_ptr<MapBuilderServer> uploading_server_;
175  std::unique_ptr<MapBuilderStub> stub_;
176  std::unique_ptr<MapBuilderStub> stub_for_uploading_server_;
177  TrajectoryBuilderInterface::LocalSlamResultCallback
179  std::condition_variable local_slam_result_condition_;
180  std::condition_variable local_slam_result_upload_condition_;
183  std::vector<transform::Rigid3d> local_slam_result_poses_;
185 };
186 
187 TEST_F(ClientServerTest, StartAndStopServer) {
188  InitializeRealServer();
189  server_->Start();
190  server_->Shutdown();
191 }
192 
193 TEST_F(ClientServerTest, AddTrajectoryBuilder) {
194  InitializeRealServer();
195  server_->Start();
196  InitializeStub();
197  int trajectory_id = stub_->AddTrajectoryBuilder(
198  {kImuSensorId}, trajectory_builder_options_, nullptr);
199  EXPECT_FALSE(stub_->pose_graph()->IsTrajectoryFinished(trajectory_id));
200  stub_->FinishTrajectory(trajectory_id);
201  EXPECT_TRUE(stub_->pose_graph()->IsTrajectoryFinished(trajectory_id));
202  EXPECT_FALSE(stub_->pose_graph()->IsTrajectoryFrozen(trajectory_id));
203  server_->Shutdown();
204 }
205 
206 TEST_F(ClientServerTest, AddTrajectoryBuilderWithMock) {
207  InitializeServerWithMockMapBuilder();
208  server_->Start();
209  InitializeStub();
210  std::set<SensorId> expected_sensor_ids = {kImuSensorId};
211  EXPECT_CALL(
213  AddTrajectoryBuilder(::testing::ContainerEq(expected_sensor_ids), _, _))
214  .WillOnce(::testing::Return(3));
215  EXPECT_CALL(*mock_map_builder_, GetTrajectoryBuilder(_))
216  .WillRepeatedly(::testing::Return(nullptr));
217  int trajectory_id = stub_->AddTrajectoryBuilder(
218  expected_sensor_ids, trajectory_builder_options_, nullptr);
219  EXPECT_EQ(trajectory_id, 3);
220  EXPECT_CALL(*mock_map_builder_, FinishTrajectory(trajectory_id));
221  stub_->FinishTrajectory(trajectory_id);
222  server_->Shutdown();
223 }
224 
225 TEST_F(ClientServerTest, AddSensorData) {
226  trajectory_builder_options_.mutable_trajectory_builder_2d_options()
227  ->set_use_imu_data(true);
228  InitializeRealServer();
229  server_->Start();
230  InitializeStub();
231  int trajectory_id = stub_->AddTrajectoryBuilder(
232  {kImuSensorId}, trajectory_builder_options_, nullptr);
233  TrajectoryBuilderInterface* trajectory_stub =
234  stub_->GetTrajectoryBuilder(trajectory_id);
235  sensor::ImuData imu_data{common::FromUniversal(42),
236  Eigen::Vector3d(0., 0., 9.8),
237  Eigen::Vector3d::Zero()};
238  trajectory_stub->AddSensorData(kImuSensorId.id, imu_data);
239  stub_->FinishTrajectory(trajectory_id);
240  server_->Shutdown();
241 }
242 
243 TEST_F(ClientServerTest, AddSensorDataWithMock) {
244  InitializeServerWithMockMapBuilder();
245  server_->Start();
246  InitializeStub();
247  std::set<SensorId> expected_sensor_ids = {kImuSensorId};
248  EXPECT_CALL(
250  AddTrajectoryBuilder(::testing::ContainerEq(expected_sensor_ids), _, _))
251  .WillOnce(::testing::Return(3));
252  int trajectory_id = stub_->AddTrajectoryBuilder(
253  expected_sensor_ids, trajectory_builder_options_, nullptr);
254  EXPECT_EQ(trajectory_id, 3);
255  EXPECT_CALL(*mock_map_builder_, GetTrajectoryBuilder(_))
256  .WillRepeatedly(::testing::Return(mock_trajectory_builder_.get()));
257  mapping::TrajectoryBuilderInterface* trajectory_stub =
258  stub_->GetTrajectoryBuilder(trajectory_id);
259  sensor::ImuData imu_data{common::FromUniversal(42),
260  Eigen::Vector3d(0., 0., 9.8),
261  Eigen::Vector3d::Zero()};
262  EXPECT_CALL(*mock_trajectory_builder_,
263  AddSensorData(::testing::StrEq(kImuSensorId.id),
264  ::testing::Matcher<const sensor::ImuData&>(_)))
265  .WillOnce(::testing::Return());
266  trajectory_stub->AddSensorData(kImuSensorId.id, imu_data);
267  EXPECT_CALL(*mock_map_builder_, FinishTrajectory(trajectory_id));
268  stub_->FinishTrajectory(trajectory_id);
269  server_->Shutdown();
270 }
271 
272 TEST_F(ClientServerTest, LocalSlam2D) {
273  InitializeRealServer();
274  server_->Start();
275  InitializeStub();
276  int trajectory_id =
277  stub_->AddTrajectoryBuilder({kRangeSensorId}, trajectory_builder_options_,
279  TrajectoryBuilderInterface* trajectory_stub =
280  stub_->GetTrajectoryBuilder(trajectory_id);
281  const auto measurements = mapping::test::GenerateFakeRangeMeasurements(
282  kTravelDistance, kDuration, kTimeStep);
283  for (const auto& measurement : measurements) {
284  trajectory_stub->AddSensorData(kRangeSensorId.id, measurement);
285  }
286  WaitForLocalSlamResults(measurements.size());
287  stub_->FinishTrajectory(trajectory_id);
288  EXPECT_EQ(local_slam_result_poses_.size(), measurements.size());
289  EXPECT_NEAR(kTravelDistance,
290  (local_slam_result_poses_.back().translation() -
291  local_slam_result_poses_.front().translation())
292  .norm(),
293  0.1 * kTravelDistance);
294  server_->Shutdown();
295 }
296 
297 TEST_F(ClientServerTest, GlobalSlam3D) {
298  map_builder_server_options_.mutable_map_builder_options()
299  ->set_use_trajectory_builder_2d(false);
300  map_builder_server_options_.mutable_map_builder_options()
301  ->set_use_trajectory_builder_3d(true);
302  map_builder_server_options_.mutable_map_builder_options()
303  ->mutable_pose_graph_options()
304  ->set_optimize_every_n_nodes(3);
305  trajectory_builder_options_.mutable_trajectory_builder_3d_options()
306  ->mutable_motion_filter_options()
307  ->set_max_distance_meters(0);
308  trajectory_builder_options_.mutable_trajectory_builder_3d_options()
309  ->mutable_motion_filter_options()
310  ->set_max_angle_radians(0);
311  InitializeRealServer();
312  server_->Start();
313  InitializeStub();
314  int trajectory_id = stub_->AddTrajectoryBuilder(
315  {kRangeSensorId, kImuSensorId}, trajectory_builder_options_,
317  TrajectoryBuilderInterface* trajectory_stub =
318  stub_->GetTrajectoryBuilder(trajectory_id);
319  const auto measurements = mapping::test::GenerateFakeRangeMeasurements(
320  kTravelDistance, kDuration, kTimeStep);
321  for (const auto& measurement : measurements) {
322  sensor::ImuData imu_data{
323  measurement.time - common::FromSeconds(kTimeStep / 2),
324  Eigen::Vector3d(0., 0., 9.8), Eigen::Vector3d::Zero()};
325  trajectory_stub->AddSensorData(kImuSensorId.id, imu_data);
326  trajectory_stub->AddSensorData(kRangeSensorId.id, measurement);
327  }
328  // First range data will not call back while initializing PoseExtrapolator, so
329  // expect one less.
330  WaitForLocalSlamResults(measurements.size() - 1);
331  stub_->FinishTrajectory(trajectory_id);
332  EXPECT_NEAR(kTravelDistance,
333  (local_slam_result_poses_.back().translation() -
334  local_slam_result_poses_.front().translation())
335  .norm(),
336  0.1 * kTravelDistance);
337  server_->Shutdown();
338 }
339 
340 TEST_F(ClientServerTest, StartAndStopUploadingServerAndServer) {
341  InitializeRealServer();
342  server_->Start();
343  InitializeRealUploadingServer();
344  uploading_server_->Start();
345  uploading_server_->Shutdown();
346  server_->Shutdown();
347 }
348 
349 TEST_F(ClientServerTest, AddTrajectoryBuilderWithUploadingServer) {
350  InitializeRealServer();
351  server_->Start();
352  InitializeRealUploadingServer();
353  uploading_server_->Start();
354  InitializeStub();
355  InitializeStubForUploadingServer();
356  int trajectory_id = stub_for_uploading_server_->AddTrajectoryBuilder(
357  {kImuSensorId}, trajectory_builder_options_, nullptr);
358  EXPECT_FALSE(stub_for_uploading_server_->pose_graph()->IsTrajectoryFinished(
359  trajectory_id));
360  EXPECT_FALSE(stub_->pose_graph()->IsTrajectoryFinished(trajectory_id));
361  stub_for_uploading_server_->FinishTrajectory(trajectory_id);
362  EXPECT_TRUE(stub_for_uploading_server_->pose_graph()->IsTrajectoryFinished(
363  trajectory_id));
364  EXPECT_TRUE(stub_->pose_graph()->IsTrajectoryFinished(trajectory_id));
365  EXPECT_FALSE(stub_for_uploading_server_->pose_graph()->IsTrajectoryFrozen(
366  trajectory_id));
367  EXPECT_FALSE(stub_->pose_graph()->IsTrajectoryFrozen(trajectory_id));
368  uploading_server_->Shutdown();
369  server_->Shutdown();
370 }
371 
372 TEST_F(ClientServerTest, LocalSlam2DWithUploadingServer) {
373  InitializeRealServer();
374  server_->Start();
375  InitializeStub();
376  InitializeRealUploadingServer();
377  uploading_server_->Start();
378  InitializeStubForUploadingServer();
379  int trajectory_id = stub_for_uploading_server_->AddTrajectoryBuilder(
380  {kRangeSensorId}, trajectory_builder_options_,
382  TrajectoryBuilderInterface* trajectory_stub =
383  stub_for_uploading_server_->GetTrajectoryBuilder(trajectory_id);
384  const auto measurements = mapping::test::GenerateFakeRangeMeasurements(
385  kTravelDistance, kDuration, kTimeStep);
386  for (const auto& measurement : measurements) {
387  trajectory_stub->AddSensorData(kRangeSensorId.id, measurement);
388  }
389  WaitForLocalSlamResults(measurements.size());
390  WaitForLocalSlamResultUploads(number_of_insertion_results_);
391  stub_for_uploading_server_->FinishTrajectory(trajectory_id);
392  EXPECT_EQ(local_slam_result_poses_.size(), measurements.size());
393  EXPECT_NEAR(kTravelDistance,
394  (local_slam_result_poses_.back().translation() -
395  local_slam_result_poses_.front().translation())
396  .norm(),
397  0.1 * kTravelDistance);
398  uploading_server_->Shutdown();
399  server_->Shutdown();
400 }
401 
402 } // namespace
403 } // namespace cloud
404 } // namespace cartographer
std::condition_variable local_slam_result_upload_condition_
Rigid3< double > Rigid3d
std::vector< cartographer::sensor::TimedPointCloudData > GenerateFakeRangeMeasurements(double travel_distance, double duration, double time_step)
int number_of_insertion_results_
std::vector< transform::Rigid3d > local_slam_result_poses_
std::mutex local_slam_result_upload_mutex_
::cartographer::mapping::proto::TrajectoryBuilderOptions trajectory_builder_options_
UniversalTimeScaleClock::time_point Time
Definition: time.h:44
std::mutex local_slam_result_mutex_
Time FromUniversal(const int64 ticks)
Definition: time.cc:34
std::unique_ptr< MockPoseGraph > mock_pose_graph_
Duration FromSeconds(const double seconds)
Definition: time.cc:24
proto::MapBuilderServerOptions uploading_map_builder_server_options_
std::unique_ptr< MockTrajectoryBuilder > mock_trajectory_builder_
TrajectoryBuilderInterface::LocalSlamResultCallback local_slam_result_callback_
proto::TrajectoryBuilderOptions CreateTrajectoryBuilderOptions(common::LuaParameterDictionary *const parameter_dictionary)
std::unique_ptr< MapBuilderServer > server_
std::unique_ptr< MapBuilderServer > uploading_server_
std::condition_variable local_slam_result_condition_
proto::MapBuilderServerOptions CreateMapBuilderServerOptions(common::LuaParameterDictionary *lua_parameter_dictionary)
MockMapBuilder * mock_map_builder_
std::unique_ptr<::cartographer::common::LuaParameterDictionary > ResolveLuaParameters(const std::string &lua_code)
::cartographer::mapping::TrajectoryBuilderInterface::SensorId SensorId
std::unique_ptr< MapBuilderStub > stub_for_uploading_server_
proto::MapBuilderServerOptions map_builder_server_options_
std::unique_ptr< MapBuilderStub > stub_


cartographer
Author(s): The Cartographer Authors
autogenerated on Mon Feb 28 2022 22:00:58