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 // stop the thread that feeds cartographer before tearing cartographer down
111 approxTimeQueue.reset();
112
113 ARMARX_INFO << "Finishing cartographer";
114 mapBuilder->FinishTrajectory(trajectoryId);
115
116 ARMARX_INFO << "Releasing cartographer";
117 mapBuilder.reset();
118
119 ARMARX_INFO << "Done";
120 }
121
123 const std::filesystem::path& mapPath,
124 const std::filesystem::path& configPath,
125 SlamDataCallable& slamDataCallable,
126 const Config& config,
127 const std::optional<std::filesystem::path>& mapToLoad,
128 const std::optional<Eigen::Isometry3f>& map_T_robot_prior,
129 const DebugObserverInterfacePrx& debugObserver) :
130 config(config), mapPath(mapPath), slamDataCallable(slamDataCallable)
131 {
133 const std::string mapBuilderLuaCode = R"text(
134 include "map_builder.lua"
135 return MAP_BUILDER)text";
136
137 const std::string trajectoryBuilderLuaCode = R"text(
138 include "trajectory_builder.lua"
139 return TRAJECTORY_BUILDER)text";
140
141 const auto mapBuilderParameters = util::resolveLuaParameters(mapBuilderLuaCode, configPath);
142 auto mapBuilderOptions =
143 carto::mapping::CreateMapBuilderOptions(mapBuilderParameters.get());
144
145
146 if (config.global_localization_min_score > 0)
147 {
148 ARMARX_INFO << "Setting `global_localization_min_score` to "
149 << config.global_localization_min_score;
150 mapBuilderOptions.mutable_pose_graph_options()
151 ->mutable_constraint_builder_options()
152 ->set_global_localization_min_score(config.global_localization_min_score);
153 }
154
155 if (config.min_score > 0)
156 {
157 ARMARX_INFO << "Setting `min_score` to " << config.min_score;
158 mapBuilderOptions.mutable_pose_graph_options()
159 ->mutable_constraint_builder_options()
160 ->set_min_score(config.min_score);
161 }
162
163 const auto trajectoryBuilderParameters =
164 util::resolveLuaParameters(trajectoryBuilderLuaCode, configPath);
165 trajectoryBuilderOptions =
166 carto::mapping::CreateTrajectoryBuilderOptions(trajectoryBuilderParameters.get());
167
168 // create map builder
169 mapBuilder = carto::mapping::CreateMapBuilder(mapBuilderOptions);
170
171 if (config.useLaserScanner)
172 {
173 sensorSet.insert(sensorIdLaser);
174 }
175
176 if (config.useOdometry)
177 {
178 sensorSet.insert(sensorIdOdom);
179 }
180
181 if (config.useImu)
182 {
183 sensorSet.insert(sensorIdIMU);
184 }
185
186 std::vector<std::string> sensorSetNames;
187 std::transform(sensorSet.begin(),
188 sensorSet.end(),
189 std::back_inserter(sensorSetNames),
190 [](const auto& sensorId) { return sensorId.id; });
191
192 ARMARX_IMPORTANT << "Sensor set '" << sensorSetNames << "' will be used";
193
194 if (config.useLaserScanner)
195 {
196 ARMARX_IMPORTANT << "This includes the following laser scanners: "
197 << std::vector<std::string>(config.laserScanners.begin(),
198 config.laserScanners.end());
199
200 std::for_each(config.laserScanners.begin(),
201 config.laserScanners.end(),
202 [&](const auto& laserScannerName)
203 {
204 const SensorId sensorId{.type = SensorId::SensorType::RANGE,
205 .id = laserScannerName};
206 laserSensorMap.insert(
207 {laserScannerName,
208 LaserScannerSensor(sensorId, Eigen::Isometry3f::Identity())});
209 });
210 }
211
212
213 if (mapToLoad)
214 {
216 ARMARX_DEBUG << "Loading map";
217 carto::io::ProtoStreamReader reader(mapToLoad->string());
218 mapBuilder->LoadState(&reader, true /* load_frozen_state */);
219 mapBuilder->pose_graph()->RunFinalOptimization();
220
221
222 if (map_T_robot_prior)
223 {
224 ARMARX_INFO << "Using pose prior \n" << map_T_robot_prior->matrix();
225
226 ::cartographer::mapping::proto::InitialTrajectoryPose* initial_trajectory_pose =
227 new ::cartographer::mapping::proto::InitialTrajectoryPose;
228
229 initial_trajectory_pose->set_allocated_relative_pose(
230 new ::cartographer::transform::proto::Rigid3d(
231 ::cartographer::transform::ToProto(fromEigen(*map_T_robot_prior))));
232
233 trajectoryBuilderOptions.set_allocated_initial_trajectory_pose(
234 std::move(initial_trajectory_pose)); // owner -> trajectoryBuilderOptions
235 }
236 }
237
238
239 trajectoryId = mapBuilder->AddTrajectoryBuilder(
240 sensorSet,
241 trajectoryBuilderOptions,
242 [this](auto&&... args)
243 { return getLocalSlamResultCallback(std::forward<decltype(args)>(args)...); });
244
245 // TODO(fabian.reister): variable sensor set
246 const auto dt = static_cast<int64_t>(1'000'000 / config.frequency);
247 const float dtHistoryLength = 1'000'000;
248
249 ARMARX_IMPORTANT << "Frequency: " << config.frequency << ", dt: " << dt;
250
251 approxTimeQueue =
252 std::make_unique<ApproximateTimeQueue>(dt,
253 dtHistoryLength,
254 config.laserScanners,
255 *this,
256 config.useOdometryBasedLaserCorrection);
257
258 if (debugObserver)
259 {
261 ARMARX_IMPORTANT << "Debug observer is set";
262 cartographerInputDataReporterLaserScanner.emplace(
263 debugObserver, "CartographerMappingAndLocalization_input_laser");
264 cartographerInputDataReporterOdometry.emplace(
265 debugObserver, "CartographerMappingAndLocalization_input_odom");
266 if (config.enableDebugTiming)
267 {
268 debugObserverHelper.emplace(
269 "CartographerMappingAndLocalization_CartographerAdapter", debugObserver, true);
270 }
271 }
272 }
273
274 void
276 {
278 pushInOdomData(data.odomPose);
279 pushInLaserData(data.laserData);
280 if (debugObserverHelper)
281 {
283 std::unique_lock g(debugObserverHelperMtx);
284 debugObserverHelper->sendDebugObserverBatch();
285 }
286 }
287
288 void
289 CartographerAdapter::pushInOdomData(
291 {
293 const DebugObserverScopedTimer timer(this, "pushInOdomData | Entire Method");
294 if (lastOdomTimestamp.has_value())
295 {
297 if (odomPose.timestamp <= lastOdomTimestamp.value())
298 {
300 << "Requested to add old data into odom queue. Not willing to do this. It is "
301 << (odomPose.timestamp - lastOdomTimestamp.value()) << "ms in the past.";
302 return;
303 }
304 }
305
306 lastOdomTimestamp = odomPose.timestamp;
307
308 const auto& timestamp = odomPose.timestamp;
309 ARMARX_DEBUG << "New odom pose received " << timestamp;
310
311 auto isOdomSensor = [](const SensorId& sensorId)
312 { return sensorId.type == SensorId::SensorType::ODOMETRY; };
313
314 if (not std::any_of(sensorSet.begin(), sensorSet.end(), isOdomSensor))
315 {
317 ARMARX_WARNING << "No odometry sensor is registered. Will not use odometry data.";
318 ARMARX_DEBUG << deactivateSpam(2.) << "Odometry will not be used";
319 return;
320 }
321
322 ARMARX_DEBUG << "Processing odom pose";
323
324 const Eigen::Quaternionf q(odomPose.pose.linear());
325 const Eigen::Vector3f p = odomPose.pose.translation();
326
327 carto::sensor::OdometryData odomData;
328 odomData.pose =
329 carto::transform::Rigid3d::FromArrays(std::array<double, 4>{q.w(), q.x(), q.y(), q.z()},
330 std::array<double, 3>{p.x(), p.y(), p.z()});
331 odomData.time = util::toCarto(timestamp);
332
333 ARMARX_VERBOSE << "Will now insert odom data";
334
335 {
337 const DebugObserverScopedTimer localTimer(this, "pushInOdomData | Inserting Odom Data");
338 std::lock_guard guard{cartoInsertMtx};
339
340 mapBuilder->GetTrajectoryBuilder(trajectoryId)
341 ->AddSensorData(sensorIdOdom.id, odomData);
342 }
343
344 if (cartographerInputDataReporterOdometry.has_value())
345 {
347 cartographerInputDataReporterOdometry->add(timestamp);
348 }
349
350 ARMARX_DEBUG << "Inserted odom data";
351 }
352
353 void
354 CartographerAdapter::pushInLaserData(const LaserMessages& laserMessages)
355 {
357
358 if (not config.useLaserScanner)
359 {
360 ARMARX_INFO << deactivateSpam(100) << "Not considering laser scanner data.";
361 return;
362 }
363
364 const DebugObserverScopedTimer timer(this, "pushInLaserData | Entire Method");
365 carto::sensor::TimedPointCloudData timedPointCloudData;
366 timedPointCloudData.origin = Eigen::Vector3f::Zero();
367
368 {
370 const DebugObserverScopedTimer laserMessageTimer(
371 this, "pushInLaserData | Iterate over laser messages");
372 for (const auto& message : laserMessages)
373 {
374 const auto& data = message.data;
375
376 ARMARX_VERBOSE << "pushInLaserData" << data.scan.size() << " for "
377 << message.data.frame;
378
379 // validate timestamp
380 {
381 // First iteration: lastTimestamp will be created and initialized to 0
382 auto& lastTimestamp = lastSensorDataTimestamp[data.frame];
383
384 if (data.timestamp <= lastTimestamp)
385 {
386 ARMARX_DEBUG << "Requested to add old data with timestamp "
387 << data.timestamp << " into laser queue for sensor "
388 << data.frame << ". Not willing to do this. It is "
389 << (data.timestamp - lastTimestamp) << "ms in the past.";
390 return;
391 }
392
393 lastTimestamp = data.timestamp;
394 }
395
396 // assumption: all points from single sensor
397 Eigen::Isometry3f robot_T_sensor;
398 try
399 {
400 const LaserScannerSensor sensor = lookupSensor(data.frame);
401 ARMARX_DEBUG << "Sensor " << data.frame << " position is "
402 << sensor.pose.translation();
403
404 robot_T_sensor = sensor.pose;
405 }
406 catch (const armarx::LocalException&)
407 {
408 ARMARX_INFO << "Sensor `" << data.frame << "` not found in sensor set.";
409 return;
410 }
411
412 // [m]
413
414 {
415 const DebugObserverScopedTimer localTimer(
416 this, "pushInLaserData | Reserve TimedPointCloudData");
417 timedPointCloudData.time =
418 util::toCarto(data.timestamp); // universal is in 100ns
419 timedPointCloudData.ranges.reserve(timedPointCloudData.ranges.size() +
420 data.scan.size());
421 }
422 ARMARX_DEBUG << "Laser range data: " << data.scan.size() << " points";
423
424 {
425 const DebugObserverScopedTimer localTimer(
426 this, "pushInLaserData | Transform to TimedPointCloudData");
427 std::transform(data.scan.begin(),
428 data.scan.end(),
429 std::back_inserter(timedPointCloudData.ranges),
430 [&](const auto& scanStep) -> carto::sensor::TimedRangefinderPoint
431 {
432 auto rangePoint =
433 toCartesian<Eigen::Vector3f>(scanStep); // [mm]
434 rangePoint /= 1000; // [mm] -> [m]
435
436 carto::sensor::TimedRangefinderPoint point;
437 // point.position = robot_time_correction_T_sensor* rangePoint;
438 point.position = robot_T_sensor * rangePoint;
439 point.time = .0; // relative measurement time (not known)
440 return point;
441 });
442 }
443 }
444 }
445
446 auto cloud = toPCL(timedPointCloudData.ranges);
447 {
448 const DebugObserverScopedTimer localTimer(this, "pushInLaserData | onLaserSensorData");
449 ARMARX_VERBOSE << VAROUT(cloud.size());
450 slamDataCallable.onLaserSensorData({util::fromCarto(timedPointCloudData.time), cloud});
451 }
452 {
454 const DebugObserverScopedTimer localTimer(this,
455 "pushInLaserData | Inserting Laser Data");
456 std::lock_guard guard{cartoInsertMtx};
457
458 auto* trajBuilder = mapBuilder->GetTrajectoryBuilder(trajectoryId);
459 if (trajBuilder == nullptr)
460 {
461 ARMARX_WARNING << "No trajectory builder.";
462 return;
463 }
464
465 const std::int64_t laserScannerInsertCartoTimestamp =
466 timedPointCloudData.time.time_since_epoch().count();
467
468 ARMARX_DEBUG << "Inserting " << sensorIdLaser.id << " with timestamp "
469 << laserScannerInsertCartoTimestamp;
470
471 if (lastLaserScannerInsertCartoTimestamp.has_value())
472 {
473 if (laserScannerInsertCartoTimestamp <= lastLaserScannerInsertCartoTimestamp)
474 {
475 ARMARX_INFO << "Received laser scanner data out of order. Will not handle it.";
476 return;
477 }
478 }
479
480 lastLaserScannerInsertCartoTimestamp = laserScannerInsertCartoTimestamp;
481
482 {
483 const DebugObserverScopedTimer addSensorDataTimer(
484 this, "pushInLaserData | Add Sensor Data to TrajectoryBuilder");
485 ARMARX_VERBOSE << VAROUT(timedPointCloudData.ranges.size());
486 trajBuilder->AddSensorData(sensorIdLaser.id, timedPointCloudData);
487 }
488
489 if (cartographerInputDataReporterLaserScanner)
490 {
491 cartographerInputDataReporterLaserScanner->add(
492 Duration::MicroSeconds(util::fromCarto(timedPointCloudData.time)));
493 }
494 }
495
496
497 ARMARX_DEBUG << "Inserted laser data";
498 }
499
500 void
502 {
504 const DebugObserverScopedTimer timer(this, "processOdometryPose | Entire Method");
506
507 odomPose.timestamp = odom.timestamp;
508 odomPose.pose.setIdentity();
509 odomPose.pose.translation() = odom.position;
510 odomPose.pose.linear() = odom.orientation.toRotationMatrix();
511
512 approxTimeQueue->insertOdomData(std::move(odomPose));
513 }
514
515 void
517 {
519 const DebugObserverScopedTimer timer(this, "processSensorValues | Entire Method");
520 ARMARX_DEBUG << "processing sensor values (intro)";
521
522
523 // auto isSensorRegistered = [&](const std::string& sensorId)
524 // {
525 // return std::any_of(sensorSet.begin(),
526 // sensorSet.end(),
527 // [&sensorId](const SensorId& id) -> bool
528 // { return id.id == sensorId; });
529 // };
530
531 // if (not isSensorRegistered(data.frame))
532 // {
533 // ARMARX_VERBOSE << deactivateSpam(1.0) << "Sensor " << data.frame << " not registered. Registered sensors: " << sensorSet;
534 // return;
535 // }
536
537 ARMARX_CHECK_NOT_NULL(approxTimeQueue);
538 approxTimeQueue->insertLaserData(std::move(data));
539 }
540
541 void
542 CartographerAdapter::getLocalSlamResultCallback(
543 const int trajectoryId,
544 const ::cartographer::common::Time time,
545 const ::cartographer::transform::Rigid3d localPose,
546 ::cartographer::sensor::RangeData rangeDataInLocal,
547 const std::unique_ptr<
548 const ::cartographer::mapping::TrajectoryBuilderInterface::InsertionResult>
549 insertion_result)
550 {
552 const DebugObserverScopedTimer timer(this, "getLocalSlamResultCallback | Entire Method");
553 // std::lock_guard g{cartoInsertMtx};
554
555 ARMARX_DEBUG << "Callback (getLocalSlamResultCallback)";
556
557
558 // std::lock_guard g{cartoInsertMtx};
559
560 // const auto constraints = mapBuilder->pose_graph()->constraints();
561 // ARMARX_DEBUG << "number of contraints: " << constraints.size();
562
563 // const size_t nConstraintsInter = std::count_if(
564 // constraints.begin(),
565 // constraints.end(),
566 // [](const ::cartographer::mapping::PoseGraphInterface::Constraint & constraint)
567 // {
568 // return constraint.tag ==
569 // ::cartographer::mapping::PoseGraphInterface::Constraint::INTER_SUBMAP;
570 // });
571
572 // ARMARX_DEBUG << "Inter submap constraints: " << nConstraintsInter;
573
574 LocalSlamData localSlamData;
575
576 {
578 const DebugObserverScopedTimer localTimer(
579 this, "getLocalSlamResultCallback | Prepare Local Slam Data");
580 const auto timestampInMicroSeconds = util::fromCarto(time);
581
582 ARMARX_DEBUG << "local slam data timestamp: "
583 << IceUtil::Time::microSeconds(timestampInMicroSeconds);
584
585 localSlamData.local_points = toPCL(rangeDataInLocal.returns.points());
586 localSlamData.misses = toPCL(rangeDataInLocal.misses.points());
587 localSlamData.local_pose = toEigen(localPose);
588 localSlamData.timestamp = timestampInMicroSeconds;
589 localSlamData.trajectory_pose =
590 toEigen(mapBuilder->pose_graph()->GetLocalToGlobalTransform(trajectoryId));
591
592 ARMARX_DEBUG << "Callbacks will be triggered (getLocalSlamResultCallback)";
593 }
594 {
595 const DebugObserverScopedTimer localTimer(
596 this, "getLocalSlamResultCallback | On Local Slam Data");
597 slamDataCallable.onLocalSlamData(localSlamData);
598 }
599 // triggerCallbacks();
600
601 // report status of localization quality
602 {
603 const auto nConstraints = numConstraints();
604
605 if (debugObserverHelper.has_value())
606 {
607 const std::unique_lock lock(debugObserverHelperMtx);
608 debugObserverHelper->setDebugObserverDatafield("Number of constraints",
609 nConstraints);
610 }
611 }
612
613 ARMARX_DEBUG << "Callback done (getLocalSlamResultCallback)";
614 }
615
616 // void CartographerAdapter::triggerCallbacks() const
617 // {
618 // // slamDataCallable.onGraphOptimized(optimizedGraphData());
619 // // slamDataCallable.onGridMap(submapData(trajectoryId));
620 // }
621
622 bool
624 {
626 const DebugObserverScopedTimer timer(this, "hasReceivedSensorData | Entire Method");
627 std::lock_guard g{cartoInsertMtx};
628
629 const auto trajectoryNodes = mapBuilder->pose_graph()->GetTrajectoryNodes();
630
631 auto matchesTrajectoryId = [&](const auto& node) -> bool
632 { return node.id.trajectory_id == trajectoryId; };
633
634 // checks if nodes wrt. trajectory_id exist
635 return std::any_of(trajectoryNodes.begin(), trajectoryNodes.end(), matchesTrajectoryId);
636 }
637
638 bool
639 storeDefaultRegistrationFile(const fs::path& jsonFile)
640 {
642 std::ofstream ofs(jsonFile, std::ios::out);
643
644 ARMARX_CHECK(ofs.is_open());
645 ARMARX_CHECK(not ofs.fail());
646
647 nlohmann::json data;
648 data["x"] = 0.F;
649 data["y"] = 0.F;
650 data["yaw"] = 0.F;
651
652 ARMARX_INFO << "Creating dummy registration file `" << jsonFile << "`";
653 ofs << data;
654
655 return true;
656 }
657
658 bool
660 {
662 const std::string filenameNoExtension = timestamp();
663
664 const fs::path mapFilename =
665 std::filesystem::path(mapOutputPath.toSystemPath()) / (filenameNoExtension + ".carto");
666 ARMARX_DEBUG << "The concrete map file is " << mapFilename.string();
667 assert(!fs::exists(map_filename));
668
669 // Create a new trajectory such that new data will not interfer with the map
670 // that we are optimizing. Therefore, keep track of the trajectory that we
671 // optimize.
672 const int trajectoryIdToBeOptimized = trajectoryId;
673
674 std::lock_guard g{cartoInsertMtx};
675
676 trajectoryId = mapBuilder->AddTrajectoryBuilder(
677 sensorSet,
678 trajectoryBuilderOptions,
679 [&](auto... args)
680 { return getLocalSlamResultCallback(std::forward<decltype(args)>(args)...); });
681
682 ARMARX_IMPORTANT << "Optimizing map ...";
683 mapBuilder->FinishTrajectory(trajectoryIdToBeOptimized);
684 mapBuilder->pose_graph()->RunFinalOptimization();
685 ARMARX_IMPORTANT << "... done.";
686
687 carto::io::ProtoStreamWriter writer(mapFilename);
688 mapBuilder->SerializeState(true, &writer);
689 writer.Close();
690
691 ARMARX_IMPORTANT << "Saved map to '" << mapFilename << "'";
692
693 const fs::path registrationFilename = mapPath / (filenameNoExtension + ".json");
694 ARMARX_INFO << "The default registration data will be stored in " << registrationFilename;
695 storeDefaultRegistrationFile(registrationFilename);
696
697 // slamDataCallable.onGraphOptimized(optimizedGraphData());
698 // slamDataCallable.onGridMap(submapData(trajectoryIdToBeOptimized));
699
700 return true;
701 }
702
704 CartographerAdapter::lookupSensor(const std::string& device) const
705 {
707 const DebugObserverScopedTimer timer(this, "lookupSensor");
708 auto laserSensorIt = laserSensorMap.find(device);
709 if (laserSensorIt == laserSensorMap.end())
710 {
711 throw armarx::LocalException("No sensor with id '" + device + "' found.");
712 }
713 return laserSensorIt->second;
714 }
715
716 void
717 CartographerAdapter::setSensorPose(const std::string& sensorId, const Eigen::Isometry3f& pose)
718 {
720 auto laserSensorIt = laserSensorMap.find(sensorId);
721 if (laserSensorIt == laserSensorMap.end())
722 {
723 throw armarx::LocalException("No sensor with id '" + sensorId + "' found.");
724 }
725 laserSensorIt->second.pose = pose;
726 }
727
728 std::vector<std::string>
730 {
732 return armarx::getMapKeys(laserSensorMap);
733 }
734
735 CartographerAdapter::DebugObserverScopedTimer::~DebugObserverScopedTimer()
736 {
738 if (parent->debugObserverHelper)
739 {
740 const armarx::Duration duration = armarx::DateTime::Now() - start;
741 const std::unique_lock lock(parent->debugObserverHelperMtx);
742 parent->debugObserverHelper->setDebugObserverDatafield(name + " [ms]",
743 duration.toMicroSeconds());
744 }
745 }
746
747 CartographerAdapter::DebugObserverScopedTimer::DebugObserverScopedTimer(
748 const CartographerAdapter* parent,
749 const std::string& name) :
750 parent(parent), name(name), start(armarx::DateTime::Now())
751 {
752 }
753
754 unsigned int
756 {
757 const auto constraints = mapBuilder->pose_graph()->constraints();
758 return std::count_if(
759 constraints.begin(),
760 constraints.end(),
761 [trajectoryId = this->trajectoryId](
762 const ::cartographer::mapping::PoseGraphInterface::Constraint& constraint)
763 { return constraint.node_id.trajectory_id == trajectoryId; });
764 }
765
766 ::cartographer::mapping::MapBuilderInterface&
768 {
769 return *mapBuilder;
770 }
771} // 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:179
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:188
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:182
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:191
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:185
#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:75