simulation_us.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 <tf/transform_listener.h>
12 #include <string>
13 #include <vector>
14 #include <sensor_msgs/Range.h>
15 #include <yaml-cpp/yaml.h>
17 #include <dynamic_reconfigure/server.h>
18 #include <pses_simulation/RangeSensorConfig.h>
19 
25 namespace YAML
26 {
30 template <> struct convert<geometry_msgs::Pose>
31 {
37  static Node encode(const geometry_msgs::Pose& rhs)
38  {
39  Node node;
40  node.push_back(rhs.position.x);
41  node.push_back(rhs.position.y);
42  node.push_back(rhs.position.z);
43  return node;
44  }
52  static bool decode(const Node& node, geometry_msgs::Pose& rhs)
53  {
54  if (!node.IsSequence() || node.size() != 3)
55  {
56  return false;
57  }
58 
59  rhs.position.x = node[0].as<double>();
60  rhs.position.y = node[1].as<double>();
61  rhs.position.z = node[2].as<double>();
62  return true;
63  }
64 };
65 }
66 
72 namespace usscan
73 {
78 typedef std::shared_ptr<sensor_msgs::Range> scan_msg_ptr;
83 typedef std::shared_ptr<geometry_msgs::Pose> pose_msg_ptr;
90 cv::Point setGridPosition(geometry_msgs::Pose& sensor,
91  nav_msgs::MapMetaData& mapInfo)
92 {
93  unsigned int grid_x =
94  (unsigned int)((sensor.position.x - mapInfo.origin.position.x) /
95  mapInfo.resolution);
96  unsigned int grid_y =
97  (unsigned int)((-sensor.position.y - mapInfo.origin.position.y) /
98  mapInfo.resolution);
99 
100  return cv::Point(grid_x, grid_y);
101 }
111 void getPositionInfo(const std::string& base_frame,
112  const std::string& target_frame,
113  const tf::TransformListener& listener,
114  geometry_msgs::Pose* position, std::vector<double>* rpy)
115 {
116  bool transformReady = false;
117  tf::StampedTransform stf;
118  tf::Stamped<tf::Pose> tmp;
119  geometry_msgs::PoseStamped tmp2;
120  tf::Quaternion q;
121 
122  try
123  {
124  transformReady = listener.waitForTransform(
125  base_frame, target_frame, ros::Time(0), ros::Duration(0.01));
126  }
127  catch (tf::TransformException ex)
128  {
129  ROS_ERROR("%s", ex.what());
130  }
131 
132  if (transformReady)
133  {
134  try
135  {
136  listener.lookupTransform(base_frame, target_frame, ros::Time(0), stf);
137  }
138  catch (tf::TransformException ex)
139  {
140  ROS_ERROR("%s", ex.what());
141  }
142  tmp = tf::Stamped<tf::Pose>(stf, stf.stamp_, base_frame);
143  tf::poseStampedTFToMsg(tmp, tmp2);
144  *position = tmp2.pose;
145 
146  try
147  {
148  tf::quaternionMsgToTF(tmp2.pose.orientation, q);
149  tf::Matrix3x3(q).getRPY((*rpy)[0], (*rpy)[1], (*rpy)[2]);
150  }
151  catch (std::exception ex)
152  {
153  ROS_ERROR("%s", ex.what());
154  }
155  }
156 }
165 void configCallback(pses_simulation::RangeSensorConfig& config, uint32_t level,
166  rs::RangeSensor* sensor,
167  pses_simulation::RangeSensorConfig* dynConfig)
168 {
169  sensor->setConfig(config);
170  *dynConfig = config;
171  ROS_DEBUG("Config was set");
172 }
173 
174 static const double DEFAULT_LOOP_RATE = 30.0;
175 static const std::string DEFAULT_US_RIGHT_TOPIC = "/uc_bridge/usr";
176 static const std::string DEFAULT_US_FRONT_TOPIC = "/uc_bridge/usf";
177 static const std::string DEFAULT_US_LEFT_TOPIC = "/uc_bridge/usl";
178 static const std::string DEFAULT_MAP_LOCATION =
179  ros::package::getPath("pses_simulation") + "/data/map/map.pgm";
180 static const std::string DEFAULT_MAP_METADATA_LOCATION =
181  ros::package::getPath("pses_simulation") + "/data/map/map.yaml";
183 static const std::string DEFAULT_US_RIGHT_FRAME_ID = "right_sensor";
184 static const std::string DEFAULT_US_FRONT_FRAME_ID = "front_sensor";
185 static const std::string DEFAULT_US_LEFT_FRAME_ID = "left_sensor";
186 static const std::string DEFAULT_MAP_FRAME_ID = "map";
193 void fetchLoopRate(ros::NodeHandle* nh, double& loopRate)
194 {
195  if (nh->hasParam("us_sim/loop_rate_laserscan"))
196  {
197  nh->getParam("us_sim/loop_rate_laserscan", loopRate);
198  }
199  else
200  {
201  loopRate = DEFAULT_LOOP_RATE;
202  }
203 }
210 void fetchUSRTopic(ros::NodeHandle* nh, std::string& usrTopic)
211 {
212  if (nh->hasParam("us_sim/us_right_topic"))
213  {
214  nh->getParam("us_sim/us_right_topic", usrTopic);
215  }
216  else
217  {
218  usrTopic = DEFAULT_US_RIGHT_TOPIC;
219  }
220 }
227 void fetchUSFTopic(ros::NodeHandle* nh, std::string& usfTopic)
228 {
229  if (nh->hasParam("us_sim/us_front_topic"))
230  {
231  nh->getParam("us_sim/us_front_topic", usfTopic);
232  }
233  else
234  {
235  usfTopic = DEFAULT_US_FRONT_TOPIC;
236  }
237 }
244 void fetchUSLTopic(ros::NodeHandle* nh, std::string& uslTopic)
245 {
246  if (nh->hasParam("us_sim/us_left_topic"))
247  {
248  nh->getParam("us_sim/us_left_topic", uslTopic);
249  }
250  else
251  {
252  uslTopic = DEFAULT_US_LEFT_TOPIC;
253  }
254 }
260 void fetchMapLocation(ros::NodeHandle* nh, std::string& mapLocation)
261 {
262  if (nh->hasParam("us_sim/map_location"))
263  {
264  nh->getParam("us_sim/map_location", mapLocation);
265  }
266  else
267  {
268  mapLocation = DEFAULT_MAP_LOCATION;
269  }
270 }
276 void fetchMapMetadataLocation(ros::NodeHandle* nh,
277  std::string& mapMetadataLocation)
278 {
279  if (nh->hasParam("us_sim/map_metadata_location"))
280  {
281  nh->getParam("us_sim/map_metadata_location", mapMetadataLocation);
282  }
283  else
284  {
285  mapMetadataLocation = DEFAULT_MAP_METADATA_LOCATION;
286  }
287 }
293 void fetchUSRFrameID(ros::NodeHandle* nh, std::string& usrFrameID)
294 {
295  if (nh->hasParam("us_sim/us_right_frame_id"))
296  {
297  nh->getParam("us_sim/us_right_frame_id", usrFrameID);
298  }
299  else
300  {
301  usrFrameID = DEFAULT_US_RIGHT_FRAME_ID;
302  }
303 }
309 void fetchUSFFrameID(ros::NodeHandle* nh, std::string& usfFrameID)
310 {
311  if (nh->hasParam("us_sim/us_front_frame_id"))
312  {
313  nh->getParam("us_sim/us_front_frame_id", usfFrameID);
314  }
315  else
316  {
317  usfFrameID = DEFAULT_US_FRONT_FRAME_ID;
318  }
319 }
325 void fetchUSLFrameID(ros::NodeHandle* nh, std::string& uslFrameID)
326 {
327  if (nh->hasParam("us_sim/us_left_frame_id"))
328  {
329  nh->getParam("us_sim/us_left_frame_id", uslFrameID);
330  }
331  else
332  {
333  uslFrameID = DEFAULT_US_LEFT_FRAME_ID;
334  }
335 }
341 void fetchMapFrameID(ros::NodeHandle* nh, std::string& mapFrameID)
342 {
343  if (nh->hasParam("us_sim/map_frame_id"))
344  {
345  nh->getParam("us_sim/map_frame_id", mapFrameID);
346  }
347  else
348  {
349  mapFrameID = DEFAULT_MAP_FRAME_ID;
350  }
351 }
352 }
353 
354 using namespace usscan;
358 int main(int argc, char** argv)
359 {
360 
361  ros::init(argc, argv, "simulation_usscan");
362  ros::NodeHandle nh;
363  double loopRate;
364  std::string usrTopic, usfTopic, uslTopic, mapLocation, mapMetadataLocation,
365  usrFrameID, usfFrameID, uslFrameID, mapFrameID;
366 
367  fetchLoopRate(&nh, loopRate);
368  fetchUSRTopic(&nh, usrTopic);
369  fetchUSFTopic(&nh, usfTopic);
370  fetchUSLTopic(&nh, uslTopic);
371  fetchMapLocation(&nh, mapLocation);
372  fetchMapMetadataLocation(&nh, mapMetadataLocation);
373  fetchUSRFrameID(&nh, usrFrameID);
374  fetchUSFFrameID(&nh, usfFrameID);
375  fetchUSLFrameID(&nh, uslFrameID);
376  fetchMapFrameID(&nh, mapFrameID);
377 
378  dynamic_reconfigure::Server<pses_simulation::RangeSensorConfig> server;
379  dynamic_reconfigure::Server<pses_simulation::RangeSensorConfig>::CallbackType
380  f;
381  pses_simulation::RangeSensorConfig dynConfig;
382 
383  ros::Publisher front_us_range =
384  nh.advertise<sensor_msgs::Range>(usfTopic, 10);
385  ros::Publisher left_us_range = nh.advertise<sensor_msgs::Range>(uslTopic, 10);
386  ros::Publisher right_us_range =
387  nh.advertise<sensor_msgs::Range>(usrTopic, 10);
388 
389  sensor_msgs::Range front_range, left_range, right_range;
390 
391  // get "god" map meta info
392  nav_msgs::MapMetaData mapInfo;
393  YAML::Node imgMetaInfo = YAML::LoadFile(mapMetadataLocation);
394  double resolution = imgMetaInfo["resolution"].as<double>();
395  geometry_msgs::Pose origin = imgMetaInfo["origin"].as<geometry_msgs::Pose>();
396  mapInfo.origin = origin;
397  mapInfo.resolution = resolution;
398 
399  // get "god" map
400  cv::Mat map = cv::imread(mapLocation, 1);
401  cv::cvtColor(map, map, CV_RGB2GRAY);
402 
403  // create sensor object and link with config object
404  rs::RangeSensor rs_sonar(rs::us);
405  rs_sonar.setMap(map);
406  rs_sonar.setMapMetaData(mapInfo);
407 
408  f = boost::bind(&configCallback, _1, _2, &rs_sonar, &dynConfig);
409  server.setCallback(f);
410 
411  // variables needed for transformations
412  tf::TransformListener listener;
413  geometry_msgs::Pose position;
414  std::vector<double> rpy(3, 0.0);
415  cv::Point gridPose;
416 
417  ros::Time currentTime = ros::Time::now();
418 
419  front_range.header.frame_id = usfFrameID;
420  front_range.radiation_type = 0;
421 
422  left_range.header.frame_id = uslFrameID;
423  left_range.radiation_type = 0;
424 
425  right_range.header.frame_id = usrFrameID;
426  right_range.radiation_type = 0;
427 
428  // Loop starts here:
429  ros::Rate loop_rate(loopRate);
430  while (ros::ok())
431  {
432  currentTime = ros::Time::now();
433 
434  front_range.header.stamp = currentTime;
435  front_range.field_of_view = rs::degToRad(dynConfig.us_field_of_view);
436  front_range.min_range = dynConfig.us_min_sensor_distance;
437  front_range.max_range = dynConfig.us_max_sensor_distance;
438 
439  left_range.header.stamp = currentTime;
440  left_range.field_of_view = rs::degToRad(dynConfig.us_field_of_view);
441  left_range.min_range = dynConfig.us_min_sensor_distance;
442  left_range.max_range = dynConfig.us_max_sensor_distance;
443 
444  right_range.header.stamp = currentTime;
445  right_range.field_of_view = rs::degToRad(dynConfig.us_field_of_view);
446  right_range.min_range = dynConfig.us_min_sensor_distance;
447  right_range.max_range = dynConfig.us_max_sensor_distance;
448 
449  // front sensor
450  getPositionInfo(mapFrameID, usfFrameID, listener, &position, &rpy);
451  gridPose = setGridPosition(position, mapInfo);
452  front_range.range = rs_sonar.getUSScan(gridPose, rs::radToDeg(rpy[2]));
453 
454  // left sensor
455  getPositionInfo(mapFrameID, uslFrameID, listener, &position, &rpy);
456  gridPose = setGridPosition(position, mapInfo);
457  left_range.range = rs_sonar.getUSScan(gridPose, rs::radToDeg(rpy[2]));
458 
459  // right sensor
460  getPositionInfo(mapFrameID, usrFrameID, listener, &position, &rpy);
461  gridPose = setGridPosition(position, mapInfo);
462  right_range.range = rs_sonar.getUSScan(gridPose, rs::radToDeg(rpy[2]));
463 
464  // publish sensor msgs
465  front_us_range.publish(front_range);
466  right_us_range.publish(right_range);
467  left_us_range.publish(left_range);
468 
469  ros::spinOnce();
470  loop_rate.sleep();
471  }
472 
473  ros::spin();
474 }
This namespace groups all typedefs, utility functions and parameter getter used in the simulation_us ...
void fetchLoopRate(ros::NodeHandle *nh, double &loopRate)
Get loop rate launch parameter.
The rs::RangeSensor class simulates different range finder sensors based on the given rs::SensorType ...
void fetchMapLocation(ros::NodeHandle *nh, std::string &mapLocation)
Get map location launch parameter.
Header file for the rs::RangeSensor class.
std::shared_ptr< sensor_msgs::Range > scan_msg_ptr
shortcut for a pointer to a range message
void fetchUSRFrameID(ros::NodeHandle *nh, std::string &usrFrameID)
Get right ultra sonic sensor frame id launch parameter.
static const std::string DEFAULT_MAP_LOCATION
static Node encode(const geometry_msgs::Pose &rhs)
Encodes a pose message to YAML::Node containing x,y,z variables.
void fetchMapMetadataLocation(ros::NodeHandle *nh, std::string &mapMetadataLocation)
Get map meta data location launch parameter.
static const std::string DEFAULT_MAP_METADATA_LOCATION
void fetchMapFrameID(ros::NodeHandle *nh, std::string &mapFrameID)
Get map frame id launch parameter.
void fetchUSFTopic(ros::NodeHandle *nh, std::string &usfTopic)
Get front ultra sonic sensor topic launch parameter.
void configCallback(pses_simulation::RangeSensorConfig &config, uint32_t level, rs::RangeSensor *sensor, pses_simulation::RangeSensorConfig *dynConfig)
Sets the RangeSensorConfig object of this sensor simulation.
void fetchUSLTopic(ros::NodeHandle *nh, std::string &uslTopic)
Get left ultra sonic sensor topic launch parameter.
cv::Point setGridPosition(geometry_msgs::Pose &sensor, nav_msgs::MapMetaData &mapInfo)
Calculate the occupancy grid postion of a given pose.
static bool decode(const Node &node, geometry_msgs::Pose &rhs)
Decodes a YAML::Node containing x,y,z variables to a pose message.
static const std::string DEFAULT_MAP_FRAME_ID
static const std::string DEFAULT_US_LEFT_TOPIC
static const std::string DEFAULT_US_RIGHT_FRAME_ID
static const std::string DEFAULT_US_RIGHT_TOPIC
void fetchUSFFrameID(ros::NodeHandle *nh, std::string &usfFrameID)
Get front ultra sonic sensor 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.
int main(int argc, char **argv)
Main function of this ros node.
double radToDeg(double angle)
Conversion from radiants to degrees.
Definition: RangeSensor.cpp:35
static const std::string DEFAULT_US_FRONT_TOPIC
void fetchUSRTopic(ros::NodeHandle *nh, std::string &usrTopic)
Get right ultra sonic sensor topic launch parameter.
static const std::string DEFAULT_US_FRONT_FRAME_ID
static const double DEFAULT_LOOP_RATE
This namespace contains special functionality to parse from .yaml files or write to ...
double degToRad(double angle)
Conversion from degrees to radiants.
Definition: RangeSensor.cpp:33
void fetchUSLFrameID(ros::NodeHandle *nh, std::string &uslFrameID)
Get left ultra sonic sensor frame id launch parameter.
static const std::string DEFAULT_US_LEFT_FRAME_ID
std::shared_ptr< geometry_msgs::Pose > pose_msg_ptr
shortcut for a pointer to a pose message


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