virtual_sensor_node.cpp
Go to the documentation of this file.
1 /*
2  * virtual_sensor_node.cpp
3  *
4  * Created on: May 13, 2013
5  * Author: jorge
6  */
7 
9 
10 
11 namespace virtual_sensor
12 {
13 
15 {
16 }
17 
19 {
20 }
21 
22 
24 {
25  ros::NodeHandle nh;
26  ros::NodeHandle pnh("~");
27 
28  int samples;
29 
30  pnh.param("samples", samples, 360);
31  pnh.param("angle_min", angle_min_, -M_PI);
32  pnh.param("angle_max", angle_max_, +M_PI);
33  pnh.param("range_min", range_min_, 0.0);
34  pnh.param("range_max", range_max_, std::numeric_limits<double>::quiet_NaN());
35  pnh.param("frequency", frequency_, std::numeric_limits<double>::quiet_NaN());
36  pnh.param("hits_count", hits_count_, 2);
37  pnh.param("sensor_frame", sensor_frame_id_, std::string("/base_link"));
38  pnh.param("global_frame", global_frame_id_, std::string("/map"));
39 
40  double costmap_update_frequency, costmap_width, costmap_height;
41 
42  nh.getParam("move_base/local_costmap/update_frequency", costmap_update_frequency);
43  nh.getParam("move_base/local_costmap/width", costmap_width);
44  nh.getParam("move_base/local_costmap/height", costmap_height);
45 
46  // Use local costmap configuration to decide some default values
47  if (std::isnan(range_max_) == true)
48  range_max_ = std::max(costmap_width, costmap_height)/2.0;
49 
50  if (std::isnan(frequency_) == true)
51  frequency_ = costmap_update_frequency*2.0;
52 
53  column_poses_sub_ = nh.subscribe("column_pose_list", 1, &VirtualSensorNode::columnPosesCB, this);
54  wall_poses_sub_ = nh.subscribe("wall_pose_list", 1, &VirtualSensorNode::wallPosesCB, this);
55  virtual_obs_pub_ = nh.advertise <sensor_msgs::LaserScan> ("virtual_sensor_scan", 1, true);
56 
57  // Set virtual scan configuration
58  scan_.header.frame_id = sensor_frame_id_;
59  scan_.angle_min = angle_min_;
60  scan_.angle_max = angle_max_;
61  scan_.angle_increment = (angle_max_ - angle_min_)/samples;
62  scan_.scan_time = 1.0 / frequency_;
63  scan_.range_min = range_min_;
64  scan_.range_max = range_max_;
65  scan_.ranges.resize(samples);
66 
67  return true;
68 }
69 
70 void VirtualSensorNode::columnPosesCB(const yocs_msgs::ColumnList::ConstPtr& msg)
71 {
72  columns_ = msg->obstacles;
73 }
74 
75 void VirtualSensorNode::wallPosesCB(const yocs_msgs::WallList::ConstPtr& msg)
76 {
77  walls_ = msg->obstacles;
78 }
79 
80 
82 {
83  ros::Rate rate(frequency_);
84 
85  while (ros::ok())
86  {
87  if ((virtual_obs_pub_.getNumSubscribers() > 0) && ((columns_.size() > 0) || (walls_.size() > 0)))
88  {
89  scan_.header.stamp = ros::Time::now();
90 
91  tf::StampedTransform robot_gb;
92  try
93  {
95  }
96  catch (tf::TransformException& e)
97  {
98  // This can happen during startup, while some part of the localization chain is missing
99  // If not, probably sensor_frame is missconfigured
100  ROS_WARN_THROTTLE(2, "Cannot get tf %s -> %s: %s",
101  global_frame_id_.c_str(), sensor_frame_id_.c_str(), e.what());
102  continue;
103  }
104  tf::Transform robot_gb_inv = robot_gb.inverse();
105 
106  // Pre-filter obstacles:
107  // - put in sensor reference system
108  // - remove those out of range
109  // - short by increasing distance to the robot
110  std::vector< boost::shared_ptr<Obstacle> > obstacles;
111 
112  // Column obstacles
113  for (unsigned int i = 0; i < columns_.size(); i++)
114  {
115  tf::Transform obs_abs_tf;
116  tf::poseMsgToTF(columns_[i].pose.pose.pose, obs_abs_tf);
118  tf::Transform obs_tf = robot_gb_inv * obs_abs_tf;
119  boost::shared_ptr<Obstacle> new_obs(new Column(columns_[i].name, obs_tf, columns_[i].radius, columns_[i].height));
120 
121  add(new_obs, obstacles);
122  }
123 
124  // Wall obstacles
125  for (unsigned int i = 0; i < walls_.size(); i++)
126  {
127  tf::Transform obs_abs_tf;
128  tf::poseMsgToTF(walls_[i].pose.pose.pose, obs_abs_tf);
129  tf::Transform obs_tf = robot_gb_inv * obs_abs_tf;
130  boost::shared_ptr<Obstacle> new_obs(new Wall(walls_[i].name, obs_tf, walls_[i].length, walls_[i].width, walls_[i].height));
131 
132  add(new_obs, obstacles);
133  }
134 
135  int ray = 0;
136 
137  // Fire sensor "rays" and register closest hit, if any. We test hits_count_ consecutive objects; in most
138  // cases 2 hits should be enough, although in some cases three or more ill-arranged obstacles will return
139  // a wrong shortest distance (remember that obstacles are shorted by its closest distance to the robot)
140  for (double ray_theta = scan_.angle_min; ray_theta <= scan_.angle_max; ray_theta += scan_.angle_increment)
141  {
142  double rx = scan_.range_max*std::cos(ray_theta);
143  double ry = scan_.range_max*std::sin(ray_theta);
144 
145  int hits = 0;
146  scan_.ranges[ray] = scan_.range_max;
147 
148  for (unsigned int i = 0; i < obstacles.size(); i++)
149  {
150  double distance;
151  if (obstacles[i]->intersects(rx, ry, scan_.range_max, distance) == true)
152  {
153  // Hit; take the shortest distance until now and keep checking until we reach hits_count_
154  scan_.ranges[ray] = std::min(scan_.ranges[ray], (float)distance);
155 
156  if (hits < hits_count_)
157  {
158  hits++;
159  }
160  else
161  {
162  break; // enough hits
163  }
164  }
165  }
166 
167  ray++;
168  }
169 
171  }
172 
173  ros::spinOnce();
174  rate.sleep();
175  }
176 }
177 
179 {
180  if ((new_obs->minHeight() > 0.0) || (new_obs->maxHeight() < 0.0))
181  {
182  return false; // Obstacle above/below the virtual sensor (who is a 2D scan)
183  }
184 
185  if (new_obs->distance() <= 0.0)
186  {
187  ROS_WARN_THROTTLE(2, "The robot is inside an obstacle??? Ignore it (distance: %f)", new_obs->distance());
188  return false;
189  }
190 
191  if (new_obs->distance() <= scan_.range_max)
192  {
193  std::vector< boost::shared_ptr<Obstacle> >::iterator it;
194  for (it = obstacles.begin(); it != obstacles.end(); ++it)
195  {
196  if (new_obs->distance() <= (*it)->distance())
197  {
198  obstacles.insert(it, new_obs);
199  return true;
200  }
201  }
202 
203  if ((obstacles.size() == 0) || it == obstacles.end())
204  {
205  // This obstacle is the first inserted or is the farthest from the robot
206  obstacles.push_back(new_obs);
207  return true;
208  }
209  }
210 
211  return false;
212 }
213 
214 } // namespace virtual_sensor
215 
216 
217 int main(int argc, char **argv)
218 {
219  ros::init(argc, argv, "virtual_sensor");
220 
222  if (node.init() == false)
223  {
224  ROS_ERROR("%s initialization failed", ros::this_node::getName().c_str());
225  return -1;
226  }
227  ROS_INFO("%s initialized", ros::this_node::getName().c_str());
228  node.spin();
229 
230  return 0;
231 }
TFSIMD_FORCE_INLINE void setRotation(const Quaternion &q)
static void poseMsgToTF(const geometry_msgs::Pose &msg, Pose &bt)
#define ROS_WARN_THROTTLE(rate,...)
void publish(const boost::shared_ptr< M > &message) const
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
ROSCPP_DECL const std::string & getName()
TFSIMD_FORCE_INLINE tfScalar distance(const Vector3 &v) const
std::vector< yocs_msgs::Wall > walls_
void columnPosesCB(const yocs_msgs::ColumnList::ConstPtr &msg)
static const Quaternion & getIdentity()
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
ROSCPP_DECL bool ok()
Transform inverse() const
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
void lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, StampedTransform &transform) const
bool sleep()
int main(int argc, char **argv)
uint32_t getNumSubscribers() const
bool getParam(const std::string &key, std::string &s) const
static Time now()
TFSIMD_FORCE_INLINE tfScalar length(const Quaternion &q)
ROSCPP_DECL void spinOnce()
bool add(boost::shared_ptr< Obstacle > &new_obs, std::vector< boost::shared_ptr< Obstacle > > &obstacles)
#define ROS_ERROR(...)
void wallPosesCB(const yocs_msgs::WallList::ConstPtr &msg)
std::vector< yocs_msgs::Column > columns_


yocs_virtual_sensor
Author(s): Jorge Santos
autogenerated on Mon Jun 10 2019 15:54:08