gazebo_ros_prosilica.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2013 Open Source Robotics Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16 */
17 
18 /*
19  @mainpage
20  Desc: GazeboRosProsilica plugin for simulating Prosilica cameras in Gazebo
21  Author: John Hsu
22  Date: 24 Sept 2008
23 */
24 
25 #include <algorithm>
26 #include <assert.h>
27 
29 
30 #include <gazebo/physics/World.hh>
31 #include <gazebo/physics/HingeJoint.hh>
32 #include <gazebo/sensors/Sensor.hh>
33 #include <gazebo/common/Exception.hh>
34 #include <gazebo/sensors/CameraSensor.hh>
35 #include <gazebo/sensors/SensorTypes.hh>
36 #include <gazebo/rendering/Camera.hh>
37 
38 #include <sdf/sdf.hh>
39 #include <sdf/Param.hh>
40 
41 #include <sensor_msgs/Image.h>
42 #include <sensor_msgs/CameraInfo.h>
43 #include <sensor_msgs/fill_image.h>
45 #include <sensor_msgs/RegionOfInterest.h>
46 
47 #include <opencv2/highgui.hpp>
48 
49 #include <boost/scoped_ptr.hpp>
50 #include <boost/bind.hpp>
51 #include <boost/tokenizer.hpp>
52 #include <boost/thread.hpp>
53 #include <boost/thread/recursive_mutex.hpp>
54 #include <string>
55 #include <chrono>
56 #include <thread>
57 
58 namespace gazebo
59 {
60 
62 // Constructor
64 {
65 }
66 
68 // Destructor
70 {
71  // Finalize the controller
72  this->poll_srv_.shutdown();
73 }
74 
76 // Load the controller
77 void GazeboRosProsilica::Load(sensors::SensorPtr _parent, sdf::ElementPtr _sdf)
78 {
79 
80  CameraPlugin::Load(_parent, _sdf);
81  this->parentSensor_ = this->parentSensor;
82  this->width_ = this->width;
83  this->height_ = this->height;
84  this->depth_ = this->depth;
85  this->format_ = this->format;
86  this->camera_ = this->camera;
87  GazeboRosCameraUtils::Load(_parent, _sdf);
88 
90 }
91 
93 {
94  // camera mode for prosilica:
95  // prosilica::AcquisitionMode mode_; /// @todo Make this property of Camera
96 
97  //ROS_ERROR_NAMED("prosilica", "before trigger_mode %s %s",this->mode_param_name.c_str(),this->mode_.c_str());
98 
99  if (!this->rosnode_->searchParam("trigger_mode",this->mode_param_name))
100  this->mode_param_name = "trigger_mode";
101 
102  if (!this->rosnode_->getParam(this->mode_param_name,this->mode_))
103  this->mode_ = "streaming";
104 
105  ROS_INFO_NAMED("prosilica", "trigger_mode %s %s",this->mode_param_name.c_str(),this->mode_.c_str());
106 
107 
108  if (this->mode_ == "polled")
109  {
111  }
112  else if (this->mode_ == "streaming")
113  {
114  ROS_DEBUG_NAMED("prosilica", "do nothing here,mode: %s",this->mode_.c_str());
115  }
116  else
117  {
118  ROS_ERROR_NAMED("prosilica", "trigger_mode is invalid: %s, using streaming mode",this->mode_.c_str());
119  }
120 }
121 
123 // Update the controller
124 void GazeboRosProsilica::OnNewImageFrame(const unsigned char *_image,
125  unsigned int _width, unsigned int _height, unsigned int _depth,
126  const std::string &_format)
127 {
128  if (!this->rosnode_->getParam(this->mode_param_name,this->mode_))
129  this->mode_ = "streaming";
130 
131  // should do nothing except turning camera on/off, as we are using service.
133  common::Time sensor_update_time = this->parentSensor_->LastMeasurementTime();
134 
135  // as long as ros is connected, parent is active
136  //ROS_ERROR_NAMED("prosilica", "debug image count %d",this->image_connect_count_);
137  if (!this->parentSensor->IsActive())
138  {
139  if ((*this->image_connect_count_) > 0)
140  // do this first so there's chance for sensor to run 1 frame after activate
141  this->parentSensor->SetActive(true);
142  }
143  else
144  {
145  //ROS_ERROR_NAMED("prosilica", "camera_ new frame %s %s",this->parentSensor_->Name().c_str(),this->frame_name_.c_str());
146 
147  if (this->mode_ == "streaming")
148  {
149  if ((*this->image_connect_count_) > 0)
150  {
151  if (sensor_update_time - this->last_update_time_ >= this->update_period_)
152  {
153  this->PutCameraData(_image, sensor_update_time);
154  this->PublishCameraInfo(sensor_update_time);
155  this->last_update_time_ = sensor_update_time;
156  }
157  }
158  }
159 
160  }
161 }
162 
163 
165 // new prosilica interface.
166 void GazeboRosProsilica::pollCallback(polled_camera::GetPolledImage::Request& req,
167  polled_camera::GetPolledImage::Response& rsp,
168  sensor_msgs::Image& image, sensor_msgs::CameraInfo& info)
169 {
170  if (!this->rosnode_->getParam(this->mode_param_name,this->mode_))
171  this->mode_ = "streaming";
172 
176 
177  if (this->mode_ != "polled")
178  {
179  rsp.success = false;
180  rsp.status_message = "Camera is not in triggered mode";
181  return;
182  }
183 
184  if (req.binning_x > 1 || req.binning_y > 1)
185  {
186  rsp.success = false;
187  rsp.status_message = "Gazebo Prosilica plugin does not support binning";
188  return;
189  }
190 
191  // get region from request
192  if (req.roi.x_offset <= 0 || req.roi.y_offset <= 0 || req.roi.width <= 0 || req.roi.height <= 0)
193  {
194  req.roi.x_offset = 0;
195  req.roi.y_offset = 0;
196  req.roi.width = this->width_;
197  req.roi.height = this->height;
198  }
199  const unsigned char *src = NULL;
200  ROS_ERROR_NAMED("prosilica", "roidebug %d %d %d %d", req.roi.x_offset, req.roi.y_offset, req.roi.width, req.roi.height);
201 
202  // signal sensor to start update
203  (*this->image_connect_count_)++;
204 
205  // wait until an image has been returned
206  while(!src)
207  {
208  {
209  // Get a pointer to image data
210  src = this->parentSensor->Camera()->ImageData(0);
211 
212  if (src)
213  {
214 
215  // fill CameraInfo
216  this->roiCameraInfoMsg = &info;
217  this->roiCameraInfoMsg->header.frame_id = this->frame_name_;
218 
219  common::Time roiLastRenderTime = this->parentSensor_->LastMeasurementTime();
220  this->roiCameraInfoMsg->header.stamp.sec = roiLastRenderTime.sec;
221  this->roiCameraInfoMsg->header.stamp.nsec = roiLastRenderTime.nsec;
222 
223  this->roiCameraInfoMsg->width = req.roi.width; //this->parentSensor->ImageWidth() ;
224  this->roiCameraInfoMsg->height = req.roi.height; //this->parentSensor->ImageHeight();
225  // distortion
226 #if ROS_VERSION_MINIMUM(1, 3, 0)
227  this->roiCameraInfoMsg->distortion_model = "plumb_bob";
228  this->roiCameraInfoMsg->D.resize(5);
229 #endif
230  this->roiCameraInfoMsg->D[0] = this->distortion_k1_;
231  this->roiCameraInfoMsg->D[1] = this->distortion_k2_;
232  this->roiCameraInfoMsg->D[2] = this->distortion_k3_;
233  this->roiCameraInfoMsg->D[3] = this->distortion_t1_;
234  this->roiCameraInfoMsg->D[4] = this->distortion_t2_;
235  // original camera matrix
236  this->roiCameraInfoMsg->K[0] = this->focal_length_;
237  this->roiCameraInfoMsg->K[1] = 0.0;
238  this->roiCameraInfoMsg->K[2] = this->cx_ - req.roi.x_offset;
239  this->roiCameraInfoMsg->K[3] = 0.0;
240  this->roiCameraInfoMsg->K[4] = this->focal_length_;
241  this->roiCameraInfoMsg->K[5] = this->cy_ - req.roi.y_offset;
242  this->roiCameraInfoMsg->K[6] = 0.0;
243  this->roiCameraInfoMsg->K[7] = 0.0;
244  this->roiCameraInfoMsg->K[8] = 1.0;
245  // rectification
246  this->roiCameraInfoMsg->R[0] = 1.0;
247  this->roiCameraInfoMsg->R[1] = 0.0;
248  this->roiCameraInfoMsg->R[2] = 0.0;
249  this->roiCameraInfoMsg->R[3] = 0.0;
250  this->roiCameraInfoMsg->R[4] = 1.0;
251  this->roiCameraInfoMsg->R[5] = 0.0;
252  this->roiCameraInfoMsg->R[6] = 0.0;
253  this->roiCameraInfoMsg->R[7] = 0.0;
254  this->roiCameraInfoMsg->R[8] = 1.0;
255  // camera projection matrix (same as camera matrix due to lack of distortion/rectification) (is this generated?)
256  this->roiCameraInfoMsg->P[0] = this->focal_length_;
257  this->roiCameraInfoMsg->P[1] = 0.0;
258  this->roiCameraInfoMsg->P[2] = this->cx_ - req.roi.x_offset;
259  this->roiCameraInfoMsg->P[3] = -this->focal_length_ * this->hack_baseline_;
260  this->roiCameraInfoMsg->P[4] = 0.0;
261  this->roiCameraInfoMsg->P[5] = this->focal_length_;
262  this->roiCameraInfoMsg->P[6] = this->cy_ - req.roi.y_offset;
263  this->roiCameraInfoMsg->P[7] = 0.0;
264  this->roiCameraInfoMsg->P[8] = 0.0;
265  this->roiCameraInfoMsg->P[9] = 0.0;
266  this->roiCameraInfoMsg->P[10] = 1.0;
267  this->roiCameraInfoMsg->P[11] = 0.0;
269 
270  // copy data into image_msg_, then convert to roiImageMsg(image)
271  this->image_msg_.header.frame_id = this->frame_name_;
272 
273  common::Time lastRenderTime = this->parentSensor_->LastMeasurementTime();
274  this->image_msg_.header.stamp.sec = lastRenderTime.sec;
275  this->image_msg_.header.stamp.nsec = lastRenderTime.nsec;
276 
277  //unsigned char dst[this->width_*this->height];
278 
280 
281  // copy from src to image_msg_
282  fillImage(this->image_msg_,
283  this->type_,
284  this->height_,
285  this->width_,
286  this->skip_*this->width_,
287  (void*)src );
288 
290 
291  this->image_pub_.publish(this->image_msg_);
292 
293  {
294  // copy data into ROI image
295  this->roiImageMsg = &image;
296  this->roiImageMsg->header.frame_id = this->frame_name_;
297  common::Time roiLastRenderTime = this->parentSensor_->LastMeasurementTime();
298  this->roiImageMsg->header.stamp.sec = roiLastRenderTime.sec;
299  this->roiImageMsg->header.stamp.nsec = roiLastRenderTime.nsec;
300 
301  // convert image_msg_ to a CvImage using cv_bridge
303  img_bridge_ = cv_bridge::toCvCopy(this->image_msg_);
304 
305  // for debug
306  //cvNamedWindow("showme",CV_WINDOW_AUTOSIZE);
307  //cvSetMouseCallback("showme", &GazeboRosProsilica::mouse_cb, this);
308  //cvStartWindowThread();
309  //cvShowImage("showme",img_bridge_.toIpl());
310 
311  // crop image to roi
312  cv::Mat roi(img_bridge_->image,
313  cv::Rect(req.roi.x_offset, req.roi.y_offset,
314  req.roi.width, req.roi.height));
315  img_bridge_->image = roi;
316 
317  // copy roi'd image into roiImageMsg
318  img_bridge_->toImageMsg(*this->roiImageMsg);
319  }
320  }
321  }
322  std::this_thread::sleep_for(std::chrono::microseconds(100000));
323  }
324  (*this->image_connect_count_)--;
325  rsp.success = true;
326  return;
327 }
328 
329 
330 /*
331 void GazeboRosProsilica::OnStats( const boost::shared_ptr<msgs::WorldStatistics const> &_msg)
332 {
333  this->simTime = msgs::Convert( _msg->sim_time() );
334 
335  ignition::math::Pose3d pose;
336  pose.Pos().X() = 0.5*sin(0.01*this->simTime.Double());
337  gzdbg << "plugin simTime [" << this->simTime.Double() << "] update pose [" << pose.Pos().X() << "]\n";
338 }
339 */
340 
341 // Register this plugin with the simulator
342 GZ_REGISTER_SENSOR_PLUGIN(GazeboRosProsilica)
343 
344 
345 }
polled_camera::PublicationServer poll_srv_
image_transport
#define ROS_INFO_NAMED(name,...)
sensor_msgs::CameraInfo * roiCameraInfoMsg
event::ConnectionPtr load_connection_
image_transport::Publisher image_pub_
void Load(sensors::SensorPtr _parent, sdf::ElementPtr _sdf, const std::string &_camera_name_suffix="")
Load the plugin.
sensor_msgs::Image * roiImageMsg
ros message
boost::shared_ptr< int > image_connect_count_
Keep track of number of image connections.
virtual ~GazeboRosProsilica()
Destructor.
sensor_msgs::Image image_msg_
ROS image message.
#define ROS_DEBUG_NAMED(name,...)
ros::Publisher camera_info_pub_
camera info
PublicationServer advertise(ros::NodeHandle &nh, const std::string &service, const PublicationServer::DriverCallback &cb, const ros::VoidPtr &tracked_object=ros::VoidPtr())
void publish(const boost::shared_ptr< M > &message) const
void pollCallback(polled_camera::GetPolledImage::Request &req, polled_camera::GetPolledImage::Response &rsp, sensor_msgs::Image &image, sensor_msgs::CameraInfo &info)
event::ConnectionPtr OnLoad(const boost::function< void()> &)
bool getParam(const std::string &key, std::string &s) const
virtual void OnNewImageFrame(const unsigned char *_image, unsigned int _width, unsigned int _height, unsigned int _depth, const std::string &_format)
Update the controller.
CvImagePtr toCvCopy(const sensor_msgs::ImageConstPtr &source, const std::string &encoding=std::string())
std::string frame_name_
ROS frame transform name to use in the image message header. This should typically match the link nam...
void publish(const sensor_msgs::Image &message) const
bool searchParam(const std::string &key, std::string &result) const
void PutCameraData(const unsigned char *_src)
Put camera data to the ROS topic.
ros::NodeHandle * rosnode_
A pointer to the ROS node. A node will be instantiated if it does not exist.
#define ROS_ERROR_NAMED(name,...)
void Load(sensors::SensorPtr _parent, sdf::ElementPtr _sdf)
Load the controller.
std::string type_
size of image buffer
std::string pollServiceName
ROS image topic name.


gazebo_plugins
Author(s): John Hsu
autogenerated on Wed Aug 24 2022 02:47:52