2016-02-25 13:13:02 -04:00
|
|
|
#pragma once
|
2010-09-08 05:21:46 -03:00
|
|
|
|
2016-05-02 18:39:03 -03:00
|
|
|
#include <cmath>
|
2016-02-25 13:13:02 -04:00
|
|
|
#include <limits>
|
2016-05-02 18:39:03 -03:00
|
|
|
#include <stdint.h>
|
2016-02-25 13:13:02 -04:00
|
|
|
#include <type_traits>
|
2010-09-08 05:21:46 -03:00
|
|
|
|
2015-08-11 03:28:44 -03:00
|
|
|
#include <AP_Common/AP_Common.h>
|
|
|
|
#include <AP_Param/AP_Param.h>
|
2016-02-25 13:13:02 -04:00
|
|
|
|
2016-05-02 18:39:03 -03:00
|
|
|
#include "definitions.h"
|
2019-05-19 09:05:36 -03:00
|
|
|
#include "crc.h"
|
2016-05-02 18:39:03 -03:00
|
|
|
#include "matrix3.h"
|
|
|
|
#include "polygon.h"
|
|
|
|
#include "quaternion.h"
|
2012-03-09 22:44:36 -04:00
|
|
|
#include "rotations.h"
|
2010-09-08 05:21:46 -03:00
|
|
|
#include "vector2.h"
|
|
|
|
#include "vector3.h"
|
2018-03-23 01:08:34 -03:00
|
|
|
#include "spline5.h"
|
2019-03-11 14:15:09 -03:00
|
|
|
#include "location.h"
|
2014-04-03 19:44:56 -03:00
|
|
|
|
2012-02-17 19:00:26 -04:00
|
|
|
// define AP_Param types AP_Vector3f and Ap_Matrix3f
|
|
|
|
AP_PARAMDEFV(Vector3f, Vector3f, AP_PARAM_VECTOR3F);
|
2012-02-23 07:56:40 -04:00
|
|
|
|
2016-04-16 06:59:20 -03:00
|
|
|
/*
|
|
|
|
* Check whether two floats are equal
|
|
|
|
*/
|
2017-06-20 21:42:39 -03:00
|
|
|
template <typename Arithmetic1, typename Arithmetic2>
|
2016-12-17 14:16:39 -04:00
|
|
|
typename std::enable_if<std::is_integral<typename std::common_type<Arithmetic1, Arithmetic2>::type>::value ,bool>::type
|
|
|
|
is_equal(const Arithmetic1 v_1, const Arithmetic2 v_2);
|
|
|
|
|
2017-06-20 21:42:39 -03:00
|
|
|
template <typename Arithmetic1, typename Arithmetic2>
|
2016-12-17 14:16:39 -04:00
|
|
|
typename std::enable_if<std::is_floating_point<typename std::common_type<Arithmetic1, Arithmetic2>::type>::value, bool>::type
|
|
|
|
is_equal(const Arithmetic1 v_1, const Arithmetic2 v_2);
|
2015-04-28 03:06:13 -03:00
|
|
|
|
2016-05-16 15:14:55 -03:00
|
|
|
/*
|
|
|
|
* @brief: Check whether a float is zero
|
|
|
|
*/
|
2017-06-20 21:42:39 -03:00
|
|
|
template <typename T>
|
2016-05-16 15:14:55 -03:00
|
|
|
inline bool is_zero(const T fVal1) {
|
|
|
|
static_assert(std::is_floating_point<T>::value || std::is_base_of<T,AP_Float>::value,
|
|
|
|
"Template parameter not of type float");
|
2016-12-19 08:59:44 -04:00
|
|
|
return (fabsf(static_cast<float>(fVal1)) < FLT_EPSILON);
|
2016-05-16 15:14:55 -03:00
|
|
|
}
|
2016-04-16 06:59:08 -03:00
|
|
|
|
2017-05-18 23:47:56 -03:00
|
|
|
/*
|
|
|
|
* @brief: Check whether a float is greater than zero
|
|
|
|
*/
|
2017-06-20 21:42:39 -03:00
|
|
|
template <typename T>
|
2017-05-18 23:47:56 -03:00
|
|
|
inline bool is_positive(const T fVal1) {
|
|
|
|
static_assert(std::is_floating_point<T>::value || std::is_base_of<T,AP_Float>::value,
|
|
|
|
"Template parameter not of type float");
|
2017-05-26 21:20:10 -03:00
|
|
|
return (static_cast<float>(fVal1) >= FLT_EPSILON);
|
2017-05-18 23:47:56 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @brief: Check whether a float is less than zero
|
|
|
|
*/
|
2017-06-20 21:42:39 -03:00
|
|
|
template <typename T>
|
2017-05-18 23:47:56 -03:00
|
|
|
inline bool is_negative(const T fVal1) {
|
|
|
|
static_assert(std::is_floating_point<T>::value || std::is_base_of<T,AP_Float>::value,
|
|
|
|
"Template parameter not of type float");
|
2017-05-26 21:20:10 -03:00
|
|
|
return (static_cast<float>(fVal1) <= (-1.0 * FLT_EPSILON));
|
2017-05-18 23:47:56 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-16 06:59:08 -03:00
|
|
|
/*
|
|
|
|
* A variant of asin() that checks the input ranges and ensures a valid angle
|
|
|
|
* as output. If nan is given as input then zero is returned.
|
|
|
|
*/
|
2017-06-20 21:42:39 -03:00
|
|
|
template <typename T>
|
2016-04-16 06:59:08 -03:00
|
|
|
float safe_asin(const T v);
|
2012-02-23 19:40:56 -04:00
|
|
|
|
2016-04-16 06:59:08 -03:00
|
|
|
/*
|
|
|
|
* A variant of sqrt() that checks the input ranges and ensures a valid value
|
|
|
|
* as output. If a negative number is given then 0 is returned. The reasoning
|
|
|
|
* is that a negative number for sqrt() in our code is usually caused by small
|
|
|
|
* numerical rounding errors, so the real input should have been zero
|
|
|
|
*/
|
2017-06-20 21:42:39 -03:00
|
|
|
template <typename T>
|
2016-04-16 06:59:08 -03:00
|
|
|
float safe_sqrt(const T v);
|
2012-02-23 20:23:12 -04:00
|
|
|
|
2015-12-05 05:10:07 -04:00
|
|
|
// invOut is an inverted 4x4 matrix when returns true, otherwise matrix is Singular
|
2019-07-24 20:25:06 -03:00
|
|
|
bool inverse3x3(float m[], float invOut[]) WARN_IF_UNUSED;
|
2015-12-05 05:10:07 -04:00
|
|
|
|
|
|
|
// invOut is an inverted 3x3 matrix when returns true, otherwise matrix is Singular
|
2019-07-24 20:25:06 -03:00
|
|
|
bool inverse4x4(float m[],float invOut[]) WARN_IF_UNUSED;
|
2015-12-05 05:10:07 -04:00
|
|
|
|
2015-12-28 19:19:05 -04:00
|
|
|
// matrix multiplication of two NxN matrices
|
2016-05-03 21:32:49 -03:00
|
|
|
float *mat_mul(float *A, float *B, uint8_t n);
|
|
|
|
|
|
|
|
// matrix algebra
|
2019-07-24 20:25:06 -03:00
|
|
|
bool inverse(float x[], float y[], uint16_t dim) WARN_IF_UNUSED;
|
2015-12-28 19:19:05 -04:00
|
|
|
|
2013-03-28 23:13:37 -03:00
|
|
|
/*
|
2016-04-27 06:35:18 -03:00
|
|
|
* Constrain an angle to be within the range: -180 to 180 degrees. The second
|
|
|
|
* parameter changes the units. Default: 1 == degrees, 10 == dezi,
|
|
|
|
* 100 == centi.
|
2013-03-28 23:13:37 -03:00
|
|
|
*/
|
2017-06-20 21:42:39 -03:00
|
|
|
template <typename T>
|
2019-09-17 06:50:00 -03:00
|
|
|
T wrap_180(const T angle, T unit_mod = T(1));
|
2013-03-28 23:13:37 -03:00
|
|
|
|
2013-06-01 05:18:50 -03:00
|
|
|
/*
|
2016-04-27 06:35:18 -03:00
|
|
|
* Wrap an angle in centi-degrees. See wrap_180().
|
2013-06-01 05:18:50 -03:00
|
|
|
*/
|
2019-09-17 06:50:00 -03:00
|
|
|
inline float wrap_180_cd(const float angle) { return wrap_180(angle, float(100)); }
|
|
|
|
inline int32_t wrap_180_cd(const int32_t angle) { return wrap_180(int(angle), int(100)); }
|
|
|
|
#ifdef ALLOW_DOUBLE_MATH_FUNCTIONS
|
|
|
|
inline double wrap_180_cd(const double angle) { return wrap_180(angle, double(100)); }
|
|
|
|
#endif
|
2013-06-01 05:18:50 -03:00
|
|
|
|
2015-11-24 17:11:34 -04:00
|
|
|
/*
|
2016-04-27 06:35:18 -03:00
|
|
|
* Constrain an euler angle to be within the range: 0 to 360 degrees. The
|
|
|
|
* second parameter changes the units. Default: 1 == degrees, 10 == dezi,
|
|
|
|
* 100 == centi.
|
2015-11-24 17:11:34 -04:00
|
|
|
*/
|
2019-09-17 06:50:00 -03:00
|
|
|
float wrap_360(const float angle, float unit_mod = 1);
|
|
|
|
#ifdef ALLOW_DOUBLE_MATH_FUNCTIONS
|
|
|
|
double wrap_360(const double angle, double unit_mod = 1);
|
|
|
|
#endif
|
|
|
|
int wrap_360(const int angle, int unit_mod = 1);
|
|
|
|
|
|
|
|
inline int32_t wrap_360_cd(const int32_t angle) { return wrap_360(int(angle), int(100)); }
|
|
|
|
inline float wrap_360_cd(const float angle) { return wrap_360(angle, float(100)); }
|
|
|
|
#ifdef ALLOW_DOUBLE_MATH_FUNCTIONS
|
|
|
|
inline double wrap_360_cd(const double angle) { return wrap_360(angle, double(100)); }
|
|
|
|
#endif
|
2016-04-27 06:35:18 -03:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
wrap an angle in radians to -PI ~ PI (equivalent to +- 180 degrees)
|
|
|
|
*/
|
2017-06-20 21:42:39 -03:00
|
|
|
template <typename T>
|
2016-04-27 06:35:18 -03:00
|
|
|
float wrap_PI(const T radian);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* wrap an angle in radians to 0..2PI
|
|
|
|
*/
|
2017-06-20 21:42:39 -03:00
|
|
|
template <typename T>
|
2016-04-27 06:35:18 -03:00
|
|
|
float wrap_2PI(const T radian);
|
2015-11-24 17:11:34 -04:00
|
|
|
|
2016-04-16 06:58:58 -03:00
|
|
|
/*
|
|
|
|
* Constrain a value to be within the range: low and high
|
|
|
|
*/
|
2017-06-20 21:42:39 -03:00
|
|
|
template <typename T>
|
2016-04-16 06:58:58 -03:00
|
|
|
T constrain_value(const T amt, const T low, const T high);
|
2016-04-27 06:35:18 -03:00
|
|
|
|
2016-05-11 14:35:30 -03:00
|
|
|
inline float constrain_float(const float amt, const float low, const float high)
|
|
|
|
{
|
|
|
|
return constrain_value(amt, low, high);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline int16_t constrain_int16(const int16_t amt, const int16_t low, const int16_t high)
|
|
|
|
{
|
|
|
|
return constrain_value(amt, low, high);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline int32_t constrain_int32(const int32_t amt, const int32_t low, const int32_t high)
|
|
|
|
{
|
|
|
|
return constrain_value(amt, low, high);
|
|
|
|
}
|
2015-03-21 05:48:46 -03:00
|
|
|
|
2018-04-17 00:54:06 -03:00
|
|
|
inline int64_t constrain_int64(const int64_t amt, const int64_t low, const int64_t high)
|
|
|
|
{
|
|
|
|
return constrain_value(amt, low, high);
|
|
|
|
}
|
|
|
|
|
2012-12-18 22:33:52 -04:00
|
|
|
// degrees -> radians
|
2017-09-30 08:10:57 -03:00
|
|
|
static inline constexpr float radians(float deg)
|
2016-05-03 21:32:49 -03:00
|
|
|
{
|
|
|
|
return deg * DEG_TO_RAD;
|
2015-03-21 05:48:46 -03:00
|
|
|
}
|
2012-12-18 22:33:52 -04:00
|
|
|
|
|
|
|
// radians -> degrees
|
2017-09-30 08:10:57 -03:00
|
|
|
static inline constexpr float degrees(float rad)
|
2016-05-03 21:32:49 -03:00
|
|
|
{
|
|
|
|
return rad * RAD_TO_DEG;
|
2015-03-21 05:48:46 -03:00
|
|
|
}
|
2012-12-18 22:33:52 -04:00
|
|
|
|
2017-06-20 21:42:39 -03:00
|
|
|
template<typename T>
|
2016-04-16 06:58:46 -03:00
|
|
|
float sq(const T val)
|
|
|
|
{
|
2019-02-22 23:10:10 -04:00
|
|
|
float v = static_cast<float>(val);
|
|
|
|
return v*v;
|
2015-03-21 05:48:46 -03:00
|
|
|
}
|
|
|
|
|
2016-04-16 06:58:46 -03:00
|
|
|
/*
|
|
|
|
* Variadic template for calculating the square norm of a vector of any
|
|
|
|
* dimension.
|
|
|
|
*/
|
2017-06-20 21:42:39 -03:00
|
|
|
template<typename T, typename... Params>
|
2016-04-16 06:58:46 -03:00
|
|
|
float sq(const T first, const Params... parameters)
|
|
|
|
{
|
|
|
|
return sq(first) + sq(parameters...);
|
2015-03-21 05:48:46 -03:00
|
|
|
}
|
2012-12-18 22:33:52 -04:00
|
|
|
|
2016-04-16 06:58:46 -03:00
|
|
|
/*
|
|
|
|
* Variadic template for calculating the norm (pythagoras) of a vector of any
|
|
|
|
* dimension.
|
|
|
|
*/
|
2017-06-20 21:42:39 -03:00
|
|
|
template<typename T, typename U, typename... Params>
|
2017-06-20 21:32:55 -03:00
|
|
|
float norm(const T first, const U second, const Params... parameters)
|
2016-04-16 06:58:46 -03:00
|
|
|
{
|
2017-06-20 21:32:55 -03:00
|
|
|
return sqrtf(sq(first, second, parameters...));
|
2015-03-21 05:48:46 -03:00
|
|
|
}
|
2012-12-18 22:33:52 -04:00
|
|
|
|
AP_Math: turn MIN/MAX macros into inline functions
The problem with the current MIN/MAX macros is that they evaluate twice
the arguments. For example, these cases provide unintended results:
// a is incremented twice
a = MIN(a++, b);
// foo() with side-effects
a = MIN(foo(), b);
The alternative implementation here was provided by Daniel Frenzel using
template function. It doesn't have type safety as std::min and std::max,
but adding type safety would mean to check case by case what would be a
reasonable type and add proper casts. Here the arguments for MIN and MAX
can have different types and the return type is deduced from the
expression in the function.
Inspecting the current callers no place was found with the unintended
results above, but some in which now we don't calculate twice the
parameters will benefit from this new version. Examples:
float velocity_max = MIN(_pos_control.get_speed_xy(), safe_sqrt(0.5f*_pos_control.get_accel_xy()*_radius));
float acro_level_mix = constrain_float(1-MAX(MAX(abs(roll_in), abs(pitch_in)), abs(yaw_in))/4500.0, 0, 1)*ahrs.cos_pitch()
accel_x_cmss = (GRAVITY_MSS * 100) * (-(_ahrs.cos_yaw() * _ahrs.sin_pitch() / MAX(_ahrs.cos_pitch(),0.5f)) - _ahrs.sin_yaw() * _ahrs.sin_roll() / MAX(_ahrs.cos_roll(),0.5f));
track_leash_slack = MIN(_track_leash_length*(leash_z-track_error_z)/leash_z, _track_leash_length*(leash_xy-track_error_xy)/leash_xy);
RC_Channel_aux::move_servo(RC_Channel_aux::k_sprayer_pump, MIN(MAX(ground_speed * _pump_pct_1ms, 100 *_pump_min_pct),10000),0,10000);
2015-11-27 13:27:32 -04:00
|
|
|
template<typename A, typename B>
|
2016-05-03 21:32:49 -03:00
|
|
|
static inline auto MIN(const A &one, const B &two) -> decltype(one < two ? one : two)
|
|
|
|
{
|
AP_Math: turn MIN/MAX macros into inline functions
The problem with the current MIN/MAX macros is that they evaluate twice
the arguments. For example, these cases provide unintended results:
// a is incremented twice
a = MIN(a++, b);
// foo() with side-effects
a = MIN(foo(), b);
The alternative implementation here was provided by Daniel Frenzel using
template function. It doesn't have type safety as std::min and std::max,
but adding type safety would mean to check case by case what would be a
reasonable type and add proper casts. Here the arguments for MIN and MAX
can have different types and the return type is deduced from the
expression in the function.
Inspecting the current callers no place was found with the unintended
results above, but some in which now we don't calculate twice the
parameters will benefit from this new version. Examples:
float velocity_max = MIN(_pos_control.get_speed_xy(), safe_sqrt(0.5f*_pos_control.get_accel_xy()*_radius));
float acro_level_mix = constrain_float(1-MAX(MAX(abs(roll_in), abs(pitch_in)), abs(yaw_in))/4500.0, 0, 1)*ahrs.cos_pitch()
accel_x_cmss = (GRAVITY_MSS * 100) * (-(_ahrs.cos_yaw() * _ahrs.sin_pitch() / MAX(_ahrs.cos_pitch(),0.5f)) - _ahrs.sin_yaw() * _ahrs.sin_roll() / MAX(_ahrs.cos_roll(),0.5f));
track_leash_slack = MIN(_track_leash_length*(leash_z-track_error_z)/leash_z, _track_leash_length*(leash_xy-track_error_xy)/leash_xy);
RC_Channel_aux::move_servo(RC_Channel_aux::k_sprayer_pump, MIN(MAX(ground_speed * _pump_pct_1ms, 100 *_pump_min_pct),10000),0,10000);
2015-11-27 13:27:32 -04:00
|
|
|
return one < two ? one : two;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename A, typename B>
|
2016-05-03 21:32:49 -03:00
|
|
|
static inline auto MAX(const A &one, const B &two) -> decltype(one > two ? one : two)
|
|
|
|
{
|
AP_Math: turn MIN/MAX macros into inline functions
The problem with the current MIN/MAX macros is that they evaluate twice
the arguments. For example, these cases provide unintended results:
// a is incremented twice
a = MIN(a++, b);
// foo() with side-effects
a = MIN(foo(), b);
The alternative implementation here was provided by Daniel Frenzel using
template function. It doesn't have type safety as std::min and std::max,
but adding type safety would mean to check case by case what would be a
reasonable type and add proper casts. Here the arguments for MIN and MAX
can have different types and the return type is deduced from the
expression in the function.
Inspecting the current callers no place was found with the unintended
results above, but some in which now we don't calculate twice the
parameters will benefit from this new version. Examples:
float velocity_max = MIN(_pos_control.get_speed_xy(), safe_sqrt(0.5f*_pos_control.get_accel_xy()*_radius));
float acro_level_mix = constrain_float(1-MAX(MAX(abs(roll_in), abs(pitch_in)), abs(yaw_in))/4500.0, 0, 1)*ahrs.cos_pitch()
accel_x_cmss = (GRAVITY_MSS * 100) * (-(_ahrs.cos_yaw() * _ahrs.sin_pitch() / MAX(_ahrs.cos_pitch(),0.5f)) - _ahrs.sin_yaw() * _ahrs.sin_roll() / MAX(_ahrs.cos_roll(),0.5f));
track_leash_slack = MIN(_track_leash_length*(leash_z-track_error_z)/leash_z, _track_leash_length*(leash_xy-track_error_xy)/leash_xy);
RC_Channel_aux::move_servo(RC_Channel_aux::k_sprayer_pump, MIN(MAX(ground_speed * _pump_pct_1ms, 100 *_pump_min_pct),10000),0,10000);
2015-11-27 13:27:32 -04:00
|
|
|
return one > two ? one : two;
|
|
|
|
}
|
2012-12-18 22:33:52 -04:00
|
|
|
|
2015-10-27 13:07:07 -03:00
|
|
|
inline uint32_t hz_to_nsec(uint32_t freq)
|
|
|
|
{
|
2017-05-05 07:09:29 -03:00
|
|
|
return AP_NSEC_PER_SEC / freq;
|
2015-10-27 13:07:07 -03:00
|
|
|
}
|
|
|
|
|
2015-12-07 12:18:44 -04:00
|
|
|
inline uint32_t nsec_to_hz(uint32_t nsec)
|
2015-10-27 13:07:07 -03:00
|
|
|
{
|
2017-05-05 07:09:29 -03:00
|
|
|
return AP_NSEC_PER_SEC / nsec;
|
2015-10-27 13:07:07 -03:00
|
|
|
}
|
|
|
|
|
2015-10-27 13:07:51 -03:00
|
|
|
inline uint32_t usec_to_nsec(uint32_t usec)
|
|
|
|
{
|
2017-05-05 07:09:29 -03:00
|
|
|
return usec * AP_NSEC_PER_USEC;
|
2015-10-27 13:07:51 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
inline uint32_t nsec_to_usec(uint32_t nsec)
|
|
|
|
{
|
2017-05-05 07:09:29 -03:00
|
|
|
return nsec / AP_NSEC_PER_USEC;
|
2015-10-27 13:07:51 -03:00
|
|
|
}
|
|
|
|
|
2015-12-07 12:19:50 -04:00
|
|
|
inline uint32_t hz_to_usec(uint32_t freq)
|
|
|
|
{
|
2017-05-05 07:09:29 -03:00
|
|
|
return AP_USEC_PER_SEC / freq;
|
2015-12-07 12:19:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline uint32_t usec_to_hz(uint32_t usec)
|
|
|
|
{
|
2017-05-05 07:09:29 -03:00
|
|
|
return AP_USEC_PER_SEC / usec;
|
2015-12-07 12:19:50 -04:00
|
|
|
}
|
|
|
|
|
2016-04-02 08:44:47 -03:00
|
|
|
/*
|
|
|
|
linear interpolation based on a variable in a range
|
|
|
|
*/
|
|
|
|
float linear_interpolate(float low_output, float high_output,
|
|
|
|
float var_value,
|
|
|
|
float var_low, float var_high);
|
2016-11-17 01:23:11 -04:00
|
|
|
|
2019-04-06 15:38:40 -03:00
|
|
|
/* cubic "expo" curve generator
|
|
|
|
* alpha range: [0,1] min to max expo
|
|
|
|
* input range: [-1,1]
|
|
|
|
*/
|
|
|
|
float expo_curve(float alpha, float input);
|
|
|
|
|
|
|
|
/* throttle curve generator
|
|
|
|
* thr_mid: output at mid stick
|
|
|
|
* alpha: expo coefficient
|
|
|
|
* thr_in: [0-1]
|
|
|
|
*/
|
|
|
|
float throttle_curve(float thr_mid, float alpha, float thr_in);
|
|
|
|
|
2016-11-17 01:23:11 -04:00
|
|
|
/* simple 16 bit random number generator */
|
|
|
|
uint16_t get_random16(void);
|
|
|
|
|
2017-04-12 08:16:07 -03:00
|
|
|
// generate a random float between -1 and 1, for use in SITL
|
|
|
|
float rand_float(void);
|
|
|
|
|
2017-06-21 14:39:07 -03:00
|
|
|
// generate a random Vector3f of size 1
|
|
|
|
Vector3f rand_vec3f(void);
|
2018-05-22 14:33:07 -03:00
|
|
|
|
|
|
|
// confirm a value is a valid octal value
|
2019-07-24 20:25:06 -03:00
|
|
|
bool is_valid_octal(uint16_t octal) WARN_IF_UNUSED;
|
2018-05-22 14:33:07 -03:00
|
|
|
|
2018-10-01 00:04:11 -03:00
|
|
|
// return true if two rotations are equal
|
2019-07-24 20:25:06 -03:00
|
|
|
bool rotation_equal(enum Rotation r1, enum Rotation r2) WARN_IF_UNUSED;
|
2019-10-05 18:38:57 -03:00
|
|
|
|
|
|
|
#if CONFIG_HAL_BOARD == HAL_BOARD_SITL
|
|
|
|
// fill an array of float with NaN, used to invalidate memory in SITL
|
|
|
|
void fill_nanf(float *f, uint16_t count);
|
|
|
|
#endif
|