CartographerAdapter.cpp
Go to the documentation of this file.
2
3// STL
4#include <algorithm>
5#include <cmath>
6#include <cstdlib>
7#include <ctime>
8#include <filesystem>
9#include <functional>
10#include <iterator>
11#include <memory>
12#include <mutex>
13#include <optional>
14#include <stdexcept>
15#include <string>
16
17// Eigen
18#include <Eigen/Core>
19#include <Eigen/Geometry>
20
21// Ice
22#include <IceUtil/Time.h>
23
24// PCL
25#include <pcl/common/transforms.h>
26#include <pcl/io/pcd_io.h>
27#include <pcl/point_cloud.h>
28#include <pcl/point_types.h>
29
30// OpenCV
31#include <opencv2/core/mat.hpp>
32#include <opencv2/imgcodecs.hpp>
33
34// Simox
35#include <SimoxUtility/algorithm/string/string_tools.h>
36#include <SimoxUtility/json/json.hpp>
37#include <SimoxUtility/math.h>
38
39// ArmarX
44
45// RobotComponents
47
48// cartographer (this has to come last!)
49#include <cartographer/common/configuration_file_resolver.h>
50#include <cartographer/common/time.h>
51#include <cartographer/io/file_writer.h>
52#include <cartographer/io/points_processor_pipeline_builder.h>
53#include <cartographer/io/proto_stream.h>
54#include <cartographer/mapping/2d/grid_2d.h>
55#include <cartographer/mapping/2d/probability_grid.h>
56#include <cartographer/mapping/2d/submap_2d.h>
57#include <cartographer/mapping/internal/2d/tsdf_2d.h>
58#include <cartographer/mapping/map_builder.h>
59#include <cartographer/mapping/map_builder_interface.h>
60#include <cartographer/mapping/pose_graph_interface.h>
61#include <cartographer/mapping/submaps.h>
62#include <cartographer/mapping/trajectory_builder_interface.h>
63#include <cartographer/mapping/trajectory_node.h>
64#include <cartographer/sensor/point_cloud.h>
65#include <cartographer/sensor/rangefinder_point.h>
66#include <cartographer/transform/rigid_transform.h>
67#include <cartographer/transform/transform.h>
68
69// this library
71#include "ArVizDrawer.h"
72#include "grid_conversion.h"
73#include "types.h"
78
79namespace carto = ::cartographer;
80
81constexpr int SCALE_M_TO_MM = 1000;
82
83namespace fs = ::std::filesystem;
84
85std::string
87{
88 // http://www.cplusplus.com/reference/ctime/strftime/
89
90 time_t rawtime{};
91 struct tm* timeinfo{};
92 std::array<char, 4 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1> buffer;
93
94 time(&rawtime);
95 timeinfo = localtime(&rawtime);
96
97 strftime(buffer.data(), buffer.size(), "%Y-%m-%d-%H-%M", timeinfo);
98
99 std::string timestamp(buffer.data());
100 return timestamp;
101}
102
104{
105
107 {
109
110 ARMARX_INFO << "Finishing cartographer";
111 mapBuilder->FinishTrajectory(trajectoryId);
112
113 ARMARX_INFO << "Releasing cartographer";
114 mapBuilder.reset();
115
116 ARMARX_INFO << "Done";
117 }
118
120 const std::filesystem::path& mapPath,
121 const std::filesystem::path& configPath,
122 SlamDataCallable& slamDataCallable,
123 const Config& config,
124 const std::optional<std::filesystem::path>& mapToLoad,
125 const std::optional<Eigen::Isometry3f>& map_T_robot_prior,
126 const DebugObserverInterfacePrx& debugObserver) :
127 config(config), mapPath(mapPath), slamDataCallable(slamDataCallable)
128 {
130 const std::string mapBuilderLuaCode = R"text(
131 include "map_builder.lua"
132 return MAP_BUILDER)text";
133
134 const std::string trajectoryBuilderLuaCode = R"text(
135 include "trajectory_builder.lua"
136 return TRAJECTORY_BUILDER)text";
137
138 const auto mapBuilderParameters = util::resolveLuaParameters(mapBuilderLuaCode, configPath);
139 auto mapBuilderOptions =
140 carto::mapping::CreateMapBuilderOptions(mapBuilderParameters.get());
141
142
143 if (config.global_localization_min_score > 0)
144 {
145 ARMARX_INFO << "Setting `global_localization_min_score` to "
146 << config.global_localization_min_score;
147 mapBuilderOptions.mutable_pose_graph_options()
148 ->mutable_constraint_builder_options()
149 ->set_global_localization_min_score(config.global_localization_min_score);
150 }
151
152 if (config.min_score > 0)
153 {
154 ARMARX_INFO << "Setting `min_score` to " << config.min_score;
155 mapBuilderOptions.mutable_pose_graph_options()
156 ->mutable_constraint_builder_options()
157 ->set_min_score(config.min_score);
158 }
159
160 const auto trajectoryBuilderParameters =
161 util::resolveLuaParameters(trajectoryBuilderLuaCode, configPath);
162 trajectoryBuilderOptions =
163 carto::mapping::CreateTrajectoryBuilderOptions(trajectoryBuilderParameters.get());
164
165 // create map builder
166 mapBuilder = carto::mapping::CreateMapBuilder(mapBuilderOptions);
167
168 if (config.useLaserScanner)
169 {
170 sensorSet.insert(sensorIdLaser);
171 }
172
173 if (config.useOdometry)
174 {
175 sensorSet.insert(sensorIdOdom);
176 }
177
178 if (config.useImu)
179 {
180 sensorSet.insert(sensorIdIMU);
181 }
182
183 std::vector<std::string> sensorSetNames;
184 std::transform(sensorSet.begin(),
185 sensorSet.end(),
186 std::back_inserter(sensorSetNames),
187 [](const auto& sensorId) { return sensorId.id; });
188
189 ARMARX_IMPORTANT << "Sensor set '" << sensorSetNames << "' will be used";
190
191 if (config.useLaserScanner)
192 {
193 ARMARX_IMPORTANT << "This includes the following laser scanners: "
194 << std::vector<std::string>(config.laserScanners.begin(),
195 config.laserScanners.end());
196
197 std::for_each(config.laserScanners.begin(),
198 config.laserScanners.end(),
199 [&](const auto& laserScannerName)
200 {
201 const SensorId sensorId{.type = SensorId::SensorType::RANGE,
202 .id = laserScannerName};
203 laserSensorMap.insert(
204 {laserScannerName,
205 LaserScannerSensor(sensorId, Eigen::Isometry3f::Identity())});
206 });
207 }
208
209
210 if (mapToLoad)
211 {
213 ARMARX_DEBUG << "Loading map";
214 carto::io::ProtoStreamReader reader(mapToLoad->string());
215 mapBuilder->LoadState(&reader, true /* load_frozen_state */);
216 mapBuilder->pose_graph()->RunFinalOptimization();
217
218
219 if (map_T_robot_prior)
220 {
221 ARMARX_INFO << "Using pose prior \n" << map_T_robot_prior->matrix();
222
223 ::cartographer::mapping::proto::InitialTrajectoryPose* initial_trajectory_pose =
224 new ::cartographer::mapping::proto::InitialTrajectoryPose;
225
226 initial_trajectory_pose->set_allocated_relative_pose(
227 new ::cartographer::transform::proto::Rigid3d(
228 ::cartographer::transform::ToProto(fromEigen(*map_T_robot_prior))));
229
230 trajectoryBuilderOptions.set_allocated_initial_trajectory_pose(
231 std::move(initial_trajectory_pose)); // owner -> trajectoryBuilderOptions
232 }
233 }
234
235
236 trajectoryId = mapBuilder->AddTrajectoryBuilder(
237 sensorSet,
238 trajectoryBuilderOptions,
239 [this](auto&&... args)
240 { return getLocalSlamResultCallback(std::forward<decltype(args)>(args)...); });
241
242 // TODO(fabian.reister): variable sensor set
243 const auto dt = static_cast<int64_t>(1'000'000 / config.frequency);
244 const float dtHistoryLength = 1'000'000;
245
246 ARMARX_IMPORTANT << "Frequency: " << config.frequency << ", dt: " << dt;
247
248 approxTimeQueue =
249 std::make_unique<ApproximateTimeQueue>(dt,
250 dtHistoryLength,
251 config.laserScanners,
252 *this,
253 config.useOdometryBasedLaserCorrection);
254
255 if (debugObserver)
256 {
258 ARMARX_IMPORTANT << "Debug observer is set";
259 cartographerInputDataReporterLaserScanner.emplace(
260 debugObserver, "CartographerMappingAndLocalization_input_laser");
261 cartographerInputDataReporterOdometry.emplace(
262 debugObserver, "CartographerMappingAndLocalization_input_odom");
263 if (config.enableDebugTiming)
264 {
265 debugObserverHelper.emplace(
266 "CartographerMappingAndLocalization_CartographerAdapter", debugObserver, true);
267 }
268 }
269 }
270
271 void
273 {
275 pushInOdomData(data.odomPose);
276 pushInLaserData(data.laserData);
277 if (debugObserverHelper)
278 {
280 std::unique_lock g(debugObserverHelperMtx);
281 debugObserverHelper->sendDebugObserverBatch();
282 }
283 }
284
285 void
286 CartographerAdapter::pushInOdomData(
288 {
290 const DebugObserverScopedTimer timer(this, "pushInOdomData | Entire Method");
291 if (lastOdomTimestamp.has_value())
292 {
294 if (odomPose.timestamp <= lastOdomTimestamp.value())
295 {
297 << "Requested to add old data into odom queue. Not willing to do this. It is "
298 << (odomPose.timestamp - lastOdomTimestamp.value()) << "ms in the past.";
299 return;
300 }
301 }
302
303 lastOdomTimestamp = odomPose.timestamp;
304
305 const auto& timestamp = odomPose.timestamp;
306 ARMARX_DEBUG << "New odom pose received " << timestamp;
307
308 auto isOdomSensor = [](const SensorId& sensorId)
309 { return sensorId.type == SensorId::SensorType::ODOMETRY; };
310
311 if (not std::any_of(sensorSet.begin(), sensorSet.end(), isOdomSensor))
312 {
314 ARMARX_WARNING << "No odometry sensor is registered. Will not use odometry data.";
315 ARMARX_DEBUG << deactivateSpam(2.) << "Odometry will not be used";
316 return;
317 }
318
319 ARMARX_DEBUG << "Processing odom pose";
320
321 const Eigen::Quaternionf q(odomPose.pose.linear());
322 const Eigen::Vector3f p = odomPose.pose.translation();
323
324 carto::sensor::OdometryData odomData;
325 odomData.pose =
326 carto::transform::Rigid3d::FromArrays(std::array<double, 4>{q.w(), q.x(), q.y(), q.z()},
327 std::array<double, 3>{p.x(), p.y(), p.z()});
328 odomData.time = util::toCarto(timestamp);
329
330 ARMARX_VERBOSE << "Will now insert odom data";
331
332 {
334 const DebugObserverScopedTimer localTimer(this, "pushInOdomData | Inserting Odom Data");
335 std::lock_guard guard{cartoInsertMtx};
336
337 mapBuilder->GetTrajectoryBuilder(trajectoryId)
338 ->AddSensorData(sensorIdOdom.id, odomData);
339 }
340
341 if (cartographerInputDataReporterOdometry.has_value())
342 {
344 cartographerInputDataReporterOdometry->add(timestamp);
345 }
346
347 ARMARX_DEBUG << "Inserted odom data";
348 }
349
350 void
351 CartographerAdapter::pushInLaserData(const LaserMessages& laserMessages)
352 {
354
355 if (not config.useLaserScanner)
356 {
357 ARMARX_INFO << deactivateSpam(100) << "Not considering laser scanner data.";
358 return;
359 }
360
361 const DebugObserverScopedTimer timer(this, "pushInLaserData | Entire Method");
362 carto::sensor::TimedPointCloudData timedPointCloudData;
363 timedPointCloudData.origin = Eigen::Vector3f::Zero();
364
365 {
367 const DebugObserverScopedTimer laserMessageTimer(
368 this, "pushInLaserData | Iterate over laser messages");
369 for (const auto& message : laserMessages)
370 {
371 const auto& data = message.data;
372
373 ARMARX_VERBOSE << "pushInLaserData" << data.scan.size() << " for "
374 << message.data.frame;
375
376 // validate timestamp
377 {
378 // First iteration: lastTimestamp will be created and initialized to 0
379 auto& lastTimestamp = lastSensorDataTimestamp[data.frame];
380
381 if (data.timestamp <= lastTimestamp)
382 {
383 ARMARX_DEBUG << "Requested to add old data with timestamp "
384 << data.timestamp << " into laser queue for sensor "
385 << data.frame << ". Not willing to do this. It is "
386 << (data.timestamp - lastTimestamp) << "ms in the past.";
387 return;
388 }
389
390 lastTimestamp = data.timestamp;
391 }
392
393 // assumption: all points from single sensor
394 Eigen::Isometry3f robot_T_sensor;
395 try
396 {
397 const LaserScannerSensor sensor = lookupSensor(data.frame);
398 ARMARX_DEBUG << "Sensor " << data.frame << " position is "
399 << sensor.pose.translation();
400
401 robot_T_sensor = sensor.pose;
402 }
403 catch (const armarx::LocalException&)
404 {
405 ARMARX_INFO << "Sensor `" << data.frame << "` not found in sensor set.";
406 return;
407 }
408
409 // [m]
410
411 {
412 const DebugObserverScopedTimer localTimer(
413 this, "pushInLaserData | Reserve TimedPointCloudData");
414 timedPointCloudData.time =
415 util::toCarto(data.timestamp); // universal is in 100ns
416 timedPointCloudData.ranges.reserve(timedPointCloudData.ranges.size() +
417 data.scan.size());
418 }
419 ARMARX_DEBUG << "Laser range data: " << data.scan.size() << " points";
420
421 {
422 const DebugObserverScopedTimer localTimer(
423 this, "pushInLaserData | Transform to TimedPointCloudData");
424 std::transform(data.scan.begin(),
425 data.scan.end(),
426 std::back_inserter(timedPointCloudData.ranges),
427 [&](const auto& scanStep) -> carto::sensor::TimedRangefinderPoint
428 {
429 auto rangePoint =
430 toCartesian<Eigen::Vector3f>(scanStep); // [mm]
431 rangePoint /= 1000; // [mm] -> [m]
432
433 carto::sensor::TimedRangefinderPoint point;
434 // point.position = robot_time_correction_T_sensor* rangePoint;
435 point.position = robot_T_sensor * rangePoint;
436 point.time = .0; // relative measurement time (not known)
437 return point;
438 });
439 }
440 }
441 }
442
443 auto cloud = toPCL(timedPointCloudData.ranges);
444 {
445 const DebugObserverScopedTimer localTimer(this, "pushInLaserData | onLaserSensorData");
446 ARMARX_VERBOSE << VAROUT(cloud.size());
447 slamDataCallable.onLaserSensorData({util::fromCarto(timedPointCloudData.time), cloud});
448 }
449 {
451 const DebugObserverScopedTimer localTimer(this,
452 "pushInLaserData | Inserting Laser Data");
453 std::lock_guard guard{cartoInsertMtx};
454
455 auto* trajBuilder = mapBuilder->GetTrajectoryBuilder(trajectoryId);
456 if (trajBuilder == nullptr)
457 {
458 ARMARX_WARNING << "No trajectory builder.";
459 return;
460 }
461
462 const std::int64_t laserScannerInsertCartoTimestamp =
463 timedPointCloudData.time.time_since_epoch().count();
464
465 ARMARX_DEBUG << "Inserting " << sensorIdLaser.id << " with timestamp "
466 << laserScannerInsertCartoTimestamp;
467
468 if (lastLaserScannerInsertCartoTimestamp.has_value())
469 {
470 if (laserScannerInsertCartoTimestamp <= lastLaserScannerInsertCartoTimestamp)
471 {
472 ARMARX_INFO << "Received laser scanner data out of order. Will not handle it.";
473 return;
474 }
475 }
476
477 lastLaserScannerInsertCartoTimestamp = laserScannerInsertCartoTimestamp;
478
479 {
480 const DebugObserverScopedTimer addSensorDataTimer(
481 this, "pushInLaserData | Add Sensor Data to TrajectoryBuilder");
482 ARMARX_VERBOSE << VAROUT(timedPointCloudData.ranges.size());
483 trajBuilder->AddSensorData(sensorIdLaser.id, timedPointCloudData);
484 }
485
486 if (cartographerInputDataReporterLaserScanner)
487 {
488 cartographerInputDataReporterLaserScanner->add(
489 Duration::MicroSeconds(util::fromCarto(timedPointCloudData.time)));
490 }
491 }
492
493
494 ARMARX_DEBUG << "Inserted laser data";
495 }
496
497 void
499 {
501 const DebugObserverScopedTimer timer(this, "processOdometryPose | Entire Method");
503
504 odomPose.timestamp = odom.timestamp;
505 odomPose.pose.setIdentity();
506 odomPose.pose.translation() = odom.position;
507 odomPose.pose.linear() = odom.orientation.toRotationMatrix();
508
509 approxTimeQueue->insertOdomData(std::move(odomPose));
510 }
511
512 void
514 {
516 const DebugObserverScopedTimer timer(this, "processSensorValues | Entire Method");
517 ARMARX_DEBUG << "processing sensor values (intro)";
518
519
520 // auto isSensorRegistered = [&](const std::string& sensorId)
521 // {
522 // return std::any_of(sensorSet.begin(),
523 // sensorSet.end(),
524 // [&sensorId](const SensorId& id) -> bool
525 // { return id.id == sensorId; });
526 // };
527
528 // if (not isSensorRegistered(data.frame))
529 // {
530 // ARMARX_VERBOSE << deactivateSpam(1.0) << "Sensor " << data.frame << " not registered. Registered sensors: " << sensorSet;
531 // return;
532 // }
533
534 ARMARX_CHECK_NOT_NULL(approxTimeQueue);
535 approxTimeQueue->insertLaserData(std::move(data));
536 }
537
538 void
539 CartographerAdapter::getLocalSlamResultCallback(
540 const int trajectoryId,
541 const ::cartographer::common::Time time,
542 const ::cartographer::transform::Rigid3d localPose,
543 ::cartographer::sensor::RangeData rangeDataInLocal,
544 const std::unique_ptr<
545 const ::cartographer::mapping::TrajectoryBuilderInterface::InsertionResult>
546 insertion_result)
547 {
549 const DebugObserverScopedTimer timer(this, "getLocalSlamResultCallback | Entire Method");
550 // std::lock_guard g{cartoInsertMtx};
551
552 ARMARX_DEBUG << "Callback (getLocalSlamResultCallback)";
553
554
555 // std::lock_guard g{cartoInsertMtx};
556
557 // const auto constraints = mapBuilder->pose_graph()->constraints();
558 // ARMARX_DEBUG << "number of contraints: " << constraints.size();
559
560 // const size_t nConstraintsInter = std::count_if(
561 // constraints.begin(),
562 // constraints.end(),
563 // [](const ::cartographer::mapping::PoseGraphInterface::Constraint & constraint)
564 // {
565 // return constraint.tag ==
566 // ::cartographer::mapping::PoseGraphInterface::Constraint::INTER_SUBMAP;
567 // });
568
569 // ARMARX_DEBUG << "Inter submap constraints: " << nConstraintsInter;
570
571 LocalSlamData localSlamData;
572
573 {
575 const DebugObserverScopedTimer localTimer(
576 this, "getLocalSlamResultCallback | Prepare Local Slam Data");
577 const auto timestampInMicroSeconds = util::fromCarto(time);
578
579 ARMARX_DEBUG << "local slam data timestamp: "
580 << IceUtil::Time::microSeconds(timestampInMicroSeconds);
581
582 localSlamData.local_points = toPCL(rangeDataInLocal.returns.points());
583 localSlamData.misses = toPCL(rangeDataInLocal.misses.points());
584 localSlamData.local_pose = toEigen(localPose);
585 localSlamData.timestamp = timestampInMicroSeconds;
586 localSlamData.trajectory_pose =
587 toEigen(mapBuilder->pose_graph()->GetLocalToGlobalTransform(trajectoryId));
588
589 ARMARX_DEBUG << "Callbacks will be triggered (getLocalSlamResultCallback)";
590 }
591 {
592 const DebugObserverScopedTimer localTimer(
593 this, "getLocalSlamResultCallback | On Local Slam Data");
594 slamDataCallable.onLocalSlamData(localSlamData);
595 }
596 // triggerCallbacks();
597
598 // report status of localization quality
599 {
600 const auto nConstraints = numConstraints();
601
602 if (debugObserverHelper.has_value())
603 {
604 const std::unique_lock lock(debugObserverHelperMtx);
605 debugObserverHelper->setDebugObserverDatafield("Number of constraints",
606 nConstraints);
607 }
608 }
609
610 ARMARX_DEBUG << "Callback done (getLocalSlamResultCallback)";
611 }
612
613 // void CartographerAdapter::triggerCallbacks() const
614 // {
615 // // slamDataCallable.onGraphOptimized(optimizedGraphData());
616 // // slamDataCallable.onGridMap(submapData(trajectoryId));
617 // }
618
619 bool
621 {
623 const DebugObserverScopedTimer timer(this, "hasReceivedSensorData | Entire Method");
624 std::lock_guard g{cartoInsertMtx};
625
626 const auto trajectoryNodes = mapBuilder->pose_graph()->GetTrajectoryNodes();
627
628 auto matchesTrajectoryId = [&](const auto& node) -> bool
629 { return node.id.trajectory_id == trajectoryId; };
630
631 // checks if nodes wrt. trajectory_id exist
632 return std::any_of(trajectoryNodes.begin(), trajectoryNodes.end(), matchesTrajectoryId);
633 }
634
635 bool
636 storeDefaultRegistrationFile(const fs::path& jsonFile)
637 {
639 std::ofstream ofs(jsonFile, std::ios::out);
640
641 ARMARX_CHECK(ofs.is_open());
642 ARMARX_CHECK(not ofs.fail());
643
644 nlohmann::json data;
645 data["x"] = 0.F;
646 data["y"] = 0.F;
647 data["yaw"] = 0.F;
648
649 ARMARX_INFO << "Creating dummy registration file `" << jsonFile << "`";
650 ofs << data;
651
652 return true;
653 }
654
655 bool
657 {
659 const std::string filenameNoExtension = timestamp();
660
661 const fs::path mapFilename =
662 std::filesystem::path(mapOutputPath.toSystemPath()) / (filenameNoExtension + ".carto");
663 ARMARX_DEBUG << "The concrete map file is " << mapFilename.string();
664 assert(!fs::exists(map_filename));
665
666 // Create a new trajectory such that new data will not interfer with the map
667 // that we are optimizing. Therefore, keep track of the trajectory that we
668 // optimize.
669 const int trajectoryIdToBeOptimized = trajectoryId;
670
671 std::lock_guard g{cartoInsertMtx};
672
673 trajectoryId = mapBuilder->AddTrajectoryBuilder(
674 sensorSet,
675 trajectoryBuilderOptions,
676 [&](auto... args)
677 { return getLocalSlamResultCallback(std::forward<decltype(args)>(args)...); });
678
679 ARMARX_IMPORTANT << "Optimizing map ...";
680 mapBuilder->FinishTrajectory(trajectoryIdToBeOptimized);
681 mapBuilder->pose_graph()->RunFinalOptimization();
682 ARMARX_IMPORTANT << "... done.";
683
684 carto::io::ProtoStreamWriter writer(mapFilename);
685 mapBuilder->SerializeState(true, &writer);
686 writer.Close();
687
688 ARMARX_IMPORTANT << "Saved map to '" << mapFilename << "'";
689
690 const fs::path registrationFilename = mapPath / (filenameNoExtension + ".json");
691 ARMARX_INFO << "The default registration data will be stored in " << registrationFilename;
692 storeDefaultRegistrationFile(registrationFilename);
693
694 // slamDataCallable.onGraphOptimized(optimizedGraphData());
695 // slamDataCallable.onGridMap(submapData(trajectoryIdToBeOptimized));
696
697 return true;
698 }
699
701 CartographerAdapter::lookupSensor(const std::string& device) const
702 {
704 const DebugObserverScopedTimer timer(this, "lookupSensor");
705 auto laserSensorIt = laserSensorMap.find(device);
706 if (laserSensorIt == laserSensorMap.end())
707 {
708 throw armarx::LocalException("No sensor with id '" + device + "' found.");
709 }
710 return laserSensorIt->second;
711 }
712
713 void
714 CartographerAdapter::setSensorPose(const std::string& sensorId, const Eigen::Isometry3f& pose)
715 {
717 auto laserSensorIt = laserSensorMap.find(sensorId);
718 if (laserSensorIt == laserSensorMap.end())
719 {
720 throw armarx::LocalException("No sensor with id '" + sensorId + "' found.");
721 }
722 laserSensorIt->second.pose = pose;
723 }
724
725 std::vector<std::string>
727 {
729 return armarx::getMapKeys(laserSensorMap);
730 }
731
732 CartographerAdapter::DebugObserverScopedTimer::~DebugObserverScopedTimer()
733 {
735 if (parent->debugObserverHelper)
736 {
737 const armarx::Duration duration = armarx::DateTime::Now() - start;
738 const std::unique_lock lock(parent->debugObserverHelperMtx);
739 parent->debugObserverHelper->setDebugObserverDatafield(name + " [ms]",
740 duration.toMicroSeconds());
741 }
742 }
743
744 CartographerAdapter::DebugObserverScopedTimer::DebugObserverScopedTimer(
745 const CartographerAdapter* parent,
746 const std::string& name) :
747 parent(parent), name(name), start(armarx::DateTime::Now())
748 {
749 }
750
751 unsigned int
753 {
754 const auto constraints = mapBuilder->pose_graph()->constraints();
755 return std::count_if(
756 constraints.begin(),
757 constraints.end(),
758 [trajectoryId = this->trajectoryId](
759 const ::cartographer::mapping::PoseGraphInterface::Constraint& constraint)
760 { return constraint.node_id.trajectory_id == trajectoryId; });
761 }
762
763 ::cartographer::mapping::MapBuilderInterface&
765 {
766 return *mapBuilder;
767 }
768} // namespace armarx::localization_and_mapping::cartographer_adapter
std::string timestamp()
constexpr int SCALE_M_TO_MM
uint8_t data[1]
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition Logging.cpp:75
#define VAROUT(x)
constexpr T dt
static DateTime Now()
Definition DateTime.cpp:51
static Duration MicroSeconds(std::int64_t microSeconds)
Constructs a duration in microseconds.
Definition Duration.cpp:24
static std::filesystem::path toSystemPath(const data::PackagePath &pp)
Represents a point in time.
Definition DateTime.h:25
Represents a duration.
Definition Duration.h:17
std::int64_t toMicroSeconds() const
Returns the amount of microseconds.
Definition Duration.cpp:36
CartographerAdapter(const std::filesystem::path &mapPath, const std::filesystem::path &configPath, SlamDataCallable &slamDataCallable, const Config &config, const std::optional< std::filesystem::path > &mapToLoad=std::nullopt, const std::optional< Eigen::Isometry3f > &map_T_robot_prior=std::nullopt, const DebugObserverInterfacePrx &debugObserver=nullptr)
void setSensorPose(const std::string &sensorId, const Eigen::Isometry3f &pose)
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:190
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:184
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:187
#define q
Quaternion< float, 0 > Quaternionf
pcl::PointXYZ toPCL(const Eigen::Vector3f &v)
int64_t fromCarto(::cartographer::common::Time time)
Convert cartographer time to unix time in [µs].
std::unique_ptr<::cartographer::common::LuaParameterDictionary > resolveLuaParameters(const std::string &luaCode, const std::filesystem::path &configPath)
Helper function to create Lua parameter object from string.
::pcl::PointCloud<::pcl::PointXYZ > toPCL(const std::vector<::cartographer::sensor::TimedRangefinderPoint > &points)
::cartographer::transform::Rigid3d fromEigen(const Eigen::Isometry3f &pose)
This file offers overloads of toIce() and fromIce() functions for STL container types.
::IceInternal::ProxyHandle<::IceProxy::armarx::DebugObserverInterface > DebugObserverInterfacePrx
void getMapKeys(const MapType &map, OutputIteratorType it)
Definition algorithm.h:173
Eigen::Vector3f toEigen(const pcl::PointXYZ &pt)
#define ARMARX_TRACE
Definition trace.h:77