balls_in_box_occupancy_map.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018, The Regents of the University of California (Regents).
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above
13  * copyright notice, this list of conditions and the following
14  * disclaimer in the documentation and/or other materials provided
15  * with the distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Please contact the author(s) of this library if you have any questions.
34  * Authors: David Fridovich-Keil ( dfk@eecs.berkeley.edu )
35  */
36 
38 //
39 //
41 
43 
44 namespace fastrack {
45 namespace environment {
46 
47 // Occupancy probability for a single point.
49  double time) const {
50  if (!initialized_) {
51  ROS_WARN("%s: Tried to collision check without initializing.",
52  name_.c_str());
53  return kOccupiedProbability;
54  }
55 
56  // Check box limits.
57  if (p(0) < lower_(0) || p(0) > upper_(0) || p(1) < lower_(1) ||
58  p(1) > upper_(1) || p(2) < lower_(2) || p(2) > upper_(2))
59  return kOccupiedProbability;
60 
61  // Check if this point is inside any obstacles.
62  // NOTE: use KnnSearch instead of RadiusSearch for extra precision.
63  constexpr size_t kOneNearestNeighbor = 1;
64  const std::vector<std::pair<Vector3d, double>> neighboring_obstacles =
65  obstacles_.KnnSearch(p, kOneNearestNeighbor);
66  for (const auto& entry : neighboring_obstacles) {
67  if ((p - entry.first).norm() < entry.second) return kOccupiedProbability;
68  }
69 
70  // Check if this point is inside any sensor FOVs.
71  const std::vector<std::pair<Vector3d, double>> neighboring_sensors =
72  sensor_fovs_.KnnSearch(p, kOneNearestNeighbor);
73  for (const auto& entry : neighboring_sensors) {
74  if ((p - entry.first).norm() < entry.second) return kFreeProbability;
75  }
76 
77  return kUnknownProbability;
78 }
79 
80 // Occupancy probability for a box tracking error bound centered at the given
81 // point. Occupancy is set to occupied if ANY of the bound is occupied. Next,
82 // if ANY of the bound is unknown the result is unknown. Otherwise, free.
84  const TrackingBound& bound,
85  double time) const {
86  if (!initialized_) {
87  ROS_WARN("%s: Tried to collision check without initializing.",
88  name_.c_str());
89  return kOccupiedProbability;
90  }
91 
92  // Check box limits.
93  if (!bound.ContainedWithinBox(p, lower_, upper_)) return kOccupiedProbability;
94 
95  // Helper function to check if any sphere in the given KdtreeMap overlaps
96  // the given Box.
97  auto overlaps = [&p, &bound](const KdtreeMap<3, double>& kdtree) {
98  // Get k-nearest neighbors as a heuristic.
99  // NOTE: using KnnSearch instead of RadiusSearch because it seems to
100  // be more precise. When the Kdtree is huge it may make more sense to
101  // radius search, or it may not matter.
102  constexpr size_t kNumNearestNeighbors = 10;
103  const auto neighbors = kdtree.KnnSearch(p, kNumNearestNeighbors);
104 
105  // Check for overlaps.
106  for (const auto& entry : neighbors) {
107  const Vector3d& center = entry.first;
108  const double& radius = entry.second;
109  if (bound.OverlapsSphere(p, center, radius)) return true;
110  }
111 
112  return false;
113  }; //\overlaps
114 
115  // Check if this point is inside any obstacles.
116  if (overlaps(obstacles_)) return kOccupiedProbability;
117 
118  // Check if this point contains any unknown space.
119  if (!overlaps(sensor_fovs_)) return kUnknownProbability;
120 
121  return kFreeProbability;
122 }
123 
124 // Update this environment with the information contained in the given
125 // sensor measurement.
126 // NOTE! This function needs to publish on `updated_topic_`.
128  const fastrack_msgs::SensedSpheres::ConstPtr& msg) {
129  bool updated_env = false;
130 
131  // Add sensor FOV to kdtree.
132  const Vector3d sensor_position(msg->sensor_position.x, msg->sensor_position.y,
133  msg->sensor_position.z);
134 
135  // If this is far enough from any existing sensor FOV then add to the kdtree.
136  constexpr size_t kOneNearestNeighbor = 1;
137  constexpr double kSmallNumber = 1e-2;
138  const auto neighboring_fovs =
139  sensor_fovs_.KnnSearch(sensor_position, kOneNearestNeighbor);
140  if (neighboring_fovs.empty() ||
141  (neighboring_fovs[0].first - sensor_position).norm() > kSmallNumber) {
142  sensor_fovs_.Insert(std::make_pair(sensor_position, msg->sensor_radius));
143  updated_env = true;
144  }
145 
146  // Check list lengths.
147  if (msg->centers.size() != msg->radii.size())
148  ROS_WARN("%s: Malformed SensedSpheres msg.", name_.c_str());
149 
150  const size_t num_obstacles = std::min(msg->centers.size(), msg->radii.size());
151 
152  // Add each unique obstacle to list.
153  for (size_t ii = 0; ii < num_obstacles; ii++) {
154  const Vector3d p(msg->centers[ii].x, msg->centers[ii].y,
155  msg->centers[ii].z);
156  const double r = msg->radii[ii];
157 
158  // If not unique, discard.
159  bool unique = true;
160  const auto neighbors = obstacles_.KnnSearch(p, kOneNearestNeighbor);
161  for (const auto& entry : neighbors) {
162  if ((p - entry.first).squaredNorm() < constants::kEpsilon &&
163  std::abs(r - entry.second) < constants::kEpsilon) {
164  unique = false;
165  break;
166  }
167  }
168 
169  if (unique) {
170  updated_env = true;
171  obstacles_.Insert({p, r});
172  }
173  }
174 
175  if (updated_env) {
176  // Let the system know this environment has been updated.
177  updated_pub_.publish(std_msgs::Empty());
178  }
179 
180  // Visualize.
181  Visualize();
182 }
183 
184 // Generate a sensor measurement as a service response.
185 fastrack_msgs::SensedSpheres BallsInBoxOccupancyMap::SimulateSensor(
186  const SphereSensorParams& params) const {
187  fastrack_msgs::SensedSpheres msg;
188 
189  // Find nearest neighbors.
190  const auto neighbors = obstacles_.RadiusSearch(
191  params.position, params.range + largest_obstacle_radius_);
192 
193  // Check and see if any are actually in range.
194  for (const auto& entry : neighbors) {
195  if ((params.position - entry.first).norm() < params.range + entry.second) {
196  geometry_msgs::Vector3 c;
197  c.x = entry.first(0);
198  c.y = entry.first(1);
199  c.z = entry.first(2);
200 
201  msg.centers.push_back(c);
202  msg.radii.push_back(entry.second);
203  }
204  }
205 
206  return msg;
207 }
208 
209 // Load parameters. This may be overridden by derived classes if needed
210 // (they should still call this one via OccupancyMap::LoadParameters).
211 bool BallsInBoxOccupancyMap::LoadParameters(const ros::NodeHandle& n) {
212  if (!OccupancyMap::LoadParameters(n)) return false;
213 
214  return true;
215 }
216 
217 // Derived classes must have some sort of visualization through RViz.
219  if (vis_pub_.getNumSubscribers() <= 0) return;
220 
221  // Set up box marker.
222  visualization_msgs::Marker cube;
223  cube.ns = "cube";
224  cube.header.frame_id = fixed_frame_;
225  cube.header.stamp = ros::Time::now();
226  cube.id = 0;
227  cube.type = visualization_msgs::Marker::CUBE;
228  cube.action = visualization_msgs::Marker::ADD;
229  cube.color.a = 0.5;
230  cube.color.r = 0.3;
231  cube.color.g = 0.7;
232  cube.color.b = 0.7;
233 
234  geometry_msgs::Point center;
235 
236  // Fill in center and scale.
237  cube.scale.x = upper_(0) - lower_(0);
238  center.x = lower_(0) + 0.5 * cube.scale.x;
239 
240  cube.scale.y = upper_(1) - lower_(1);
241  center.y = lower_(1) + 0.5 * cube.scale.y;
242 
243  cube.scale.z = upper_(2) - lower_(2);
244  center.z = lower_(2) + 0.5 * cube.scale.z;
245 
246  cube.pose.position = center;
247  cube.pose.orientation.x = 0.0;
248  cube.pose.orientation.y = 0.0;
249  cube.pose.orientation.z = 0.0;
250  cube.pose.orientation.w = 1.0;
251 
252  // Publish cube marker.
253  vis_pub_.publish(cube);
254 
255  // Visualize obstacles as spheres.
256  const auto& obstacle_registry = obstacles_.Registry();
257  for (size_t ii = 0; ii < obstacle_registry.size(); ii++) {
258  const auto& entry = obstacle_registry[ii];
259 
260  visualization_msgs::Marker sphere;
261  sphere.ns = "obstacles";
262  sphere.header.frame_id = fixed_frame_;
263  sphere.header.stamp = ros::Time::now();
264  sphere.id = static_cast<int>(ii);
265  sphere.type = visualization_msgs::Marker::SPHERE;
266  sphere.action = visualization_msgs::Marker::ADD;
267 
268  sphere.scale.x = 2.0 * entry.second;
269  sphere.scale.y = 2.0 * entry.second;
270  sphere.scale.z = 2.0 * entry.second;
271 
272  sphere.color.a = 0.9;
273  sphere.color.r = 0.7;
274  sphere.color.g = 0.5;
275  sphere.color.b = 0.5;
276 
277  geometry_msgs::Point p;
278  p.x = entry.first(0);
279  p.y = entry.first(1);
280  p.z = entry.first(2);
281 
282  sphere.pose.position = p;
283 
284  // Publish sphere marker.
285  vis_pub_.publish(sphere);
286  ros::Duration(0.001).sleep();
287  }
288 
289  // Visualize sensor FOVs as spheres too.
290  const auto& sensor_registry = sensor_fovs_.Registry();
291  for (size_t ii = 0; ii < sensor_registry.size(); ii++) {
292  const auto& entry = sensor_registry[ii];
293 
294  visualization_msgs::Marker sphere;
295  sphere.ns = "sensors";
296  sphere.header.frame_id = fixed_frame_;
297  sphere.header.stamp = ros::Time::now();
298  sphere.id = static_cast<int>(ii);
299  sphere.type = visualization_msgs::Marker::SPHERE;
300  sphere.action = visualization_msgs::Marker::ADD;
301 
302  sphere.scale.x = 2.0 * entry.second;
303  sphere.scale.y = 2.0 * entry.second;
304  sphere.scale.z = 2.0 * entry.second;
305 
306  sphere.color.a = 0.025;
307  sphere.color.r = 0.5;
308  sphere.color.g = 0.8;
309  sphere.color.b = 0.5;
310 
311  geometry_msgs::Point p;
312  p.x = entry.first(0);
313  p.y = entry.first(1);
314  p.z = entry.first(2);
315 
316  sphere.pose.position = p;
317 
318  // Publish sphere marker.
319  vis_pub_.publish(sphere);
320  ros::Duration(0.001).sleep();
321  }
322 }
323 
324 } // namespace environment
325 } // namespace fastrack
fastrack_msgs::SensedSpheres SimulateSensor(const SphereSensorParams &params) const
std::vector< std::pair< VectorKd, V > > KnnSearch(const VectorKd &query, size_t k) const
Definition: kdtree_map.h:132
const std::vector< std::pair< VectorKd, V > > & Registry() const
Definition: kdtree_map.h:89
double OccupancyProbability(const Vector3d &p, double time=std::numeric_limits< double >::quiet_NaN()) const
void SensorCallback(const typename fastrack_msgs::SensedSpheres::ConstPtr &msg)
static constexpr double kEpsilon
Definition: types.h:70
Definition: box.h:53
virtual bool LoadParameters(const ros::NodeHandle &n)
std::vector< std::pair< VectorKd, V > > RadiusSearch(const VectorKd &query, double r) const
Definition: kdtree_map.h:165
bool Insert(const std::pair< VectorKd, V > &entry)
Definition: kdtree_map.h:105


fastrack
Author(s): David Fridovich-Keil
autogenerated on Mon Aug 3 2020 21:28:37