numerics.hpp
Go to the documentation of this file.
1 /*********************************************************************
2  * BSD 3-Clause License
3  *
4  * Copyright (c) 2020 Northwestern University
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * * Redistributions of source code must retain the above copyright notice, this
11  * list of conditions and the following disclaimer.
12  *
13  * * Redistributions in binary form must reproduce the above copyright notice,
14  * this list of conditions and the following disclaimer in the documentation
15  * and/or other materials provided with the distribution.
16  *
17  * * Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived from
19  * 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 ARE
24  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *********************************************************************/
38 #ifndef NUMERICS_HPP
39 #define NUMERICS_HPP
40 
41 #include <cmath>
42 #include <algorithm>
43 // #include <numbers>
44 
45 #include <armadillo>
46 
47 #include <nav_msgs/Path.h>
49 
51 
52 namespace ergodic_exploration
53 {
54 using arma::mat;
55 using arma::vec;
56 
57 // TODO: why gcc cant find numbers
58 constexpr double PI = 3.14159265358979323846;
59 
67 inline bool almost_equal(double d1, double d2, double epsilon = 1.0e-12)
68 {
69  return std::fabs(d1 - d2) < epsilon ? true : false;
70 }
71 
77 inline double normalize_angle_PI(double rad)
78 {
79  // floating point remainder essentially this is fmod
80  const auto q = std::floor((rad + PI) / (2.0 * PI));
81  rad = (rad + PI) - q * 2.0 * PI;
82 
83  if (rad < 0.0)
84  {
85  rad += 2.0 * PI;
86  }
87 
88  return (rad - PI);
89 }
90 
96 inline double normalize_angle_2PI(double rad)
97 {
98  // floating point remainder essentially this is fmod
99  const auto q = std::floor(rad / (2.0 * PI));
100  rad = (rad)-q * 2.0 * PI;
101 
102  if (rad < 0.0)
103  {
104  rad += 2.0 * PI;
105  }
106 
107  return rad;
108 }
109 
118 inline double getYaw(double qx, double qy, double qz, double qw)
119 {
120  // TODO: add unit test
121  // Source: https://github.com/ros/geometry2/blob/noetic-devel/tf2/include/tf2/impl/utils.h#L122
122  const auto sqx = qx * qx;
123  const auto sqy = qy * qy;
124  const auto sqz = qz * qz;
125  const auto sqw = qw * qw;
126 
127  // Normalization added from urdfom_headers
128  const auto sarg = -2.0 * (qx * qz - qw * qy) / (sqx + sqy + sqz + sqw);
129 
130  // Cases derived from https://orbitalstation.wordpress.com/tag/quaternion/
131  if (sarg < -0.99999 || almost_equal(sarg, -0.99999))
132  {
133  return -2.0 * std::atan2(qy, qx);
134  }
135 
136  else if (sarg > 0.99999 || almost_equal(sarg, 0.99999))
137  {
138  return 2.0 * std::atan2(qy, qx);
139  }
140 
141  return std::atan2(2.0 * (qx * qy + qw * qz), sqw + sqx - sqy - sqz);
142 }
143 
152 inline double distance(double x0, double y0, double x1, double y1)
153 {
154  const auto dx = x1 - x0;
155  const auto dy = y1 - y0;
156  return std::sqrt(dx * dx + dy * dy);
157 }
158 
164 inline double entropy(double p)
165 {
166  // Assign zero information gain
167  if (almost_equal(0.0, p) || almost_equal(1.0, p) /*|| p < 0.0*/)
168  {
169  return 1e-3;
170  }
171 
172  // unknowm: p = -1 => entropy(0.5) = 0.7
173  else if (p < 0.0)
174  {
175  return 0.7;
176  }
177 
178  return -p * std::log(p) - (1.0 - p) * std::log(1.0 - p);
179 }
180 
186 inline vec polar2Cartesian(double angle, double range)
187 {
188  const auto x = range * std::cos(angle);
189  const auto y = range * std::sin(angle);
190  return { x, y };
191 }
192 
198 inline vec polar2CartesianHomo(double angle, double range)
199 {
200  const auto x = range * std::cos(angle);
201  const auto y = range * std::sin(angle);
202  return { x, y, 1.0 };
203 }
204 
212 inline mat transform2d(double x, double y, double angle)
213 {
214  const mat trans2d = { { std::cos(angle), -std::sin(angle), x },
215  { std::sin(angle), std::cos(angle), y },
216  { 0.0, 0.0, 1.0 } };
217 
218  return trans2d;
219 }
220 
227 inline mat transform2d(double x, double y)
228 {
229  const mat trans2d = { { 1.0, 0.0, x }, { 0.0, 1.0, y }, { 0.0, 0.0, 1.0 } };
230 
231  return trans2d;
232 }
233 
239 inline mat transform2d(double angle)
240 {
241  const mat trans2d = { { std::cos(angle), -std::sin(angle), 0.0 },
242  { std::sin(angle), std::cos(angle), 0.0 },
243  { 0.0, 0.0, 1.0 } };
244  return trans2d;
245 }
246 
252 inline mat transform2dInv(const mat& trans2d)
253 {
254  // R^T flip sign in sin
255  const auto stheta = -trans2d(1, 0);
256  const auto ctheta = trans2d(0, 0);
257  const auto theta = std::atan2(stheta, ctheta);
258 
259  // p' = -R^T * p
260  const auto x = -(ctheta * trans2d(0, 2) - stheta * trans2d(1, 2));
261  const auto y = -(stheta * trans2d(0, 2) + ctheta * trans2d(1, 2));
262 
263  return transform2d(theta, x, y);
264 }
265 
273 inline vec integrate_twist(const vec& x, const vec& u, double dt)
274 {
275  // Eqn. 13.35 and 13.36 pg 471 Modern Robotics
276  // displacement b to b' (dx, dy, dth)
277  vec dqb(3);
278 
279  // no rotation
280  if (almost_equal(u(2), 0.0))
281  {
282  dqb(0) = u(0) * dt;
283  dqb(1) = u(1) * dt;
284  dqb(2) = 0.0;
285  }
286 
287  else
288  {
289  const vec vb = u * dt;
290  dqb(0) = (vb(0) * std::sin(vb(2)) + vb(1) * (std::cos(vb(2)) - 1.0)) / vb(2);
291 
292  dqb(1) = (vb(1) * std::sin(vb(2)) + vb(0) * (1.0 - std::cos(vb(2)))) / vb(2);
293 
294  dqb(2) = vb(2);
295  }
296 
297  return x + transform2d(x(2)) * dqb;
298 }
299 
312 inline bool validate_control(const Collision& collision, const GridMap& grid,
313  const vec& x0, const vec& u, double dt, double horizon)
314 {
315  vec x = x0;
316  const auto steps = static_cast<unsigned int>(std::abs(horizon / dt));
317 
318  for (unsigned int i = 0; i < steps; i++)
319  {
320  x = integrate_twist(x, u, dt);
321  x(2) = normalize_angle_PI(x(2));
322 
323  if (collision.collisionCheck(grid, x))
324  {
325  return false;
326  }
327  }
328 
329  return true;
330 }
331 
340 inline nav_msgs::Path constTwistPath(const std::string& map_frame_id, const vec& x0,
341  const vec& u, double dt, double horizon)
342 {
343  nav_msgs::Path path;
344  path.header.frame_id = map_frame_id;
345 
346  const auto steps = static_cast<unsigned int>(std::abs(horizon / dt));
347  path.poses.resize(steps);
348 
349  vec x = x0;
350  for (unsigned int i = 0; i < steps; i++)
351  {
352  x = integrate_twist(x, u, dt);
353 
354  path.poses.at(i).pose.position.x = x(0);
355  path.poses.at(i).pose.position.y = x(1);
356 
357  tf2::Quaternion quat;
358  quat.setRPY(0.0, 0.0, normalize_angle_PI(x(2)));
359 
360  path.poses.at(i).pose.orientation.x = quat.x();
361  path.poses.at(i).pose.orientation.y = quat.y();
362  path.poses.at(i).pose.orientation.z = quat.z();
363  path.poses.at(i).pose.orientation.w = quat.w();
364  }
365 
366  return path;
367 }
368 
369 } // namespace ergodic_exploration
370 #endif
ergodic_exploration::validate_control
bool validate_control(const Collision &collision, const GridMap &grid, const vec &x0, const vec &u, double dt, double horizon)
Determine if control will cause a collision.
Definition: numerics.hpp:312
epsilon
double epsilon
angle
TFSIMD_FORCE_INLINE tfScalar angle(const Quaternion &q1, const Quaternion &q2)
collision.hpp
Collision checking in 2D.
tf2::Quaternion::setRPY
void setRPY(const tf2Scalar &roll, const tf2Scalar &pitch, const tf2Scalar &yaw)
ergodic_exploration::normalize_angle_2PI
double normalize_angle_2PI(double rad)
Wraps angle between 0 and 2pi or 0 to -2pi.
Definition: numerics.hpp:96
ergodic_exploration::constTwistPath
nav_msgs::Path constTwistPath(const std::string &map_frame_id, const vec &x0, const vec &u, double dt, double horizon)
Visualize path from following a constant twist.
Definition: numerics.hpp:340
ergodic_exploration::distance
double distance(double x0, double y0, double x1, double y1)
Euclidean distance between two points.
Definition: numerics.hpp:152
ergodic_exploration::integrate_twist
vec integrate_twist(const vec &x, const vec &u, double dt)
Integrate a constant twist.
Definition: numerics.hpp:273
ergodic_exploration::getYaw
double getYaw(double qx, double qy, double qz, double qw)
Get yaw from quaternion.
Definition: numerics.hpp:118
ergodic_exploration::normalize_angle_PI
double normalize_angle_PI(double rad)
Wraps angle between -pi and pi.
Definition: numerics.hpp:77
ergodic_exploration
Definition: basis.hpp:43
ergodic_exploration::GridMap
Constructs an 2D grid.
Definition: grid.hpp:79
Quaternion.h
ergodic_exploration::polar2Cartesian
vec polar2Cartesian(double angle, double range)
Convert polar to cartesian coordinates.
Definition: numerics.hpp:186
ergodic_exploration::almost_equal
bool almost_equal(double d1, double d2, double epsilon=1.0e-12)
approximately compare two floating-point numbers
Definition: numerics.hpp:67
ergodic_exploration::polar2CartesianHomo
vec polar2CartesianHomo(double angle, double range)
Convert polar to cartesian homogenous coordinates.
Definition: numerics.hpp:198
ergodic_exploration::transform2dInv
mat transform2dInv(const mat &trans2d)
Construct 2D transformation inverse.
Definition: numerics.hpp:252
ergodic_exploration::transform2d
mat transform2d(double x, double y, double angle)
Construct 2D transformation matrix.
Definition: numerics.hpp:212
tf2::Quaternion
ergodic_exploration::entropy
double entropy(double p)
Entropy of a single grid cell.
Definition: numerics.hpp:164
ergodic_exploration::Collision::collisionCheck
bool collisionCheck(const GridMap &grid, const vec &pose) const
Check if the given state is a collision.
Definition: collision.cpp:126
ergodic_exploration::PI
constexpr double PI
Definition: numerics.hpp:58
ergodic_exploration::Collision
2D collision detection
Definition: collision.hpp:85


ergodic_exploration
Author(s): bostoncleek
autogenerated on Wed Mar 2 2022 00:17:13