$search
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: GazeboRosProsilica 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 GazeboRosProsilica plugin mimics after prosilica_camera package 00029 */ 00030 00031 #include <algorithm> 00032 #include <assert.h> 00033 00034 #include <pr2_gazebo_plugins/gazebo_ros_prosilica.h> 00035 00036 #include <gazebo/Sensor.hh> 00037 #include <gazebo/Model.hh> 00038 #include <gazebo/Global.hh> 00039 #include <gazebo/XMLConfig.hh> 00040 #include <gazebo/Simulator.hh> 00041 #include <gazebo/gazebo.h> 00042 #include <gazebo/GazeboError.hh> 00043 #include <gazebo/ControllerFactory.hh> 00044 #include "gazebo/MonoCameraSensor.hh" 00045 00046 00047 #include <sensor_msgs/Image.h> 00048 #include <sensor_msgs/CameraInfo.h> 00049 #include <sensor_msgs/fill_image.h> 00050 #include <diagnostic_updater/diagnostic_updater.h> 00051 #include <sensor_msgs/RegionOfInterest.h> 00052 00053 #include <cv_bridge/CvBridge.h> 00054 #include <opencv/cv.h> 00055 #include <opencv/highgui.h> 00056 00057 #include <cv.h> 00058 #include <cvwimage.h> 00059 00060 #include <boost/scoped_ptr.hpp> 00061 #include <boost/bind.hpp> 00062 #include <boost/tokenizer.hpp> 00063 #include <boost/thread.hpp> 00064 #include <boost/thread/recursive_mutex.hpp> 00065 #include <string> 00066 00067 namespace gazebo 00068 { 00069 00070 GZ_REGISTER_DYNAMIC_CONTROLLER("gazebo_ros_prosilica", GazeboRosProsilica); 00071 00073 // Constructor 00074 GazeboRosProsilica::GazeboRosProsilica(Entity *parent) 00075 : Controller(parent) 00076 { 00077 this->myParent = dynamic_cast<MonoCameraSensor*>(this->parent); 00078 00079 if (!this->myParent) 00080 gzthrow("GazeboRosProsilica controller requires a Camera Sensor as its parent"); 00081 00082 Param::Begin(&this->parameters); 00083 this->robotNamespaceP = new ParamT<std::string>("robotNamespace", "/", 0); 00084 this->imageTopicNameP = new ParamT<std::string>("imageTopicName","image_raw", 0); 00085 this->cameraInfoTopicNameP = new ParamT<std::string>("cameraInfoTopicName","camera_info", 0); 00086 this->pollServiceNameP = new ParamT<std::string>("pollServiceName","request_image", 0); 00087 this->cameraNameP = new ParamT<std::string>("cameraName","", 0); 00088 this->frameNameP = new ParamT<std::string>("frameName","camera", 0); 00089 // camera parameters 00090 this->CxPrimeP = new ParamT<double>("CxPrime",320, 0); // for 640x480 image 00091 this->CxP = new ParamT<double>("Cx" ,320, 0); // for 640x480 image 00092 this->CyP = new ParamT<double>("Cy" ,240, 0); // for 640x480 image 00093 this->focal_lengthP = new ParamT<double>("focal_length" ,554.256, 0); // == image_width(px) / (2*tan( hfov(radian) /2)) 00094 this->hack_baselineP = new ParamT<double>("hackBaseline" ,0, 0); // hack for right stereo camera 00095 this->distortion_k1P = new ParamT<double>("distortion_k1" ,0, 0); 00096 this->distortion_k2P = new ParamT<double>("distortion_k2" ,0, 0); 00097 this->distortion_k3P = new ParamT<double>("distortion_k3" ,0, 0); 00098 this->distortion_t1P = new ParamT<double>("distortion_t1" ,0, 0); 00099 this->distortion_t2P = new ParamT<double>("distortion_t2" ,0, 0); 00100 Param::End(); 00101 00102 this->imageConnectCount = 0; 00103 this->infoConnectCount = 0; 00104 } 00105 00107 // Destructor 00108 GazeboRosProsilica::~GazeboRosProsilica() 00109 { 00110 delete this->robotNamespaceP; 00111 delete this->rosnode_; 00112 delete this->imageTopicNameP; 00113 delete this->cameraInfoTopicNameP; 00114 delete this->pollServiceNameP; 00115 delete this->frameNameP; 00116 delete this->CxPrimeP; 00117 delete this->CxP; 00118 delete this->CyP; 00119 delete this->focal_lengthP; 00120 delete this->hack_baselineP; 00121 delete this->distortion_k1P; 00122 delete this->distortion_k2P; 00123 delete this->distortion_k3P; 00124 delete this->distortion_t1P; 00125 delete this->distortion_t2P; 00126 00127 } 00128 00130 // Load the controller 00131 void GazeboRosProsilica::LoadChild(XMLConfigNode *node) 00132 { 00133 this->robotNamespaceP->Load(node); 00134 this->robotNamespace = this->robotNamespaceP->GetValue(); 00135 if (!ros::isInitialized()) 00136 { 00137 int argc = 0; 00138 char** argv = NULL; 00139 ros::init(argc,argv,"gazebo",ros::init_options::NoSigintHandler|ros::init_options::AnonymousName); 00140 } 00141 00142 this->cameraNameP->Load(node); 00143 this->cameraName = this->cameraNameP->GetValue(); 00144 this->rosnode_ = new ros::NodeHandle(this->robotNamespace+"/"+this->cameraName); 00145 this->rosnode_->setCallbackQueue(&this->prosilica_queue_); 00146 this->itnode_ = new image_transport::ImageTransport(*this->rosnode_); 00147 00148 this->imageTopicNameP->Load(node); 00149 this->cameraInfoTopicNameP->Load(node); 00150 this->pollServiceNameP->Load(node); 00151 this->frameNameP->Load(node); 00152 this->CxPrimeP->Load(node); 00153 this->CxP->Load(node); 00154 this->CyP->Load(node); 00155 this->focal_lengthP->Load(node); 00156 this->hack_baselineP->Load(node); 00157 this->distortion_k1P->Load(node); 00158 this->distortion_k2P->Load(node); 00159 this->distortion_k3P->Load(node); 00160 this->distortion_t1P->Load(node); 00161 this->distortion_t2P->Load(node); 00162 00163 this->imageTopicName = this->imageTopicNameP->GetValue(); 00164 this->cameraInfoTopicName = this->cameraInfoTopicNameP->GetValue(); 00165 this->pollServiceName = this->pollServiceNameP->GetValue(); 00166 this->frameName = this->frameNameP->GetValue(); 00167 this->CxPrime = this->CxPrimeP->GetValue(); 00168 this->Cx = this->CxP->GetValue(); 00169 this->Cy = this->CyP->GetValue(); 00170 this->focal_length = this->focal_lengthP->GetValue(); 00171 this->hack_baseline = this->hack_baselineP->GetValue(); 00172 this->distortion_k1 = this->distortion_k1P->GetValue(); 00173 this->distortion_k2 = this->distortion_k2P->GetValue(); 00174 this->distortion_k3 = this->distortion_k3P->GetValue(); 00175 this->distortion_t1 = this->distortion_t1P->GetValue(); 00176 this->distortion_t2 = this->distortion_t2P->GetValue(); 00177 if ((this->distortion_k1 != 0.0) || (this->distortion_k2 != 0.0) || 00178 (this->distortion_k3 != 0.0) || (this->distortion_t1 != 0.0) || 00179 (this->distortion_t2 != 0.0)) 00180 ROS_WARN("gazebo_ros_prosilica simulation does not support non-zero distortion parameters right now, your simulation maybe wrong."); 00181 00182 // camera mode for prosilica: 00183 // prosilica::AcquisitionMode mode_; /// @todo Make this property of Camera 00184 std::string mode_param_name; 00185 00186 //ROS_ERROR("before trigger_mode %s %s",mode_param_name.c_str(),this->mode_.c_str()); 00187 00188 if (!this->rosnode_->searchParam("trigger_mode",mode_param_name)) 00189 mode_param_name = "trigger_mode"; 00190 00191 if (!this->rosnode_->getParam(mode_param_name,this->mode_)) 00192 this->mode_ = "streaming"; 00193 00194 ROS_INFO("trigger_mode %s %s",mode_param_name.c_str(),this->mode_.c_str()); 00195 00196 00197 if (this->mode_ == "polled") 00198 { 00199 poll_srv_ = polled_camera::advertise(*this->rosnode_,this->pollServiceName,&GazeboRosProsilica::pollCallback,this); 00200 } 00201 else if (this->mode_ == "streaming") 00202 { 00203 ROS_DEBUG("do nothing here,mode: %s",this->mode_.c_str()); 00204 } 00205 else 00206 { 00207 ROS_ERROR("trigger_mode is invalid: %s, using streaming mode",this->mode_.c_str()); 00208 } 00209 00211 this->image_pub_ = this->itnode_->advertise( 00212 this->imageTopicName,1, 00213 boost::bind( &GazeboRosProsilica::ImageConnect,this), 00214 boost::bind( &GazeboRosProsilica::ImageDisconnect,this), ros::VoidPtr(), &this->prosilica_queue_); 00215 00216 ros::AdvertiseOptions camera_info_ao = ros::AdvertiseOptions::create<sensor_msgs::CameraInfo>( 00217 this->cameraInfoTopicName,1, 00218 boost::bind( &GazeboRosProsilica::InfoConnect,this), 00219 boost::bind( &GazeboRosProsilica::InfoDisconnect,this), ros::VoidPtr(), &this->prosilica_queue_); 00220 this->camera_info_pub_ = this->rosnode_->advertise(camera_info_ao); 00221 00222 #ifdef SIMULATOR_GAZEBO_GAZEBO_ROS_CAMERA_DYNAMIC_RECONFIGURE 00223 if (!this->cameraName.empty()) { 00224 dyn_srv_ = new dynamic_reconfigure::Server<gazebo_plugins::GazeboRosCameraConfig>(*this->rosnode_); 00225 dynamic_reconfigure::Server<gazebo_plugins::GazeboRosCameraConfig>::CallbackType f = boost::bind(&GazeboRosProsilica::configCallback, this, _1, _2); 00226 dyn_srv_->setCallback(f); 00227 } 00228 #endif 00229 00230 } 00231 00232 #ifdef SIMULATOR_GAZEBO_GAZEBO_ROS_CAMERA_DYNAMIC_RECONFIGURE 00233 00234 // Dynamic Reconfigure Callback 00235 void GazeboRosProsilica::configCallback(gazebo_plugins::GazeboRosCameraConfig &config, uint32_t level) 00236 { 00237 ROS_INFO("Reconfigure request for the gazebo ros camera: %s. New rate: %.2f", this->cameraName.c_str(), config.imager_rate); 00238 00239 (dynamic_cast<OgreCamera*>(this->myParent))->SetUpdateRate(config.imager_rate); 00240 } 00241 #endif 00242 00244 // Initialize the controller 00245 void GazeboRosProsilica::InitChild() 00246 { 00247 // sensor generation off by default 00248 this->myParent->SetActive(false); 00249 00250 // set buffer size 00251 this->width = this->myParent->GetImageWidth(); 00252 this->height = this->myParent->GetImageHeight(); 00253 this->depth = this->myParent->GetImageDepth(); 00254 //ROS_INFO("image format in urdf is %s\n",this->myParent->GetImageFormat().c_str()); 00255 if (this->myParent->GetImageFormat() == "L8") 00256 { 00257 this->type = sensor_msgs::image_encodings::MONO8; 00258 this->skip = 1; 00259 } 00260 else if (this->myParent->GetImageFormat() == "R8G8B8") 00261 { 00262 this->type = sensor_msgs::image_encodings::RGB8; 00263 this->skip = 3; 00264 } 00265 else if (this->myParent->GetImageFormat() == "B8G8R8") 00266 { 00267 this->type = sensor_msgs::image_encodings::BGR8; 00268 this->skip = 3; 00269 } 00270 else if (this->myParent->GetImageFormat() == "BAYER_RGGB8") 00271 { 00272 this->type = sensor_msgs::image_encodings::BAYER_RGGB8; 00273 this->skip = 1; 00274 } 00275 else if (this->myParent->GetImageFormat() == "BAYER_BGGR8") 00276 { 00277 this->type = sensor_msgs::image_encodings::BAYER_BGGR8; 00278 this->skip = 1; 00279 } 00280 else if (this->myParent->GetImageFormat() == "BAYER_GBRG8") 00281 { 00282 this->type = sensor_msgs::image_encodings::BAYER_GBRG8; 00283 this->skip = 1; 00284 } 00285 else if (this->myParent->GetImageFormat() == "BAYER_GRBG8") 00286 { 00287 this->type = sensor_msgs::image_encodings::BAYER_GRBG8; 00288 this->skip = 1; 00289 } 00290 else 00291 { 00292 ROS_ERROR("Unsupported Gazebo ImageFormat for Prosilica, using BGR8\n"); 00293 this->type = sensor_msgs::image_encodings::BGR8; 00294 this->skip = 3; 00295 } 00296 00298 if (this->CxPrime == 0) 00299 this->CxPrime = ((double)this->width+1.0) /2.0; 00300 if (this->Cx == 0) 00301 this->Cx = ((double)this->width+1.0) /2.0; 00302 if (this->Cy == 0) 00303 this->Cy = ((double)this->height+1.0) /2.0; 00304 00305 double computed_focal_length = ((double)this->width) / (2.0 *tan(this->myParent->GetHFOV().GetAsRadian()/2.0)); 00306 if (this->focal_length == 0) 00307 this->focal_length = computed_focal_length; 00308 else if (fabs(this->focal_length - computed_focal_length) > 1e-8) // check against float precision 00309 ROS_WARN("The <focal_length>[%f] you have provided for camera [%s] is inconsistent with specified image_width [%d] and HFOV [%f]. Please double check to see that focal_length = width / (2.0 * tan( HFOV/2.0 )), the explected focal_lengtth value is [%f], please update your camera model description accordingly.", 00310 this->focal_length,this->myParent->GetName().c_str(),this->width,this->myParent->GetHFOV().GetAsRadian(), 00311 computed_focal_length); 00312 00313 #ifdef USE_CBQ 00314 // start custom queue for prosilica 00315 this->prosilica_callback_queue_thread_ = boost::thread( boost::bind( &GazeboRosProsilica::ProsilicaQueueThread,this ) ); 00316 #else 00317 // start ros spinner as it is done in prosilica node 00318 this->ros_spinner_thread_ = boost::thread( boost::bind( &GazeboRosProsilica::ProsilicaROSThread,this ) ); 00319 #endif 00320 00321 } 00322 00324 // Increment count 00325 void GazeboRosProsilica::ImageConnect() 00326 { 00327 this->imageConnectCount++; 00328 } 00330 // Decrement count 00331 void GazeboRosProsilica::ImageDisconnect() 00332 { 00333 this->imageConnectCount--; 00334 00335 if ((this->infoConnectCount == 0) && (this->imageConnectCount == 0)) 00336 this->myParent->SetActive(false); 00337 } 00338 00340 // Increment count 00341 void GazeboRosProsilica::InfoConnect() 00342 { 00343 this->infoConnectCount++; 00344 } 00346 // Decrement count 00347 void GazeboRosProsilica::InfoDisconnect() 00348 { 00349 this->infoConnectCount--; 00350 00351 if ((this->infoConnectCount == 0) && (this->imageConnectCount == 0)) 00352 this->myParent->SetActive(false); 00353 } 00354 00356 // Update the controller 00357 void GazeboRosProsilica::UpdateChild() 00358 { 00359 00360 // should do nothing except turning camera on/off, as we are using service. 00362 00363 // as long as ros is connected, parent is active 00364 //ROS_ERROR("debug image count %d",this->imageConnectCount); 00365 if (!this->myParent->IsActive()) 00366 { 00367 if (this->imageConnectCount > 0) 00368 // do this first so there's chance for sensor to run 1 frame after activate 00369 this->myParent->SetActive(true); 00370 } 00371 else 00372 { 00373 // publish if in continuous mode, otherwise triggered by poll 00374 if (this->mode_ == "streaming") 00375 this->PutCameraData(); 00376 } 00377 00379 if (this->infoConnectCount > 0) 00380 if (this->mode_ == "streaming") 00381 this->PublishCameraInfo(); 00382 } 00384 // Put laser data to the interface 00385 void GazeboRosProsilica::PutCameraData() 00386 { 00387 const unsigned char *src; 00388 00389 //boost::recursive_mutex::scoped_lock mr_lock(*Simulator::Instance()->GetMRMutex()); 00390 00391 // Get a pointer to image data 00392 src = this->myParent->GetImageData(0); 00393 00394 if (src) 00395 { 00396 //double tmpT0 = Simulator::Instance()->GetWallTime(); 00397 00398 unsigned char dst[this->width*this->height]; 00399 00400 this->lock.lock(); 00401 // copy data into image 00402 this->imageMsg.header.frame_id = this->frameName; 00403 #if GAZEBO_MAJOR_VERSION == 0 && GAZEBO_MINOR_VERSION >= 10 00404 this->imageMsg.header.stamp.fromSec(Simulator::Instance()->GetSimTime().Double()); 00405 #else 00406 this->imageMsg.header.stamp.fromSec(Simulator::Instance()->GetSimTime()); 00407 #endif 00408 00409 //double tmpT1 = Simulator::Instance()->GetWallTime(); 00410 //double tmpT2; 00411 00413 if (this->image_pub_.getNumSubscribers() > 0) 00414 { 00415 00416 // do last minute conversion if Bayer pattern is requested but not provided, go from R8G8B8 00417 // deprecated in gazebo2 branch, keep for backwards compatibility 00418 if (this->myParent->GetImageFormat() == "BAYER_RGGB8" && this->depth == 3) 00419 { 00420 for (int i=0;i<this->width;i++) 00421 { 00422 for (int j=0;j<this->height;j++) 00423 { 00424 // 00425 // RG 00426 // GB 00427 // 00428 // determine position 00429 if (j%2) // even column 00430 if (i%2) // even row, red 00431 dst[i+j*this->width] = src[i*3+j*this->width*3+0]; 00432 else // odd row, green 00433 dst[i+j*this->width] = src[i*3+j*this->width*3+1]; 00434 else // odd column 00435 if (i%2) // even row, green 00436 dst[i+j*this->width] = src[i*3+j*this->width*3+1]; 00437 else // odd row, blue 00438 dst[i+j*this->width] = src[i*3+j*this->width*3+2]; 00439 } 00440 } 00441 src=dst; 00442 } 00443 else if (this->myParent->GetImageFormat() == "BAYER_BGGR8" && this->depth == 3) 00444 { 00445 for (int i=0;i<this->width;i++) 00446 { 00447 for (int j=0;j<this->height;j++) 00448 { 00449 // 00450 // BG 00451 // GR 00452 // 00453 // determine position 00454 if (j%2) // even column 00455 if (i%2) // even row, blue 00456 dst[i+j*this->width] = src[i*3+j*this->width*3+2]; 00457 else // odd row, green 00458 dst[i+j*this->width] = src[i*3+j*this->width*3+1]; 00459 else // odd column 00460 if (i%2) // even row, green 00461 dst[i+j*this->width] = src[i*3+j*this->width*3+1]; 00462 else // odd row, red 00463 dst[i+j*this->width] = src[i*3+j*this->width*3+0]; 00464 } 00465 } 00466 src=dst; 00467 } 00468 else if (this->myParent->GetImageFormat() == "BAYER_GBRG8" && this->depth == 3) 00469 { 00470 for (int i=0;i<this->width;i++) 00471 { 00472 for (int j=0;j<this->height;j++) 00473 { 00474 // 00475 // GB 00476 // RG 00477 // 00478 // determine position 00479 if (j%2) // even column 00480 if (i%2) // even row, green 00481 dst[i+j*this->width] = src[i*3+j*this->width*3+1]; 00482 else // odd row, blue 00483 dst[i+j*this->width] = src[i*3+j*this->width*3+2]; 00484 else // odd column 00485 if (i%2) // even row, red 00486 dst[i+j*this->width] = src[i*3+j*this->width*3+0]; 00487 else // odd row, green 00488 dst[i+j*this->width] = src[i*3+j*this->width*3+1]; 00489 } 00490 } 00491 src=dst; 00492 } 00493 else if (this->myParent->GetImageFormat() == "BAYER_GRBG8" && this->depth == 3) 00494 { 00495 for (int i=0;i<this->width;i++) 00496 { 00497 for (int j=0;j<this->height;j++) 00498 { 00499 // 00500 // GR 00501 // BG 00502 // 00503 // determine position 00504 if (j%2) // even column 00505 if (i%2) // even row, green 00506 dst[i+j*this->width] = src[i*3+j*this->width*3+1]; 00507 else // odd row, red 00508 dst[i+j*this->width] = src[i*3+j*this->width*3+0]; 00509 else // odd column 00510 if (i%2) // even row, blue 00511 dst[i+j*this->width] = src[i*3+j*this->width*3+2]; 00512 else // odd row, green 00513 dst[i+j*this->width] = src[i*3+j*this->width*3+1]; 00514 } 00515 } 00516 src=dst; 00517 } 00518 00519 //ROS_ERROR("debug %d %d %d %d", this->type, this->height, this->width, this->skip); 00520 00521 // copy from src to imageMsg 00522 fillImage(this->imageMsg, 00523 this->type, 00524 this->height, 00525 this->width, 00526 this->skip*this->width, 00527 (void*)src ); 00528 00529 //tmpT2 = Simulator::Instance()->GetWallTime(); 00530 00531 // publish to ros 00532 this->image_pub_.publish(this->imageMsg); 00533 } 00534 00535 //double tmpT3 = Simulator::Instance()->GetWallTime(); 00536 00537 this->lock.unlock(); 00538 } 00539 00540 } 00541 00543 // Put laser data to the interface 00544 void GazeboRosProsilica::PublishCameraInfo() 00545 { 00546 // fill CameraInfo 00547 this->cameraInfoMsg.header.frame_id = this->frameName; 00548 #if GAZEBO_MAJOR_VERSION == 0 && GAZEBO_MINOR_VERSION >= 10 00549 this->cameraInfoMsg.header.stamp.fromSec(Simulator::Instance()->GetSimTime().Double()); 00550 #else 00551 this->cameraInfoMsg.header.stamp.fromSec(Simulator::Instance()->GetSimTime()); 00552 #endif 00553 this->cameraInfoMsg.height = this->height; 00554 this->cameraInfoMsg.width = this->width; 00555 00556 // distortion 00557 #if ROS_VERSION_MINIMUM(1, 3, 0) 00558 this->cameraInfoMsg.distortion_model = "plumb_bob"; 00559 this->cameraInfoMsg.D.resize(5); 00560 #endif 00561 this->cameraInfoMsg.D[0] = this->distortion_k1; 00562 this->cameraInfoMsg.D[1] = this->distortion_k2; 00563 this->cameraInfoMsg.D[2] = this->distortion_k3; 00564 this->cameraInfoMsg.D[3] = this->distortion_t1; 00565 this->cameraInfoMsg.D[4] = this->distortion_t2; 00566 // original camera matrix 00567 this->cameraInfoMsg.K[0] = this->focal_length; 00568 this->cameraInfoMsg.K[1] = 0.0; 00569 this->cameraInfoMsg.K[2] = this->Cx; 00570 this->cameraInfoMsg.K[3] = 0.0; 00571 this->cameraInfoMsg.K[4] = this->focal_length; 00572 this->cameraInfoMsg.K[5] = this->Cy; 00573 this->cameraInfoMsg.K[6] = 0.0; 00574 this->cameraInfoMsg.K[7] = 0.0; 00575 this->cameraInfoMsg.K[8] = 1.0; 00576 // rectification 00577 this->cameraInfoMsg.R[0] = 1.0; 00578 this->cameraInfoMsg.R[1] = 0.0; 00579 this->cameraInfoMsg.R[2] = 0.0; 00580 this->cameraInfoMsg.R[3] = 0.0; 00581 this->cameraInfoMsg.R[4] = 1.0; 00582 this->cameraInfoMsg.R[5] = 0.0; 00583 this->cameraInfoMsg.R[6] = 0.0; 00584 this->cameraInfoMsg.R[7] = 0.0; 00585 this->cameraInfoMsg.R[8] = 1.0; 00586 // camera projection matrix (same as camera matrix due to lack of distortion/rectification) (is this generated?) 00587 this->cameraInfoMsg.P[0] = this->focal_length; 00588 this->cameraInfoMsg.P[1] = 0.0; 00589 this->cameraInfoMsg.P[2] = this->Cx; 00590 this->cameraInfoMsg.P[3] = -this->focal_length * this->hack_baseline; 00591 this->cameraInfoMsg.P[4] = 0.0; 00592 this->cameraInfoMsg.P[5] = this->focal_length; 00593 this->cameraInfoMsg.P[6] = this->Cy; 00594 this->cameraInfoMsg.P[7] = 0.0; 00595 this->cameraInfoMsg.P[8] = 0.0; 00596 this->cameraInfoMsg.P[9] = 0.0; 00597 this->cameraInfoMsg.P[10] = 1.0; 00598 this->cameraInfoMsg.P[11] = 0.0; 00599 this->camera_info_pub_.publish(this->cameraInfoMsg); 00600 } 00601 00603 // new prosilica interface. 00604 void GazeboRosProsilica::pollCallback(polled_camera::GetPolledImage::Request& req, 00605 polled_camera::GetPolledImage::Response& rsp, 00606 sensor_msgs::Image& image, sensor_msgs::CameraInfo& info) 00607 { 00611 00612 if (this->mode_ != "polled") 00613 { 00614 rsp.success = false; 00615 rsp.status_message = "Camera is not in triggered mode"; 00616 return; 00617 } 00618 00619 if (req.binning_x > 1 || req.binning_y > 1) 00620 { 00621 rsp.success = false; 00622 rsp.status_message = "Gazebo Prosilica plugin does not support binning"; 00623 return; 00624 } 00625 00626 /* 00627 // fill out the cam info part 00628 info.header.frame_id = this->frameName; 00629 #if GAZEBO_MAJOR_VERSION == 0 && GAZEBO_MINOR_VERSION >= 10 00630 info.header.stamp.fromSec(Simulator::Instance()->GetSimTime().Double()); 00631 #else 00632 info.header.stamp.fromSec(Simulator::Instance()->GetSimTime()); 00633 #endif 00634 info.height = this->myParent->GetImageHeight(); 00635 info.width = this->myParent->GetImageWidth() ; 00636 // distortion 00637 #if ROS_VERSION_MINIMUM(1, 3, 0) 00638 info.distortion_model = "plumb_bob"; 00639 info.D.resize(5); 00640 #endif 00641 info.D[0] = this->distortion_k1; 00642 info.D[1] = this->distortion_k2; 00643 info.D[2] = this->distortion_k3; 00644 info.D[3] = this->distortion_t1; 00645 info.D[4] = this->distortion_t2; 00646 // original camera matrix 00647 info.K[0] = this->focal_length; 00648 info.K[1] = 0.0; 00649 info.K[2] = this->Cx; 00650 info.K[3] = 0.0; 00651 info.K[4] = this->focal_length; 00652 info.K[5] = this->Cy; 00653 info.K[6] = 0.0; 00654 info.K[7] = 0.0; 00655 info.K[8] = 1.0; 00656 // rectification 00657 info.R[0] = 1.0; 00658 info.R[1] = 0.0; 00659 info.R[2] = 0.0; 00660 info.R[3] = 0.0; 00661 info.R[4] = 1.0; 00662 info.R[5] = 0.0; 00663 info.R[6] = 0.0; 00664 info.R[7] = 0.0; 00665 info.R[8] = 1.0; 00666 // camera projection matrix (same as camera matrix due to lack of distortion/rectification) (is this generated?) 00667 info.P[0] = this->focal_length; 00668 info.P[1] = 0.0; 00669 info.P[2] = this->Cx; 00670 info.P[3] = -this->focal_length * this->hack_baseline; 00671 info.P[4] = 0.0; 00672 info.P[5] = this->focal_length; 00673 info.P[6] = this->Cy; 00674 info.P[7] = 0.0; 00675 info.P[8] = 0.0; 00676 info.P[9] = 0.0; 00677 info.P[10] = 1.0; 00678 info.P[11] = 0.0; 00679 */ 00680 00681 // get region from request 00682 if (req.roi.x_offset <= 0 || req.roi.y_offset <= 0 || req.roi.width <= 0 || req.roi.height <= 0) 00683 { 00684 req.roi.x_offset = 0; 00685 req.roi.y_offset = 0; 00686 req.roi.width = this->width; 00687 req.roi.height = this->height; 00688 } 00689 const unsigned char *src = NULL; 00690 ROS_ERROR("roidebug %d %d %d %d", req.roi.x_offset, req.roi.y_offset, req.roi.width, req.roi.height); 00691 00692 // signal sensor to start update 00693 this->ImageConnect(); 00694 // wait until an image has been returned 00695 while(!src) 00696 { 00697 { 00698 boost::recursive_mutex::scoped_lock lock(*Simulator::Instance()->GetMRMutex()); 00699 // Get a pointer to image data 00700 src = this->myParent->GetImageData(0); 00701 00702 if (src) 00703 { 00704 00705 // fill CameraInfo 00706 this->roiCameraInfoMsg = &info; 00707 this->roiCameraInfoMsg->header.frame_id = this->frameName; 00708 #if GAZEBO_MAJOR_VERSION == 0 && GAZEBO_MINOR_VERSION >= 10 00709 this->roiCameraInfoMsg->header.stamp.fromSec( (dynamic_cast<OgreCamera*>(this->myParent))->GetLastRenderTime().Double()); 00710 #else 00711 this->roiCameraInfoMsg->header.stamp.fromSec( (dynamic_cast<OgreCamera*>(this->myParent))->GetLastRenderTime()); 00712 #endif 00713 this->roiCameraInfoMsg->width = req.roi.width; //this->myParent->GetImageWidth() ; 00714 this->roiCameraInfoMsg->height = req.roi.height; //this->myParent->GetImageHeight(); 00715 // distortion 00716 #if ROS_VERSION_MINIMUM(1, 3, 0) 00717 this->roiCameraInfoMsg->distortion_model = "plumb_bob"; 00718 this->roiCameraInfoMsg->D.resize(5); 00719 #endif 00720 this->roiCameraInfoMsg->D[0] = this->distortion_k1; 00721 this->roiCameraInfoMsg->D[1] = this->distortion_k2; 00722 this->roiCameraInfoMsg->D[2] = this->distortion_k3; 00723 this->roiCameraInfoMsg->D[3] = this->distortion_t1; 00724 this->roiCameraInfoMsg->D[4] = this->distortion_t2; 00725 // original camera matrix 00726 this->roiCameraInfoMsg->K[0] = this->focal_length; 00727 this->roiCameraInfoMsg->K[1] = 0.0; 00728 this->roiCameraInfoMsg->K[2] = this->Cx - req.roi.x_offset; 00729 this->roiCameraInfoMsg->K[3] = 0.0; 00730 this->roiCameraInfoMsg->K[4] = this->focal_length; 00731 this->roiCameraInfoMsg->K[5] = this->Cy - req.roi.y_offset; 00732 this->roiCameraInfoMsg->K[6] = 0.0; 00733 this->roiCameraInfoMsg->K[7] = 0.0; 00734 this->roiCameraInfoMsg->K[8] = 1.0; 00735 // rectification 00736 this->roiCameraInfoMsg->R[0] = 1.0; 00737 this->roiCameraInfoMsg->R[1] = 0.0; 00738 this->roiCameraInfoMsg->R[2] = 0.0; 00739 this->roiCameraInfoMsg->R[3] = 0.0; 00740 this->roiCameraInfoMsg->R[4] = 1.0; 00741 this->roiCameraInfoMsg->R[5] = 0.0; 00742 this->roiCameraInfoMsg->R[6] = 0.0; 00743 this->roiCameraInfoMsg->R[7] = 0.0; 00744 this->roiCameraInfoMsg->R[8] = 1.0; 00745 // camera projection matrix (same as camera matrix due to lack of distortion/rectification) (is this generated?) 00746 this->roiCameraInfoMsg->P[0] = this->focal_length; 00747 this->roiCameraInfoMsg->P[1] = 0.0; 00748 this->roiCameraInfoMsg->P[2] = this->Cx - req.roi.x_offset; 00749 this->roiCameraInfoMsg->P[3] = -this->focal_length * this->hack_baseline; 00750 this->roiCameraInfoMsg->P[4] = 0.0; 00751 this->roiCameraInfoMsg->P[5] = this->focal_length; 00752 this->roiCameraInfoMsg->P[6] = this->Cy - req.roi.y_offset; 00753 this->roiCameraInfoMsg->P[7] = 0.0; 00754 this->roiCameraInfoMsg->P[8] = 0.0; 00755 this->roiCameraInfoMsg->P[9] = 0.0; 00756 this->roiCameraInfoMsg->P[10] = 1.0; 00757 this->roiCameraInfoMsg->P[11] = 0.0; 00758 this->camera_info_pub_.publish(*this->roiCameraInfoMsg); 00759 00760 // copy data into imageMsg, then convert to roiImageMsg(image) 00761 this->imageMsg.header.frame_id = this->frameName; 00762 #if GAZEBO_MAJOR_VERSION == 0 && GAZEBO_MINOR_VERSION >= 10 00763 this->imageMsg.header.stamp.fromSec( (dynamic_cast<OgreCamera*>(this->myParent))->GetLastRenderTime().Double()); 00764 #else 00765 this->imageMsg.header.stamp.fromSec( (dynamic_cast<OgreCamera*>(this->myParent))->GetLastRenderTime()); 00766 #endif 00767 00768 unsigned char dst[this->width*this->height]; 00769 00771 00772 // do last minute conversion if Bayer pattern is requested but not provided, go from R8G8B8 00773 // deprecated in gazebo2 branch, keep for backwards compatibility 00774 if (this->myParent->GetImageFormat() == "BAYER_RGGB8" && this->depth == 3) 00775 { 00776 for (int i=0;i<this->width;i++) 00777 { 00778 for (int j=0;j<this->height;j++) 00779 { 00780 // 00781 // RG 00782 // GB 00783 // 00784 // determine position 00785 if (j%2) // even column 00786 if (i%2) // even row, red 00787 dst[i+j*this->width] = src[i*3+j*this->width*3+0]; 00788 else // odd row, green 00789 dst[i+j*this->width] = src[i*3+j*this->width*3+1]; 00790 else // odd column 00791 if (i%2) // even row, green 00792 dst[i+j*this->width] = src[i*3+j*this->width*3+1]; 00793 else // odd row, blue 00794 dst[i+j*this->width] = src[i*3+j*this->width*3+2]; 00795 } 00796 } 00797 src=dst; 00798 } 00799 else if (this->myParent->GetImageFormat() == "BAYER_BGGR8" && this->depth == 3) 00800 { 00801 for (int i=0;i<this->width;i++) 00802 { 00803 for (int j=0;j<this->height;j++) 00804 { 00805 // 00806 // BG 00807 // GR 00808 // 00809 // determine position 00810 if (j%2) // even column 00811 if (i%2) // even row, blue 00812 dst[i+j*this->width] = src[i*3+j*this->width*3+2]; 00813 else // odd row, green 00814 dst[i+j*this->width] = src[i*3+j*this->width*3+1]; 00815 else // odd column 00816 if (i%2) // even row, green 00817 dst[i+j*this->width] = src[i*3+j*this->width*3+1]; 00818 else // odd row, red 00819 dst[i+j*this->width] = src[i*3+j*this->width*3+0]; 00820 } 00821 } 00822 src=dst; 00823 } 00824 else if (this->myParent->GetImageFormat() == "BAYER_GBRG8" && this->depth == 3) 00825 { 00826 for (int i=0;i<this->width;i++) 00827 { 00828 for (int j=0;j<this->height;j++) 00829 { 00830 // 00831 // GB 00832 // RG 00833 // 00834 // determine position 00835 if (j%2) // even column 00836 if (i%2) // even row, green 00837 dst[i+j*this->width] = src[i*3+j*this->width*3+1]; 00838 else // odd row, blue 00839 dst[i+j*this->width] = src[i*3+j*this->width*3+2]; 00840 else // odd column 00841 if (i%2) // even row, red 00842 dst[i+j*this->width] = src[i*3+j*this->width*3+0]; 00843 else // odd row, green 00844 dst[i+j*this->width] = src[i*3+j*this->width*3+1]; 00845 } 00846 } 00847 src=dst; 00848 } 00849 else if (this->myParent->GetImageFormat() == "BAYER_GRBG8" && this->depth == 3) 00850 { 00851 for (int i=0;i<this->width;i++) 00852 { 00853 for (int j=0;j<this->height;j++) 00854 { 00855 // 00856 // GR 00857 // BG 00858 // 00859 // determine position 00860 if (j%2) // even column 00861 if (i%2) // even row, green 00862 dst[i+j*this->width] = src[i*3+j*this->width*3+1]; 00863 else // odd row, red 00864 dst[i+j*this->width] = src[i*3+j*this->width*3+0]; 00865 else // odd column 00866 if (i%2) // even row, blue 00867 dst[i+j*this->width] = src[i*3+j*this->width*3+2]; 00868 else // odd row, green 00869 dst[i+j*this->width] = src[i*3+j*this->width*3+1]; 00870 } 00871 } 00872 src=dst; 00873 } 00874 00875 // copy from src to imageMsg 00876 fillImage(this->imageMsg, 00877 this->type, 00878 this->height, 00879 this->width, 00880 this->skip*this->width, 00881 (void*)src ); 00882 00884 00885 this->image_pub_.publish(this->imageMsg); 00886 00887 // error if Bayer pattern is requested but not provided, roi not supported in this case 00888 // not supported in old image_pipeline as well, this might change, but ultimately 00889 // this is deprecated in gazebo2 branch, keep for backwards compatibility 00890 if (((this->myParent->GetImageFormat() == "BAYER_RGGB8") || 00891 (this->myParent->GetImageFormat() == "BAYER_BGGR8") || 00892 (this->myParent->GetImageFormat() == "BAYER_GBRG8") || 00893 (this->myParent->GetImageFormat() == "BAYER_GRBG8") ) && 00894 this->depth == 3) 00895 { 00896 ROS_ERROR("prosilica does not support bayer roi, using full image"); 00897 00898 // copy from src to imageMsg 00899 fillImage(image, 00900 this->type, 00901 this->height, 00902 this->width, 00903 this->skip*this->width, 00904 (void*)src ); 00905 } 00906 else 00907 { 00908 // copy data into ROI image 00909 this->roiImageMsg = ℑ 00910 this->roiImageMsg->header.frame_id = this->frameName; 00911 #if GAZEBO_MAJOR_VERSION == 0 && GAZEBO_MINOR_VERSION >= 10 00912 this->roiImageMsg->header.stamp.fromSec( (dynamic_cast<OgreCamera*>(this->myParent))->GetLastRenderTime().Double()); 00913 #else 00914 this->roiImageMsg->header.stamp.fromSec( (dynamic_cast<OgreCamera*>(this->myParent))->GetLastRenderTime()); 00915 #endif 00916 00917 //sensor_msgs::CvBridge img_bridge_(&this->imageMsg); 00918 //IplImage* cv_image; 00919 //img_bridge_.to_cv( &cv_image ); 00920 00921 sensor_msgs::CvBridge img_bridge_; 00922 img_bridge_.fromImage(this->imageMsg); 00923 00924 //cvNamedWindow("showme",CV_WINDOW_AUTOSIZE); 00925 //cvSetMouseCallback("showme", &GazeboRosProsilica::mouse_cb, this); 00926 //cvStartWindowThread(); 00927 00928 //cvShowImage("showme",img_bridge_.toIpl()); 00929 cvSetImageROI(img_bridge_.toIpl(),cvRect(req.roi.x_offset,req.roi.y_offset,req.roi.width,req.roi.height)); 00930 IplImage *roi = cvCreateImage(cvSize(req.roi.width,req.roi.height), 00931 img_bridge_.toIpl()->depth, 00932 img_bridge_.toIpl()->nChannels); 00933 cvCopy(img_bridge_.toIpl(),roi); 00934 00935 img_bridge_.fromIpltoRosImage(roi,*this->roiImageMsg); 00936 00937 cvReleaseImage(&roi); 00938 } 00939 } 00940 } 00941 usleep(100000); 00942 } 00943 this->ImageDisconnect(); 00944 rsp.success = true; 00945 return; 00946 } 00947 00949 // Finalize the controller 00950 void GazeboRosProsilica::FiniChild() 00951 { 00952 this->myParent->SetActive(false); 00953 this->rosnode_->shutdown(); 00954 #ifdef USE_CBQ 00955 this->prosilica_queue_.clear(); 00956 this->prosilica_queue_.disable(); 00957 this->prosilica_callback_queue_thread_.join(); 00958 #else 00959 this->ros_spinner_thread_.join(); 00960 #endif 00961 00962 this->poll_srv_.shutdown(); 00963 this->image_pub_.shutdown(); 00964 this->camera_info_pub_.shutdown(); 00965 00966 } 00967 00968 #ifdef USE_CBQ 00969 00970 // Put laser data to the interface 00971 void GazeboRosProsilica::ProsilicaQueueThread() 00972 { 00973 static const double timeout = 0.01; 00974 00975 while (this->rosnode_->ok()) 00976 { 00977 this->prosilica_queue_.callAvailable(ros::WallDuration(timeout)); 00978 } 00979 } 00980 #else 00981 void GazeboRosProsilica::ProsilicaROSThread() 00982 { 00983 ROS_INFO_STREAM("Callback thread id=" << boost::this_thread::get_id()); 00984 00985 ros::Rate rate(1000); 00986 00987 while (this->rosnode_->ok()) 00988 { 00989 //rate.sleep(); // using rosrate gets stuck on model delete 00990 usleep(1000); 00991 ros::spinOnce(); 00992 } 00993 } 00994 #endif 00995 00996 00997 }