common.h
Go to the documentation of this file.
1 /*
2  * Copyright 2015 Fadri Furrer, ASL, ETH Zurich, Switzerland
3  * Copyright 2015 Michael Burri, ASL, ETH Zurich, Switzerland
4  * Copyright 2015 Markus Achtelik, ASL, ETH Zurich, Switzerland
5  * Copyright 2015 Helen Oleynikova, ASL, ETH Zurich, Switzerland
6  * Copyright 2015 Mina Kamel, ASL, ETH Zurich, Switzerland
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13 
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 // Common conversion functions between geometry messages, Eigen types, and yaw.
22 
23 #ifndef MAV_MSGS_COMMON_H
24 #define MAV_MSGS_COMMON_H
25 
26 #include <geometry_msgs/Point.h>
27 #include <geometry_msgs/Quaternion.h>
28 #include <geometry_msgs/Vector3.h>
29 #include <Eigen/Geometry>
30 #include <boost/algorithm/clamp.hpp>
31 
32 namespace mav_msgs {
33 
34 const double kSmallValueCheck = 1.e-6;
35 const double kNumNanosecondsPerSecond = 1.e9;
36 
39 inline double MagnitudeOfGravity(const double height,
40  const double latitude_radians) {
41  // gravity calculation constants
42  const double kGravity_0 = 9.780327;
43  const double kGravity_a = 0.0053024;
44  const double kGravity_b = 0.0000058;
45  const double kGravity_c = 3.155 * 1e-7;
46 
47  double sin_squared_latitude = std::sin(latitude_radians) * std::sin(latitude_radians);
48  double sin_squared_twice_latitude =
49  std::sin(2 * latitude_radians) * std::sin(2 * latitude_radians);
50  return kGravity_0 * ((1 + kGravity_a * sin_squared_latitude -
51  kGravity_b * sin_squared_twice_latitude) -
52  kGravity_c * height);
53 }
54 
55 inline Eigen::Vector3d vector3FromMsg(const geometry_msgs::Vector3& msg) {
56  return Eigen::Vector3d(msg.x, msg.y, msg.z);
57 }
58 
59 inline Eigen::Vector3d vector3FromPointMsg(const geometry_msgs::Point& msg) {
60  return Eigen::Vector3d(msg.x, msg.y, msg.z);
61 }
62 
63 inline Eigen::Quaterniond quaternionFromMsg(
64  const geometry_msgs::Quaternion& msg) {
65  // Make sure this always returns a valid Quaternion, even if the message was
66  // uninitialized or only approximately set.
67  Eigen::Quaterniond quaternion(msg.w, msg.x, msg.y, msg.z);
68  if (quaternion.norm() < std::numeric_limits<double>::epsilon()) {
69  quaternion.setIdentity();
70  } else {
71  quaternion.normalize();
72  }
73  return quaternion;
74 }
75 
76 inline void vectorEigenToMsg(const Eigen::Vector3d& eigen,
77  geometry_msgs::Vector3* msg) {
78  assert(msg != NULL);
79  msg->x = eigen.x();
80  msg->y = eigen.y();
81  msg->z = eigen.z();
82 }
83 
84 inline void pointEigenToMsg(const Eigen::Vector3d& eigen,
85  geometry_msgs::Point* msg) {
86  assert(msg != NULL);
87  msg->x = eigen.x();
88  msg->y = eigen.y();
89  msg->z = eigen.z();
90 }
91 
92 inline void quaternionEigenToMsg(const Eigen::Quaterniond& eigen,
93  geometry_msgs::Quaternion* msg) {
94  assert(msg != NULL);
95  msg->x = eigen.x();
96  msg->y = eigen.y();
97  msg->z = eigen.z();
98  msg->w = eigen.w();
99 }
100 
107 inline double yawFromQuaternion(const Eigen::Quaterniond& q) {
108  return std::atan2(2.0 * (q.w() * q.z() + q.x() * q.y()),
109  1.0 - 2.0 * (q.y() * q.y() + q.z() * q.z()));
110 }
111 
112 inline Eigen::Quaterniond quaternionFromYaw(double yaw) {
113  return Eigen::Quaterniond(Eigen::AngleAxisd(yaw, Eigen::Vector3d::UnitZ()));
114 }
115 
116 inline void setQuaternionMsgFromYaw(double yaw,
117  geometry_msgs::Quaternion* msg) {
118  assert(msg != NULL);
119  Eigen::Quaterniond q_yaw = quaternionFromYaw(yaw);
120  msg->x = q_yaw.x();
121  msg->y = q_yaw.y();
122  msg->z = q_yaw.z();
123  msg->w = q_yaw.w();
124 }
125 
126 inline void setAngularVelocityMsgFromYawRate(double yaw_rate,
127  geometry_msgs::Vector3* msg) {
128  assert(msg != NULL);
129  msg->x = 0.0;
130  msg->y = 0.0;
131  msg->z = yaw_rate;
132 }
133 
134 inline void getEulerAnglesFromQuaternion(const Eigen::Quaternion<double>& q,
135  Eigen::Vector3d* euler_angles) {
136  {
137  assert(euler_angles != NULL);
138 
139  *euler_angles << std::atan2(2.0 * (q.w() * q.x() + q.y() * q.z()),
140  1.0 - 2.0 * (q.x() * q.x() + q.y() * q.y())),
141  std::asin(2.0 * (q.w() * q.y() - q.z() * q.x())),
142  std::atan2(2.0 * (q.w() * q.z() + q.x() * q.y()),
143  1.0 - 2.0 * (q.y() * q.y() + q.z() * q.z()));
144  }
145 }
146 
147 inline void skewMatrixFromVector(const Eigen::Vector3d& vec,
148  Eigen::Matrix3d* vec_skew) {
149  assert(vec_skew);
150  *vec_skew << 0.0f, -vec(2), vec(1), vec(2), 0.0f, -vec(0), -vec(1), vec(0),
151  0.0f;
152 }
153 
154 inline bool vectorFromSkewMatrix(const Eigen::Matrix3d& vec_skew,
155  Eigen::Vector3d* vec) {
156  assert(vec);
157  if ((vec_skew + vec_skew.transpose()).norm() < kSmallValueCheck){
158  *vec << vec_skew(2,1), vec_skew(0,2), vec_skew(1,0);
159  return true;
160  } else {
161  std::cerr << "[mav_msgs] Matrix is not skew-symmetric." << std::endl;
162  *vec = Eigen::Vector3d::Zero();
163  return false;
164  }
165 }
166 
167 inline bool isRotationMatrix(const Eigen::Matrix3d& mat){
168  // Check that R^T * R = I
169  if ((mat.transpose() * mat - Eigen::Matrix3d::Identity()).norm() > kSmallValueCheck){
170  std::cerr << "[mav_msgs::common] Rotation matrix requirement violated (R^T * R = I)" << std::endl;
171  return false;
172  }
173  // Check that det(R) = 1
174  if (mat.determinant() - 1.0 > kSmallValueCheck){
175  std::cerr << "[mav_msgs::common] Rotation matrix requirement violated (det(R) = 1)" << std::endl;
176  return false;
177  }
178  return true;
179 }
180 
181 // Rotation matrix from rotation vector as described in
182 // "Computationally Efficient Trajectory Generation for Fully Actuated Multirotor Vehicles"
183 // Brescianini 2018
184 inline void matrixFromRotationVector(const Eigen::Vector3d& vec,
185  Eigen::Matrix3d* mat) {
186  // R = (I + sin||r|| / ||r||) [r] + ((1 - cos||r||)/||r||^2) [r]^2
187  // where [r] is the skew matrix of r vector
188  assert(mat);
189  double r_norm = vec.norm();
190  Eigen::Matrix3d vec_skew_norm = Eigen::Matrix3d::Zero();
191  if (r_norm > 0.0){
192  skewMatrixFromVector(vec / r_norm, &vec_skew_norm);
193  }
194 
195  *mat = Eigen::Matrix3d::Identity() + vec_skew_norm * std::sin(r_norm) +
196  vec_skew_norm * vec_skew_norm * (1 - std::cos(r_norm));
197 }
198 
199 // Rotation vector from rotation matrix as described in
200 // "Computationally Efficient Trajectory Generation for Fully Actuated Multirotor Vehicles"
201 // Brescianini 2018
202 inline bool vectorFromRotationMatrix(const Eigen::Matrix3d& mat,
203  Eigen::Vector3d* vec) {
204  // [r] = phi / 2sin(phi) * (R - R^T)
205  // where [r] is the skew matrix of r vector
206  // and phi satisfies 1 + 2cos(phi) = trace(R)
207  assert(vec);
208 
209  if (!isRotationMatrix(mat)){
210  std::cerr << "[mav_msgs::common] Not a rotation matrix." << std::endl;
211  return false;
212  }
213 
214  if ((mat - Eigen::Matrix3d::Identity()).norm() < kSmallValueCheck){
215  *vec = Eigen::Vector3d::Zero();
216  return true;
217  }
218 
219  // Compute cosine of angle and clamp in range [-1, 1]
220  double cos_phi = (mat.trace() - 1.0) / 2.0;
221  double cos_phi_clamped = boost::algorithm::clamp(cos_phi, -1.0, 1.0);
222  double phi = std::acos(cos_phi_clamped);
223 
224  if (phi < kSmallValueCheck){
225  *vec = Eigen::Vector3d::Zero();
226  } else{
227  Eigen::Matrix3d vec_skew = (mat - mat.transpose()) * phi / (2.0 * std::sin(phi));
228  Eigen::Vector3d vec_unskewed;
229  if (vectorFromSkewMatrix(vec_skew, &vec_unskewed)){
230  *vec = vec_unskewed;
231  }else{
232  return false;
233  }
234 
235  }
236  return true;
237 }
238 
239 // Calculates angular velocity (omega) from rotation vector derivative
240 // based on formula derived in "Finite rotations and angular velocity" by Asher
241 // Peres
242 inline Eigen::Vector3d omegaFromRotationVector(
243  const Eigen::Vector3d& rot_vec, const Eigen::Vector3d& rot_vec_vel)
244 {
245  double phi = rot_vec.norm();
246  if (std::abs(phi) < 1.0e-3) {
247  // This captures the case of zero rotation
248  return rot_vec_vel;
249  }
250 
251  double phi_inv = 1.0 / phi;
252  double phi_2_inv = phi_inv / phi;
253  double phi_3_inv = phi_2_inv / phi;
254 
255  // Create skew-symmetric matrix from rotation vector
256  Eigen::Matrix3d phi_skew;
257  skewMatrixFromVector(rot_vec, &phi_skew);
258 
259  // Set up matrix to calculate omega
260  Eigen::Matrix3d W;
261  W = Eigen::MatrixXd::Identity(3, 3) + phi_skew * (1 - std::cos(phi)) * phi_2_inv +
262  phi_skew * phi_skew * (phi - std::sin(phi)) * phi_3_inv;
263  return W * rot_vec_vel;
264 }
265 
266 // Calculates angular acceleration (omegaDot) from rotation vector derivative
267 // based on formula derived in "Finite rotations and angular velocity" by Asher
268 // Peres
269 inline Eigen::Vector3d omegaDotFromRotationVector(
270  const Eigen::Vector3d& rot_vec, const Eigen::Vector3d& rot_vec_vel,
271  const Eigen::Vector3d& rot_vec_acc)
272 {
273  double phi = rot_vec.norm();
274  if (std::abs(phi) < 1.0e-3) {
275  // This captures the case of zero rotation
276  return rot_vec_acc;
277  }
278 
279  double phi_dot = rot_vec.dot(rot_vec_vel) / phi;
280 
281  double phi_inv = 1.0 / phi;
282  double phi_2_inv = phi_inv / phi;
283  double phi_3_inv = phi_2_inv / phi;
284  double phi_4_inv = phi_3_inv / phi;
285 
286 
287  // Create skew-symmetric matrix from rotation vector and velocity
288  Eigen::Matrix3d phi_skew;
289  Eigen::Matrix3d phi_dot_skew;
290 
291  skewMatrixFromVector(rot_vec, &phi_skew);
292  skewMatrixFromVector(rot_vec_vel, &phi_dot_skew);
293 
294  // Set up matrices to calculate omega dot
295  Eigen::Matrix3d W_vel;
296  Eigen::Matrix3d W_acc;
297  W_vel = phi_skew * (phi * std::sin(phi) - 2.0f + 2.0f * std::cos(phi)) * phi_dot *
298  phi_3_inv +
299  phi_skew * phi_skew *
300  (-2.0f * phi - phi * std::cos(phi) + 3.0f * std::sin(phi)) * phi_dot *
301  phi_4_inv +
302  phi_dot_skew * phi_skew * (phi - std::sin(phi)) * phi_3_inv;
303 
304  W_acc = Eigen::MatrixXd::Identity(3, 3) +
305  phi_skew * (1.0f - std::cos(phi)) * phi_2_inv +
306  phi_skew * phi_skew * (phi - std::sin(phi)) * phi_3_inv;
307 
308  return W_vel * rot_vec_vel + W_acc * rot_vec_acc;
309 }
310 
311 // Calculate the nominal rotor rates given the MAV mass, allocation matrix,
312 // angular velocity, angular acceleration, and body acceleration (normalized
313 // thrust).
314 //
315 // [torques, thrust]' = A * n^2, where
316 // torques = J * ang_acc + ang_vel x J
317 // thrust = m * norm(acc)
318 //
319 // The allocation matrix A has of a hexacopter is:
320 // A = K * B, where
321 // K = diag(l*c_T, l*c_T, c_M, c_T),
322 // [ s 1 s -s -1 -s]
323 // B = [-c 0 c c 0 -c]
324 // [-1 1 -1 1 -1 1]
325 // [ 1 1 1 1 1 1],
326 // l: arm length
327 // c_T: thrust constant
328 // c_M: moment constant
329 // s: sin(30°)
330 // c: cos(30°)
331 //
332 // The inverse can be computed computationally efficient:
333 // A^-1 \approx B^pseudo * K^-1
335  const Eigen::MatrixXd& allocation_inv, const Eigen::Vector3d& inertia,
336  double mass, const Eigen::Vector3d& angular_velocity_B,
337  const Eigen::Vector3d& angular_acceleration_B,
338  const Eigen::Vector3d& acceleration_B,
339  Eigen::VectorXd* rotor_rates_squared) {
340  const Eigen::Vector3d torque =
341  inertia.asDiagonal() * angular_acceleration_B +
342  angular_velocity_B.cross(inertia.asDiagonal() * angular_velocity_B);
343  const double thrust_force = mass * acceleration_B.norm();
344  Eigen::Vector4d input;
345  input << torque, thrust_force;
346  *rotor_rates_squared = allocation_inv * input;
347 }
348 
349 inline double nanosecondsToSeconds(int64_t nanoseconds) {
350  double seconds = nanoseconds / kNumNanosecondsPerSecond;
351  return seconds;
352 }
353 
354 inline int64_t secondsToNanoseconds(double seconds) {
355  int64_t nanoseconds =
356  static_cast<int64_t>(seconds * kNumNanosecondsPerSecond);
357  return nanoseconds;
358 }
359 
360 } // namespace mav_msgs
361 
362 #endif // MAV_MSGS_COMMON_H
void quaternionEigenToMsg(const Eigen::Quaterniond &eigen, geometry_msgs::Quaternion *msg)
Definition: common.h:92
double MagnitudeOfGravity(const double height, const double latitude_radians)
Definition: common.h:39
bool vectorFromRotationMatrix(const Eigen::Matrix3d &mat, Eigen::Vector3d *vec)
Definition: common.h:202
void setAngularVelocityMsgFromYawRate(double yaw_rate, geometry_msgs::Vector3 *msg)
Definition: common.h:126
Eigen::Vector3d omegaFromRotationVector(const Eigen::Vector3d &rot_vec, const Eigen::Vector3d &rot_vec_vel)
Definition: common.h:242
void getSquaredRotorSpeedsFromAllocationAndState(const Eigen::MatrixXd &allocation_inv, const Eigen::Vector3d &inertia, double mass, const Eigen::Vector3d &angular_velocity_B, const Eigen::Vector3d &angular_acceleration_B, const Eigen::Vector3d &acceleration_B, Eigen::VectorXd *rotor_rates_squared)
Definition: common.h:334
void skewMatrixFromVector(const Eigen::Vector3d &vec, Eigen::Matrix3d *vec_skew)
Definition: common.h:147
Eigen::Vector3d vector3FromMsg(const geometry_msgs::Vector3 &msg)
Definition: common.h:55
void setQuaternionMsgFromYaw(double yaw, geometry_msgs::Quaternion *msg)
Definition: common.h:116
const double kNumNanosecondsPerSecond
Definition: common.h:35
void getEulerAnglesFromQuaternion(const Eigen::Quaternion< double > &q, Eigen::Vector3d *euler_angles)
Definition: common.h:134
bool vectorFromSkewMatrix(const Eigen::Matrix3d &vec_skew, Eigen::Vector3d *vec)
Definition: common.h:154
bool isRotationMatrix(const Eigen::Matrix3d &mat)
Definition: common.h:167
int64_t secondsToNanoseconds(double seconds)
Definition: common.h:354
double nanosecondsToSeconds(int64_t nanoseconds)
Definition: common.h:349
double yawFromQuaternion(const Eigen::Quaterniond &q)
Extracts the yaw part from a quaternion, using RPY / euler (z-y&#39;-z&#39;&#39;) angles. RPY rotates about the f...
Definition: common.h:107
void vectorEigenToMsg(const Eigen::Vector3d &eigen, geometry_msgs::Vector3 *msg)
Definition: common.h:76
Eigen::Quaterniond quaternionFromMsg(const geometry_msgs::Quaternion &msg)
Definition: common.h:63
const double kSmallValueCheck
Definition: common.h:34
Eigen::Vector3d vector3FromPointMsg(const geometry_msgs::Point &msg)
Definition: common.h:59
Eigen::Quaterniond quaternionFromYaw(double yaw)
Definition: common.h:112
void matrixFromRotationVector(const Eigen::Vector3d &vec, Eigen::Matrix3d *mat)
Definition: common.h:184
Eigen::Vector3d omegaDotFromRotationVector(const Eigen::Vector3d &rot_vec, const Eigen::Vector3d &rot_vec_vel, const Eigen::Vector3d &rot_vec_acc)
Definition: common.h:269
void pointEigenToMsg(const Eigen::Vector3d &eigen, geometry_msgs::Point *msg)
Definition: common.h:84


mav_msgs
Author(s): Simon Lynen, Markus Achtelik, Pascal Gohl, Sammy Omari, Michael Burri, Fadri Furrer, Helen Oleynikova, Mina Kamel, Karen Bodie, Rik Bähnemann
autogenerated on Thu Jan 23 2020 03:14:00