Conscience Core
CscSlamEngine.h
Go to the documentation of this file.
1 //
2 // CscSlamEngine.hpp
3 // ConscienceRobotManager
4 //
5 // Created by Iliès Zaoui on 23/10/2022.
6 // Copyright © 2022 Conscience Robotics. All rights reserved.
7 //
8 
9 #ifndef CscSlamEngine_h
10 #define CscSlamEngine_h
11 
12 #include <CscCommon.h>
13 #include <mutex>
14 
15 #include <queue>
16 #include <mrpt/math/TPose2D.h>
18 #include <Axiomes/Csc2dTypes.h>
19 namespace mrpt::maps {
20 class COccupancyGridMap2D;
21 }
22 namespace mrpt::obs {
23 class CObservation2DRangeScan;
24 }
25 namespace mrpt::slam {
26 class CMonteCarloLocalization2D;
27 class CMetricMapBuilderRBPF;
28 }
29 using namespace conscience_utils::logging;
30 using mrpt::math::TPoint2D, mrpt::math::TPose2D, mrpt::obs::CObservation2DRangeScan, mrpt::maps::COccupancyGridMap2D, mrpt::slam::CMonteCarloLocalization2D, mrpt::slam::CMetricMapBuilderRBPF;
31 using std::string, std::recursive_mutex, std::vector, std::map, std::pair, std::lock_guard, std::queue;
32 namespace fs = std::filesystem;
33 using namespace conscience_core::axiomes;
34 
35 namespace conscience_core::lidar {
36 
37 class CscLidarEngine;
38 struct LidarValues;
39 
40 enum class CscSlamCellOccupancyStatus : uint8_t {
44 };
45 
47 public:
48  static constexpr double defaultCellOccupiedThreshold = 0.14;
49 
53  struct PhantomCluster {
54  vector<pair<int, int>> cells; // (i,j) indices
55  double overlapRatio{0.0}; // supported/occCount
56  bool duplicate;
57  };
62  std::vector<std::pair<int, int>> cells; // occupied cells in cluster
63  int hits = 0; // number of times observed
64  std::chrono::steady_clock::time_point lastHit;
65  };
66 
67  CscSlamEngine(const string &entitySerialNumber, bool isSimulatedEntity, CscEntityPositionManager *positionManager, CscLidarEngine *lidarEngine);
68  ~CscSlamEngine();
69 
70  void stop();
71  void start(CscPoint3dOriented *initialPosition = nullptr);
72 
73  const CscPoint3d &getRobotStartPosition() const;
74  const CscQuaternion &getRobotStartOrientation() const;
78  CscPoint3dOriented *getRobotPose3d() const;
79 
84  fs::path saveCartography();
85  bool loadCartography(const fs::path &cartographyDir);
86  bool loadLatestCartography();
87  bool hasLoadedCartography();
88 
89  bool isStarted() const;
90  bool isStartedAndReady() const;
91 
92  void consumeLidarValues();
93 
94  void forceLocalisationPosition(double xInMeters, double zInMeters, double headingInRad);
95 
101  optional<TPose2D> robotPose = nullopt;
102 
103  map<TPoint2D, Vec3> dots;
107  map<TPoint2D, Vec3> crosses;
111  vector<TPose2D> path;
116  vector<CscSlamEngine::PhantomCluster> clusters;
117  vector<CscSlamEngine::PhantomClusterTracked> clustersTracked;
121  vector<uint8_t> cellsVisibility;
122 
126  const CObservation2DRangeScan *lidarScan = nullptr;
127  };
128  void saveMrptMapToPng(const string &filename,
129  const MapToImageParams &params);
130 
131  CscPoint3d *transformToWorld3dPosition(const TPoint2D &pointSlam2d) const;
132  vector<CscPoint3d *> getMapAsWorldPoints(double threshold = defaultCellOccupiedThreshold) const;
133 
134  inline constexpr CscSlamCellOccupancyStatus getCellStatus(float cellValue, double occupiedThreshold = defaultCellOccupiedThreshold) {
135  if (cellValue < 0.0f || std::abs(cellValue - 0.5f) < 1e-6f) { // Tolérance pour floating point
136  return CscSlamCellOccupancyStatus::SlamCellOccupancyStatus_Unknown;
137  }
138  if (cellValue <= occupiedThreshold) {
139  return CscSlamCellOccupancyStatus::SlamCellOccupancyStatus_Occupied;
140  }
141  return CscSlamCellOccupancyStatus::SlamCellOccupancyStatus_Free;
142  }
143 
144  void clearCartography();
145 
150  mrpt::math::TPose2D getRobotPose() const;
154  ptr<CObservation2DRangeScan> getLidarScan() const;
159  ptr<COccupancyGridMap2D> getSLAMMap() const;
160 
161 private:
162  class PhantomClusterTracker {
163  public:
164  PhantomClusterTracker(double overlapThreshold = 0.3, int maxAgeSeconds = 300);
165 
166  // Update tracker with new clusters from this tick
167  void update(const std::vector<PhantomCluster> &newClusters);
168 
169  const std::vector<PhantomClusterTracked> &tracked() const;
170 
171  string getSummary() const;
172 
173  private:
174  std::vector<PhantomClusterTracked> trackedClusters;
175  const double overlapThreshold;
176  const int maxAgeSeconds;
177 
178  // Check if clusters overlap enough to be considered the same
179  bool clustersSimilar(
180  const std::vector<std::pair<int, int>> &a,
181  const std::vector<std::pair<int, int>> &b) const;
182  };
183 
184  const string entitySerialNumber;
185  const bool isSimulatedEntity;
186  void consumeLidarValues(const LidarValues &lidarValues);
187 
188  CscPoint3d robotStartPosition;
189  CscQuaternion robotStartOrientation;
190  CscEntityPositionManager *positionManager = nullptr;
191  CscLidarEngine *lidarEngine = nullptr;
192 
193  void clearSlamData();
194 
195  CMonteCarloLocalization2D *slamLocalization = nullptr;
196 
197  mutable recursive_mutex slamInstanceMutex;
198  CMetricMapBuilderRBPF *slamInstance = nullptr;
199  ptr<COccupancyGridMap2D> slamMap = nullptr;
200  bool slamInitialized = false;
201  double robotStartYaw = 0;
202  void initMrptSlam();
203  queue<const LidarValues *> lidarValuesQueue;
204 
205  unique_ptr<CscLogger> logger;
206 
207  unsigned long long lastLidarValuesTimestamp = 0;
208 
209  mutable mutex lastRangeScanMutex;
210  ptr<CObservation2DRangeScan> lastRangeScan = nullptr;
211  std::chrono::steady_clock::time_point lastPngExportTime = std::chrono::steady_clock::now();
212  double odoLastX = 0;
213  double odoLastZ = 0;
214  bool started = false;
215  bool odoDiffInitialized = false;
216  unsigned int lastMapSize = 0;
217  unsigned int identicalCount = 0;
218  std::chrono::steady_clock::time_point lastTimeSlamOdo = std::chrono::steady_clock::now();
219 
220  struct CscSlamMapDiscrepancyState {
221  size_t discrepantScanCount = 0;
222  size_t ticksSinceDiscrepancyStart = 0;
223  double refMean = 0;
224  double refStd = 0;
225  size_t initializationTicksCount = 0;
226  };
227  CscSlamMapDiscrepancyState discrepancyState;
228 
229  struct PhantomClusterParams {
234  double maxDistanceMeters = 8;
235 
240  double minOverlapRatio = 0.2;
241 
246  int supportRadius = 2;
247 
251  int clusterThresh = 10;
252 
257  int maxClusterShiftCells = 14;
258 
263  int gapTolerance = 2;
264 
269  int mergeDistanceCells = 3;
270  };
271  struct PhantomClusterResult {
272  bool hasPhantoms{false};
273  vector<PhantomCluster> clusters;
274  vector<uint8_t> visible;
275  };
276  PhantomClusterResult detectPhantomClusters(
277  const COccupancyGridMap2D &slamMap,
278  const CObservation2DRangeScan &scan,
279  const TPose2D &pose,
280  const PhantomClusterParams &params,
281  double occThreshold = defaultCellOccupiedThreshold);
282  PhantomClusterResult lastClustersResult;
283  PhantomClusterTracker phantomClusterTracker;
284 
285  CscPoint3dOriented *initialPosition = nullptr;
286 
287 protected:
288 };
289 
290 /* MRPT HELPERS - START */
291 
292 inline double distancePoints(const TPoint2D &pointA, const TPoint2D &pointB) {
293  return std::hypot(pointA.x - pointB.x, pointA.y - pointB.y);
294 }
295 inline double distancePoints(const TPose2D &poseA, const TPose2D &poseB) {
296  return distancePoints(TPoint2D(poseA), TPoint2D(poseB));
297 }
299  return CscPoint2d(point.x / 100.0 /*to meters*/, point.z / 100.0 /*to meters*/);
300 }
301 
302 string mrptPoseToJson(const TPose2D &pose);
303 string mrptPointToJson(const TPoint2D &point);
305 CscPoint2d mrptPointToCscPoint(const TPoint2D &point);
306 
307 /* MRPT HELPERS - END */
308 
309 namespace directions {
310 
312  double relYaw;
313  string name;
314 };
315 
316 static const CscAvailableDirection AVAILABLE_DIRECTION_FORWARD = {0.0, "forward"};
317 static const CscAvailableDirection AVAILABLE_DIRECTION_LEFT = {M_PI_2, "left"};
318 static const CscAvailableDirection AVAILABLE_DIRECTION_RIGHT = {-M_PI_2, "right"};
319 static const CscAvailableDirection AVAILABLE_DIRECTION_BACK = {M_PI, "back"};
320 static const vector<CscAvailableDirection> AVAILABLE_ALL_DIRECTIONS = {
325 
326 optional<pair<int, double>> getBestDirectionForScan(
327  CObservation2DRangeScan *scan,
328  const vector<CscAvailableDirection> &authorizedDirections,
329  double robotWidth, double robotLength, map<int, double> *computedDirections = nullptr);
331  const mrpt::obs::CObservation2DRangeScan &scan,
332  double bestYaw,
333  const std::string &bestDirName,
334  const fs::path &filename,
335  double robotWidth, double robotLength);
336 
338  double directionYawRads,
339  const mrpt::obs::CObservation2DRangeScan &scan,
340  double robotWidthMeters,
341  double robotLengthMeters,
342  double minClusterDistanceMeters = 0.10,
343  int minClusterSize = 3,
344  double maxDepthMeters = 2.0);
345 
346 }
347 
348 }
349 
350 #endif
conscience_core::lidar::directions::AVAILABLE_DIRECTION_FORWARD
static const CscAvailableDirection AVAILABLE_DIRECTION_FORWARD
Definition: CscSlamEngine.h:316
conscience_core::lidar::CscSlamEngine::PhantomClusterTracked
Definition: CscSlamEngine.h:61
conscience_core::lidar::mrptPoseToJson
string mrptPoseToJson(const TPose2D &pose)
Definition: CscSlamEngine.cpp:649
conscience_core::axiomes::CscPoint3d
The CscPoint3d class represents a point in three-dimensional space. It is primarily used to denote a ...
Definition: Csc3dTypes.h:24
conscience_core::lidar::directions::estimateFreeDistanceForLidarScan
double estimateFreeDistanceForLidarScan(double directionYawRads, const mrpt::obs::CObservation2DRangeScan &scan, double robotWidthMeters, double robotLengthMeters, double minClusterDistanceMeters, int minClusterSize, double maxDepthMeters)
Definition: CscSlamEngine.cpp:1557
conscience_core::lidar::CscSlamEngine::PhantomClusterTracked::lastHit
std::chrono::steady_clock::time_point lastHit
Definition: CscSlamEngine.h:64
conscience_core::lidar::CscLidarEngine
Definition: CscLidarEngine.h:62
conscience_core::lidar::toMrptReferenceFrame
CscPoint2d toMrptReferenceFrame(const CscPoint3d &point)
Definition: CscSlamEngine.h:298
conscience_core::lidar::mrptPoseToCscPointOriented
CscPoint2dOriented mrptPoseToCscPointOriented(const TPose2D &pose)
Definition: CscSlamEngine.cpp:665
conscience_core::lidar::directions::CscAvailableDirection::name
string name
Definition: CscSlamEngine.h:313
conscience_core::lidar::CscSlamEngine::MapToImageParams::cellsVisibility
vector< uint8_t > cellsVisibility
Definition: CscSlamEngine.h:121
conscience_core::lidar::CscSlamCellOccupancyStatus::SlamCellOccupancyStatus_Unknown
@ SlamCellOccupancyStatus_Unknown
conscience_core::axiomes
Definition: Csc2dTypes.cpp:9
conscience_core::lidar
Definition: CscEntityReflexion.h:42
conscience_core::lidar::directions::getBestDirectionForScan
optional< pair< int, double > > getBestDirectionForScan(CObservation2DRangeScan *scan, const vector< CscAvailableDirection > &authorizedDirections, double robotWidth, double robotLength, map< int, double > *computedDirections)
Definition: CscSlamEngine.cpp:1650
conscience_core::lidar::CscSlamEngine::MapToImageParams::path
vector< TPose2D > path
Definition: CscSlamEngine.h:111
conscience_core::lidar::CscSlamEngine::PhantomCluster
Definition: CscSlamEngine.h:53
conscience_core::lidar::directions::AVAILABLE_ALL_DIRECTIONS
static const vector< CscAvailableDirection > AVAILABLE_ALL_DIRECTIONS
Definition: CscSlamEngine.h:320
conscience_core::lidar::directions::AVAILABLE_DIRECTION_LEFT
static const CscAvailableDirection AVAILABLE_DIRECTION_LEFT
Definition: CscSlamEngine.h:317
mrpt::obs
Definition: CscSlamEngine.h:22
conscience_core::lidar::directions::CscAvailableDirection
Definition: CscSlamEngine.h:311
logger
static std::unique_ptr< CscLogger > logger
Definition: gltfHelpers.cpp:6
conscience_core::lidar::CscSlamCellOccupancyStatus::SlamCellOccupancyStatus_Occupied
@ SlamCellOccupancyStatus_Occupied
conscience_core::lidar::mrptPointToCscPoint
CscPoint2d mrptPointToCscPoint(const TPoint2D &point)
Definition: CscSlamEngine.cpp:669
conscience_core::lidar::CscSlamEngine::getCellStatus
constexpr CscSlamCellOccupancyStatus getCellStatus(float cellValue, double occupiedThreshold=defaultCellOccupiedThreshold)
Definition: CscSlamEngine.h:134
conscience_utils::logging
Definition: conscience_log.cpp:20
conscience_core::lidar::directions::AVAILABLE_DIRECTION_RIGHT
static const CscAvailableDirection AVAILABLE_DIRECTION_RIGHT
Definition: CscSlamEngine.h:318
conscience_core::lidar::CscSlamCellOccupancyStatus::SlamCellOccupancyStatus_Free
@ SlamCellOccupancyStatus_Free
conscience_core::lidar::CscSlamEngine::MapToImageParams::clustersTracked
vector< CscSlamEngine::PhantomClusterTracked > clustersTracked
Definition: CscSlamEngine.h:117
conscience_core::lidar::directions::saveScanWithBestDirectionAsPng
void saveScanWithBestDirectionAsPng(const mrpt::obs::CObservation2DRangeScan &scan, double bestYaw, const std::string &bestDirName, const fs::path &filename, double robotWidth, double robotLength)
Definition: CscSlamEngine.cpp:1675
CscCommon.h
conscience_core::axiomes::CscPoint2d
Definition: Csc2dTypes.h:21
conscience_core::lidar::directions::CscAvailableDirection::relYaw
double relYaw
Definition: CscSlamEngine.h:312
conscience_core::lidar::CscSlamCellOccupancyStatus
CscSlamCellOccupancyStatus
Definition: CscSlamEngine.h:40
conscience_core::lidar::CscSlamEngine::MapToImageParams::crosses
map< TPoint2D, Vec3 > crosses
Definition: CscSlamEngine.h:107
conscience_core::lidar::CscSlamEngine::PhantomClusterTracked::cells
std::vector< std::pair< int, int > > cells
Definition: CscSlamEngine.h:62
Csc2dTypes.h
conscience_core::axiomes::CscQuaternion
Definition: Csc3dTypes.h:138
conscience_core::ai::occThreshold
const double occThreshold
Definition: CscMrptAutonomousExploration.cpp:55
conscience_core::lidar::CscSlamEngine
Definition: CscSlamEngine.h:46
conscience_core::lidar::CscSlamEngine::MapToImageParams
Definition: CscSlamEngine.h:96
conscience_core::lidar::CscSlamEngine::PhantomCluster::duplicate
bool duplicate
Definition: CscSlamEngine.h:56
conscience_core::lidar::directions::AVAILABLE_DIRECTION_BACK
static const CscAvailableDirection AVAILABLE_DIRECTION_BACK
Definition: CscSlamEngine.h:319
conscience_core::lidar::CscSlamEngine::PhantomCluster::cells
vector< pair< int, int > > cells
Definition: CscSlamEngine.h:54
conscience_core::lidar::distancePoints
double distancePoints(const TPose2D &poseA, const TPose2D &poseB)
Definition: CscSlamEngine.h:295
conscience_core::axiomes::CscPoint2dOriented
Definition: Csc2dTypes.h:165
conscience_core::lidar::CscSlamEngine::MapToImageParams::clusters
vector< CscSlamEngine::PhantomCluster > clusters
Definition: CscSlamEngine.h:116
conscience_core::lidar::CscEntityPositionManager
Definition: CscEntityPositionManager.h:44
conscience_core::axiomes::CscPoint3dOriented
Definition: Csc3dTypes.h:265
mrpt::maps
Definition: CscSlamEngine.h:19
f
double f
Definition: HybridAStar.cpp:190
conscience_core::lidar::CscSlamEngine::MapToImageParams::dots
map< TPoint2D, Vec3 > dots
Definition: CscSlamEngine.h:103
conscience_core::axiomes::CscPoint3d::z
double z
Definition: Csc3dTypes.h:33
CscEntityPositionManager.h
mrpt::slam
Definition: CscSlamEngine.h:25
ptr
std::shared_ptr< T > ptr
Definition: CscCommon.h:29
conscience_core::lidar::mrptPointToJson
string mrptPointToJson(const TPoint2D &point)
Definition: CscSlamEngine.cpp:657
conscience_core::axiomes::CscPoint3d::x
double x
Definition: Csc3dTypes.h:31