Coverage Control Library
Loading...
Searching...
No Matches
coverage_system.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
30#ifndef CPPSRC_CORE_INCLUDE_COVERAGECONTROL_COVERAGE_SYSTEM_H_
31#define CPPSRC_CORE_INCLUDE_COVERAGECONTROL_COVERAGE_SYSTEM_H_
32
33#define EIGEN_NO_CUDA // Don't use eigen's cuda facility
34#include <omp.h>
35
36#include <Eigen/Dense> // Eigen is used for maps
37#include <algorithm>
38#include <iostream>
39#include <list>
40#include <mutex>
41#include <random>
42#include <string>
43#include <utility>
44#include <vector>
45
55
56namespace CoverageControl {
57
67 Parameters const params_;
68 std::shared_ptr <WorldIDF> world_idf_ptr_;
69 size_t num_robots_ = 0;
70 std::vector<RobotModel> robots_;
71 double normalization_factor_ = 0;
72 Voronoi voronoi_;
73 std::vector<VoronoiCell> voronoi_cells_;
74 mutable std::random_device
75 rd_;
76 mutable std::mt19937 gen_;
77 mutable std::mutex mutex_;
78 std::uniform_real_distribution<>
79 distrib_pts_;
80 PointVector robot_global_positions_;
82 system_map_;
84 exploration_map_;
86 explored_idf_map_;
87 std::vector<std::list<Point2>>
88 robot_positions_history_;
89 double exploration_ratio_ = 0;
90 double weighted_exploration_ratio_ =
91 0;
92 double total_idf_weight_ = 0;
93 std::vector<PlotterData> plotter_data_;
94 std::vector<std::vector<Point2>>
95 relative_positions_neighbors_;
97 std::vector<std::vector<int>>
98 neighbor_ids_;
99
101 void InitSetup();
102
104 void UpdateSystemMap() {
105 // This is not necessarily thread safe. Do NOT parallelize this for loop
106 for (size_t i = 0; i < num_robots_; ++i) {
107 MapUtils::MapBounds index, offset;
108 MapUtils::ComputeOffsets(params_.pResolution, robot_global_positions_[i],
109 params_.pSensorSize, params_.pWorldMapSize,
110 index, offset);
111 explored_idf_map_.block(index.left + offset.left,
112 index.bottom + offset.bottom, offset.width,
113 offset.height) =
114 GetRobotSensorView(i).block(offset.left, offset.bottom, offset.width,
115 offset.height);
116 exploration_map_.block(
117 index.left + offset.left, index.bottom + offset.bottom, offset.width,
118 offset.height) = MapType::Zero(offset.width, offset.height);
119 }
120 system_map_ = explored_idf_map_ - exploration_map_;
121 /* exploration_ratio_ = 1.0 -
122 * (double)(exploration_map_.sum())/(params_.pWorldMapSize *
123 * params_.pWorldMapSize); */
124 /* weighted_exploration_ratio_ =
125 * (double)(explored_idf_map_.sum())/(total_idf_weight_); */
126 /* std::cout << "Exploration: " << exploration_ratio_ << " Weighted: " <<
127 * weighted_exploration_ratio_ << std::endl; */
128 /* std::cout << "Diff: " << (exploration_map_.count() -
129 * exploration_map_.sum()) << std::endl; */
130 }
131
134 void PostStepCommands(size_t robot_id);
135
139 void PostStepCommands();
140
142 void ComputeAdjacencyMatrix();
143
145 void UpdateRobotPositions() {
146 for (size_t iRobot = 0; iRobot < num_robots_; ++iRobot) {
147 robot_global_positions_[iRobot] =
148 robots_[iRobot].GetGlobalCurrentPosition();
149 }
150 }
151
153 void UpdateNeighbors();
154
155 public:
158
160 CoverageSystem() = delete;
161
167 explicit CoverageSystem(Parameters const &params);
168
176 CoverageSystem(Parameters const &params, int const num_gaussians,
177 int const num_robots);
178
179 CoverageSystem(Parameters const &params, int const num_gaussians,
180 int const num_polygons, int const num_robots);
181
189 CoverageSystem(Parameters const &params, WorldIDF const &world_idf,
190 std::string const &pos_file_name);
191
198 CoverageSystem(Parameters const &params, WorldIDF const &world_idf,
199 std::vector<Point2> const &robot_positions);
200
207 CoverageSystem(Parameters const &params,
208 std::vector<BivariateNormalDistribution> const &dists,
209 std::vector<Point2> const &robot_positions);
210
212
215
218 void SetLocalRobotPositions(std::vector<Point2> const &relative_pos) {
219 SetRobotPositions(relative_pos);
220 }
221
223 void SetLocalRobotPosition(size_t const robot_id,
224 Point2 const &relative_pos) {
225 robots_[robot_id].SetRobotPosition(relative_pos);
226 PostStepCommands(robot_id);
227 }
228
230 void SetGlobalRobotPosition(size_t const robot_id, Point2 const &global_pos) {
231 robots_[robot_id].SetGlobalRobotPosition(global_pos);
232 PostStepCommands(robot_id);
233 }
234 //
236 void SetGlobalRobotPositions(PointVector const &global_positions) {
237 if (global_positions.size() != num_robots_) {
238 throw std::length_error{
239 "The size of the positions don't match with the number of robots"};
240 }
241 for (size_t i = 0; i < num_robots_; ++i) {
242 robots_[i].SetGlobalRobotPosition(global_positions[i]);
243 }
244 PostStepCommands();
245 }
246
249 void SetRobotPositions(std::vector<Point2> const &positions) {
250 if (positions.size() != num_robots_) {
251 throw std::length_error{
252 "The size of the positions don't match with the number of robots"};
253 }
254 for (size_t i = 0; i < num_robots_; ++i) {
255 robots_[i].SetRobotPosition(positions[i]);
256 }
257 PostStepCommands();
258 }
259
261 void SetWorldIDF(WorldIDF const &world_idf) {
262 world_idf_ptr_.reset(new WorldIDF{world_idf});
263 normalization_factor_ = world_idf_ptr_->GetNormalizationFactor();
264 }
266
269
279 [[nodiscard]] bool StepActions(PointVector const &actions) {
280 for (size_t iRobot = 0; iRobot < num_robots_; ++iRobot) {
281 Point2 action = actions[iRobot];
282 double speed = action.norm();
283 Point2 direction = action.normalized();
284 if (robots_[iRobot].StepControl(direction, speed)) {
285 std::cerr << "Control incorrect\n";
286 return 1;
287 }
288 }
289 PostStepCommands();
290 return 0;
291 }
292
303 [[nodiscard]] bool StepAction(size_t const robot_id, Point2 const action) {
304 double speed = action.norm();
305 Point2 direction = action.normalized();
306 if (robots_[robot_id].StepControl(direction, speed)) {
307 std::cerr << "Control incorrect\n";
308 return 1;
309 }
310 PostStepCommands();
311 return 0;
312 }
313
325 [[nodiscard]] bool StepControl(size_t robot_id, Point2 const &direction,
326 double const speed) {
327 if (robots_[robot_id].StepControl(direction, speed)) {
328 std::cerr << "Control incorrect\n";
329 return 1;
330 }
331 PostStepCommands();
332 return 0;
333 }
334
336 Point2 AddNoise(Point2 const pt) const;
337
341 bool CheckOscillation(size_t const robot_id) const {
342 if (params_.pCheckOscillations == false) {
343 return false;
344 }
345 if (robot_positions_history_[robot_id].size() < 3) {
346 return false;
347 }
348 auto const &history = robot_positions_history_[robot_id];
349 Point2 const last_pos = history.back();
350 auto it_end = std::next(history.crbegin(), std::min(6, static_cast<int>(history.size()) - 1));
351 bool flag = false;
352 int count = 0;
353 std::for_each(history.crbegin(), it_end,
354 [last_pos, &count](Point2 const &pt) {
355 if ((pt - last_pos).norm() < kLargeEps) {
356 ++count;
357 }
358 });
359 if (count > 2) {
360 flag = true;
361 }
362 return flag;
363 }
364
365 void CheckRobotID(size_t const id) const {
366 if (id >= num_robots_) {
367 throw std::out_of_range{"Robot index more than the number of robots"};
368 }
369 }
370
372 UpdateRobotPositions();
373 voronoi_ = Voronoi(robot_global_positions_, GetWorldMap(),
374 Point2(params_.pWorldMapSize, params_.pWorldMapSize),
375 params_.pResolution);
376 voronoi_cells_ = voronoi_.GetVoronoiCells();
377 }
378
387 bool StepRobotToGoal(int const robot_id, Point2 const &goal,
388 double const speed_factor = 1);
389
397 bool StepRobotsToGoals(PointVector const &goals, PointVector &actions);
398
400 for (size_t i = 0; i < num_robots_; ++i) {
401 robots_[i].ClearRobotMap();
402 }
403 }
404
406 explored_idf_map_ =
407 MapType::Constant(params_.pWorldMapSize, params_.pWorldMapSize, 0);
408 }
409
411
414 int WriteRobotPositions(std::string const &file_name) const;
415 int WriteRobotPositions(std::string const &file_name,
416 PointVector const &positions) const;
417 int WriteEnvironment(std::string const &pos_filename,
418 std::string const &env_filename) const;
420
423 void PlotFrontiers(std::string const &, int const &,
424 PointVector const &) const;
425 void PlotSystemMap(std::string const &dir_name, int const &step) const {
426 std::vector<int> robot_status(num_robots_, 0);
427 PlotSystemMap(dir_name, step, robot_status);
428 }
429 void PlotSystemMap(std::string const &) const;
430 void PlotSystemMap(std::string const &, int const &,
431 std::vector<int> const &) const;
432 void PlotMapVoronoi(std::string const &, int const &);
433 void PlotMapVoronoi(std::string const &, int const &, Voronoi const &,
434 PointVector const &) const;
435 void PlotWorldMap(std::string const &, std::string const &) const;
436 void PlotWorldMapRobots(std::string const &, std::string const &) const;
437 void PlotInitMap(std::string const &filename) const {
438 PlotInitMap("./", filename);
439 }
440 void PlotInitMap(std::string const &, std::string const &) const;
441 void PlotRobotLocalMap(std::string const &, int const &, int const &);
442 void PlotRobotSystemMap(std::string const &, int const &, int const &);
443 void PlotRobotExplorationMap(std::string const &, int const &, int const &);
444 void PlotRobotSensorView(std::string const &, int const &, int const &);
445 void PlotRobotObstacleMap(std::string const &, int const &, int const &);
446 void PlotRobotCommunicationMaps(std::string const &, int const &, int const &,
447 size_t const &);
448
449 void RenderRecordedMap(std::string const &, std::string const &) const;
450 void RecordPlotData(std::vector<int> const &, std::string const &);
451 void RecordPlotData(std::vector<int> const &robot_status) {
452 RecordPlotData(robot_status, "system");
453 }
454 void RecordPlotData(std::string const &map_name) {
455 std::vector<int> robot_status(num_robots_, 0);
456 RecordPlotData(robot_status, map_name);
457 }
459 std::vector<int> robot_status(num_robots_, 0);
460 RecordPlotData(robot_status, "system");
461 }
463
465 //
467 std::shared_ptr<const WorldIDF> GetWorldIDFPtr() const {
468 return world_idf_ptr_;
469 }
470 const WorldIDF &GetWorldIDFObject() const { return *world_idf_ptr_; }
471 const MapType &GetSystemMap() const { return system_map_; }
472 const MapType &GetSystemExplorationMap() const { return exploration_map_; }
473 const MapType &GetSystemExploredIDFMap() const { return explored_idf_map_; }
474 MapType &GetSystemExploredIDFMapMutable() { return explored_idf_map_; }
476 const MapType &GetWorldMap() const { return world_idf_ptr_->GetWorldMap(); }
478 MapType &GetWorldMapMutable() { return world_idf_ptr_->GetWorldMapMutable(); }
479
480 MapType &GetRobotMapMutable(size_t const id) {
481 CheckRobotID(id);
482 return robots_[id].GetRobotMapMutable();
483 }
484
485 inline auto GetNumRobots() const { return num_robots_; }
486 inline auto GetNumFeatures() const { return num_robots_; }
487
488 inline double GetExplorationRatio() const {
489 double exploration_ratio =
490 1.0 - static_cast<double>(exploration_map_.sum()) /
491 (params_.pWorldMapSize * params_.pWorldMapSize);
492 return exploration_ratio;
493 }
494
496 inline double GetWeightedExplorationRatio() const {
497 double weighted_exploration_ratio =
498 static_cast<double>(explored_idf_map_.sum()) / (total_idf_weight_);
499 return weighted_exploration_ratio;
500 }
501
502 PointVector GetRelativePositonsNeighbors(size_t const robot_id);
503 std::vector<int> GetNeighborIDs(size_t const robot_id) const {
504 return neighbor_ids_[robot_id];
505 }
506
514 PointVector GetRobotPositions(bool force_no_noise = false) {
515 UpdateRobotPositions();
516 if (params_.pAddNoisePositions and not force_no_noise) {
517 PointVector noisy_robot_global_positions;
518 for (Point2 pt : robot_global_positions_) {
519 noisy_robot_global_positions.push_back(AddNoise(pt));
520 }
521 return noisy_robot_global_positions;
522 }
523 return robot_global_positions_;
524 }
525
526 Point2 GetRobotPosition(int const robot_id,
527 bool force_no_noise = false) const {
528 Point2 robot_pos;
529 robot_pos[0] = robots_[robot_id].GetGlobalCurrentPosition()[0];
530 robot_pos[1] = robots_[robot_id].GetGlobalCurrentPosition()[1];
531 if (params_.pAddNoisePositions and not force_no_noise) {
532 return AddNoise(robot_pos);
533 }
534 return robot_pos;
535 }
536
537 const MapType &GetRobotLocalMap(size_t const id) {
538 CheckRobotID(id);
539 return robots_[id].GetRobotLocalMap();
540 }
541
542 const MapType &GetRobotMap(size_t const id) const {
543 CheckRobotID(id);
544 return robots_[id].GetRobotMap();
545 }
546
547 const MapType &GetRobotExplorationMap(size_t const id) {
548 CheckRobotID(id);
549 return robots_[id].GetExplorationMap();
550 }
551
552 const MapType &GetRobotSystemMap(size_t const id) {
553 CheckRobotID(id);
554 return robots_[id].GetRobotSystemMap();
555 }
556 const MapType &GetRobotObstacleMap(size_t const id) {
557 CheckRobotID(id);
558 return robots_[id].GetObstacleMap();
559 }
560
561 const MapType &GetRobotSensorView(size_t const id) const {
562 CheckRobotID(id);
563 return robots_[id].GetSensorView();
564 }
565
566 auto GetRobotsInCommunication(size_t const id) const {
567 CheckRobotID(id);
568 PointVector robot_neighbors_pos;
569 for (size_t i = 0; i < num_robots_; ++i) {
570 if (id == i) {
571 continue;
572 }
573 Point2 relative_pos =
574 robot_global_positions_[i] - robot_global_positions_[id];
575 if (relative_pos.norm() < params_.pCommunicationRange) {
576 robot_neighbors_pos.push_back(relative_pos);
577 }
578 }
579 std::sort(
580 robot_neighbors_pos.begin(), robot_neighbors_pos.end(),
581 [](Point2 const &a, Point2 const &b) { return a.norm() < b.norm(); });
582 return robot_neighbors_pos;
583 }
584
585 std::pair<MapType, MapType> GetRobotCommunicationMaps(size_t const, size_t);
586
587 std::vector<MapType> GetCommunicationMaps(size_t map_size) {
588 std::vector<MapType> communication_maps(2 * num_robots_);
589 /* #pragma omp parallel for num_threads(num_robots_) */
590 for (size_t i = 0; i < num_robots_; ++i) {
591 auto comm_map = GetRobotCommunicationMaps(i, map_size);
592 communication_maps[2 * i] = comm_map.first;
593 communication_maps[2 * i + 1] = comm_map.second;
594 }
595 return communication_maps;
596 }
597
599 ComputeVoronoiCells();
600 return voronoi_.GetSumIDFSiteDistSqr();
601 }
602
604 std::vector<std::vector<double>> features(num_robots_);
605#pragma omp parallel for num_threads(num_robots_)
606 for (size_t iRobot = 0; iRobot < num_robots_; ++iRobot) {
607 features[iRobot] = robots_[iRobot].GetExplorationFeatures();
608 }
609 return features;
610 }
611
613 std::vector<std::vector<double>> features(num_robots_);
614#pragma omp parallel for num_threads(num_robots_)
615 for (size_t iRobot = 0; iRobot < num_robots_; ++iRobot) {
616 features[iRobot] = robots_[iRobot].GetVoronoiFeatures();
617 }
618 return features;
619 }
620
624 std::vector<double> GetLocalVoronoiFeatures(int const robot_id);
625
626 std::vector<std::vector<double>> GetLocalVoronoiFeatures() {
627 std::vector<std::vector<double>> features(num_robots_);
628#pragma omp parallel for num_threads(num_robots_)
629 for (size_t iRobot = 0; iRobot < num_robots_; ++iRobot) {
630 features[iRobot] = GetLocalVoronoiFeatures(iRobot);
631 }
632 return features;
633 }
634
635 auto GetVoronoiCells() { return voronoi_cells_; }
636 Voronoi &GetVoronoi() { return voronoi_; }
637
638 auto GetVoronoiCell(int const robot_id) { return voronoi_cells_[robot_id]; }
639
641 normalization_factor_ = world_idf_ptr_->GetNormalizationFactor();
642 return normalization_factor_;
643 }
644
646};
647
648} /* namespace CoverageControl */
649#endif // CPPSRC_CORE_INCLUDE_COVERAGECONTROL_COVERAGE_SYSTEM_H_
Class for Bivariate Normal Distribution.
The CoverageSystem class is the main class for the coverage control library.
PointVector GetRobotPositions(bool force_no_noise=false)
Get the global positions of all robots.
const MapType & GetSystemExploredIDFMap() const
MapType & GetWorldMapMutable()
Get the world map (mutable)
void SetLocalRobotPositions(std::vector< Point2 > const &relative_pos)
double GetWeightedExplorationRatio() const
Get the weighted (by IDF) exploration ratio.
auto GetVoronoiCell(int const robot_id)
bool StepControl(size_t robot_id, Point2 const &direction, double const speed)
Execute velocity control for robot_id.
std::vector< MapType > GetCommunicationMaps(size_t map_size)
const MapType & GetRobotExplorationMap(size_t const id)
const MapType & GetRobotSensorView(size_t const id) const
void RecordPlotData(std::string const &map_name)
const MapType & GetSystemExplorationMap() const
const MapType & GetSystemMap() const
void RecordPlotData(std::vector< int > const &robot_status)
std::vector< int > GetNeighborIDs(size_t const robot_id) const
const MapType & GetRobotObstacleMap(size_t const id)
void CheckRobotID(size_t const id) const
std::shared_ptr< const WorldIDF > GetWorldIDFPtr() const
bool CheckOscillation(size_t const robot_id) const
bool StepActions(PointVector const &actions)
Execute given actions for all robots.
void PlotInitMap(std::string const &filename) const
Point2 GetRobotPosition(int const robot_id, bool force_no_noise=false) const
const MapType & GetWorldMap() const
Get the world map.
MapType & GetRobotMapMutable(size_t const id)
void SetRobotPositions(std::vector< Point2 > const &positions)
void PlotSystemMap(std::string const &dir_name, int const &step) const
std::vector< std::vector< double > > GetLocalVoronoiFeatures()
auto GetRobotsInCommunication(size_t const id) const
const MapType & GetRobotMap(size_t const id) const
const MapType & GetRobotSystemMap(size_t const id)
void SetGlobalRobotPosition(size_t const robot_id, Point2 const &global_pos)
Set the global position of robot_id.
void SetLocalRobotPosition(size_t const robot_id, Point2 const &relative_pos)
Set the position of robot_id with respect to its current position.
bool StepAction(size_t const robot_id, Point2 const action)
Execute given action for robot_id.
const WorldIDF & GetWorldIDFObject() const
const MapType & GetRobotLocalMap(size_t const id)
Point2 AddNoise(Point2 const pt) const
Add noise to the given point and ensure within bounds.
void SetGlobalRobotPositions(PointVector const &global_positions)
Set the global positions of all robots.
void SetWorldIDF(WorldIDF const &world_idf)
Set the world IDF and recompute the world map.
Class to store parameters.
Definition parameters.h:48
double pCommunicationRange
Radius of communication (in meters)
Definition parameters.h:134
Class for computing Voronoi cells.
Definition voronoi.h:116
auto GetVoronoiCells() const
Definition voronoi.h:185
double GetSumIDFSiteDistSqr()
Definition voronoi.h:188
Class for Importance Density Function (IDF) for the world.
Definition world_idf.h:61
Constants for the CoverageControl library.
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
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:59
Namespace for the CoverageControl library.
Contains parameters.
Class to plot the map.
Class for handling the robot model.
Contains typedefs for the library.
Class for computing Voronoi cells.
Contains the class for Importance Density Function (IDF) for the world.