Nav2 Navigation Stack - kilted  kilted
ROS 2 Navigation Stack
beam_model.cpp
1 /*
2  * Player - One Hell of a Robot Server
3  * Copyright (C) 2000 Brian Gerkey & Kasper Stoy
4  * gerkey@usc.edu kaspers@robotics.usc.edu
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  */
21 
22 #include <math.h>
23 #include <assert.h>
24 
25 #include "nav2_amcl/sensors/laser/laser.hpp"
26 
27 namespace nav2_amcl
28 {
29 
30 BeamModel::BeamModel(
31  double z_hit, double z_short, double z_max, double z_rand, double sigma_hit,
32  double lambda_short, double chi_outlier, size_t max_beams, map_t * map)
33 : Laser(max_beams, map)
34 {
35  z_hit_ = z_hit;
36  z_rand_ = z_rand;
37  sigma_hit_ = sigma_hit;
38  z_short_ = z_short;
39  z_max_ = z_max;
40  lambda_short_ = lambda_short;
41  chi_outlier_ = chi_outlier;
42 }
43 
44 // Determine the probability for the given pose
45 double
46 BeamModel::sensorFunction(LaserData * data, pf_sample_set_t * set)
47 {
48  BeamModel * self;
49  int i, j, step;
50  double z, pz;
51  double p;
52  double map_range;
53  double obs_range, obs_bearing;
54  double total_weight;
55  pf_sample_t * sample;
56  pf_vector_t pose;
57 
58  self = reinterpret_cast<BeamModel *>(data->laser);
59 
60  total_weight = 0.0;
61 
62  // Compute the sample weights
63  for (j = 0; j < set->sample_count; j++) {
64  sample = set->samples + j;
65  pose = sample->pose;
66 
67  // Take account of the laser pose relative to the robot
68  pose = pf_vector_coord_add(self->laser_pose_, pose);
69 
70  p = 1.0;
71 
72  step = (data->range_count - 1) / (self->max_beams_ - 1);
73  for (i = 0; i < data->range_count; i += step) {
74  obs_range = data->ranges[i][0];
75 
76  // Check for NaN
77  if (isnan(obs_range)) {
78  continue;
79  }
80 
81  obs_bearing = data->ranges[i][1];
82 
83  // Compute the range according to the map
84  map_range = map_calc_range(
85  self->map_, pose.v[0], pose.v[1],
86  pose.v[2] + obs_bearing, data->range_max);
87  pz = 0.0;
88 
89  // Part 1: good, but noisy, hit
90  z = obs_range - map_range;
91  pz += self->z_hit_ * exp(-(z * z) / (2 * self->sigma_hit_ * self->sigma_hit_));
92 
93  // Part 2: short reading from unexpected obstacle (e.g., a person)
94  if (z < 0) {
95  pz += self->z_short_ * self->lambda_short_ * exp(-self->lambda_short_ * obs_range);
96  }
97 
98  // Part 3: Failure to detect obstacle, reported as max-range
99  if (obs_range == data->range_max) {
100  pz += self->z_max_ * 1.0;
101  }
102 
103  // Part 4: Random measurements
104  if (obs_range < data->range_max) {
105  pz += self->z_rand_ * 1.0 / data->range_max;
106  }
107 
108  // TODO(?): outlier rejection for short readings
109 
110  assert(pz <= 1.0);
111  assert(pz >= 0.0);
112  // p *= pz;
113  // here we have an ad-hoc weighting scheme for combining beam probs
114  // works well, though...
115  p += pz * pz * pz;
116  }
117 
118  sample->weight *= p;
119  total_weight += sample->weight;
120  }
121 
122  return total_weight;
123 }
124 
125 bool
126 BeamModel::sensorUpdate(pf_t * pf, LaserData * data)
127 {
128  if (max_beams_ < 2) {
129  return false;
130  }
131  pf_update_sensor(pf, (pf_sensor_model_fn_t) sensorFunction, data);
132 
133  return true;
134 }
135 
136 } // namespace nav2_amcl
Definition: pf.hpp:112
Definition: map.hpp:62