Corentin Chauvin-Hameau – 2019-2020
Coverage Path Planning for an underwater robot surveying a marine farm
common.hpp
Go to the documentation of this file.
1 /**
2  * @file
3  *
4  * \brief Declaration of common functions
5  * \author Corentin Chauvin-Hameau
6  * \date 2020
7  */
8 
9 #ifndef COMMON_HPP
10 #define COMMON_HPP
11 
12 #include "mf_common/EulerPose.h"
13 #include <geometry_msgs/TransformStamped.h>
14 #include <geometry_msgs/Pose.h>
15 #include <geometry_msgs/Quaternion.h>
16 #include <geometry_msgs/Point.h>
17 #include <tf2/LinearMath/Matrix3x3.h>
18 #include <tf2/LinearMath/Vector3.h>
19 #include <tf2_geometry_msgs/tf2_geometry_msgs.h>
20 #include <eigen3/Eigen/Dense>
21 
22 
23 namespace mfcpp {
24 
25 /**
26  * \brief Converts a TransformStamped message to a Pose message
27  */
28 inline geometry_msgs::Pose to_pose(const geometry_msgs::TransformStamped &transform)
29 {
30  geometry_msgs::Pose pose;
31  pose.position.x = transform.transform.translation.x;
32  pose.position.y = transform.transform.translation.y;
33  pose.position.z = transform.transform.translation.z;
34  pose.orientation.x = transform.transform.rotation.x;
35  pose.orientation.y = transform.transform.rotation.y;
36  pose.orientation.z = transform.transform.rotation.z;
37  pose.orientation.w = transform.transform.rotation.w;
38 
39  return pose;
40 }
41 
42 /**
43  * \brief Brings back an angle into [-pi, pi)
44  */
45 template <class T>
46 inline T modulo_2pi(T angle)
47 {
48  while (angle >= M_PI && angle < -M_PI) {
49  if (angle >= M_PI)
50  angle -= 2*M_PI;
51  else
52  angle += 2*M_PI;
53  }
54 
55  return angle;
56 }
57 
58 /**
59  * \brief Computes the square of the euclidean distance between two positions
60  */
61 inline float distance2(const geometry_msgs::Point &p1, const geometry_msgs::Point &p2)
62 {
63  return pow(p1.x-p2.x, 2) + pow(p1.y-p2.y, 2) + pow(p1.z-p2.z, 2);
64 }
65 
66 /**
67  * \brief Computes the the euclidean distance between two positions
68  */
69 inline float distance(const geometry_msgs::Point &p1, const geometry_msgs::Point &p2)
70 {
71  return sqrt(distance2(p1, p2));
72 }
73 
74 /**
75  * \brief Computes the the euclidean distance between the position of two poses
76  */
77 inline float distance(const geometry_msgs::Pose &p1, const geometry_msgs::Pose &p2)
78 {
79  return distance(p1.position, p2.position);
80 }
81 
82 /**
83  * \brief Interpolates linearily two poses
84  *
85  * The position is linearily interpolated, the orientation is interpolated using
86  * Spherical Linear Interpolation.
87  *
88  * \param pose1 First pose
89  * \param pose2 Second pose
90  * \param t Interpolation coefficient
91  * \return Interpolated pose
92  */
93 inline geometry_msgs::Pose interpolate(
94  const geometry_msgs::Pose &pose1,
95  const geometry_msgs::Pose &pose2,
96  float t)
97 {
98  geometry_msgs::Pose new_pose;
99 
100  // Interpolate position
101  tf2::Vector3 p1, p2;
102  tf2::convert(pose1.position, p1);
103  tf2::convert(pose2.position, p2);
104  tf2::toMsg(p1 + (p2-p1) * t, new_pose.position);
105 
106  // Interpolate orientation
107  tf2::Quaternion q1, q2;
108  tf2::convert(pose1.orientation, q1);
109  tf2::convert(pose2.orientation, q2);
110  tf2::convert(slerp(q1, q2, t), new_pose.orientation);
111 
112  return new_pose;
113 }
114 
115 /**
116  * \brief Spherical Linear Interpolation of two quaternions
117  *
118  * Adapted from Wikipedia: https://en.wikipedia.org/wiki/Slerp
119  *
120  * \param q0 First quaternion
121  * \param q1 Second quaternion
122  * \param t Interpolation coefficient
123  */
124 inline tf2::Quaternion slerp(
125  const tf2::Quaternion &q0,
126  const tf2::Quaternion &q1,
127  float t)
128 {
129  // Convert the quaternions into tf2 datatypes
130  tf2::Quaternion v0, v1;
131  tf2::convert(q0, v0);
132  tf2::convert(q1, v1);
133 
134  // Only unit quaternions are valid rotations.
135  // Normalize to avoid undefined behavior.
136  v0.normalize();
137  v1.normalize();
138 
139  // Compute the cosine of the angle between the two vectors.
140  double dot = v0.dot(v1);
141 
142  // If the dot product is negative, slerp won't take
143  // the shorter path. Note that v1 and -v1 are equivalent when
144  // the negation is applied to all four components. Fix by
145  // reversing one quaternion.
146  if (dot < 0.0f) {
147  v1 *= -1.0;
148  dot = -dot;
149  }
150 
151  const double DOT_THRESHOLD = 0.9995;
152  if (dot > DOT_THRESHOLD) {
153  // If the inputs are too close for comfort, linearly interpolate
154  // and normalize the result.
155  tf2::Quaternion result = v0 + (v1 - v0) * t;
156  result.normalize();
157  return result;
158  }
159 
160  // Since dot is in range [0, DOT_THRESHOLD], acos is safe
161  double theta_0 = acos(dot); // theta_0 = angle between input vectors
162  double theta = theta_0*t; // theta = angle between v0 and result
163  double sin_theta = sin(theta); // compute this value only once
164  double sin_theta_0 = sin(theta_0); // compute this value only once
165 
166  double s0 = cos(theta) - dot * sin_theta / sin_theta_0; // == sin(theta_0 - theta) / sin(theta_0)
167  double s1 = sin_theta / sin_theta_0;
168 
169  return (v0 * s0) + (v1 * s1);
170 }
171 
172 /**
173  * \brief Converts a quaternion to Roll-Pitch-Yaw Euler angles
174  *
175  * \param[in] quat Quaternion to convert
176  * \param[out] roll Resulting roll angle
177  * \param[out] pitch Resulting pitch angle
178  * \param[out] yaw Resulting yaw angle
179  */
180 inline void to_euler(const tf2::Quaternion &quat, double &roll, double &pitch, double &yaw)
181 {
182  tf2::Matrix3x3(quat).getRPY(roll, pitch, yaw);
183 }
184 
185 /**
186  * \brief Converts a quaternion to Roll-Pitch-Yaw Euler angles
187  *
188  * \param[in] quat Quaternion to convert
189  * \param[out] roll Resulting roll angle
190  * \param[out] pitch Resulting pitch angle
191  * \param[out] yaw Resulting yaw angle
192  */
193 inline void to_euler(const geometry_msgs::Quaternion &quat, double &roll, double &pitch, double &yaw)
194 {
195  tf2::Quaternion _quat(quat.x, quat.y, quat.z, quat.w);
196  to_euler(_quat, roll, pitch, yaw);
197 }
198 
199 /**
200  * \brief Converts Roll-Pitch-Yaw Euler angles to a quaternion
201  *
202  * \param[in] roll Roll angle to convert
203  * \param[in] pitch Pitch angle to convert
204  * \param[in] yaw Yaw angle to convert
205  * \param[out] quat Resulting quaternion
206  */
207 inline void to_quaternion(double roll, double pitch, double yaw, tf2::Quaternion &quat)
208 {
209  quat.setRPY(roll, pitch, yaw);
210 }
211 
212 /**
213  * \brief Converts Roll-Pitch-Yaw Euler angles to a quaternion
214  *
215  * \param[in] roll Roll angle to convert
216  * \param[in] pitch Pitch angle to convert
217  * \param[in] yaw Yaw angle to convert
218  * \param[out] quat Resulting quaternion
219  */
220 inline void to_quaternion(double roll, double pitch, double yaw, geometry_msgs::Quaternion &quat)
221 {
222  tf2::Quaternion _quat;
223  _quat.setRPY(roll, pitch, yaw);
224  tf2::convert(_quat, quat);
225 }
226 
227 /**
228  * \brief Converts Axis-angle to a quaternion
229  *
230  * \param[in] x X coordinate of the axis vector
231  * \param[in] y Y coordinate of the axis vector
232  * \param[in] z Z coordinate of the axis vector
233  * \param[in] angle Angle around the axis vector
234  * \param[out] quat Resulting quaternion
235  */
236 inline void to_quaternion(
237  float x, float y, float z, float angle,
238  geometry_msgs::Quaternion &quat)
239 {
240  tf2::Vector3 vect(x, y, z);
241  tf2::Quaternion _quat(vect, angle);
242  tf2::convert(_quat, quat);
243 }
244 
245 /**
246  * \brief Get orientation vector (x vector of the frame) given by Roll-Pitch-Yaw
247  *
248  * VectorT can be either Eigen::Vector3f or Eigen::Vector3d
249  *
250  * \param[in] roll Roll angle to convert
251  * \param[in] pitch Pitch angle to convert
252  * \param[in] yaw Yaw angle to convert
253  * \param[out] orientation Resulting orientation
254  */
255 template <class VectorT>
256 inline void get_orientation(float roll, float pitch, float yaw, VectorT &orientation)
257 {
258  tf2::Matrix3x3 mat;
259  mat.setRPY(roll, pitch, yaw);
260  tf2::Vector3 column = mat.getColumn(0);
261 
262  orientation << column.getX(), column.getY(), column.getZ();
263 }
264 
265 
266 /**
267  * \brief Computes the difference between two poses
268  *
269  * \param[in] p1 First pose
270  * \param[in] p2 Second pose
271  * \param[out] diff Difference between p1 and p2
272  */
273 inline void diff_pose(
274  const geometry_msgs::Pose &p1,
275  const geometry_msgs::Pose &p2,
276  geometry_msgs::Pose &diff)
277 {
278  diff.position.x = p1.position.x - p2.position.x;
279  diff.position.y = p1.position.y - p2.position.y;
280  diff.position.z = p1.position.z - p2.position.z;
281 
282  double roll1, pitch1, yaw1;
283  double roll2, pitch2, yaw2;
284  to_euler(p1.orientation, roll1, pitch1, yaw1);
285  to_euler(p2.orientation, roll2, pitch2, yaw2);
286  to_quaternion(roll1 - roll2, pitch1 - pitch2, yaw1 - yaw2, diff.orientation);
287 }
288 
289 
290 /**
291  * \brief Computes the difference between two poses
292  *
293  * \param[in] p1 First pose
294  * \param[in] p2 Second pose
295  * \param[out] diff Difference between p1 and p2
296  */
297 inline void diff_pose(
298  const geometry_msgs::Pose &p1,
299  const geometry_msgs::Pose &p2,
300  mf_common::EulerPose &diff)
301 {
302  diff.x = p1.position.x - p2.position.x;
303  diff.y = p1.position.y - p2.position.y;
304  diff.z = p1.position.z - p2.position.z;
305 
306  double roll1, pitch1, yaw1;
307  double roll2, pitch2, yaw2;
308  to_euler(p1.orientation, roll1, pitch1, yaw1);
309  to_euler(p2.orientation, roll2, pitch2, yaw2);
310  diff.roll = roll1 - roll2;
311  diff.pitch = pitch1 - pitch2;
312  diff.yaw = yaw1 - yaw2;
313 }
314 
315 /**
316  * \brief Fills a Eigen DiagonalMatrix from a std::Vector
317  *
318  * \param[in] v Vector containing the diagonal terms of the matrix
319  * \param[out] D Diagonal matrix to fill
320  */
321 template <class T>
322 inline void fill_diag_mat(
323  const std::vector<T> &v,
324  Eigen::DiagonalMatrix<T, Eigen::Dynamic> &D)
325 {
326  Eigen::Matrix<T, Eigen::Dynamic, 1> vec(v.size());
327 
328  for (int k = 0; k < v.size(); k++)
329  vec(k) = v[k];
330 
331  D = vec.asDiagonal();
332 }
333 
334 /**
335  * \brief Fills a Eigen matrix from a std::Vector
336  *
337  * \param[in] v Vector containing the diagonal terms of the matrix
338  * \param[out] D Square diagonal matrix to fill
339  */
340 template <class T, class MatrixT>
341 inline void fill_diag_mat(
342  const std::vector<T> &v,
343  MatrixT &D)
344 {
345  int n = v.size();
346  D = MatrixT::Zero(n, n);
347 
348  for (int k = 0; k < n; k++) {
349  D(k, k) = v[k];
350  }
351 }
352 
353 
354 } // namespace mfcpp
355 
356 #endif
Definition: common.hpp:23
void diff_pose(const geometry_msgs::Pose &p1, const geometry_msgs::Pose &p2, geometry_msgs::Pose &diff)
Computes the difference between two poses.
Definition: common.hpp:273
void to_quaternion(double roll, double pitch, double yaw, tf2::Quaternion &quat)
Converts Roll-Pitch-Yaw Euler angles to a quaternion.
Definition: common.hpp:207
geometry_msgs::Pose interpolate(const geometry_msgs::Pose &pose1, const geometry_msgs::Pose &pose2, float t)
Interpolates linearily two poses.
Definition: common.hpp:93
float distance(const geometry_msgs::Point &p1, const geometry_msgs::Point &p2)
Computes the the euclidean distance between two positions.
Definition: common.hpp:69
void fill_diag_mat(const std::vector< T > &v, Eigen::DiagonalMatrix< T, Eigen::Dynamic > &D)
Fills a Eigen DiagonalMatrix from a std::Vector.
Definition: common.hpp:322
tf2::Quaternion slerp(const tf2::Quaternion &q0, const tf2::Quaternion &q1, float t)
Spherical Linear Interpolation of two quaternions.
Definition: common.hpp:124
float distance2(const geometry_msgs::Point &p1, const geometry_msgs::Point &p2)
Computes the square of the euclidean distance between two positions.
Definition: common.hpp:61
geometry_msgs::Pose to_pose(const geometry_msgs::TransformStamped &transform)
Converts a TransformStamped message to a Pose message.
Definition: common.hpp:28
T modulo_2pi(T angle)
Brings back an angle into [-pi, pi)
Definition: common.hpp:46
void get_orientation(float roll, float pitch, float yaw, VectorT &orientation)
Get orientation vector (x vector of the frame) given by Roll-Pitch-Yaw.
Definition: common.hpp:256
void to_euler(const tf2::Quaternion &quat, double &roll, double &pitch, double &yaw)
Converts a quaternion to Roll-Pitch-Yaw Euler angles.
Definition: common.hpp:180