Coverage Control Library
Loading...
Searching...
No Matches
robot_model.h
Go to the documentation of this file.
1/*
2 * This file is part of the CoverageControl library
3 *
4 * Author: Saurav Agarwal
5 * Contact: sauravag@seas.upenn.edu, agr.saurav1@gmail.com
6 * Repository: https://github.com/KumarRobotics/CoverageControl
7 *
8 * Copyright (c) 2024, Saurav Agarwal
9 *
10 * The CoverageControl library is free software: you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or (at your
13 * option) any later version.
14 *
15 * The CoverageControl library is distributed in the hope that it will be
16 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
18 * Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along with
21 * CoverageControl library. If not, see <https://www.gnu.org/licenses/>.
22 */
23
33#ifndef CPPSRC_CORE_INCLUDE_COVERAGECONTROL_ROBOT_MODEL_H_
34#define CPPSRC_CORE_INCLUDE_COVERAGECONTROL_ROBOT_MODEL_H_
35
36#include <algorithm>
37#include <cmath>
38#include <iostream>
39#include <memory>
40#include <vector>
41
48
49namespace CoverageControl {
50
62 private:
63 Parameters const params_;
64
65 Point2 global_start_position_, global_current_position_;
66 Point2 local_start_position_, local_current_position_;
67 double normalization_factor_ = 0;
68
69 MapType robot_map_;
71 MapType sensor_view_;
72 MapType local_map_;
73 MapType obstacle_map_;
74 MapType system_map_;
76 local_exploration_map_;
77 MapType exploration_map_;
78 double time_step_dist_ = 0;
79 double sensor_area_ = 0;
80
81 std::shared_ptr<const WorldIDF>
82 world_idf_;
83 // const WorldIDF *world_idf_; //!< Robots cannot change the world
84
85 // Gets the sensor data from world IDF at the global_current_position_ and
86 // updates robot_map_
87 void UpdateSensorView() {
88 sensor_view_ = MapType::Zero(params_.pSensorSize, params_.pSensorSize);
90 params_.pResolution, global_current_position_, params_.pSensorSize,
91 params_.pWorldMapSize)) {
92 return;
93 }
94 world_idf_->GetSubWorldMap(global_current_position_, params_.pSensorSize,
95 sensor_view_);
96 }
97
98 void UpdateRobotMap() {
99 MapUtils::MapBounds index, offset;
100 MapUtils::ComputeOffsets(params_.pResolution, global_current_position_,
101 params_.pSensorSize, params_.pWorldMapSize, index,
102 offset);
103 robot_map_.block(index.left + offset.left, index.bottom + offset.bottom,
104 offset.width, offset.height) =
105 sensor_view_.block(offset.left, offset.bottom, offset.width,
106 offset.height);
107 }
108
109 void UpdateExplorationMap() {
111 params_.pResolution, global_current_position_, params_.pSensorSize,
112 params_.pWorldMapSize)) {
113 return;
114 }
115 MapUtils::MapBounds index, offset;
116 MapUtils::ComputeOffsets(params_.pResolution, global_current_position_,
117 params_.pSensorSize, params_.pWorldMapSize, index,
118 offset);
119 exploration_map_.block(
120 index.left + offset.left, index.bottom + offset.bottom, offset.width,
121 offset.height) = MapType::Zero(offset.width, offset.height);
122 }
123
124 void Initialize() {
125 normalization_factor_ = world_idf_->GetNormalizationFactor();
126 global_current_position_ = global_start_position_;
127
128 sensor_view_ = MapType::Zero(params_.pSensorSize, params_.pSensorSize);
129 local_map_ = MapType::Zero(params_.pLocalMapSize, params_.pLocalMapSize);
130 obstacle_map_ = MapType::Zero(params_.pLocalMapSize, params_.pLocalMapSize);
131
132 local_start_position_ = Point2{0, 0};
133 local_current_position_ = local_start_position_;
134
136
137 if (params_.pUpdateExplorationMap == true) {
138 exploration_map_ =
139 MapType::Constant(params_.pRobotMapSize, params_.pRobotMapSize, 1);
140 local_exploration_map_ =
141 MapType::Constant(params_.pRobotMapSize, params_.pRobotMapSize, 1);
142 UpdateExplorationMap();
143 } else {
144 exploration_map_ =
145 MapType::Constant(params_.pRobotMapSize, params_.pRobotMapSize, 0);
146 local_exploration_map_ =
147 MapType::Constant(params_.pRobotMapSize, params_.pRobotMapSize, 0);
148 }
149
150 time_step_dist_ =
151 params_.pMaxRobotSpeed * params_.pTimeStep * params_.pResolution;
152 sensor_area_ = params_.pSensorSize * params_.pSensorSize;
153 }
154
155 public:
164 RobotModel(Parameters const &params, Point2 const &global_start_position,
165 std::shared_ptr<const WorldIDF> const &world_idf)
166 : params_{params},
167 global_start_position_{global_start_position},
168 world_idf_{world_idf} {
169 Initialize();
170 }
171
172 RobotModel(Parameters const &params, Point2 const &global_start_position,
173 WorldIDF const &world_idf)
174 : params_{params},
175 global_start_position_{global_start_position},
176 world_idf_{std::make_shared<const WorldIDF>(world_idf)} {
177 Initialize();
178 }
179
181 if (params_.pRobotMapUseUnknownImportance == true) {
182 robot_map_ =
183 MapType::Constant(params_.pRobotMapSize, params_.pRobotMapSize,
184 params_.pUnknownImportance * params_.pNorm);
185 } else {
186 robot_map_ = MapType::Zero(params_.pRobotMapSize, params_.pRobotMapSize);
187 }
188
189 if (params_.pUpdateSensorView == true) {
190 UpdateSensorView();
191 }
192 if (params_.pUpdateRobotMap == true) {
193 UpdateRobotMap();
194 }
195 }
196
200 int StepControl(Point2 const &direction, double const &speed) {
201 auto dir = direction;
202 auto sp = speed;
203 Point2 new_pos = local_current_position_;
204 if (sp > params_.pMaxRobotSpeed) {
205 sp = params_.pMaxRobotSpeed;
206 }
207 bool invalid_dir = dir.norm() < kEps and sp >= kEps;
208 if (sp < 0 or invalid_dir) {
209 std::cout << sp << " " << dir.norm() << std::endl;
210 std::cerr << "Speed needs to be non-negative\n";
211 std::cerr << "Zero-vector direction cannot be given in control\n";
212 std::throw_with_nested(
213 std::runtime_error("Speed needs to be non-negative"));
214 return 1;
215 }
216 /* if (dir.normalize() and sp > kEps) { */
217 /* std::cerr << "Zero-vector direction given in control\n"; */
218 /* return 1; */
219 /* } */
220 dir.normalize();
221 if (sp > kEps) {
222 new_pos = local_current_position_ + dir * sp * params_.pTimeStep;
223 }
224 SetRobotPosition(new_pos);
225 return 0;
226 }
227
229 void SetRobotPosition(Point2 const &pos) {
230 Point2 new_global_pos = pos + global_start_position_;
231 if (new_global_pos.x() <= 0) {
232 new_global_pos[0] = 0 + kLargeEps;
233 }
234 if (new_global_pos.y() <= 0) {
235 new_global_pos[1] = 0 + kLargeEps;
236 }
237 double max_xy = params_.pWorldMapSize * params_.pResolution;
238 if (new_global_pos.x() >= max_xy) {
239 new_global_pos[0] = max_xy - kLargeEps;
240 }
241 if (new_global_pos.y() >= max_xy) {
242 new_global_pos[1] = max_xy - kLargeEps;
243 }
244
245 local_current_position_ = new_global_pos - global_start_position_;
246 global_current_position_ = new_global_pos;
247 if (params_.pUpdateSensorView == true) {
248 UpdateSensorView();
249 }
250 if (params_.pUpdateRobotMap == true) {
251 UpdateRobotMap();
252 }
253 if (params_.pUpdateExplorationMap == true) {
254 UpdateExplorationMap();
255 }
256 }
257
259 Point2 new_global_pos = pos;
260 if (new_global_pos.x() <= 0) {
261 new_global_pos[0] = 0 + kLargeEps;
262 }
263 if (new_global_pos.y() <= 0) {
264 new_global_pos[1] = 0 + kLargeEps;
265 }
266 double max_xy = params_.pWorldMapSize * params_.pResolution;
267 if (new_global_pos.x() >= max_xy) {
268 new_global_pos[0] = max_xy - kLargeEps;
269 }
270 if (new_global_pos.y() >= max_xy) {
271 new_global_pos[1] = max_xy - kLargeEps;
272 }
273
274 local_current_position_ = new_global_pos - global_start_position_;
275 global_current_position_ = new_global_pos;
276 if (params_.pUpdateSensorView == true) {
277 UpdateSensorView();
278 }
279 if (params_.pUpdateRobotMap == true) {
280 UpdateRobotMap();
281 }
282 if (params_.pUpdateExplorationMap == true) {
283 UpdateExplorationMap();
284 }
285 }
286
287 Point2 GetGlobalStartPosition() const { return global_start_position_; }
288 Point2 GetGlobalCurrentPosition() const { return global_current_position_; }
289
290 const MapType &GetRobotMap() const { return robot_map_; }
291 const MapType &GetSensorView() const { return sensor_view_; }
292
296 system_map_ = local_map_ - local_exploration_map_;
297 return system_map_;
298 }
299
300 // const MapType &GetRobotLocalMap() {
301 /* local_map_ = MapType::Constant(params_.pLocalMapSize,
302 * params_.pLocalMapSize, -1.0); */
304 local_map_ =
305 MapType::Constant(params_.pLocalMapSize, params_.pLocalMapSize, 0.);
307 params_.pResolution, global_current_position_,
308 params_.pLocalMapSize, params_.pWorldMapSize)) {
309 MapUtils::GetSubMap(params_.pResolution, global_current_position_,
310 params_.pRobotMapSize, robot_map_,
311 params_.pLocalMapSize, local_map_);
312 }
313 }
314 MapType &GetRobotMapMutable() { return robot_map_; }
315
318 return local_map_;
319 }
320
322 /* local_exploration_map_ = MapType::Constant(params_.pLocalMapSize,
323 * params_.pLocalMapSize, 0); */
324 local_exploration_map_ =
325 MapType::Constant(params_.pLocalMapSize, params_.pLocalMapSize, -1.0);
327 params_.pResolution, global_current_position_,
328 params_.pLocalMapSize, params_.pWorldMapSize)) {
329 MapUtils::GetSubMap(params_.pResolution, global_current_position_,
330 params_.pRobotMapSize, exploration_map_,
331 params_.pLocalMapSize, local_exploration_map_);
332 }
333 return local_exploration_map_;
334 }
335
337 obstacle_map_ = MapType::Ones(params_.pLocalMapSize, params_.pLocalMapSize);
338 MapUtils::MapBounds index, offset;
339 ComputeOffsets(params_.pResolution, global_current_position_,
340 params_.pLocalMapSize, params_.pRobotMapSize, index, offset);
341 obstacle_map_.block(offset.left, offset.bottom, offset.width,
342 offset.height) =
343 MapType::Zero(offset.width, offset.height);
344 return obstacle_map_;
345 }
346
348 queue_t frontiers;
349 Point2 const &pos = global_current_position_;
350
351 double factor = 4;
352 double pos_x_lim = std::min(pos[0] + factor * time_step_dist_,
353 static_cast<double>(params_.pWorldMapSize));
354 double pos_y_lim = std::min(pos[1] + factor * time_step_dist_,
355 static_cast<double>(params_.pWorldMapSize));
356 for (double pos_x = std::max(pos[0] - factor * time_step_dist_, kLargeEps);
357 pos_x < pos_x_lim; pos_x += 1 * params_.pResolution) {
358 for (double pos_y =
359 std::max(pos[1] - factor * time_step_dist_, kLargeEps);
360 pos_y < pos_y_lim; pos_y += 1 * params_.pResolution) {
361 Point2 qpos{pos_x, pos_y};
362 double dist = (qpos - pos).norm();
363 dist = std::max(dist, time_step_dist_);
364 MapUtils::MapBounds index, offset;
365 MapUtils::ComputeOffsets(params_.pResolution, qpos, params_.pSensorSize,
366 params_.pWorldMapSize, index, offset);
367 double unexplored =
368 exploration_map_
369 .block(index.left + offset.left, index.bottom + offset.bottom,
370 offset.width, offset.height)
371 .sum();
372 double benefit = unexplored;
373 if (unexplored > 0.1 * sensor_area_) {
374 double idf_value =
375 robot_map_
376 .block(index.left + offset.left, index.bottom + offset.bottom,
377 offset.width, offset.height)
378 .count();
379 benefit += 2 * idf_value;
380 }
381 double bcr = benefit / dist;
382
383 if (frontiers.size() < size_t(params_.pNumFrontiers)) {
384 frontiers.push(Frontier(qpos, bcr));
385 } else {
386 auto worst_frontier = frontiers.top();
387 if (worst_frontier.value < bcr) {
388 frontiers.pop();
389 frontiers.push(Frontier(qpos, bcr));
390 }
391 }
392 }
393 }
394 std::vector<double> frontier_features(params_.pNumFrontiers * 2);
395 int count = 0;
396 while (!frontiers.empty()) {
397 auto point = frontiers.top();
398 frontier_features[count++] = point.pt[0] - pos[0];
399 frontier_features[count++] = point.pt[1] - pos[1];
400 frontiers.pop();
401 }
402 return frontier_features;
403 }
404
405 /* The centroid is computed with orgin of the map, i.e., the lower left corner
406 * of the map. */
407 /* Only the local map is considered for the computation of the centroid. */
409 auto const &pos = global_current_position_;
410 MapUtils::MapBounds index, offset;
412 params_.pWorldMapSize, index, offset);
413 auto trimmed_local_map =
414 robot_map_.block(index.left + offset.left, index.bottom + offset.bottom,
415 offset.width, offset.height);
416
417 Point2 map_size(offset.width, offset.height);
418 Point2 map_translation(
419 (index.left + offset.left) * params_.pResolution,
420 (index.bottom + offset.bottom) * params_.pResolution);
421
422 PointVector robot_positions(1);
423 robot_positions[0] = pos - map_translation;
424 Voronoi voronoi(robot_positions, trimmed_local_map, map_size,
425 params_.pResolution, true, 0);
426 auto vcell = voronoi.GetVoronoiCell();
427 /* vcell.centroid += Point2(params_.pLocalMapSize / 2.,
428 * params_.pLocalMapSize / 2.); */
429 return vcell.GetFeatureVector();
430 }
431};
432
433} /* namespace CoverageControl */
434#endif // CPPSRC_CORE_INCLUDE_COVERAGECONTROL_ROBOT_MODEL_H_
Class to store parameters.
Definition parameters.h:48
int pRobotMapSize
Robot map saves what the robot has seen.
Definition parameters.h:79
double pTimeStep
Each time step corresponds to pTimeStep seconds.
Definition parameters.h:140
Class for handling the robot model.
Definition robot_model.h:61
const MapType & GetObstacleMap()
void SetGlobalRobotPosition(Point2 const &pos)
Point2 GetGlobalCurrentPosition() const
const MapType & GetSensorView() const
const MapType & GetExplorationMap()
void SetRobotPosition(Point2 const &pos)
Set robot position relative to the current position.
const MapType & GetRobotMap() const
RobotModel(Parameters const &params, Point2 const &global_start_position, std::shared_ptr< const WorldIDF > const &world_idf)
Constructor for the robot model.
const MapType & GetRobotSystemMap()
int StepControl(Point2 const &direction, double const &speed)
const MapType & GetRobotLocalMap()
Point2 GetGlobalStartPosition() const
RobotModel(Parameters const &params, Point2 const &global_start_position, WorldIDF const &world_idf)
Class for computing Voronoi cells.
Definition voronoi.h:116
Class for Importance Density Function (IDF) for the world.
Definition world_idf.h:61
Constants for the CoverageControl library.
double const kEps
Definition constants.h:48
double const kLargeEps
Definition constants.h:50
Eigen::Matrix< float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > MapType
Definition typedefs.h:48
std::vector< Point2 > PointVector
Definition typedefs.h:51
Eigen::Vector2d Point2
Definition typedefs.h:44
std::priority_queue< Frontier, std::vector< Frontier >, FrontierCompare > queue_t
Definition typedefs.h:86
Utility functions for transforming maps.
int IsPointOutsideBoundary(double const resolution, Point2 const &pos, int const sensor_size, int const boundary)
Definition map_utils.h:140
void GetSubMap(double const resolution, Point2 const &pos, int const map_size, T const &map, int const submap_size, T &submap)
Definition map_utils.h:89
void ComputeOffsets(double const resolution, Point2 const &pos, int const submap_size, int const map_size, MapBounds &index, MapBounds &offset)
Definition map_utils.h:59
Namespace for the CoverageControl library.
Contains parameters.
A struct to store a frontier points and a value.
Definition typedefs.h:69
Contains typedefs for the library.
Class for computing Voronoi cells.
Contains the class for Importance Density Function (IDF) for the world.