visual_odometry.cpp
Go to the documentation of this file.
00001 
00024 #include "ccny_rgbd/apps/visual_odometry.h"
00025 
00026 namespace ccny_rgbd {
00027   
00028 VisualOdometry::VisualOdometry(
00029   const ros::NodeHandle& nh, 
00030   const ros::NodeHandle& nh_private):
00031   nh_(nh), 
00032   nh_private_(nh_private),
00033   initialized_(false),
00034   frame_count_(0)
00035 {
00036   ROS_INFO("Starting RGBD Visual Odometry");
00037 
00038   // **** initialize ROS parameters
00039   
00040   initParams();
00041 
00042   // **** inititialize state variables
00043   
00044   f2b_.setIdentity();
00045 
00046   // **** publishers
00047 
00048   odom_publisher_ = nh_.advertise<OdomMsg>(
00049     "vo", queue_size_);
00050   cloud_publisher_ = nh_.advertise<PointCloudFeature>(
00051     "feature/cloud", 1);
00052   path_pub_ = nh_.advertise<PathMsg>(
00053     "path", queue_size_);
00054   
00055   // **** subscribers
00056   
00057   ImageTransport rgb_it(nh_);
00058   ImageTransport depth_it(nh_);
00059 
00060   sub_rgb_.subscribe(rgb_it,     "/rgbd/rgb",   queue_size_);
00061   sub_depth_.subscribe(depth_it, "/rgbd/depth", queue_size_);
00062   sub_info_.subscribe(nh_,       "/rgbd/info",  queue_size_);
00063   
00064   // Synchronize inputs.
00065   sync_.reset(new RGBDSynchronizer3(
00066                 RGBDSyncPolicy3(queue_size_), sub_rgb_, sub_depth_, sub_info_));
00067   
00068   sync_->registerCallback(boost::bind(&VisualOdometry::RGBDCallback, this, _1, _2, _3));  
00069 }
00070 
00071 VisualOdometry::~VisualOdometry()
00072 {
00073   ROS_INFO("Destroying RGBD Visual Odometry"); 
00074 }
00075 
00076 void VisualOdometry::initParams()
00077 {
00078   if (!nh_private_.getParam ("publish_tf", publish_tf_))
00079     publish_tf_ = true;  
00080   if (!nh_private_.getParam ("publish_path", publish_path_))
00081     publish_path_ = true;
00082   if (!nh_private_.getParam ("publish_odom", publish_odom_))
00083     publish_odom_ = true;
00084   if (!nh_private_.getParam ("fixed_frame", fixed_frame_))
00085     fixed_frame_ = "/odom";
00086   if (!nh_private_.getParam ("base_frame", base_frame_))
00087     base_frame_ = "/camera_link";
00088   if (!nh_private_.getParam ("queue_size", queue_size_))
00089     queue_size_ = 5;
00090 
00091   // detector params
00092   
00093   if (!nh_private_.getParam ("feature/publish_cloud", publish_cloud_))
00094     publish_cloud_ = false;
00095   if (!nh_private_.getParam ("feature/detector_type", detector_type_))
00096     detector_type_ = "GFT";
00097   
00098   resetDetector();
00099   
00100   int smooth;
00101   double max_range, max_stdev;
00102   
00103   if (!nh_private_.getParam ("feature/smooth", smooth))
00104     smooth = 0;
00105   if (!nh_private_.getParam ("feature/max_range", max_range))
00106     max_range = 5.5;
00107   if (!nh_private_.getParam ("feature/max_stdev", max_stdev))
00108     max_stdev = 0.03;
00109   
00110   feature_detector_->setSmooth(smooth);
00111   feature_detector_->setMaxRange(max_range);
00112   feature_detector_->setMaxStDev(max_stdev);
00113   
00114   // registration params
00115   
00116   if (!nh_private_.getParam ("reg/reg_type", reg_type_))
00117     reg_type_ = "ICPProbModel";
00118   
00119   if      (reg_type_ == "ICP")
00120     motion_estimation_ = new MotionEstimationICP(nh_, nh_private_);
00121   else if (reg_type_ == "ICPProbModel")
00122     motion_estimation_ = new MotionEstimationICPProbModel(nh_, nh_private_);
00123   else
00124     ROS_FATAL("%s is not a valid registration type!", reg_type_.c_str());
00125 }
00126 
00127 void VisualOdometry::resetDetector()
00128 {  
00129   gft_config_server_.reset();
00130   star_config_server_.reset();
00131   orb_config_server_.reset();
00132   surf_config_server_.reset();
00133   
00134   if (detector_type_ == "ORB")
00135   { 
00136     ROS_INFO("Creating ORB detector");
00137     feature_detector_.reset(new OrbDetector());
00138     orb_config_server_.reset(new 
00139       OrbDetectorConfigServer(ros::NodeHandle(nh_private_, "feature/ORB")));
00140     
00141     // dynamic reconfigure
00142     OrbDetectorConfigServer::CallbackType f = boost::bind(
00143       &VisualOdometry::orbReconfigCallback, this, _1, _2);
00144     orb_config_server_->setCallback(f);
00145   }
00146   else if (detector_type_ == "SURF")
00147   {
00148     ROS_INFO("Creating SURF detector");
00149     feature_detector_.reset(new SurfDetector());
00150     surf_config_server_.reset(new 
00151       SurfDetectorConfigServer(ros::NodeHandle(nh_private_, "feature/SURF")));
00152     
00153     // dynamic reconfigure
00154     SurfDetectorConfigServer::CallbackType f = boost::bind(
00155       &VisualOdometry::surfReconfigCallback, this, _1, _2);
00156     surf_config_server_->setCallback(f);
00157   }
00158   else if (detector_type_ == "GFT")
00159   {
00160     ROS_INFO("Creating GFT detector");
00161     feature_detector_.reset(new GftDetector());
00162     gft_config_server_.reset(new 
00163       GftDetectorConfigServer(ros::NodeHandle(nh_private_, "feature/GFT")));
00164     
00165     // dynamic reconfigure
00166     GftDetectorConfigServer::CallbackType f = boost::bind(
00167       &VisualOdometry::gftReconfigCallback, this, _1, _2);
00168     gft_config_server_->setCallback(f);
00169   }
00170   else if (detector_type_ == "STAR")
00171   {
00172     ROS_INFO("Creating STAR detector");
00173     feature_detector_.reset(new StarDetector());
00174     star_config_server_.reset(new 
00175       StarDetectorConfigServer(ros::NodeHandle(nh_private_, "feature/STAR")));
00176     
00177     // dynamic reconfigure
00178     StarDetectorConfigServer::CallbackType f = boost::bind(
00179       &VisualOdometry::starReconfigCallback, this, _1, _2);
00180     star_config_server_->setCallback(f);
00181   }
00182   else
00183   {
00184     ROS_FATAL("%s is not a valid detector type! Using GFT", detector_type_.c_str());
00185     feature_detector_.reset(new GftDetector());
00186     gft_config_server_.reset(new 
00187       GftDetectorConfigServer(ros::NodeHandle(nh_private_, "feature/GFT")));
00188     
00189     // dynamic reconfigure
00190     GftDetectorConfigServer::CallbackType f = boost::bind(
00191       &VisualOdometry::gftReconfigCallback, this, _1, _2);
00192     gft_config_server_->setCallback(f);
00193   }
00194 }
00195 
00196 void VisualOdometry::RGBDCallback(
00197   const ImageMsg::ConstPtr& rgb_msg,
00198   const ImageMsg::ConstPtr& depth_msg,
00199   const CameraInfoMsg::ConstPtr& info_msg)
00200 {
00201   ros::WallTime start = ros::WallTime::now();
00202 
00203   // **** initialize ***************************************************
00204 
00205   if (!initialized_)
00206   {
00207     initialized_ = getBaseToCameraTf(rgb_msg->header);
00208     init_time_ = rgb_msg->header.stamp;
00209     if (!initialized_) return;
00210 
00211     motion_estimation_->setBaseToCameraTf(b2c_);
00212   }
00213 
00214   // **** create frame *************************************************
00215 
00216   ros::WallTime start_frame = ros::WallTime::now();
00217   RGBDFrame frame(rgb_msg, depth_msg, info_msg);
00218   ros::WallTime end_frame = ros::WallTime::now();
00219 
00220   // **** find features ************************************************
00221 
00222   ros::WallTime start_features = ros::WallTime::now();
00223   feature_detector_->findFeatures(frame);
00224   ros::WallTime end_features = ros::WallTime::now();
00225 
00226   // **** registration *************************************************
00227   
00228   ros::WallTime start_reg = ros::WallTime::now();
00229   tf::Transform motion = motion_estimation_->getMotionEstimation(frame);
00230   f2b_ = motion * f2b_;
00231   ros::WallTime end_reg = ros::WallTime::now();
00232 
00233   // **** publish outputs **********************************************
00234   
00235   if (publish_tf_)   publishTf(rgb_msg->header);
00236   if (publish_odom_) publishOdom(rgb_msg->header);
00237   if (publish_path_) publishPath(rgb_msg->header);
00238 
00239   if (publish_cloud_) publishFeatureCloud(frame);
00240 
00241   // **** print diagnostics *******************************************
00242 
00243   ros::WallTime end = ros::WallTime::now();
00244 
00245   int n_features = frame.keypoints.size();
00246   int n_valid_features = frame.n_valid_keypoints;
00247   int n_model_pts = motion_estimation_->getModelSize();
00248 
00249   double d_frame    = 1000.0 * (end_frame    - start_frame   ).toSec();
00250   double d_features = 1000.0 * (end_features - start_features).toSec();
00251   double d_reg      = 1000.0 * (end_reg      - start_reg     ).toSec();
00252   double d_total    = 1000.0 * (end          - start         ).toSec();
00253 
00254   printf("[VO %d] Fr: %2.1f %s[%d][%d]: %3.1f %s[%d] %4.1f TOTAL %4.1f\n",
00255     frame_count_,
00256     d_frame, 
00257     detector_type_.c_str(), n_features, n_valid_features, d_features, 
00258     reg_type_.c_str(), n_model_pts, d_reg, 
00259     d_total);
00260 
00261   frame_count_++;
00262 }
00263 
00264 void VisualOdometry::publishTf(const std_msgs::Header& header)
00265 {
00266   tf::StampedTransform transform_msg(
00267    f2b_, header.stamp, fixed_frame_, base_frame_);
00268   tf_broadcaster_.sendTransform (transform_msg);
00269 }
00270 
00271 void VisualOdometry::publishOdom(const std_msgs::Header& header)
00272 {
00273   OdomMsg odom;
00274   odom.header.stamp = header.stamp;
00275   odom.header.frame_id = fixed_frame_;
00276   tf::poseTFToMsg(f2b_, odom.pose.pose);
00277   odom_publisher_.publish(odom);
00278 }
00279 
00280 void VisualOdometry::publishPath(const std_msgs::Header& header)
00281 {
00282   path_msg_.header.stamp = header.stamp;
00283   path_msg_.header.frame_id = fixed_frame_;
00284 
00285   geometry_msgs::PoseStamped pose_stamped;
00286   pose_stamped.header.stamp = header.stamp;
00287   pose_stamped.header.frame_id = fixed_frame_;
00288   tf::poseTFToMsg(f2b_, pose_stamped.pose);
00289 
00290   path_msg_.poses.push_back(pose_stamped);
00291   path_pub_.publish(path_msg_);
00292 }
00293 
00294 void VisualOdometry::publishFeatureCloud(RGBDFrame& frame)
00295 {
00296   PointCloudFeature cloud;
00297   cloud.header = frame.header;
00298   frame.constructFeaturePointCloud(cloud);   
00299   cloud_publisher_.publish(cloud);
00300 }
00301 
00302 bool VisualOdometry::getBaseToCameraTf(const std_msgs::Header& header)
00303 {
00304   tf::StampedTransform tf_m;
00305 
00306   try
00307   {
00308     tf_listener_.waitForTransform(
00309       base_frame_, header.frame_id, header.stamp, ros::Duration(1.0));
00310     tf_listener_.lookupTransform (
00311       base_frame_, header.frame_id, header.stamp, tf_m);
00312   }
00313   catch (tf::TransformException& ex)
00314   {
00315     ROS_WARN("Base to camera transform unavailable %s", ex.what());
00316     return false;
00317   }
00318 
00319   b2c_ = tf_m;
00320 
00321   return true;
00322 }
00323 
00324 void VisualOdometry::gftReconfigCallback(GftDetectorConfig& config, uint32_t level)
00325 {
00326   GftDetectorPtr gft_detector = 
00327     boost::static_pointer_cast<GftDetector>(feature_detector_);
00328     
00329   gft_detector->setNFeatures(config.n_features);
00330   gft_detector->setMinDistance(config.min_distance); 
00331 }
00332 
00333 void VisualOdometry::starReconfigCallback(StarDetectorConfig& config, uint32_t level)
00334 {
00335   StarDetectorPtr star_detector = 
00336     boost::static_pointer_cast<StarDetector>(feature_detector_);
00337     
00338   star_detector->setThreshold(config.threshold);
00339   star_detector->setMinDistance(config.min_distance); 
00340 }
00341 
00342 void VisualOdometry::surfReconfigCallback(SurfDetectorConfig& config, uint32_t level)
00343 {
00344   SurfDetectorPtr surf_detector = 
00345     boost::static_pointer_cast<SurfDetector>(feature_detector_);
00346     
00347   surf_detector->setThreshold(config.threshold);
00348 }
00349     
00350 void VisualOdometry::orbReconfigCallback(OrbDetectorConfig& config, uint32_t level)
00351 {
00352   OrbDetectorPtr orb_detector = 
00353     boost::static_pointer_cast<OrbDetector>(feature_detector_);
00354     
00355   orb_detector->setThreshold(config.threshold);
00356   orb_detector->setNFeatures(config.n_features);
00357 }
00358 
00359 } // namespace ccny_rgbd
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends


ccny_rgbd
Author(s): Ivan Dryanovski
autogenerated on Fri Apr 12 2013 20:38:48