11#include " realsense_gazebo_plugin/gazebo_ros_realsense.h"
22#include < sensor_msgs/fill_image.h>
3+ #include < sensor_msgs/point_cloud2_iterator.h>
34
45namespace {
56std::string extractCameraName (const std::string &name);
@@ -47,6 +48,11 @@ void GazeboRosRealsense::Load(physics::ModelPtr _model, sdf::ElementPtr _sdf) {
4748 cameraParamsMap_[IRED2_CAMERA_NAME].topic_name , 2 );
4849 this ->depth_pub_ = this ->itnode_ ->advertiseCamera (
4950 cameraParamsMap_[DEPTH_CAMERA_NAME].topic_name , 2 );
51+ if (pointCloud_)
52+ {
53+ this ->pointcloud_pub_ =
54+ this ->rosnode_ ->advertise <sensor_msgs::PointCloud2>(pointCloudTopic_, 2 , false );
55+ }
5056}
5157
5258void GazeboRosRealsense::OnNewFrame (const rendering::CameraPtr cam,
@@ -93,6 +99,99 @@ void GazeboRosRealsense::OnNewFrame(const rendering::CameraPtr cam,
9399 image_pub->publish (this ->image_msg_ , camera_info_msg);
94100}
95101
102+ // Referenced from gazebo_plugins
103+ // https://github.com/ros-simulation/gazebo_ros_pkgs/blob/kinetic-devel/gazebo_plugins/src/gazebo_ros_openni_kinect.cpp#L302
104+ // Fill depth information
105+ bool GazeboRosRealsense::FillPointCloudHelper (sensor_msgs::PointCloud2 &point_cloud_msg,
106+ uint32_t rows_arg, uint32_t cols_arg,
107+ uint32_t step_arg, void *data_arg)
108+ {
109+ sensor_msgs::PointCloud2Modifier pcd_modifier (point_cloud_msg);
110+ pcd_modifier.setPointCloud2FieldsByString (2 , " xyz" , " rgb" );
111+ // convert to flat array shape, we need to reconvert later
112+ pcd_modifier.resize (rows_arg * cols_arg);
113+ point_cloud_msg.is_dense = true ;
114+
115+ sensor_msgs::PointCloud2Iterator<float > iter_x (pointcloud_msg_, " x" );
116+ sensor_msgs::PointCloud2Iterator<float > iter_y (pointcloud_msg_, " y" );
117+ sensor_msgs::PointCloud2Iterator<float > iter_z (pointcloud_msg_, " z" );
118+ sensor_msgs::PointCloud2Iterator<uint8_t > iter_rgb (pointcloud_msg_, " rgb" );
119+
120+ float *toCopyFrom = (float *)data_arg;
121+ int index = 0 ;
122+
123+ double hfov = this ->depthCam ->HFOV ().Radian ();
124+ double fl = ((double )this ->depthCam ->ImageWidth ()) / (2.0 * tan (hfov / 2.0 ));
125+
126+ // convert depth to point cloud
127+ for (uint32_t j = 0 ; j < rows_arg; j++)
128+ {
129+ double pAngle;
130+ if (rows_arg > 1 )
131+ pAngle = atan2 ((double )j - 0.5 * (double )(rows_arg - 1 ), fl);
132+ else
133+ pAngle = 0.0 ;
134+
135+ for (uint32_t i = 0 ; i < cols_arg; i++, ++iter_x, ++iter_y, ++iter_z, ++iter_rgb)
136+ {
137+ double yAngle;
138+ if (cols_arg > 1 )
139+ yAngle = atan2 ((double )i - 0.5 * (double )(cols_arg - 1 ), fl);
140+ else
141+ yAngle = 0.0 ;
142+
143+ double depth = toCopyFrom[index++]; // + 0.0*this->myParent->GetNearClip();
144+
145+ if (depth > pointCloudCutOff_ && depth < pointCloudCutOffMax_)
146+ {
147+ // in optical frame
148+ // hardcoded rotation rpy(-M_PI/2, 0, -M_PI/2) is built-in
149+ // to urdf, where the *_optical_frame should have above relative
150+ // rotation from the physical camera *_frame
151+ *iter_x = depth * tan (yAngle);
152+ *iter_y = depth * tan (pAngle);
153+ *iter_z = depth;
154+ }
155+ else // point in the unseeable range
156+ {
157+ *iter_x = *iter_y = *iter_z = std::numeric_limits<float >::quiet_NaN ();
158+ point_cloud_msg.is_dense = false ;
159+ }
160+
161+ // put image color data for each point
162+ uint8_t *image_src = (uint8_t *)(&(this ->image_msg_ .data [0 ]));
163+ if (this ->image_msg_ .data .size () == rows_arg * cols_arg * 3 )
164+ {
165+ // color
166+ iter_rgb[0 ] = image_src[i * 3 + j * cols_arg * 3 + 0 ];
167+ iter_rgb[1 ] = image_src[i * 3 + j * cols_arg * 3 + 1 ];
168+ iter_rgb[2 ] = image_src[i * 3 + j * cols_arg * 3 + 2 ];
169+ }
170+ else if (this ->image_msg_ .data .size () == rows_arg * cols_arg)
171+ {
172+ // mono (or bayer? @todo; fix for bayer)
173+ iter_rgb[0 ] = image_src[i + j * cols_arg];
174+ iter_rgb[1 ] = image_src[i + j * cols_arg];
175+ iter_rgb[2 ] = image_src[i + j * cols_arg];
176+ }
177+ else
178+ {
179+ // no image
180+ iter_rgb[0 ] = 0 ;
181+ iter_rgb[1 ] = 0 ;
182+ iter_rgb[2 ] = 0 ;
183+ }
184+ }
185+ }
186+
187+ // reconvert to original height and width after the flat reshape
188+ point_cloud_msg.height = rows_arg;
189+ point_cloud_msg.width = cols_arg;
190+ point_cloud_msg.row_step = point_cloud_msg.point_step * point_cloud_msg.width ;
191+
192+ return true ;
193+ }
194+
96195void GazeboRosRealsense::OnNewDepthFrame () {
97196 // get current time
98197 common::Time current_time = this ->world ->SimTime ();
@@ -118,6 +217,19 @@ void GazeboRosRealsense::OnNewDepthFrame() {
118217 auto depth_info_msg =
119218 cameraInfo (this ->depth_msg_ , this ->depthCam ->HFOV ().Radian ());
120219 this ->depth_pub_ .publish (this ->depth_msg_ , depth_info_msg);
220+
221+ if (pointCloud_ && this ->pointcloud_pub_ .getNumSubscribers () > 0 )
222+ {
223+ this ->pointcloud_msg_ .header = this ->depth_msg_ .header ;
224+ this ->pointcloud_msg_ .width = this ->depthCam ->ImageWidth ();
225+ this ->pointcloud_msg_ .height = this ->depthCam ->ImageHeight ();
226+ this ->pointcloud_msg_ .row_step =
227+ this ->pointcloud_msg_ .point_step * this ->depthCam ->ImageWidth ();
228+ FillPointCloudHelper (this ->pointcloud_msg_ , this ->depthCam ->ImageHeight (),
229+ this ->depthCam ->ImageWidth (), 2 * this ->depthCam ->ImageWidth (),
230+ (void *)this ->depthCam ->DepthData ());
231+ this ->pointcloud_pub_ .publish (this ->pointcloud_msg_ );
232+ }
121233}
122234}
123235
0 commit comments