40 :
CoverageSystem(params, params.pNumGaussianFeatures, params.pNumPolygons,
44 int const num_gaussians,
int const num_robots)
48 int const num_gaussians,
int const num_polygons,
56 distrib_pts_ = std::uniform_real_distribution<>(
58 std::uniform_real_distribution<> distrib_var(params_.
pMinSigma,
60 std::uniform_real_distribution<> distrib_peak(params_.
pMinPeak,
63 world_idf_ptr_ = std::make_shared<WorldIDF>(params_);
64 for (
int i = 0; i < num_gaussians; ++i) {
65 Point2 mean(distrib_pts_(gen_), distrib_pts_(gen_));
70 sigma = distrib_var(gen_);
76 scale = distrib_peak(gen_);
80 world_idf_ptr_->AddNormalDistribution(dist);
83 std::vector<PointVector> polygons;
88 for (
auto &poly : polygons) {
90 double importance = 0.00005;
94 importance = distrib_peak(gen_) * importance;
97 world_idf_ptr_->AddUniformDistributionPolygon(poly_feature);
100 world_idf_ptr_->GenerateMap();
101 normalization_factor_ = world_idf_ptr_->GetNormalizationFactor();
103 std::uniform_real_distribution<> env_point_dist(
105 robots_.reserve(num_robots);
106 for (
int i = 0; i < num_robots; ++i) {
107 Point2 start_pos(env_point_dist(gen_), env_point_dist(gen_));
108 robots_.push_back(
RobotModel(params_, start_pos, world_idf_ptr_));
115 std::string
const &pos_file_name)
120 std::ifstream file_pos(pos_file_name);
121 if (!file_pos.is_open()) {
122 std::cout <<
"Error: Could not open file " << pos_file_name << std::endl;
125 std::vector<Point2> robot_positions;
127 while (file_pos >> x >> y) {
128 robot_positions.push_back(
Point2(x, y));
130 robots_.reserve(robot_positions.size());
131 num_robots_ = robot_positions.size();
132 if(params_.
pNumRobots !=
static_cast<int>(num_robots_)) {
133 std::cerr <<
"Number of robots in the file does not match the number of robots in the parameters\n";
134 std::cerr <<
"Number of robots in the file: " << num_robots_ <<
" Number of robots in the parameters: " << params_.
pNumRobots << std::endl;
137 for (
Point2 const &pos : robot_positions) {
138 robots_.push_back(
RobotModel(params_, pos, world_idf_ptr_));
145 std::vector<Point2>
const &robot_positions)
149 robots_.reserve(robot_positions.size());
150 num_robots_ = robot_positions.size();
151 for (
auto const &pos : robot_positions) {
152 robots_.push_back(
RobotModel(params_, pos, world_idf_ptr_));
159 std::vector<BivariateNormalDistribution>
const &dists,
160 std::vector<Point2>
const &robot_positions)
162 world_idf_ptr_ = std::make_shared<WorldIDF>(params_);
163 world_idf_ptr_->AddNormalDistribution(dists);
164 num_robots_ = robot_positions.size();
167 world_idf_ptr_->GenerateMap();
168 normalization_factor_ = world_idf_ptr_->GetNormalizationFactor();
170 robots_.reserve(num_robots_);
171 for (
auto const &pos : robot_positions) {
172 robots_.push_back(
RobotModel(params_, pos, world_idf_ptr_));
178 size_t const id,
size_t map_size) {
179 std::pair<MapType, MapType> communication_maps = std::make_pair(
180 MapType::Zero(map_size, map_size), MapType::Zero(map_size, map_size));
182 double center = map_size / 2. - params_.
pResolution / 2.;
183 Point2 center_point(center, center);
184 for (
Point2 const &relative_pos : robot_neighbors_pos) {
185 Point2 scaled_indices_val =
186 relative_pos * map_size /
189 int scaled_indices_x = std::round(scaled_indices_val[0]);
190 int scaled_indices_y = std::round(scaled_indices_val[1]);
193 communication_maps.first(scaled_indices_x, scaled_indices_y) +=
194 normalized_relative_pos[0];
195 communication_maps.second(scaled_indices_x, scaled_indices_y) +=
196 normalized_relative_pos[1];
198 return communication_maps;
201void CoverageSystem::InitSetup() {
202 num_robots_ = robots_.size();
203 robot_positions_history_.resize(num_robots_);
205 voronoi_cells_.resize(num_robots_);
207 robot_global_positions_.resize(num_robots_);
208 for (
size_t iRobot = 0; iRobot < num_robots_; ++iRobot) {
209 robot_global_positions_[iRobot] =
210 robots_[iRobot].GetGlobalCurrentPosition();
219 relative_positions_neighbors_.resize(num_robots_);
220 neighbor_ids_.resize(num_robots_);
221 for (
size_t iRobot = 0; iRobot < num_robots_; ++iRobot) {
222 relative_positions_neighbors_[iRobot].reserve(num_robots_);
223 neighbor_ids_[iRobot].reserve(num_robots_);
228void CoverageSystem::PostStepCommands(
size_t robot_id) {
229 robot_global_positions_[robot_id] =
230 robots_[robot_id].GetGlobalCurrentPosition();
234 MapUtils::MapBounds index, offset;
236 params_.
pResolution, robot_global_positions_[robot_id],
238 explored_idf_map_.block(index.left + offset.left,
239 index.bottom + offset.bottom, offset.width,
242 offset.width, offset.height);
243 exploration_map_.block(
244 index.left + offset.left, index.bottom + offset.bottom, offset.width,
245 offset.height) = MapType::Zero(offset.width, offset.height);
246 system_map_ = explored_idf_map_ - exploration_map_;
248 auto &history = robot_positions_history_[robot_id];
249 if (history.size() > 0 and
253 history.push_back(robot_global_positions_[robot_id]);
257void CoverageSystem::PostStepCommands() {
258 UpdateRobotPositions();
263 for (
size_t iRobot = 0; iRobot < num_robots_; ++iRobot) {
264 auto &history = robot_positions_history_[iRobot];
265 if (history.size() > 0 and
269 history.push_back(robot_global_positions_[iRobot]);
274void CoverageSystem::UpdateNeighbors() {
275 for (
size_t iRobot = 0; iRobot < num_robots_; ++iRobot) {
276 relative_positions_neighbors_[iRobot].clear();
277 neighbor_ids_[iRobot].clear();
279 for (
size_t iRobot = 0; iRobot < num_robots_; ++iRobot) {
280 for (
size_t jRobot = iRobot + 1; jRobot < num_robots_; ++jRobot) {
281 Point2 relative_pos =
282 robot_global_positions_[jRobot] - robot_global_positions_[iRobot];
284 relative_positions_neighbors_[iRobot].push_back(relative_pos);
285 neighbor_ids_[iRobot].push_back(jRobot);
286 relative_positions_neighbors_[jRobot].push_back(-relative_pos);
287 neighbor_ids_[jRobot].push_back(iRobot);
294 double const speed_factor) {
295 Point2 curr_pos = robots_[robot_id].GetGlobalCurrentPosition();
296 Point2 diff = goal - curr_pos;
297 double dist = diff.norm();
298 double speed = speed_factor * dist / params_.
pTimeStep;
304 direction.normalize();
305 if (robots_[robot_id].
StepControl(direction, speed)) {
306 std::cerr <<
"Control incorrect\n";
315 bool cont_flag =
false;
316 UpdateRobotPositions();
318 for (
size_t iRobot = 0; iRobot < num_robots_; ++iRobot) {
319 actions[iRobot] =
Point2(0, 0);
320 Point2 diff = goals[iRobot] - robot_global_positions_[iRobot];
321 double dist = diff.norm();
328 direction.normalize();
329 actions[iRobot] = speed * direction;
331 std::cerr <<
"Control incorrect\n";
347 std::lock_guard<std::mutex> lock(mutex_);
348 std::normal_distribution pos_noise{0.0, noise_sigma};
349 noisy_pt +=
Point2(pos_noise(gen_), pos_noise(gen_));
369 std::ofstream file_obj(file_name);
371 std::cerr <<
"[Error] Could not open " << file_name <<
" for writing."
376 for (
auto const &pos : robot_global_positions_) {
377 file_obj << pos[0] <<
" " << pos[1] << std::endl;
385 std::ofstream file_obj(file_name);
387 std::cerr <<
"[Error] Could not open " << file_name <<
" for writing."
391 for (
auto const &pos : positions) {
392 file_obj << pos[0] <<
" " << pos[1] << std::endl;
399 std::string
const &env_filename)
const {
401 world_idf_ptr_->WriteDistributions(env_filename);
406 std::string
const &video_name)
const {
407 std::string frame_dir = dir_name +
"/frames/";
408 std::filesystem::create_directory(frame_dir);
412 Plotter plotter_voronoi(frame_dir,
416#pragma omp parallel for
417 for (
size_t i = 0; i < plotter_data_.size(); ++i) {
418 auto iPlotter = plotter;
422 iPlotter.PlotMap(plotter_data_[i].map, plotter_data_[i].positions,
423 plotter_data_[i].positions_history,
424 plotter_data_[i].robot_status,
426 auto iPlotterVoronoi = plotter_voronoi;
428 iPlotterVoronoi.PlotMap(plotter_data_[i].world_map, plotter_data_[i].positions,
429 plotter_data_[i].voronoi,
430 plotter_data_[i].positions_history);
433 system((
"ffmpeg -y -r 30 -i " + frame_dir +
434 "map%04d.png -vcodec libx264 -crf 25 -pix_fmt yuv420p " +
435 dir_name +
"/" + video_name)
438 std::cout <<
"Error: ffmpeg call failed." << std::endl;
441 system((
"ffmpeg -y -r 30 -i " + frame_dir +
442 "voronoi_map%04d.png -vcodec libx264 -crf 25 -pix_fmt yuv420p " +
443 dir_name +
"/voronoi_" + video_name)
446 std::cout <<
"Error: ffmpeg call failed." << std::endl;
448 std::filesystem::remove_all(frame_dir);
452 std::string
const &map_name) {
454 if (map_name ==
"world") {
457 data.
map = system_map_;
459 data.
positions = robot_global_positions_;
463 std::vector<std::list<Point2>> voronoi;
465 for (
size_t i = 0; i < num_robots_; ++i) {
466 std::list<Point2> cell_points;
467 for (
auto const &pos : voronoi_cells[i].cell) {
468 cell_points.push_back(
Point2(pos[0], pos[1]));
470 cell_points.push_back(cell_points.front());
471 voronoi.push_back(cell_points);
475 plotter_data_.push_back(data);
479 std::vector<int> robot_status(num_robots_, 0);
484 plotter.PlotMap(system_map_, robot_global_positions_,
485 robot_positions_history_, robot_status,
490 std::vector<int>
const &robot_status)
const {
495 plotter.PlotMap(system_map_, robot_global_positions_,
496 robot_positions_history_, robot_status);
500 std::string
const &map_name)
const {
505 std::vector<int> robot_status(num_robots_, 0);
506 plotter.PlotMap(
GetWorldMap(), robot_global_positions_,
507 robot_positions_history_, robot_status);
511 std::string
const &map_name)
const {
520 std::string
const &map_name)
const {
525 plotter.PlotMap(
GetWorldMap(), robot_global_positions_);
535 plotter.PlotMap(
GetWorldMap(), robot_global_positions_, voronoi_,
536 robot_positions_history_);
540 int const &step,
Voronoi const &voronoi,
546 plotter.PlotMap(
GetWorldMap(), robot_global_positions_, goals, voronoi);
555 plotter.PlotMap(system_map_, robot_global_positions_,
556 robot_positions_history_, frontiers);
560 int const &robot_id,
int const &step) {
563 plotter.
SetPlotName(
"robot_" + std::to_string(robot_id) +
"_", step);
565 for (
Point2 &pos : neighbours_positions) {
573 int const &robot_id,
int const &step) {
577 plotter.
SetPlotName(
"robot_" + std::to_string(robot_id) +
"_", step);
586 plotter.
SetPlotName(
"robot_exp_" + std::to_string(robot_id) +
"_", step);
591 int const &robot_id,
int const &step) {
594 plotter.
SetPlotName(
"robot_sensor_" + std::to_string(robot_id) +
"_", step);
603 plotter.
SetPlotName(
"robot_obstacle_map_" + std::to_string(robot_id) +
"_",
611 size_t const &map_size) {
616 "robot_communication_map_x_" + std::to_string(robot_id) +
"_", step);
617 plotter_x.PlotMap(robot_communication_maps.first);
621 "robot_communication_map_y_" + std::to_string(robot_id) +
"_", step);
622 plotter_y.PlotMap(robot_communication_maps.second);
626 size_t const robot_id) {
629 for (
Point2 &pt : noisy_positions) {
633 for (
size_t i = 0; i < num_robots_; ++i) {
637 if ((noisy_positions[i] - noisy_positions[robot_id]).norm() <
639 relative_positions.push_back(noisy_positions[i] -
640 noisy_positions[robot_id]);
643 return relative_positions;
645 return relative_positions_neighbors_[robot_id];
649 int const robot_id) {
650 auto const &pos = robot_global_positions_[robot_id];
654 auto robot_map = robots_[robot_id].GetRobotMap();
655 auto trimmed_local_map =
664 PointVector robot_positions(robot_neighbors_pos.size() + 1);
666 robot_positions[0] = pos - map_translation;
668 for (
auto const &neighbor_pos : robot_neighbors_pos) {
669 robot_positions[count] = neighbor_pos - map_translation;
672 Voronoi voronoi(robot_positions, trimmed_local_map, map_size,
675 return vcell.GetFeatureVector();
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.
void PlotRobotSensorView(std::string const &, int const &, int const &)
void PlotWorldMap(std::string const &, std::string const &) const
bool StepControl(size_t robot_id, Point2 const &direction, double const speed)
Execute velocity control for robot_id.
const MapType & GetRobotExplorationMap(size_t const id)
std::pair< MapType, MapType > GetRobotCommunicationMaps(size_t const, size_t)
const MapType & GetRobotSensorView(size_t const id) const
void PlotMapVoronoi(std::string const &, int const &)
void PlotRobotExplorationMap(std::string const &, int const &, int const &)
void PlotRobotObstacleMap(std::string const &, int const &, int const &)
void PlotRobotLocalMap(std::string const &, int const &, int const &)
bool StepRobotsToGoals(PointVector const &goals, PointVector &actions)
const MapType & GetRobotObstacleMap(size_t const id)
void PlotFrontiers(std::string const &, int const &, PointVector const &) const
void PlotWorldMapRobots(std::string const &, std::string const &) const
void ComputeVoronoiCells()
int WriteEnvironment(std::string const &pos_filename, std::string const &env_filename) const
void PlotInitMap(std::string const &filename) const
const MapType & GetWorldMap() const
Get the world map.
void RenderRecordedMap(std::string const &, std::string const &) const
PointVector GetRelativePositonsNeighbors(size_t const robot_id)
void PlotSystemMap(std::string const &dir_name, int const &step) const
std::vector< std::vector< double > > GetLocalVoronoiFeatures()
void PlotRobotSystemMap(std::string const &, int const &, int const &)
auto GetRobotsInCommunication(size_t const id) const
const MapType & GetRobotSystemMap(size_t const id)
int WriteRobotPositions(std::string const &file_name) const
bool StepRobotToGoal(int const robot_id, Point2 const &goal, double const speed_factor=1)
void PlotRobotCommunicationMaps(std::string const &, int const &, int const &, size_t 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 SetWorldIDF(WorldIDF const &world_idf)
Set the world IDF and recompute the world map.
Class to store parameters.
double pTimeStep
Each time step corresponds to pTimeStep seconds.
int pNumRobots
Number of robots.
double pPositionsNoiseSigma
int pMaxVertices
Maximum number of vertices in a polygon.
int pRobotPosHistorySize
Number of previous positions to store.
double pCommunicationRange
Radius of communication (in meters)
void SetPlotName(std::string const &name)
void SetScale(double const &sc)
Class for handling the robot model.
Class for computing Voronoi cells.
auto GetVoronoiCells() const
Class for Importance Density Function (IDF) for the world.
The file contains the CoverageSystem class, which is the main class for the coverage control library.
constexpr auto kMaxPrecision
std::vector< Point2 > PointVector
void ComputeOffsets(double const resolution, Point2 const &pos, int const submap_size, int const map_size, MapBounds &index, MapBounds &offset)
Namespace for the CoverageControl library.
void GenerateRandomPolygons(int const num_polygons, int const max_vertices, double const half_width, double const world_size, std::vector< PointVector > &polygons)
Generate random polygons.
Provides utilities for polygon manipulation using CGAL.
Data structure to store plotter data.
std::vector< std::list< Point2 > > voronoi
std::vector< std::list< Point2 > > positions_history
std::vector< int > robot_status
A struct to store a polygon feature and a uniform importance value.