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> 23 #include <eigen3/Eigen/Dense> 38 sig_atomic_t
volatile GPNodelet::b_sigint_ = 0;
39 ros::Timer GPNodelet::main_timer_ = ros::Timer();
44 GPNodelet::GPNodelet():
45 tf_listener_(tf_buffer_)
55 nh_ = getNodeHandle();
59 struct sigaction sigIntHandler;
61 sigemptyset(&sigIntHandler.sa_mask);
62 sigIntHandler.sa_flags = 0;
63 sigaction(SIGINT, &sigIntHandler, NULL);
90 delta_x_ = size_wall_x_ / (size_gp_x_-1);
91 delta_y_ = size_wall_y_ / (size_gp_y_-1);
98 * (
lambert_wm1(-matern_thresh_/(exp(1)*matern_var_)) + 1);
124 if (!ros::ok() || ros::isShuttingDown() ||
b_sigint_)
130 NODELET_INFO(
"[gp_nodelet] Initialisation of Gaussian Process...");
134 NODELET_INFO(
"[gp_nodelet] Gaussian Process initialised.");
142 vector<float> x, y, z;
146 vector<float> distances(x.size());
147 for (
unsigned int k = 0; k < x.size(); k++) {
180 if (msg->x.size() > 0) {
189 geometry_msgs::TransformStamped transform;
194 catch (tf2::TransformException &ex) {
195 NODELET_WARN(
"[gp_nodelet] %s", ex.what());
205 mf_mapping::UpdateGP::Response &res)
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");
213 if (!req.use_internal_cov && req.cov.size() !=
size_gp_) {
214 NODELET_WARN(
"[gp_nodelet] Input covariance of the wrong size");
225 if (!req.update_mean || req.use_internal_mean)
228 for (
int k = 0; k <
size_gp_; k++) {
229 mean(k) = req.mean[k];
233 if (req.use_internal_cov)
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);
245 geometry_msgs::TransformStamped wall_camera_tf;
250 catch (tf2::TransformException &ex) {
251 NODELET_WARN(
"[gp_nodelet] %s", ex.what());
256 int n_meas = req.meas.size();
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);
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;
266 values[k] = req.meas[k].value;
267 distances[k] = req.meas[k].distance;
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);
276 vector<unsigned int> idx_obs;
279 for (
int k = 0; k < n_meas; k++) {
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);
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;
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],
297 if (req.update_mean) {
298 res.new_mean[k].data.resize(
size_gp_);
300 for (
int l = 0; l <
size_gp_; l++) {
301 res.new_mean[k].data[l] = mean(l);
305 if (req.return_cov_diag) {
306 res.new_cov_diag[k].data.resize(
size_gp_);
308 for (
int l = 0; l <
size_gp_; l++) {
309 res.new_cov_diag[k].data[l] = cov(l, l);
312 res.new_cov[k].data.resize(
size_gp_);
314 for (
int i = 0; i <
size_gp_; i++) {
315 res.new_cov[k].data[i].data.resize(size_gp_);
317 for (
int j = 0; j <=
size_gp_; j++) {
318 res.new_cov[k].data[i].data[j] = cov(i, j);
327 mf_mapping::LoadGP::Response &res)
331 res.gp_not_yet_init =
true;
332 res.gp_loaded =
false;
335 res.gp_not_yet_init =
false;
340 ROS_WARN(
"[gp_nodelet] Trying to load the GP with the wrong size (given: %d, expected: %d)",
343 res.gp_loaded =
false;
348 for (
int k = 0; k <
size_gp_; k++) {
353 gp_cov_ = Eigen::MatrixXf::Zero(size_gp_, size_gp_);
355 for (
unsigned int k = 0; k <
size_gp_; k++) {
366 for (
int k = 0; k <
size_gp_; k++) {
372 res.gp_loaded =
true;
378 vec_f &x_out,
vec_f &y_out,
vec_f &z_out,
string frame_in,
string frame_out)
381 geometry_msgs::TransformStamped transform;
384 transform =
tf_buffer_.lookupTransform(frame_out, frame_in, ros::Time(0));
386 catch (tf2::TransformException &ex) {
387 NODELET_WARN(
"[gp_nodelet] %s",ex.what());
397 vec_f &x_out,
vec_f &y_out,
vec_f &z_out,
const geometry_msgs::TransformStamped &transform)
399 unsigned int n = x_in.size();
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];
410 tf2::doTransform(p_in, p_out, transform);
412 x_out[k] = p_out.position.x;
413 y_out[k] = p_out.position.y;
414 z_out[k] = p_out.position.z;
425 NODELET_WARN(
"[gp_nodelet] Calling lambert_w0 with z=%f", z);
437 if (z < -1/exp(1) || z >= 0) {
438 NODELET_WARN(
"[gp_nodelet] Calling lambert_wm1 with z=%f", z);
452 int safe_count = 100;
455 w = w - (w*exp(w) - z) / (exp(w) + w*exp(w));
456 delta = abs(last_w - w);
458 }
while (delta > precision && safe_count-- > 0);
461 NODELET_WARN(
"[gp_nodelet] lambert_w0(%f) fails to converge, throwing intermediary result w=%f anyway.", z, w);
tf2_ros::Buffer tf_buffer_
Tf2 buffer for getting tf transforms.
ros::Publisher cov_img_pub_
Publisher for an image of the GP covariance.
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.
geometry_msgs::TransformStamped wall_camera_tf_
float size_wall_x_
Size (m) of the algae wall in the x direction.
ros::Publisher gp_mean_pub_
Publisher for the GP mean.
float main_freq_
Frequency of the main loop.
void camera_cb(const mf_sensors_simulator::CameraOutputConstPtr &msg)
Callback for the camera output.
static ros::Timer main_timer_
Timer callback for the main function.
float gp_noise_var_
Noise variance of the Gaussian Process.
double lambert_w(double z, double precision, double init_w) const
Applies Netwton's method to evaluate Lambert W function.
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.
ros::Subscriber camera_sub_
Subscriber for the camera.
float delta_y_
Increment (m) in the y direction.
float gp_init_mean_
Initial mean values of the Gaussian Process.
double lambert_w0(double z, double precision=0.01, double init_w=1.0) const
Evaluates the Lambert W (0 branch) function.
float matern_thresh_
Threshold to consider that the kernel value is 0.
Eigen::VectorXf gp_mean_
Mean of the Gaussian Process.
ros::NodeHandle nh_
Node handler (for topics and services)
float camera_var_
Max variance on camera measurements.
unsigned int size_gp_
Total size of the Gaussian Process.
ros::ServiceServer update_gp_serv_
Service server for updating the GP.
int size_img_x_
Size of the output image in the x direction.
std::vector< bool > changed_pxl_
Whether an output pixel has been updated.
unsigned int size_img_
Total size of the image.
ros::Publisher wall_img_pub_
Publisher for an image of the wall GP.
bool gp_initialised_
Whether the Gaussian Process is initialised.
double lambert_wm1(double z, double precision=0.01, double init_w=-2.0) const
Evaluates the Lambert W (-1 branch) function.
virtual void onInit()
Function called at beginning of nodelet execution.
float size_wall_y_
Size (m) of the algae wall in the y direction.
static void sigint_handler(int s)
SINGINT (Ctrl+C) callback to stop the nodelet properly.
ros::Publisher gp_eval_pub_
Publisher for the evaluated GP over the wall.
float matern_var_
Signal variance of the Matern kernel.
void init_gp()
Initialises the Gaussian Process.
static sig_atomic_t volatile b_sigint_
Whether SIGINT signal has been received.
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.
float delta_x_
Increment (m) in the x direction.
bool tf_got_
Whether transforms have been retrieved.
bool load_gp_cb(mf_mapping::LoadGP::Request &req, mf_mapping::LoadGP::Response &res)
Service to load the Gaussian Process mean.
std::string wall_frame_
Name of the wall frame.
Nodelet for a Gaussian Process mapping an algae wall.
std::vector< unsigned int > idx_obs_
Array of corresponding indices for observed states.
std::vector< float > out_values_
Output values of the Gaussian Process.
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.
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.
Eigen::MatrixXf gp_cov_
Covariance of the Gaussian Process.
void publish_gp_state()
Publishes mean and covariance of the Gaussian Process.
float radius_obs_
Radius of influence of an observation on the GP.
void main_cb(const ros::TimerEvent &timer_event)
Main callback which is called by a timer.
void notif_changing_pxls(const RectArea &coord)
Notifies changing pixels during GP update.
void publish_gp_eval()
Publishes the evaluated GP and its covariance.
bool get_tf()
Gets necessary tf transforms.
std::vector< float > vec_f
ros::ServiceServer load_gp_serv_
Service server for loading the GP.
mf_sensors_simulator::CameraOutput::ConstPtr camera_msg_
Last camera message.
ros::NodeHandle private_nh_
Private node handler (for parameters)
ros::Publisher gp_cov_pub_
Publisher for the GP covariance.
float matern_length_
Lengthscale of the Matern kernel.
int size_gp_x_
Size of the Gaussian Process mean in the x direction.
bool camera_msg_available_
Whether a new camera message is available.
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.
float camera_decay_
Exponential decay rate on camera measurements.
std::string camera_frame_
Name of the camera frame.
int size_gp_y_
Size of the Gaussian Process mean in the y direction.