Corentin Chauvin-Hameau – 2019-2020
Coverage Path Planning for an underwater robot surveying a marine farm
gp_nodelet.cpp
Go to the documentation of this file.
1 /**
2  * @file
3  *
4  * \brief Definition of a nodelet for a Gaussian Process mapping an
5  * algae wall
6  * \author Corentin Chauvin-Hameau
7  * \date 2019
8  */
9 
10 #include "gp_nodelet.hpp"
11 #include "mf_common/Array2D.h"
12 #include "mf_common/Float32Array.h"
13 #include "mf_mapping/UpdateGP.h"
14 #include "mf_mapping/LoadGP.h"
15 #include "mf_sensors_simulator/CameraOutput.h"
16 #include <sensor_msgs/Image.h>
17 #include <geometry_msgs/TransformStamped.h>
18 #include <geometry_msgs/Pose.h>
19 #include <std_msgs/Float32.h>
20 #include <tf2_geometry_msgs/tf2_geometry_msgs.h>
21 #include <pluginlib/class_list_macros.h>
22 #include <ros/ros.h>
23 #include <eigen3/Eigen/Dense>
24 #include <string>
25 #include <vector>
26 #include <iostream>
27 
28 using namespace std;
29 
30 PLUGINLIB_EXPORT_CLASS(mfcpp::GPNodelet, nodelet::Nodelet)
31 
32 
33 namespace mfcpp {
34 
35 /*
36  * Definition of static variables
37  */
38 sig_atomic_t volatile GPNodelet::b_sigint_ = 0;
39 ros::Timer GPNodelet::main_timer_ = ros::Timer();
40 
41 /*
42  * Definition of member functions
43  */
44 GPNodelet::GPNodelet():
45  tf_listener_(tf_buffer_)
46 {
47 
48 }
49 
51 
52 
54 {
55  nh_ = getNodeHandle();
56  private_nh_ = getPrivateNodeHandle();
57 
58  // Catch SIGINT (Ctrl+C) stop signal
59  struct sigaction sigIntHandler;
60  sigIntHandler.sa_handler = GPNodelet::sigint_handler;
61  sigemptyset(&sigIntHandler.sa_mask);
62  sigIntHandler.sa_flags = 0;
63  sigaction(SIGINT, &sigIntHandler, NULL);
64 
65  // ROS parameters
66  private_nh_.param<float>("main_freq", main_freq_, 1.0);
67  private_nh_.param<string>("wall_frame", wall_frame_, "wall");
68  private_nh_.param<string>("camera_frame", camera_frame_, "camera");
69  private_nh_.param<float>("camera_var", camera_var_, 1.0);
70  private_nh_.param<float>("camera_decay", camera_decay_, 1.0);
71  private_nh_.param<float>("matern_length", matern_length_, 1.0);
72  private_nh_.param<float>("matern_var", matern_var_, 1.0);
73  private_nh_.param<float>("matern_thresh", matern_thresh_, 0.001);
74  private_nh_.param<float>("gp_init_mean", gp_init_mean_, 1.0);
75  private_nh_.param<float>("gp_noise_var", gp_noise_var_, 1.0);
76  private_nh_.param<float>("gp_cov_thresh", gp_cov_thresh_, 0.0);
77  private_nh_.param<float>("out_scale", out_scale_, 1.0);
78  private_nh_.param<float>("size_wall_x", size_wall_x_, 2.0);
79  private_nh_.param<float>("size_wall_y", size_wall_y_, 30.0);
80  private_nh_.param<int>("size_gp_x", size_gp_x_, 2);
81  private_nh_.param<int>("size_gp_y", size_gp_y_, 30);
82  private_nh_.param<int>("size_img_x", size_img_x_, 40);
83  private_nh_.param<int>("size_img_y", size_img_y_, 600);
84 
85  // Other variables
86  camera_msg_available_ = false;
87  tf_got_ = false;
88  gp_initialised_ = false;
89  gp_loaded_ = false;
90  delta_x_ = size_wall_x_ / (size_gp_x_-1);
91  delta_y_ = size_wall_y_ / (size_gp_y_-1);
92  size_gp_ = size_gp_x_ * size_gp_y_;
93  size_img_ = size_img_x_ * size_img_y_;
94  out_values_.resize(size_img_, 0.5);
95  changed_pxl_.resize(size_img_, false);
96 
97  radius_obs_ = -matern_length_/sqrt(3)
98  * (lambert_wm1(-matern_thresh_/(exp(1)*matern_var_)) + 1);
99 
100  // ROS subscribers
101  camera_sub_ = nh_.subscribe<mf_sensors_simulator::CameraOutput>("camera_out", 1, &GPNodelet::camera_cb, this);
102 
103  // ROS publishers
104  wall_img_pub_ = nh_.advertise<sensor_msgs::Image>("gp_wall_img", 0);
105  cov_img_pub_ = nh_.advertise<sensor_msgs::Image>("gp_cov_img", 0);
106  gp_mean_pub_ = nh_.advertise<mf_common::Float32Array>("gp_mean", 0);
107  gp_cov_pub_ = nh_.advertise<mf_common::Array2D>("gp_cov", 0);
108  gp_eval_pub_ = nh_.advertise<mf_common::Array2D>("gp_eval", 0);
109 
110  // ROS services
111  update_gp_serv_ = nh_.advertiseService("update_gp", &GPNodelet::update_gp_cb, this);
112  load_gp_serv_ = nh_.advertiseService("load_gp", &GPNodelet::load_gp_cb, this);
113 
114 
115  // Main loop
116  main_timer_ = private_nh_.createTimer(
117  ros::Duration(1/main_freq_), &GPNodelet::main_cb, this
118  );
119 }
120 
121 
122 void GPNodelet::main_cb(const ros::TimerEvent &timer_event)
123 {
124  if (!ros::ok() || ros::isShuttingDown() || b_sigint_)
125  return;
126 
127  tf_got_ = get_tf();
128 
129  if (!gp_initialised_) {
130  NODELET_INFO("[gp_nodelet] Initialisation of Gaussian Process...");
131  init_gp();
132  gp_initialised_ = true;
133 
134  NODELET_INFO("[gp_nodelet] Gaussian Process initialised.");
135  }
136  else if (camera_msg_available_) {
137  if (gp_loaded_) {
138  // Don't update using measurement, the GP has been manually loaded
139  gp_loaded_ = false;
140  } else {
141  // Prepare input data
142  vector<float> x, y, z;
144  x, y, z, camera_msg_->header.frame_id, wall_frame_);
145 
146  vector<float> distances(x.size());
147  for (unsigned int k = 0; k < x.size(); k++) {
148  distances[k] = Eigen::Vector3f(camera_msg_->x[k],
149  camera_msg_->y[k],
150  camera_msg_->z[k]).norm();
151  }
152 
153  // Update the Gaussian Process
154  RectArea obs_coord; // coordinates of the rectangular area of the observed state
155  update_gp(x, y, z, distances, camera_msg_->value, gp_mean_, gp_cov_, idx_obs_,
156  obs_coord);
157 
158  notif_changing_pxls(obs_coord); // notified changed pixels
159  }
160 
161  // Publish output
162  publish_gp_state(); // publish mean and covariance of the GP
163  publish_gp_eval(); // publish evaluated GP and covariance
164 
165  camera_msg_available_ = false;
166  }
167 }
168 
169 
171  b_sigint_ = 1;
172  main_timer_.stop();
173 
174  raise(SIGTERM);
175 }
176 
177 
178 void GPNodelet::camera_cb(const mf_sensors_simulator::CameraOutput::ConstPtr &msg)
179 {
180  if (msg->x.size() > 0) {
181  camera_msg_ = msg;
182  camera_msg_available_ = true;
183  }
184 }
185 
186 
188 {
189  geometry_msgs::TransformStamped transform;
190 
191  try {
192  transform = tf_buffer_.lookupTransform(wall_frame_, camera_frame_, ros::Time(0));
193  }
194  catch (tf2::TransformException &ex) {
195  NODELET_WARN("[gp_nodelet] %s", ex.what());
196  return false;
197  }
198 
199  wall_camera_tf_ = transform;
200  return true;
201 }
202 
203 
204 bool GPNodelet::update_gp_cb(mf_mapping::UpdateGP::Request &req,
205  mf_mapping::UpdateGP::Response &res)
206 {
207  // Check input data validity and initialisation
208  if (req.update_mean && !req.use_internal_mean && req.mean.size() != size_gp_) {
209  NODELET_WARN("[gp_nodelet] Input mean of the wrong size");
210  return false;
211  }
212 
213  if (!req.use_internal_cov && req.cov.size() != size_gp_) {
214  NODELET_WARN("[gp_nodelet] Input covariance of the wrong size");
215  return false;
216  }
217 
218  if (!tf_got_)
219  return false;
220 
221  // Parse the input GP mean and covariance
222  Eigen::VectorXf mean(size_gp_);
223  Eigen::MatrixXf cov(size_gp_, size_gp_);
224 
225  if (!req.update_mean || req.use_internal_mean)
226  mean = gp_mean_;
227  else {
228  for (int k = 0; k < size_gp_; k++) {
229  mean(k) = req.mean[k];
230  }
231  }
232 
233  if (req.use_internal_cov)
234  cov = gp_cov_;
235  else {
236  for (int i = 0; i < size_gp_; i++) {
237  for (int j = 0; j <= i; j++) {
238  cov(i, j) = req.cov[i].data[j];
239  cov(j, i) = cov(i, j);
240  }
241  }
242  }
243 
244  // Get wall to camera ROS transform
245  geometry_msgs::TransformStamped wall_camera_tf;
246 
247  try {
248  wall_camera_tf = tf_buffer_.lookupTransform(wall_frame_, camera_frame_, req.stamp);
249  }
250  catch (tf2::TransformException &ex) {
251  NODELET_WARN("[gp_nodelet] %s", ex.what());
252  return false;
253  }
254 
255  // Parse the input sets of measurements
256  int n_meas = req.meas.size(); // number of sets of measurements
257  vector<vector<float>> x_meas(n_meas), y_meas(n_meas), z_meas(n_meas);
258  vector<vector<float>> values(n_meas), distances(n_meas);
259 
260  for (int k = 0; k < n_meas; k++) {
261  vector<float> x = req.meas[k].x;
262  vector<float> y = req.meas[k].y;
263  vector<float> z = req.meas[k].z;
264  transform_points(x, y, z, x_meas[k], y_meas[k], z_meas[k], wall_camera_tf);
265 
266  values[k] = req.meas[k].value;
267  distances[k] = req.meas[k].distance;
268  }
269 
270  // Update and evaluate the given Gaussian Processes
271  res.new_mean.resize(n_meas);
272  res.new_cov.resize(n_meas);
273  res.new_cov_diag.resize(n_meas);
274  res.eval_values.resize(n_meas);
275 
276  vector<unsigned int> idx_obs; // array of corresponding indices for obs states
277  RectArea obs_coord; // (won't be used)
278 
279  for (int k = 0; k < n_meas; k++) {
280  // Update and evaluate the GP
281  update_gp(x_meas[k], y_meas[k], z_meas[k], distances[k], values[k],
282  mean, cov, idx_obs, obs_coord, req.update_mean);
283 
284  if (req.eval_gp) {
285  int size_meas = x_meas[k].size();
286  res.eval_values[k].data.resize(size_meas);
287  Eigen::VectorXf x_obs, y_obs, W; // necessary objects for evaluation
288  prepare_eval(idx_obs, mean, x_obs, y_obs, W);
289 
290  for (int l = 0; l < size_meas; l++) {
291  res.eval_values[k].data[l] = eval_gp(x_meas[k][l], y_meas[k][l],
292  x_obs, y_obs, W);
293  }
294  }
295 
296  // Fill the outputs
297  if (req.update_mean) {
298  res.new_mean[k].data.resize(size_gp_);
299 
300  for (int l = 0; l < size_gp_; l++) {
301  res.new_mean[k].data[l] = mean(l);
302  }
303  }
304 
305  if (req.return_cov_diag) {
306  res.new_cov_diag[k].data.resize(size_gp_);
307 
308  for (int l = 0; l < size_gp_; l++) {
309  res.new_cov_diag[k].data[l] = cov(l, l);
310  }
311  } else {
312  res.new_cov[k].data.resize(size_gp_);
313 
314  for (int i = 0; i < size_gp_; i++) {
315  res.new_cov[k].data[i].data.resize(size_gp_);
316 
317  for (int j = 0; j <= size_gp_; j++) {
318  res.new_cov[k].data[i].data[j] = cov(i, j);
319  }
320  }
321  }
322  }
323 }
324 
325 
326 bool GPNodelet::load_gp_cb(mf_mapping::LoadGP::Request &req,
327  mf_mapping::LoadGP::Response &res)
328 {
329  // Check GP has been initialised
330  if (!gp_initialised_) {
331  res.gp_not_yet_init = true;
332  res.gp_loaded = false;
333  return true;
334  } else {
335  res.gp_not_yet_init = false;
336  }
337 
338  // Check input validity
339  if (req.mean.size() != size_gp_) {
340  ROS_WARN("[gp_nodelet] Trying to load the GP with the wrong size (given: %d, expected: %d)",
341  (int)req.mean.size(), size_gp_);
342 
343  res.gp_loaded = false;
344  return true;
345  }
346 
347  // Set GP mean and covariance
348  for (int k = 0; k < size_gp_; k++) {
349  gp_mean_[k] = req.mean[k];
350  }
351 
352  if (req.init_cov) {
353  gp_cov_ = Eigen::MatrixXf::Zero(size_gp_, size_gp_);
354 
355  for (unsigned int k = 0; k < size_gp_; k++) {
356  gp_cov_(k, k) = 1/gp_noise_var_;
357  }
358  }
359 
360  // Notify changed pixels (all pixels)
361  for (int k = 0; k < changed_pxl_.size(); k++) {
362  changed_pxl_[k] = true;
363  }
364 
365  idx_obs_.resize(size_gp_);
366  for (int k = 0; k < size_gp_; k++) {
367  idx_obs_[k] = k;
368  }
369 
370  // Return values
371  gp_loaded_ = true;
372  res.gp_loaded = true;
373  return true;
374 }
375 
376 
377 bool GPNodelet::transform_points(const vec_f &x_in, const vec_f &y_in, const vec_f &z_in,
378  vec_f &x_out, vec_f &y_out, vec_f &z_out, string frame_in, string frame_out)
379 {
380  // Get the tf transform
381  geometry_msgs::TransformStamped transform;
382 
383  try {
384  transform = tf_buffer_.lookupTransform(frame_out, frame_in, ros::Time(0));
385  }
386  catch (tf2::TransformException &ex) {
387  NODELET_WARN("[gp_nodelet] %s",ex.what());
388  return false;
389  }
390 
391  // Transform the points
392  return transform_points(x_in, y_in, z_in, x_out, y_out, z_out, transform);
393 }
394 
395 
396 bool GPNodelet::transform_points(const vec_f &x_in, const vec_f &y_in, const vec_f &z_in,
397  vec_f &x_out, vec_f &y_out, vec_f &z_out, const geometry_msgs::TransformStamped &transform)
398 {
399  unsigned int n = x_in.size();
400  x_out.resize(n);
401  y_out.resize(n);
402  z_out.resize(n);
403 
404  for (unsigned int k = 0; k < n; k++) {
405  geometry_msgs::Pose p_in, p_out;
406  p_in.position.x = x_in[k];
407  p_in.position.y = y_in[k];
408  p_in.position.z = z_in[k];
409 
410  tf2::doTransform(p_in, p_out, transform);
411 
412  x_out[k] = p_out.position.x;
413  y_out[k] = p_out.position.y;
414  z_out[k] = p_out.position.z;
415  }
416 
417  return true;
418 }
419 
420 
421 double GPNodelet::lambert_w0(double z, double precision, double init_w) const
422 {
423  // Handle out of bound case
424  if (z < 0) {
425  NODELET_WARN("[gp_nodelet] Calling lambert_w0 with z=%f", z);
426  return 0;
427  }
428 
429  // Apply Newton's method
430  return lambert_w(z, precision, init_w);
431 }
432 
433 
434 double GPNodelet::lambert_wm1(double z, double precision, double init_w) const
435 {
436  // Handle out of bound case
437  if (z < -1/exp(1) || z >= 0) {
438  NODELET_WARN("[gp_nodelet] Calling lambert_wm1 with z=%f", z);
439  return 0;
440  }
441 
442  // Apply Newton's method
443  return lambert_w(z, precision, init_w);
444 }
445 
446 
447 double GPNodelet::lambert_w(double z, double precision, double init_w) const
448 {
449  double w = init_w;
450  double last_w = w;
451  double delta;
452  int safe_count = 100;
453 
454  do {
455  w = w - (w*exp(w) - z) / (exp(w) + w*exp(w));
456  delta = abs(last_w - w);
457  last_w = w;
458  } while (delta > precision && safe_count-- > 0);
459 
460  if (safe_count == 0)
461  NODELET_WARN("[gp_nodelet] lambert_w0(%f) fails to converge, throwing intermediary result w=%f anyway.", z, w);
462 
463  return w;
464 }
465 
466 
467 
468 
469 
470 } // namespace mfcpp
tf2_ros::Buffer tf_buffer_
Tf2 buffer for getting tf transforms.
Definition: gp_nodelet.hpp:77
Definition: common.hpp:23
ros::Publisher cov_img_pub_
Publisher for an image of the GP covariance.
Definition: gp_nodelet.hpp:71
void prepare_eval(const std::vector< unsigned int > &idx_obs, const Eigen::VectorXf &gp_mean, Eigen::VectorXf &x_obs, Eigen::VectorXf &y_obs, Eigen::VectorXf &W) const
Prepares objects needed for Gaussian Process evaluation.
Definition: gp.cpp:358
geometry_msgs::TransformStamped wall_camera_tf_
Definition: gp_nodelet.hpp:89
float size_wall_x_
Size (m) of the algae wall in the x direction.
Definition: gp_nodelet.hpp:120
ros::Publisher gp_mean_pub_
Publisher for the GP mean.
Definition: gp_nodelet.hpp:72
float main_freq_
Frequency of the main loop.
Definition: gp_nodelet.hpp:104
void camera_cb(const mf_sensors_simulator::CameraOutputConstPtr &msg)
Callback for the camera output.
Definition: gp_nodelet.cpp:178
static ros::Timer main_timer_
Timer callback for the main function.
Definition: gp_nodelet.hpp:64
float gp_noise_var_
Noise variance of the Gaussian Process.
Definition: gp_nodelet.hpp:115
double lambert_w(double z, double precision, double init_w) const
Applies Netwton&#39;s method to evaluate Lambert W function.
Definition: gp_nodelet.cpp:447
bool update_gp_cb(mf_mapping::UpdateGP::Request &req, mf_mapping::UpdateGP::Response &res)
Service to update the Gaussian Process for several sets of measurements.
Definition: gp_nodelet.cpp:204
ros::Subscriber camera_sub_
Subscriber for the camera.
Definition: gp_nodelet.hpp:69
float delta_y_
Increment (m) in the y direction.
Definition: gp_nodelet.hpp:86
float gp_init_mean_
Initial mean values of the Gaussian Process.
Definition: gp_nodelet.hpp:114
double lambert_w0(double z, double precision=0.01, double init_w=1.0) const
Evaluates the Lambert W (0 branch) function.
Definition: gp_nodelet.cpp:421
float matern_thresh_
Threshold to consider that the kernel value is 0.
Definition: gp_nodelet.hpp:113
Eigen::VectorXf gp_mean_
Mean of the Gaussian Process.
Definition: gp_nodelet.hpp:92
ros::NodeHandle nh_
Node handler (for topics and services)
Definition: gp_nodelet.hpp:67
float camera_var_
Max variance on camera measurements.
Definition: gp_nodelet.hpp:108
unsigned int size_gp_
Total size of the Gaussian Process.
Definition: gp_nodelet.hpp:87
ros::ServiceServer update_gp_serv_
Service server for updating the GP.
Definition: gp_nodelet.hpp:75
int size_img_x_
Size of the output image in the x direction.
Definition: gp_nodelet.hpp:124
std::vector< bool > changed_pxl_
Whether an output pixel has been updated.
Definition: gp_nodelet.hpp:100
unsigned int size_img_
Total size of the image.
Definition: gp_nodelet.hpp:88
ros::Publisher wall_img_pub_
Publisher for an image of the wall GP.
Definition: gp_nodelet.hpp:70
bool gp_initialised_
Whether the Gaussian Process is initialised.
Definition: gp_nodelet.hpp:80
double lambert_wm1(double z, double precision=0.01, double init_w=-2.0) const
Evaluates the Lambert W (-1 branch) function.
Definition: gp_nodelet.cpp:434
virtual void onInit()
Function called at beginning of nodelet execution.
Definition: gp_nodelet.cpp:53
float size_wall_y_
Size (m) of the algae wall in the y direction.
Definition: gp_nodelet.hpp:121
static void sigint_handler(int s)
SINGINT (Ctrl+C) callback to stop the nodelet properly.
Definition: gp_nodelet.cpp:170
ros::Publisher gp_eval_pub_
Publisher for the evaluated GP over the wall.
Definition: gp_nodelet.hpp:74
float matern_var_
Signal variance of the Matern kernel.
Definition: gp_nodelet.hpp:112
void init_gp()
Initialises the Gaussian Process.
Definition: gp.cpp:21
static sig_atomic_t volatile b_sigint_
Whether SIGINT signal has been received.
Definition: gp_nodelet.hpp:63
float eval_gp(float x, float y, const Eigen::VectorXf &x_obs, const Eigen::VectorXf &y_obs, const Eigen::VectorXf &W) const
Evaluates the Gaussian Process at a given point.
Definition: gp.cpp:385
float delta_x_
Increment (m) in the x direction.
Definition: gp_nodelet.hpp:85
bool tf_got_
Whether transforms have been retrieved.
Definition: gp_nodelet.hpp:83
2D rectangular area
Definition: gp_nodelet.hpp:51
bool load_gp_cb(mf_mapping::LoadGP::Request &req, mf_mapping::LoadGP::Response &res)
Service to load the Gaussian Process mean.
Definition: gp_nodelet.cpp:326
std::string wall_frame_
Name of the wall frame.
Definition: gp_nodelet.hpp:105
Nodelet for a Gaussian Process mapping an algae wall.
Definition: gp_nodelet.hpp:32
std::vector< unsigned int > idx_obs_
Array of corresponding indices for observed states.
Definition: gp_nodelet.hpp:96
std::vector< float > out_values_
Output values of the Gaussian Process.
Definition: gp_nodelet.hpp:99
Declaration of a nodelet for Gaussian Process mapping of an algae wall.
bool gp_loaded_
Whether the GP has been loaded from an external source.
Definition: gp_nodelet.hpp:81
void update_gp(const vec_f &x_meas, const vec_f &y_meas, const vec_f &z_meas, const vec_f &distances, const vec_f &values, Eigen::VectorXf &gp_mean, Eigen::MatrixXf &gp_cov, std::vector< unsigned int > &idx_obs, RectArea &obs_coord, bool update_mean=true) const
Updates the Gaussian Process given measured data points.
Definition: gp.cpp:234
Eigen::MatrixXf gp_cov_
Covariance of the Gaussian Process.
Definition: gp_nodelet.hpp:93
void publish_gp_state()
Publishes mean and covariance of the Gaussian Process.
Definition: gp_output.cpp:26
float radius_obs_
Radius of influence of an observation on the GP.
Definition: gp_nodelet.hpp:90
void main_cb(const ros::TimerEvent &timer_event)
Main callback which is called by a timer.
Definition: gp_nodelet.cpp:122
void notif_changing_pxls(const RectArea &coord)
Notifies changing pixels during GP update.
Definition: gp.cpp:107
void publish_gp_eval()
Publishes the evaluated GP and its covariance.
Definition: gp_output.cpp:50
bool get_tf()
Gets necessary tf transforms.
Definition: gp_nodelet.cpp:187
std::vector< float > vec_f
Definition: gp_nodelet.hpp:59
ros::ServiceServer load_gp_serv_
Service server for loading the GP.
Definition: gp_nodelet.hpp:76
mf_sensors_simulator::CameraOutput::ConstPtr camera_msg_
Last camera message.
Definition: gp_nodelet.hpp:84
ros::NodeHandle private_nh_
Private node handler (for parameters)
Definition: gp_nodelet.hpp:68
ros::Publisher gp_cov_pub_
Publisher for the GP covariance.
Definition: gp_nodelet.hpp:73
float matern_length_
Lengthscale of the Matern kernel.
Definition: gp_nodelet.hpp:111
int size_gp_x_
Size of the Gaussian Process mean in the x direction.
Definition: gp_nodelet.hpp:122
bool camera_msg_available_
Whether a new camera message is available.
Definition: gp_nodelet.hpp:82
bool transform_points(const vec_f &x_in, const vec_f &y_in, const vec_f &z_in, vec_f &x_out, vec_f &y_out, vec_f &z_out, std::string frame_in, std::string frame_out)
Transforms points from one frame to another.
float gp_cov_thresh_
Threshold to consider a value as 0 in the covariance.
Definition: gp_nodelet.hpp:116
float camera_decay_
Exponential decay rate on camera measurements.
Definition: gp_nodelet.hpp:109
std::string camera_frame_
Name of the camera frame.
Definition: gp_nodelet.hpp:106
int size_gp_y_
Size of the Gaussian Process mean in the y direction.
Definition: gp_nodelet.hpp:123