39 int const num_gaussians,
int const num_robots)
43 int const num_gaussians,
int const num_polygons,
45 : params_{params}, world_idf_{
WorldIDF(params_)} {
51 distrib_pts_ = std::uniform_real_distribution<>(
53 std::uniform_real_distribution<> distrib_var(params_.pMinSigma,
55 std::uniform_real_distribution<> distrib_peak(params_.pMinPeak,
57 for (
int i = 0; i < num_gaussians; ++i) {
58 Point2 mean(distrib_pts_(gen_), distrib_pts_(gen_));
59 double sigma(distrib_var(gen_));
60 double scale(distrib_peak(gen_));
61 scale = 2 * M_PI * sigma * sigma * scale;
66 std::vector<PointVector> polygons;
68 params_.pPolygonRadius,
71 for (
auto &poly : polygons) {
72 double importance = distrib_peak(gen_) * 0.5;
73 PolygonFeature poly_feature(poly, importance);
77 world_idf_.GenerateMap();
78 normalization_factor_ = world_idf_.GetNormalizationFactor();
80 std::uniform_real_distribution<> env_point_dist(
82 robots_.reserve(num_robots);
83 for (
int i = 0; i < num_robots; ++i) {
84 Point2 start_pos(env_point_dist(gen_), env_point_dist(gen_));
85 robots_.push_back(RobotModel(params_, start_pos, world_idf_));
92 std::string
const &pos_file_name)
93 : params_{params}, world_idf_{
WorldIDF(params_)} {
97 std::ifstream file_pos(pos_file_name);
98 if (!file_pos.is_open()) {
99 std::cout <<
"Error: Could not open file " << pos_file_name << std::endl;
102 std::vector<Point2> robot_positions;
104 while (file_pos >> x >> y) {
105 robot_positions.push_back(
Point2(x, y));
107 robots_.reserve(robot_positions.size());
108 num_robots_ = robot_positions.size();
109 for (
Point2 const &pos : robot_positions) {
110 robots_.push_back(
RobotModel(params_, pos, world_idf_));
117 std::vector<Point2>
const &robot_positions)
118 : params_{params}, world_idf_{
WorldIDF(params_)} {
121 robots_.reserve(robot_positions.size());
122 num_robots_ = robot_positions.size();
123 for (
auto const &pos : robot_positions) {
124 robots_.push_back(
RobotModel(params_, pos, world_idf_));
131 std::vector<BivariateNormalDistribution>
const &dists,
132 std::vector<Point2>
const &robot_positions)
133 : params_{params}, world_idf_{
WorldIDF(params_)} {
135 num_robots_ = robot_positions.size();
138 world_idf_.GenerateMap();
139 normalization_factor_ = world_idf_.GetNormalizationFactor();
141 robots_.reserve(num_robots_);
142 for (
auto const &pos : robot_positions) {
143 robots_.push_back(
RobotModel(params_, pos, world_idf_));
148std::pair<MapType, MapType>
const &CoverageSystem::GetCommunicationMap(
149 size_t const id,
size_t map_size) {
150 communication_maps_[id] = std::make_pair(MapType::Zero(map_size, map_size),
151 MapType::Zero(map_size, map_size));
152 PointVector robot_neighbors_pos = GetRelativePositonsNeighbors(
id);
153 double center = map_size / 2. - params_.
pResolution / 2.;
154 Point2 center_point(center, center);
155 for (
Point2 const &relative_pos : robot_neighbors_pos) {
156 Point2 scaled_indices_val =
157 relative_pos * map_size /
160 int scaled_indices_x = scaled_indices_val[0];
161 int scaled_indices_y = scaled_indices_val[1];
164 communication_maps_[id].first(scaled_indices_x, scaled_indices_y) +=
165 normalized_relative_pos[0];
166 communication_maps_[id].second(scaled_indices_x, scaled_indices_y) +=
167 normalized_relative_pos[1];
169 return communication_maps_[id];
172void CoverageSystem::InitSetup() {
173 num_robots_ = robots_.size();
174 robot_positions_history_.resize(num_robots_);
176 voronoi_cells_.resize(num_robots_);
177 communication_maps_.resize(num_robots_);
179 robot_global_positions_.resize(num_robots_);
180 for (
size_t iRobot = 0; iRobot < num_robots_; ++iRobot) {
181 robot_global_positions_[iRobot] =
182 robots_[iRobot].GetGlobalCurrentPosition();
191 relative_positions_neighbors_.resize(num_robots_);
192 neighbor_ids_.resize(num_robots_);
193 for (
size_t iRobot = 0; iRobot < num_robots_; ++iRobot) {
194 relative_positions_neighbors_[iRobot].reserve(num_robots_);
195 neighbor_ids_[iRobot].reserve(num_robots_);
200void CoverageSystem::PostStepCommands(
size_t robot_id) {
201 robot_global_positions_[robot_id] =
202 robots_[robot_id].GetGlobalCurrentPosition();
205 if (params_.pUpdateSystemMap) {
206 MapUtils::MapBounds index, offset;
208 params_.
pResolution, robot_global_positions_[robot_id],
210 explored_idf_map_.block(index.left + offset.left,
211 index.bottom + offset.bottom, offset.width,
213 GetRobotSensorView(robot_id).block(offset.left, offset.bottom,
214 offset.width, offset.height);
215 exploration_map_.block(
216 index.left + offset.left, index.bottom + offset.bottom, offset.width,
217 offset.height) = MapType::Zero(offset.width, offset.height);
218 system_map_ = explored_idf_map_ - exploration_map_;
220 auto &history = robot_positions_history_[robot_id];
221 if (history.size() > 0 and
225 history.push_back(robot_global_positions_[robot_id]);
229void CoverageSystem::PostStepCommands() {
230 UpdateRobotPositions();
232 if (params_.pUpdateSystemMap) {
235 for (
size_t iRobot = 0; iRobot < num_robots_; ++iRobot) {
236 auto &history = robot_positions_history_[iRobot];
237 if (history.size() > 0 and
241 history.push_back(robot_global_positions_[iRobot]);
246void CoverageSystem::UpdateNeighbors() {
247 for (
size_t iRobot = 0; iRobot < num_robots_; ++iRobot) {
248 relative_positions_neighbors_[iRobot].clear();
249 neighbor_ids_[iRobot].clear();
251 for (
size_t iRobot = 0; iRobot < num_robots_; ++iRobot) {
252 for (
size_t jRobot = iRobot + 1; jRobot < num_robots_; ++jRobot) {
253 Point2 relative_pos =
254 robot_global_positions_[jRobot] - robot_global_positions_[iRobot];
256 relative_positions_neighbors_[iRobot].push_back(relative_pos);
257 neighbor_ids_[iRobot].push_back(jRobot);
258 relative_positions_neighbors_[jRobot].push_back(-relative_pos);
259 neighbor_ids_[jRobot].push_back(iRobot);
266 double const speed_factor) {
267 Point2 curr_pos = robots_[robot_id].GetGlobalCurrentPosition();
268 Point2 diff = goal - curr_pos;
269 double dist = diff.norm();
270 double speed = speed_factor * dist / params_.
pTimeStep;
274 speed = std::min(params_.pMaxRobotSpeed, speed);
276 direction.normalize();
277 if (robots_[robot_id].
StepControl(direction, speed)) {
278 std::cerr <<
"Control incorrect\n";
287 bool cont_flag =
false;
288 UpdateRobotPositions();
290 for (
size_t iRobot = 0; iRobot < num_robots_; ++iRobot) {
291 actions[iRobot] =
Point2(0, 0);
292 Point2 diff = goals[iRobot] - robot_global_positions_[iRobot];
293 double dist = diff.norm();
298 speed = std::min(params_.pMaxRobotSpeed, speed);
300 direction.normalize();
301 actions[iRobot] = speed * direction;
303 std::cerr <<
"Control incorrect\n";
315 auto noise_sigma = params_.pPositionsNoiseSigma;
319 std::lock_guard<std::mutex> lock(mutex_);
320 std::normal_distribution pos_noise{0.0, noise_sigma};
321 noisy_pt +=
Point2(pos_noise(gen_), pos_noise(gen_));
340int CoverageSystem::WriteRobotPositions(std::string
const &file_name)
const {
341 std::ofstream file_obj(file_name);
343 std::cerr <<
"[Error] Could not open " << file_name <<
" for writing."
348 for (
auto const &pos : robot_global_positions_) {
349 file_obj << pos[0] <<
" " << pos[1] << std::endl;
355int CoverageSystem::WriteRobotPositions(std::string
const &file_name,
356 PointVector
const &positions)
const {
357 std::ofstream file_obj(file_name);
359 std::cerr <<
"[Error] Could not open " << file_name <<
" for writing."
363 for (
auto const &pos : positions) {
364 file_obj << pos[0] <<
" " << pos[1] << std::endl;
370int CoverageSystem::WriteEnvironment(std::string
const &pos_filename,
371 std::string
const &env_filename)
const {
372 WriteRobotPositions(pos_filename);
373 world_idf_.WriteDistributions(env_filename);
377void CoverageSystem::RenderRecordedMap(std::string
const &dir_name,
378 std::string
const &video_name)
const {
379 std::string frame_dir = dir_name +
"/frames/";
380 std::filesystem::create_directory(frame_dir);
384 Plotter plotter_voronoi(frame_dir,
388#pragma omp parallel for
389 for (
size_t i = 0; i < plotter_data_.size(); ++i) {
390 auto iPlotter = plotter;
391 iPlotter.SetPlotName(
"map", i);
394 iPlotter.PlotMap(plotter_data_[i].map, plotter_data_[i].positions,
395 plotter_data_[i].positions_history,
396 plotter_data_[i].robot_status,
398 auto iPlotterVoronoi = plotter_voronoi;
399 iPlotterVoronoi.SetPlotName(
"voronoi_map", i);
400 iPlotterVoronoi.PlotMap(
GetWorldMap(), plotter_data_[i].positions,
401 plotter_data_[i].voronoi,
402 plotter_data_[i].positions_history);
405 system((
"ffmpeg -y -r 30 -i " + frame_dir +
406 "map%04d.png -vcodec libx264 -crf 25 -pix_fmt yuv420p " +
407 dir_name +
"/" + video_name)
410 std::cout <<
"Error: ffmpeg call failed." << std::endl;
413 system((
"ffmpeg -y -r 30 -i " + frame_dir +
414 "voronoi_map%04d.png -vcodec libx264 -crf 25 -pix_fmt yuv420p " +
415 dir_name +
"/voronoi_" + video_name)
418 std::cout <<
"Error: ffmpeg call failed." << std::endl;
420 std::filesystem::remove_all(frame_dir);
423void CoverageSystem::RecordPlotData(std::vector<int>
const &robot_status,
424 std::string
const &map_name) {
426 if (map_name ==
"world") {
429 data.map = system_map_;
431 data.positions = robot_global_positions_;
432 data.positions_history = robot_positions_history_;
433 data.robot_status = robot_status;
434 ComputeVoronoiCells();
435 std::vector<std::list<Point2>> voronoi;
436 auto voronoi_cells = voronoi_.GetVoronoiCells();
437 for (
size_t i = 0; i < num_robots_; ++i) {
438 std::list<Point2> cell_points;
439 for (
auto const &pos : voronoi_cells[i].cell) {
440 cell_points.push_back(
Point2(pos[0], pos[1]));
442 cell_points.push_back(cell_points.front());
443 voronoi.push_back(cell_points);
445 data.voronoi = voronoi;
446 plotter_data_.push_back(data);
449void CoverageSystem::PlotSystemMap(std::string
const &filename)
const {
450 std::vector<int> robot_status(num_robots_, 0);
454 plotter.SetPlotName(filename);
455 plotter.PlotMap(system_map_, robot_global_positions_,
456 robot_positions_history_, robot_status,
460void CoverageSystem::PlotSystemMap(std::string
const &dir_name,
int const &step,
461 std::vector<int>
const &robot_status)
const {
465 plotter.SetPlotName(
"map", step);
466 plotter.PlotMap(system_map_, robot_global_positions_,
467 robot_positions_history_, robot_status);
470void CoverageSystem::PlotWorldMapRobots(std::string
const &dir_name,
471 std::string
const &map_name)
const {
475 plotter.SetPlotName(map_name);
476 std::vector<int> robot_status(num_robots_, 0);
477 plotter.PlotMap(
GetWorldMap(), robot_global_positions_,
478 robot_positions_history_, robot_status);
481void CoverageSystem::PlotWorldMap(std::string
const &dir_name,
482 std::string
const &map_name)
const {
486 plotter.SetPlotName(map_name);
490void CoverageSystem::PlotInitMap(std::string
const &dir_name,
491 std::string
const &map_name)
const {
495 plotter.SetPlotName(map_name);
496 plotter.PlotMap(
GetWorldMap(), robot_global_positions_);
499void CoverageSystem::PlotMapVoronoi(std::string
const &dir_name,
501 ComputeVoronoiCells();
505 plotter.SetPlotName(
"voronoi_map", step);
506 plotter.PlotMap(
GetWorldMap(), robot_global_positions_, voronoi_,
507 robot_positions_history_);
510void CoverageSystem::PlotMapVoronoi(std::string
const &dir_name,
511 int const &step, Voronoi
const &voronoi,
512 PointVector
const &goals)
const {
516 plotter.SetPlotName(
"map", step);
517 plotter.PlotMap(
GetWorldMap(), robot_global_positions_, goals, voronoi);
520void CoverageSystem::PlotFrontiers(std::string
const &dir_name,
int const &step,
521 PointVector
const &frontiers)
const {
525 plotter.SetPlotName(
"map", step);
526 plotter.PlotMap(system_map_, robot_global_positions_,
527 robot_positions_history_, frontiers);
530void CoverageSystem::PlotRobotSystemMap(std::string
const &dir_name,
531 int const &robot_id,
int const &step) {
534 plotter.SetPlotName(
"robot_" + std::to_string(robot_id) +
"_", step);
535 PointVector neighbours_positions = GetRelativePositonsNeighbors(robot_id);
536 for (Point2 &pos : neighbours_positions) {
540 plotter.PlotMap(GetRobotSystemMap(robot_id), neighbours_positions);
543void CoverageSystem::PlotRobotIDFMap(std::string
const &dir_name,
544 int const &robot_id,
int const &step) {
548 plotter.SetPlotName(
"robot_" + std::to_string(robot_id) +
"_", step);
549 plotter.PlotMap(GetRobotLocalMap(robot_id));
552void CoverageSystem::PlotRobotExplorationMap(std::string
const &dir_name,
557 plotter.SetPlotName(
"robot_exp_" + std::to_string(robot_id) +
"_", step);
558 plotter.PlotMap(GetRobotExplorationMap(robot_id));
561void CoverageSystem::PlotRobotSensorView(std::string
const &dir_name,
562 int const &robot_id,
int const &step) {
563 Plotter plotter(dir_name, params_.pSensorSize * params_.
pResolution,
565 plotter.SetPlotName(
"robot_sensor_" + std::to_string(robot_id) +
"_", step);
566 plotter.PlotMap(GetRobotSensorView(robot_id));
569void CoverageSystem::PlotRobotLocalMap(std::string
const &dir_name,
570 int const &robot_id,
int const &step) {
573 plotter.SetPlotName(
"robot_map_" + std::to_string(robot_id) +
"_", step);
574 plotter.PlotMap(GetRobotLocalMap(robot_id));
577void CoverageSystem::PlotRobotObstacleMap(std::string
const &dir_name,
582 plotter.SetPlotName(
"robot_obstacle_map_" + std::to_string(robot_id) +
"_",
584 plotter.PlotMap(GetRobotObstacleMap(robot_id));
587void CoverageSystem::PlotRobotCommunicationMaps(std::string
const &dir_name,
590 size_t const &map_size) {
591 auto robot_communication_maps = GetCommunicationMap(robot_id, map_size);
592 Plotter plotter_x(dir_name, map_size * params_.
pResolution,
594 plotter_x.SetPlotName(
595 "robot_communication_map_x_" + std::to_string(robot_id) +
"_", step);
596 plotter_x.PlotMap(robot_communication_maps.first);
597 Plotter plotter_y(dir_name, map_size * params_.
pResolution,
599 plotter_y.SetPlotName(
600 "robot_communication_map_y_" + std::to_string(robot_id) +
"_", step);
601 plotter_y.PlotMap(robot_communication_maps.second);
604PointVector CoverageSystem::GetRelativePositonsNeighbors(
605 size_t const robot_id) {
606 if (params_.pAddNoisePositions) {
608 for (Point2 &pt : noisy_positions) {
611 PointVector relative_positions;
612 for (
size_t i = 0; i < num_robots_; ++i) {
616 if ((noisy_positions[i] - noisy_positions[robot_id]).norm() <
618 relative_positions.push_back(noisy_positions[i] -
619 noisy_positions[robot_id]);
622 return relative_positions;
624 return relative_positions_neighbors_[robot_id];
627std::vector<double> CoverageSystem::GetLocalVoronoiFeatures(
628 int const robot_id) {
629 auto const &pos = robot_global_positions_[robot_id];
633 auto robot_map = robots_[robot_id].GetRobotMap();
634 auto trimmed_local_map =
635 robot_map.block(index.left + offset.left, index.bottom + offset.bottom,
636 offset.width, offset.height);
637 Point2 map_size(offset.width, offset.height);
640 (index.bottom + offset.bottom) * params_.
pResolution);
642 auto robot_neighbors_pos = GetRobotsInCommunication(robot_id);
643 PointVector robot_positions(robot_neighbors_pos.size() + 1);
645 robot_positions[0] = pos - map_translation;
647 for (
auto const &neighbor_pos : robot_neighbors_pos) {
648 robot_positions[count] = neighbor_pos - map_translation;
651 Voronoi voronoi(robot_positions, trimmed_local_map, map_size,
653 auto vcell = voronoi.GetVoronoiCell();
654 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.
bool StepControl(size_t robot_id, Point2 const &direction, double const speed)
Execute velocity control for robot_id.
bool StepRobotsToGoals(PointVector const &goals, PointVector &actions)
const MapType & GetWorldMap() const
Get the world map.
bool StepRobotToGoal(int const robot_id, Point2 const &goal, double const speed_factor=1)
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 pMaxVertices
Maximum number of vertices in a polygon.
int pRobotPosHistorySize
Number of previous positions to store.
double pCommunicationRange
Radius of communication (in meters)
Class for handling the robot model.
Class for computing Voronoi cells.
Class for Importance Density Function (IDF) for the world.
void AddNormalDistribution(BivariateNormalDistribution const &distribution)
void AddUniformDistributionPolygon(PolygonFeature const &poly_feature)
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.