Go to the documentation of this file.00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 #include <ros/ros.h>
00031 
00032 
00033 #include <actionlib/server/action_server.h>
00034 #include <pr2_tilt_laser_interface/GetSnapshotAction.h>
00035 
00036 
00037 #include <pr2_msgs/SetLaserTrajCmd.h>
00038 
00039 
00040 #include <sensor_msgs/LaserScan.h>
00041 #include <laser_geometry/laser_geometry.h>
00042 #include <pcl_ros/transforms.h>
00043 
00044 #include <tf/transform_listener.h>
00045 #include "tf/message_filter.h"
00046 #include <message_filters/subscriber.h>
00047 #include <pcl/io/io.h>
00048 
00049 void appendCloud(sensor_msgs::PointCloud2& dest, const sensor_msgs::PointCloud2& src)
00050 {
00051   
00052   dest.height += 1;
00053 
00054   size_t start = dest.data.size ();
00055 
00056   if (start == 0)
00057   {
00058     dest = src;
00059     return;
00060   }
00061 
00062   dest.data.resize (start + src.data.size ());
00063   memcpy (&dest.data[start], &src.data[0], src.data.size ());
00064 
00065   
00066   int time_index = src.fields[pcl::getFieldIndex (dest, "timestamp")].offset;
00067   float time_offset = src.header.stamp.toSec () - dest.header.stamp.toSec ();
00068   float* time_ptr;
00069   for (size_t i = 0; i < src.width * src.height; ++i)
00070   {
00071     time_ptr = (float*) &dest.data[start + i * src.point_step + time_index];
00072     *time_ptr += time_offset;
00073   }
00074 }
00075 
00076 using namespace pr2_tilt_laser_interface;
00077 
00078 namespace SnapshotStates
00079 {
00080   enum SnapshotState
00081   {
00082     COLLECTING = 1,
00083     IDLE = 2
00084   };
00085 }
00086 typedef SnapshotStates::SnapshotState SnapshotState;
00087 
00088 typedef actionlib::ActionServer<GetSnapshotAction> SnapshotActionServer;
00089 
00090 class Snapshotter
00091 {
00092 public:
00093   Snapshotter();
00094 
00095   void startScan(double move_to_start_wait_time=1.0);
00096   
00097   void scanCallback(const sensor_msgs::LaserScanConstPtr& scan);
00098 
00099   
00100   void goalCallback(SnapshotActionServer::GoalHandle gh);
00101   void cancelCallback(SnapshotActionServer::GoalHandle gh);
00102 
00103 private:
00104   ros::NodeHandle nh_;
00105   SnapshotActionServer as_;
00106 
00107   message_filters::Subscriber<sensor_msgs::LaserScan> scan_sub_;
00108   ros::ServiceClient laser_controller_sc_;
00109 
00110   boost::mutex state_mutex_;
00111   SnapshotState state_;
00112   ros::Time interval_start_;
00113   ros::Time interval_end_;
00114   laser_geometry::LaserProjection lg_;
00115   GetSnapshotResult snapshot_result_;
00116   GetSnapshotFeedback snapshot_feedback_;
00117 
00118   SnapshotActionServer::GoalHandle current_gh_;
00119   GetSnapshotGoal goal_;
00120 
00121   tf::TransformListener tf_;
00122   std::string fixed_frame_;
00123   boost::scoped_ptr<tf::MessageFilter<sensor_msgs::LaserScan> > tf_filter_;
00124   
00125 };
00126 
00127 Snapshotter::Snapshotter() :
00128   as_(nh_, "get_laser_snapshot", false),
00129   state_(SnapshotStates::IDLE),
00130   tf_(nh_)
00131 {
00132   as_.registerGoalCallback(    boost::bind(&Snapshotter::goalCallback,    this, _1) );
00133   as_.registerCancelCallback(  boost::bind(&Snapshotter::cancelCallback, this, _1) );
00134 
00135   
00136   
00137   laser_controller_sc_ = nh_.serviceClient<pr2_msgs::SetLaserTrajCmd>("laser_tilt_controller/set_traj_cmd");
00138 
00139   
00140   ros::NodeHandle private_ns_("~");
00141   if (!private_ns_.getParam("fixed_frame", fixed_frame_))
00142       ROS_FATAL("Need to set parameter ~fixed_frame");
00143   ROS_DEBUG("Using fixed frame [%s]", fixed_frame_.c_str());
00144 
00145   
00146   scan_sub_.subscribe(nh_, "tilt_scan", 10);
00147   tf_filter_.reset( new tf::MessageFilter<sensor_msgs::LaserScan>(scan_sub_, tf_, fixed_frame_, 10) );
00148   tf_filter_->setTolerance(ros::Duration(0.025));
00149   tf_filter_->registerCallback( boost::bind(&Snapshotter::scanCallback, this, _1) );
00150 
00151   
00152   as_.start();
00153 }
00154 
00155 void Snapshotter::scanCallback(const sensor_msgs::LaserScanConstPtr& scan)
00156 {
00157   boost::mutex::scoped_lock lock(state_mutex_);
00158 
00159   if (state_ == SnapshotStates::IDLE)
00160     return;
00161 
00162   sensor_msgs::PointCloud2& cloud = (goal_.continuous ? snapshot_feedback_.cloud : snapshot_result_.cloud);
00163   
00164   if (state_ == SnapshotStates::COLLECTING)
00165   {
00166     if (scan->header.stamp < interval_start_)
00167     {
00168       ROS_DEBUG("Waiting to get to the start of the interval");
00169       
00170       return;
00171     }
00172     else if (scan->header.stamp < interval_end_)
00173     {
00174       
00175       ROS_DEBUG("In the actual interval");
00176       sensor_msgs::PointCloud2 cur_cloud_tf;
00177 
00178       if (!goal_.hi_fidelity)
00179       {
00180         sensor_msgs::PointCloud2 cur_cloud;
00181         lg_.projectLaser (*scan, cur_cloud);
00182         tf::StampedTransform net_transform;
00183         tf_.lookupTransform (fixed_frame_, cur_cloud.header.frame_id, cur_cloud.header.stamp, net_transform);
00184         pcl_ros::transformPointCloud (fixed_frame_, net_transform, cur_cloud, cur_cloud_tf);
00185       }
00186       else
00187       {
00188         lg_.transformLaserScanToPointCloud (fixed_frame_, *scan, cur_cloud_tf, tf_);
00189       }
00190       appendCloud (cloud, cur_cloud_tf);
00191     }
00192     else
00193     {
00194       ROS_DEBUG ("Bundling everything up and publishing cloud with %u points", cloud.width * cloud.width);
00195 
00196       state_ = SnapshotStates::IDLE;
00197       
00198       if (goal_.continuous)
00199       {
00200         
00201         current_gh_.publishFeedback (snapshot_feedback_);
00202         std::swap(goal_.start_angle, goal_.end_angle);
00203         startScan(0.1);
00204       }
00205       else
00206       {
00207         current_gh_.setSucceeded (snapshot_result_);
00208       }
00209       cloud.data.clear ();
00210     }
00211   }
00212   else
00213     ROS_ERROR("In an unknown state.  This is a programming error");
00214 
00215 }
00216 
00217 void Snapshotter::goalCallback(SnapshotActionServer::GoalHandle gh)
00218 {
00219   boost::mutex::scoped_lock lock(state_mutex_);
00220   
00221   
00222   if (state_ != SnapshotStates::IDLE)
00223   {
00224     current_gh_.setCanceled();
00225     state_ = SnapshotStates::IDLE;
00226   }
00227 
00228   current_gh_ = gh;
00229   current_gh_.setAccepted();
00230   
00231   goal_ = *current_gh_.getGoal();
00232 
00233   startScan();
00234 }
00235 
00236 void Snapshotter::startScan(double move_to_start_wait_time)
00237 {
00238   
00239 
00240   
00241 
00242   pr2_msgs::LaserTrajCmd cmd;
00243 
00244   cmd.profile = "linear";
00245   cmd.position.resize(4);
00246   cmd.position[0] = goal_.start_angle;
00247   cmd.position[1] = goal_.start_angle;
00248   cmd.position[2] = goal_.end_angle;
00249   cmd.position[3] = (goal_.continuous ? goal_.end_angle : goal_.start_angle);
00250 
00251   if (goal_.speed==0.0)
00252   {
00253     ROS_ERROR("Scan speed is set to zero -> aborting!\n");
00254     return;
00255   }
00256   
00257   ros::Duration scan_duration( (goal_.start_angle - goal_.end_angle)/goal_.speed );
00258   if (scan_duration.toSec() < 0.0)
00259     scan_duration = -scan_duration;
00260 
00261   ros::Duration wait_time(move_to_start_wait_time);
00262   cmd.time_from_start.resize(4);
00263   cmd.time_from_start[0] = ros::Duration(0.0);
00264   cmd.time_from_start[1] = wait_time;
00265   cmd.time_from_start[2] = wait_time + scan_duration;
00266   cmd.time_from_start[3] = wait_time + scan_duration + scan_duration;
00267   cmd.max_velocity = 0;
00268   cmd.max_acceleration= 0;
00269 
00270   pr2_msgs::SetLaserTrajCmd laser_srv_cmd;
00271   laser_srv_cmd.request.command = cmd;
00272 
00273   laser_controller_sc_.call(laser_srv_cmd);
00274 
00275   
00276   interval_start_ = laser_srv_cmd.response.start_time + cmd.time_from_start[1];
00277   interval_end_   = laser_srv_cmd.response.start_time + cmd.time_from_start[2];
00278 
00279   
00280   assert(state_ == SnapshotStates::IDLE);
00281   state_ = SnapshotStates::COLLECTING;
00282   
00283   snapshot_feedback_.cloud.data.clear();
00284   snapshot_result_.cloud.data.clear();
00285 }
00286 
00287 void Snapshotter::cancelCallback(SnapshotActionServer::GoalHandle gh)
00288 {
00289   boost::mutex::scoped_lock lock(state_mutex_);
00290 
00291   
00292   if (current_gh_ != gh)
00293   {
00294     ROS_DEBUG("Got a cancel request for some other goal. Ignoring it");
00295     return;
00296   }
00297   current_gh_.setCanceled();
00298   state_ = SnapshotStates::IDLE;
00299 }
00300 
00301 
00302 
00303   
00304             
00305             
00306             
00307             
00308             
00309 
00310 
00311 int main(int argc, char** argv)
00312 {
00314   
00315   
00316     
00317       
00318         
00319         
00320         
00321       
00322         
00323         
00324     
00325   
00326   
00327   ros::init(argc, argv, "laser_snapshotter");
00328   Snapshotter snapshotter;
00329   ros::spin();
00330 }