12 #include "mf_common/EulerPose.h" 13 #include "mf_common/Array2D.h" 14 #include "mf_common/Float32Array.h" 15 #include "mf_farm_simulator/Algae.h" 16 #include "mf_farm_simulator/Alga.h" 17 #include "mf_mapping/LoadGP.h" 18 #include <nav_msgs/Odometry.h> 19 #include <nav_msgs/Path.h> 20 #include <geometry_msgs/PoseStamped.h> 21 #include <geometry_msgs/Pose.h> 22 #include <ros/package.h> 24 #include <eigen3/Eigen/Dense> 32 #include <sensor_msgs/Image.h> 33 #include <sensor_msgs/image_encodings.h> 47 tf_listener_(tf_buffer_)
65 nh_.param<
string>(
"out_file_name", out_file_name,
"/tmp/control_out.txt");
82 out_file_ <<
"t, d, x, y, z, x_ref, y_ref, z_ref, pos_err, orient_err, gp_cov_trace, gp_diff_norm" << endl;
84 ROS_WARN(
"[experiment_stats] Couldn't open file '%s' in write mode", out_file_name.c_str());
95 ref_pub_ =
nh_.advertise<geometry_msgs::Pose>(
"reference", 0);
108 ros::Time t_path = ros::Time::now();
109 bool experiment_over =
false;
111 while (ros::ok() && !experiment_over) {
116 vector<float> gp_mean;
120 mf_mapping::LoadGP srv;
121 srv.request.mean = gp_mean;
125 if (srv_called && srv.response.gp_loaded) {
127 ROS_INFO(
"[experiment_stats] GP loaded");
128 }
else if (!srv_called || (srv_called && !srv.response.gp_not_yet_init)){
129 ROS_WARN(
"[experiment_stats] Could not load GP");
139 mf_common::EulerPose error;
143 float gp_cov_trace = 0.0;
144 float information = 0.0;
147 for (
int k = 0; k < size_gp; k++) {
161 write_output(
odom_.pose.pose, reference_pose, error, gp_cov_trace, information, gp_diff_norm);
168 geometry_msgs::TransformStamped wall_robot_tf;
171 wall_robot_tf =
tf_buffer_.lookupTransform(
"wall",
"base_link", ros::Time(0));
173 catch (tf2::TransformException &ex) {
174 ROS_WARN(
"[experiment_stats] %s", ex.what());
178 if (wall_robot_tf.transform.translation.y < 0 && wall_robot_tf.transform.translation.z < 0) {
179 experiment_over =
true;
180 ROS_INFO(
"========== EXPERIMENT OVER ===========");
198 const std::vector<geometry_msgs::PoseStamped> &path,
199 const geometry_msgs::Pose &pose)
201 if (path.size() == 0)
202 return geometry_msgs::Pose();
204 float min_dist =
distance2(path[0].pose.position, pose.position);
207 for (
int k = 1; k < path.size(); k++) {
208 float d =
distance2(path[k].pose.position, pose.position);
216 return path[best_k].pose;
221 const std::vector<std::vector<float>> &array1,
222 const std::vector<std::vector<float>> &array2)
224 const vector<vector<float>> *small_array;
225 const vector<vector<float>> *big_array;
228 if (array1.size() < array2.size()) {
229 small_array = &array1;
232 small_array = &array2;
236 float size_x[2] = {(float)(*small_array).size(), (float)(*big_array).size()};
237 float size_y[2] = {(float)(*small_array)[0].size(), (float)(*big_array)[0].size()};
240 typedef const vector<vector<float>>* Array2DPtr;
241 Array2DPtr arrays[2] = {small_array, big_array};
242 float maximums[2] = {0, 0};
244 for (
int k = 0; k < 2; k++) {
245 for (
int x = 0; x < size_x[k]; x++) {
246 for (
int y = 0; y < size_y[k]; y++) {
247 if ((*(arrays[k]))[x][y] > maximums[k])
248 maximums[k] = (*(arrays[k]))[x][y];
254 sensor_msgs::Image diff_img;
255 diff_img.header.stamp = ros::Time::now();
256 diff_img.height = size_x[0];
257 diff_img.width = size_y[0];
258 diff_img.encoding = sensor_msgs::image_encodings::MONO8;
259 diff_img.is_bigendian =
false;
260 diff_img.step = size_y[0];
261 diff_img.data.resize(size_x[0]*size_y[0]);
266 for (
int k = 0; k < size_x[0]; k++) {
267 int x = k * float(size_x[1] / size_x[0]);
269 for (
int l = 0; l < size_y[0]; l++) {
270 int y = l * float(size_y[1] / size_y[0]);
271 float small_val = (*small_array)[k][l];
272 float big_val = (*big_array)[x][y];
274 norm += pow(small_val/maximums[0] - big_val/maximums[1], 2);
275 diff_img.data[k*size_y[0] + l] = fabs(small_val/maximums[0] - big_val/maximums[1])*255;
280 return sqrt(norm) / (size_x[0]*size_y[0]);
285 const geometry_msgs::Pose &pose,
286 const geometry_msgs::Pose &reference,
287 const mf_common::EulerPose &error,
295 float error_pos = sqrt(error.x*error.x + error.y*error.y + error.z*error.z);
296 float error_orient = sqrt(error.pitch*error.pitch + error.yaw*error.yaw);
301 << pose.position.x <<
", " 302 << pose.position.y <<
", " 303 << pose.position.z <<
", " 304 << reference.position.x <<
", " 305 << reference.position.y <<
", " 306 << reference.position.z <<
", " 308 << error_orient <<
", " 309 << gp_cov_trace <<
", " 310 << information <<
", " 311 << gp_diff_norm << endl;
316 std::string file_name,
317 std::vector<float> &gp_mean)
322 if (!file.is_open()) {
323 ROS_WARN(
"[experiment_stats] Couldn't open file '%s' in write mode",
gp_file_name_.c_str());
328 ROS_INFO(
"[experiment_stats] Loading GP mean from '%s'\n",
gp_file_name_.c_str());
331 for (
string line; std::getline(file, line); ) {
333 gp_mean.emplace_back(stof(line));
346 if (!file.is_open()) {
347 ROS_WARN(
"[experiment_stats] Couldn't open file '%s' in write mode",
gp_file_name_.c_str());
352 printf(
"[experiment_stats] Saving GP to '%s'\n",
gp_file_name_.c_str());
354 for (
int k = 0; k <
gp_mean_.size(); k++) {
367 float dt = (msg.header.stamp -
odom_.header.stamp).toSec();
368 float v = msg.twist.twist.linear.x;
395 int n = msg.data.size();
398 for (
int k = 0; k <
n; k++)
399 gp_cov_[k] = msg.data[k].data[k];
412 for (
int k = 0; k < msg.data.size(); k++) {
413 gp_eval_[k].resize(msg.data[k].data.size());
415 for (
int l = 0; l < msg.data[k].data.size(); l++) {
416 gp_eval_[k][l] = msg.data[k].data[l];
428 for (
int k = 0; k < msg.algae.size(); k++) {
429 const mf_farm_simulator::Alga *alga = &msg.algae[k];
432 for (
int l = 0; l < alga->disease_heatmap.size(); l++) {
435 for (
int m = 0; m < alga->disease_heatmap[l].data.size(); m++) {
452 int main(
int argc,
char **argv)
454 ros::init(argc, argv,
"experiment_stats");
void save_gp()
Saves the mean of the Gaussian Process in a file.
void algae_cb(const mf_farm_simulator::Algae msg)
Callback for farm algae.
float moved_distance_
Distance moved by the robot since the start.
ros::Subscriber path_sub_
Subscriber for the reference path.
bool gp_cov_received_
Whether the covariance of the GP has been received.
std::vector< float > init_gp_cov_
Diagonal of the initial covariance of the GP.
float gp_threshold_
Threshold to consider a GP component in information gain computation.
ros::Subscriber odom_sub_
Subscriber for robot odometry.
float main_freq_
Frequency of the main loop.
void gp_mean_cb(const mf_common::Float32Array msg)
Callback for the mean of the Gaussian Process.
void gp_eval_cb(const mf_common::Array2D msg)
Callback for the evaluated GP.
std::vector< float > gp_cov_
Diagonal of the covariance of the Gaussian Proces.
void diff_pose(const geometry_msgs::Pose &p1, const geometry_msgs::Pose &p2, geometry_msgs::Pose &diff)
Computes the difference between two poses.
std::string gp_file_name_
double start_time_
Start time of the test.
ros::Publisher ref_pub_
Publisher for the reference pose.
Declaration of common functions.
ros::Publisher diff_img_pub_
Publisher for the image of the difference between the mapped GP and the algae heatmap.
nav_msgs::Path path_
Reference path to follow.
bool odom_received_
Whether odometry has been received.
Declaration of a class for 3D spline interpolation.
ros::Subscriber gp_cov_sub_
Subscriber for covariance of the GP.
std::vector< std::vector< std::vector< float > > > algae_heatmaps_
Disease heatmaps of the algae.
std::vector< float > gp_mean_
Mean of the Gaussian Process.
void gp_cov_cb(const mf_common::Array2D msg)
Callback for the covariance of the Gaussian Process.
bool load_gp(std::string file_name, std::vector< float > &gp_mean)
Loads the GP mean from a file.
bool path_received_
Whether the reference path has been received.
Class to measure statistics about experiments.
ros::Subscriber algae_sub_
Subscriber for the farm algae.
void odom_cb(const nav_msgs::Odometry msg)
Callback for odometry.
void path_cb(const nav_msgs::Path msg)
Callback for the reference path.
bool gp_mean_received_
Whether the mean of the GP has been received.
float compute_diff(const std::vector< std::vector< float >> &array1, const std::vector< std::vector< float >> &array2)
Computes the difference between two arrays.
float distance2(const geometry_msgs::Point &p1, const geometry_msgs::Point &p2)
Computes the square of the euclidean distance between two positions.
bool save_gp_
Whether to save the Gaussian Process at the end.
ros::NodeHandle nh_
Node handler.
std::vector< std::vector< float > > gp_eval_
Evaluated GP.
std::ofstream out_file_
Output CSV file containg data of the experiment.
bool load_gp_
Whether to load the Gaussian Process at the beginning.
geometry_msgs::Pose find_closest(const std::vector< geometry_msgs::PoseStamped > &path, const geometry_msgs::Pose &pose)
Finds the closest pose in a path.
Declaration of a node to measure statistics about experiments.
int main(int argc, char **argv)
Main function called before node initialisation.
ros::Subscriber gp_mean_sub_
Subscriber for mean of the GP.
ros::Subscriber gp_eval_sub_
Subscriber for the evaluated GP.
ros::Publisher error_pub_
Publisher for the tracking error.
bool gp_eval_received_
Whether the evaluated GP has been received.
nav_msgs::Odometry odom_
Last odometry message received.
void init_node()
Initialises the node and its parameters.
bool algae_received_
Whether the farm algae have been received.
void write_output(const geometry_msgs::Pose &pose, const geometry_msgs::Pose &reference, const mf_common::EulerPose &error, float gp_cov_trace, float information, float gp_diff_norm)
Writes the output statistics in the out file.
void run_node()
Runs the node.
ros::ServiceClient load_gp_client_
Service client for loading the GP.
tf2_ros::Buffer tf_buffer_
Buffer for tf2.