Corentin Chauvin-Hameau – 2019-2020
Coverage Path Planning for an underwater robot surveying a marine farm
farm_output.cpp
Go to the documentation of this file.
1 /**
2  * @file
3  *
4  * \brief Implementation of functions publishing farm data
5  * \author Corentin Chauvin-Hameau
6  * \date 2019
7  */
8 
9 #include "farm_nodelet.hpp"
10 #include "rviz_visualisation.hpp"
11 #include "farm_common.hpp"
13 #include "mf_farm_simulator/Alga.h"
14 #include "mf_farm_simulator/Algae.h"
15 #include <std_msgs/Float32.h>
16 #include <tf2_geometry_msgs/tf2_geometry_msgs.h>
17 
18 using namespace std;
19 
20 
21 namespace mfcpp {
22 
23 void FarmNodelet::pub_rviz_markers(float duration) const
24 {
25  // Initialise common marker data
26  MarkerArgs args;
27  args.stamp = ros::Time::now();
28  args.duration = ros::Duration(duration);
29  args.frame_id = "/world";
30  args.color.r = 0.8;
31  args.color.g = 0.8;
32  args.color.b = 0.8;
33  args.color.a = 1.0;
34 
35  visualization_msgs::MarkerArray markers;
36  unsigned int nbr_assets = nbr_lines_ * (5 + nbr_algae_);
37  markers.markers.reserve(nbr_assets);
38 
39  // Add anchor markers
40  args.ns = "anchors";
41  for (unsigned int i = 0; i < nbr_lines_; i++) {
42  const AlgaeLine *al = &algae_lines_[i]; // for convenience
43 
44  markers.markers.emplace_back(
46  );
47  markers.markers.emplace_back(
49  );
50  }
51 
52  // Add buoys
53  args.ns = "buoys";
54  visualization_msgs::Marker buoys_marker;
55  pop_buoys_marker(buoys_marker, args);
56  markers.markers.emplace_back(buoys_marker);
57 
58  // Add ropes
59  args.ns = "ropes";
60  visualization_msgs::Marker line_marker;
61  pop_ropes_marker(line_marker, args);
62  markers.markers.emplace_back(line_marker);
63 
64  // Add algae
65  args.ns = "algae";
66  visualization_msgs::Marker rect_marker;
67  pop_algae_marker(rect_marker, args);
68  markers.markers.emplace_back(rect_marker);
69 
70  // Add disease heatmaps
71  if (disp_disease_) {
72  args.ns = "heatmaps";
73  visualization_msgs::Marker img_marker;
74  pop_algae_heatmaps(img_marker, args);
75  markers.markers.emplace_back(img_marker);
76  }
77 
78  // Publish the markers
79  pop_marker_ids(markers);
80  rviz_pub_.publish(markers);
81 
82 }
83 
84 void FarmNodelet::pop_buoys_marker(visualization_msgs::Marker &marker,
85  MarkerArgs args) const
86 {
87  marker = rviz_marker_spheres(buoys_diameter_, args);
88  marker.points.reserve(nbr_lines_ * nbr_buoys_);
89 
90  for (unsigned int i = 0; i < nbr_lines_; i++) {
91  const AlgaeLine *al = &algae_lines_[i]; // for convenience
92  geometry_msgs::Point point;
93  tf2::Vector3 X1 = al->floating_rope.p1;
94  tf2::Vector3 X2 = al->floating_rope.p2;
95  unsigned int n = al->nbr_buoys;
96 
97  for (unsigned int k = 0; k < n; k++) {
98  tf2::Vector3 X = X1 + float(k)/(n-1) * (X2-X1);
99  marker.points.emplace_back(tf2::toMsg(X, point));
100  }
101  }
102 }
103 
104 
105 void FarmNodelet::pop_ropes_marker(visualization_msgs::Marker &marker,
106  MarkerArgs args) const
107 {
108  marker = rviz_marker_line(thickness_ropes_, args);
109  marker.points.reserve(3 * nbr_lines_);
110 
111  for (unsigned int i = 0; i < nbr_lines_; i++) {
112  const AlgaeLine *al = &algae_lines_[i];
113  geometry_msgs::Point point;
114 
115  marker.points.emplace_back(tf2::toMsg(al->anchor1, point));
116  marker.points.emplace_back(tf2::toMsg(al->floating_rope.p1, point));
117  marker.points.emplace_back(tf2::toMsg(al->floating_rope.p2, point));
118  marker.points.emplace_back(tf2::toMsg(al->anchor2, point));
119  marker.points.emplace_back(tf2::toMsg(al->floating_rope.p1, point));
120  marker.points.emplace_back(tf2::toMsg(al->floating_rope.p2, point));
121  marker.points.emplace_back(tf2::toMsg(al->line.p1, point));
122  marker.points.emplace_back(tf2::toMsg(al->line.p2, point));
123 
124  // Ropes between the buoys and the algae line
125  unsigned int n = al->nbr_buoys;
126  tf2::Vector3 X1 = al->floating_rope.p1;
127  tf2::Vector3 X2 = al->floating_rope.p2;
128  tf2::Vector3 Y1 = al->line.p1;
129  tf2::Vector3 Y2 = al->line.p2;
130 
131  for (unsigned int k = 1; k < n-1; k++) {
132  tf2::Vector3 X = X1 + float(k)/(n-1) * (X2-X1);
133  tf2::Vector3 Y = Y1 + float(k)/(n-1) * (Y2-Y1);
134  marker.points.emplace_back(tf2::toMsg(X, point));
135  marker.points.emplace_back(tf2::toMsg(Y, point));
136  }
137  }
138 }
139 
140 
141 void FarmNodelet::pop_algae_marker(visualization_msgs::Marker &marker,
142  MarkerArgs args) const
143 {
144  marker = rviz_marker_triangles(args);
145  marker.points.reserve(2 * nbr_lines_ * nbr_algae_);
146 
147  for (unsigned int i = 0; i < nbr_lines_; i++) {
148  const AlgaeLine *al = &algae_lines_[i];
149 
150  tf2::Vector3 X1 = al->line.p1;
151  tf2::Vector3 X2 = al->line.p2;
152  tf2::Vector3 z0(0, 0, 1);
153  tf2::Vector3 y0(X2.getX()-X1.getX(), X2.getY()-X1.getY(), 0);
154  y0 /= tf2::tf2Distance(y0, tf2::Vector3(0, 0, 0));
155  float delta = asin((X2.getZ()-X1.getZ()) / length_lines_);
156 
157  tf2::Vector3 z1 = cos(delta)*z0 - sin(delta)*y0;
158  tf2::Vector3 y1 = (X2-X1) / tf2::tf2Distance(X1, X2);
159  tf2::Vector3 x1 = tf2::tf2Cross(y1, z1);
160 
161  for (unsigned int k = 0; k < al->algae.size(); k++) {
162  tf2::Vector3 X = al->algae[k].position;
163  float psi = al->algae[k].orientation;
164  float H = al->algae[k].length;
165  float W = al->algae[k].width;
166 
167  tf2::Vector3 p1 = X - W/2*y1;
168  tf2::Vector3 p2 = X + W/2*y1;
169  tf2::Vector3 p3 = p2 - H*(cos(psi)*z1 - sin(psi)*x1);
170  tf2::Vector3 p4 = p1 - H*(cos(psi)*z1 - sin(psi)*x1);
171 
172  // Add the rectangular alga as two triangles
173  geometry_msgs::Point point;
174  marker.points.emplace_back(tf2::toMsg(p1, point)); // first triangle
175  marker.points.emplace_back(tf2::toMsg(p2, point));
176  marker.points.emplace_back(tf2::toMsg(p4, point));
177 
178  marker.points.emplace_back(tf2::toMsg(p2, point)); // second triangle
179  marker.points.emplace_back(tf2::toMsg(p3, point));
180  marker.points.emplace_back(tf2::toMsg(p4, point));
181  }
182  }
183 
184  std_msgs::ColorRGBA color;
185  color.r = 0.1;
186  color.g = 0.8;
187  color.b = 0.1;
188  color.a = 1.0;
189  marker.colors.resize(marker.points.size()/3, color);
190 }
191 
192 
193 void FarmNodelet::pop_algae_heatmaps(visualization_msgs::Marker &marker,
194  MarkerArgs args) const
195 {
196  marker = rviz_marker_rect(args);
197  marker.points.reserve(nbr_lines_ * nbr_algae_
198  * 2 * height_disease_heatmap_ * width_disease_heatmap_);
199  marker.colors.reserve(nbr_lines_ * nbr_algae_
200  * 2 * height_disease_heatmap_ * width_disease_heatmap_);
201 
202  for (int k = 0; k < nbr_lines_; k++) {
203  const AlgaeLine *al = &algae_lines_[k];
204 
205  tf2::Vector3 X1 = al->line.p1;
206  tf2::Vector3 X2 = al->line.p2;
207  tf2::Vector3 z(0, 0, 1);
208  tf2::Vector3 y = (X2-X1) / tf2::tf2Distance(X1, X2);
209  tf2::Vector3 x = tf2::tf2Cross(y, z);
210 
211  for (int l = 0; l < al->algae.size(); l++) {
212  // Find the coordinates of the corners of the alga
213  tf2::Vector3 X = al->algae[l].position;
214  float psi = al->algae[l].orientation;
215  float H = al->algae[l].length;
216  float W = al->algae[l].width;
217 
218  vector<tf2::Vector3> coord(4);
219  coord[0] = X - W/2*y;
220  coord[1] = X + W/2*y;
221  coord[2] = coord[1] - H*(cos(psi)*z - sin(psi)*x);
222  coord[3] = coord[0] - H*(cos(psi)*z - sin(psi)*x);
223 
224  // Display its disease heatmap
225  pop_img_marker(marker, al->algae[l].disease_heatmap, coord);
226  }
227  }
228 
229 }
230 
231 
232 void FarmNodelet::pop_img_marker(visualization_msgs::Marker &marker,
233  vector<vector<float>> img, const vector<tf2::Vector3> &coord) const
234 {
235  int height = img.size();
236  int width;
237 
238  if (height > 0)
239  width = img[0].size();
240  else {
241  NODELET_ERROR("[farm_output] Dimensions of image not valid");
242  return;
243  }
244 
245  // coord[0] | coord[1] --> y
246  // ------------------- |
247  // coord[3] | coord[2] V x
248  tf2::Vector3 x = (coord[3]-coord[0])/height;
249  tf2::Vector3 y = (coord[1]-coord[0])/width;
250 
251  for (unsigned int i = 0; i < height; i++) {
252  tf2::Vector3 p = coord[0] + i*x; // current point
253 
254  for (unsigned int j = 0; j < width; j++) {
255  // Add the points corresponding to the triangles representing the pixel
256  geometry_msgs::Point point;
257  marker.points.emplace_back(tf2::toMsg(p, point)); // first triangle
258  marker.points.emplace_back(tf2::toMsg(p+y, point));
259  marker.points.emplace_back(tf2::toMsg(p+y+x, point));
260 
261  marker.points.emplace_back(tf2::toMsg(p, point)); // second triangle
262  marker.points.emplace_back(tf2::toMsg(p+x, point));
263  marker.points.emplace_back(tf2::toMsg(p+y+x, point));
264 
265  // Add the color
266  std_msgs::ColorRGBA color;
267  color.r = img[i][j];
268  color.g = img[i][j];
269  color.b = img[i][j];
270  color.a = 1.0;
271  marker.colors.emplace_back(color);
272  marker.colors.emplace_back(color);
273 
274  // Increment the current point
275  p += y;
276  }
277  }
278 }
279 
280 
281 void FarmNodelet::pub_algae()
282 {
283  mf_farm_simulator::Algae algae;
284  algae.algae.reserve(nbr_lines_ * nbr_algae_);
285 
286  for (unsigned int k = 0; k < nbr_lines_; k++) {
287  const AlgaeLine *al = &algae_lines_[k];
288 
289  tf2::Vector3 X1 = al->line.p1;
290  tf2::Vector3 X2 = al->line.p2;
291  tf2::Vector3 z0(0, 0, 1);
292  tf2::Vector3 y0(X2.getX()-X1.getX(), X2.getY()-X1.getY(), 0);
293  y0 /= tf2::tf2Distance(y0, tf2::Vector3(0, 0, 0));
294  float delta = asin((X2.getZ()-X1.getZ()) / length_lines_);
295 
296  tf2::Vector3 z1 = cos(delta)*z0 - sin(delta)*y0;
297  tf2::Vector3 y1 = (X2-X1) / tf2::tf2Distance(X1, X2);
298  tf2::Vector3 x1 = tf2::tf2Cross(y1, z1);
299 
300 
301  for (unsigned int l = 0; l < al->algae.size(); l++) {
302  mf_farm_simulator::Alga alga;
303 
304  // Set the orientation of the alga
305  float psi = al->algae[l].orientation;
306  float H = al->algae[l].length;
307  float W = al->algae[l].width;
308 
309  tf2::Vector3 x3 = -cos(psi)*x1 + sin(-psi)*y1;
310  tf2::Vector3 y3 = y1;
311  tf2::Vector3 z3 = -cos(psi)*z1 - sin(-psi)*x1;
312 
313 
314  tf2::Matrix3x3 rotation(x3.getX(), x3.getY(), x3.getZ(),
315  y3.getX(), y3.getY(), y3.getZ(),
316  z3.getX(), z3.getY(), z3.getZ());
317  tf2::Quaternion quati;
318  double R, P, Y;
319  rotation.getRPY(R, P, Y, 2);
320  quati.setRPY(R, -P, Y);
321  alga.orientation = tf2::toMsg(quati);
322 
323  // Set the position of the alga
324  tf2::Vector3 X = al->algae[l].position;
325  alga.position = vector3_to_point32(X + H/2*z3);
326 
327  // Set the dimensions of the alga
328  alga.dimensions.x = thickness_algae_;
329  alga.dimensions.y = W;
330  alga.dimensions.z = H;
331 
332  // Set the disease heatmap of the alga
333  int n_height = height_disease_heatmap_;
334  int n_width = width_disease_heatmap_;
335 
336  alga.disease_heatmap.resize(n_height);
337  for (unsigned int i = 0; i < n_height; i++)
338  alga.disease_heatmap[i].data.resize(n_width);
339 
340  for (unsigned int i = 0; i < n_height; i++) {
341  for (unsigned int j = 0; j < n_width; j++) {
342  alga.disease_heatmap[i].data[j] = al->algae[l].disease_heatmap[i][j];
343  }
344  }
345 
346  // Add the alga
347  algae.algae.emplace_back(alga);
348  }
349  }
350 
351  algae_pub_.publish(algae);
352 }
353 
354 
355 } // namespace mfcpp
Definition: common.hpp:23
Declaration of 2D perlin noise generator.
Rope floating_rope
Rope on wich the buoys are.
Definition: farm_common.hpp:61
visualization_msgs::Marker rviz_marker_line(float thickness, const MarkerArgs &common_args)
Creates a blank Rviz marker to display lines.
Declaration of common structures and functions for farm simulator.
Arguments used to create a Rviz maker.
ros::Time stamp
Time stamp for the ROS message.
float anchors_diameter
Anchors diameter.
Definition: farm_common.hpp:65
tf2::Vector3 anchor1
First anchor.
Definition: farm_common.hpp:62
void pop_marker_ids(visualization_msgs::MarkerArray &array)
Populates id of all the markers in a marker array.
tf2::Vector3 anchor2
Second anchor.
Definition: farm_common.hpp:63
std::string frame_id
Frame in which position/orientation of the object is.
Declaration of common Rviz display functions.
std::vector< Alga > algae
List of algae hanging on the line.
Definition: farm_common.hpp:69
visualization_msgs::Marker rviz_marker_rect(const MarkerArgs &common_args)
Creates a blank Rviz marker to display rectangles.
Declaration of nodelet for managing the farm simulation.
geometry_msgs::Point32 vector3_to_point32(tf2::Vector3 p)
Convert a tf2::Vector3 to a geometry_msgs::Point32.
visualization_msgs::Marker rviz_marker_cylinder(tf2::Vector3 p, float diameter, float height, const MarkerArgs &common_args)
Creates a Rviz marker to display a cylinder.
tf2::Vector3 p1
Position of the first extremity of the rope.
Definition: farm_common.hpp:25
tf2::Vector3 p2
Position of the second extremity of the rope.
Definition: farm_common.hpp:26
Rope line
Rope on wich the algae grow.
Definition: farm_common.hpp:60
visualization_msgs::Marker rviz_marker_triangles(const MarkerArgs &common_args)
Creates a blank Rviz marker to display triangles.
unsigned int nbr_buoys
Number of buoys on the floating rope.
Definition: farm_common.hpp:67
ros::Duration duration
Duration of the marker (in sec)
float anchors_height
Anchors height.
Definition: farm_common.hpp:66
Line on which algae grow.
Definition: farm_common.hpp:58
visualization_msgs::Marker rviz_marker_spheres(float thickness, const MarkerArgs &common_args)
Creates a blank Rviz marker to display spheres.
std::string ns
Namespace for the Rviz marker.
std_msgs::ColorRGBA color
Color of the marker.