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 std::shared_ptr<const WorldIDF>
79 world_idf_;
80 double time_step_dist_ = 0;
81 double sensor_area_ = 0;
82
83 // Gets the sensor data from world IDF at the global_current_position_ and
84 // updates robot_map_
85 void UpdateSensorView() {
86 sensor_view_ = MapType::Zero(params_.pSensorSize, params_.pSensorSize);
87 if (MapUtils::IsPointOutsideBoundary(
88 params_.pResolution, global_current_position_, params_.pSensorSize,
89 params_.pWorldMapSize)) {
90 return;
91 }
92 world_idf_->GetSubWorldMap(global_current_position_, params_.pSensorSize,
93 sensor_view_);
94 }
95
96 void UpdateRobotMap() {
97 MapUtils::MapBounds index, offset;
98 MapUtils::ComputeOffsets(params_.pResolution, global_current_position_,
99 params_.pSensorSize, params_.pWorldMapSize, index,
100 offset);
101 robot_map_.block(index.left + offset.left, index.bottom + offset.bottom,
102 offset.width, offset.height) =
103 sensor_view_.block(offset.left, offset.bottom, offset.width,
104 offset.height);
105 }
106
107 void UpdateExplorationMap() {
108 if (MapUtils::IsPointOutsideBoundary(
109 params_.pResolution, global_current_position_, params_.pSensorSize,
110 params_.pWorldMapSize)) {
111 return;
112 }
113 MapUtils::MapBounds index, offset;
114 MapUtils::ComputeOffsets(params_.pResolution, global_current_position_,
115 params_.pSensorSize, params_.pWorldMapSize, index,
116 offset);
117 exploration_map_.block(
118 index.left + offset.left, index.bottom + offset.bottom, offset.width,
119 offset.height) = MapType::Zero(offset.width, offset.height);
120 }
121
122 public:
130 RobotModel(Parameters const &params, Point2 const &global_start_position,
131 WorldIDF const &world_idf)
132 : params_{params}, global_start_position_{global_start_position} {
133 world_idf_ = std::make_shared<const WorldIDF>(world_idf);
134 normalization_factor_ = world_idf_->GetNormalizationFactor();
135 global_current_position_ = global_start_position_;
136
137 sensor_view_ = MapType::Zero(params_.pSensorSize, params_.pSensorSize);
138 local_map_ = MapType::Zero(params_.pLocalMapSize, params_.pLocalMapSize);
139 obstacle_map_ = MapType::Zero(params_.pLocalMapSize, params_.pLocalMapSize);
140
141 local_start_position_ = Point2{0, 0};
142 local_current_position_ = local_start_position_;
143
144 ClearRobotMap();
145
146 if (params_.pUpdateExplorationMap == true) {
147 exploration_map_ =
148 MapType::Constant(params_.pRobotMapSize, params_.pRobotMapSize, 1);
149 local_exploration_map_ =
150 MapType::Constant(params_.pRobotMapSize, params_.pRobotMapSize, 1);
151 UpdateExplorationMap();
152 } else {
153 exploration_map_ =
154 MapType::Constant(params_.pRobotMapSize, params_.pRobotMapSize, 0);
155 local_exploration_map_ =
156 MapType::Constant(params_.pRobotMapSize, params_.pRobotMapSize, 0);
157 }
158
159 time_step_dist_ =
160 params_.pMaxRobotSpeed * params_.pTimeStep * params_.pResolution;
161 sensor_area_ = params_.pSensorSize * params_.pSensorSize;
162 }
163
164 void ClearRobotMap() {
165 if (params_.pRobotMapUseUnknownImportance == true) {
166 robot_map_ =
167 MapType::Constant(params_.pRobotMapSize, params_.pRobotMapSize,
168 params_.pUnknownImportance * params_.pNorm);
169 } else {
170 robot_map_ = MapType::Zero(params_.pRobotMapSize, params_.pRobotMapSize);
171 }
172
173 if (params_.pUpdateSensorView == true) {
174 UpdateSensorView();
175 }
176 if (params_.pUpdateRobotMap == false) {
177 robot_map_ = world_idf_->GetWorldMap();
178 } else {
179 UpdateRobotMap();
180 }
181 }
182
186 int StepControl(Point2 const &direction, double const &speed) {
187 auto dir = direction;
188 auto sp = speed;
189 Point2 new_pos = local_current_position_;
190 if (sp > params_.pMaxRobotSpeed) {
191 sp = params_.pMaxRobotSpeed;
192 }
193 bool invalid_dir = dir.norm() < kEps and sp >= kEps;
194 if (sp < 0 or invalid_dir) {
195 std::cout << sp << " " << dir.norm() << std::endl;
196 std::cerr << "Speed needs to be non-negative\n";
197 std::cerr << "Zero-vector direction cannot be given in control\n";
198 std::throw_with_nested(
199 std::runtime_error("Speed needs to be non-negative"));
200 return 1;
201 }
202 /* if (dir.normalize() and sp > kEps) { */
203 /* std::cerr << "Zero-vector direction given in control\n"; */
204 /* return 1; */
205 /* } */
206 dir.normalize();
207 if (sp > kEps) {
208 new_pos = local_current_position_ + dir * sp * params_.pTimeStep;
209 }
210 SetRobotPosition(new_pos);
211 return 0;
212 }
213
215 void SetRobotPosition(Point2 const &pos) {
216 Point2 new_global_pos = pos + global_start_position_;
217 if (new_global_pos.x() <= 0) {
218 new_global_pos[0] = 0 + kLargeEps;
219 }
220 if (new_global_pos.y() <= 0) {
221 new_global_pos[1] = 0 + kLargeEps;
222 }
223 double max_xy = params_.pWorldMapSize * params_.pResolution;
224 if (new_global_pos.x() >= max_xy) {
225 new_global_pos[0] = max_xy - kLargeEps;
226 }
227 if (new_global_pos.y() >= max_xy) {
228 new_global_pos[1] = max_xy - kLargeEps;
229 }
230
231 local_current_position_ = new_global_pos - global_start_position_;
232 global_current_position_ = new_global_pos;
233 if (params_.pUpdateSensorView == true) {
234 UpdateSensorView();
235 }
236 if (params_.pUpdateRobotMap == true) {
237 UpdateRobotMap();
238 }
239 if (params_.pUpdateExplorationMap == true) {
240 UpdateExplorationMap();
241 }
242 }
243
244 void SetGlobalRobotPosition(Point2 const &pos) {
245 Point2 new_global_pos = pos;
246 if (new_global_pos.x() <= 0) {
247 new_global_pos[0] = 0 + kLargeEps;
248 }
249 if (new_global_pos.y() <= 0) {
250 new_global_pos[1] = 0 + kLargeEps;
251 }
252 double max_xy = params_.pWorldMapSize * params_.pResolution;
253 if (new_global_pos.x() >= max_xy) {
254 new_global_pos[0] = max_xy - kLargeEps;
255 }
256 if (new_global_pos.y() >= max_xy) {
257 new_global_pos[1] = max_xy - kLargeEps;
258 }
259
260 local_current_position_ = new_global_pos - global_start_position_;
261 global_current_position_ = new_global_pos;
262 if (params_.pUpdateSensorView == true) {
263 UpdateSensorView();
264 }
265 if (params_.pUpdateRobotMap == true) {
266 UpdateRobotMap();
267 }
268 if (params_.pUpdateExplorationMap == true) {
269 UpdateExplorationMap();
270 }
271 }
272
273 Point2 GetGlobalStartPosition() const { return global_start_position_; }
274 Point2 GetGlobalCurrentPosition() const { return global_current_position_; }
275
276 const MapType &GetRobotMap() const { return robot_map_; }
277 const MapType &GetSensorView() const { return sensor_view_; }
278
279 const MapType &GetRobotSystemMap() {
280 GetRobotLocalMap();
281 GetExplorationMap();
282 system_map_ = local_map_ - local_exploration_map_;
283 return system_map_;
284 }
285
286 const MapType &GetRobotLocalMap() {
287 /* local_map_ = MapType::Constant(params_.pLocalMapSize,
288 * params_.pLocalMapSize, -1.0); */
289 local_map_ =
290 MapType::Constant(params_.pLocalMapSize, params_.pLocalMapSize, 0.);
291 if (not MapUtils::IsPointOutsideBoundary(
292 params_.pResolution, global_current_position_,
293 params_.pLocalMapSize, params_.pWorldMapSize)) {
294 MapUtils::GetSubMap(params_.pResolution, global_current_position_,
295 params_.pRobotMapSize, robot_map_,
296 params_.pLocalMapSize, local_map_);
297 }
298 return local_map_;
299 }
300
301 const MapType &GetExplorationMap() {
302 /* local_exploration_map_ = MapType::Constant(params_.pLocalMapSize,
303 * params_.pLocalMapSize, 0); */
304 local_exploration_map_ =
305 MapType::Constant(params_.pLocalMapSize, params_.pLocalMapSize, -1.0);
306 if (not MapUtils::IsPointOutsideBoundary(
307 params_.pResolution, global_current_position_,
308 params_.pLocalMapSize, params_.pWorldMapSize)) {
309 MapUtils::GetSubMap(params_.pResolution, global_current_position_,
310 params_.pRobotMapSize, exploration_map_,
311 params_.pLocalMapSize, local_exploration_map_);
312 }
313 return local_exploration_map_;
314 }
315
316 const MapType &GetObstacleMap() {
317 obstacle_map_ = MapType::Ones(params_.pLocalMapSize, params_.pLocalMapSize);
318 MapUtils::MapBounds index, offset;
319 ComputeOffsets(params_.pResolution, global_current_position_,
320 params_.pLocalMapSize, params_.pRobotMapSize, index, offset);
321 obstacle_map_.block(offset.left, offset.bottom, offset.width,
322 offset.height) =
323 MapType::Zero(offset.width, offset.height);
324 return obstacle_map_;
325 }
326
327 auto GetExplorationFeatures() {
328 queue_t frontiers;
329 Point2 const &pos = global_current_position_;
330
331 double factor = 4;
332 double pos_x_lim = std::min(pos[0] + factor * time_step_dist_,
333 static_cast<double>(params_.pWorldMapSize));
334 double pos_y_lim = std::min(pos[1] + factor * time_step_dist_,
335 static_cast<double>(params_.pWorldMapSize));
336 for (double pos_x = std::max(pos[0] - factor * time_step_dist_, kLargeEps);
337 pos_x < pos_x_lim; pos_x += 1 * params_.pResolution) {
338 for (double pos_y =
339 std::max(pos[1] - factor * time_step_dist_, kLargeEps);
340 pos_y < pos_y_lim; pos_y += 1 * params_.pResolution) {
341 Point2 qpos{pos_x, pos_y};
342 double dist = (qpos - pos).norm();
343 dist = std::max(dist, time_step_dist_);
344 MapUtils::MapBounds index, offset;
345 MapUtils::ComputeOffsets(params_.pResolution, qpos, params_.pSensorSize,
346 params_.pWorldMapSize, index, offset);
347 double unexplored =
348 exploration_map_
349 .block(index.left + offset.left, index.bottom + offset.bottom,
350 offset.width, offset.height)
351 .sum();
352 double benefit = unexplored;
353 if (unexplored > 0.1 * sensor_area_) {
354 double idf_value =
355 robot_map_
356 .block(index.left + offset.left, index.bottom + offset.bottom,
357 offset.width, offset.height)
358 .count();
359 benefit += 2 * idf_value;
360 }
361 double bcr = benefit / dist;
362
363 if (frontiers.size() < size_t(params_.pNumFrontiers)) {
364 frontiers.push(Frontier(qpos, bcr));
365 } else {
366 auto worst_frontier = frontiers.top();
367 if (worst_frontier.value < bcr) {
368 frontiers.pop();
369 frontiers.push(Frontier(qpos, bcr));
370 }
371 }
372 }
373 }
374 std::vector<double> frontier_features(params_.pNumFrontiers * 2);
375 int count = 0;
376 while (!frontiers.empty()) {
377 auto point = frontiers.top();
378 frontier_features[count++] = point.pt[0] - pos[0];
379 frontier_features[count++] = point.pt[1] - pos[1];
380 frontiers.pop();
381 }
382 return frontier_features;
383 }
384
385 /* The centroid is computed with orgin of the map, i.e., the lower left corner
386 * of the map. */
387 /* Only the local map is considered for the computation of the centroid. */
388 auto GetVoronoiFeatures() {
389 auto const &pos = global_current_position_;
390 MapUtils::MapBounds index, offset;
392 params_.pWorldMapSize, index, offset);
393 auto trimmed_local_map =
394 robot_map_.block(index.left + offset.left, index.bottom + offset.bottom,
395 offset.width, offset.height);
396
397 Point2 map_size(offset.width, offset.height);
398 Point2 map_translation(
399 (index.left + offset.left) * params_.pResolution,
400 (index.bottom + offset.bottom) * params_.pResolution);
401
402 PointVector robot_positions(1);
403 robot_positions[0] = pos - map_translation;
404 Voronoi voronoi(robot_positions, trimmed_local_map, map_size,
405 params_.pResolution, true, 0);
406 auto vcell = voronoi.GetVoronoiCell();
407 /* vcell.centroid += Point2(params_.pLocalMapSize / 2.,
408 * params_.pLocalMapSize / 2.); */
409 return vcell.GetFeatureVector();
410 }
411};
412
413} /* namespace CoverageControl */
414#endif // CPPSRC_CORE_INCLUDE_COVERAGECONTROL_ROBOT_MODEL_H_
Class to store parameters.
Definition parameters.h:50
int pRobotMapSize
Robot map saves what the robot has seen.
Definition parameters.h:85
double pTimeStep
Each time step corresponds to pTimeStep seconds.
Definition parameters.h:141
Class for handling the robot model.
Definition robot_model.h:61
void SetRobotPosition(Point2 const &pos)
Set robot position relative to the current position.
int StepControl(Point2 const &direction, double const &speed)
RobotModel(Parameters const &params, Point2 const &global_start_position, WorldIDF const &world_idf)
Constructor for the robot model.
Class for Importance Density Function (IDF) for the world.
Definition world_idf.h:66
Constants for the CoverageControl library.
double const kEps
Definition constants.h:49
double const kLargeEps
Definition constants.h:51
Eigen::Matrix< float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > MapType
Definition typedefs.h:48
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.
void ComputeOffsets(double const resolution, Point2 const &pos, int const submap_size, int const map_size, MapBounds &index, MapBounds &offset)
Definition map_utils.h:57
Namespace for the CoverageControl library.
Contains parameters.
Contains typedefs for the library.
Class for computing Voronoi cells.
Contains the class for Importance Density Function (IDF) for the world.