00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <string>
00019 #include <algorithm>
00020 #include <assert.h>
00021 #include <boost/thread/thread.hpp>
00022 #include <boost/bind.hpp>
00023
00024 #include <tf/tf.h>
00025 #include <tf/transform_listener.h>
00026 #include <sensor_msgs/Image.h>
00027 #include <sensor_msgs/fill_image.h>
00028 #include <image_transport/image_transport.h>
00029 #include <geometry_msgs/Point32.h>
00030 #include <sensor_msgs/ChannelFloat32.h>
00031 #include <camera_info_manager/camera_info_manager.h>
00032
00033 #include <sdf/sdf.hh>
00034
00035 #include <gazebo/physics/World.hh>
00036 #include <gazebo/physics/HingeJoint.hh>
00037 #include <gazebo/sensors/Sensor.hh>
00038 #include <gazebo/common/Exception.hh>
00039 #include <gazebo/sensors/CameraSensor.hh>
00040 #include <gazebo/sensors/SensorTypes.hh>
00041 #include <gazebo/rendering/Camera.hh>
00042
00043 #include "gazebo_plugins/gazebo_ros_camera_utils.h"
00044
00045 namespace gazebo
00046 {
00048
00049 GazeboRosCameraUtils::GazeboRosCameraUtils()
00050 {
00051 this->last_update_time_ = common::Time(0);
00052 this->last_info_update_time_ = common::Time(0);
00053 this->height_ = 0;
00054 this->width_ = 0;
00055 this->skip_ = 0;
00056 this->format_ = "";
00057 this->initialized_ = false;
00058 }
00059
00060 void GazeboRosCameraUtils::configCallback(
00061 gazebo_plugins::GazeboRosCameraConfig &config, uint32_t level)
00062 {
00063 if (this->initialized_)
00064 {
00065 ROS_INFO("Reconfigure request for the gazebo ros camera_: %s. New rate: %.2f",
00066 this->camera_name_.c_str(), config.imager_rate);
00067 this->parentSensor_->SetUpdateRate(config.imager_rate);
00068 }
00069 }
00070
00072
00073 GazeboRosCameraUtils::~GazeboRosCameraUtils()
00074 {
00075 this->parentSensor_->SetActive(false);
00076 this->rosnode_->shutdown();
00077 this->camera_queue_.clear();
00078 this->camera_queue_.disable();
00079 this->callback_queue_thread_.join();
00080 delete this->rosnode_;
00081 }
00082
00084
00085 void GazeboRosCameraUtils::Load(sensors::SensorPtr _parent,
00086 sdf::ElementPtr _sdf,
00087 const std::string &_camera_name_suffix,
00088 double _hack_baseline)
00089 {
00090
00091
00092
00093
00094 this->Load(_parent, _sdf, _camera_name_suffix);
00095
00096
00097
00098 this->hack_baseline_ = _hack_baseline;
00099 }
00100
00102
00103 void GazeboRosCameraUtils::Load(sensors::SensorPtr _parent,
00104 sdf::ElementPtr _sdf,
00105 const std::string &_camera_name_suffix)
00106 {
00107
00108 # if GAZEBO_MAJOR_VERSION >= 7
00109 std::string world_name = _parent->WorldName();
00110 # else
00111 std::string world_name = _parent->GetWorldName();
00112 # endif
00113
00114
00115 this->world_ = physics::get_world(world_name);
00116
00117
00118 this->sdf = _sdf;
00119
00120
00121
00122 this->world = this->world_;
00123
00124 std::stringstream ss;
00125 this->robot_namespace_ = GetRobotNamespace(_parent, _sdf, "Camera");
00126
00127 this->image_topic_name_ = "image_raw";
00128 if (this->sdf->HasElement("imageTopicName"))
00129 this->image_topic_name_ = this->sdf->Get<std::string>("imageTopicName");
00130
00131 this->camera_info_topic_name_ = "camera_info";
00132 if (this->sdf->HasElement("cameraInfoTopicName"))
00133 this->camera_info_topic_name_ =
00134 this->sdf->Get<std::string>("cameraInfoTopicName");
00135
00136 if (!this->sdf->HasElement("cameraName"))
00137 ROS_DEBUG("Camera plugin missing <cameraName>, default to empty");
00138 else
00139 this->camera_name_ = this->sdf->Get<std::string>("cameraName");
00140
00141
00142
00143 this->camera_name_ += _camera_name_suffix;
00144
00145 if (!this->sdf->HasElement("frameName"))
00146 ROS_DEBUG("Camera plugin missing <frameName>, defaults to /world");
00147 else
00148 this->frame_name_ = this->sdf->Get<std::string>("frameName");
00149
00150 if (!this->sdf->HasElement("updateRate"))
00151 {
00152 ROS_DEBUG("Camera plugin missing <updateRate>, defaults to unlimited (0).");
00153 this->update_rate_ = 0;
00154 }
00155 else
00156 this->update_rate_ = this->sdf->Get<double>("updateRate");
00157
00158 if (!this->sdf->HasElement("CxPrime"))
00159 {
00160 ROS_DEBUG("Camera plugin missing <CxPrime>, defaults to 0");
00161 this->cx_prime_ = 0;
00162 }
00163 else
00164 this->cx_prime_ = this->sdf->Get<double>("CxPrime");
00165
00166 if (!this->sdf->HasElement("Cx"))
00167 {
00168 ROS_DEBUG("Camera plugin missing <Cx>, defaults to 0");
00169 this->cx_= 0;
00170 }
00171 else
00172 this->cx_ = this->sdf->Get<double>("Cx");
00173
00174 if (!this->sdf->HasElement("Cy"))
00175 {
00176 ROS_DEBUG("Camera plugin missing <Cy>, defaults to 0");
00177 this->cy_= 0;
00178 }
00179 else
00180 this->cy_ = this->sdf->Get<double>("Cy");
00181
00182 if (!this->sdf->HasElement("focalLength"))
00183 {
00184 ROS_DEBUG("Camera plugin missing <focalLength>, defaults to 0");
00185 this->focal_length_= 0;
00186 }
00187 else
00188 this->focal_length_ = this->sdf->Get<double>("focalLength");
00189
00190 if (!this->sdf->HasElement("hackBaseline"))
00191 {
00192 ROS_DEBUG("Camera plugin missing <hackBaseline>, defaults to 0");
00193 this->hack_baseline_= 0;
00194 }
00195 else
00196 this->hack_baseline_ = this->sdf->Get<double>("hackBaseline");
00197
00198 if (!this->sdf->HasElement("distortionK1"))
00199 {
00200 ROS_DEBUG("Camera plugin missing <distortionK1>, defaults to 0");
00201 this->distortion_k1_= 0;
00202 }
00203 else
00204 this->distortion_k1_ = this->sdf->Get<double>("distortionK1");
00205
00206 if (!this->sdf->HasElement("distortionK2"))
00207 {
00208 ROS_DEBUG("Camera plugin missing <distortionK2>, defaults to 0");
00209 this->distortion_k2_= 0;
00210 }
00211 else
00212 this->distortion_k2_ = this->sdf->Get<double>("distortionK2");
00213
00214 if (!this->sdf->HasElement("distortionK3"))
00215 {
00216 ROS_DEBUG("Camera plugin missing <distortionK3>, defaults to 0");
00217 this->distortion_k3_= 0;
00218 }
00219 else
00220 this->distortion_k3_ = this->sdf->Get<double>("distortionK3");
00221
00222 if (!this->sdf->HasElement("distortionT1"))
00223 {
00224 ROS_DEBUG("Camera plugin missing <distortionT1>, defaults to 0");
00225 this->distortion_t1_= 0;
00226 }
00227 else
00228 this->distortion_t1_ = this->sdf->Get<double>("distortionT1");
00229
00230 if (!this->sdf->HasElement("distortionT2"))
00231 {
00232 ROS_DEBUG("Camera plugin missing <distortionT2>, defaults to 0");
00233 this->distortion_t2_= 0;
00234 }
00235 else
00236 this->distortion_t2_ = this->sdf->Get<double>("distortionT2");
00237
00238 if ((this->distortion_k1_ != 0.0) || (this->distortion_k2_ != 0.0) ||
00239 (this->distortion_k3_ != 0.0) || (this->distortion_t1_ != 0.0) ||
00240 (this->distortion_t2_ != 0.0))
00241 {
00242 ROS_WARN("gazebo_ros_camera_ simulation does not support non-zero"
00243 " distortion parameters right now, your simulation maybe wrong.");
00244 }
00245
00246
00247 if (!this->image_connect_count_) this->image_connect_count_ = boost::shared_ptr<int>(new int(0));
00248 if (!this->image_connect_count_lock_) this->image_connect_count_lock_ = boost::shared_ptr<boost::mutex>(new boost::mutex);
00249 if (!this->was_active_) this->was_active_ = boost::shared_ptr<bool>(new bool(false));
00250
00251
00252 this->deferred_load_thread_ = boost::thread(
00253 boost::bind(&GazeboRosCameraUtils::LoadThread, this));
00254 }
00255
00256 event::ConnectionPtr GazeboRosCameraUtils::OnLoad(const boost::function<void()>& load_function)
00257 {
00258 return load_event_.Connect(load_function);
00259 }
00260
00262
00263 void GazeboRosCameraUtils::LoadThread()
00264 {
00265
00266 if (!ros::isInitialized())
00267 {
00268 gzerr << "Not loading plugin since ROS hasn't been "
00269 << "properly initialized. Try starting gazebo with ros plugin:\n"
00270 << " gazebo -s libgazebo_ros_api_plugin.so\n";
00271 return;
00272 }
00273
00274
00275
00276 this->parentSensor_->SetActive(false);
00277
00278 this->rosnode_ = new ros::NodeHandle(this->robot_namespace_ + "/" + this->camera_name_);
00279
00280
00281 this->camera_info_manager_.reset(new camera_info_manager::CameraInfoManager(
00282 *this->rosnode_, this->camera_name_));
00283
00284 this->itnode_ = new image_transport::ImageTransport(*this->rosnode_);
00285
00286
00287 this->tf_prefix_ = tf::getPrefixParam(*this->rosnode_);
00288 if(this->tf_prefix_.empty()) {
00289 this->tf_prefix_ = this->robot_namespace_;
00290 boost::trim_right_if(this->tf_prefix_,boost::is_any_of("/"));
00291 }
00292 this->frame_name_ = tf::resolve(this->tf_prefix_, this->frame_name_);
00293
00294 ROS_INFO("Camera Plugin (ns = %s) <tf_prefix_>, set to \"%s\"",
00295 this->robot_namespace_.c_str(), this->tf_prefix_.c_str());
00296
00297
00298 if (!this->camera_name_.empty())
00299 {
00300 dyn_srv_ =
00301 new dynamic_reconfigure::Server<gazebo_plugins::GazeboRosCameraConfig>
00302 (*this->rosnode_);
00303 dynamic_reconfigure::Server<gazebo_plugins::GazeboRosCameraConfig>
00304 ::CallbackType f =
00305 boost::bind(&GazeboRosCameraUtils::configCallback, this, _1, _2);
00306 dyn_srv_->setCallback(f);
00307 }
00308 else
00309 {
00310 ROS_WARN("dynamic reconfigure is not enabled for this image topic [%s]"
00311 " becuase <cameraName> is not specified",
00312 this->image_topic_name_.c_str());
00313 }
00314
00315 this->image_pub_ = this->itnode_->advertise(
00316 this->image_topic_name_, 2,
00317 boost::bind(&GazeboRosCameraUtils::ImageConnect, this),
00318 boost::bind(&GazeboRosCameraUtils::ImageDisconnect, this),
00319 ros::VoidPtr(), true);
00320
00321
00322
00323
00324
00325
00326
00327
00328 ros::AdvertiseOptions cio =
00329 ros::AdvertiseOptions::create<sensor_msgs::CameraInfo>(
00330 this->camera_info_topic_name_, 2,
00331 boost::bind(&GazeboRosCameraUtils::ImageConnect, this),
00332 boost::bind(&GazeboRosCameraUtils::ImageDisconnect, this),
00333 ros::VoidPtr(), &this->camera_queue_);
00334 this->camera_info_pub_ = this->rosnode_->advertise(cio);
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352 this->Init();
00353 }
00354
00356
00357 void GazeboRosCameraUtils::SetHFOV(const std_msgs::Float64::ConstPtr& hfov)
00358 {
00359 #if GAZEBO_MAJOR_VERSION >= 7
00360 this->camera_->SetHFOV(ignition::math::Angle(hfov->data));
00361 #else
00362 this->camera_->SetHFOV(gazebo::math::Angle(hfov->data));
00363 #endif
00364 }
00365
00367
00368 void GazeboRosCameraUtils::SetUpdateRate(
00369 const std_msgs::Float64::ConstPtr& update_rate)
00370 {
00371 this->parentSensor_->SetUpdateRate(update_rate->data);
00372 }
00373
00375
00376 void GazeboRosCameraUtils::ImageConnect()
00377 {
00378 boost::mutex::scoped_lock lock(*this->image_connect_count_lock_);
00379
00380
00381 if ((*this->image_connect_count_) == 0)
00382 *this->was_active_ = this->parentSensor_->IsActive();
00383
00384 (*this->image_connect_count_)++;
00385
00386 this->parentSensor_->SetActive(true);
00387 }
00389
00390 void GazeboRosCameraUtils::ImageDisconnect()
00391 {
00392 boost::mutex::scoped_lock lock(*this->image_connect_count_lock_);
00393
00394 (*this->image_connect_count_)--;
00395
00396
00397
00398
00399 if ((*this->image_connect_count_) <= 0 && !*this->was_active_)
00400 this->parentSensor_->SetActive(false);
00401 }
00402
00404
00405 void GazeboRosCameraUtils::Init()
00406 {
00407
00408
00409
00410 if (this->update_rate_ > 0.0)
00411 this->update_period_ = 1.0/this->update_rate_;
00412 else
00413 this->update_period_ = 0.0;
00414
00415
00416 if (this->format_ == "L8")
00417 {
00418 this->type_ = sensor_msgs::image_encodings::MONO8;
00419 this->skip_ = 1;
00420 }
00421 else if (this->format_ == "R8G8B8")
00422 {
00423 this->type_ = sensor_msgs::image_encodings::RGB8;
00424 this->skip_ = 3;
00425 }
00426 else if (this->format_ == "B8G8R8")
00427 {
00428 this->type_ = sensor_msgs::image_encodings::BGR8;
00429 this->skip_ = 3;
00430 }
00431 else if (this->format_ == "BAYER_RGGB8")
00432 {
00433 ROS_INFO("bayer simulation maybe computationally expensive.");
00434 this->type_ = sensor_msgs::image_encodings::BAYER_RGGB8;
00435 this->skip_ = 1;
00436 }
00437 else if (this->format_ == "BAYER_BGGR8")
00438 {
00439 ROS_INFO("bayer simulation maybe computationally expensive.");
00440 this->type_ = sensor_msgs::image_encodings::BAYER_BGGR8;
00441 this->skip_ = 1;
00442 }
00443 else if (this->format_ == "BAYER_GBRG8")
00444 {
00445 ROS_INFO("bayer simulation maybe computationally expensive.");
00446 this->type_ = sensor_msgs::image_encodings::BAYER_GBRG8;
00447 this->skip_ = 1;
00448 }
00449 else if (this->format_ == "BAYER_GRBG8")
00450 {
00451 ROS_INFO("bayer simulation maybe computationally expensive.");
00452 this->type_ = sensor_msgs::image_encodings::BAYER_GRBG8;
00453 this->skip_ = 1;
00454 }
00455 else
00456 {
00457 ROS_ERROR("Unsupported Gazebo ImageFormat\n");
00458 this->type_ = sensor_msgs::image_encodings::BGR8;
00459 this->skip_ = 3;
00460 }
00461
00463 if (this->cx_prime_ == 0)
00464 this->cx_prime_ = (static_cast<double>(this->width_) + 1.0) /2.0;
00465 if (this->cx_ == 0)
00466 this->cx_ = (static_cast<double>(this->width_) + 1.0) /2.0;
00467 if (this->cy_ == 0)
00468 this->cy_ = (static_cast<double>(this->height_) + 1.0) /2.0;
00469
00470
00471 # if GAZEBO_MAJOR_VERSION >= 7
00472 double computed_focal_length =
00473 (static_cast<double>(this->width_)) /
00474 (2.0 * tan(this->camera_->HFOV().Radian() / 2.0));
00475 # else
00476 double computed_focal_length =
00477 (static_cast<double>(this->width_)) /
00478 (2.0 * tan(this->camera_->GetHFOV().Radian() / 2.0));
00479 # endif
00480
00481 if (this->focal_length_ == 0)
00482 {
00483 this->focal_length_ = computed_focal_length;
00484 }
00485 else
00486 {
00487
00488 if (!gazebo::math::equal(this->focal_length_, computed_focal_length))
00489 {
00490 # if GAZEBO_MAJOR_VERSION >= 7
00491 ROS_WARN("The <focal_length>[%f] you have provided for camera_ [%s]"
00492 " is inconsistent with specified image_width [%d] and"
00493 " HFOV [%f]. Please double check to see that"
00494 " focal_length = width_ / (2.0 * tan(HFOV/2.0)),"
00495 " the explected focal_lengtth value is [%f],"
00496 " please update your camera_ model description accordingly.",
00497 this->focal_length_, this->parentSensor_->Name().c_str(),
00498 this->width_, this->camera_->HFOV().Radian(),
00499 computed_focal_length);
00500 # else
00501 ROS_WARN("The <focal_length>[%f] you have provided for camera_ [%s]"
00502 " is inconsistent with specified image_width [%d] and"
00503 " HFOV [%f]. Please double check to see that"
00504 " focal_length = width_ / (2.0 * tan(HFOV/2.0)),"
00505 " the explected focal_lengtth value is [%f],"
00506 " please update your camera_ model description accordingly.",
00507 this->focal_length_, this->parentSensor_->GetName().c_str(),
00508 this->width_, this->camera_->GetHFOV().Radian(),
00509 computed_focal_length);
00510
00511 # endif
00512 }
00513 }
00514
00515
00516 sensor_msgs::CameraInfo camera_info_msg;
00517
00518 camera_info_msg.header.frame_id = this->frame_name_;
00519
00520 camera_info_msg.height = this->height_;
00521 camera_info_msg.width = this->width_;
00522
00523 #if ROS_VERSION_MINIMUM(1, 3, 0)
00524 camera_info_msg.distortion_model = "plumb_bob";
00525 camera_info_msg.D.resize(5);
00526 #endif
00527
00528
00529
00530 camera_info_msg.D[0] = this->distortion_k1_;
00531 camera_info_msg.D[1] = this->distortion_k2_;
00532 camera_info_msg.D[2] = this->distortion_t1_;
00533 camera_info_msg.D[3] = this->distortion_t2_;
00534 camera_info_msg.D[4] = this->distortion_k3_;
00535
00536 camera_info_msg.K[0] = this->focal_length_;
00537 camera_info_msg.K[1] = 0.0;
00538 camera_info_msg.K[2] = this->cx_;
00539 camera_info_msg.K[3] = 0.0;
00540 camera_info_msg.K[4] = this->focal_length_;
00541 camera_info_msg.K[5] = this->cy_;
00542 camera_info_msg.K[6] = 0.0;
00543 camera_info_msg.K[7] = 0.0;
00544 camera_info_msg.K[8] = 1.0;
00545
00546 camera_info_msg.R[0] = 1.0;
00547 camera_info_msg.R[1] = 0.0;
00548 camera_info_msg.R[2] = 0.0;
00549 camera_info_msg.R[3] = 0.0;
00550 camera_info_msg.R[4] = 1.0;
00551 camera_info_msg.R[5] = 0.0;
00552 camera_info_msg.R[6] = 0.0;
00553 camera_info_msg.R[7] = 0.0;
00554 camera_info_msg.R[8] = 1.0;
00555
00556
00557 camera_info_msg.P[0] = this->focal_length_;
00558 camera_info_msg.P[1] = 0.0;
00559 camera_info_msg.P[2] = this->cx_;
00560 camera_info_msg.P[3] = -this->focal_length_ * this->hack_baseline_;
00561 camera_info_msg.P[4] = 0.0;
00562 camera_info_msg.P[5] = this->focal_length_;
00563 camera_info_msg.P[6] = this->cy_;
00564 camera_info_msg.P[7] = 0.0;
00565 camera_info_msg.P[8] = 0.0;
00566 camera_info_msg.P[9] = 0.0;
00567 camera_info_msg.P[10] = 1.0;
00568 camera_info_msg.P[11] = 0.0;
00569
00570 this->camera_info_manager_->setCameraInfo(camera_info_msg);
00571
00572
00573 this->callback_queue_thread_ = boost::thread(
00574 boost::bind(&GazeboRosCameraUtils::CameraQueueThread, this));
00575
00576 load_event_();
00577 this->initialized_ = true;
00578 }
00579
00581
00582 void GazeboRosCameraUtils::PutCameraData(const unsigned char *_src,
00583 common::Time &last_update_time)
00584 {
00585 this->sensor_update_time_ = last_update_time;
00586 this->PutCameraData(_src);
00587 }
00588
00589 void GazeboRosCameraUtils::PutCameraData(const unsigned char *_src)
00590 {
00591 if (!this->initialized_ || this->height_ <=0 || this->width_ <=0)
00592 return;
00593
00595 if ((*this->image_connect_count_) > 0)
00596 {
00597 boost::mutex::scoped_lock lock(this->lock_);
00598
00599
00600 this->image_msg_.header.frame_id = this->frame_name_;
00601 this->image_msg_.header.stamp.sec = this->sensor_update_time_.sec;
00602 this->image_msg_.header.stamp.nsec = this->sensor_update_time_.nsec;
00603
00604
00605 fillImage(this->image_msg_, this->type_, this->height_, this->width_,
00606 this->skip_*this->width_, reinterpret_cast<const void*>(_src));
00607
00608
00609 this->image_pub_.publish(this->image_msg_);
00610 }
00611 }
00612
00614
00615 void GazeboRosCameraUtils::PublishCameraInfo(common::Time &last_update_time)
00616 {
00617 if (!this->initialized_ || this->height_ <=0 || this->width_ <=0)
00618 return;
00619
00620 this->sensor_update_time_ = last_update_time;
00621 this->PublishCameraInfo();
00622 }
00623
00624 void GazeboRosCameraUtils::PublishCameraInfo()
00625 {
00626 if (!this->initialized_ || this->height_ <=0 || this->width_ <=0)
00627 return;
00628
00629 if (this->camera_info_pub_.getNumSubscribers() > 0)
00630 {
00631 # if GAZEBO_MAJOR_VERSION >= 7
00632 this->sensor_update_time_ = this->parentSensor_->LastMeasurementTime();
00633 # else
00634 this->sensor_update_time_ = this->parentSensor_->GetLastMeasurementTime();
00635 # endif
00636 if (this->sensor_update_time_ - this->last_info_update_time_ >= this->update_period_)
00637 {
00638 this->PublishCameraInfo(this->camera_info_pub_);
00639 this->last_info_update_time_ = this->sensor_update_time_;
00640 }
00641 }
00642 }
00643
00644 void GazeboRosCameraUtils::PublishCameraInfo(
00645 ros::Publisher camera_info_publisher)
00646 {
00647 sensor_msgs::CameraInfo camera_info_msg = camera_info_manager_->getCameraInfo();
00648
00649 camera_info_msg.header.stamp.sec = this->sensor_update_time_.sec;
00650 camera_info_msg.header.stamp.nsec = this->sensor_update_time_.nsec;
00651
00652 camera_info_publisher.publish(camera_info_msg);
00653 }
00654
00655
00657
00658 void GazeboRosCameraUtils::CameraQueueThread()
00659 {
00660 static const double timeout = 0.001;
00661
00662 while (this->rosnode_->ok())
00663 {
00665 this->camera_queue_.callAvailable(ros::WallDuration(timeout));
00666 }
00667 }
00668 }