ParticleFilter.cpp
Go to the documentation of this file.
1 
18 #include "ParticleFilter.h"
19 
20 namespace amcl3d
21 {
22 ParticleFilter::ParticleFilter() : generator_(rd_())
23 {
24 }
25 
27 {
28 }
29 
30 void ParticleFilter::buildParticlesPoseMsg(const geometry_msgs::Point32& offset, geometry_msgs::PoseArray& msg) const
31 {
32  msg.poses.resize(p_.size());
33 
34  for (uint32_t i = 0; i < p_.size(); ++i)
35  {
36  msg.poses[i].position.x = static_cast<double>(p_[i].x) + offset.x;
37  msg.poses[i].position.y = static_cast<double>(p_[i].y) + offset.y;
38  msg.poses[i].position.z = static_cast<double>(p_[i].z) + offset.z;
39  msg.poses[i].orientation.x = 0.;
40  msg.poses[i].orientation.y = 0.;
41  msg.poses[i].orientation.z = sin(static_cast<double>(p_[i].a * 0.5f));
42  msg.poses[i].orientation.w = cos(static_cast<double>(p_[i].a * 0.5f));
43  }
44 }
45 
46 void ParticleFilter::init(const int num_particles, const float x_init, const float y_init, const float z_init,
47  const float a_init, const float x_dev, const float y_dev, const float z_dev,
48  const float a_dev)
49 {
51  p_.resize(abs(num_particles));
52 
54  const float dev = std::max(std::max(x_dev, y_dev), z_dev);
55  const float gauss_const_1 = 1. / (dev * sqrt(2 * M_PI));
56  const float gauss_const_2 = 1. / (2 * dev * dev);
57 
58  p_[0].x = x_init;
59  p_[0].y = y_init;
60  p_[0].z = z_init;
61  p_[0].a = a_init;
62  p_[0].w = gauss_const_1;
63 
64  float wt = p_[0].w;
65  float dist;
66 
67  for (uint32_t i = 1; i < p_.size(); ++i)
68  {
69  p_[i].x = p_[0].x + ranGaussian(0, x_dev);
70  p_[i].y = p_[0].y + ranGaussian(0, y_dev);
71  p_[i].z = p_[0].z + ranGaussian(0, z_dev);
72  p_[i].a = p_[0].a + ranGaussian(0, a_dev);
73 
74  dist = sqrt((p_[i].x - p_[0].x) * (p_[i].x - p_[0].x) + (p_[i].y - p_[0].y) * (p_[i].y - p_[0].y) +
75  (p_[i].z - p_[0].z) * (p_[i].z - p_[0].z));
76 
77  p_[i].w = gauss_const_1 * exp(-dist * dist * gauss_const_2);
78 
79  wt += p_[i].w;
80  }
81 
82  Particle mean_p;
83  for (uint32_t i = 0; i < p_.size(); ++i)
84  {
85  p_[i].w /= wt;
86 
87  mean_p.x += p_[i].w * p_[i].x;
88  mean_p.y += p_[i].w * p_[i].y;
89  mean_p.z += p_[i].w * p_[i].z;
90  mean_p.a += p_[i].w * p_[i].a;
91  }
92  mean_ = mean_p;
93 
94  initialized_ = true;
95 }
96 
97 void ParticleFilter::predict(const double odom_x_mod, const double odom_y_mod, const double odom_z_mod,
98  const double odom_a_mod, const double delta_x, const double delta_y, const double delta_z,
99  const double delta_a)
100 {
101  const double x_dev = fabs(delta_x * odom_x_mod);
102  const double y_dev = fabs(delta_y * odom_y_mod);
103  const double z_dev = fabs(delta_z * odom_z_mod);
104  const double a_dev = fabs(delta_a * odom_a_mod);
105 
107  float sa, ca, rand_x, rand_y;
108  for (uint32_t i = 0; i < p_.size(); ++i)
109  {
110  sa = sin(p_[i].a);
111  ca = cos(p_[i].a);
112  rand_x = delta_x + ranGaussian(0, x_dev);
113  rand_y = delta_y + ranGaussian(0, y_dev);
114  p_[i].x += ca * rand_x - sa * rand_y;
115  p_[i].y += sa * rand_x + ca * rand_y;
116  p_[i].z += delta_z + ranGaussian(0, z_dev);
117  p_[i].a += delta_a + ranGaussian(0, a_dev);
118  }
119 }
120 
121 void ParticleFilter::update(const Grid3d& grid3d, const std::vector<pcl::PointXYZ>& points,
122  const std::vector<Range>& range_data, const double alpha, const double sigma)
123 {
125  float wtp = 0, wtr = 0;
126 
127  clock_t begin_for1 = clock();
128  for (uint32_t i = 0; i < p_.size(); ++i)
129  {
131  float tx = p_[i].x;
132  float ty = p_[i].y;
133  float tz = p_[i].z;
134 
136  if (!grid3d.isIntoMap(tx, ty, tz))
137  {
138  // std::cout << "Not into map: " << grid3d_.isIntoMap(tx, ty, tz-1.0) << std::endl;
139  p_[i].w = 0;
140  continue;
141  }
142 
144  p_[i].wp = grid3d.computeCloudWeight(points, tx, ty, tz, p_[i].a);
145 
147  p_[i].wr = computeRangeWeight(tx, ty, tz, range_data, sigma);
148 
150  wtp += p_[i].wp;
151  wtr += p_[i].wr;
152  }
153  clock_t end_for1 = clock();
154  double elapsed_secs = double(end_for1 - begin_for1) / CLOCKS_PER_SEC;
155  ROS_INFO("Update time 1: [%lf] sec", elapsed_secs);
156 
158  float wt = 0;
159  for (uint32_t i = 0; i < p_.size(); ++i)
160  {
161  if (wtp > 0)
162  p_[i].wp /= wtp;
163  else
164  p_[i].wp = 0;
165 
166  if (wtr > 0)
167  p_[i].wr /= wtr;
168  else
169  p_[i].wr = 0;
170 
171  p_[i].w = p_[i].wp * alpha + p_[i].wr * (1 - alpha);
172  wt += p_[i].w;
173  }
174 
175  Particle mean_p;
176  for (uint32_t i = 0; i < p_.size(); ++i)
177  {
178  if (wt > 0)
179  p_[i].w /= wt;
180  else
181  p_[i].w = 0;
182 
183  mean_p.x += p_[i].w * p_[i].x;
184  mean_p.y += p_[i].w * p_[i].y;
185  mean_p.z += p_[i].w * p_[i].z;
186  mean_p.a += p_[i].w * p_[i].a;
187  }
188  mean_ = mean_p;
189 }
190 
192 {
193  std::vector<Particle> new_p(p_.size());
194  const float factor = 1.f / p_.size();
195  const float r = factor * rngUniform(0, 1);
196  float c = p_[0].w;
197  float u;
198 
200  for (uint32_t m = 0, i = 0; m < p_.size(); ++m)
201  {
202  u = r + factor * m;
203  while (u > c)
204  {
205  if (++i >= p_.size())
206  break;
207  c += p_[i].w;
208  }
209  new_p[m] = p_[i];
210  new_p[m].w = factor;
211  }
212 
214  p_ = new_p;
215 }
216 
217 float ParticleFilter::computeRangeWeight(const float x, const float y, const float z,
218  const std::vector<Range>& range_data, const double sigma)
219 {
220  if (range_data.empty())
221  return 0;
222 
223  float w = 1;
224  const float k1 = 1.f / (sigma * sqrt(2 * M_PI));
225  const float k2 = 0.5f / (sigma * sigma);
226  float ax, ay, az, r;
227  for (uint32_t i = 0; i < range_data.size(); ++i)
228  {
229  ax = range_data[i].ax;
230  ay = range_data[i].ay;
231  az = range_data[i].az;
232  r = sqrt((x - ax) * (x - ax) + (y - ay) * (y - ay) + (z - az) * (z - az));
233  w *= k1 * exp(-k2 * (r - range_data[i].r) * (r - range_data[i].r));
234  }
235 
236  return w;
237 }
238 
239 float ParticleFilter::ranGaussian(const double mean, const double sigma)
240 {
241  std::normal_distribution<float> distribution(mean, sigma);
242  return distribution(generator_);
243 }
244 
245 float ParticleFilter::rngUniform(const float range_from, const float range_to)
246 {
247  std::uniform_real_distribution<float> distribution(range_from, range_to);
248  return distribution(generator_);
249 }
250 
251 } // namespace amcl3d
bool isIntoMap(const float x, const float y, const float z) const
Definition: Grid3d.cpp:154
float rngUniform(const float range_from, const float range_to)
f
float ranGaussian(const double mean, const double sigma)
#define M_PI
TFSIMD_FORCE_INLINE const tfScalar & y() const
void update(const Grid3d &grid3d, const std::vector< pcl::PointXYZ > &points, const std::vector< Range > &range_data, const double alpha, const double sigma)
Update Particles with a pointcloud update.
std::vector< Particle > p_
Particles.
float a
Yaw angle.
Struct that contains the data concerning one particle.
float computeCloudWeight(const std::vector< pcl::PointXYZ > &points, const float tx, const float ty, const float tz, const float a) const
Definition: Grid3d.cpp:122
Include Grid.hpp.
Definition: Grid3d.cpp:23
#define ROS_INFO(...)
void buildParticlesPoseMsg(const geometry_msgs::Point32 &offset, geometry_msgs::PoseArray &msg) const
TFSIMD_FORCE_INLINE const tfScalar & x() const
void predict(const double odom_x_mod, const double odom_y_mod, const double odom_z_mod, const double odom_a_mod, const double delta_x, const double delta_y, const double delta_z, const double delta_a)
TFSIMD_FORCE_INLINE const tfScalar & z() const
bool initialized_
Indicates if the filter was initialized.
TFSIMD_FORCE_INLINE const tfScalar & w() const
float computeRangeWeight(const float x, const float y, const float z, const std::vector< Range > &range_data, const double sigma)
void init(const int num_particles, const float x_init, const float y_init, const float z_init, const float a_init, const float x_dev, const float y_dev, const float z_dev, const float a_dev)
Set the initial pose of the particle filter.
void resample()
Resample the set of particles using low-variance sampling.
float x
Position.


amcl3d
Author(s): Francisco J.Perez-Grau
autogenerated on Sun Sep 15 2019 04:08:05