m3rsm_engine.h
Go to the documentation of this file.
1 #ifndef SLAM_CTOR_CORE_M3RSM_ENGINE_H
2 #define SLAM_CTOR_CORE_M3RSM_ENGINE_H
3 
4 #include <cmath>
5 #include <memory>
6 #include <queue>
7 #include <iostream>
8 #include <cstdlib>
9 
10 #include "../geometry_primitives.h"
11 #include "grid_scan_matcher.h"
12 
13 // Many-to-Many Multiple Resolution Scan Matching Engine based on Olson (2015).
14 
15 struct Match {
16 private: // types
18  using SPEPtr = std::shared_ptr<ScanProbabilityEstimator>;
19  using Rect = decltype(SPEParams{}.sp_analysis_area);
20 public:
21  // result
22  double prob_upper_bound; // max scan probability given the assumptions below
23  // assumptions
24  double rotation;
26  // args
28  std::shared_ptr<LaserScan2D> filtered_scan;
30  const RobotPose *pose; // owner - user of the engine
31  GridMap *map; // owner - user of the engine
32 
33  static Match invalid_match() {
34  static auto invalid_match = Match{std::numeric_limits<double>::quiet_NaN()};
35  return invalid_match;
36  }
37 
38  Match(double rot, const Rect &tdrift, SPEPtr scan_prob_est,
39  std::shared_ptr<LaserScan2D> filtered_lscan, bool is_rotated,
40  const RobotPose &robot_pose, GridMap &grid_map, bool is_root = true)
41  : rotation{rot}, translation_drift{tdrift}, spe{scan_prob_est}
42  , filtered_scan{filtered_lscan}, scan_is_prerotated{is_rotated}
43  , pose{&robot_pose}, map{&grid_map}
44  , _abs_rotation{std::abs(rotation)}
45  , _drift_amount{tdrift.hside_len() + tdrift.vside_len()} {
46 
47  Point2D avg_drift = translation_drift.center();
48 
49  auto drifted_pose = *pose;
50  if (scan_is_prerotated) {
51  drifted_pose = {pose->x + avg_drift.x, pose->y + avg_drift.y, 0};
52  } else {
53  drifted_pose += RobotPoseDelta{avg_drift.x, avg_drift.y, rotation};
54  }
55  if (scan_is_prerotated && is_root) { filter_prerotated_scan(); }
56  map->rescale(translation_drift.side()); // FIXME: non-squared areas handling
57  prob_upper_bound = spe->estimate_scan_probability(
58  *filtered_scan, drifted_pose, *map,
59  SPEParams{translation_drift, scan_is_prerotated});
60  }
61 
62  Match(const Rect &tdrift, const Match &that)
63  : Match(that.rotation, tdrift, that.spe, that.filtered_scan,
64  that.scan_is_prerotated, *that.pose, *that.map, false) {}
65 
66  bool is_valid() const { return !std::isnan(prob_upper_bound); }
67  double is_finest(double threashold = 0) const {
68  return _drift_amount <= threashold;
69  }
70 
71  // returns true if the matching is _less_ prepefable than a given one
72  bool operator<(const Match &that) const {
73  if (!are_equal(prob_upper_bound, that.prob_upper_bound)) {
74  // greater is "better" -> correctness
75  return less(prob_upper_bound, that.prob_upper_bound);
76  }
78  // finer is "better" -> speed up
79  return _drift_amount > that._drift_amount;
80  }
81  // smaller is "better" -> fixes "blindness" of SPE
82  return _abs_rotation > that._abs_rotation;
83  }
84 
85 private: // methods
86  Match(double prob) : prob_upper_bound{prob} {}
87 
89  return;
90  /*
91  GridMap::Coord curr_area_id;
92  auto points_in_area = std::vector<ScanPoint2D>{};
93 
94  map->rescale(0);
95  auto scan = filtered_scan;
96  auto filtered_pts = std::vector<ScanPoint2D>{};
97  for (const auto &sp : scan->points()) {
98  auto world_point = sp.move_origin(pose->x, pose->y);
99  auto area_id = map->world_to_cell(world_point);
100 
101  if (points_in_area.size() == 0 || area_id == curr_area_id) {
102  curr_area_id = area_id;
103  points_in_area.push_back(sp);
104  } else {
105  auto effective_sp = points_in_area[0].set_factor(points_in_area.size());
106  filtered_pts.push_back(effective_sp);
107  //std::cout << points_in_area.size() << std::endl;
108  curr_area_id = area_id;
109  points_in_area.clear();
110  }
111  }
112  if (points_in_area.size()) {
113  auto effective_sp = points_in_area[0].set_factor(points_in_area.size());
114  filtered_pts.push_back(effective_sp);
115  }
116  //std::cout << scan->points().size() << " -> " << filtered_pts.size() << std::endl;
117  scan->points() = std::move(filtered_pts);
118  */
119  }
120 
121 private: // fields
123 };
124 
125 std::ostream& operator<<(std::ostream &os, const Match &match) {
126  return os << "[" << rad2deg(match.rotation) << "]"
127  << " + " << match.translation_drift
128  << " -> " << match.prob_upper_bound;
129 }
130 
131 
132 class M3RSMEngine {
133 private: // types
134  using Matches = std::priority_queue<Match>;
136 public: // types
137  using Rect = decltype(SPEParams{}.sp_analysis_area);
138 public:
139 
140  M3RSMEngine(double max_finest_prob_diff = 0)
141  : _max_finest_prob_diff{max_finest_prob_diff} {
142  reset_engine_state();
143  }
144 
146  _matches = Matches{};
147  _best_finest_probability = 0.0;
148  }
149 
150  void set_translation_lookup_range(double max_x_error, double max_y_error) {
151  _max_x_error = max_x_error;
152  _max_y_error = max_y_error;
153  }
154 
155  void set_rotation_lookup_range(double sector, double step) {
156  _rotation_sector = sector;
157  _rotation_resolution = step;
158  }
159 
160  void add_match(Match&& match) {
161  double match_prob = match.prob_upper_bound;
162  if (match_prob < _best_finest_probability) { return; }
163 
164  if (match.is_finest()) {
165  _best_finest_probability = std::max(_best_finest_probability,
166  match_prob - _max_finest_prob_diff);
167  }
168  _matches.push(std::move(match));
169  }
170 
171  void add_scan_matching_request(std::shared_ptr<ScanProbabilityEstimator> spe,
172  const RobotPose &pose,
173  const LaserScan2D &raw_scan, GridMap &map,
174  bool prerotate_scan = false) {
175  // generate pose translation ranges to be checked
176  const auto empty_trs_range = Rect{0, 0, 0, 0};
177  const auto entire_trs_range = Rect{-_max_y_error, _max_y_error,
178  -_max_x_error, _max_x_error};
179 
180  double rotation_drift = 0;
181  auto fscan = std::make_shared<LaserScan2D>(spe->filter_scan(raw_scan, pose,
182  map));
183  auto rotation_resolution = _rotation_resolution;
184  while (less_or_equal(2 * rotation_drift, _rotation_sector)) {
185  for (auto &rot : std::set<double>{rotation_drift, -rotation_drift}) {
186  auto scan = prerotate_scan ?
187  std::make_shared<LaserScan2D>(fscan->to_cartesian(rot + pose.theta))
188  : fscan;
189  add_match(Match{rot, empty_trs_range, spe,
190  scan, prerotate_scan, pose, map});
191  add_match(Match{rot, entire_trs_range, spe,
192  scan, prerotate_scan, pose, map});
193  }
194  rotation_drift += rotation_resolution;
195  }
196  }
197 
198  Match next_best_match(double translation_step) {
199  while (!_matches.empty()) {
200  auto best_match = _matches.top();
201  _matches.pop();
202  auto coarse_drift = best_match.translation_drift;
203  auto should_branch_horz = less(translation_step,
204  coarse_drift.hside_len());
205  auto should_branch_vert = less(translation_step,
206  coarse_drift.vside_len());
207  if (!should_branch_horz && !should_branch_vert) {
208  return best_match;
209  }
210  branch(best_match, should_branch_horz, should_branch_vert);
211  }
212  return Match::invalid_match();
213  }
214 
215 private:
216 
217  void branch(const Match &coarse_match, bool is_horz, bool is_vert) {
218  auto coarse_drift = coarse_match.translation_drift;
219  auto finer_drifts = std::vector<Rect>{};
220 
221  if (is_horz && is_vert) {
222  finer_drifts = coarse_drift.split4_evenly();
223  } else if (is_horz) {
224  finer_drifts = coarse_drift.split_horz();
225  } else if (is_vert) {
226  finer_drifts = coarse_drift.split_vert();
227  }
228 
229  // update matches with finer ones
230  for (auto& finer_drift : finer_drifts) {
231  auto finer_match = Match{finer_drift, coarse_match};
232  assert(less_or_equal(finer_match.prob_upper_bound,
233  coarse_match.prob_upper_bound) &&
234  "BUG: Bounding assumption is violated");
235  add_match(std::move(finer_match));
236  }
237  }
238 
239 private:
241  std::priority_queue<Match> _matches;
243  double _max_x_error, _max_y_error;
244  double _rotation_sector, _rotation_resolution;
245 };
246 
247 #endif
Rect translation_drift
Definition: m3rsm_engine.h:25
bool scan_is_prerotated
Definition: m3rsm_engine.h:29
void branch(const Match &coarse_match, bool is_horz, bool is_vert)
Definition: m3rsm_engine.h:217
void set_translation_lookup_range(double max_x_error, double max_y_error)
Definition: m3rsm_engine.h:150
CONSTEXPR bool are_equal(const T &a, const T &b, const T &eps)
Definition: math_utils.h:17
double theta
Definition: robot_pose.h:131
GridMap * map
Definition: m3rsm_engine.h:31
static Match invalid_match()
Definition: m3rsm_engine.h:33
void set_rotation_lookup_range(double sector, double step)
Definition: m3rsm_engine.h:155
M3RSMEngine(double max_finest_prob_diff=0)
Definition: m3rsm_engine.h:140
Match next_best_match(double translation_step)
Definition: m3rsm_engine.h:198
double _max_y_error
Definition: m3rsm_engine.h:243
std::priority_queue< Match > _matches
Definition: m3rsm_engine.h:241
std::priority_queue< Match > Matches
Definition: m3rsm_engine.h:134
double prob_upper_bound
Definition: m3rsm_engine.h:22
std::shared_ptr< ScanProbabilityEstimator > SPEPtr
Definition: m3rsm_engine.h:18
Match(double rot, const Rect &tdrift, SPEPtr scan_prob_est, std::shared_ptr< LaserScan2D > filtered_lscan, bool is_rotated, const RobotPose &robot_pose, GridMap &grid_map, bool is_root=true)
Definition: m3rsm_engine.h:38
SPEPtr spe
Definition: m3rsm_engine.h:27
void add_match(Match &&match)
Definition: m3rsm_engine.h:160
double rotation
Definition: m3rsm_engine.h:24
std::ostream & operator<<(std::ostream &os, const Match &match)
Definition: m3rsm_engine.h:125
double is_finest(double threashold=0) const
Definition: m3rsm_engine.h:67
double _drift_amount
Definition: m3rsm_engine.h:122
constexpr double rad2deg(double angle_rad)
Definition: math_utils.h:60
void filter_prerotated_scan()
Definition: m3rsm_engine.h:88
decltype(SPEParams{}.sp_analysis_area) Rect
Definition: m3rsm_engine.h:137
bool less_or_equal(double a, double b)
Definition: math_utils.h:44
double _rotation_sector
Definition: m3rsm_engine.h:244
void add_scan_matching_request(std::shared_ptr< ScanProbabilityEstimator > spe, const RobotPose &pose, const LaserScan2D &raw_scan, GridMap &map, bool prerotate_scan=false)
Definition: m3rsm_engine.h:171
CONSTEXPR bool less(double a, double b)
Definition: math_utils.h:29
double y
Definition: robot_pose.h:131
decltype(SPEParams{}.sp_analysis_area) Rect
Definition: m3rsm_engine.h:19
bool operator<(const Match &that) const
Definition: m3rsm_engine.h:72
void reset_engine_state()
Definition: m3rsm_engine.h:145
Match(double prob)
Definition: m3rsm_engine.h:86
std::shared_ptr< LaserScan2D > filtered_scan
Definition: m3rsm_engine.h:28
virtual void rescale(double)
double _best_finest_probability
Definition: m3rsm_engine.h:242
bool is_valid() const
Definition: m3rsm_engine.h:66
double _max_finest_prob_diff
Definition: m3rsm_engine.h:240
double x
Definition: robot_pose.h:131
double _abs_rotation
Definition: m3rsm_engine.h:122
const RobotPose * pose
Definition: m3rsm_engine.h:30
Match(const Rect &tdrift, const Match &that)
Definition: m3rsm_engine.h:62


slam_constructor
Author(s): JetBrains Research, OSLL team
autogenerated on Mon Jun 10 2019 15:08:25