在看move_base源码时,有几处用到了 angles::shortest_angular_distance 以及angles::normalize_angle ,就查了下angle这个类,发现是ros中的一个名称为angles的软件包,就读了下源码。
一.函数功能说明
功能说明:该软件包提供了一组简单的数学实用程序来处理角度。 该实用程序涵盖了简单的事情,例如标准化角度以及度和弧度之间的转换 角度包含以下方法: 角度转换:angles :: from_degrees,angles :: to_degrees 标准化角度以及度和弧度之间的转换 角度操作:angles :: normalize_angle_positive,angles :: normalize_angle 角距:angles :: shortest_angular_distance,angles :: shortest_angular_distance_with_limits 角度工具:angles :: find_min_max_delta,angles :: two_pi_complement
程序说明,
1.from_degrees-角度转弧度
static inline double from_degrees(double degrees) {
return degrees * M_PI / 180.0;
}
2.to_degrees-弧度转角度
static inline double to_degrees(double radians) {
return radians * 180.0 / M_PI;
}
3.normalize_angle_positive-转换为[0,2PI]
static inline double normalize_angle_positive(double angle) {
const double result = fmod(angle, 2.0 * M_PI);
if (result < 0)
return result + 2.0 * M_PI;
return result;
}
3.normalize_angle-转换为[-PI,PI]
static inline double normalize_angle(double angle) {
const double result = fmod(angle + M_PI, 2.0 * M_PI);
if (result <= 0.0)
return result + M_PI;
return result - M_PI;
}
4.shortest_angular_distance-两角最小距离
static inline double shortest_angular_distance(double from, double to) {
return normalize_angle(to - from);
}
5.two_pi_complement-返回沿单位圆反向的角度
static inline double two_pi_complement(double angle) {
if (angle > 2 * M_PI || angle < -2.0 * M_PI)
angle = fmod(angle, 2.0 * M_PI);
if (angle < 0)
return (2 * M_PI + angle);
else if (angle > 0)
return (-2 * M_PI + angle);
return (2 * M_PI);
}
6.shortest_angular_distance_with_large_limits与shortest_angular_distance_with_limits
这两个主要是用来返回限定角度范围内的最小角间距 不太常用
#ifndef GEOMETRY_ANGLES_UTILS_H
#define GEOMETRY_ANGLES_UTILS_H
#include <algorithm>
#include <cmath>
namespace angles {
static bool find_min_max_delta(double from, double left_limit,
double right_limit, double &result_min_delta,
double &result_max_delta) {
double delta[4];
delta[0] = shortest_angular_distance(from, left_limit);
delta[1] = shortest_angular_distance(from, right_limit);
delta[2] = two_pi_complement(delta[0]);
delta[3] = two_pi_complement(delta[1]);
if (delta[0] == 0) {
result_min_delta = delta[0];
result_max_delta = std::max<double>(delta[1], delta[3]);
return true;
}
if (delta[1] == 0) {
result_max_delta = delta[1];
result_min_delta = std::min<double>(delta[0], delta[2]);
return true;
}
double delta_min = delta[0];
double delta_min_2pi = delta[2];
if (delta[2] < delta_min) {
delta_min = delta[2];
delta_min_2pi = delta[0];
}
double delta_max = delta[1];
double delta_max_2pi = delta[3];
if (delta[3] > delta_max) {
delta_max = delta[3];
delta_max_2pi = delta[1];
}
if ((delta_min <= delta_max_2pi) || (delta_max >= delta_min_2pi)) {
result_min_delta = delta_max_2pi;
result_max_delta = delta_min_2pi;
if (left_limit == -M_PI && right_limit == M_PI)
return true;
else
return false;
}
result_min_delta = delta_min;
result_max_delta = delta_max;
return true;
}
static inline bool shortest_angular_distance_with_large_limits(
double from, double to, double left_limit, double right_limit,
double &shortest_angle) {
double delta = shortest_angular_distance(from, to);
double delta_2pi = two_pi_complement(delta);
if (std::fabs(delta) > std::fabs(delta_2pi))
std::swap(delta, delta_2pi);
if (left_limit > right_limit) {
shortest_angle = delta;
return false;
}
double to2 = from + delta;
if (left_limit <= to2 && to2 <= right_limit) {
shortest_angle = delta;
return left_limit <= from && from <= right_limit;
}
to2 = from + delta_2pi;
if (left_limit <= to2 && to2 <= right_limit) {
shortest_angle = delta_2pi;
return left_limit <= from && from <= right_limit;
}
shortest_angle = delta;
return false;
}
static inline bool
shortest_angular_distance_with_limits(double from, double to, double left_limit,
double right_limit,
double &shortest_angle) {
double min_delta = -2 * M_PI;
double max_delta = 2 * M_PI;
double min_delta_to = -2 * M_PI;
double max_delta_to = 2 * M_PI;
bool flag =
find_min_max_delta(from, left_limit, right_limit, min_delta, max_delta);
double delta = shortest_angular_distance(from, to);
double delta_mod_2pi = two_pi_complement(delta);
if (flag)
{
if (delta >= min_delta && delta <= max_delta) {
shortest_angle = delta;
return true;
} else if (delta_mod_2pi >= min_delta && delta_mod_2pi <= max_delta) {
shortest_angle = delta_mod_2pi;
return true;
} else
{
find_min_max_delta(to, left_limit, right_limit, min_delta_to,
max_delta_to);
if (fabs(min_delta_to) < fabs(max_delta_to))
shortest_angle = std::max<double>(delta, delta_mod_2pi);
else if (fabs(min_delta_to) > fabs(max_delta_to))
shortest_angle = std::min<double>(delta, delta_mod_2pi);
else {
if (fabs(delta) < fabs(delta_mod_2pi))
shortest_angle = delta;
else
shortest_angle = delta_mod_2pi;
}
return false;
}
} else
{
find_min_max_delta(to, left_limit, right_limit, min_delta_to, max_delta_to);
if (fabs(min_delta) < fabs(max_delta))
shortest_angle = std::min<double>(delta, delta_mod_2pi);
else if (fabs(min_delta) > fabs(max_delta))
shortest_angle = std::max<double>(delta, delta_mod_2pi);
else {
if (fabs(delta) < fabs(delta_mod_2pi))
shortest_angle = delta;
else
shortest_angle = delta_mod_2pi;
}
return false;
}
shortest_angle = delta;
return false;
}
}
#endif
二.gtest 测试
功能包中提供了gtest测试实例 包括了C++版和python版
#include "angles/angles.h"
#include <gtest/gtest.h>
using namespace angles;
TEST(Angles, shortestDistanceWithLimits){
double shortest_angle;
bool result = angles::shortest_angular_distance_with_limits(-0.5, 0.5,-0.25,0.25,shortest_angle);
EXPECT_FALSE(result);
result = angles::shortest_angular_distance_with_limits(-0.5, 0.5,0.25,0.25,shortest_angle);
EXPECT_FALSE(result);
result = angles::shortest_angular_distance_with_limits(-0.5, 0.5,0.25,-0.25,shortest_angle);
EXPECT_TRUE(result);
EXPECT_NEAR(shortest_angle, -2*M_PI+1.0,1e-6);
result = angles::shortest_angular_distance_with_limits(0.5, 0.5,0.25,-0.25,shortest_angle);
EXPECT_TRUE(result);
EXPECT_NEAR(shortest_angle, 0,1e-6);
result = angles::shortest_angular_distance_with_limits(0.5, 0,0.25,-0.25,shortest_angle);
EXPECT_FALSE(result);
EXPECT_NEAR(shortest_angle, -0.5,1e-6);
result = angles::shortest_angular_distance_with_limits(-0.5, 0,0.25,-0.25,shortest_angle);
EXPECT_FALSE(result);
EXPECT_NEAR(shortest_angle, 0.5,1e-6);
result = angles::shortest_angular_distance_with_limits(-0.2,0.2,0.25,-0.25,shortest_angle);
EXPECT_FALSE(result);
EXPECT_NEAR(shortest_angle, -2*M_PI+0.4,1e-6);
result = angles::shortest_angular_distance_with_limits(0.2,-0.2,0.25,-0.25,shortest_angle);
EXPECT_FALSE(result);
EXPECT_NEAR(shortest_angle,2*M_PI-0.4,1e-6);
result = angles::shortest_angular_distance_with_limits(0.2,0,0.25,-0.25,shortest_angle);
EXPECT_FALSE(result);
EXPECT_NEAR(shortest_angle,2*M_PI-0.2,1e-6);
result = angles::shortest_angular_distance_with_limits(-0.2,0,0.25,-0.25,shortest_angle);
EXPECT_FALSE(result);
EXPECT_NEAR(shortest_angle,-2*M_PI+0.2,1e-6);
result = angles::shortest_angular_distance_with_limits(-0.25,-0.5,0.25,-0.25,shortest_angle);
EXPECT_TRUE(result);
EXPECT_NEAR(shortest_angle,-0.25,1e-6);
result = angles::shortest_angular_distance_with_limits(-0.25,0.5,0.25,-0.25,shortest_angle);
EXPECT_TRUE(result);
EXPECT_NEAR(shortest_angle,-2*M_PI+0.75,1e-6);
result = angles::shortest_angular_distance_with_limits(-0.2500001,0.5,0.25,-0.25,shortest_angle);
EXPECT_TRUE(result);
EXPECT_NEAR(shortest_angle,-2*M_PI+0.5+0.2500001,1e-6);
result = angles::shortest_angular_distance_with_limits(-0.6, 0.5,-0.25,0.25,shortest_angle);
EXPECT_FALSE(result);
result = angles::shortest_angular_distance_with_limits(-0.5, 0.6,-0.25,0.25,shortest_angle);
EXPECT_FALSE(result);
result = angles::shortest_angular_distance_with_limits(-0.6, 0.75,-0.25,0.3,shortest_angle);
EXPECT_FALSE(result);
result = angles::shortest_angular_distance_with_limits(-0.6, M_PI*3.0/4.0,-0.25,0.3,shortest_angle);
EXPECT_FALSE(result);
result = angles::shortest_angular_distance_with_limits(-M_PI, M_PI,-M_PI,M_PI,shortest_angle);
EXPECT_TRUE(result);
EXPECT_NEAR(shortest_angle,0.0,1e-6);
}
TEST(Angles, shortestDistanceWithLargeLimits)
{
double shortest_angle;
bool result;
result = angles::shortest_angular_distance_with_large_limits(0, 10.5*M_PI, -2*M_PI, 2*M_PI, shortest_angle);
EXPECT_TRUE(result);
EXPECT_NEAR(shortest_angle, 0.5*M_PI, 1e-6);
result = angles::shortest_angular_distance_with_large_limits(0, 10.5*M_PI, -2*M_PI, 0.1*M_PI, shortest_angle);
EXPECT_TRUE(result);
EXPECT_NEAR(shortest_angle, -1.5*M_PI, 1e-6);
result = angles::shortest_angular_distance_with_large_limits(2*M_PI, M_PI, 2*M_PI-0.1, 2*M_PI+0.1, shortest_angle);
EXPECT_FALSE(result);
result = angles::shortest_angular_distance_with_large_limits(10.5*M_PI, 0, -2*M_PI, 2*M_PI, shortest_angle);
EXPECT_FALSE(result);
result = angles::shortest_angular_distance_with_large_limits(0, 0.1, 2*M_PI, -2*M_PI, shortest_angle);
EXPECT_FALSE(result);
result = angles::shortest_angular_distance_with_large_limits(0.999507, 1.0, -20*M_PI, 20*M_PI, shortest_angle);
EXPECT_TRUE(result);
EXPECT_NEAR(shortest_angle, 0.000493, 1e-6);
}
TEST(Angles, from_degrees)
{
double epsilon = 1e-9;
EXPECT_NEAR(0, from_degrees(0), epsilon);
EXPECT_NEAR(M_PI/2, from_degrees(90), epsilon);
EXPECT_NEAR(M_PI, from_degrees(180), epsilon);
EXPECT_NEAR(M_PI*3/2, from_degrees(270), epsilon);
EXPECT_NEAR(2*M_PI, from_degrees(360), epsilon);
EXPECT_NEAR(M_PI/3, from_degrees(60), epsilon);
EXPECT_NEAR(M_PI*2/3, from_degrees(120), epsilon);
EXPECT_NEAR(M_PI/4, from_degrees(45), epsilon);
EXPECT_NEAR(M_PI*3/4, from_degrees(135), epsilon);
EXPECT_NEAR(M_PI/6, from_degrees(30), epsilon);
}
TEST(Angles, to_degrees)
{
double epsilon = 1e-9;
EXPECT_NEAR(to_degrees(0), 0, epsilon);
EXPECT_NEAR(to_degrees(M_PI/2), 90, epsilon);
EXPECT_NEAR(to_degrees(M_PI), 180, epsilon);
EXPECT_NEAR(to_degrees(M_PI*3/2), 270, epsilon);
EXPECT_NEAR(to_degrees(2*M_PI), 360, epsilon);
EXPECT_NEAR(to_degrees(M_PI/3), 60, epsilon);
EXPECT_NEAR(to_degrees(M_PI*2/3), 120, epsilon);
EXPECT_NEAR(to_degrees(M_PI/4), 45, epsilon);
EXPECT_NEAR(to_degrees(M_PI*3/4), 135, epsilon);
EXPECT_NEAR(to_degrees(M_PI/6), 30, epsilon);
}
TEST(Angles, normalize_angle_positive)
{
double epsilon = 1e-9;
EXPECT_NEAR(0, normalize_angle_positive(0), epsilon);
EXPECT_NEAR(M_PI, normalize_angle_positive(M_PI), epsilon);
EXPECT_NEAR(0, normalize_angle_positive(2*M_PI), epsilon);
EXPECT_NEAR(M_PI, normalize_angle_positive(3*M_PI), epsilon);
EXPECT_NEAR(0, normalize_angle_positive(4*M_PI), epsilon);
EXPECT_NEAR(0, normalize_angle_positive(-0), epsilon);
EXPECT_NEAR(M_PI, normalize_angle_positive(-M_PI), epsilon);
EXPECT_NEAR(0, normalize_angle_positive(-2*M_PI), epsilon);
EXPECT_NEAR(M_PI, normalize_angle_positive(-3*M_PI), epsilon);
EXPECT_NEAR(0, normalize_angle_positive(-4*M_PI), epsilon);
EXPECT_NEAR(0, normalize_angle_positive(-0), epsilon);
EXPECT_NEAR(3*M_PI/2, normalize_angle_positive(-M_PI/2), epsilon);
EXPECT_NEAR(M_PI, normalize_angle_positive(-M_PI), epsilon);
EXPECT_NEAR(M_PI/2, normalize_angle_positive(-3*M_PI/2), epsilon);
EXPECT_NEAR(0, normalize_angle_positive(-4*M_PI/2), epsilon);
EXPECT_NEAR(0, normalize_angle_positive(0), epsilon);
EXPECT_NEAR(M_PI/2, normalize_angle_positive(M_PI/2), epsilon);
EXPECT_NEAR(M_PI/2, normalize_angle_positive(5*M_PI/2), epsilon);
EXPECT_NEAR(M_PI/2, normalize_angle_positive(9*M_PI/2), epsilon);
EXPECT_NEAR(M_PI/2, normalize_angle_positive(-3*M_PI/2), epsilon);
}
TEST(Angles, normalize_angle)
{
double epsilon = 1e-9;
EXPECT_NEAR(0, normalize_angle(0), epsilon);
EXPECT_NEAR(M_PI, normalize_angle(M_PI), epsilon);
EXPECT_NEAR(0, normalize_angle(2*M_PI), epsilon);
EXPECT_NEAR(M_PI, normalize_angle(3*M_PI), epsilon);
EXPECT_NEAR(0, normalize_angle(4*M_PI), epsilon);
EXPECT_NEAR(0, normalize_angle(-0), epsilon);
EXPECT_NEAR(M_PI, normalize_angle(-M_PI), epsilon);
EXPECT_NEAR(0, normalize_angle(-2*M_PI), epsilon);
EXPECT_NEAR(M_PI, normalize_angle(-3*M_PI), epsilon);
EXPECT_NEAR(0, normalize_angle(-4*M_PI), epsilon);
EXPECT_NEAR(0, normalize_angle(-0), epsilon);
EXPECT_NEAR(-M_PI/2, normalize_angle(-M_PI/2), epsilon);
EXPECT_NEAR(M_PI, normalize_angle(-M_PI), epsilon);
EXPECT_NEAR(M_PI/2, normalize_angle(-3*M_PI/2), epsilon);
EXPECT_NEAR(0, normalize_angle(-4*M_PI/2), epsilon);
EXPECT_NEAR(0, normalize_angle(0), epsilon);
EXPECT_NEAR(M_PI/2, normalize_angle(M_PI/2), epsilon);
EXPECT_NEAR(M_PI/2, normalize_angle(5*M_PI/2), epsilon);
EXPECT_NEAR(M_PI/2, normalize_angle(9*M_PI/2), epsilon);
EXPECT_NEAR(M_PI/2, normalize_angle(-3*M_PI/2), epsilon);
}
TEST(Angles, shortest_angular_distance)
{
double epsilon = 1e-9;
EXPECT_NEAR(M_PI/2, shortest_angular_distance(0, M_PI/2), epsilon);
EXPECT_NEAR(-M_PI/2, shortest_angular_distance(0, -M_PI/2), epsilon);
EXPECT_NEAR(-M_PI/2, shortest_angular_distance(M_PI/2, 0), epsilon);
EXPECT_NEAR(M_PI/2, shortest_angular_distance(-M_PI/2, 0), epsilon);
EXPECT_NEAR(-M_PI/2, shortest_angular_distance(M_PI, M_PI/2), epsilon);
EXPECT_NEAR(M_PI/2, shortest_angular_distance(M_PI, -M_PI/2), epsilon);
EXPECT_NEAR(M_PI/2, shortest_angular_distance(M_PI/2, M_PI), epsilon);
EXPECT_NEAR(-M_PI/2, shortest_angular_distance(-M_PI/2, M_PI), epsilon);
EXPECT_NEAR(-M_PI/2, shortest_angular_distance(5*M_PI, M_PI/2), epsilon);
EXPECT_NEAR(M_PI/2, shortest_angular_distance(7*M_PI, -M_PI/2), epsilon);
EXPECT_NEAR(M_PI/2, shortest_angular_distance(9*M_PI/2, M_PI), epsilon);
EXPECT_NEAR(M_PI/2, shortest_angular_distance(-3*M_PI/2, M_PI), epsilon);
EXPECT_NEAR(-M_PI/2, shortest_angular_distance(-3*M_PI/4, 3*M_PI/4), epsilon);
EXPECT_NEAR(M_PI/2, shortest_angular_distance(3*M_PI/4, -3*M_PI/4), epsilon);
}
TEST(Angles, two_pi_complement)
{
double epsilon = 1e-9;
EXPECT_NEAR(two_pi_complement(0), 2*M_PI, epsilon);
EXPECT_NEAR(two_pi_complement(2*M_PI), 0, epsilon);
EXPECT_NEAR(two_pi_complement(-2*M_PI), 0, epsilon);
EXPECT_NEAR(two_pi_complement(2*M_PI-epsilon), -epsilon, epsilon);
EXPECT_NEAR(two_pi_complement(-2*M_PI+epsilon), epsilon, epsilon);
EXPECT_NEAR(two_pi_complement(M_PI/2), -3*M_PI/2, epsilon);
EXPECT_NEAR(two_pi_complement(M_PI), -M_PI, epsilon);
EXPECT_NEAR(two_pi_complement(-M_PI), M_PI, epsilon);
EXPECT_NEAR(two_pi_complement(-M_PI/2), 3*M_PI/2, epsilon);
EXPECT_NEAR(two_pi_complement(3*M_PI), -M_PI, epsilon);
EXPECT_NEAR(two_pi_complement(-3.0*M_PI), M_PI, epsilon);
EXPECT_NEAR(two_pi_complement(-5.0*M_PI/2.0), 3*M_PI/2, epsilon);
}
TEST(Angles, find_min_max_delta)
{
double epsilon = 1e-9;
double min_delta, max_delta;
EXPECT_TRUE(find_min_max_delta( 0, -M_PI, M_PI, min_delta, max_delta));
EXPECT_NEAR(min_delta, -M_PI, epsilon);
EXPECT_NEAR(max_delta, M_PI, epsilon);
EXPECT_TRUE(find_min_max_delta( M_PI/2, -M_PI, M_PI, min_delta, max_delta));
EXPECT_NEAR(min_delta, -3*M_PI/2, epsilon);
EXPECT_NEAR(max_delta, M_PI/2, epsilon);
EXPECT_TRUE(find_min_max_delta( -M_PI/2, -M_PI, M_PI, min_delta, max_delta));
EXPECT_NEAR(min_delta, -M_PI/2, epsilon);
EXPECT_NEAR(max_delta, 3*M_PI/2, epsilon);
EXPECT_TRUE(find_min_max_delta( 0, -M_PI/2, M_PI/2, min_delta, max_delta));
EXPECT_NEAR(min_delta, -M_PI/2, epsilon);
EXPECT_NEAR(max_delta, M_PI/2, epsilon);
EXPECT_TRUE(find_min_max_delta( M_PI/4, -M_PI/2, M_PI/2, min_delta, max_delta));
EXPECT_NEAR(min_delta, -3*M_PI/4, epsilon);
EXPECT_NEAR(max_delta, M_PI/4, epsilon);
EXPECT_TRUE(find_min_max_delta( -M_PI/4, -M_PI/2, M_PI/2, min_delta, max_delta));
EXPECT_NEAR(min_delta, -M_PI/4, epsilon);
EXPECT_NEAR(max_delta, 3*M_PI/4, epsilon);
EXPECT_TRUE(find_min_max_delta( -M_PI, -M_PI, M_PI, min_delta, max_delta));
EXPECT_TRUE((fabs(min_delta) <= epsilon && fabs(max_delta - 2*M_PI) <= epsilon) || (fabs(min_delta+2*M_PI) <= epsilon && fabs(max_delta) <= epsilon));
EXPECT_NEAR(min_delta, 0.0, epsilon);
EXPECT_NEAR(max_delta, 2*M_PI, epsilon);
EXPECT_TRUE(find_min_max_delta(-0.25,0.25,-0.25,min_delta, max_delta));
EXPECT_NEAR(min_delta, -2*M_PI+0.5, epsilon);
EXPECT_NEAR(max_delta, 0.0, epsilon);
EXPECT_TRUE(find_min_max_delta( M_PI-epsilon, -M_PI, M_PI, min_delta, max_delta));
EXPECT_NEAR(min_delta, -2*M_PI+epsilon, epsilon);
EXPECT_NEAR(max_delta, epsilon, epsilon);
EXPECT_TRUE(find_min_max_delta( -M_PI, -M_PI, M_PI, min_delta, max_delta));
EXPECT_NEAR(min_delta, 0, epsilon);
EXPECT_NEAR(max_delta, 2*M_PI, epsilon);
EXPECT_TRUE(find_min_max_delta( -M_PI/2, -M_PI/2, M_PI/2, min_delta, max_delta));
EXPECT_NEAR(min_delta, 0.0, epsilon);
EXPECT_NEAR(max_delta, M_PI, epsilon);
EXPECT_FALSE(find_min_max_delta( -M_PI, -M_PI/2, M_PI/2, min_delta, max_delta));
EXPECT_FALSE(find_min_max_delta( M_PI, -M_PI/2, M_PI/2, min_delta, max_delta));
EXPECT_TRUE(find_min_max_delta( 3*M_PI/4, M_PI/2, -M_PI/2, min_delta, max_delta));
EXPECT_NEAR(min_delta, -M_PI/4, epsilon);
EXPECT_NEAR(max_delta, 3*M_PI/4, epsilon);
}
int main(int argc, char **argv){
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
测试结果
三.用法说明
该包在安装ROS的时候已经默认安装了,所以在CMakelist中 添加包依赖后可直接包含头文件 在CMakelist中 添加包依赖
find_package(catkin REQUIRED
COMPONENTS
angles
)
包含头文件
#include <angles/angles.h>
使用其中的函数 如 shortest_angular_distance
double dist_left = std::fabs(angles::shortest_angular_distance(current_angle, start_angle))
|