plane_finder.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2015-2017 Fetch Robotics Inc.
00003  * Copyright (C) 2013-2014 Unbounded Robotics Inc.
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 // Author: Niharika Arora
00019 
00020 #include <robot_calibration/capture/plane_finder.h>
00021 #include <sensor_msgs/point_cloud2_iterator.h>
00022 #include <math.h>
00023 #include <tf2_ros/transform_listener.h>
00024 #include <tf2_geometry_msgs/tf2_geometry_msgs.h>
00025 
00026 namespace robot_calibration
00027 {
00028 
00029 const unsigned X = 0;
00030 const unsigned Y = 1;
00031 const unsigned Z = 2;
00032 
00033 PlaneFinder::PlaneFinder(ros::NodeHandle & nh) :
00034     FeatureFinder(nh),
00035     waiting_(false)
00036 {
00037   std::string topic_name;
00038   nh.param<std::string>("topic", topic_name, "/points");
00039   subscriber_ = nh.subscribe(topic_name,
00040                              1,
00041                              &PlaneFinder::cameraCallback,
00042                              this);
00043 
00044   nh.param<std::string>("camera_sensor_name", camera_sensor_name_, "camera");
00045   nh.param<double>("points_max", points_max_, 60);
00046   nh.param<double>("min_x", min_x_, -2.0);
00047   nh.param<double>("max_x", max_x_, 2.0);
00048   nh.param<double>("min_y", min_y_, -2.0);
00049   nh.param<double>("max_y", max_y_, 2.0);
00050   nh.param<double>("min_z", min_z_, 0.0);
00051   nh.param<double>("max_z", max_z_, 2.0);
00052   nh.param<std::string>("transform_frame", transform_frame_, "base_link");
00053 
00054   publisher_ = nh.advertise<sensor_msgs::PointCloud2>("plane_points", 10);
00055   if (!depth_camera_manager_.init(nh))
00056   {
00057     // Error will be printed in manager
00058     throw;
00059   }
00060 
00061 }
00062 
00063 void PlaneFinder::cameraCallback(const sensor_msgs::PointCloud2& cloud)
00064 {
00065   if (waiting_)
00066   {
00067     cloud_ = cloud;
00068     waiting_ = false;
00069   }
00070 }
00071 
00072 bool PlaneFinder::waitForCloud()
00073 {
00074   ros::Duration(1/10.0).sleep();
00075 
00076   waiting_ = true;
00077   int count = 250;
00078   while (--count)
00079   {
00080     if (!waiting_)
00081     {
00082       // success
00083       return true;
00084     }
00085     ros::Duration(0.01).sleep();
00086     ros::spinOnce();
00087   }
00088   ROS_ERROR("Failed to get cloud");
00089   return !waiting_;
00090 }
00091 
00092 bool PlaneFinder::find(robot_calibration_msgs::CalibrationData * msg)
00093 {
00094   geometry_msgs::PointStamped rgbd;
00095   geometry_msgs::PointStamped world;
00096 
00097   if (!waitForCloud())
00098   {
00099     ROS_ERROR("No point cloud data");
00100     return false;
00101   }
00102 
00103   //  Remove NaNs in the point cloud
00104   size_t num_points = cloud_.width * cloud_.height;
00105   sensor_msgs::PointCloud2ConstIterator<float> xyz(cloud_, "x");
00106   sensor_msgs::PointCloud2Iterator<float> iter(cloud_, "x");
00107 
00108   tf2_ros::Buffer tfBuffer;
00109   tf2_ros::TransformListener tfListener(tfBuffer);
00110   geometry_msgs::TransformStamped transformStamped;
00111   try
00112   {
00113     transformStamped = tfBuffer.lookupTransform("base_link", cloud_.header.frame_id,
00114                              ros::Time(0), ros::Duration(10.0));
00115   }
00116   catch (tf2::TransformException ex)
00117   {
00118     ROS_ERROR("%s",ex.what());
00119     ros::Duration(1.0).sleep();
00120   }
00121 
00122   size_t j = 0;
00123   for (size_t i = 0; i < num_points; i++)
00124   {
00125     geometry_msgs::PointStamped p;
00126     p.point.x = (xyz + i)[X];
00127     p.point.y = (xyz + i)[Y];
00128     p.point.z = (xyz + i)[Z];
00129     p.header.stamp = ros::Time(0);
00130     p.header.frame_id = cloud_.header.frame_id;
00131 
00132     geometry_msgs::PointStamped p_out;
00133     try
00134     {
00135       tfBuffer.transform(p, p_out, transform_frame_);
00136     }
00137     catch (tf2::TransformException ex)
00138     {
00139       ROS_ERROR("%s", ex.what());
00140       ros::Duration(1.0).sleep();
00141     }
00142 
00143     // Remove the NaNs in the point cloud
00144     if (!std::isfinite(p.point.x) || !std::isfinite(p.point.y) || !std::isfinite(p.point.z))
00145       continue;
00146 
00147     // Remove the points immediately in front of the camera in the point cloud
00148     // NOTE : This is to handle sensors that publish zeros instead of NaNs in the point cloud
00149     if (p.point.z == 0)
00150       continue;
00151 
00152     // Transformed point in the transformed frame (default is base_link))
00153     if (p_out.point.x < min_x_ || p_out.point.x > max_x_ || p_out.point.y < min_y_ || p_out.point.y > max_y_ ||
00154         p_out.point.z < min_z_ || p_out.point.z > max_z_)
00155     {
00156       continue;
00157     }
00158 
00159     (iter + j)[X] = (xyz + i)[X];
00160     (iter + j)[Y] = (xyz + i)[Y];
00161     (iter + j)[Z] = (xyz + i)[Z];
00162     j++;
00163   }
00164 
00165   cloud_.height = 1;
00166   cloud_.width  = j;
00167   cloud_.data.resize(cloud_.width * cloud_.point_step);
00168 
00169   size_t points_total = std::min(static_cast<size_t>(points_max_), j);
00170   std::vector<cv::Point2f> points;
00171   points.resize(points_total);
00172 
00173   // Create PointCloud2 to publish
00174   sensor_msgs::PointCloud2 cloud;
00175   cloud.width = 0;
00176   cloud.height = 0;
00177   cloud.header.stamp = ros::Time::now();
00178   cloud.header.frame_id = cloud_.header.frame_id;
00179   sensor_msgs::PointCloud2Modifier cloud_mod(cloud);
00180   cloud_mod.setPointCloud2FieldsByString(1, "xyz");
00181   cloud_mod.resize(points_total);
00182   sensor_msgs::PointCloud2Iterator<float> iter_cloud(cloud, "x");
00183 
00184   // Set msg size
00185   int idx_cam = msg->observations.size() + 0;
00186   msg->observations.resize(msg->observations.size() + 1);
00187   msg->observations[idx_cam].sensor_name = camera_sensor_name_;
00188   msg->observations[idx_cam].features.resize(points_total);
00189 
00190   size_t step = cloud_.width/(points_total);
00191   size_t k = 0;
00192 
00193   for (size_t i = step; i < cloud_.width && k < points_total; i += step)
00194   {
00195     points[k].x = i;
00196     k++;
00197   }
00198 
00199   for (size_t i = 0; i < points.size(); i++)
00200   {
00201     // Get 3d point
00202     int index = static_cast<int>(points[i].x);
00203     rgbd.point.x = (xyz + index)[X];
00204     rgbd.point.y = (xyz + index)[Y];
00205     rgbd.point.z = (xyz + index)[Z];
00206     msg->observations[idx_cam].features[i] = rgbd;
00207     msg->observations[idx_cam].ext_camera_info = depth_camera_manager_.getDepthCameraInfo();
00208 
00209     iter_cloud[0] = rgbd.point.x;
00210     iter_cloud[1] = rgbd.point.y;
00211     iter_cloud[2] = rgbd.point.z;
00212     ++iter_cloud;
00213   }
00214 
00215   // Publish debug info
00216   msg->observations[idx_cam].cloud = cloud_;
00217   publisher_.publish(cloud);
00218   return true;
00219 }
00220 }  // namespace robot_calibration


robot_calibration
Author(s): Michael Ferguson
autogenerated on Thu Jun 6 2019 21:54:10