gazebo_ros_depth_camera.cpp
Go to the documentation of this file.
00001 /*
00002  *  Gazebo - Outdoor Multi-Robot Simulator
00003  *  Copyright (C) 2003
00004  *     Nate Koenig & Andrew Howard
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  */
00021 /*
00022  @mainpage
00023    Desc: GazeboRosDepthCamera plugin for simulating cameras in Gazebo
00024    Author: John Hsu
00025    Date: 24 Sept 2008
00026    SVN info: $Id$
00027  @htmlinclude manifest.html
00028  @b GazeboRosDepthCamera plugin broadcasts ROS Image messages
00029  */
00030 
00031 #include <algorithm>
00032 #include <assert.h>
00033 #include <boost/thread/thread.hpp>
00034 #include <boost/bind.hpp>
00035 
00036 #include <gazebo_plugins/gazebo_ros_depth_camera.h>
00037 
00038 #include "sensors/Sensor.hh"
00039 #include "sdf/interface/SDF.hh"
00040 #include "sensors/SensorTypes.hh"
00041 
00042 // for creating PointCloud2 from pcl point cloud
00043 #include "pcl/ros/conversions.h"
00044 
00045 #include "tf/tf.h"
00046 
00047 namespace gazebo
00048 {
00049 
00051 // Constructor
00052 GazeboRosDepthCamera::GazeboRosDepthCamera()
00053 {
00054   this->point_cloud_connect_count_ = 0;
00055 }
00056 
00058 // Destructor
00059 GazeboRosDepthCamera::~GazeboRosDepthCamera()
00060 {
00061 }
00062 
00064 // Increment count
00065 void GazeboRosDepthCamera::InfoConnect()
00066 {
00067   this->info_connect_count_++;
00068 }
00070 // Decrement count
00071 void GazeboRosDepthCamera::InfoDisconnect()
00072 {
00073   this->info_connect_count_--;
00074 }
00075 
00077 // Load the controller
00078 void GazeboRosDepthCamera::Load(sensors::SensorPtr _parent, sdf::ElementPtr _sdf)
00079 {
00080   DepthCameraPlugin::Load(_parent, _sdf);
00081 
00082   // copying from DepthCameraPlugin into GazeboRosCameraUtils
00083   this->parentSensor_ = this->parentSensor;
00084   this->width_ = this->width;
00085   this->height_ = this->height;
00086   this->depth_ = this->depth;
00087   this->format_ = this->format;
00088   this->camera_ = this->depthCamera;
00089 
00090   GazeboRosCameraUtils::Load(_parent, _sdf);
00091 
00092   // using a different default
00093   if (!_sdf->GetElement("imageTopicName"))
00094     this->image_topic_name_ = "ir/image_raw";
00095   if (!_sdf->HasElement("cameraInfoTopicName"))
00096     this->camera_info_topic_name_ = "ir/camera_info";
00097 
00098   // point cloud stuff
00099   if (!_sdf->GetElement("pointCloudTopicName"))
00100     this->point_cloud_topic_name_ = "points";
00101   else
00102     this->point_cloud_topic_name_ = _sdf->GetElement("pointCloudTopicName")->GetValueString();
00103 
00104   // depth image stuff
00105   if (!_sdf->GetElement("depthImageTopicName"))
00106     this->depth_image_topic_name_ = "depth/image_raw";
00107   else
00108     this->depth_image_topic_name_ = _sdf->GetElement("depthImageTopicName")->GetValueString();
00109 
00110   if (!_sdf->GetElement("depthImageCameraInfoTopicName"))
00111     this->depth_image_camera_info_topic_name_ = "depth/camera_info";
00112   else
00113     this->depth_image_camera_info_topic_name_ = _sdf->GetElement("depthImageCameraInfoTopicName")->GetValueString();
00114 
00115   if (!_sdf->GetElement("pointCloudCutoff"))
00116     this->point_cloud_cutoff_ = 0.4;
00117   else
00118     this->point_cloud_cutoff_ = _sdf->GetElement("pointCloudCutoff")->GetValueDouble();
00119 
00120   ros::AdvertiseOptions point_cloud_ao =
00121     ros::AdvertiseOptions::create<sensor_msgs::PointCloud2 >(
00122       this->point_cloud_topic_name_,1,
00123       boost::bind( &GazeboRosDepthCamera::PointCloudConnect,this),
00124       boost::bind( &GazeboRosDepthCamera::PointCloudDisconnect,this),
00125       ros::VoidPtr(), &this->camera_queue_);
00126   this->point_cloud_pub_ = this->rosnode_->advertise(point_cloud_ao);
00127 
00128   ros::AdvertiseOptions depth_image_ao =
00129     ros::AdvertiseOptions::create< sensor_msgs::Image >(
00130       this->depth_image_topic_name_,1,
00131       boost::bind( &GazeboRosDepthCamera::PointCloudConnect,this),
00132       boost::bind( &GazeboRosDepthCamera::PointCloudDisconnect,this),
00133       ros::VoidPtr(), &this->camera_queue_);
00134   this->depth_image_pub_ = this->rosnode_->advertise(depth_image_ao);
00135 
00136   ros::AdvertiseOptions depth_image_camera_info_ao =
00137     ros::AdvertiseOptions::create<sensor_msgs::CameraInfo>(
00138         this->depth_image_camera_info_topic_name_,1,
00139         boost::bind( &GazeboRosDepthCamera::InfoConnect,this),
00140         boost::bind( &GazeboRosDepthCamera::InfoDisconnect,this),
00141         ros::VoidPtr(), &this->camera_queue_);
00142   this->depth_image_camera_info_pub_ = this->rosnode_->advertise(depth_image_camera_info_ao);
00143 
00144 }
00145 
00147 // Increment count
00148 void GazeboRosDepthCamera::PointCloudConnect()
00149 {
00150   this->point_cloud_connect_count_++;
00151   this->image_connect_count_++;
00152   this->parentSensor->SetActive(true);
00153 }
00155 // Decrement count
00156 void GazeboRosDepthCamera::PointCloudDisconnect()
00157 {
00158   this->point_cloud_connect_count_--;
00159   this->image_connect_count_--;
00160   if (this->point_cloud_connect_count_ <= 0)
00161     this->parentSensor->SetActive(false);
00162 }
00163 
00165 // Update the controller
00166 void GazeboRosDepthCamera::OnNewDepthFrame(const float *_image,
00167     unsigned int _width, unsigned int _height, unsigned int _depth,
00168     const std::string &_format)
00169 {
00170   this->depth_sensor_update_time_ = this->parentSensor->GetLastUpdateTime();
00171   if (!this->parentSensor->IsActive())
00172   {
00173     if (this->point_cloud_connect_count_ > 0)
00174       // do this first so there's chance for sensor to run 1 frame after activate
00175       this->parentSensor->SetActive(true);
00176   }
00177   else
00178   {
00179     if (this->point_cloud_connect_count_ > 0)
00180       this->FillPointdCloud(_image);
00181   }
00182 }
00183 
00185 // Update the controller
00186 void GazeboRosDepthCamera::OnNewRGBPointCloud(const float *_pcd,
00187     unsigned int _width, unsigned int _height, unsigned int _depth,
00188     const std::string &_format)
00189 {
00190   this->depth_sensor_update_time_ = this->parentSensor->GetLastUpdateTime();
00191   if (!this->parentSensor->IsActive())
00192   {
00193     if (this->point_cloud_connect_count_ > 0)
00194       // do this first so there's chance for sensor to run 1 frame after activate
00195       this->parentSensor->SetActive(true);
00196   }
00197   else
00198   {
00199     if (this->point_cloud_connect_count_ > 0)
00200     {
00201       this->lock_.lock();
00202       this->point_cloud_msg_.header.frame_id = this->frame_name_;
00203       this->point_cloud_msg_.header.stamp.sec = this->depth_sensor_update_time_.sec;
00204       this->point_cloud_msg_.header.stamp.nsec = this->depth_sensor_update_time_.nsec;
00205       this->point_cloud_msg_.width = this->width;
00206       this->point_cloud_msg_.height = this->height;
00207       this->point_cloud_msg_.row_step = this->point_cloud_msg_.point_step * this->width;
00208 
00209       pcl::PointCloud<pcl::PointXYZRGB> point_cloud;
00210       point_cloud.points.resize(0);
00211       point_cloud.is_dense = true;
00212 
00213       for (unsigned int i = 0; i < _width; i++)
00214       {
00215         for (unsigned int j = 0; j < _height; j++)
00216         {
00217           unsigned int index = (j * _width) + i;
00218           pcl::PointXYZRGB point;
00219           point.x = _pcd[4 * index];
00220           point.y = _pcd[4 * index + 1];
00221           point.z = _pcd[4 * index + 2];
00222           point.rgb = _pcd[4 * index + 3];
00223           point_cloud.points.push_back(point);
00224           if (i == _width /2 && j == _height / 2)
00225           {
00226             uint32_t rgb = *reinterpret_cast<int*>(&point.rgb);
00227             uint8_t r = (rgb >> 16) & 0x0000ff;
00228             uint8_t g = (rgb >> 8)  & 0x0000ff;
00229             uint8_t b = (rgb)       & 0x0000ff;
00230             std::cerr << (int)r << " " << (int)g << " " << (int)b << "\n";
00231           }
00232         }
00233       }
00234       point_cloud.header = this->point_cloud_msg_.header;
00235       pcl::toROSMsg(point_cloud, this->point_cloud_msg_);
00236 
00237       this->point_cloud_pub_.publish(this->point_cloud_msg_);
00238       this->lock_.unlock();
00239     }
00240   }
00241 }
00242 
00244 // Update the controller
00245 void GazeboRosDepthCamera::OnNewImageFrame(const unsigned char *_image,
00246     unsigned int _width, unsigned int _height, unsigned int _depth,
00247     const std::string &_format)
00248 {
00249   //ROS_ERROR("camera_ new frame %s %s",this->parentSensor_->GetName().c_str(),this->frame_name_.c_str());
00250   this->sensor_update_time_ = this->parentSensor->GetLastUpdateTime();
00251 
00252   if (!this->parentSensor->IsActive())
00253   {
00254     if (this->image_connect_count_ > 0)
00255       // do this first so there's chance for sensor to run 1 frame after activate
00256       this->parentSensor->SetActive(true);
00257   }
00258   else
00259   {
00260     if (this->image_connect_count_ > 0)
00261       this->PutCameraData(_image);
00262   }
00263 }
00264 
00266 // Put camera data to the interface
00267 void GazeboRosDepthCamera::FillPointdCloud(const float *_src)
00268 {
00269   this->lock_.lock();
00270 
00271   this->point_cloud_msg_.header.frame_id = this->frame_name_;
00272   this->point_cloud_msg_.header.stamp.sec = this->depth_sensor_update_time_.sec;
00273   this->point_cloud_msg_.header.stamp.nsec = this->depth_sensor_update_time_.nsec;
00274   this->point_cloud_msg_.width = this->width;
00275   this->point_cloud_msg_.height = this->height;
00276   this->point_cloud_msg_.row_step = this->point_cloud_msg_.point_step * this->width;
00277 
00279   FillPointCloudHelper(this->point_cloud_msg_,
00280                  this->height,
00281                  this->width,
00282                  1,
00283                  (void*)_src );
00284 
00285   this->point_cloud_pub_.publish(this->point_cloud_msg_);
00286 
00287   // copy data into image
00288   this->depth_image_msg_.header.frame_id = this->frame_name_;
00289   this->depth_image_msg_.header.stamp.sec = this->depth_sensor_update_time_.sec;
00290   this->depth_image_msg_.header.stamp.nsec = this->depth_sensor_update_time_.nsec;
00291 
00293   FillDepthImageHelper(this->depth_image_msg_,
00294                  this->height,
00295                  this->width,
00296                  1,
00297                  (void*)_src );
00298 
00299   this->depth_image_pub_.publish(this->depth_image_msg_);
00300 
00301   this->lock_.unlock();
00302 }
00303 
00304 
00305 // Fill depth information
00306 bool GazeboRosDepthCamera::FillPointCloudHelper(
00307     sensor_msgs::PointCloud2 &point_cloud_msg,
00308     uint32_t rows_arg, uint32_t cols_arg,
00309     uint32_t step_arg, void* data_arg)
00310 {
00311   pcl::PointCloud<pcl::PointXYZRGB> point_cloud;
00312 
00313   point_cloud.points.resize(0);
00314   point_cloud.is_dense = true;
00315 
00316   float* toCopyFrom = (float*)data_arg;
00317   int index = 0;
00318 
00319   double hfov = this->parentSensor->GetDepthCamera()->GetHFOV().GetAsRadian();
00320   double fl = ((double)this->width) / (2.0 *tan(hfov/2.0));
00321 
00322   // convert depth to point cloud
00323   for (uint32_t j=0; j<rows_arg; j++)
00324   {
00325     double pAngle;
00326     if (rows_arg>1) pAngle = atan2( (double)j - 0.5*(double)(rows_arg-1), fl);
00327     else            pAngle = 0.0;
00328 
00329     for (uint32_t i=0; i<cols_arg; i++)
00330     {
00331       double yAngle;
00332       if (cols_arg>1) yAngle = atan2( (double)i - 0.5*(double)(cols_arg-1), fl);
00333       else            yAngle = 0.0;
00334 
00335       double depth = toCopyFrom[index++];
00336 
00337       // in optical frame
00338       // hardcoded rotation rpy(-M_PI/2, 0, -M_PI/2) is built-in
00339       // to urdf, where the *_optical_frame should have above relative
00340       // rotation from the physical camera *_frame
00341       pcl::PointXYZRGB point;
00342       point.x      = depth * tan(yAngle);
00343       point.y      = depth * tan(pAngle);
00344       if(depth > this->point_cloud_cutoff_)
00345       {
00346         point.z    = depth;
00347       }
00348       else //point in the unseeable range
00349       {
00350         point.x = point.y = point.z = std::numeric_limits<float>::quiet_NaN ();
00351         point_cloud.is_dense = false;
00352       }
00353 
00354       // put image color data for each point
00355       uint8_t*  image_src = (uint8_t*)(&(this->image_msg_.data[0]));
00356       if (this->image_msg_.data.size() == rows_arg*cols_arg*3)
00357       {
00358         // color
00359         point.r = image_src[i*3+j*cols_arg*3+0];
00360         point.g = image_src[i*3+j*cols_arg*3+1];
00361         point.b = image_src[i*3+j*cols_arg*3+2];
00362       }
00363       else if (this->image_msg_.data.size() == rows_arg*cols_arg)
00364       {
00365         // mono (or bayer?  @todo; fix for bayer)
00366         point.r = image_src[i+j*cols_arg];
00367         point.g = image_src[i+j*cols_arg];
00368         point.b = image_src[i+j*cols_arg];
00369       }
00370       else
00371       {
00372         // no image
00373         point.r = 0;
00374         point.g = 0;
00375         point.b = 0;
00376       }
00377 
00378       point_cloud.points.push_back(point);
00379     }
00380   }
00381 
00382   point_cloud.header = point_cloud_msg.header;
00383   pcl::toROSMsg(point_cloud, point_cloud_msg);
00384   return true;
00385 }
00386 
00387 // Fill depth information
00388 bool GazeboRosDepthCamera::FillDepthImageHelper(
00389     sensor_msgs::Image& image_msg,
00390     uint32_t rows_arg, uint32_t cols_arg,
00391     uint32_t step_arg, void* data_arg)
00392 {
00393   image_msg.encoding = sensor_msgs::image_encodings::TYPE_32FC1;
00394   image_msg.height = rows_arg;
00395   image_msg.width = cols_arg;
00396   image_msg.step = 1;
00397   image_msg.data.resize(rows_arg * cols_arg * sizeof(float));
00398   image_msg.is_bigendian = 0;
00399 
00400   const float bad_point = std::numeric_limits<float>::quiet_NaN();
00401 
00402   float* dest = (float*)(&(image_msg.data[0]));
00403   float* toCopyFrom = (float*)data_arg;
00404   int index = 0;
00405 
00406   // convert depth to point cloud
00407   for (uint32_t j = 0; j < rows_arg; j++)
00408   {
00409     for (uint32_t i = 0; i < cols_arg; i++)
00410     {
00411       float depth = 0;
00412       for (uint32_t s = 0; s < step_arg; s++) // if depth > 1 (e.g. rgb), average
00413         depth += toCopyFrom[index++];
00414       depth = depth / (float)step_arg;
00415 
00416       if (depth > this->point_cloud_cutoff_)
00417       {
00418         dest[i + j * cols_arg] = depth;
00419       }
00420       else //point in the unseeable range
00421       {
00422         dest[i + j * cols_arg] = bad_point;
00423       }
00424     }
00425   }
00426   return true;
00427 }
00428 
00429 void GazeboRosDepthCamera::PublishCameraInfo()
00430 {
00431   ROS_DEBUG("publishing depth camera info, then camera info");
00432   GazeboRosCameraUtils::PublishCameraInfo();
00433   this->PublishCameraInfo(this->depth_image_camera_info_pub_);
00434 }
00435 
00436 //@todo: publish disparity similar to openni_camera_deprecated/src/nodelets/openni_nodelet.cpp.
00437 /*
00438 #include <stereo_msgs/DisparityImage.h>
00439 pub_disparity_ = comm_nh.advertise<stereo_msgs::DisparityImage > ("depth/disparity", 5, subscriberChanged2, subscriberChanged2);
00440 
00441 void GazeboRosDepthCamera::PublishDisparityImage(const DepthImage& depth, ros::Time time)
00442 {
00443   stereo_msgs::DisparityImagePtr disp_msg = boost::make_shared<stereo_msgs::DisparityImage > ();
00444   disp_msg->header.stamp                  = time;
00445   disp_msg->header.frame_id               = device_->isDepthRegistered () ? rgb_frame_id_ : depth_frame_id_;
00446   disp_msg->image.header                  = disp_msg->header;
00447   disp_msg->image.encoding                = sensor_msgs::image_encodings::TYPE_32FC1;
00448   disp_msg->image.height                  = depth_height_;
00449   disp_msg->image.width                   = depth_width_;
00450   disp_msg->image.step                    = disp_msg->image.width * sizeof (float);
00451   disp_msg->image.data.resize (disp_msg->image.height * disp_msg->image.step);
00452   disp_msg->T = depth.getBaseline ();
00453   disp_msg->f = depth.getFocalLength () * depth_width_ / depth.getWidth ();
00454 
00456   disp_msg->min_disparity = 0.0;
00457   disp_msg->max_disparity = disp_msg->T * disp_msg->f / 0.3;
00458   disp_msg->delta_d = 0.125;
00459 
00460   depth.fillDisparityImage (depth_width_, depth_height_, reinterpret_cast<float*>(&disp_msg->image.data[0]), disp_msg->image.step);
00461 
00462   pub_disparity_.publish (disp_msg);
00463 }
00464 */
00465 
00466 // Register this plugin with the simulator
00467 GZ_REGISTER_SENSOR_PLUGIN(GazeboRosDepthCamera)
00468 
00469 }


gazebo_plugins
Author(s): Sachin Chitta, Stu Glaser, John Hsu
autogenerated on Sun Jan 5 2014 11:34:58