00001
00002 #include <iostream>
00003 #include <limits>
00004 #include <cmath>
00005 #include <cstdlib>
00006 #include <map>
00007
00008 #include <boost/thread/thread.hpp>
00009 #include <pcl/common/common_headers.h>
00010 #include <pcl/common/common_headers.h>
00011 #include <pcl/io/pcd_io.h>
00012 #include <pcl/console/parse.h>
00013 #include <pcl/point_types.h>
00014 #include <pcl/filters/statistical_outlier_removal.h>
00015 #include <pcl/filters/passthrough.h>
00016
00017 #include <sensor_msgs/PointCloud2.h>
00018 #include <sensor_msgs/point_cloud_conversion.h>
00019
00020 #include <ros/ros.h>
00021 #include <pcl_ros/transforms.h>
00022 #include <sensor_msgs/PointCloud2.h>
00023
00024 #include <tf/tf.h>
00025 #include <visualization_msgs/Marker.h>
00026 #include <visualization_msgs/MarkerArray.h>
00027 #include <eigen3/Eigen/src/Core/EigenBase.h>
00028 #include <eigen3/Eigen/src/Geometry/Quaternion.h>
00029
00030 #include <octomap_ros/OctomapROS.h>
00031 #include <octomap/octomap.h>
00032 #include <octomap_ros/conversions.h>
00033
00034 #include <surfacelet/SurfacePatch.h>
00035 #include <surfacelet/SubmodMap.h>
00036
00037 #include <coverage_3d_planning/TSPSearch.h>
00038 #include <coverage_3d_arm_navigation/openrave_ik.h>
00039 #include <coverage_3d_arm_navigation/JointSpaceArmController.h>
00040 #include <coverage_3d_planning/NeighborhoodGraph.h>
00041 #include <coverage_3d_tools/conversions.h>
00042 #include <coverage_3d_planning/TSPSolver.h>
00043 #include <coverage_3d_planning/GTSPSolver.h>
00044 #include <coverage_3d_planning/JointGTSPSolver.h>
00045 #include <coverage_3d_srvs/CleanSpot.h>
00046 #include <coverage_3d_tools/filter.h>
00047 #include <actionlib/client/simple_action_client.h>
00048 #include <tf/tf.h>
00049
00050 #include <ros/ros.h>
00051 #include <sensor_msgs/PointCloud2.h>
00052 #include <pcl/ros/conversions.h>
00053 #include <pcl/point_types.h>
00054 #include <tf/transform_listener.h>
00055 #include <Eigen/Core>
00056 #include <boost/algorithm/string.hpp>
00057 #include <std_srvs/Empty.h>
00058 #include <tf/transform_listener.h>
00059 #include <boost/thread.hpp>
00060 #include <boost/format.hpp>
00061 #include <boost/thread/thread.hpp>
00062 #include <boost/thread/mutex.hpp>
00063 #include <coverage_3d_tools/AssembleCloud.h>
00064 #include <pcl_ros/transforms.h>
00065
00066 using namespace std;
00067 namespace coverage_3d_executive {
00068
00069 class CleanSpotServer {
00070
00071 public:
00072 CleanSpotServer(ros::NodeHandle& n);
00073 ~CleanSpotServer();
00074 void cloudCB(const sensor_msgs::PointCloud2ConstPtr& msg);
00075
00076 private:
00077 ros::NodeHandle nh_;
00078 ros::ServiceServer srv_;
00079 ros::Subscriber cloud_sub_;
00080 ros::Publisher cloud_pub_;
00081 tf::TransformListener tf_;
00082
00083 ros::Publisher pub_cloud_used_;
00084 ros::Publisher pub_cloud_not_used_;
00085 ros::Publisher pub_patches_;
00086 ros::Publisher pub_normals_;
00087 ros::Publisher pub_nhgraph_;
00088 ros::Publisher pub_solution_;
00089
00090 pcl::PointCloud<pcl::PointXYZ> assembled_cloud_;
00091
00092 bool srvCB(coverage_3d_srvs::CleanSpot::Request& req,
00093 coverage_3d_srvs::CleanSpot::Response& resp);
00094 void runThreadCallbackLoop();
00095 void constructSolutionMarker(std::vector<pcl::PointXYZ> surface_samples,
00096 const std::vector<std::vector<unsigned int> >& solutions, const std::string frame_id,
00097 std::vector<visualization_msgs::Marker>& marker_list);
00098 void constructPathMarker(const std::vector<tf::Pose>& poses, const std::string frame_id,
00099 visualization_msgs::MarkerArray& marker_list);
00100 void endEffectorPose(const SurfacePatch p1, const double dist_above_surface, tf::Pose& pose);
00101
00102 ros::NodeHandle cloud_nh_;
00103 boost::thread * cloud_thread_;
00104 bool cloud_thread_shutdown_;
00105 bool cloud_received_;
00106 double box_size_;
00107 JointSpaceArmController* arm_control_;
00108
00109 ros::CallbackQueue cloud_callback_queue_;
00110 boost::recursive_mutex cloud_mutex_;
00111 tf::TransformListener listener;
00112 pcl::PointXYZ cloud_view_point_;
00113 tf::Point spot_to_clean_;
00114 pcl::PointCloud<pcl::PointXYZ> cloud_;
00115 pcl::PointCloud<pcl::PointXYZ> cloud_nans_removed_;
00116 pcl::PointCloud<pcl::PointXYZ> cloud_not_used_;
00117 std::vector<double> start_joint_pose_;
00118 tf::Pose start_tf_pose_;
00119
00120
00121 };
00122
00123 CleanSpotServer::CleanSpotServer(ros::NodeHandle& n) :
00124 nh_(n), cloud_thread_shutdown_(true),cloud_received_(false),box_size_(0.3),arm_control_(0){
00125 cloud_nh_.setCallbackQueue(&cloud_callback_queue_);
00126 srv_ = nh_.advertiseService("clean_spot", &CleanSpotServer::srvCB,
00127 this);
00128 cloud_pub_=nh_.advertise<sensor_msgs::PointCloud2>("build_cloud_msg",2);
00129
00130 pub_cloud_used_ = nh_.advertise<sensor_msgs::PointCloud2>("cloud_used", 1);
00131 pub_cloud_not_used_ = nh_.advertise<sensor_msgs::PointCloud2>("cloud_not_used", 1);
00132 pub_patches_ = nh_.advertise<visualization_msgs::MarkerArray>("surface_patches", 1);
00133 pub_normals_ = nh_.advertise<visualization_msgs::MarkerArray>("surface_normals", 1);
00134 pub_nhgraph_= nh_.advertise<visualization_msgs::Marker>("neighborhood_graph", 1);
00135 pub_solution_ = nh_.advertise<visualization_msgs::Marker>("tsp_solution", 1);
00136
00137
00138 start_joint_pose_.resize(7);
00139 start_joint_pose_[0] = -1.68;
00140 start_joint_pose_[1] = 0.052;
00141 start_joint_pose_[2] = -1.48;
00142 start_joint_pose_[3] = -1.65;
00143 start_joint_pose_[4] = -1.60;
00144 start_joint_pose_[5] = -1.57;
00145 start_joint_pose_[6] = -3.02;
00146
00147 start_tf_pose_.setOrigin(tf::Point(0.278, -0.710, -0.158));
00148
00149
00150
00151 cloud_view_point_ = pcl::PointXYZ(0,0,0);
00152 }
00153 CleanSpotServer::~CleanSpotServer() {
00154 if (arm_control_!=0){
00155 delete arm_control_;
00156 }
00157 }
00158
00159 void CleanSpotServer::runThreadCallbackLoop() {
00160 ros::Rate r(15);
00161 while (ros::ok() && !cloud_thread_shutdown_) {
00162 ROS_INFO("Listening for pointclouds ");
00163 cloud_callback_queue_.callAvailable(ros::WallDuration());
00164 r.sleep();
00165 }
00166 }
00167
00168
00169 bool CleanSpotServer::srvCB(coverage_3d_srvs::CleanSpot::Request& req,
00170 coverage_3d_srvs::CleanSpot::Response& resp) {
00171 arm_control_ = new JointSpaceArmController(nh_);
00172 box_size_=req.box_size/2.0;
00173
00174
00175
00176
00177 ROS_INFO("Transforming spot received to torso_lift_link");
00178 tf::StampedTransform transform_kinect_torso;
00179
00180 bool transform_received = false;
00181 while (!transform_received && ros::ok()) {
00182 try {
00183 ros::Duration timeout(15.0 / 30.0);
00184 tf_.waitForTransform("/torso_lift_link", req.spot.header.frame_id,ros::Time(0), timeout);
00185 tf_.lookupTransform("/torso_lift_link", req.spot.header.frame_id, ros::Time(0), transform_kinect_torso);
00186 transform_received = true;
00187 } catch (exception e) {
00188 ROS_WARN_STREAM(e.what());
00189 }ROS_INFO( "Continue waiting for transform.");
00190 ros::Rate r(10);
00191 r.sleep();
00192 }
00193
00194 tf::Point received_spot;
00195 tf::pointMsgToTF(req.spot.point,received_spot);
00196 spot_to_clean_= transform_kinect_torso*received_spot;
00197
00198
00199
00200 cloud_received_ = false;
00201 cloud_sub_ = nh_.subscribe("/kinect_head/depth_registered/points", 100,
00202 &CleanSpotServer::cloudCB, this);
00203
00204
00205
00206
00207
00208 ros::Rate loop_rate(10);
00209 while (!cloud_received_) {
00210 ROS_INFO("Waiting for pointcloud.");
00211 loop_rate.sleep();
00212 }
00213 cloud_thread_shutdown_ = true;
00214
00215 cloud_sub_.shutdown();
00216 ROS_INFO("Pointcloud received.");
00217
00218
00219
00220
00221 surfacelet::SubmodMap map;
00222 pcl::PointCloud<pcl::PointXYZ> not_used_cloud;
00223 map.insertScan(cloud_nans_removed_, not_used_cloud, cloud_view_point_);
00224
00225 sensor_msgs::PointCloud2 not_used_msg;
00226 pcl::toROSMsg(not_used_cloud, not_used_msg);
00227 not_used_msg.header.stamp = ros::Time::now();
00228 not_used_msg.header.frame_id = cloud_.header.frame_id;
00229 pub_cloud_not_used_.publish(not_used_msg);
00230
00231 sensor_msgs::PointCloud2 msg;
00232 pcl::toROSMsg(cloud_nans_removed_, msg);
00233 msg.header.stamp = ros::Time::now();
00234 msg.header.frame_id = cloud_.header.frame_id;
00235 pub_cloud_used_.publish(msg);
00236
00237
00238
00239
00240
00241
00242
00243 ROS_INFO("Constructing Octomap");
00244 octomap::OctomapROS<octomap::OcTree> octomap(0.01);
00245 octomap.octree.setOccupancyThres(0.6);
00246 octomap.insertScan(cloud_nans_removed_, cloud_view_point_);
00247
00248
00249
00250 ROS_INFO("Constructing Neigborhood Graph Object");
00251 std::vector<SurfacePatch> g_patches;
00252 std::vector<pcl::PointXYZ> g_surface_points;
00253 Eigen::MatrixXi adjacency;
00254 std::vector<std::vector<tf::Pose> > coll_free_poses;
00255 std::vector<std::vector<std::vector<std::vector<double> > > > coll_free_ik;
00256 std::vector<bool> reachable;
00257
00258 {
00259 ros::NodeHandle nh("zweitnodehandle");
00260
00261 NeighborhoodGraph nh_graph(nh, map.map_, &octomap);
00262 nh_graph.setSurfaceDist(0.03);
00263
00264 nh_graph.getGraph(g_patches, g_surface_points, adjacency, coll_free_poses, coll_free_ik);
00265
00266 nh_graph.getReachableVector(reachable);
00267 }
00268
00269
00270
00271 if (g_patches.size()==0){
00272 ROS_ERROR("No valid patches found for wiping");
00273 return false;
00274 }
00275
00276 std::vector<tf::Pose> all_poses;
00277 all_poses.clear();
00278
00279 for (int i = 0; i < adjacency.rows(); ++i) {
00280 for (unsigned int j = 0; j < coll_free_poses[i].size(); ++j) {
00281 all_poses.push_back(coll_free_poses[i][j]);
00282 geometry_msgs::Pose geom_pose;
00283 tf::poseTFToMsg(coll_free_poses[i][j], geom_pose);
00284 }
00285
00286 }
00287
00288
00289
00290
00291
00292
00293 std::vector<std::vector<unsigned int> > solutions;
00294
00295 GTSPSolver tsp;
00296 tsp.setStartPose(start_joint_pose_, start_tf_pose_);
00297 tsp.setGraph(g_patches, g_surface_points, adjacency, coll_free_poses, coll_free_ik);
00298 std::vector<std::vector<double> > res_joint_path_tsp;
00299 std::vector<tf::Pose> res_pose_path_tsp;
00300 std::vector<unsigned int> res_actions_tsp;
00301 std::vector<unsigned int> res_traj_tsp;
00302 tsp.getSolution(res_joint_path_tsp, res_pose_path_tsp, res_actions_tsp, res_traj_tsp);
00303
00304
00305 visualization_msgs::MarkerArray array;
00306 map.constructMarker(cloud_.header.frame_id, reachable, array);
00307 pub_patches_.publish(array);
00308
00309
00310 visualization_msgs::MarkerArray normal_marker;
00311 map.constructNormalMarker(cloud_.header.frame_id, normal_marker);
00312 pub_normals_.publish(normal_marker);
00313
00314
00315
00316
00317
00318
00319
00320
00321 ROS_INFO("Constructing solution markers");
00322 std::vector<visualization_msgs::Marker> solutions_marker;
00323 solutions.push_back(res_traj_tsp);
00324 constructSolutionMarker(g_surface_points, solutions, cloud_.header.frame_id, solutions_marker);
00325
00326
00327 for (unsigned int i = 0; i < solutions.size(); i++) {
00328 pub_solution_.publish(solutions_marker[i]);
00329 ros::Duration(0.5).sleep();
00330 }
00331
00332 std::vector<tf::Pose> touch_points_allowed;
00333 touch_points_allowed.push_back(start_tf_pose_);
00334 for (unsigned int i = 0; i < res_traj_tsp.size(); ++i) {
00335 tf::Pose tmp;
00336 endEffectorPose(g_patches[res_traj_tsp[i]], 0.00, tmp);
00337 touch_points_allowed.push_back(tmp);
00338 }
00339 touch_points_allowed.push_back(start_tf_pose_);
00340
00341 std::vector<tf::Pose> poses_above_surface;
00342 poses_above_surface.push_back(start_tf_pose_);
00343 for (unsigned int i = 0; i < g_patches.size(); ++i) {
00344 tf::Pose tmp;
00345 endEffectorPose(g_patches[res_traj_tsp[i]], 0.30, tmp);
00346 poses_above_surface.push_back(tmp);
00347 }
00348 poses_above_surface.push_back(start_tf_pose_);
00349
00350 ROS_ERROR_STREAM("Size of trajectories " << res_traj_tsp.size() << " " << touch_points_allowed.size() << " " << poses_above_surface.size() << " "
00351 << res_joint_path_tsp.size() << " " << res_pose_path_tsp.size() << " " << res_actions_tsp.size());
00352
00353 bool cleaning_succeeded = arm_control_->followEntireTrajectory(res_joint_path_tsp, "right_arm", res_actions_tsp, res_pose_path_tsp, touch_points_allowed,
00354 poses_above_surface);
00355 ROS_INFO("FINISHED CLEANING");
00356 delete(arm_control_);
00357
00358
00359 return cleaning_succeeded;
00360 }
00361
00362 void CleanSpotServer::cloudCB(const sensor_msgs::PointCloud2ConstPtr& msg) {
00363
00364 if (!cloud_received_) {
00365
00366 tf::StampedTransform transform_kinect_torso;
00367
00368 bool transform_received = false;
00369 while (!transform_received && ros::ok()) {
00370 ros::Time lookup_time = ros::Time::now();
00371 try {
00372 ros::Duration timeout(15.0 / 30.0);
00373 tf_.waitForTransform("/torso_lift_link", msg->header.frame_id, lookup_time, timeout);
00374 tf_.lookupTransform("/torso_lift_link", msg->header.frame_id, lookup_time, transform_kinect_torso);
00375 transform_received = true;
00376 } catch (exception e) {
00377 ROS_WARN_STREAM(e.what());
00378 }ROS_INFO( "Continue waiting for transform.");
00379 ros::Rate r(10);
00380 r.sleep();
00381 }
00382
00383 pcl::PointCloud<pcl::PointXYZ> tmp_cloud;
00384 pcl::fromROSMsg(*msg, tmp_cloud);
00385 pcl_ros::transformPointCloud(tmp_cloud, cloud_, transform_kinect_torso);
00386 cloud_.header.frame_id = "/torso_lift_link";
00387
00388 pcl::PointCloud<pcl::PointXYZ> tmp_cloud2;
00389 filterXYZ(cloud_, tmp_cloud2, spot_to_clean_.getX()-box_size_, spot_to_clean_.getX()+box_size_, spot_to_clean_.getY()-box_size_, spot_to_clean_.getY()+box_size_, spot_to_clean_.getZ()-box_size_, spot_to_clean_.getZ()+box_size_);
00390
00391
00392 cloud_nans_removed_.points.clear();
00393 for (unsigned int i = 0; i < tmp_cloud2.points.size(); ++i) {
00394 if (!pcl_isnan (tmp_cloud2.points[i].x) && !pcl_isnan (tmp_cloud2.points[i].y)
00395 && !pcl_isnan (tmp_cloud2.points[i].z)) {
00396 cloud_nans_removed_.points.push_back(tmp_cloud2.points[i]);
00397 }
00398 }
00399 cloud_nans_removed_.is_dense = false;
00400 cloud_nans_removed_.height = 1;
00401 cloud_nans_removed_.width = cloud_nans_removed_.points.size();
00402
00403 pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
00404 sor.setInputCloud(cloud_nans_removed_.makeShared());
00405 sor.setMeanK(50);
00406 sor.setStddevMulThresh(1.0);
00407 pcl::PointCloud<pcl::PointXYZ> tmp_cloud3;
00408 sor.filter(tmp_cloud3);
00409 cloud_nans_removed_ = tmp_cloud3;
00410
00411 tf::Point org_view_point(0, 0, 0);
00412 org_view_point = transform_kinect_torso * org_view_point;
00413 cloud_view_point_.x = org_view_point.x();
00414 cloud_view_point_.y = org_view_point.y();
00415 cloud_view_point_.z = org_view_point.z();
00416 ROS_DEBUG_STREAM("View Point " << cloud_view_point_.x << " " << cloud_view_point_.y << " " << cloud_view_point_.z);
00417 ROS_DEBUG_STREAM("Original View Point " <<org_view_point.x() << " " << org_view_point.y() << " " << org_view_point.z());
00418 cloud_received_ = true;
00419 }
00420 }
00421
00422 void CleanSpotServer::constructSolutionMarker(std::vector<pcl::PointXYZ> surface_samples,
00423 const std::vector<std::vector<unsigned int> >& solutions, const std::string frame_id,
00424 std::vector<visualization_msgs::Marker>& marker_list) {
00425
00426 marker_list.clear();
00427 visualization_msgs::Marker marker;
00428
00429
00430 marker.header.frame_id = frame_id;
00431 marker.header.stamp = ros::Time::now();
00432
00433
00434
00435 marker.ns = "coverage";
00436
00437
00438 marker.type = visualization_msgs::Marker::LINE_LIST;
00439
00440
00441 marker.action = visualization_msgs::Marker::MODIFY;
00442
00443
00444 marker.scale.x = 0.005;
00445 marker.scale.y = 0.005;
00446 marker.scale.z = 0.005;
00447
00448
00449 marker.color.r = 1;
00450 marker.color.g = 1;
00451 marker.color.b = 0.5;
00452 marker.color.a = 1.0;
00453
00454 geometry_msgs::Point start;
00455 geometry_msgs::Point end;
00456
00457 for (unsigned int i = 0; i < solutions.size(); i++) {
00458 marker.id = i;
00459 marker.points.clear();
00460
00461 for (unsigned int j = 0; j < solutions[i].size() - 1; j++) {
00462 start.x = surface_samples[solutions[i][j]].x;
00463 start.y = surface_samples[solutions[i][j]].y;
00464 start.z = surface_samples[solutions[i][j]].z;
00465 end.x = surface_samples[solutions[i][j + 1]].x;
00466 end.y = surface_samples[solutions[i][j + 1]].y;
00467 end.z = surface_samples[solutions[i][j + 1]].z;
00468
00469 marker.points.push_back(start);
00470 marker.points.push_back(end);
00471 }
00472 marker_list.push_back(marker);
00473 }
00474
00475 }
00476
00477 void CleanSpotServer::constructPathMarker(const std::vector<tf::Pose>& poses, const std::string frame_id,
00478 visualization_msgs::MarkerArray& marker_list) {
00479
00480 marker_list.markers.clear();
00481 for (unsigned int i = 0; i < poses.size(); i++) {
00482
00483 visualization_msgs::Marker marker;
00484
00485
00486 marker.header.frame_id = frame_id;
00487 marker.header.stamp = ros::Time::now() - ros::Duration(0.5);
00488
00489
00490
00491 marker.ns = "coverage";
00492
00493
00494 marker.type = visualization_msgs::Marker::ARROW;
00495
00496
00497 marker.action = visualization_msgs::Marker::MODIFY;
00498
00499
00500 marker.scale.x = 0.01;
00501 marker.scale.y = 0.05;
00502 marker.scale.z = 0.03;
00503
00504
00505 marker.color.r = 0.0;
00506 marker.color.g = 0.0;
00507 marker.color.b = 0.9;
00508 marker.color.a = 1.0;
00509
00510 marker.id = i;
00511 tf::poseTFToMsg(poses[i], marker.pose);
00512 marker_list.markers.push_back(marker);
00513 }
00514
00515 }
00516
00517
00518 void CleanSpotServer::endEffectorPose(const SurfacePatch p1, const double dist_above_surface, tf::Pose& pose) {
00519
00520 Eigen::Vector3f origin = p1.getVector3fMap() + (dist_above_surface * p1.getNormalVector3fMap().normalized())
00521 + ((p1.scale_z / 2.0) * p1.getNormalVector3fMap().normalized());
00522
00523
00524 Eigen::Vector3f z_axis = p1.getVector3fMap() - origin;
00525 z_axis.normalize();
00526
00527
00528
00529
00530 Eigen::Vector3f cross_product = Eigen::Vector3f(1, 0, 0).cross(z_axis);
00531 Eigen::Matrix3f rot_matrix;
00532 cross_product.normalize();
00533 float angle = 0;
00534 if (cross_product.norm() > 0.000000001) {
00535 angle = acos(z_axis.dot(Eigen::Vector3f(1, 0, 0)));
00536 rot_matrix = Eigen::AngleAxis<float>(angle, cross_product).toRotationMatrix();
00537 } else {
00538 double tmp = z_axis.dot(Eigen::Vector3f(1, 0, 0));
00539 if (tmp > 0) {
00540 rot_matrix = Eigen::Matrix3f::Identity();
00541 } else {
00542 angle = M_PI;
00543 rot_matrix = Eigen::AngleAxis<float>(angle, cross_product).toRotationMatrix();
00544 }
00545 }
00546
00547
00548 pose.setOrigin(tf::Point(origin[0], origin[1], origin[2]));
00549 Eigen::Quaternion<float> quat(rot_matrix);
00550 tf::Quaternion tf_quat(quat.x(), quat.y(), quat.z(), quat.w());
00551 pose.setRotation(tf_quat);
00552 }
00553 };
00554 int main(int argc, char** argv) {
00555
00556 ros::init(argc, argv, "clean_spot_server");
00557 ros::NodeHandle n;
00558 coverage_3d_executive::CleanSpotServer server(n);
00559 ros::Rate r(15);
00560
00561 ros::AsyncSpinner spinner(4);
00562 spinner.start();
00563 ros::waitForShutdown();
00564
00565
00566
00567
00568
00569
00570
00571
00572 }
00573