CleanSpotServer.cpp
Go to the documentation of this file.
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 //#include <surfacelet/PatchMap.h>
00037 #include <coverage_3d_planning/TSPSearch.h>
00038 #include <coverage_3d_arm_navigation/openrave_ik.h> //ik generated by openrave for the right arm
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     //set the arm start poses
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  //   arm_control_ = new  JointSpaceArmController(nh_);
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()); // call all available callbacks
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 //    std::vector<tf::Pose> tmp;
00174 //    arm_control_->moveArmToJointGoalUsingPlanner("right_arm", start_joint_pose_, false, tmp);
00175 
00176     //transforming the received cleaning spot to our frame
00177     ROS_INFO("Transforming spot received to torso_lift_link");
00178     tf::StampedTransform transform_kinect_torso;
00179     //get transform to torso_lift_link
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     //getting the pointcloud
00200     cloud_received_ = false;
00201     cloud_sub_ = nh_.subscribe("/kinect_head/depth_registered/points", 100,
00202             &CleanSpotServer::cloudCB, this);
00203     //cloud_thread_shutdown_ = false;
00204     //cloud_thread_ = new boost::thread(
00205      //       &CleanSpotServer::runThreadCallbackLoop, this);
00206 
00207     //wait for point cloud
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     //delete (cloud_thread_);
00215     cloud_sub_.shutdown();
00216     ROS_INFO("Pointcloud received.");
00217 
00218         //cloud_mutex_.lock();
00219     //Patch construction and publishing
00220 //    surfacelet::PatchMap map;
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 //    if (cloud_nans_removed_.size()==0){
00238 //      ROS_ERROR("No valid patches found for wiping");
00239 //      return false;
00240 //    }
00241 
00242     //Octomap construction
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     //return true;
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 //    int test = 0;
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 //        test = test + coll_free_poses[i].size() - adjacency.row(i).array().sum();
00286     }
00287 
00288 //    visualization_msgs::MarkerArray all_poses_markers;
00289 //    constructPathMarker(all_poses, cloud_.header.frame_id, all_poses_markers);
00290 
00291 
00292     //search TSP solution for each graph
00293     std::vector<std::vector<unsigned int> > solutions;
00294 //  TSPSolver tsp;
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     //publish patches
00305     visualization_msgs::MarkerArray array;
00306     map.constructMarker(cloud_.header.frame_id, reachable, array);
00307     pub_patches_.publish(array);
00308 
00309     //publish patch normals
00310     visualization_msgs::MarkerArray normal_marker;
00311     map.constructNormalMarker(cloud_.header.frame_id, normal_marker);
00312     pub_normals_.publish(normal_marker);
00313 
00314     //publish neighborhood graph
00315 //    visualization_msgs::Marker graph_marker;
00316  //   nh_graph.constructGraphMarker(g_surface_points, adjacency, cloud_.header.frame_id, graph_marker);
00317   //  graph_marker.lifetime= ros::Duration(5.0);
00318    // pub_nhgraph_.publish(graph_marker);
00319 
00320     //publish solution
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     //publish resulting path as marker
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; //need another vector as it is cleared in the function
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; //need another vector as it is cleared in the function
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   //ROS_ASSERT(false);
00358         //cloud_mutex_.unlock();
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                 //get transform to torso_lift_link
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 //              filterXYZ(cloud_, tmp_cloud2, -1.2, 1.2, -0.3, 0.3, -1.0, 0.7);
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         // Set the frame ID and timestamp.  See the TF tutorials for information on these.
00430         marker.header.frame_id = frame_id;
00431         marker.header.stamp = ros::Time::now();
00432 
00433         // Set the namespace and id for this marker.  This serves to create a unique ID
00434         // Any marker sent with the same namespace and id will overwrite the old one
00435         marker.ns = "coverage";
00436 
00437         // Set the marker type.  Initially this is CUBE, and cycles between that and SPHERE, ARROW, and CYLINDER
00438         marker.type = visualization_msgs::Marker::LINE_LIST;
00439 
00440         // Set the marker action.  Options are ADD and DELETE
00441         marker.action = visualization_msgs::Marker::MODIFY;
00442 
00443         // Set the scale of the marker -- 1x1x1 here means 1m on a side
00444         marker.scale.x = 0.005;
00445         marker.scale.y = 0.005;
00446         marker.scale.z = 0.005;
00447 
00448         // Set the color -- be sure to set alpha to something non-zero!
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                 // Set the frame ID and timestamp.  See the TF tutorials for information on these.
00486                 marker.header.frame_id = frame_id;
00487                 marker.header.stamp = ros::Time::now() - ros::Duration(0.5);
00488 
00489                 // Set the namespace and id for this marker.  This serves to create a unique ID
00490                 // Any marker sent with the same namespace and id will overwrite the old one
00491                 marker.ns = "coverage";
00492 
00493                 // Set the marker type.  Initially this is CUBE, and cycles between that and SPHERE, ARROW, and CYLINDER
00494                 marker.type = visualization_msgs::Marker::ARROW;
00495 
00496                 // Set the marker action.  Options are ADD and DELETE
00497                 marker.action = visualization_msgs::Marker::MODIFY;
00498 
00499                 // Set the scale of the marker -- 1x1x1 here means 1m on a side
00500                 marker.scale.x = 0.01;
00501                 marker.scale.y = 0.05;
00502                 marker.scale.z = 0.03;
00503 
00504                 // Set the color -- be sure to set alpha to something non-zero!
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 // for a single pose we sample end-effector rotations
00518 void CleanSpotServer::endEffectorPose(const SurfacePatch p1, const double dist_above_surface, tf::Pose& pose) {
00519         //compute point above surface
00520         Eigen::Vector3f origin = p1.getVector3fMap() + (dist_above_surface * p1.getNormalVector3fMap().normalized())
00521                         + ((p1.scale_z / 2.0) * p1.getNormalVector3fMap().normalized());
00522 
00523         //set x_axis to point to surface
00524         Eigen::Vector3f z_axis = p1.getVector3fMap() - origin;
00525         z_axis.normalize();
00526 
00527         //compute angle-axis representation
00528         //compute cross product of normal and z-axis and get the rotation with smallest angle
00529         //cross product is the rotation axis with smallest angle
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) { //everything ok
00535                 angle = acos(z_axis.dot(Eigen::Vector3f(1, 0, 0)));
00536                 rot_matrix = Eigen::AngleAxis<float>(angle, cross_product).toRotationMatrix();
00537         } else { //cross product 0 - normal either in or exactly opposite of z-axis
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         //set everything into the pose
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); // Use 4 threads
00562     spinner.start();
00563     ros::waitForShutdown();
00564 //    while (ros::ok()) {
00565 //        ROS_INFO("Spining");
00566 //        ros::spinOnce();
00567 //        r.sleep();
00568 //    }
00569 
00570     //ros::spin();
00571 
00572 }
00573 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends


coverage_3d_executive
Author(s): Juergen Hess
autogenerated on Wed Dec 26 2012 16:13:34