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
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_camera.h>
00037
00038 #include <gazebo/Timer.hh>
00039 #include <gazebo/Sensor.hh>
00040 #include <gazebo/Model.hh>
00041 #include <gazebo/Global.hh>
00042 #include <gazebo/XMLConfig.hh>
00043 #include <gazebo/Simulator.hh>
00044 #include <gazebo/gazebo.h>
00045 #include <gazebo/GazeboError.hh>
00046 #include <gazebo/ControllerFactory.hh>
00047 #include <gazebo/MonoCameraSensor.hh>
00048
00049 #include "sensor_msgs/Image.h"
00050 #include "sensor_msgs/fill_image.h"
00051
00052 namespace gazebo
00053 {
00054
00055 GZ_REGISTER_DYNAMIC_CONTROLLER("gazebo_ros_camera", GazeboRosCamera);
00056
00058
00059 GazeboRosCamera::GazeboRosCamera(Entity *parent)
00060 : Controller(parent)
00061 {
00062 this->myParent = dynamic_cast<MonoCameraSensor*>(this->parent);
00063
00064 if (!this->myParent)
00065 gzthrow("GazeboRosCamera controller requires a Camera Sensor as its parent");
00066
00067 Param::Begin(&this->parameters);
00068 this->robotNamespaceP = new ParamT<std::string>("robotNamespace","/",0);
00069 this->imageTopicNameP = new ParamT<std::string>("imageTopicName","", 1);
00070 this->cameraInfoTopicNameP = new ParamT<std::string>("cameraInfoTopicName","", 1);
00071 this->frameNameP = new ParamT<std::string>("frameName","generic_camera_link", 0);
00072
00073 this->CxPrimeP = new ParamT<double>("CxPrime",0, 0);
00074 this->CxP = new ParamT<double>("Cx" ,0, 0);
00075 this->CyP = new ParamT<double>("Cy" ,0, 0);
00076 this->focal_lengthP = new ParamT<double>("focal_length" ,0, 0);
00077 this->hack_baselineP = new ParamT<double>("hackBaseline" ,0, 0);
00078 this->distortion_k1P = new ParamT<double>("distortion_k1" ,0, 0);
00079 this->distortion_k2P = new ParamT<double>("distortion_k2" ,0, 0);
00080 this->distortion_k3P = new ParamT<double>("distortion_k3" ,0, 0);
00081 this->distortion_t1P = new ParamT<double>("distortion_t1" ,0, 0);
00082 this->distortion_t2P = new ParamT<double>("distortion_t2" ,0, 0);
00083 Param::End();
00084
00085 this->imageConnectCount = 0;
00086 this->infoConnectCount = 0;
00087
00088
00089
00090 }
00091
00093
00094 GazeboRosCamera::~GazeboRosCamera()
00095 {
00096 delete this->robotNamespaceP;
00097 delete this->rosnode_;
00098 delete this->imageTopicNameP;
00099 delete this->cameraInfoTopicNameP;
00100 delete this->frameNameP;
00101 delete this->CxPrimeP;
00102 delete this->CxP;
00103 delete this->CyP;
00104 delete this->focal_lengthP;
00105 delete this->hack_baselineP;
00106 delete this->distortion_k1P;
00107 delete this->distortion_k2P;
00108 delete this->distortion_k3P;
00109 delete this->distortion_t1P;
00110 delete this->distortion_t2P;
00111 }
00112
00114
00115 void GazeboRosCamera::LoadChild(XMLConfigNode *node)
00116 {
00117 this->robotNamespaceP->Load(node);
00118 this->robotNamespace = this->robotNamespaceP->GetValue();
00119 if (!ros::isInitialized())
00120 {
00121 int argc = 0;
00122 char** argv = NULL;
00123 ros::init(argc,argv,"gazebo",ros::init_options::NoSigintHandler|ros::init_options::AnonymousName);
00124 }
00125
00126 this->rosnode_ = new ros::NodeHandle(this->robotNamespace);
00127
00128 this->imageTopicNameP->Load(node);
00129 this->cameraInfoTopicNameP->Load(node);
00130 this->frameNameP->Load(node);
00131 this->CxPrimeP->Load(node);
00132 this->CxP->Load(node);
00133 this->CyP->Load(node);
00134 this->focal_lengthP->Load(node);
00135 this->hack_baselineP->Load(node);
00136 this->distortion_k1P->Load(node);
00137 this->distortion_k2P->Load(node);
00138 this->distortion_k3P->Load(node);
00139 this->distortion_t1P->Load(node);
00140 this->distortion_t2P->Load(node);
00141 this->imageTopicName = this->imageTopicNameP->GetValue();
00142 this->cameraInfoTopicName = this->cameraInfoTopicNameP->GetValue();
00143 this->frameName = this->frameNameP->GetValue();
00144 this->CxPrime = this->CxPrimeP->GetValue();
00145 this->Cx = this->CxP->GetValue();
00146 this->Cy = this->CyP->GetValue();
00147 this->focal_length = this->focal_lengthP->GetValue();
00148 this->hack_baseline = this->hack_baselineP->GetValue();
00149 this->distortion_k1 = this->distortion_k1P->GetValue();
00150 this->distortion_k2 = this->distortion_k2P->GetValue();
00151 this->distortion_k3 = this->distortion_k3P->GetValue();
00152 this->distortion_t1 = this->distortion_t1P->GetValue();
00153 this->distortion_t2 = this->distortion_t2P->GetValue();
00154
00155 #ifdef USE_CBQ
00156 ros::AdvertiseOptions image_ao = ros::AdvertiseOptions::create<sensor_msgs::Image>(
00157 this->imageTopicName,1,
00158 boost::bind( &GazeboRosCamera::ImageConnect,this),
00159 boost::bind( &GazeboRosCamera::ImageDisconnect,this), ros::VoidPtr(), &this->camera_queue_);
00160 this->image_pub_ = this->rosnode_->advertise(image_ao);
00161
00162 ros::AdvertiseOptions camera_info_ao = ros::AdvertiseOptions::create<sensor_msgs::CameraInfo>(
00163 this->cameraInfoTopicName,1,
00164 boost::bind( &GazeboRosCamera::InfoConnect,this),
00165 boost::bind( &GazeboRosCamera::InfoDisconnect,this), ros::VoidPtr(), &this->camera_queue_);
00166 this->camera_info_pub_ = this->rosnode_->advertise(camera_info_ao);
00167
00168 ros::SubscribeOptions zoom_so = ros::SubscribeOptions::create<std_msgs::Float64>(
00169 "set_hfov",1,
00170 boost::bind( &GazeboRosCamera::SetHFOV,this,_1),
00171 ros::VoidPtr(), &this->camera_queue_);
00172 this->cameraHFOVSubscriber_ = this->rosnode_->subscribe(zoom_so);
00173
00174 ros::SubscribeOptions rate_so = ros::SubscribeOptions::create<std_msgs::Float64>(
00175 "set_update_rate",1,
00176 boost::bind( &GazeboRosCamera::SetUpdateRate,this,_1),
00177 ros::VoidPtr(), &this->camera_queue_);
00178 this->cameraUpdateRateSubscriber_ = this->rosnode_->subscribe(rate_so);
00179
00180 #else
00181 this->image_pub_ = this->rosnode_->advertise<sensor_msgs::Image>(this->imageTopicName,1,
00182 boost::bind( &GazeboRosCamera::ImageConnect, this),
00183 boost::bind( &GazeboRosCamera::ImageDisconnect, this));
00184 this->camera_info_pub_ = this->rosnode_->advertise<sensor_msgs::CameraInfo>(this->cameraInfoTopicName,1,
00185 boost::bind( &GazeboRosCamera::InfoConnect, this),
00186 boost::bind( &GazeboRosCamera::InfoDisconnect, this));
00187 #endif
00188 }
00189
00191
00192 void GazeboRosCamera::InfoConnect()
00193 {
00194 this->infoConnectCount++;
00195 }
00197
00198 void GazeboRosCamera::InfoDisconnect()
00199 {
00200 this->infoConnectCount--;
00201 }
00202
00204
00205 void GazeboRosCamera::SetHFOV(const std_msgs::Float64::ConstPtr& hfov)
00206 {
00207 (dynamic_cast<OgreCamera*>(this->myParent))->SetFOV(hfov->data);
00208 }
00209
00211
00212 void GazeboRosCamera::SetUpdateRate(const std_msgs::Float64::ConstPtr& update_rate)
00213 {
00214 (dynamic_cast<OgreCamera*>(this->myParent))->SetUpdateRate(update_rate->data);
00215 }
00216
00218
00219 void GazeboRosCamera::ImageConnect()
00220 {
00221 this->imageConnectCount++;
00222 }
00224
00225 void GazeboRosCamera::ImageDisconnect()
00226 {
00227 this->imageConnectCount--;
00228
00229 if (this->imageConnectCount == 0)
00230 this->myParent->SetActive(false);
00231 }
00232
00234
00235 void GazeboRosCamera::InitChild()
00236 {
00237
00238 this->myParent->SetActive(false);
00239
00240
00241 this->width = this->myParent->GetImageWidth();
00242 this->height = this->myParent->GetImageHeight();
00243 this->depth = this->myParent->GetImageDepth();
00244 if (this->myParent->GetImageFormat() == "L8")
00245 {
00246 this->type = sensor_msgs::image_encodings::MONO8;
00247 this->skip = 1;
00248 }
00249 else if (this->myParent->GetImageFormat() == "R8G8B8")
00250 {
00251 this->type = sensor_msgs::image_encodings::RGB8;
00252 this->skip = 3;
00253 }
00254 else if (this->myParent->GetImageFormat() == "B8G8R8")
00255 {
00256 this->type = sensor_msgs::image_encodings::BGR8;
00257 this->skip = 3;
00258 }
00259 else if (this->myParent->GetImageFormat() == "BAYER_RGGB8")
00260 {
00261 this->type = sensor_msgs::image_encodings::BAYER_RGGB8;
00262 this->skip = 1;
00263 }
00264 else if (this->myParent->GetImageFormat() == "BAYER_BGGR8")
00265 {
00266 this->type = sensor_msgs::image_encodings::BAYER_BGGR8;
00267 this->skip = 1;
00268 }
00269 else if (this->myParent->GetImageFormat() == "BAYER_GBRG8")
00270 {
00271 this->type = sensor_msgs::image_encodings::BAYER_GBRG8;
00272 this->skip = 1;
00273 }
00274 else if (this->myParent->GetImageFormat() == "BAYER_GRBG8")
00275 {
00276 this->type = sensor_msgs::image_encodings::BAYER_GRBG8;
00277 this->skip = 1;
00278 }
00279 else
00280 {
00281 ROS_ERROR("Unsupported Gazebo ImageFormat\n");
00282 this->type = sensor_msgs::image_encodings::BGR8;
00283 this->skip = 3;
00284 }
00285
00287 if (this->CxPrime == 0)
00288 this->CxPrime = ((double)this->width+1.0) /2.0;
00289 if (this->Cx == 0)
00290 this->Cx = ((double)this->width+1.0) /2.0;
00291 if (this->Cy == 0)
00292 this->Cy = ((double)this->height+1.0) /2.0;
00293 if (this->focal_length == 0)
00294 this->focal_length = ((double)this->width) / (2.0 *tan(this->myParent->GetHFOV().GetAsRadian()/2.0));
00295
00296
00297 #ifdef USE_CBQ
00298
00299 this->callback_queue_thread_ = boost::thread( boost::bind( &GazeboRosCamera::CameraQueueThread,this ) );
00300 #endif
00301
00302
00303 }
00304
00306
00307 void GazeboRosCamera::UpdateChild()
00308 {
00309
00310
00311
00312 if (!this->myParent->IsActive())
00313 {
00314 if (this->imageConnectCount > 0)
00315
00316 this->myParent->SetActive(true);
00317 }
00318 else
00319 {
00320 this->PutCameraData();
00321 }
00322
00324 if (this->infoConnectCount > 0)
00325 this->PublishCameraInfo();
00326 }
00327
00329
00330 void GazeboRosCamera::FiniChild()
00331 {
00332 this->myParent->SetActive(false);
00333 this->rosnode_->shutdown();
00334 #ifdef USE_CBQ
00335 this->camera_queue_.clear();
00336 this->camera_queue_.disable();
00337 this->callback_queue_thread_.join();
00338 #endif
00339
00340 }
00341
00343
00344 void GazeboRosCamera::PutCameraData()
00345 {
00346
00347 const unsigned char *src;
00348
00349
00350
00351
00352 {
00353
00354 src = this->myParent->GetImageData(0);
00355 }
00356
00357 if (src)
00358 {
00359
00360
00361 unsigned char dst[this->width*this->height];
00362
00363 this->lock.lock();
00364
00365 this->imageMsg.header.frame_id = this->frameName;
00366 Time lastRenderTime = (dynamic_cast<OgreCamera*>(this->myParent))->GetLastRenderTime();
00367
00368
00369
00370 this->imageMsg.header.stamp.sec = lastRenderTime.sec;
00371 this->imageMsg.header.stamp.nsec = lastRenderTime.nsec;
00372
00373
00374
00375
00377 if (this->image_pub_.getNumSubscribers() > 0)
00378 {
00379
00380
00381
00382 if (this->myParent->GetImageFormat() == "BAYER_RGGB8" && this->depth == 3)
00383 {
00384 for (int i=0;i<this->width;i++)
00385 {
00386 for (int j=0;j<this->height;j++)
00387 {
00388
00389
00390
00391
00392
00393 if (j%2)
00394 if (i%2)
00395 dst[i+j*this->width] = src[i*3+j*this->width*3+0];
00396 else
00397 dst[i+j*this->width] = src[i*3+j*this->width*3+1];
00398 else
00399 if (i%2)
00400 dst[i+j*this->width] = src[i*3+j*this->width*3+1];
00401 else
00402 dst[i+j*this->width] = src[i*3+j*this->width*3+2];
00403 }
00404 }
00405 src=dst;
00406 }
00407 else if (this->myParent->GetImageFormat() == "BAYER_BGGR8" && this->depth == 3)
00408 {
00409 for (int i=0;i<this->width;i++)
00410 {
00411 for (int j=0;j<this->height;j++)
00412 {
00413
00414
00415
00416
00417
00418 if (j%2)
00419 if (i%2)
00420 dst[i+j*this->width] = src[i*3+j*this->width*3+2];
00421 else
00422 dst[i+j*this->width] = src[i*3+j*this->width*3+1];
00423 else
00424 if (i%2)
00425 dst[i+j*this->width] = src[i*3+j*this->width*3+1];
00426 else
00427 dst[i+j*this->width] = src[i*3+j*this->width*3+0];
00428 }
00429 }
00430 src=dst;
00431 }
00432 else if (this->myParent->GetImageFormat() == "BAYER_GBRG8" && this->depth == 3)
00433 {
00434 for (int i=0;i<this->width;i++)
00435 {
00436 for (int j=0;j<this->height;j++)
00437 {
00438
00439
00440
00441
00442
00443 if (j%2)
00444 if (i%2)
00445 dst[i+j*this->width] = src[i*3+j*this->width*3+1];
00446 else
00447 dst[i+j*this->width] = src[i*3+j*this->width*3+2];
00448 else
00449 if (i%2)
00450 dst[i+j*this->width] = src[i*3+j*this->width*3+0];
00451 else
00452 dst[i+j*this->width] = src[i*3+j*this->width*3+1];
00453 }
00454 }
00455 src=dst;
00456 }
00457 else if (this->myParent->GetImageFormat() == "BAYER_GRBG8" && this->depth == 3)
00458 {
00459 for (int i=0;i<this->width;i++)
00460 {
00461 for (int j=0;j<this->height;j++)
00462 {
00463
00464
00465
00466
00467
00468 if (j%2)
00469 if (i%2)
00470 dst[i+j*this->width] = src[i*3+j*this->width*3+1];
00471 else
00472 dst[i+j*this->width] = src[i*3+j*this->width*3+0];
00473 else
00474 if (i%2)
00475 dst[i+j*this->width] = src[i*3+j*this->width*3+2];
00476 else
00477 dst[i+j*this->width] = src[i*3+j*this->width*3+1];
00478 }
00479 }
00480 src=dst;
00481 }
00482
00483
00484 fillImage(this->imageMsg,
00485 this->type,
00486 this->height,
00487 this->width,
00488 this->skip*this->width,
00489 (void*)src );
00490
00491
00492
00493
00494 this->image_pub_.publish(this->imageMsg);
00495 }
00496
00497
00498
00499 this->lock.unlock();
00500 }
00501
00502 }
00503
00505
00506 void GazeboRosCamera::PublishCameraInfo()
00507 {
00508
00509 this->cameraInfoMsg.header.frame_id = this->frameName;
00510 Time lastRenderTime = (dynamic_cast<OgreCamera*>(this->myParent))->GetLastRenderTime();
00511
00512 this->cameraInfoMsg.header.stamp.sec = lastRenderTime.sec;
00513 this->cameraInfoMsg.header.stamp.nsec = lastRenderTime.nsec;
00514 this->cameraInfoMsg.height = this->height;
00515 this->cameraInfoMsg.width = this->width;
00516
00517 #if ROS_VERSION_MINIMUM(1, 3, 0)
00518 this->cameraInfoMsg.distortion_model = "plumb_bob";
00519 this->cameraInfoMsg.D.resize(5);
00520 #endif
00521 this->cameraInfoMsg.D[0] = this->distortion_k1;
00522 this->cameraInfoMsg.D[1] = this->distortion_k2;
00523 this->cameraInfoMsg.D[2] = this->distortion_k3;
00524 this->cameraInfoMsg.D[3] = this->distortion_t1;
00525 this->cameraInfoMsg.D[4] = this->distortion_t2;
00526
00527 this->cameraInfoMsg.K[0] = this->focal_length;
00528 this->cameraInfoMsg.K[1] = 0.0;
00529 this->cameraInfoMsg.K[2] = this->Cx;
00530 this->cameraInfoMsg.K[3] = 0.0;
00531 this->cameraInfoMsg.K[4] = this->focal_length;
00532 this->cameraInfoMsg.K[5] = this->Cy;
00533 this->cameraInfoMsg.K[6] = 0.0;
00534 this->cameraInfoMsg.K[7] = 0.0;
00535 this->cameraInfoMsg.K[8] = 1.0;
00536
00537 this->cameraInfoMsg.R[0] = 1.0;
00538 this->cameraInfoMsg.R[1] = 0.0;
00539 this->cameraInfoMsg.R[2] = 0.0;
00540 this->cameraInfoMsg.R[3] = 0.0;
00541 this->cameraInfoMsg.R[4] = 1.0;
00542 this->cameraInfoMsg.R[5] = 0.0;
00543 this->cameraInfoMsg.R[6] = 0.0;
00544 this->cameraInfoMsg.R[7] = 0.0;
00545 this->cameraInfoMsg.R[8] = 1.0;
00546
00547 this->cameraInfoMsg.P[0] = this->focal_length;
00548 this->cameraInfoMsg.P[1] = 0.0;
00549 this->cameraInfoMsg.P[2] = this->Cx;
00550 this->cameraInfoMsg.P[3] = -this->focal_length * this->hack_baseline;
00551 this->cameraInfoMsg.P[4] = 0.0;
00552 this->cameraInfoMsg.P[5] = this->focal_length;
00553 this->cameraInfoMsg.P[6] = this->Cy;
00554 this->cameraInfoMsg.P[7] = 0.0;
00555 this->cameraInfoMsg.P[8] = 0.0;
00556 this->cameraInfoMsg.P[9] = 0.0;
00557 this->cameraInfoMsg.P[10] = 1.0;
00558 this->cameraInfoMsg.P[11] = 0.0;
00559 this->camera_info_pub_.publish(this->cameraInfoMsg);
00560 }
00561
00562
00563 #ifdef USE_CBQ
00564
00565
00566 void GazeboRosCamera::CameraQueueThread()
00567 {
00568 static const double timeout = 0.01;
00569
00570 while (this->rosnode_->ok())
00571 {
00572 this->camera_queue_.callAvailable(ros::WallDuration(timeout));
00573 }
00574 }
00575 #endif
00576
00577 }