grasp_adjust_action_server.cpp
Go to the documentation of this file.
00001 /*
00002  * grasp_adjust_server
00003  * Copyright (c) 2010, Willow Garage, Inc.
00004  * All rights reserved.
00005  *
00006  * Software License Agreement (BSD License)
00007  *
00008  *
00009  * Redistribution and use in source and binary forms, with or without
00010  * modification, are permitted provided that the following conditions are met:
00011  *
00012  *     * Redistributions of source code must retain the above copyright
00013  *       notice, this list of conditions and the following disclaimer.
00014  *     * Redistributions in binary form must reproduce the above copyright
00015  *       notice, this list of conditions and the following disclaimer in the
00016  *       documentation and/or other materials provided with the distribution.
00017  *     * Neither the name of Willow Garage nor the names of its
00018  *       contributors may be used to endorse or promote products derived from
00019  *       this software without specific prior written permission.
00020  *
00021  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00024  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00025  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00026  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00027  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00030  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00031  * POSSIBILITY OF SUCH DAMAGE.
00032  */
00033 
00036 
00037 
00038 #include <ros/ros.h>
00039 
00040 #include <tf/tf.h>
00041 #include <tf/transform_listener.h>
00042 #include <tf/transform_broadcaster.h>
00043 
00044 #include <boost/bind.hpp>
00045 
00046 
00047 #include <std_msgs/String.h>
00048 #include <sensor_msgs/point_cloud_conversion.h>
00049 
00050 #include <visualization_msgs/Marker.h>
00051 #include <visualization_msgs/MarkerArray.h>
00052 
00053 #include <object_manipulation_msgs/GraspPlanning.h>
00054 #include <object_manipulation_msgs/ManipulationResult.h>
00055 #include <object_manipulation_msgs/FindClusterBoundingBox.h>
00056 #include <object_manipulator/tools/service_action_wrappers.h>
00057 
00058 #include <dynamic_reconfigure/server.h>
00059 #include "pr2_grasp_adjust/EstimateConfig.h"
00060 //#include "pr2_grasp_adjust/GraspAdjustAction.h"
00061 #include <object_manipulation_msgs/GraspPlanningAction.h>
00062 
00063 #include <actionlib/server/simple_action_server.h>
00064 
00065 #include <iostream>
00066 #include <fstream>
00067 #include <queue>
00068 
00069 #include "gripper_model.h"
00070 #include "helpers.h"
00071 #include "grasp_adjust.h"
00072 
00073 #include "pcl/io/pcd_io.h"
00074 #include "pcl/point_types.h"
00075 #include <pcl/ModelCoefficients.h>
00076 #include <pcl/features/normal_3d.h>
00077 #include <pcl/features/normal_3d_omp.h>
00078 #include <pcl/filters/extract_indices.h>
00079 #include <pcl/filters/passthrough.h>
00080 #include "pcl/filters/voxel_grid.h"
00081 #include <pcl/sample_consensus/method_types.h>
00082 #include <pcl/sample_consensus/model_types.h>
00083 #include <pcl/segmentation/sac_segmentation.h>
00084 
00085 
00086 /*
00087 #define PROF_ENABLED
00088 #include <profiling/profiling.h>
00089 PROF_DECLARE(TOTAL_TIMER)
00090 PROF_DECLARE(TRANSFORM_INPUT_CLOUD)
00091 PROF_DECLARE(DO_DESCENT)
00092 PROF_DECLARE(PROF_1)
00093 */
00094 
00095 typedef pcl::PointXYZRGBNormal PointT;
00096 
00097 const int GLOBAL_SEARCH =  pr2_grasp_adjust::Estimate_global_search;
00098 const int LOCAL_SEARCH =  pr2_grasp_adjust::Estimate_local_search;
00099 const int SINGLE_POSE =  pr2_grasp_adjust::Estimate_single_pose;
00100 
00101 // output file for training data
00102 std::ofstream outputFile;
00103 
00104 // **** 10 ***** 20 ****** 30 ****** 40 ****** 50 ****** 60 ****** 70 ****** 80 ****** 90 ***** 100 ***** 110 ***** 120
00105 
00106 class GraspAdjustActionServer{
00107 
00108     ros::NodeHandle nh_, nh_pvt_;
00109     ros::Subscriber sub_as_;
00110     ros::Publisher pub_cloud_, pub_cloud_roi_, pub_marker_, pub_marker_array_;
00111     ros::Publisher pub_im_status_;
00112 
00113     std::string input_topic_;
00114     std::string output_topic_;
00115 
00116     tf::TransformListener tfl_;
00117     tf::TransformBroadcaster tfb_;
00118 
00119     sensor_msgs::PointCloud2 cloud_msg_;
00120     geometry_msgs::PoseStamped seed_ps_;
00121 
00122     ros::Time now_;
00123 
00124     GraspAdjust grasp_adjust_;
00125 
00126     //actionlib::SimpleActionServer<pr2_grasp_adjust::GraspAdjustAction> as_;
00127     actionlib::SimpleActionServer<object_manipulation_msgs::GraspPlanningAction> as_;
00128     //pr2_grasp_adjust::GraspAdjustFeedback feedback_;
00129     //pr2_grasp_adjust::GraspAdjustResult result_;
00130 
00131     std::string action_name_;
00132 
00133     // ***** Dynamic reconfigure stuff *****
00134     typedef pr2_grasp_adjust::EstimateConfig Config;
00135     dynamic_reconfigure::Server<Config>                dyn_srv;
00136     dynamic_reconfigure::Server<Config>::CallbackType  dyn_cb;
00137 
00138 //    // Service wrapper for cluster bounding box finder service
00139 //    object_manipulator::ServiceWrapper<object_manipulation_msgs::FindClusterBoundingBox> bounding_box_client_;
00140 
00141 // **** 10 ***** 20 ****** 30 ****** 40 ****** 50 ****** 60 ****** 70 ****** 80 ****** 90 ***** 100 ***** 110 ***** 120
00142 public:
00146     GraspAdjustActionServer(char* argv[]):
00147             nh_("/"),
00148             nh_pvt_("~"),
00149             output_topic_("/cloud_out"),
00150             as_(nh_, ros::this_node::getName(), boost::bind(&GraspAdjustActionServer::executeCB, this, _1), false),
00151             action_name_(ros::this_node::getName()),
00152             dyn_srv(ros::NodeHandle("~config"))
00153     {
00154         // Clouds
00155         pub_cloud_ = nh_.advertise<sensor_msgs::PointCloud2>(output_topic_, 1);
00156         pub_cloud_roi_ = nh_.advertise<sensor_msgs::PointCloud2>("/roi_snapshot", 1);
00157 
00158         // Marker topics
00159         pub_marker_ = nh_.advertise<visualization_msgs::Marker>("/markers", 50);
00160         pub_marker_array_ = nh_.advertise<visualization_msgs::MarkerArray>("/markers_array", 50);
00161 
00162         // Interactive manipulation front-end status feedback
00163         pub_im_status_ = nh_.advertise<std_msgs::String>("interactive_manipulation_status", 1);
00164 
00165         grasp_adjust_.pub_cloud_ = &pub_cloud_;
00166         grasp_adjust_.pub_cloud_roi_ = &pub_cloud_roi_;
00167         grasp_adjust_.pub_marker_ = &pub_marker_;
00168         grasp_adjust_.pub_marker_array_ = &pub_marker_array_;
00169         grasp_adjust_.listener_ = &tfl_;
00170         grasp_adjust_.broadcaster_ = &tfb_;
00171 
00172         // This server is for the user to adjust the algorithm weights
00173         dyn_cb = boost::bind( &GraspAdjustActionServer::dynamicCallback, this, _1, _2 );
00174         dyn_srv.setCallback(dyn_cb);
00175 
00176         // -------------------------------------------------
00177 
00178         //register the goal and feeback callbacks
00179         //as_.registerGoalCallback(boost::bind(&GraspAdjustActionServer::goalCB, this));
00180         //as_.registerPreemptCallback(boost::bind(&GraspAdjustActionServer::preemptCB, this));
00181 
00182         //subscribe to the data topic of interest
00183         //sub_as_ = nh_.subscribe("/grasp_adjust_action_server", 1, &GraspAdjustActionServer::analysisCB, this);
00184         as_.start();
00185 
00186         ROS_INFO("Grasp adjust action server: Finished constructor!");
00187     }
00188 
00189 private:
00190 
00191     //void executeCB(const pr2_grasp_adjust::GraspAdjustGoalConstPtr &goal)
00192     void executeCB(const object_manipulation_msgs::GraspPlanningGoalConstPtr &goal)
00193     {
00194 
00195       // make sure that the action hasn't been canceled
00196       if (!as_.isActive())
00197         return;
00198 
00199       std_msgs::String status;
00200       status.data = "Running grasp planning action!";
00201       pub_im_status_.publish(status);
00202 
00203       //pr2_grasp_adjust::GraspAdjustResult result;
00204       object_manipulation_msgs::GraspPlanningResult result;
00205 
00206       ROS_INFO("Received action request, cloud with %d points!", goal->target.region.cloud.width * goal->target.region.cloud.height);
00207 
00208       //pub_cloud_.publish(goal->target.region.cloud);
00209 
00210       bool success = false;
00211 
00212       pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());
00213       pcl::PointCloud<PointT>::Ptr cloudT(new pcl::PointCloud<PointT>());
00214       pcl::PointCloud<PointT>::Ptr cloud_filtered(new pcl::PointCloud<PointT>());
00215       pcl::fromROSMsg(goal->target.region.cloud, *cloud);
00216       cloud->header.stamp = ros::Time(0);
00217       pcl::copyPointCloud(*cloud, *cloudT);
00218       pcl::copyPointCloud(*cloud, *cloud_filtered);
00219       ROS_ASSERT(cloudT->points.size() == cloud_filtered->points.size());
00220 
00221 
00222 
00223 
00224       // ----------------
00225 
00226       // Create the filtering object
00227       pcl::VoxelGrid<PointT > vox;
00228       vox.setInputCloud (cloudT);
00229       vox.setLeafSize (0.003, 0.003, 0.003);
00230       vox.setFilterFieldName("z");
00231       vox.setFilterLimits(-100, 100);
00232       vox.filter (*cloud_filtered);
00233 
00234       ROS_INFO("Down-sampled cloud has %d points!", (int)cloud_filtered->points.size());
00235 
00236 
00237 
00238       // Estimate point normals
00239       pcl::search::KdTree<PointT>::Ptr tree (new pcl::search::KdTree<PointT> ());
00240       pcl::NormalEstimationOMP<PointT, PointT> ne;
00241       ne.setSearchMethod (tree);
00242       ne.setInputCloud (cloud_filtered);
00243       ne.setKSearch (12);
00244       ne.compute (*cloud_filtered);
00245       ROS_INFO("Cloud in frame %s has %d points, stamp %f!",
00246                cloud_filtered->header.frame_id.c_str(),
00247                (int)cloud_filtered->size(),
00248                cloud_filtered->header.stamp.toSec());
00249 
00250       if(pub_cloud_.getNumSubscribers() > 0)
00251       {
00252         sensor_msgs::PointCloud2 cloud_out;
00253         pcl::toROSMsg(*cloud_filtered, cloud_out);
00254         pub_cloud_.publish(cloud_out);
00255       }
00256 
00257 
00258 
00259 //      grasp_adjust_.setInputCloud(cloud);
00260 //      ROS_INFO("Finished preparing cloud!");
00261 
00262       //Generate start poses from the top and sides
00263       std::vector<geometry_msgs::PoseStamped> start_poses;
00264 
00265       // -----------------
00266 
00267       if(goal->grasps_to_evaluate.empty())
00268       {
00269         geometry_msgs::Vector3Stamped seed_normal;
00270         seed_normal.header.frame_id = "/base_link";
00271         seed_normal.header.stamp = cloud->header.stamp;
00272         seed_normal.vector = object_manipulator::msg::createVector3Msg(0,0,-1);
00273         tfl_.transformVector(cloud_filtered->header.frame_id, seed_normal, seed_normal);
00274 
00275         geometry_msgs::Vector3Stamped forward;
00276         forward.header.frame_id = "/base_link";
00277         forward.header.stamp = cloud->header.stamp;
00278         forward.vector = object_manipulator::msg::createVector3Msg(1,0,0);
00279         tfl_.transformVector(cloud_filtered->header.frame_id, forward, forward);
00280 
00281         geometry_msgs::Vector3Stamped right;
00282         right.header.frame_id = "/base_link";
00283         right.header.stamp = cloud->header.stamp;
00284         right.vector = object_manipulator::msg::createVector3Msg(0,-1,0);
00285         tfl_.transformVector(cloud_filtered->header.frame_id, right, right);
00286 
00287         // poses
00288 //        start_poses.push_back(generateAlignedPose(goal->pose_stamped, seed_normal.vector, forward.vector));
00289 //        start_poses.push_back(generateAlignedPose(goal->pose_stamped, seed_normal.vector, right.vector));
00290       }
00291       else
00292       {
00293         for(unsigned int i = 0; i < goal->grasps_to_evaluate.size(); i++)
00294         {
00295           start_poses.push_back(
00296               object_manipulator::msg::createPoseStampedMsg( goal->grasps_to_evaluate[i].grasp_pose,
00297                                                              goal->target.reference_frame_id, ros::Time(0)));
00298         }
00299       }
00300 
00301       grasp_adjust_.setInputCloud(*cloud_filtered);
00302 
00303       std::priority_queue<GripperModel, std::vector<GripperModel>, GripperModel::compareModels> ranked_poses;
00304 
00305       //Adjust the start poses to find good grasps
00306       for(size_t start_pose_ind=0; start_pose_ind < start_poses.size(); start_pose_ind++)
00307       {
00308         int mode = GLOBAL_SEARCH;
00309         int value = grasp_adjust_.findGrasps(start_poses[start_pose_ind], &ranked_poses, mode,  goal->target.reference_frame_id);
00310         success = success || (value == object_manipulation_msgs::GraspPlanningErrorCode::SUCCESS);
00311       }
00312 
00313       if (as_.isPreemptRequested() || !ros::ok())
00314       {
00315         ROS_INFO("%s: Preempted", action_name_.c_str());
00316         // set the action state to preempted
00317         as_.setPreempted();
00318         success = false;
00319       }
00320       if(success)
00321       {
00322         result.error_code.value = object_manipulation_msgs::GraspPlanningErrorCode::SUCCESS;
00323       }
00324 
00325       ROS_INFO("Globally, found %d valid poses!", (int)ranked_poses.size());
00326       while(success && !ranked_poses.empty())
00327       {
00328         GripperModel model = ranked_poses.top();
00329         ranked_poses.pop();
00330         ROS_INFO("Pose with score %.3f", model.score_);
00331         geometry_msgs::PoseStamped ps;
00332         model.toPoseStamped(ps);
00333         model.publishModel(pub_marker_array_, "grasp_adjust_action", 0, ros::Duration(), model.score_*model.score_);
00334 
00335         object_manipulation_msgs::Grasp grasp;
00336 
00337         grasp.grasp_pose = ps.pose;
00338         grasp.min_approach_distance = 0.05;
00339         grasp.desired_approach_distance = 0.07;
00340         grasp.success_probability = model.score_;
00341 
00342         result.grasps.push_back(grasp);
00343 
00344       }
00345 
00346 
00347 
00348       if(success)
00349       {
00350         ROS_INFO("%s: Succeeded", action_name_.c_str());
00351         status.data = "Found a grasp!";
00352         pub_im_status_.publish(status);
00353         as_.setSucceeded(result);
00354       }
00355       else
00356       {
00357         ROS_INFO("%s: Failed", action_name_.c_str());
00358         status.data = "Didn't find a grasp; keeping previous pose.";
00359         pub_im_status_.publish(status);
00360         as_.setAborted();
00361       }
00362     }
00363 
00369     bool graspAdjustCallback(   pr2_grasp_adjust::GraspAdjust::Request  &req,
00370                                 pr2_grasp_adjust::GraspAdjust::Response &res )
00371     {
00372 
00373         int mode = req.search_mode;
00374         res.result.value = grasp_adjust_.findGrasps(req.grasp_pose, &(res.grasp_poses), &(res.pose_scores), mode);
00375 
00376         ROS_INFO("pr2_grasp_adjust::grasp_adjust returned %d", res.result.value);
00377 
00378         return true;
00379     }
00380 
00386     void setupGraspPlanning(object_manipulation_msgs::GraspPlanning::Request &req, pcl::PointCloud<PointT> &cloud)
00387     {
00388       pcl::PointCloud<pcl::PointXYZ> cloud_in;
00389       //pcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal> ());
00390       sensor_msgs::PointCloud2 cloud_msg;
00391 
00392       sensor_msgs::convertPointCloudToPointCloud2(req.target.cluster, cloud_msg);
00393       ROS_INFO("Cloud_in in frame %s, reference frame %s!", cloud_msg.header.frame_id.c_str(), req.target.reference_frame_id.c_str());
00394       //for(int i = 0; i < cloud_msg.fields.size(); i++) ROS_INFO_STREAM("Cloud msg has field " << cloud_msg.fields[i]);
00395       pcl::fromROSMsg(cloud_msg, cloud_in);
00396 
00397       prepareCloud(cloud_in, cloud);
00398   }
00399 
00400   void prepareCloud(pcl::PointCloud<pcl::PointXYZ> cloud_in, pcl::PointCloud<PointT> &cloud)
00401   {
00402 
00403     // Estimate point normals
00404     pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ());
00405     pcl::NormalEstimation<pcl::PointXYZ, PointT> ne;
00406     ne.setSearchMethod (tree);
00407     ne.setInputCloud (boost::make_shared<pcl::PointCloud<pcl::PointXYZ> >(cloud_in));
00408     ne.setKSearch (15);
00409     ne.compute (cloud);
00410     for(unsigned int i = 0; i < cloud_in.size(); i++){
00411       cloud.points[i].x = cloud_in.points[i].x;
00412       cloud.points[i].y = cloud_in.points[i].y;
00413       cloud.points[i].z = cloud_in.points[i].z;
00414     }
00415     ROS_INFO("Cloud_out in frame %s has %d points, stamp %f!", cloud.header.frame_id.c_str(), (int)cloud.size(), cloud.header.stamp.toSec());
00416 
00417     if(pub_cloud_.getNumSubscribers() > 0)
00418     {
00419       sensor_msgs::PointCloud2 cloud_out;
00420       pcl::toROSMsg(cloud, cloud_out);
00421       pub_cloud_.publish(cloud_out);
00422     }
00423 
00424     grasp_adjust_.setInputCloud(cloud);
00425     ROS_INFO("Finished preparing cloud!");
00426   }
00427 
00428 
00429 
00433   void dynamicCallback(Config &new_config, uint32_t id)
00434     {
00435         // This info will get printed back to reconfigure gui
00436         char status[256] = "\0";
00437 
00438         switch(id)
00439         {
00440         case(-1): //Init // If you are tempted to put anything here, it should probably go in the constructor
00441           break;
00442         case(0): // Connect
00443           printf("Reconfigure GUI connected to me!\n");
00444           new_config = grasp_adjust_.config_;
00445           break;
00446         default:
00447           ROS_INFO("Dynamic reconfigure did something, variable id %d.", id);
00448         }
00449         grasp_adjust_.config_ = new_config;
00450         new_config.status = status;
00451     }
00452 };
00453 
00454 
00455 
00456 /* ---[ */
00457 int main (int argc, char* argv[])
00458 {
00459   ros::init(argc, argv, "grasp_adjust_action_server_node");
00460   GraspAdjustActionServer server(argv);
00461   ros::spin();
00462   return (0);
00463 }
00464 /* ]--- */


pr2_grasp_adjust
Author(s): Adam Leeper
autogenerated on Fri Jan 3 2014 12:00:29