simulation_laser.cpp
Go to the documentation of this file.
1 
7 #include <ros/ros.h>
8 #include <ros/package.h>
9 #include <geometry_msgs/TransformStamped.h>
10 #include <nav_msgs/MapMetaData.h>
11 #include <sensor_msgs/LaserScan.h>
12 #include <tf/transform_listener.h>
13 #include <string>
14 #include <stdexcept>
15 #include <sensor_msgs/Range.h>
16 #include <yaml-cpp/yaml.h>
17 #include <dynamic_reconfigure/server.h>
18 #include <pses_simulation/RangeSensorConfig.h>
20 
26 namespace YAML
27 {
31 template <> struct convert<geometry_msgs::Pose>
32 {
38  static Node encode(const geometry_msgs::Pose& rhs)
39  {
40  Node node;
41  node.push_back(rhs.position.x);
42  node.push_back(rhs.position.y);
43  node.push_back(rhs.position.z);
44  return node;
45  }
53  static bool decode(const Node& node, geometry_msgs::Pose& rhs)
54  {
55  if (!node.IsSequence() || node.size() != 3)
56  {
57  return false;
58  }
59 
60  rhs.position.x = node[0].as<double>();
61  rhs.position.y = node[1].as<double>();
62  rhs.position.z = node[2].as<double>();
63  return true;
64  }
65 };
66 }
67 
73 namespace laserscan
74 {
79 typedef std::shared_ptr<sensor_msgs::LaserScan> scan_msg_ptr;
84 typedef std::shared_ptr<geometry_msgs::Pose> pose_msg_ptr;
85 
92 cv::Point setGridPosition(geometry_msgs::Pose& laser,
93  nav_msgs::MapMetaData& mapInfo)
94 {
95  unsigned int grid_x =
96  (unsigned int)((laser.position.x - mapInfo.origin.position.x) /
97  mapInfo.resolution);
98  unsigned int grid_y =
99  (unsigned int)((-laser.position.y - mapInfo.origin.position.y) /
100  mapInfo.resolution);
101  return cv::Point(grid_x, grid_y);
102 }
112 void getPositionInfo(const std::string& base_frame,
113  const std::string& target_frame,
114  const tf::TransformListener& listener,
115  geometry_msgs::Pose* position, std::vector<double>* rpy)
116 {
117  bool transformReady = false;
118  tf::StampedTransform stf;
119  tf::Stamped<tf::Pose> tmp;
120  geometry_msgs::PoseStamped tmp2;
121  tf::Quaternion q;
122 
123  try
124  {
125  transformReady = listener.waitForTransform(
126  base_frame, target_frame, ros::Time(0), ros::Duration(0.01));
127  }
128  catch (tf::TransformException ex)
129  {
130  ROS_ERROR("%s", ex.what());
131  }
132 
133  if (transformReady)
134  {
135  try
136  {
137  listener.lookupTransform(base_frame, target_frame, ros::Time(0), stf);
138  }
139  catch (tf::TransformException ex)
140  {
141  ROS_ERROR("%s", ex.what());
142  }
143  tmp = tf::Stamped<tf::Pose>(stf, stf.stamp_, base_frame);
144  tf::poseStampedTFToMsg(tmp, tmp2);
145  *position = tmp2.pose;
146 
147  try
148  {
149  tf::quaternionMsgToTF(tmp2.pose.orientation, q);
150  tf::Matrix3x3(q).getRPY((*rpy)[0], (*rpy)[1], (*rpy)[2]);
151  }
152  catch (std::exception ex)
153  {
154  ROS_ERROR("%s", ex.what());
155  }
156  }
157 }
166 void configCallback(pses_simulation::RangeSensorConfig& config, uint32_t level,
167  rs::RangeSensor* sensor,
168  pses_simulation::RangeSensorConfig* dynConfig)
169 {
170  sensor->setConfig(config);
171  *dynConfig = config;
172  ROS_DEBUG("Config was set");
173 }
174 
175 static const double DEFAULT_LOOP_RATE =
176  30.0;
177 static const std::string DEFAULT_LASER_SCAN_TOPIC =
178  "scan";
179 static const std::string
181  ros::package::getPath("pses_simulation") + "/data/map/map.pgm";
182 static const std::string
185  ros::package::getPath("pses_simulation") + "/data/map/map.yaml";
186 static const std::string DEFAULT_LASERSCAN_FRAME_ID =
187  "scan";
188 static const std::string DEFAULT_MAP_FRAME_ID =
189  "map";
196 void fetchLoopRate(ros::NodeHandle* nh, double& loopRate)
197 {
198  if (nh->hasParam("laser_sim/loop_rate_laserscan"))
199  {
200  nh->getParam("laser_sim/loop_rate_laserscan", loopRate);
201  }
202  else
203  {
204  loopRate = DEFAULT_LOOP_RATE;
205  }
206 }
213 void fetchLaserScanTopic(ros::NodeHandle* nh, std::string& laserScanTopic)
214 {
215  if (nh->hasParam("laser_sim/laser_scan_topic"))
216  {
217  nh->getParam("laser_sim/laser_scan_topic", laserScanTopic);
218  }
219  else
220  {
221  laserScanTopic = DEFAULT_LASER_SCAN_TOPIC;
222  }
223 }
229 void fetchMapLocation(ros::NodeHandle* nh, std::string& mapLocation)
230 {
231  if (nh->hasParam("laser_sim/map_location"))
232  {
233  nh->getParam("laser_sim/map_location", mapLocation);
234  }
235  else
236  {
237  mapLocation = DEFAULT_MAP_LOCATION;
238  }
239 }
245 void fetchMapMetadataLocation(ros::NodeHandle* nh,
246  std::string& mapMetadataLocation)
247 {
248  if (nh->hasParam("laser_sim/map_metadata_location"))
249  {
250  nh->getParam("laser_sim/map_metadata_location", mapMetadataLocation);
251  }
252  else
253  {
254  mapMetadataLocation = DEFAULT_MAP_METADATA_LOCATION;
255  }
256 }
262 void fetchLaserscanFrameID(ros::NodeHandle* nh, std::string& laserscanFrameID)
263 {
264  if (nh->hasParam("laser_sim/laserscan_frame_id"))
265  {
266  nh->getParam("laser_sim/laserscan_frame_id", laserscanFrameID);
267  }
268  else
269  {
270  laserscanFrameID = DEFAULT_LASERSCAN_FRAME_ID;
271  }
272 }
278 void fetchMapFrameID(ros::NodeHandle* nh, std::string& mapFrameID)
279 {
280  if (nh->hasParam("laser_sim/map_frame_id"))
281  {
282  nh->getParam("laser_sim/map_frame_id", mapFrameID);
283  }
284  else
285  {
286  mapFrameID = DEFAULT_MAP_FRAME_ID;
287  }
288 }
289 }
290 
291 using namespace laserscan;
292 
296 int main(int argc, char** argv)
297 {
298 
299  ros::init(argc, argv, "simulation_laserscan");
300  ros::NodeHandle nh;
301  double loopRate;
302  std::string laserScanTopic, mapLocation, mapMetadataLocation,
303  laserscanFrameID, mapFrameID;
304 
305  fetchLoopRate(&nh, loopRate);
306  fetchLaserScanTopic(&nh, laserScanTopic);
307  fetchMapLocation(&nh, mapLocation);
308  fetchMapMetadataLocation(&nh, mapMetadataLocation);
309  fetchLaserscanFrameID(&nh, laserscanFrameID);
310  fetchMapFrameID(&nh, mapFrameID);
311 
312  // create dynamic reconfigure object
313  dynamic_reconfigure::Server<pses_simulation::RangeSensorConfig> server;
314  dynamic_reconfigure::Server<pses_simulation::RangeSensorConfig>::CallbackType
315  f;
316  pses_simulation::RangeSensorConfig dynConfig;
317 
318  ros::Publisher scanPub =
319  nh.advertise<sensor_msgs::LaserScan>(laserScanTopic, 10);
320 
321  sensor_msgs::LaserScan scan;
322 
323  // get "god" map meta info
324  nav_msgs::MapMetaData mapInfo;
325  YAML::Node imgMetaInfo = YAML::LoadFile(mapMetadataLocation);
326  double resolution = imgMetaInfo["resolution"].as<double>();
327  geometry_msgs::Pose origin = imgMetaInfo["origin"].as<geometry_msgs::Pose>();
328  mapInfo.origin = origin;
329  mapInfo.resolution = resolution;
330 
331  // get "god" map
332  cv::Mat map = cv::imread(mapLocation, 1);
333  cv::cvtColor(map, map, CV_RGB2GRAY);
334 
335  // create sensor object and link with config object
336  rs::RangeSensor rs_laser(rs::laser);
337  rs_laser.setMap(map);
338  rs_laser.setMapMetaData(mapInfo);
339 
340  f = boost::bind(&configCallback, _1, _2, &rs_laser, &dynConfig);
341  server.setCallback(f);
342 
343  // variables needed for transformations
344  tf::TransformListener listener;
345  geometry_msgs::Pose position;
346  std::vector<double> rpy(3, 0.0);
347  cv::Point gridPose;
348 
349  ros::Time currentTime = ros::Time::now();
350 
351  // Loop starts here:
352  ros::Rate loop_rate(loopRate);
353  while (ros::ok())
354  {
355  currentTime = ros::Time::now();
356  scan.header.stamp = currentTime;
357  scan.header.frame_id = laserscanFrameID;
358  scan.angle_increment = rs::degToRad(dynConfig.laser_angular_resolution);
359  scan.range_min = dynConfig.laser_min_sensor_distance;
360  scan.range_max = dynConfig.laser_max_sensor_distance;
361  scan.angle_min = rs::degToRad(
362  rs::correctYawAngle(0, -dynConfig.laser_field_of_view / 2));
363  scan.angle_max =
364  rs::degToRad(rs::correctYawAngle(0, dynConfig.laser_field_of_view / 2));
365 
366  // get laser range infos
367  getPositionInfo(mapFrameID, laserscanFrameID, listener, &position, &rpy);
368  gridPose = setGridPosition(position, mapInfo);
369  scan.ranges = *rs_laser.getLaserScan(gridPose, rs::radToDeg(rpy[2]));
370 
371  // publish sensor msgs
372  scanPub.publish(scan);
373  ros::spinOnce();
374  loop_rate.sleep();
375  }
376 
377  ros::spin();
378 }
The rs::RangeSensor class simulates different range finder sensors based on the given rs::SensorType ...
int main(int argc, char **argv)
Main function of this ros node.
cv::Point setGridPosition(geometry_msgs::Pose &laser, nav_msgs::MapMetaData &mapInfo)
Calculate the occupancy grid postion of a given pose.
Header file for the rs::RangeSensor class.
static const std::string DEFAULT_MAP_FRAME_ID
void fetchMapMetadataLocation(ros::NodeHandle *nh, std::string &mapMetadataLocation)
Get map meta data location launch parameter.
void fetchMapLocation(ros::NodeHandle *nh, std::string &mapLocation)
Get map location launch parameter.
static const std::string DEFAULT_MAP_METADATA_LOCATION
static Node encode(const geometry_msgs::Pose &rhs)
Encodes a pose message to YAML::Node containing x,y,z variables.
void fetchMapFrameID(ros::NodeHandle *nh, std::string &mapFrameID)
Get map frame id launch parameter.
static const std::string DEFAULT_MAP_LOCATION
void fetchLoopRate(ros::NodeHandle *nh, double &loopRate)
Get loop rate launch parameter.
static bool decode(const Node &node, geometry_msgs::Pose &rhs)
Decodes a YAML::Node containing x,y,z variables to a pose message.
This namespace groups all typedefs, utility functions and parameter getter used in the simulation_las...
void fetchLaserscanFrameID(ros::NodeHandle *nh, std::string &laserscanFrameID)
Get laser scan frame id launch parameter.
void getPositionInfo(const std::string &base_frame, const std::string &target_frame, const tf::TransformListener &listener, geometry_msgs::Pose *position, std::vector< double > *rpy)
Get the current postion of a sensor from the tf transformation service.
std::shared_ptr< geometry_msgs::Pose > pose_msg_ptr
shortcut for a pointer to a pose message
double radToDeg(double angle)
Conversion from radiants to degrees.
Definition: RangeSensor.cpp:35
static const std::string DEFAULT_LASER_SCAN_TOPIC
This namespace contains special functionality to parse from .yaml files or write to ...
std::shared_ptr< sensor_msgs::LaserScan > scan_msg_ptr
shortcut for a pointer to a laser scan message
void configCallback(pses_simulation::RangeSensorConfig &config, uint32_t level, rs::RangeSensor *sensor, pses_simulation::RangeSensorConfig *dynConfig)
Sets the RangeSensorConfig object of this sensor simulation.
static const std::string DEFAULT_LASERSCAN_FRAME_ID
double degToRad(double angle)
Conversion from degrees to radiants.
Definition: RangeSensor.cpp:33
double correctYawAngle(const double theta, const double increment)
Calculate a correct euler angle after incrementing/decrementing.
Definition: RangeSensor.cpp:12
static const double DEFAULT_LOOP_RATE
void fetchLaserScanTopic(ros::NodeHandle *nh, std::string &laserScanTopic)
Get laser scan topic launch parameter.


pses_simulation
Author(s): Sebastian Ehmes
autogenerated on Wed Dec 13 2017 19:37:54