leica_plugin.cpp
Go to the documentation of this file.
1 
18 /*
19  Desc: based on GazeboRosGpuLaser plugin for simulating ray sensors in Gazebo
20  Author: Mihai Emanuel Dolha
21  Date: 29 March 2012
22 */
23 
24 #include <algorithm>
25 #include <string>
26 #include <assert.h>
27 
28 #include <sdf/sdf.hh>
29 
30 #include <gazebo/physics/World.hh>
31 #include <gazebo/physics/HingeJoint.hh>
32 #include <gazebo/sensors/Sensor.hh>
33 #include <gazebo/sensors/SensorManager.hh>
34 #include <gazebo/common/Exception.hh>
35 #include <gazebo/sensors/GpuRaySensor.hh>
36 #include <gazebo/sensors/SensorTypes.hh>
37 #include <gazebo/transport/transport.hh>
38 #include <gazebo/rendering/rendering.hh>
39 
40 #include <tf/tf.h>
41 #include <tf/transform_listener.h>
42 
43 #include "leica_plugin.h"
44 #include <gazebo_plugins/gazebo_ros_utils.h>
45 #include <std_msgs/String.h>
46 
47 #include <iostream>
48 #include <math.h>
49 #include <chrono>
50 
51 namespace gazebo
52 {
53  // Register this plugin so that the simulator will be able to use it
54  GZ_REGISTER_SENSOR_PLUGIN(LeicaPlugin)
55 
57  {
58  // Seed for the Gaussian noise generator
59  this->seed_ = 0;
60  }
61 
63  {
64  // End the node
65  ROS_DEBUG_STREAM("Shutting down GPU Laser");
66  this->nh_->shutdown();
67  delete this->nh_;
68  ROS_DEBUG_STREAM("Unloaded");
69  }
70 
71  void LeicaPlugin::Load(sensors::SensorPtr _parent, sdf::ElementPtr _sdf)
72  {
73  // Load the plugin
74  GpuRayPlugin::Load(_parent, this->sdf_);
75 
76  // Extract some information
77  std::string worldName = _parent->WorldName();
78 
79  // Save some pointers
80  this->world_ = physics::get_world(worldName);
81  this->sdf_ = _sdf;
82 
83  // Initialize some variables
84  start_laser_ = false;
85  this->laser_connect_count_ = 0;
86 
87  // Get the pointer to the laser
88  GAZEBO_SENSORS_USING_DYNAMIC_POINTER_CAST;
89  this->parent_ray_sensor_ = dynamic_pointer_cast<sensors::GpuRaySensor>(_parent);
90 
91  // Makes some comprobations
92  if (!this->parent_ray_sensor_)
93  gzthrow("LeicaPlugin controller requires a Ray Sensor as its parent");
94 
95  this->namespace_ = GetRobotNamespace(_parent, _sdf, "Laser");
96 
97  if (!this->sdf_->HasElement("frameName"))
98  {
99  ROS_INFO("LeicaPlugin missing <frameName>, defaults to /world");
100  this->frame_name_ = "/world";
101  }
102  else
103  this->frame_name_ = this->sdf_->Get<std::string>("frameName");
104 
105  if (!this->sdf_->HasElement("topicName"))
106  {
107  ROS_INFO("LeicaPlugin missing <topicName>, defaults to /world");
108  this->topic_name_ = "/world";
109  }
110  else
111  this->topic_name_ = this->sdf_->Get<std::string>("topicName");
112 
113  if (!ros::isInitialized())
114  {
115  ROS_FATAL_STREAM("A ROS node for Gazebo has not been initialized, unable to load plugin. "
116  << "Load the Gazebo system plugin 'leica_plugin.so')");
117  return;
118  }
119 
120  // Calls gazeboLoaderThread func
121  ROS_INFO("Starting LeicaPlugin (ns = %s)", this->namespace_.c_str());
122  this->deferred_load_thread_ = boost::thread(boost::bind(&LeicaPlugin::gazeboLoaderThread, this));
123 
124  // Subscribe to the topic that configures the scan window
126  ros::SubscribeOptions::create<sensor_msgs::RegionOfInterest>("/c5/simulator/window",
127  1,
128  boost::bind(&LeicaPlugin::configureScanWindow, this, _1),
129  ros::VoidPtr(),
130  &this->cb_queue_);
131  this->sub_ = this->nh_->subscribe(so);
132 
133  // Spin up the queue helper thread.
134  this->queue_helper_thread_ = std::thread(boost::bind(&LeicaPlugin::callbacksQueueHelperThread, this));
135  }
136 
138  {
139  // Initialise the node
140  this->gazebo_node_ = gazebo::transport::NodePtr(new gazebo::transport::Node());
141  this->gazebo_node_->Init(this->world_name_);
142  this->pmq_.startServiceThread();
143  this->nh_ = new ros::NodeHandle(this->namespace_);
144 
145  // Name the tf
146  this->tf_prefix_ = tf::getPrefixParam(*this->nh_);
147  if (this->tf_prefix_.empty())
148  {
149  this->tf_prefix_ = this->namespace_;
150  boost::trim_right_if(this->tf_prefix_, boost::is_any_of("/"));
151  }
152  ROS_INFO("Leica Plugin ns:%s <tf_prefix_>, set to \"%s\"", this->namespace_.c_str(), this->tf_prefix_.c_str());
153 
154  // resolve tf prefix
155  this->frame_name_ = tf::resolve(this->tf_prefix_, this->frame_name_);
156 
157  // Prepare the publishers needed by the manager to know when a new laser instance has been created
158  if (this->topic_name_ != "")
159  {
160  ros::AdvertiseOptions ao = ros::AdvertiseOptions::create<sensor_msgs::LaserScan>(this->topic_name_,
161  1,
162  boost::bind(&LeicaPlugin::connectToLaser, this),
163  boost::bind(&LeicaPlugin::disconnectFromLaser, this),
164  ros::VoidPtr(),
165  NULL);
166 
167  this->pub_ = this->nh_->advertise(ao);
168  this->pub_queue_ = this->pmq_.addPub<sensor_msgs::LaserScan>();
169  }
170 
171  // sensor generation off by default
172  this->parent_ray_sensor_->SetActive(false);
173 
174  ROS_INFO_STREAM("gazeboLoaderThread function completed");
175  }
176 
178  {
179  // Wait until the configuration of the scan window has been completed
180  std::unique_lock<std::mutex> lk(mutex_);
181  condition_variable_.wait(lk, [&] { return start_laser_; });
182 
183  this->laser_connect_count_++;
184 
185  ROS_INFO("LaserConnect: laser connect count: %d", laser_connect_count_);
186  if (this->laser_connect_count_ == 1)
187  this->laser_scan_sub_ = this->gazebo_node_->Subscribe(this->parent_ray_sensor_->Topic(),
189  lk.unlock();
190  }
191 
193  {
194  this->laser_connect_count_--;
195  if (this->laser_connect_count_ == 0)
196  this->laser_scan_sub_.reset();
197  }
198 
199  void LeicaPlugin::gazeboMsgToROSMsg(ConstLaserScanStampedPtr &_msg)
200  {
201  sensor_msgs::LaserScan laser_msg;
202  laser_msg.header.stamp = ros::Time(_msg->time().sec(), _msg->time().nsec());
203  laser_msg.header.frame_id = this->frame_name_;
204  laser_msg.angle_min = _msg->scan().angle_min();
205  laser_msg.angle_max = _msg->scan().angle_max();
206  laser_msg.angle_increment = _msg->scan().angle_step();
207  laser_msg.time_increment = 0;
208  laser_msg.scan_time = 0;
209  laser_msg.range_min = _msg->scan().range_min();
210  laser_msg.range_max = _msg->scan().range_max();
211  laser_msg.ranges.resize(_msg->scan().ranges_size());
212  std::copy(_msg->scan().ranges().begin(), _msg->scan().ranges().end(), laser_msg.ranges.begin());
213  laser_msg.intensities.resize(_msg->scan().intensities_size());
214  std::copy(_msg->scan().intensities().begin(), _msg->scan().intensities().end(), laser_msg.intensities.begin());
215  this->pub_queue_->push(laser_msg, this->pub_);
216  }
217 
218  void LeicaPlugin::configureScanWindow(const sensor_msgs::RegionOfInterestConstPtr &_msg)
219  {
220  // Enable gazebo to ROS message converter
221  std::lock_guard<std::mutex> lk(mutex_);
222 
223  // Get the pointer to the camera that the laser needs to function properly
224  rendering::GpuLaserPtr cam = parent_ray_sensor_->LaserCamera();
225 
226  double MIN_ANGLE_LIMIT = -1.04;
227  // Get angle values. [mm to m] for width and height
228  ignition::math::Angle half_angle = (parent_ray_sensor_->AngleMax() + parent_ray_sensor_->AngleMin()) / 2.0;
229  ignition::math::Angle angle_min = atan(_msg->y_offset - (_msg->height)*1e-3 / 2.0);
230  ignition::math::Angle angle_max = atan(_msg->y_offset + (_msg->height)*1e-3 / 2.0);
231  if(angle_min.Radian() < MIN_ANGLE_LIMIT)
232  angle_min = MIN_ANGLE_LIMIT;
233  if((angle_max - angle_min) < ignition::math::Angle::HalfPi)
234  angle_max = angle_min + ignition::math::Angle::HalfPi;
235  // Apply angles to ray
236  parent_ray_sensor_->SetAngleMax(angle_max.Radian());
237  parent_ray_sensor_->SetAngleMin(angle_min.Radian());
238 
239  // Apply angles to camera
240  ignition::math::Angle update_half_angle = (parent_ray_sensor_->AngleMax()+parent_ray_sensor_->AngleMin())/2.0;
241  ignition::math::Angle cam_angle = half_angle - update_half_angle;
242  cam->Roll(ignition::math::Angle(cam_angle), rendering::ReferenceFrame::RF_WORLD);
243  cam->SetHFOV(angle_max - angle_min);
244 
245  // Enable gazebo to ROS message converter
246  start_laser_ = true;
247  condition_variable_.notify_one();
248  }
249 
251  {
252  // invoque all callbacks available
253  static const double timeout = 0.01;
254  while (this->nh_->ok())
255  {
256  this->cb_queue_.callAvailable(ros::WallDuration(timeout));
257  }
258  }
259 } // namespace gazebo
ros::Subscriber sub_
Subscriber for the laser sensor.
Definition: leica_plugin.h:212
ros::CallbackQueue cb_queue_
Queue for the callback functions.
Definition: leica_plugin.h:218
void gazeboMsgToROSMsg(ConstLaserScanStampedPtr &_msg)
Tailor the gazebo message to the ROS format.
std::string getPrefixParam(ros::NodeHandle &nh)
physics::WorldPtr world_
Pointer to the virtual world where the simulation takes place.
Definition: leica_plugin.h:146
void disconnectFromLaser()
Unregister the laser.
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
std::string namespace_
The namespace of the Leica station.
Definition: leica_plugin.h:170
gazebo::transport::NodePtr gazebo_node_
Node for gazebo.
Definition: leica_plugin.h:224
ROSCPP_DECL bool isInitialized()
void gazeboLoaderThread()
Load the sensor controller.
PubQueue< sensor_msgs::LaserScan >::Ptr pub_queue_
Publisher queue.
Definition: leica_plugin.h:236
std::string world_name_
Stores the name of the virtual world where the simulation takes place.
Definition: leica_plugin.h:140
sdf::ElementPtr sdf_
Pointer to the *.sdf file.
Definition: leica_plugin.h:248
std::string frame_name_
Stores the name of the root of the reference system tree.
Definition: leica_plugin.h:158
std::string resolve(const std::string &prefix, const std::string &frame_name)
void Load(sensors::SensorPtr _parent, sdf::ElementPtr _sdf)
Load the plugin controller.
void connectToLaser()
Register de new laser and connect to its topic.
INLINE Rall1d< T, V, S > atan(const Rall1d< T, V, S > &x)
std::mutex mutex_
Mutex used so that no laser sensor data is published until the configuration of the scan window has b...
Definition: leica_plugin.h:176
#define ROS_FATAL_STREAM(args)
int laser_connect_count_
A counter to register the number of laser sensors in use.
Definition: leica_plugin.h:134
boost::thread deferred_load_thread_
Object for the sensor controller thread.
Definition: leica_plugin.h:254
#define ROS_INFO(...)
void configureScanWindow(const sensor_msgs::RegionOfInterestConstPtr &_msg)
Configure the scan window from a topic.
void callbacksQueueHelperThread()
Thread that calls all functions in the callback queue when resources are available.
ros::NodeHandle * nh_
Pointer to the ROS node.
Definition: leica_plugin.h:200
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
std::thread queue_helper_thread_
Thread that calls all functions in the callback queue when resources are available.
Definition: leica_plugin.h:188
gazebo::transport::SubscriberPtr laser_scan_sub_
Gazebo part of the laser sensor subscriber.
Definition: leica_plugin.h:230
#define ROS_DEBUG_STREAM(args)
std::string tf_prefix_
tf_prefix_ as the namespace
Definition: leica_plugin.h:164
ros::Publisher pub_
Publisher for the laser sensor.
Definition: leica_plugin.h:206
std::string topic_name_
Saves the name of the topic where the laser scanner publishes what it reads.
Definition: leica_plugin.h:152
#define ROS_INFO_STREAM(args)
std::condition_variable condition_variable_
Variable used to wait until the configuration of the scan window has been completed.
Definition: leica_plugin.h:182
bool start_laser_
Flag to start the laser after the scan window has been set.
Definition: leica_plugin.h:128
bool ok() const
PubMultiQueue pmq_
Object for the ROS queue system.
Definition: leica_plugin.h:242
boost::shared_ptr< void > VoidPtr
sensors::GpuRaySensorPtr parent_ray_sensor_
Pointer to the laser sensor object.
Definition: leica_plugin.h:194
~LeicaPlugin()
Destroy the Gazebo ROS Laser object.


leica_gazebo_simulation
Author(s): Ines Lara Sicilia
autogenerated on Mon Feb 22 2021 03:50:48