Initial import of FaRui Autoware Dual-Orin Stack
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(autoware_auto_common)
|
||||
|
||||
find_package(autoware_cmake REQUIRED)
|
||||
autoware_package()
|
||||
|
||||
find_package(Eigen3 REQUIRED)
|
||||
include_directories(SYSTEM ${EIGEN3_INCLUDE_DIR})
|
||||
|
||||
if(BUILD_TESTING)
|
||||
set(TEST_COMMON test_common_gtest)
|
||||
ament_add_ros_isolated_gtest(${TEST_COMMON}
|
||||
test/gtest_main.cpp
|
||||
test/test_bool_comparisons.cpp
|
||||
test/test_byte_reader.cpp
|
||||
test/test_float_comparisons.cpp
|
||||
test/test_mahalanobis_distance.cpp
|
||||
test/test_message_field_adapters.cpp
|
||||
test/test_template_utils.cpp
|
||||
test/test_angle_utils.cpp
|
||||
test/test_type_name.cpp
|
||||
test/test_type_traits.cpp
|
||||
)
|
||||
target_compile_options(${TEST_COMMON} PRIVATE -Wno-sign-conversion)
|
||||
target_include_directories(${TEST_COMMON} PRIVATE include)
|
||||
ament_target_dependencies(${TEST_COMMON}
|
||||
builtin_interfaces
|
||||
Eigen3
|
||||
geometry_msgs
|
||||
)
|
||||
endif()
|
||||
|
||||
ament_auto_package()
|
||||
@@ -0,0 +1,65 @@
|
||||
# Comparisons
|
||||
|
||||
The `float_comparisons.hpp` library is a simple set of functions for performing approximate numerical comparisons.
|
||||
There are separate functions for performing comparisons using absolute bounds and relative bounds. Absolute comparison checks are prefixed with `abs_` and relative checks are prefixed with `rel_`.
|
||||
|
||||
The `bool_comparisons.hpp` library additionally contains an XOR operator.
|
||||
|
||||
The intent of the library is to improve readability of code and reduce likelihood of typographical errors when using numerical and boolean comparisons.
|
||||
|
||||
## Target use cases
|
||||
|
||||
The approximate comparisons are intended to be used to check whether two numbers lie within some absolute or relative interval.
|
||||
The `exclusive_or` function will test whether two values cast to different boolean values.
|
||||
|
||||
## Assumptions
|
||||
|
||||
- The approximate comparisons all take an `epsilon` parameter.
|
||||
The value of this parameter must be >= 0.
|
||||
- The library is only intended to be used with floating point types.
|
||||
A static assertion will be thrown if the library is used with a non-floating point type.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```c++
|
||||
#include "autoware_auto_common/common/bool_comparisons.hpp"
|
||||
#include "autoware_auto_common/common/float_comparisons.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
// using-directive is just for illustration; don't do this in practice
|
||||
using namespace autoware::common::helper_functions::comparisons;
|
||||
|
||||
static constexpr auto epsilon = 0.2;
|
||||
static constexpr auto relative_epsilon = 0.01;
|
||||
|
||||
std::cout << exclusive_or(true, false) << "\n";
|
||||
// Prints: true
|
||||
|
||||
std::cout << rel_eq(1.0, 1.1, relative_epsilon)) << "\n";
|
||||
// Prints: false
|
||||
|
||||
std::cout << approx_eq(10000.0, 10010.0, epsilon, relative_epsilon)) << "\n";
|
||||
// Prints: true
|
||||
|
||||
std::cout << abs_eq(4.0, 4.2, epsilon) << "\n";
|
||||
// Prints: true
|
||||
|
||||
std::cout << abs_ne(4.0, 4.2, epsilon) << "\n";
|
||||
// Prints: false
|
||||
|
||||
std::cout << abs_eq_zero(0.2, epsilon) << "\n";
|
||||
// Prints: false
|
||||
|
||||
std::cout << abs_lt(4.0, 4.25, epsilon) << "\n";
|
||||
// Prints: true
|
||||
|
||||
std::cout << abs_lte(1.0, 1.2, epsilon) << "\n";
|
||||
// Prints: true
|
||||
|
||||
std::cout << abs_gt(1.25, 1.0, epsilon) << "\n";
|
||||
// Prints: true
|
||||
|
||||
std::cout << abs_gte(0.75, 1.0, epsilon) << "\n";
|
||||
// Prints: false
|
||||
```
|
||||
+222
@@ -0,0 +1,222 @@
|
||||
// Copyright 2021 Apex.AI, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Developed by Apex.AI, Inc.
|
||||
|
||||
#include "autoware_auto_common/common/types.hpp"
|
||||
#include "autoware_auto_common/common/visibility_control.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
#ifndef AUTOWARE_AUTO_COMMON__COMMON__TYPE_TRAITS_HPP_
|
||||
#define AUTOWARE_AUTO_COMMON__COMMON__TYPE_TRAITS_HPP_
|
||||
|
||||
namespace autoware
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace type_traits
|
||||
{
|
||||
|
||||
///
|
||||
/// @brief A helper function to be used in static_assert to indicate an impossible branch.
|
||||
///
|
||||
/// @details Typically used when a static_assert is used to guard a certain default
|
||||
/// implementation to never be executed and to show a helpful message to the user.
|
||||
///
|
||||
/// @tparam T Any type needed to delay the compilation of this function until it is used.
|
||||
///
|
||||
/// @return A boolean that should be false for any type passed into this function.
|
||||
///
|
||||
template <typename T>
|
||||
constexpr inline autoware::common::types::bool8_t COMMON_PUBLIC impossible_branch() noexcept
|
||||
{
|
||||
return sizeof(T) == 0;
|
||||
}
|
||||
|
||||
/// Find an index of a type in a tuple
|
||||
template <class QueryT, class TupleT>
|
||||
struct COMMON_PUBLIC index
|
||||
{
|
||||
static_assert(!std::is_same<TupleT, std::tuple<>>::value, "Could not find QueryT in given tuple");
|
||||
};
|
||||
|
||||
/// Specialization for a tuple that starts with the HeadT type. End of recursion.
|
||||
template <class HeadT, class... Tail>
|
||||
struct COMMON_PUBLIC index<HeadT, std::tuple<HeadT, Tail...>>
|
||||
: std::integral_constant<std::int32_t, 0>
|
||||
{
|
||||
};
|
||||
|
||||
/// Specialization for a tuple with a type different to QueryT that calls the recursive step.
|
||||
template <class QueryT, class HeadT, class... Tail>
|
||||
struct COMMON_PUBLIC index<QueryT, std::tuple<HeadT, Tail...>>
|
||||
: std::integral_constant<std::int32_t, 1 + index<QueryT, std::tuple<Tail...>>::value>
|
||||
{
|
||||
};
|
||||
|
||||
///
|
||||
/// @brief Visit every element in a tuple.
|
||||
///
|
||||
/// This specialization indicates the end of the recursive tuple traversal.
|
||||
///
|
||||
/// @tparam I Current index.
|
||||
/// @tparam Callable Callable type, usually a lambda with one auto input parameter.
|
||||
/// @tparam TypesT Types in the tuple.
|
||||
///
|
||||
/// @return Does not return anything. Capture variables in a lambda to return any values.
|
||||
///
|
||||
template <std::size_t I = 0UL, typename Callable, typename... TypesT>
|
||||
COMMON_PUBLIC inline constexpr typename std::enable_if_t<I == sizeof...(TypesT)> visit(
|
||||
std::tuple<TypesT...> &, Callable) noexcept
|
||||
{
|
||||
}
|
||||
/// @brief Same as the previous specialization but for const tuple.
|
||||
template <std::size_t I = 0UL, typename Callable, typename... TypesT>
|
||||
COMMON_PUBLIC inline constexpr typename std::enable_if_t<I == sizeof...(TypesT)> visit(
|
||||
const std::tuple<TypesT...> &, Callable) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
///
|
||||
/// @brief Visit every element in a tuple.
|
||||
///
|
||||
/// This specialization is used to apply the callable to an element of a tuple and
|
||||
/// recursively call this function on the next one.
|
||||
///
|
||||
/// @param tuple The tuple instance
|
||||
/// @param[in] callable A callable, usually a lambda with one auto input parameter.
|
||||
///
|
||||
/// @tparam I Current index.
|
||||
/// @tparam Callable Callable type, usually a lambda with one auto input parameter.
|
||||
/// @tparam TypesT Types in the tuple.
|
||||
///
|
||||
/// @return Does not return anything. Capture variables in a lambda to return any values.
|
||||
///
|
||||
template <std::size_t I = 0UL, typename Callable, typename... TypesT>
|
||||
COMMON_PUBLIC inline constexpr typename std::enable_if_t<I != sizeof...(TypesT)> visit(
|
||||
std::tuple<TypesT...> & tuple, Callable callable) noexcept
|
||||
{
|
||||
callable(std::get<I>(tuple));
|
||||
visit<I + 1UL, Callable, TypesT...>(tuple, callable);
|
||||
}
|
||||
/// @brief Same as the previous specialization but for const tuple.
|
||||
template <std::size_t I = 0UL, typename Callable, typename... TypesT>
|
||||
COMMON_PUBLIC inline constexpr typename std::enable_if_t<I != sizeof...(TypesT)> visit(
|
||||
const std::tuple<TypesT...> & tuple, Callable callable) noexcept
|
||||
{
|
||||
callable(std::get<I>(tuple));
|
||||
visit<I + 1UL, Callable, TypesT...>(tuple, callable);
|
||||
}
|
||||
|
||||
/// @brief A class to compute a conjunction over given traits.
|
||||
template <class...>
|
||||
struct COMMON_PUBLIC conjunction : std::true_type
|
||||
{
|
||||
};
|
||||
/// @brief A conjunction of another type shall derive from that type.
|
||||
template <class TraitT>
|
||||
struct COMMON_PUBLIC conjunction<TraitT> : TraitT
|
||||
{
|
||||
};
|
||||
template <class TraitT, class... TraitsTs>
|
||||
struct COMMON_PUBLIC conjunction<TraitT, TraitsTs...>
|
||||
: std::conditional_t<static_cast<bool>(TraitT::value), conjunction<TraitsTs...>, TraitT>
|
||||
{
|
||||
};
|
||||
|
||||
///
|
||||
/// @brief A trait to check if a tuple has a type.
|
||||
///
|
||||
/// @details Taken from https://stackoverflow.com/a/25958302/678093
|
||||
///
|
||||
/// @tparam QueryT A query type.
|
||||
/// @tparam TupleT A tuple to search the type in.
|
||||
///
|
||||
template <typename QueryT, typename TupleT>
|
||||
struct has_type;
|
||||
|
||||
///
|
||||
/// @brief An overload of the general trait that signifies that nothing can be found in an
|
||||
/// empty tuple.
|
||||
///
|
||||
/// @tparam QueryT Any type.
|
||||
///
|
||||
template <typename QueryT>
|
||||
struct has_type<QueryT, std::tuple<>> : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
///
|
||||
/// @brief Recursive override of the main trait.
|
||||
///
|
||||
/// @tparam QueryT Query type.
|
||||
/// @tparam HeadT Head type in the tuple.
|
||||
/// @tparam TailTs Rest of the tuple types.
|
||||
///
|
||||
template <typename QueryT, typename HeadT, typename... TailTs>
|
||||
struct has_type<QueryT, std::tuple<HeadT, TailTs...>> : has_type<QueryT, std::tuple<TailTs...>>
|
||||
{
|
||||
};
|
||||
|
||||
///
|
||||
/// @brief End of recursion for the main `has_type` trait. Becomes a `true_type` when the first
|
||||
/// type in the tuple matches the query type.
|
||||
///
|
||||
/// @tparam QueryT Query type.
|
||||
/// @tparam TailTs Other types in the tuple.
|
||||
///
|
||||
template <typename QueryT, typename... TailTs>
|
||||
struct has_type<QueryT, std::tuple<QueryT, TailTs...>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
///
|
||||
/// @brief A trait used to intersect types stored in tuples at compile time. The resulting
|
||||
/// typedef `type` will hold a tuple with the intersection of the types provided in the
|
||||
/// input tuples.
|
||||
///
|
||||
/// @details Taken from https://stackoverflow.com/a/41200732/1763680
|
||||
///
|
||||
/// @tparam TupleT1 Tuple 1
|
||||
/// @tparam TupleT2 Tuple 2
|
||||
///
|
||||
template <typename TupleT1, typename TupleT2>
|
||||
struct intersect
|
||||
{
|
||||
///
|
||||
/// @brief Intersect the types.
|
||||
///
|
||||
/// @details This function "iterates" over the types in TupleT1 and checks if those are in
|
||||
/// TupleT2. If this is true, these types are concatenated into a new tuple.
|
||||
///
|
||||
template <std::size_t... Indices>
|
||||
static constexpr auto make_intersection(std::index_sequence<Indices...>)
|
||||
{
|
||||
return std::tuple_cat(std::conditional_t<
|
||||
has_type<std::tuple_element_t<Indices, TupleT1>, TupleT2>::value,
|
||||
std::tuple<std::tuple_element_t<Indices, TupleT1>>, std::tuple<>>{}...);
|
||||
}
|
||||
/// The resulting tuple type.
|
||||
using type =
|
||||
decltype(make_intersection(std::make_index_sequence<std::tuple_size<TupleT1>::value>{}));
|
||||
};
|
||||
|
||||
} // namespace type_traits
|
||||
} // namespace common
|
||||
} // namespace autoware
|
||||
|
||||
#endif // AUTOWARE_AUTO_COMMON__COMMON__TYPE_TRAITS_HPP_
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
// Copyright 2017-2020 the Autoware Foundation, Arm Limited
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Co-developed by Tier IV, Inc. and Apex.AI, Inc.
|
||||
/// \file
|
||||
/// \brief This file includes common type definition
|
||||
|
||||
#ifndef AUTOWARE_AUTO_COMMON__COMMON__TYPES_HPP_
|
||||
#define AUTOWARE_AUTO_COMMON__COMMON__TYPES_HPP_
|
||||
|
||||
#include "autoware_auto_common/common/visibility_control.hpp"
|
||||
#include "autoware_auto_common/helper_functions/float_comparisons.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
namespace autoware
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace types
|
||||
{
|
||||
// Aliases to conform to MISRA C++ Rule 3-9-2 (Directive 4.6 in MISRA C).
|
||||
// Similarly, the stdint typedefs should be used instead of plain int, long etc. types.
|
||||
// We don't currently require code to comply to MISRA, but we should try to where it is
|
||||
// easily possible.
|
||||
using bool8_t = bool;
|
||||
#if __cplusplus < 201811L || !__cpp_char8_t
|
||||
using char8_t = char;
|
||||
#endif
|
||||
using uchar8_t = unsigned char;
|
||||
// If we ever compile on a platform where this is not true, float32_t and float64_t definitions
|
||||
// need to be adjusted.
|
||||
static_assert(sizeof(float) == 4, "float is assumed to be 32-bit");
|
||||
using float32_t = float;
|
||||
static_assert(sizeof(double) == 8, "double is assumed to be 64-bit");
|
||||
using float64_t = double;
|
||||
|
||||
/// pi = tau / 2
|
||||
constexpr float32_t PI = 3.14159265359F;
|
||||
/// pi/2
|
||||
constexpr float32_t PI_2 = 1.5707963267948966F;
|
||||
/// tau = 2 pi
|
||||
constexpr float32_t TAU = 6.283185307179586476925286766559F;
|
||||
|
||||
struct COMMON_PUBLIC PointXYZIF
|
||||
{
|
||||
float32_t x{0};
|
||||
float32_t y{0};
|
||||
float32_t z{0};
|
||||
float32_t intensity{0};
|
||||
uint16_t id{0};
|
||||
static constexpr uint16_t END_OF_SCAN_ID = 65535u;
|
||||
friend bool operator==(const PointXYZIF & p1, const PointXYZIF & p2) noexcept
|
||||
{
|
||||
using autoware::common::helper_functions::comparisons::rel_eq;
|
||||
const auto epsilon = std::numeric_limits<float32_t>::epsilon();
|
||||
return rel_eq(p1.x, p2.x, epsilon) && rel_eq(p1.y, p2.y, epsilon) &&
|
||||
rel_eq(p1.z, p2.z, epsilon) && rel_eq(p1.intensity, p2.intensity, epsilon) &&
|
||||
(p1.id == p2.id);
|
||||
}
|
||||
};
|
||||
|
||||
struct COMMON_PUBLIC PointXYZF
|
||||
{
|
||||
float32_t x{0};
|
||||
float32_t y{0};
|
||||
float32_t z{0};
|
||||
uint16_t id{0};
|
||||
static constexpr uint16_t END_OF_SCAN_ID = 65535u;
|
||||
friend bool operator==(const PointXYZF & p1, const PointXYZF & p2) noexcept
|
||||
{
|
||||
using autoware::common::helper_functions::comparisons::rel_eq;
|
||||
const auto epsilon = std::numeric_limits<float32_t>::epsilon();
|
||||
return rel_eq(p1.x, p2.x, epsilon) && rel_eq(p1.y, p2.y, epsilon) &&
|
||||
rel_eq(p1.z, p2.z, epsilon) && (p1.id == p2.id);
|
||||
}
|
||||
};
|
||||
|
||||
struct COMMON_PUBLIC PointXYZI
|
||||
{
|
||||
float32_t x{0.0F};
|
||||
float32_t y{0.0F};
|
||||
float32_t z{0.0F};
|
||||
float32_t intensity{0.0F};
|
||||
friend bool operator==(const PointXYZI & p1, const PointXYZI & p2) noexcept
|
||||
{
|
||||
return helper_functions::comparisons::rel_eq(
|
||||
p1.x, p2.x, std::numeric_limits<float32_t>::epsilon()) &&
|
||||
|
||||
helper_functions::comparisons::rel_eq(
|
||||
p1.y, p2.y, std::numeric_limits<float32_t>::epsilon()) &&
|
||||
|
||||
helper_functions::comparisons::rel_eq(
|
||||
p1.z, p2.z, std::numeric_limits<float32_t>::epsilon()) &&
|
||||
|
||||
helper_functions::comparisons::rel_eq(
|
||||
p1.intensity, p2.intensity, std::numeric_limits<float32_t>::epsilon());
|
||||
}
|
||||
};
|
||||
|
||||
using PointBlock = std::vector<PointXYZIF>;
|
||||
using PointPtrBlock = std::vector<const PointXYZIF *>;
|
||||
/// \brief Stores basic configuration information, does some simple validity checking
|
||||
static constexpr uint16_t POINT_BLOCK_CAPACITY = 512U;
|
||||
|
||||
// TODO(yunus.caliskan): switch to std::void_t when C++17 is available
|
||||
/// \brief `std::void_t<> implementation
|
||||
template <typename... Ts>
|
||||
using void_t = void;
|
||||
} // namespace types
|
||||
} // namespace common
|
||||
} // namespace autoware
|
||||
|
||||
#endif // AUTOWARE_AUTO_COMMON__COMMON__TYPES_HPP_
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
// Copyright 2017-2019 the Autoware Foundation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Co-developed by Tier IV, Inc. and Apex.AI, Inc.
|
||||
|
||||
#ifndef AUTOWARE_AUTO_COMMON__COMMON__VISIBILITY_CONTROL_HPP_
|
||||
#define AUTOWARE_AUTO_COMMON__COMMON__VISIBILITY_CONTROL_HPP_
|
||||
|
||||
#if defined(_MSC_VER) && defined(_WIN64)
|
||||
#if defined(COMMON_BUILDING_DLL) || defined(COMMON_EXPORTS)
|
||||
#define COMMON_PUBLIC __declspec(dllexport)
|
||||
#define COMMON_LOCAL
|
||||
#else // defined(COMMON_BUILDING_DLL) || defined(COMMON_EXPORTS)
|
||||
#define COMMON_PUBLIC __declspec(dllimport)
|
||||
#define COMMON_LOCAL
|
||||
#endif // defined(COMMON_BUILDING_DLL) || defined(COMMON_EXPORTS)
|
||||
#elif defined(__GNUC__) && defined(__linux__)
|
||||
#define COMMON_PUBLIC __attribute__((visibility("default")))
|
||||
#define COMMON_LOCAL __attribute__((visibility("hidden")))
|
||||
#elif defined(__GNUC__) && defined(__APPLE__)
|
||||
#define COMMON_PUBLIC __attribute__((visibility("default")))
|
||||
#define COMMON_LOCAL __attribute__((visibility("hidden")))
|
||||
#else // !(defined(__GNUC__) && defined(__APPLE__))
|
||||
#error "Unsupported Build Configuration"
|
||||
#endif // _MSC_VER
|
||||
|
||||
#endif // AUTOWARE_AUTO_COMMON__COMMON__VISIBILITY_CONTROL_HPP_
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
// Copyright 2020 Apex.AI, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Co-developed by Tier IV, Inc. and Apex.AI, Inc.
|
||||
|
||||
#ifndef AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__ANGLE_UTILS_HPP_
|
||||
#define AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__ANGLE_UTILS_HPP_
|
||||
|
||||
#include <cmath>
|
||||
#include <type_traits>
|
||||
|
||||
namespace autoware
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace helper_functions
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
constexpr auto kDoublePi = 2.0 * M_PI;
|
||||
} // namespace detail
|
||||
|
||||
///
|
||||
/// @brief Wrap angle to the [-pi, pi] range.
|
||||
///
|
||||
/// @details This method uses the formula suggested in the paper [On wrapping the Kalman filter
|
||||
/// and estimating with the SO(2) group](https://arxiv.org/pdf/1708.05551.pdf) and
|
||||
/// implements the following formula:
|
||||
/// \f$\mathrm{mod}(\alpha + \pi, 2 \pi) - \pi\f$.
|
||||
///
|
||||
/// @param[in] angle The input angle
|
||||
///
|
||||
/// @tparam T Type of scalar
|
||||
///
|
||||
/// @return Angle wrapped to the chosen range.
|
||||
///
|
||||
template <typename T>
|
||||
constexpr T wrap_angle(T angle) noexcept
|
||||
{
|
||||
auto help_angle = angle + T(M_PI);
|
||||
while (help_angle < T{}) {
|
||||
help_angle += T(detail::kDoublePi);
|
||||
}
|
||||
while (help_angle >= T(detail::kDoublePi)) {
|
||||
help_angle -= T(detail::kDoublePi);
|
||||
}
|
||||
return help_angle - T(M_PI);
|
||||
}
|
||||
|
||||
} // namespace helper_functions
|
||||
} // namespace common
|
||||
} // namespace autoware
|
||||
|
||||
#endif // AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__ANGLE_UTILS_HPP_
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
// Copyright 2020 Mapless AI, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
#ifndef AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__BOOL_COMPARISONS_HPP_
|
||||
#define AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__BOOL_COMPARISONS_HPP_
|
||||
|
||||
#include "autoware_auto_common/common/types.hpp"
|
||||
|
||||
namespace autoware
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace helper_functions
|
||||
{
|
||||
namespace comparisons
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Convenience method for performing logical exclusive or ops.
|
||||
* @return True iff exactly one of 'a' and 'b' is true.
|
||||
*/
|
||||
template <typename T>
|
||||
types::bool8_t exclusive_or(const T & a, const T & b)
|
||||
{
|
||||
return static_cast<types::bool8_t>(a) != static_cast<types::bool8_t>(b);
|
||||
}
|
||||
|
||||
} // namespace comparisons
|
||||
} // namespace helper_functions
|
||||
} // namespace common
|
||||
} // namespace autoware
|
||||
|
||||
#endif // AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__BOOL_COMPARISONS_HPP_
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
// Copyright 2017-2019 the Autoware Foundation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Co-developed by Tier IV, Inc. and Apex.AI, Inc.
|
||||
/// \file
|
||||
/// \brief This file includes common helper functions
|
||||
|
||||
#ifndef AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__BYTE_READER_HPP_
|
||||
#define AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__BYTE_READER_HPP_
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
namespace autoware
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace helper_functions
|
||||
{
|
||||
/// \brief A utility class to read byte vectors in big-endian order
|
||||
class ByteReader
|
||||
{
|
||||
private:
|
||||
const std::vector<uint8_t> & byte_vector_;
|
||||
std::size_t index_;
|
||||
|
||||
public:
|
||||
/// \brief Default constructor, byte reader class
|
||||
/// \param[in] byte_vector A vector to read bytes from
|
||||
explicit ByteReader(const std::vector<uint8_t> & byte_vector)
|
||||
: byte_vector_(byte_vector), index_(0U)
|
||||
{
|
||||
}
|
||||
|
||||
// brief Read bytes and store it in the argument passed in big-endian order
|
||||
/// \param[inout] value Read and store the bytes from the vector matching the size of the argument
|
||||
template <typename T>
|
||||
void read(T & value)
|
||||
{
|
||||
constexpr std::size_t kTypeSize = sizeof(T);
|
||||
union {
|
||||
T value;
|
||||
uint8_t byte_vector[kTypeSize];
|
||||
} tmp;
|
||||
|
||||
for (std::size_t i = 0; i < kTypeSize; ++i) {
|
||||
tmp.byte_vector[i] = byte_vector_[index_ + kTypeSize - 1 - i];
|
||||
}
|
||||
|
||||
value = tmp.value;
|
||||
|
||||
index_ += kTypeSize;
|
||||
}
|
||||
|
||||
void skip(std::size_t count) { index_ += count; }
|
||||
};
|
||||
} // namespace helper_functions
|
||||
} // namespace common
|
||||
} // namespace autoware
|
||||
|
||||
#endif // AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__BYTE_READER_HPP_
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
// Copyright 2017-2019 the Autoware Foundation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Co-developed by Tier IV, Inc. and Apex.AI, Inc.
|
||||
/// \file
|
||||
/// \brief This file includes common helper functions
|
||||
|
||||
#ifndef AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__CRTP_HPP_
|
||||
#define AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__CRTP_HPP_
|
||||
|
||||
namespace autoware
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace helper_functions
|
||||
{
|
||||
template <typename Derived>
|
||||
class crtp
|
||||
{
|
||||
protected:
|
||||
const Derived & impl() const
|
||||
{
|
||||
// This is the CRTP pattern for static polymorphism: this is related, static_cast is the only
|
||||
// way to do this
|
||||
// lint -e{9005, 9176, 1939} NOLINT
|
||||
return *static_cast<const Derived *>(this);
|
||||
}
|
||||
|
||||
Derived & impl()
|
||||
{
|
||||
// This is the CRTP pattern for static polymorphism: this is related, static_cast is the only
|
||||
// way to do this
|
||||
// lint -e{9005, 9176, 1939} NOLINT
|
||||
return *static_cast<Derived *>(this);
|
||||
}
|
||||
};
|
||||
} // namespace helper_functions
|
||||
} // namespace common
|
||||
} // namespace autoware
|
||||
|
||||
#endif // AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__CRTP_HPP_
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
// Copyright 2020 Mapless AI, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
#ifndef AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__FLOAT_COMPARISONS_HPP_
|
||||
#define AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__FLOAT_COMPARISONS_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
namespace autoware
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace helper_functions
|
||||
{
|
||||
namespace comparisons
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Check for approximate equality in absolute terms.
|
||||
* @pre eps >= 0
|
||||
* @return True iff 'a' and 'b' are within 'eps' of each other.
|
||||
*/
|
||||
template <typename T>
|
||||
bool abs_eq(const T & a, const T & b, const T & eps)
|
||||
{
|
||||
static_assert(
|
||||
std::is_floating_point<T>::value, "Float comparisons only support floating point types.");
|
||||
|
||||
return std::abs(a - b) <= eps;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check for approximate less than in absolute terms.
|
||||
* @pre eps >= 0
|
||||
* @return True iff 'a' is less than 'b' minus 'eps'.
|
||||
*/
|
||||
template <typename T>
|
||||
bool abs_lt(const T & a, const T & b, const T & eps)
|
||||
{
|
||||
return !abs_eq(a, b, eps) && (a < b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check for approximate less than or equal in absolute terms.
|
||||
* @pre eps >= 0
|
||||
* @return True iff 'a' is less than or equal to 'b' plus 'eps'.
|
||||
*/
|
||||
template <typename T>
|
||||
bool abs_lte(const T & a, const T & b, const T & eps)
|
||||
{
|
||||
return abs_eq(a, b, eps) || (a < b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check for approximate greater than or equal in absolute terms.
|
||||
* @pre eps >= 0
|
||||
* @return True iff 'a' is greater than or equal to 'b' minus 'eps'.
|
||||
*/
|
||||
template <typename T>
|
||||
bool abs_gte(const T & a, const T & b, const T & eps)
|
||||
{
|
||||
return !abs_lt(a, b, eps);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check for approximate greater than in absolute terms.
|
||||
* @pre eps >= 0
|
||||
* @return True iff 'a' is greater than 'b' minus 'eps'.
|
||||
*/
|
||||
template <typename T>
|
||||
bool abs_gt(const T & a, const T & b, const T & eps)
|
||||
{
|
||||
return !abs_lte(a, b, eps);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check whether a value is within epsilon of zero.
|
||||
* @pre eps >= 0
|
||||
* @return True iff 'a' is within 'eps' of zero.
|
||||
*/
|
||||
template <typename T>
|
||||
bool abs_eq_zero(const T & a, const T & eps)
|
||||
{
|
||||
return abs_eq(a, static_cast<T>(0), eps);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
|
||||
* @pre rel_eps >= 0
|
||||
* @return True iff 'a' and 'b' are within relative 'rel_eps' of each other.
|
||||
*/
|
||||
template <typename T>
|
||||
bool rel_eq(const T & a, const T & b, const T & rel_eps)
|
||||
{
|
||||
static_assert(
|
||||
std::is_floating_point<T>::value, "Float comparisons only support floating point types.");
|
||||
|
||||
const auto delta = std::abs(a - b);
|
||||
const auto larger = std::max(std::abs(a), std::abs(b));
|
||||
const auto max_rel_delta = (larger * rel_eps);
|
||||
return delta <= max_rel_delta;
|
||||
}
|
||||
|
||||
// TODO(jeff): As needed, add relative variants of <, <=, >, >=
|
||||
|
||||
/**
|
||||
* @brief Check for approximate equality in absolute and relative terms.
|
||||
*
|
||||
* @note This method should be used only if an explicit relative or absolute
|
||||
* comparison is not appropriate for the particular use case.
|
||||
*
|
||||
* @pre abs_eps >= 0
|
||||
* @pre rel_eps >= 0
|
||||
* @return True iff 'a' and 'b' are within 'eps' or 'rel_eps' of each other
|
||||
*/
|
||||
template <typename T>
|
||||
bool approx_eq(const T & a, const T & b, const T & abs_eps, const T & rel_eps)
|
||||
{
|
||||
const auto are_absolute_eq = abs_eq(a, b, abs_eps);
|
||||
const auto are_relative_eq = rel_eq(a, b, rel_eps);
|
||||
return are_absolute_eq || are_relative_eq;
|
||||
}
|
||||
|
||||
} // namespace comparisons
|
||||
} // namespace helper_functions
|
||||
} // namespace common
|
||||
} // namespace autoware
|
||||
|
||||
#endif // AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__FLOAT_COMPARISONS_HPP_
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
// Copyright 2021 Apex.AI, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Co-developed by Tier IV, Inc. and Apex.AI, Inc.
|
||||
|
||||
#ifndef AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__MAHALANOBIS_DISTANCE_HPP_
|
||||
#define AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__MAHALANOBIS_DISTANCE_HPP_
|
||||
|
||||
#include <Eigen/Cholesky>
|
||||
|
||||
namespace autoware
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace helper_functions
|
||||
{
|
||||
/// \brief Calculate square of mahalanobis distance
|
||||
/// \tparam T Type of elements in the matrix
|
||||
/// \tparam kNumOfStates Number of states
|
||||
/// \param sample Single column matrix containing sample whose distance needs to be computed
|
||||
/// \param mean Single column matrix containing mean of samples received so far
|
||||
/// \param covariance_factor Covariance matrix
|
||||
/// \return Square of mahalanobis distance
|
||||
template <typename T, std::int32_t kNumOfStates>
|
||||
types::float32_t calculate_squared_mahalanobis_distance(
|
||||
const Eigen::Matrix<T, kNumOfStates, 1> & sample, const Eigen::Matrix<T, kNumOfStates, 1> & mean,
|
||||
const Eigen::Matrix<T, kNumOfStates, kNumOfStates> & covariance_factor)
|
||||
{
|
||||
using Vector = Eigen::Matrix<T, kNumOfStates, 1>;
|
||||
// This is equivalent to the squared Mahalanobis distance of the form: diff.T * C.inv() * diff
|
||||
// Instead of the covariance matrix C we have its lower-triangular factor L, such that C = L * L.T
|
||||
// squared_mahalanobis_distance = diff.T * C.inv() * diff
|
||||
// = diff.T * (L * L.T).inv() * diff
|
||||
// = diff.T * L.T.inv() * L.inv() * diff
|
||||
// = (L.inv() * diff).T * (L.inv() * diff)
|
||||
// this allows us to efficiently find the squared Mahalanobis distance using (L.inv() * diff),
|
||||
// which can be found as a solution to: L * x = diff.
|
||||
const Vector diff = sample - mean;
|
||||
const Vector x = covariance_factor.ldlt().solve(diff);
|
||||
return x.transpose() * x;
|
||||
}
|
||||
|
||||
/// \brief Calculate mahalanobis distance
|
||||
/// \tparam T Type of elements in the matrix
|
||||
/// \tparam kNumOfStates Number of states
|
||||
/// \param sample Single column matrix containing sample whose distance needs to be computed
|
||||
/// \param mean Single column matrix containing mean of samples received so far
|
||||
/// \param covariance_factor Covariance matrix
|
||||
/// \return Mahalanobis distance
|
||||
template <typename T, std::int32_t kNumOfStates>
|
||||
types::float32_t calculate_mahalanobis_distance(
|
||||
const Eigen::Matrix<T, kNumOfStates, 1> & sample, const Eigen::Matrix<T, kNumOfStates, 1> & mean,
|
||||
const Eigen::Matrix<T, kNumOfStates, kNumOfStates> & covariance_factor)
|
||||
{
|
||||
return sqrtf(calculate_squared_mahalanobis_distance(sample, mean, covariance_factor));
|
||||
}
|
||||
} // namespace helper_functions
|
||||
} // namespace common
|
||||
} // namespace autoware
|
||||
|
||||
#endif // AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__MAHALANOBIS_DISTANCE_HPP_
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
// Copyright 2017-2019 the Autoware Foundation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Co-developed by Tier IV, Inc. and Apex.AI, Inc.
|
||||
/// \file
|
||||
/// \brief This file includes common helper functions
|
||||
|
||||
#ifndef AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__MESSAGE_ADAPTERS_HPP_
|
||||
#define AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__MESSAGE_ADAPTERS_HPP_
|
||||
|
||||
#include <builtin_interfaces/msg/time.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace autoware
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace helper_functions
|
||||
{
|
||||
namespace message_field_adapters
|
||||
{
|
||||
/// Using alias for Time message
|
||||
using TimeStamp = builtin_interfaces::msg::Time;
|
||||
|
||||
/// \brief Helper class to check existence of header file in compile time:
|
||||
/// https://stackoverflow.com/a/16000226/2325407
|
||||
template <typename T, typename = std::nullptr_t>
|
||||
struct HasHeader : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct HasHeader<T, decltype((void)T::header, nullptr)> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
/////////// Template declarations
|
||||
|
||||
/// Get frame id from message. std::nullptr_t is used to prevent template ambiguity on
|
||||
/// SFINAE specializations. Provide a default value on specializations for a friendly API.
|
||||
/// \tparam T Message type.
|
||||
/// \param msg Message.
|
||||
/// \return Frame id of the message.
|
||||
template <typename T, std::nullptr_t>
|
||||
const std::string & get_frame_id(const T & msg) noexcept;
|
||||
|
||||
/// Get a reference to the frame id from message. std::nullptr_t is used to prevent
|
||||
/// template ambiguity on SFINAE specializations. Provide a default value on
|
||||
/// specializations for a friendly API.
|
||||
/// \tparam T Message type.
|
||||
/// \param msg Message.
|
||||
/// \return Frame id of the message.
|
||||
template <typename T, std::nullptr_t>
|
||||
std::string & get_frame_id(T & msg) noexcept;
|
||||
|
||||
/// Get stamp from message. std::nullptr_t is used to prevent template ambiguity on
|
||||
/// SFINAE specializations. Provide a default value on specializations for a friendly API.
|
||||
/// \tparam T Message type.
|
||||
/// \param msg Message.
|
||||
/// \return Frame id of the message.
|
||||
template <typename T, std::nullptr_t>
|
||||
const TimeStamp & get_stamp(const T & msg) noexcept;
|
||||
|
||||
/// Get a reference to the stamp from message. std::nullptr_t is used to prevent
|
||||
/// template ambiguity on SFINAE specializations. Provide a default value on
|
||||
/// specializations for a friendly API.
|
||||
/// \tparam T Message type.
|
||||
/// \param msg Message.
|
||||
/// \return Frame id of the message.
|
||||
template <typename T, std::nullptr_t>
|
||||
TimeStamp & get_stamp(T & msg) noexcept;
|
||||
|
||||
/////////////// Default specializations for message types that contain a header.
|
||||
template <class T, typename std::enable_if<HasHeader<T>::value, std::nullptr_t>::type = nullptr>
|
||||
const std::string & get_frame_id(const T & msg) noexcept
|
||||
{
|
||||
return msg.header.frame_id;
|
||||
}
|
||||
|
||||
template <class T, typename std::enable_if<HasHeader<T>::value, std::nullptr_t>::type = nullptr>
|
||||
std::string & get_frame_id(T & msg) noexcept
|
||||
{
|
||||
return msg.header.frame_id;
|
||||
}
|
||||
|
||||
template <class T, typename std::enable_if<HasHeader<T>::value, std::nullptr_t>::type = nullptr>
|
||||
TimeStamp & get_stamp(T & msg) noexcept
|
||||
{
|
||||
return msg.header.stamp;
|
||||
}
|
||||
|
||||
template <class T, typename std::enable_if<HasHeader<T>::value, std::nullptr_t>::type = nullptr>
|
||||
TimeStamp get_stamp(const T & msg) noexcept
|
||||
{
|
||||
return msg.header.stamp;
|
||||
}
|
||||
|
||||
} // namespace message_field_adapters
|
||||
} // namespace helper_functions
|
||||
} // namespace common
|
||||
} // namespace autoware
|
||||
|
||||
#endif // AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__MESSAGE_ADAPTERS_HPP_
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
// Copyright 2021 the Autoware Foundation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Co-developed by Tier IV, Inc. and Apex.AI, Inc.
|
||||
|
||||
#ifndef AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__TEMPLATE_UTILS_HPP_
|
||||
#define AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__TEMPLATE_UTILS_HPP_
|
||||
|
||||
#include "autoware_auto_common/common/types.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace autoware
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
namespace helper_functions
|
||||
{
|
||||
/// This struct is `std::true_type` if the expression is valid for a given template and
|
||||
/// `std::false_type` otherwise.
|
||||
/// \tparam ExpressionTemplate Expression to be checked in compile time
|
||||
/// \tparam T Template parameter to instantiate the expression.
|
||||
template <template <typename...> class ExpressionTemplate, typename T, typename = void>
|
||||
struct expression_valid : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
/// This struct is `std::true_type` if the expression is valid for a given template and
|
||||
/// `std::false_type` otherwise.
|
||||
/// \tparam ExpressionTemplate Expression to be checked in compile time
|
||||
/// \tparam T Template parameter to instantiate the expression.
|
||||
template <template <typename...> class ExpressionTemplate, typename T>
|
||||
struct expression_valid<ExpressionTemplate, T, types::void_t<ExpressionTemplate<T>>>
|
||||
: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
/// This struct is `std::true_type` if the expression is valid for a given template
|
||||
/// type with the specified return type and `std::false_type` otherwise.
|
||||
/// \tparam ExpressionTemplate Expression to be checked in compile time
|
||||
/// \tparam T Template parameter to instantiate the expression.
|
||||
/// \tparam ReturnT Return type of the expression.
|
||||
template <
|
||||
template <typename...> class ExpressionTemplate, typename T, typename ReturnT, typename = void>
|
||||
struct expression_valid_with_return : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
/// This struct is `std::true_type` if the expression is valid for a given template
|
||||
/// type with the specified return type and `std::false_type` otherwise.
|
||||
/// \tparam ExpressionTemplate Expression to be checked in compile time
|
||||
/// \tparam T Template parameter to instantiate the expression.
|
||||
/// \tparam ReturnT Return type of the expression.
|
||||
template <template <typename...> class ExpressionTemplate, typename T, typename ReturnT>
|
||||
struct expression_valid_with_return<
|
||||
ExpressionTemplate, T, ReturnT,
|
||||
std::enable_if_t<std::is_same<ReturnT, ExpressionTemplate<T>>::value>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace helper_functions
|
||||
} // namespace common
|
||||
} // namespace autoware
|
||||
#endif // AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__TEMPLATE_UTILS_HPP_
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
// Copyright 2021 Apex.AI, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Co-developed by Tier IV, Inc. and Apex.AI, Inc.
|
||||
|
||||
#ifndef AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__TYPE_NAME_HPP_
|
||||
#define AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__TYPE_NAME_HPP_
|
||||
|
||||
#include "autoware_auto_common/common/visibility_control.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
|
||||
#include <cxxabi.h>
|
||||
#endif
|
||||
|
||||
namespace autoware
|
||||
{
|
||||
namespace helper_functions
|
||||
{
|
||||
|
||||
/// @brief Get a demangled name of a type.
|
||||
template <typename T>
|
||||
COMMON_PUBLIC std::string get_type_name()
|
||||
{
|
||||
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
|
||||
return abi::__cxa_demangle(typeid(T).name(), NULL, NULL, 0);
|
||||
#else
|
||||
// For unsupported compilers return a mangled name.
|
||||
return typeid(T).name();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @brief Get a demangled name of a type given its instance.
|
||||
template <typename T>
|
||||
COMMON_PUBLIC std::string get_type_name(const T &)
|
||||
{
|
||||
return get_type_name<T>();
|
||||
}
|
||||
|
||||
} // namespace helper_functions
|
||||
} // namespace autoware
|
||||
|
||||
#endif // AUTOWARE_AUTO_COMMON__HELPER_FUNCTIONS__TYPE_NAME_HPP_
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="3">
|
||||
<name>autoware_auto_common</name>
|
||||
<version>1.0.0</version>
|
||||
<description>Miscellaneous helper functions</description>
|
||||
<maintainer email="opensource@apex.ai">Apex.AI, Inc.</maintainer>
|
||||
<maintainer email="tomoya.kimura@tier4.jp">Tomoya Kimura</maintainer>
|
||||
<maintainer email="shumpei.wakabayashi@tier4.jp">Shumpei Wakabayashi</maintainer>
|
||||
<maintainer email="satoshi.ota@tier4.jp">Satoshi Ota</maintainer>
|
||||
<license>Apache License 2.0</license>
|
||||
|
||||
<buildtool_depend>ament_cmake_auto</buildtool_depend>
|
||||
<buildtool_depend>autoware_cmake</buildtool_depend>
|
||||
|
||||
<depend>builtin_interfaces</depend>
|
||||
<depend>eigen</depend>
|
||||
|
||||
<test_depend>ament_cmake_ros</test_depend>
|
||||
<test_depend>ament_lint_auto</test_depend>
|
||||
<test_depend>autoware_lint_common</test_depend>
|
||||
<test_depend>geometry_msgs</test_depend>
|
||||
|
||||
<export>
|
||||
<build_type>ament_cmake</build_type>
|
||||
</export>
|
||||
</package>
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright 2018 the Autoware Foundation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Co-developed by Tier IV, Inc. and Apex.AI, Inc.
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright 2021 Apex.AI, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Developed by Apex.AI, Inc.
|
||||
|
||||
#include "autoware_auto_common/common/types.hpp"
|
||||
#include "autoware_auto_common/helper_functions/angle_utils.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
using autoware::common::helper_functions::wrap_angle;
|
||||
using autoware::common::types::float32_t;
|
||||
using autoware::common::types::float64_t;
|
||||
|
||||
} // namespace
|
||||
|
||||
/// @test Wrap an angle.
|
||||
TEST(TestAngleUtils, WrapAngle)
|
||||
{
|
||||
EXPECT_DOUBLE_EQ(wrap_angle(-5.0 * M_PI_2), -M_PI_2);
|
||||
EXPECT_DOUBLE_EQ(wrap_angle(5.0 * M_PI_2), M_PI_2);
|
||||
EXPECT_DOUBLE_EQ(wrap_angle(M_PI), -M_PI);
|
||||
EXPECT_DOUBLE_EQ(wrap_angle(-M_PI), -M_PI);
|
||||
EXPECT_DOUBLE_EQ(wrap_angle(0.0), 0.0);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
// Copyright 2020 Mapless AI, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
#include "autoware_auto_common/helper_functions/bool_comparisons.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
// cppcheck does not like gtest macros inside of namespaces:
|
||||
// https://sourceforge.net/p/cppcheck/discussion/general/thread/e68df47b/
|
||||
// use a namespace alias instead of putting macros into the namespace
|
||||
namespace comp = autoware::common::helper_functions::comparisons;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
TEST(HelperFunctionsComparisons, ExclusiveOr)
|
||||
{
|
||||
EXPECT_TRUE(comp::exclusive_or(0, 1));
|
||||
EXPECT_TRUE(comp::exclusive_or(1, 0));
|
||||
EXPECT_FALSE(comp::exclusive_or(0, 0));
|
||||
EXPECT_FALSE(comp::exclusive_or(1, 1));
|
||||
|
||||
EXPECT_TRUE(comp::exclusive_or(false, true));
|
||||
EXPECT_TRUE(comp::exclusive_or(true, false));
|
||||
EXPECT_FALSE(comp::exclusive_or(false, false));
|
||||
EXPECT_FALSE(comp::exclusive_or(true, true));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright 2019 the Autoware Foundation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Co-developed by Tier IV, Inc. and Apex.AI, Inc.
|
||||
|
||||
#include "autoware_auto_common/common/types.hpp"
|
||||
#include "autoware_auto_common/helper_functions/byte_reader.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
using autoware::common::types::float64_t;
|
||||
|
||||
namespace
|
||||
{
|
||||
class ByteReader : public ::testing::Test
|
||||
{
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// tests serial_driver_node's get_packet function which receives serial packages
|
||||
TEST_F(ByteReader, Basic)
|
||||
{
|
||||
std::vector<uint8_t> data = {0x00, 0x00, 0x00, 0x17, 0x40, 0x28, 0xAE, 0x14,
|
||||
0x7A, 0xE1, 0x47, 0xAE, 0x00, 0x00, 0x08};
|
||||
|
||||
autoware::common::helper_functions::ByteReader byte_reader(data);
|
||||
|
||||
uint32_t a = 0;
|
||||
byte_reader.read(a);
|
||||
ASSERT_EQ(a, 23U);
|
||||
|
||||
float64_t b = 0;
|
||||
byte_reader.read(b);
|
||||
ASSERT_EQ(b, 12.34);
|
||||
|
||||
byte_reader.skip(1);
|
||||
|
||||
int16_t c = 0;
|
||||
byte_reader.read(c);
|
||||
ASSERT_EQ(c, 8);
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
// Copyright 2020 Mapless AI, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
#include "autoware_auto_common/helper_functions/float_comparisons.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
// cppcheck does not like gtest macros inside of namespaces:
|
||||
// https://sourceforge.net/p/cppcheck/discussion/general/thread/e68df47b/
|
||||
// use a namespace alias instead of putting macros into the namespace
|
||||
namespace comp = autoware::common::helper_functions::comparisons;
|
||||
|
||||
namespace
|
||||
{
|
||||
const auto a = 1.317;
|
||||
const auto b = 2.0;
|
||||
const auto c = -5.2747;
|
||||
const auto d = 0.0;
|
||||
const auto e = -5.2747177;
|
||||
const auto f = -5.2749;
|
||||
const auto epsilon = 0.0001;
|
||||
} // namespace
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
TEST(HelperFunctionsComparisons, AbsEqZero)
|
||||
{
|
||||
EXPECT_TRUE(comp::abs_eq_zero(d, epsilon));
|
||||
EXPECT_TRUE(comp::abs_eq_zero(d + epsilon * epsilon, epsilon));
|
||||
EXPECT_FALSE(comp::abs_eq_zero(d + 2.0 * epsilon, epsilon));
|
||||
EXPECT_FALSE(comp::abs_eq_zero(1.0, epsilon));
|
||||
EXPECT_TRUE(comp::abs_eq_zero(0.0, 0.0));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
TEST(HelperFunctionsComparisons, AbsEq)
|
||||
{
|
||||
EXPECT_TRUE(comp::abs_eq(c, e, epsilon));
|
||||
EXPECT_TRUE(comp::abs_eq(e, c, epsilon));
|
||||
EXPECT_FALSE(comp::abs_eq(c, e, 0.0));
|
||||
EXPECT_FALSE(comp::abs_eq(e, c, 0.0));
|
||||
EXPECT_FALSE(comp::abs_eq(a, b, epsilon));
|
||||
EXPECT_FALSE(comp::abs_eq(b, a, epsilon));
|
||||
EXPECT_TRUE(comp::abs_eq(a, a, epsilon));
|
||||
EXPECT_TRUE(comp::abs_eq(a, a, 0.0));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
TEST(HelperFunctionsComparisons, AbsLt)
|
||||
{
|
||||
EXPECT_TRUE(comp::abs_lt(f, c, 0.0));
|
||||
EXPECT_TRUE(comp::abs_lt(f, c, epsilon));
|
||||
EXPECT_FALSE(comp::abs_lt(c, f, epsilon));
|
||||
EXPECT_FALSE(comp::abs_lt(d, d, epsilon));
|
||||
EXPECT_FALSE(comp::abs_lt(d, d, 0.0));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
TEST(HelperFunctionsComparisons, AbsLte)
|
||||
{
|
||||
EXPECT_TRUE(comp::abs_lte(c, e, epsilon));
|
||||
EXPECT_TRUE(comp::abs_lte(e, c, epsilon));
|
||||
EXPECT_FALSE(comp::abs_lte(c, e, 0.0));
|
||||
EXPECT_TRUE(comp::abs_lte(e, c, 0.0));
|
||||
EXPECT_TRUE(comp::abs_lte(c, e, epsilon));
|
||||
EXPECT_TRUE(comp::abs_lte(e, c, epsilon));
|
||||
EXPECT_TRUE(comp::abs_lte(a, b, epsilon));
|
||||
EXPECT_FALSE(comp::abs_lte(b, a, epsilon));
|
||||
EXPECT_TRUE(comp::abs_lte(d, d, epsilon));
|
||||
EXPECT_TRUE(comp::abs_lte(d, d, 0.0));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
TEST(HelperFunctionsComparisons, AbsGt)
|
||||
{
|
||||
EXPECT_TRUE(comp::abs_gt(c, e, 0.0));
|
||||
EXPECT_FALSE(comp::abs_gt(c, e, epsilon));
|
||||
EXPECT_FALSE(comp::abs_gt(f, c, epsilon));
|
||||
EXPECT_TRUE(comp::abs_gt(c, f, epsilon));
|
||||
EXPECT_FALSE(comp::abs_gt(d, d, epsilon));
|
||||
EXPECT_FALSE(comp::abs_gt(d, d, 0.0));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
TEST(HelperFunctionsComparisons, AbsGte)
|
||||
{
|
||||
EXPECT_TRUE(comp::abs_gte(c, e, 0.0));
|
||||
EXPECT_FALSE(comp::abs_gte(e, c, 0.0));
|
||||
EXPECT_TRUE(comp::abs_gte(c, e, epsilon));
|
||||
EXPECT_TRUE(comp::abs_gte(e, c, epsilon));
|
||||
EXPECT_FALSE(comp::abs_gte(f, c, epsilon));
|
||||
EXPECT_TRUE(comp::abs_gte(c, f, epsilon));
|
||||
EXPECT_TRUE(comp::abs_gte(d, d, epsilon));
|
||||
EXPECT_TRUE(comp::abs_gte(d, d, 0.0));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
TEST(HelperFunctionsComparisons, RelEq)
|
||||
{
|
||||
EXPECT_FALSE(comp::rel_eq(c, e, 0.0));
|
||||
EXPECT_FALSE(comp::rel_eq(e, c, 0.0));
|
||||
EXPECT_TRUE(comp::rel_eq(a, a, 0.0));
|
||||
|
||||
EXPECT_TRUE(comp::rel_eq(c, e, 1.0));
|
||||
EXPECT_TRUE(comp::rel_eq(e, c, 1.0));
|
||||
EXPECT_TRUE(comp::rel_eq(a, b, 1.0));
|
||||
EXPECT_TRUE(comp::rel_eq(b, a, 1.0));
|
||||
|
||||
EXPECT_FALSE(comp::rel_eq(1.0, 1.1, 0.01));
|
||||
EXPECT_TRUE(comp::rel_eq(10000.0, 10010.0, 0.01));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
TEST(HelperFunctionsComparisons, ApproxEq)
|
||||
{
|
||||
EXPECT_TRUE(comp::approx_eq(c, e, epsilon, 0.0));
|
||||
EXPECT_TRUE(comp::approx_eq(e, c, epsilon, 0.0));
|
||||
EXPECT_TRUE(comp::approx_eq(a, a, epsilon, 0.0));
|
||||
EXPECT_TRUE(comp::approx_eq(a, a, 0.0, 0.0));
|
||||
|
||||
EXPECT_FALSE(comp::approx_eq(c, e, 0.0, 0.0));
|
||||
EXPECT_FALSE(comp::approx_eq(e, c, 0.0, 0.0));
|
||||
EXPECT_FALSE(comp::approx_eq(a, b, epsilon, 0.0));
|
||||
EXPECT_FALSE(comp::approx_eq(b, a, epsilon, 0.0));
|
||||
|
||||
EXPECT_TRUE(comp::approx_eq(c, e, 0.0, 1.0));
|
||||
EXPECT_TRUE(comp::approx_eq(e, c, 0.0, 1.0));
|
||||
EXPECT_TRUE(comp::approx_eq(a, b, epsilon, 1.0));
|
||||
EXPECT_TRUE(comp::approx_eq(b, a, epsilon, 1.0));
|
||||
|
||||
EXPECT_TRUE(comp::approx_eq(1.0, 1.1, 0.2, 0.01));
|
||||
EXPECT_TRUE(comp::approx_eq(10000.0, 10010.0, 0.2, 0.01));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright 2021 Apex.AI, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Co-developed by Tier IV, Inc. and Apex.AI, Inc.
|
||||
#include "autoware_auto_common/common/types.hpp"
|
||||
#include "autoware_auto_common/helper_functions/mahalanobis_distance.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(MahalanobisDistanceTest, BasicTest)
|
||||
{
|
||||
Eigen::Matrix<autoware::common::types::float32_t, 2, 1> mean;
|
||||
mean << 2.F, 2.F;
|
||||
Eigen::Matrix<autoware::common::types::float32_t, 2, 1> sample;
|
||||
sample << 2.F, 3.F;
|
||||
Eigen::Matrix<autoware::common::types::float32_t, 2, 2> cov;
|
||||
cov << 0.1F, 0.0F, 0.0F, 0.6F;
|
||||
|
||||
// the two states are independent and one has more variance than the other. With samples
|
||||
// equidistant from mean but on two different axes will have vastly different
|
||||
// mahalanobis distance values
|
||||
EXPECT_FLOAT_EQ(
|
||||
autoware::common::helper_functions::calculate_mahalanobis_distance(sample, mean, cov),
|
||||
1.666666666F);
|
||||
|
||||
sample << 3.F, 2.F;
|
||||
EXPECT_FLOAT_EQ(
|
||||
autoware::common::helper_functions::calculate_mahalanobis_distance(sample, mean, cov), 10.0F);
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// Copyright 2017-2020 the Autoware Foundation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Co-developed by Tier IV, Inc. and Apex.AI, Inc.
|
||||
|
||||
#include "autoware_auto_common/helper_functions/message_adapters.hpp"
|
||||
|
||||
#include <geometry_msgs/msg/transform_stamped.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
using autoware::common::helper_functions::message_field_adapters::get_frame_id;
|
||||
using autoware::common::helper_functions::message_field_adapters::get_stamp;
|
||||
|
||||
namespace
|
||||
{
|
||||
builtin_interfaces::msg::Time get_stamp_msg(int t)
|
||||
{
|
||||
builtin_interfaces::msg::Time stamp;
|
||||
stamp.sec = 0;
|
||||
stamp.nanosec = t;
|
||||
return stamp;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(MessageFieldAdapterTest, ConstHeaderTests)
|
||||
{
|
||||
using Message = geometry_msgs::msg::TransformStamped;
|
||||
|
||||
const auto stamp = get_stamp_msg(0);
|
||||
const auto frame_id = "MessageFieldAdapterTest_frame";
|
||||
|
||||
std_msgs::msg::Header header;
|
||||
header.stamp = stamp;
|
||||
header.frame_id = frame_id;
|
||||
const Message msg{Message{}.set__header(header)};
|
||||
|
||||
EXPECT_EQ(stamp, get_stamp(msg));
|
||||
EXPECT_EQ(frame_id, get_frame_id(msg));
|
||||
}
|
||||
|
||||
TEST(MessageFieldAdapterTest, NonconstHeaderTests)
|
||||
{
|
||||
using Message = geometry_msgs::msg::TransformStamped;
|
||||
|
||||
const auto stamp = get_stamp_msg(0);
|
||||
const auto frame_id = "MessageFieldAdapterTest_frame";
|
||||
const auto stamp2 = get_stamp_msg(500);
|
||||
const auto frame_id2 = "MessageFieldAdapterTest_frame2";
|
||||
|
||||
ASSERT_NE(stamp, stamp2);
|
||||
ASSERT_NE(frame_id, frame_id2);
|
||||
|
||||
std_msgs::msg::Header header;
|
||||
header.stamp = stamp;
|
||||
header.frame_id = frame_id;
|
||||
Message msg{Message{}.set__header(header)};
|
||||
|
||||
EXPECT_EQ(stamp, get_stamp(msg));
|
||||
EXPECT_EQ(frame_id, get_frame_id(msg));
|
||||
|
||||
get_stamp(msg) = stamp2;
|
||||
get_frame_id(msg) = frame_id2;
|
||||
|
||||
EXPECT_EQ(stamp2, get_stamp(msg));
|
||||
EXPECT_EQ(frame_id2, get_frame_id(msg));
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
// Copyright 2021 the Autoware Foundation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Co-developed by Tier IV, Inc. and Apex.AI, Inc.
|
||||
|
||||
#include "autoware_auto_common/helper_functions/template_utils.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
struct CorrectType
|
||||
{
|
||||
};
|
||||
struct FalseType
|
||||
{
|
||||
};
|
||||
|
||||
struct Foo
|
||||
{
|
||||
static CorrectType bar(CorrectType, const CorrectType &, CorrectType *) { return CorrectType{}; }
|
||||
};
|
||||
|
||||
template <template <typename> class Expression, typename... Ts>
|
||||
using expression_valid_with_return =
|
||||
::autoware::common::helper_functions::expression_valid_with_return<Expression, Ts...>;
|
||||
template <template <typename> class Expression, typename... Ts>
|
||||
using expression_valid = ::autoware::common::helper_functions::expression_valid<Expression, Ts...>;
|
||||
|
||||
// Types are defined here and not in the header because these definitions are basically the test
|
||||
// code themselves.
|
||||
|
||||
// Correct way to call Foo::bar(...)
|
||||
template <typename FooT, typename In1, typename In2, typename In3>
|
||||
using call_bar_expression = decltype(std::declval<FooT>().bar(
|
||||
std::declval<In1>(), std::declval<const In2 &>(), std::declval<In3 *>()));
|
||||
|
||||
// Another correct way to call Foo::bar(...) since a temporary can bind to the const lvalue
|
||||
// reference
|
||||
template <typename FooT, typename In1, typename In2, typename In3>
|
||||
using call_bar_expression2 = decltype(std::declval<FooT>().bar(
|
||||
std::declval<In1>(), std::declval<In2>(), std::declval<In3 *>()));
|
||||
|
||||
// Signature mismatch:
|
||||
template <typename FooT, typename In1, typename In2, typename In3>
|
||||
using false_bar_expression1 =
|
||||
decltype(std::declval<FooT>().bar(std::declval<In1>(), std::declval<In2>(), std::declval<In3>()));
|
||||
|
||||
// Signature mismatch:
|
||||
template <typename FooT, typename In1, typename In2>
|
||||
using false_bar_expression2 =
|
||||
decltype(std::declval<FooT>().bar(std::declval<In1>(), std::declval<const In2 &>()));
|
||||
|
||||
// cspell: ignore asdasd
|
||||
// Signature mismatch:
|
||||
template <typename FooT, typename In1, typename In2, typename In3>
|
||||
using false_bar_expression3 = decltype(std::declval<FooT>().asdasd(
|
||||
std::declval<In1>(), std::declval<const In2 &>(), std::declval<In3 *>()));
|
||||
|
||||
// Correct signature, correct types:
|
||||
template <typename FooT>
|
||||
using correct_expression1 = call_bar_expression<FooT, CorrectType, CorrectType, CorrectType>;
|
||||
template <typename FooT>
|
||||
using correct_expression2 = call_bar_expression2<FooT, CorrectType, CorrectType, CorrectType>;
|
||||
|
||||
// Correct signature, false types:
|
||||
template <typename FooT>
|
||||
using false_expression1 = call_bar_expression<FooT, FalseType, CorrectType, CorrectType>;
|
||||
template <typename FooT>
|
||||
using false_expression2 = call_bar_expression<FooT, CorrectType, FalseType, CorrectType>;
|
||||
template <typename FooT>
|
||||
using false_expression3 = call_bar_expression<FooT, FalseType, FalseType, FalseType>;
|
||||
|
||||
// False signature, correct types:
|
||||
template <typename FooT>
|
||||
using false_expression4 = false_bar_expression1<FooT, CorrectType, CorrectType, CorrectType>;
|
||||
template <typename FooT>
|
||||
using false_expression5 = false_bar_expression3<FooT, CorrectType, CorrectType, CorrectType>;
|
||||
|
||||
// False signature, false types:
|
||||
template <typename FooT>
|
||||
using false_expression6 = false_bar_expression1<FooT, CorrectType, CorrectType, CorrectType>;
|
||||
template <typename FooT>
|
||||
using false_expression7 = false_bar_expression2<FooT, CorrectType, CorrectType>;
|
||||
|
||||
TEST(TestTemplateUtils, ExpressionValid)
|
||||
{
|
||||
EXPECT_TRUE((expression_valid<correct_expression1, Foo>::value));
|
||||
EXPECT_TRUE((expression_valid<correct_expression2, Foo>::value));
|
||||
EXPECT_FALSE((expression_valid<false_expression1, Foo>::value));
|
||||
EXPECT_FALSE((expression_valid<false_expression2, Foo>::value));
|
||||
EXPECT_FALSE((expression_valid<false_expression3, Foo>::value));
|
||||
EXPECT_FALSE((expression_valid<false_expression4, Foo>::value));
|
||||
EXPECT_FALSE((expression_valid<false_expression5, Foo>::value));
|
||||
EXPECT_FALSE((expression_valid<false_expression6, Foo>::value));
|
||||
EXPECT_FALSE((expression_valid<false_expression7, Foo>::value));
|
||||
}
|
||||
|
||||
TEST(TestTemplateUtils, ExpressionReturnValid)
|
||||
{
|
||||
EXPECT_TRUE((expression_valid_with_return<correct_expression1, Foo, CorrectType>::value));
|
||||
EXPECT_FALSE((expression_valid_with_return<correct_expression1, Foo, FalseType>::value));
|
||||
|
||||
EXPECT_TRUE((expression_valid_with_return<correct_expression2, Foo, CorrectType>::value));
|
||||
EXPECT_FALSE((expression_valid_with_return<correct_expression2, Foo, FalseType>::value));
|
||||
|
||||
// If an expression is not valid, returning the right type will not be enough.
|
||||
EXPECT_FALSE((expression_valid_with_return<false_expression1, Foo, CorrectType>::value));
|
||||
EXPECT_FALSE((expression_valid_with_return<false_expression2, Foo, CorrectType>::value));
|
||||
EXPECT_FALSE((expression_valid_with_return<false_expression3, Foo, CorrectType>::value));
|
||||
EXPECT_FALSE((expression_valid_with_return<false_expression4, Foo, CorrectType>::value));
|
||||
EXPECT_FALSE((expression_valid_with_return<false_expression5, Foo, CorrectType>::value));
|
||||
EXPECT_FALSE((expression_valid_with_return<false_expression6, Foo, CorrectType>::value));
|
||||
EXPECT_FALSE((expression_valid_with_return<false_expression7, Foo, CorrectType>::value));
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright 2021 Apex.AI, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Developed by Apex.AI, Inc.
|
||||
|
||||
#include "autoware_auto_common/common/types.hpp"
|
||||
#include "autoware_auto_common/helper_functions/type_name.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
using autoware::common::types::float32_t;
|
||||
using autoware::common::types::float64_t;
|
||||
using autoware::helper_functions::get_type_name;
|
||||
|
||||
struct SomeStruct
|
||||
{
|
||||
};
|
||||
} // namespace
|
||||
|
||||
/// @test Test that type names can be demangled.
|
||||
TEST(TestTypeDemangling, Demangle)
|
||||
{
|
||||
EXPECT_EQ(get_type_name<float32_t>(), "float");
|
||||
const float64_t val{42.0};
|
||||
EXPECT_EQ(get_type_name(val), "double");
|
||||
EXPECT_EQ(get_type_name<SomeStruct>(), "(anonymous namespace)::SomeStruct");
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
// Copyright 2021 Apex.AI, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Developed by Apex.AI, Inc.
|
||||
|
||||
#include "autoware_auto_common/common/type_traits.hpp"
|
||||
#include "autoware_auto_common/common/types.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <tuple>
|
||||
|
||||
namespace
|
||||
{
|
||||
/// @brief A simple testing function to check if all types are arithmetic.
|
||||
///
|
||||
/// Trait "is_arithmetic" is picked at random and any other trait could have been used
|
||||
/// instead.
|
||||
template <typename... Ts>
|
||||
bool all_are_arithmetic()
|
||||
{
|
||||
// This is just a random function that we use with conjunction.
|
||||
return autoware::common::type_traits::conjunction<std::is_arithmetic<Ts>...>::value;
|
||||
}
|
||||
|
||||
using autoware::common::types::float32_t;
|
||||
using autoware::common::types::float64_t;
|
||||
|
||||
} // namespace
|
||||
|
||||
/// @test Test that index of a type can be computed.
|
||||
TEST(TestCommonTypeTraits, Index)
|
||||
{
|
||||
using T = std::tuple<std::int32_t, float64_t>;
|
||||
EXPECT_EQ(0, (autoware::common::type_traits::index<std::int32_t, T>::value));
|
||||
EXPECT_EQ(1, (autoware::common::type_traits::index<float64_t, T>::value));
|
||||
}
|
||||
|
||||
TEST(TestCommonTypeTraits, Conjunction)
|
||||
{
|
||||
EXPECT_TRUE((all_are_arithmetic<std::int32_t, float32_t>()));
|
||||
EXPECT_FALSE(
|
||||
(all_are_arithmetic<std::int32_t, float32_t, std::tuple<std::int32_t, float32_t>>()));
|
||||
}
|
||||
|
||||
TEST(TestCommonTypeTraits, Visit)
|
||||
{
|
||||
const std::tuple<std::int32_t, float64_t> t;
|
||||
std::int32_t counter{};
|
||||
autoware::common::type_traits::visit(t, [&counter](const auto &) { counter++; });
|
||||
EXPECT_EQ(2, counter);
|
||||
float64_t sum{};
|
||||
autoware::common::type_traits::visit(
|
||||
std::make_tuple(2, 42.0F, 23.0),
|
||||
[&sum](const auto & element) { sum += static_cast<float64_t>(element); });
|
||||
EXPECT_DOUBLE_EQ(67.0, sum);
|
||||
}
|
||||
|
||||
TEST(TestCommonTypeTraits, HasType)
|
||||
{
|
||||
struct T1
|
||||
{
|
||||
};
|
||||
struct T2
|
||||
{
|
||||
};
|
||||
struct T3
|
||||
{
|
||||
};
|
||||
EXPECT_TRUE((autoware::common::type_traits::has_type<T1, std::tuple<T1, T2>>::value));
|
||||
EXPECT_FALSE((autoware::common::type_traits::has_type<T3, std::tuple<T1, T2>>::value));
|
||||
EXPECT_FALSE((autoware::common::type_traits::has_type<T1, std::tuple<>>::value));
|
||||
}
|
||||
|
||||
TEST(TestCommonTypeTraits, TypeIntersection)
|
||||
{
|
||||
struct T1
|
||||
{
|
||||
};
|
||||
struct T2
|
||||
{
|
||||
};
|
||||
struct T3
|
||||
{
|
||||
};
|
||||
using A = std::tuple<T1, T2>;
|
||||
using B = std::tuple<T2, T3>;
|
||||
using C = std::tuple<T3>;
|
||||
EXPECT_TRUE(
|
||||
(std::is_same<std::tuple<T2>, autoware::common::type_traits::intersect<A, B>::type>::value));
|
||||
EXPECT_TRUE((std::is_same<A, autoware::common::type_traits::intersect<A, A>::type>::value));
|
||||
EXPECT_TRUE(
|
||||
(std::is_same<std::tuple<>, autoware::common::type_traits::intersect<A, C>::type>::value));
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(autoware_component_interface_specs)
|
||||
|
||||
find_package(autoware_cmake REQUIRED)
|
||||
autoware_package()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
ament_auto_add_gtest(gtest_${PROJECT_NAME}
|
||||
test/gtest_main.cpp
|
||||
test/test_planning.cpp
|
||||
test/test_control.cpp
|
||||
test/test_localization.cpp
|
||||
test/test_system.cpp
|
||||
test/test_map.cpp
|
||||
test/test_perception.cpp
|
||||
test/test_vehicle.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
ament_auto_package()
|
||||
@@ -0,0 +1,2 @@
|
||||
# autoware_component_interface_specs
|
||||
该功能包是**Autoware功能组件接口**的规格定义包。
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
// Copyright 2022 TIER IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef AUTOWARE__COMPONENT_INTERFACE_SPECS__CONTROL_HPP_
|
||||
#define AUTOWARE__COMPONENT_INTERFACE_SPECS__CONTROL_HPP_
|
||||
|
||||
#include <rclcpp/qos.hpp>
|
||||
|
||||
#include <tier4_control_msgs/msg/is_paused.hpp>
|
||||
#include <tier4_control_msgs/msg/is_start_requested.hpp>
|
||||
#include <tier4_control_msgs/msg/is_stopped.hpp>
|
||||
#include <tier4_control_msgs/srv/set_pause.hpp>
|
||||
#include <tier4_control_msgs/srv/set_stop.hpp>
|
||||
|
||||
namespace autoware::component_interface_specs::control
|
||||
{
|
||||
|
||||
struct SetPause
|
||||
{
|
||||
using Service = tier4_control_msgs::srv::SetPause;
|
||||
static constexpr char name[] = "/control/vehicle_cmd_gate/set_pause";
|
||||
};
|
||||
|
||||
struct IsPaused
|
||||
{
|
||||
using Message = tier4_control_msgs::msg::IsPaused;
|
||||
static constexpr char name[] = "/control/vehicle_cmd_gate/is_paused";
|
||||
static constexpr size_t depth = 1;
|
||||
static constexpr auto reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
|
||||
static constexpr auto durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL;
|
||||
};
|
||||
|
||||
struct IsStartRequested
|
||||
{
|
||||
using Message = tier4_control_msgs::msg::IsStartRequested;
|
||||
static constexpr char name[] = "/control/vehicle_cmd_gate/is_start_requested";
|
||||
static constexpr size_t depth = 1;
|
||||
static constexpr auto reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
|
||||
static constexpr auto durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL;
|
||||
};
|
||||
|
||||
struct SetStop
|
||||
{
|
||||
using Service = tier4_control_msgs::srv::SetStop;
|
||||
static constexpr char name[] = "/control/vehicle_cmd_gate/set_stop";
|
||||
};
|
||||
|
||||
struct IsStopped
|
||||
{
|
||||
using Message = tier4_control_msgs::msg::IsStopped;
|
||||
static constexpr char name[] = "/control/vehicle_cmd_gate/is_stopped";
|
||||
static constexpr size_t depth = 1;
|
||||
static constexpr auto reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
|
||||
static constexpr auto durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL;
|
||||
};
|
||||
|
||||
} // namespace autoware::component_interface_specs::control
|
||||
|
||||
#endif // AUTOWARE__COMPONENT_INTERFACE_SPECS__CONTROL_HPP_
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
// Copyright 2022 TIER IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef AUTOWARE__COMPONENT_INTERFACE_SPECS__LOCALIZATION_HPP_
|
||||
#define AUTOWARE__COMPONENT_INTERFACE_SPECS__LOCALIZATION_HPP_
|
||||
|
||||
#include <rclcpp/qos.hpp>
|
||||
|
||||
#include <autoware_adapi_v1_msgs/msg/localization_initialization_state.hpp>
|
||||
#include <geometry_msgs/msg/accel_with_covariance_stamped.hpp>
|
||||
#include <nav_msgs/msg/odometry.hpp>
|
||||
#include <tier4_localization_msgs/srv/initialize_localization.hpp>
|
||||
|
||||
namespace autoware::component_interface_specs::localization
|
||||
{
|
||||
|
||||
struct Initialize
|
||||
{
|
||||
using Service = tier4_localization_msgs::srv::InitializeLocalization;
|
||||
static constexpr char name[] = "/localization/initialize";
|
||||
};
|
||||
|
||||
struct InitializationState
|
||||
{
|
||||
using Message = autoware_adapi_v1_msgs::msg::LocalizationInitializationState;
|
||||
static constexpr char name[] = "/localization/initialization_state";
|
||||
static constexpr size_t depth = 1;
|
||||
static constexpr auto reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
|
||||
static constexpr auto durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL;
|
||||
};
|
||||
|
||||
struct KinematicState
|
||||
{
|
||||
using Message = nav_msgs::msg::Odometry;
|
||||
static constexpr char name[] = "/localization/kinematic_state";
|
||||
static constexpr size_t depth = 1;
|
||||
static constexpr auto reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
|
||||
static constexpr auto durability = RMW_QOS_POLICY_DURABILITY_VOLATILE;
|
||||
};
|
||||
|
||||
struct Acceleration
|
||||
{
|
||||
using Message = geometry_msgs::msg::AccelWithCovarianceStamped;
|
||||
static constexpr char name[] = "/localization/acceleration";
|
||||
static constexpr size_t depth = 1;
|
||||
static constexpr auto reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
|
||||
static constexpr auto durability = RMW_QOS_POLICY_DURABILITY_VOLATILE;
|
||||
};
|
||||
|
||||
} // namespace autoware::component_interface_specs::localization
|
||||
|
||||
#endif // AUTOWARE__COMPONENT_INTERFACE_SPECS__LOCALIZATION_HPP_
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// Copyright 2023 TIER IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef AUTOWARE__COMPONENT_INTERFACE_SPECS__MAP_HPP_
|
||||
#define AUTOWARE__COMPONENT_INTERFACE_SPECS__MAP_HPP_
|
||||
|
||||
#include <rclcpp/qos.hpp>
|
||||
|
||||
#include <tier4_map_msgs/msg/map_projector_info.hpp>
|
||||
|
||||
namespace autoware::component_interface_specs::map
|
||||
{
|
||||
|
||||
struct MapProjectorInfo
|
||||
{
|
||||
using Message = tier4_map_msgs::msg::MapProjectorInfo;
|
||||
static constexpr char name[] = "/map/map_projector_info";
|
||||
static constexpr size_t depth = 1;
|
||||
static constexpr auto reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
|
||||
static constexpr auto durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL;
|
||||
};
|
||||
|
||||
} // namespace autoware::component_interface_specs::map
|
||||
|
||||
#endif // AUTOWARE__COMPONENT_INTERFACE_SPECS__MAP_HPP_
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// Copyright 2022 TIER IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef AUTOWARE__COMPONENT_INTERFACE_SPECS__PERCEPTION_HPP_
|
||||
#define AUTOWARE__COMPONENT_INTERFACE_SPECS__PERCEPTION_HPP_
|
||||
|
||||
#include <rclcpp/qos.hpp>
|
||||
|
||||
#include <autoware_perception_msgs/msg/predicted_objects.hpp>
|
||||
|
||||
namespace autoware::component_interface_specs::perception
|
||||
{
|
||||
|
||||
struct ObjectRecognition
|
||||
{
|
||||
using Message = autoware_perception_msgs::msg::PredictedObjects;
|
||||
static constexpr char name[] = "/perception/object_recognition/objects";
|
||||
static constexpr size_t depth = 1;
|
||||
static constexpr auto reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
|
||||
static constexpr auto durability = RMW_QOS_POLICY_DURABILITY_VOLATILE;
|
||||
};
|
||||
|
||||
} // namespace autoware::component_interface_specs::perception
|
||||
|
||||
#endif // AUTOWARE__COMPONENT_INTERFACE_SPECS__PERCEPTION_HPP_
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
// Copyright 2022 TIER IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef AUTOWARE__COMPONENT_INTERFACE_SPECS__PLANNING_HPP_
|
||||
#define AUTOWARE__COMPONENT_INTERFACE_SPECS__PLANNING_HPP_
|
||||
|
||||
#include <rclcpp/qos.hpp>
|
||||
|
||||
#include <autoware_planning_msgs/msg/lanelet_route.hpp>
|
||||
#include <autoware_planning_msgs/msg/trajectory.hpp>
|
||||
#include <tier4_planning_msgs/msg/route_state.hpp>
|
||||
#include <tier4_planning_msgs/srv/clear_route.hpp>
|
||||
#include <tier4_planning_msgs/srv/set_lanelet_route.hpp>
|
||||
#include <tier4_planning_msgs/srv/set_waypoint_route.hpp>
|
||||
|
||||
namespace autoware::component_interface_specs::planning
|
||||
{
|
||||
|
||||
struct SetLaneletRoute
|
||||
{
|
||||
using Service = tier4_planning_msgs::srv::SetLaneletRoute;
|
||||
static constexpr char name[] = "/planning/mission_planning/route_selector/main/set_lanelet_route";
|
||||
};
|
||||
|
||||
struct SetWaypointRoute
|
||||
{
|
||||
using Service = tier4_planning_msgs::srv::SetWaypointRoute;
|
||||
static constexpr char name[] =
|
||||
"/planning/mission_planning/route_selector/main/set_waypoint_route";
|
||||
};
|
||||
|
||||
struct ClearRoute
|
||||
{
|
||||
using Service = tier4_planning_msgs::srv::ClearRoute;
|
||||
static constexpr char name[] = "/planning/mission_planning/route_selector/main/clear_route";
|
||||
};
|
||||
|
||||
struct RouteState
|
||||
{
|
||||
using Message = tier4_planning_msgs::msg::RouteState;
|
||||
static constexpr char name[] = "/planning/mission_planning/route_selector/main/state";
|
||||
static constexpr size_t depth = 1;
|
||||
static constexpr auto reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
|
||||
static constexpr auto durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL;
|
||||
};
|
||||
|
||||
struct LaneletRoute
|
||||
{
|
||||
using Message = autoware_planning_msgs::msg::LaneletRoute;
|
||||
static constexpr char name[] = "/planning/mission_planning/route_selector/main/route";
|
||||
static constexpr size_t depth = 1;
|
||||
static constexpr auto reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
|
||||
static constexpr auto durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL;
|
||||
};
|
||||
|
||||
struct Trajectory
|
||||
{
|
||||
using Message = autoware_planning_msgs::msg::Trajectory;
|
||||
static constexpr char name[] = "/planning/scenario_planning/trajectory";
|
||||
static constexpr size_t depth = 1;
|
||||
static constexpr auto reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
|
||||
static constexpr auto durability = RMW_QOS_POLICY_DURABILITY_VOLATILE;
|
||||
};
|
||||
|
||||
} // namespace autoware::component_interface_specs::planning
|
||||
|
||||
#endif // AUTOWARE__COMPONENT_INTERFACE_SPECS__PLANNING_HPP_
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
// Copyright 2022 TIER IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef AUTOWARE__COMPONENT_INTERFACE_SPECS__SYSTEM_HPP_
|
||||
#define AUTOWARE__COMPONENT_INTERFACE_SPECS__SYSTEM_HPP_
|
||||
|
||||
#include <rclcpp/qos.hpp>
|
||||
|
||||
#include <autoware_adapi_v1_msgs/msg/mrm_state.hpp>
|
||||
#include <autoware_adapi_v1_msgs/msg/operation_mode_state.hpp>
|
||||
#include <tier4_system_msgs/srv/change_autoware_control.hpp>
|
||||
#include <tier4_system_msgs/srv/change_operation_mode.hpp>
|
||||
|
||||
namespace autoware::component_interface_specs::system
|
||||
{
|
||||
|
||||
struct MrmState
|
||||
{
|
||||
using Message = autoware_adapi_v1_msgs::msg::MrmState;
|
||||
static constexpr char name[] = "/system/fail_safe/mrm_state";
|
||||
static constexpr size_t depth = 1;
|
||||
static constexpr auto reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
|
||||
static constexpr auto durability = RMW_QOS_POLICY_DURABILITY_VOLATILE;
|
||||
};
|
||||
|
||||
struct ChangeAutowareControl
|
||||
{
|
||||
using Service = tier4_system_msgs::srv::ChangeAutowareControl;
|
||||
static constexpr char name[] = "/system/operation_mode/change_autoware_control";
|
||||
};
|
||||
|
||||
struct ChangeOperationMode
|
||||
{
|
||||
using Service = tier4_system_msgs::srv::ChangeOperationMode;
|
||||
static constexpr char name[] = "/system/operation_mode/change_operation_mode";
|
||||
};
|
||||
|
||||
struct OperationModeState
|
||||
{
|
||||
using Message = autoware_adapi_v1_msgs::msg::OperationModeState;
|
||||
static constexpr char name[] = "/system/operation_mode/state";
|
||||
static constexpr size_t depth = 1;
|
||||
static constexpr auto reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
|
||||
static constexpr auto durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL;
|
||||
};
|
||||
|
||||
} // namespace autoware::component_interface_specs::system
|
||||
|
||||
#endif // AUTOWARE__COMPONENT_INTERFACE_SPECS__SYSTEM_HPP_
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
// Copyright 2023 TIER IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef AUTOWARE__COMPONENT_INTERFACE_SPECS__VEHICLE_HPP_
|
||||
#define AUTOWARE__COMPONENT_INTERFACE_SPECS__VEHICLE_HPP_
|
||||
|
||||
#include <rclcpp/qos.hpp>
|
||||
|
||||
#include <autoware_adapi_v1_msgs/msg/door_status_array.hpp>
|
||||
#include <autoware_adapi_v1_msgs/srv/get_door_layout.hpp>
|
||||
#include <autoware_adapi_v1_msgs/srv/set_door_command.hpp>
|
||||
#include <autoware_vehicle_msgs/msg/gear_report.hpp>
|
||||
#include <autoware_vehicle_msgs/msg/hazard_lights_report.hpp>
|
||||
#include <autoware_vehicle_msgs/msg/steering_report.hpp>
|
||||
#include <autoware_vehicle_msgs/msg/turn_indicators_report.hpp>
|
||||
#include <tier4_vehicle_msgs/msg/battery_status.hpp>
|
||||
|
||||
namespace autoware::component_interface_specs::vehicle
|
||||
{
|
||||
|
||||
struct SteeringStatus
|
||||
{
|
||||
using Message = autoware_vehicle_msgs::msg::SteeringReport;
|
||||
static constexpr char name[] = "/vehicle/status/steering_status";
|
||||
static constexpr size_t depth = 1;
|
||||
static constexpr auto reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
|
||||
static constexpr auto durability = RMW_QOS_POLICY_DURABILITY_VOLATILE;
|
||||
};
|
||||
|
||||
struct GearStatus
|
||||
{
|
||||
using Message = autoware_vehicle_msgs::msg::GearReport;
|
||||
static constexpr char name[] = "/vehicle/status/gear_status";
|
||||
static constexpr size_t depth = 1;
|
||||
static constexpr auto reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
|
||||
static constexpr auto durability = RMW_QOS_POLICY_DURABILITY_VOLATILE;
|
||||
};
|
||||
|
||||
struct TurnIndicatorStatus
|
||||
{
|
||||
using Message = autoware_vehicle_msgs::msg::TurnIndicatorsReport;
|
||||
static constexpr char name[] = "/vehicle/status/turn_indicators_status";
|
||||
static constexpr size_t depth = 1;
|
||||
static constexpr auto reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
|
||||
static constexpr auto durability = RMW_QOS_POLICY_DURABILITY_VOLATILE;
|
||||
};
|
||||
|
||||
struct HazardLightStatus
|
||||
{
|
||||
using Message = autoware_vehicle_msgs::msg::HazardLightsReport;
|
||||
static constexpr char name[] = "/vehicle/status/hazard_lights_status";
|
||||
static constexpr size_t depth = 1;
|
||||
static constexpr auto reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
|
||||
static constexpr auto durability = RMW_QOS_POLICY_DURABILITY_VOLATILE;
|
||||
};
|
||||
|
||||
struct EnergyStatus
|
||||
{
|
||||
using Message = tier4_vehicle_msgs::msg::BatteryStatus;
|
||||
static constexpr char name[] = "/vehicle/status/battery_charge";
|
||||
static constexpr size_t depth = 1;
|
||||
static constexpr auto reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
|
||||
static constexpr auto durability = RMW_QOS_POLICY_DURABILITY_VOLATILE;
|
||||
};
|
||||
|
||||
struct DoorCommand
|
||||
{
|
||||
using Service = autoware_adapi_v1_msgs::srv::SetDoorCommand;
|
||||
static constexpr char name[] = "/vehicle/doors/command";
|
||||
};
|
||||
|
||||
struct DoorLayout
|
||||
{
|
||||
using Service = autoware_adapi_v1_msgs::srv::GetDoorLayout;
|
||||
static constexpr char name[] = "/vehicle/doors/layout";
|
||||
};
|
||||
|
||||
struct DoorStatus
|
||||
{
|
||||
using Message = autoware_adapi_v1_msgs::msg::DoorStatusArray;
|
||||
static constexpr char name[] = "/vehicle/doors/status";
|
||||
static constexpr size_t depth = 1;
|
||||
static constexpr auto reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
|
||||
static constexpr auto durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL;
|
||||
};
|
||||
|
||||
} // namespace autoware::component_interface_specs::vehicle
|
||||
|
||||
#endif // AUTOWARE__COMPONENT_INTERFACE_SPECS__VEHICLE_HPP_
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="3">
|
||||
<name>autoware_component_interface_specs</name>
|
||||
<version>0.0.0</version>
|
||||
<description>The autoware_component_interface_specs package</description>
|
||||
<maintainer email="isamu.takagi@tier4.jp">Takagi, Isamu</maintainer>
|
||||
<maintainer email="yukihiro.saito@tier4.jp">Yukihiro Saito</maintainer>
|
||||
<license>Apache License 2.0</license>
|
||||
|
||||
<buildtool_depend>ament_cmake_auto</buildtool_depend>
|
||||
<buildtool_depend>autoware_cmake</buildtool_depend>
|
||||
|
||||
<depend>autoware_adapi_v1_msgs</depend>
|
||||
<depend>autoware_perception_msgs</depend>
|
||||
<depend>autoware_planning_msgs</depend>
|
||||
<depend>autoware_vehicle_msgs</depend>
|
||||
<depend>nav_msgs</depend>
|
||||
<depend>rcl</depend>
|
||||
<depend>rclcpp</depend>
|
||||
<depend>rosidl_runtime_cpp</depend>
|
||||
<depend>tier4_control_msgs</depend>
|
||||
<depend>tier4_localization_msgs</depend>
|
||||
<depend>tier4_map_msgs</depend>
|
||||
<depend>tier4_planning_msgs</depend>
|
||||
<depend>tier4_system_msgs</depend>
|
||||
<depend>tier4_vehicle_msgs</depend>
|
||||
|
||||
<test_depend>ament_cmake_gtest</test_depend>
|
||||
<test_depend>ament_lint_auto</test_depend>
|
||||
<test_depend>autoware_lint_common</test_depend>
|
||||
|
||||
<export>
|
||||
<build_type>ament_cmake</build_type>
|
||||
</export>
|
||||
</package>
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright 2023 The Autoware Contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright 2023 The Autoware Contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/component_interface_specs/control.hpp"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
TEST(control, interface)
|
||||
{
|
||||
{
|
||||
using autoware::component_interface_specs::control::IsPaused;
|
||||
IsPaused is_paused;
|
||||
size_t depth = 1;
|
||||
EXPECT_EQ(is_paused.depth, depth);
|
||||
EXPECT_EQ(is_paused.reliability, RMW_QOS_POLICY_RELIABILITY_RELIABLE);
|
||||
EXPECT_EQ(is_paused.durability, RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL);
|
||||
}
|
||||
|
||||
{
|
||||
using autoware::component_interface_specs::control::IsStartRequested;
|
||||
IsStartRequested is_start_requested;
|
||||
size_t depth = 1;
|
||||
EXPECT_EQ(is_start_requested.depth, depth);
|
||||
EXPECT_EQ(is_start_requested.reliability, RMW_QOS_POLICY_RELIABILITY_RELIABLE);
|
||||
EXPECT_EQ(is_start_requested.durability, RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL);
|
||||
}
|
||||
|
||||
{
|
||||
using autoware::component_interface_specs::control::IsStopped;
|
||||
IsStopped is_stopped;
|
||||
size_t depth = 1;
|
||||
EXPECT_EQ(is_stopped.depth, depth);
|
||||
EXPECT_EQ(is_stopped.reliability, RMW_QOS_POLICY_RELIABILITY_RELIABLE);
|
||||
EXPECT_EQ(is_stopped.durability, RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL);
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
// Copyright 2023 The Autoware Contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/component_interface_specs/localization.hpp"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
TEST(localization, interface)
|
||||
{
|
||||
{
|
||||
using autoware::component_interface_specs::localization::InitializationState;
|
||||
InitializationState initialization_state;
|
||||
size_t depth = 1;
|
||||
EXPECT_EQ(initialization_state.depth, depth);
|
||||
EXPECT_EQ(initialization_state.reliability, RMW_QOS_POLICY_RELIABILITY_RELIABLE);
|
||||
EXPECT_EQ(initialization_state.durability, RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL);
|
||||
}
|
||||
|
||||
{
|
||||
using autoware::component_interface_specs::localization::KinematicState;
|
||||
KinematicState kinematic_state;
|
||||
size_t depth = 1;
|
||||
EXPECT_EQ(kinematic_state.depth, depth);
|
||||
EXPECT_EQ(kinematic_state.reliability, RMW_QOS_POLICY_RELIABILITY_RELIABLE);
|
||||
EXPECT_EQ(kinematic_state.durability, RMW_QOS_POLICY_DURABILITY_VOLATILE);
|
||||
}
|
||||
|
||||
{
|
||||
using autoware::component_interface_specs::localization::Acceleration;
|
||||
Acceleration acceleration;
|
||||
size_t depth = 1;
|
||||
EXPECT_EQ(acceleration.depth, depth);
|
||||
EXPECT_EQ(acceleration.reliability, RMW_QOS_POLICY_RELIABILITY_RELIABLE);
|
||||
EXPECT_EQ(acceleration.durability, RMW_QOS_POLICY_DURABILITY_VOLATILE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright 2023 The Autoware Contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/component_interface_specs/map.hpp"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
TEST(map, interface)
|
||||
{
|
||||
{
|
||||
using autoware::component_interface_specs::map::MapProjectorInfo;
|
||||
MapProjectorInfo map_projector;
|
||||
size_t depth = 1;
|
||||
EXPECT_EQ(map_projector.depth, depth);
|
||||
EXPECT_EQ(map_projector.reliability, RMW_QOS_POLICY_RELIABILITY_RELIABLE);
|
||||
EXPECT_EQ(map_projector.durability, RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL);
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// Copyright 2023 The Autoware Contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/component_interface_specs/perception.hpp"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
TEST(perception, interface)
|
||||
{
|
||||
{
|
||||
using autoware::component_interface_specs::perception::ObjectRecognition;
|
||||
ObjectRecognition object_recognition;
|
||||
size_t depth = 1;
|
||||
EXPECT_EQ(object_recognition.depth, depth);
|
||||
EXPECT_EQ(object_recognition.reliability, RMW_QOS_POLICY_RELIABILITY_RELIABLE);
|
||||
EXPECT_EQ(object_recognition.durability, RMW_QOS_POLICY_DURABILITY_VOLATILE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright 2023 The Autoware Contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/component_interface_specs/planning.hpp"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
TEST(planning, interface)
|
||||
{
|
||||
{
|
||||
using autoware::component_interface_specs::planning::RouteState;
|
||||
RouteState state;
|
||||
size_t depth = 1;
|
||||
EXPECT_EQ(state.depth, depth);
|
||||
EXPECT_EQ(state.reliability, RMW_QOS_POLICY_RELIABILITY_RELIABLE);
|
||||
EXPECT_EQ(state.durability, RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL);
|
||||
}
|
||||
|
||||
{
|
||||
using autoware::component_interface_specs::planning::LaneletRoute;
|
||||
LaneletRoute route;
|
||||
size_t depth = 1;
|
||||
EXPECT_EQ(route.depth, depth);
|
||||
EXPECT_EQ(route.reliability, RMW_QOS_POLICY_RELIABILITY_RELIABLE);
|
||||
EXPECT_EQ(route.durability, RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL);
|
||||
}
|
||||
|
||||
{
|
||||
using autoware::component_interface_specs::planning::Trajectory;
|
||||
Trajectory trajectory;
|
||||
size_t depth = 1;
|
||||
EXPECT_EQ(trajectory.depth, depth);
|
||||
EXPECT_EQ(trajectory.reliability, RMW_QOS_POLICY_RELIABILITY_RELIABLE);
|
||||
EXPECT_EQ(trajectory.durability, RMW_QOS_POLICY_DURABILITY_VOLATILE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright 2023 The Autoware Contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/component_interface_specs/system.hpp"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
TEST(system, interface)
|
||||
{
|
||||
{
|
||||
using autoware::component_interface_specs::system::MrmState;
|
||||
MrmState state;
|
||||
size_t depth = 1;
|
||||
EXPECT_EQ(state.depth, depth);
|
||||
EXPECT_EQ(state.reliability, RMW_QOS_POLICY_RELIABILITY_RELIABLE);
|
||||
EXPECT_EQ(state.durability, RMW_QOS_POLICY_DURABILITY_VOLATILE);
|
||||
}
|
||||
|
||||
{
|
||||
using autoware::component_interface_specs::system::OperationModeState;
|
||||
OperationModeState state;
|
||||
size_t depth = 1;
|
||||
EXPECT_EQ(state.depth, depth);
|
||||
EXPECT_EQ(state.reliability, RMW_QOS_POLICY_RELIABILITY_RELIABLE);
|
||||
EXPECT_EQ(state.durability, RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// Copyright 2023 The Autoware Contributors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/component_interface_specs/vehicle.hpp"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
TEST(vehicle, interface)
|
||||
{
|
||||
{
|
||||
using autoware::component_interface_specs::vehicle::SteeringStatus;
|
||||
SteeringStatus status;
|
||||
size_t depth = 1;
|
||||
EXPECT_EQ(status.depth, depth);
|
||||
EXPECT_EQ(status.reliability, RMW_QOS_POLICY_RELIABILITY_RELIABLE);
|
||||
EXPECT_EQ(status.durability, RMW_QOS_POLICY_DURABILITY_VOLATILE);
|
||||
}
|
||||
|
||||
{
|
||||
using autoware::component_interface_specs::vehicle::GearStatus;
|
||||
GearStatus status;
|
||||
size_t depth = 1;
|
||||
EXPECT_EQ(status.depth, depth);
|
||||
EXPECT_EQ(status.reliability, RMW_QOS_POLICY_RELIABILITY_RELIABLE);
|
||||
EXPECT_EQ(status.durability, RMW_QOS_POLICY_DURABILITY_VOLATILE);
|
||||
}
|
||||
|
||||
{
|
||||
using autoware::component_interface_specs::vehicle::TurnIndicatorStatus;
|
||||
TurnIndicatorStatus status;
|
||||
size_t depth = 1;
|
||||
EXPECT_EQ(status.depth, depth);
|
||||
EXPECT_EQ(status.reliability, RMW_QOS_POLICY_RELIABILITY_RELIABLE);
|
||||
EXPECT_EQ(status.durability, RMW_QOS_POLICY_DURABILITY_VOLATILE);
|
||||
}
|
||||
|
||||
{
|
||||
using autoware::component_interface_specs::vehicle::HazardLightStatus;
|
||||
HazardLightStatus status;
|
||||
size_t depth = 1;
|
||||
EXPECT_EQ(status.depth, depth);
|
||||
EXPECT_EQ(status.reliability, RMW_QOS_POLICY_RELIABILITY_RELIABLE);
|
||||
EXPECT_EQ(status.durability, RMW_QOS_POLICY_DURABILITY_VOLATILE);
|
||||
}
|
||||
|
||||
{
|
||||
using autoware::component_interface_specs::vehicle::EnergyStatus;
|
||||
EnergyStatus status;
|
||||
size_t depth = 1;
|
||||
EXPECT_EQ(status.depth, depth);
|
||||
EXPECT_EQ(status.reliability, RMW_QOS_POLICY_RELIABILITY_RELIABLE);
|
||||
EXPECT_EQ(status.durability, RMW_QOS_POLICY_DURABILITY_VOLATILE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(autoware_geography_utils)
|
||||
|
||||
find_package(autoware_cmake REQUIRED)
|
||||
autoware_package()
|
||||
|
||||
# GeographicLib
|
||||
find_package(PkgConfig)
|
||||
find_path(GeographicLib_INCLUDE_DIR GeographicLib/Config.h
|
||||
PATH_SUFFIXES GeographicLib
|
||||
)
|
||||
set(GeographicLib_INCLUDE_DIRS ${GeographicLib_INCLUDE_DIR})
|
||||
find_library(GeographicLib_LIBRARIES NAMES Geographic)
|
||||
|
||||
ament_auto_add_library(${PROJECT_NAME} SHARED
|
||||
src/height.cpp
|
||||
src/projection.cpp
|
||||
src/lanelet2_projector.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
${GeographicLib_LIBRARIES}
|
||||
)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
find_package(ament_cmake_ros REQUIRED)
|
||||
|
||||
file(GLOB_RECURSE test_files test/*.cpp)
|
||||
|
||||
ament_add_ros_isolated_gtest(test_${PROJECT_NAME} ${test_files})
|
||||
|
||||
target_link_libraries(test_${PROJECT_NAME}
|
||||
${PROJECT_NAME}
|
||||
)
|
||||
endif()
|
||||
|
||||
ament_auto_package()
|
||||
@@ -0,0 +1,5 @@
|
||||
# geography_utils
|
||||
|
||||
## Purpose
|
||||
|
||||
This package contains geography-related functions used by other packages, so please refer to them as needed.
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
// Copyright 2023 TIER IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef AUTOWARE__GEOGRAPHY_UTILS__HEIGHT_HPP_
|
||||
#define AUTOWARE__GEOGRAPHY_UTILS__HEIGHT_HPP_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace autoware::geography_utils
|
||||
{
|
||||
|
||||
typedef double (*HeightConversionFunction)(
|
||||
const double height, const double latitude, const double longitude);
|
||||
double convert_wgs84_to_egm2008(const double height, const double latitude, const double longitude);
|
||||
double convert_egm2008_to_wgs84(const double height, const double latitude, const double longitude);
|
||||
double convert_height(
|
||||
const double height, const double latitude, const double longitude,
|
||||
const std::string & source_vertical_datum, const std::string & target_vertical_datum);
|
||||
|
||||
} // namespace autoware::geography_utils
|
||||
|
||||
#endif // AUTOWARE__GEOGRAPHY_UTILS__HEIGHT_HPP_
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
// Copyright 2023 TIER IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef AUTOWARE__GEOGRAPHY_UTILS__LANELET2_PROJECTOR_HPP_
|
||||
#define AUTOWARE__GEOGRAPHY_UTILS__LANELET2_PROJECTOR_HPP_
|
||||
|
||||
#include <tier4_map_msgs/msg/map_projector_info.hpp>
|
||||
|
||||
#include <lanelet2_io/Projection.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace autoware::geography_utils
|
||||
{
|
||||
using MapProjectorInfo = tier4_map_msgs::msg::MapProjectorInfo;
|
||||
|
||||
std::unique_ptr<lanelet::Projector> get_lanelet2_projector(const MapProjectorInfo & projector_info);
|
||||
|
||||
} // namespace autoware::geography_utils
|
||||
|
||||
#endif // AUTOWARE__GEOGRAPHY_UTILS__LANELET2_PROJECTOR_HPP_
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
// Copyright 2023 TIER IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef AUTOWARE__GEOGRAPHY_UTILS__PROJECTION_HPP_
|
||||
#define AUTOWARE__GEOGRAPHY_UTILS__PROJECTION_HPP_
|
||||
|
||||
#include <geographic_msgs/msg/geo_point.hpp>
|
||||
#include <geometry_msgs/msg/point.hpp>
|
||||
#include <tier4_map_msgs/msg/map_projector_info.hpp>
|
||||
|
||||
namespace autoware::geography_utils
|
||||
{
|
||||
using MapProjectorInfo = tier4_map_msgs::msg::MapProjectorInfo;
|
||||
using GeoPoint = geographic_msgs::msg::GeoPoint;
|
||||
using LocalPoint = geometry_msgs::msg::Point;
|
||||
|
||||
LocalPoint project_forward(const GeoPoint & geo_point, const MapProjectorInfo & projector_info);
|
||||
GeoPoint project_reverse(const LocalPoint & local_point, const MapProjectorInfo & projector_info);
|
||||
|
||||
} // namespace autoware::geography_utils
|
||||
|
||||
#endif // AUTOWARE__GEOGRAPHY_UTILS__PROJECTION_HPP_
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="3">
|
||||
<name>autoware_geography_utils</name>
|
||||
<version>0.1.0</version>
|
||||
<description>The autoware_geography_utils package</description>
|
||||
<maintainer email="koji.minoda@tier4.jp">Koji Minoda</maintainer>
|
||||
<license>Apache License 2.0</license>
|
||||
|
||||
<buildtool_depend>ament_cmake_auto</buildtool_depend>
|
||||
<buildtool_depend>autoware_cmake</buildtool_depend>
|
||||
|
||||
<depend>autoware_lanelet2_extension</depend>
|
||||
<depend>geographic_msgs</depend>
|
||||
<depend>geographiclib</depend>
|
||||
<depend>geometry_msgs</depend>
|
||||
<depend>lanelet2_io</depend>
|
||||
<depend>tier4_map_msgs</depend>
|
||||
|
||||
<test_depend>ament_cmake_ros</test_depend>
|
||||
<test_depend>ament_lint_auto</test_depend>
|
||||
<test_depend>autoware_lint_common</test_depend>
|
||||
|
||||
<export>
|
||||
<build_type>ament_cmake</build_type>
|
||||
</export>
|
||||
</package>
|
||||
@@ -0,0 +1,63 @@
|
||||
// Copyright 2023 TIER IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <GeographicLib/Geoid.hpp>
|
||||
#include <autoware/geography_utils/height.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace autoware::geography_utils
|
||||
{
|
||||
|
||||
double convert_wgs84_to_egm2008(const double height, const double latitude, const double longitude)
|
||||
{
|
||||
GeographicLib::Geoid egm2008("egm2008-1");
|
||||
// cSpell: ignore ELLIPSOIDTOGEOID
|
||||
return egm2008.ConvertHeight(latitude, longitude, height, GeographicLib::Geoid::ELLIPSOIDTOGEOID);
|
||||
}
|
||||
|
||||
double convert_egm2008_to_wgs84(const double height, const double latitude, const double longitude)
|
||||
{
|
||||
GeographicLib::Geoid egm2008("egm2008-1");
|
||||
// cSpell: ignore GEOIDTOELLIPSOID
|
||||
return egm2008.ConvertHeight(latitude, longitude, height, GeographicLib::Geoid::GEOIDTOELLIPSOID);
|
||||
}
|
||||
|
||||
double convert_height(
|
||||
const double height, const double latitude, const double longitude,
|
||||
const std::string & source_vertical_datum, const std::string & target_vertical_datum)
|
||||
{
|
||||
if (source_vertical_datum == target_vertical_datum) {
|
||||
return height;
|
||||
}
|
||||
std::map<std::pair<std::string, std::string>, HeightConversionFunction> conversion_map;
|
||||
conversion_map[{"WGS84", "EGM2008"}] = convert_wgs84_to_egm2008;
|
||||
conversion_map[{"EGM2008", "WGS84"}] = convert_egm2008_to_wgs84;
|
||||
|
||||
auto key = std::make_pair(source_vertical_datum, target_vertical_datum);
|
||||
if (conversion_map.find(key) != conversion_map.end()) {
|
||||
return conversion_map[key](height, latitude, longitude);
|
||||
} else {
|
||||
std::string error_message =
|
||||
"Invalid conversion types: " + std::string(source_vertical_datum.c_str()) + " to " +
|
||||
std::string(target_vertical_datum.c_str());
|
||||
|
||||
throw std::invalid_argument(error_message);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace autoware::geography_utils
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright 2023 TIER IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <GeographicLib/Geoid.hpp>
|
||||
#include <autoware/geography_utils/lanelet2_projector.hpp>
|
||||
#include <autoware_lanelet2_extension/projection/mgrs_projector.hpp>
|
||||
#include <autoware_lanelet2_extension/projection/transverse_mercator_projector.hpp>
|
||||
|
||||
#include <lanelet2_projection/UTM.h>
|
||||
|
||||
namespace autoware::geography_utils
|
||||
{
|
||||
|
||||
std::unique_ptr<lanelet::Projector> get_lanelet2_projector(const MapProjectorInfo & projector_info)
|
||||
{
|
||||
if (projector_info.projector_type == MapProjectorInfo::LOCAL_CARTESIAN_UTM) {
|
||||
lanelet::GPSPoint position{
|
||||
projector_info.map_origin.latitude, projector_info.map_origin.longitude,
|
||||
projector_info.map_origin.altitude};
|
||||
lanelet::Origin origin{position};
|
||||
lanelet::projection::UtmProjector projector{origin};
|
||||
return std::make_unique<lanelet::projection::UtmProjector>(projector);
|
||||
|
||||
} else if (projector_info.projector_type == MapProjectorInfo::MGRS) {
|
||||
lanelet::projection::MGRSProjector projector{};
|
||||
projector.setMGRSCode(projector_info.mgrs_grid);
|
||||
return std::make_unique<lanelet::projection::MGRSProjector>(projector);
|
||||
|
||||
} else if (projector_info.projector_type == MapProjectorInfo::TRANSVERSE_MERCATOR) {
|
||||
lanelet::GPSPoint position{
|
||||
projector_info.map_origin.latitude, projector_info.map_origin.longitude,
|
||||
projector_info.map_origin.altitude};
|
||||
lanelet::Origin origin{position};
|
||||
lanelet::projection::TransverseMercatorProjector projector{origin};
|
||||
return std::make_unique<lanelet::projection::TransverseMercatorProjector>(projector);
|
||||
}
|
||||
const std::string error_msg =
|
||||
"Invalid map projector type: " + projector_info.projector_type +
|
||||
". Currently supported types: MGRS, LocalCartesianUTM, and TransverseMercator";
|
||||
throw std::invalid_argument(error_msg);
|
||||
}
|
||||
|
||||
} // namespace autoware::geography_utils
|
||||
@@ -0,0 +1,95 @@
|
||||
// Copyright 2023 TIER IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <GeographicLib/Geoid.hpp>
|
||||
#include <autoware/geography_utils/lanelet2_projector.hpp>
|
||||
#include <autoware/geography_utils/projection.hpp>
|
||||
#include <autoware_lanelet2_extension/projection/mgrs_projector.hpp>
|
||||
|
||||
namespace autoware::geography_utils
|
||||
{
|
||||
|
||||
Eigen::Vector3d to_basic_point_3d_pt(const LocalPoint src)
|
||||
{
|
||||
Eigen::Vector3d dst;
|
||||
dst.x() = src.x;
|
||||
dst.y() = src.y;
|
||||
dst.z() = src.z;
|
||||
return dst;
|
||||
}
|
||||
|
||||
LocalPoint project_forward(const GeoPoint & geo_point, const MapProjectorInfo & projector_info)
|
||||
{
|
||||
std::unique_ptr<lanelet::Projector> projector = get_lanelet2_projector(projector_info);
|
||||
lanelet::GPSPoint position{geo_point.latitude, geo_point.longitude, geo_point.altitude};
|
||||
|
||||
lanelet::BasicPoint3d projected_local_point;
|
||||
if (projector_info.projector_type == MapProjectorInfo::MGRS) {
|
||||
const int mgrs_precision = 9; // set precision as 100 micro meter
|
||||
const auto mgrs_projector = dynamic_cast<lanelet::projection::MGRSProjector *>(projector.get());
|
||||
|
||||
// project x and y using projector
|
||||
// note that the altitude is ignored in MGRS projection conventionally
|
||||
projected_local_point = mgrs_projector->forward(position, mgrs_precision);
|
||||
} else {
|
||||
// project x and y using projector
|
||||
// note that the original projector such as UTM projector does not compensate for the altitude
|
||||
// offset
|
||||
projected_local_point = projector->forward(position);
|
||||
|
||||
// correct z based on the map origin
|
||||
// note that the converted altitude in local point is in the same vertical datum as the geo
|
||||
// point
|
||||
projected_local_point.z() = geo_point.altitude - projector_info.map_origin.altitude;
|
||||
}
|
||||
|
||||
LocalPoint local_point;
|
||||
local_point.x = projected_local_point.x();
|
||||
local_point.y = projected_local_point.y();
|
||||
local_point.z = projected_local_point.z();
|
||||
|
||||
return local_point;
|
||||
}
|
||||
|
||||
GeoPoint project_reverse(const LocalPoint & local_point, const MapProjectorInfo & projector_info)
|
||||
{
|
||||
std::unique_ptr<lanelet::Projector> projector = get_lanelet2_projector(projector_info);
|
||||
|
||||
lanelet::GPSPoint projected_gps_point;
|
||||
if (projector_info.projector_type == MapProjectorInfo::MGRS) {
|
||||
const auto mgrs_projector = dynamic_cast<lanelet::projection::MGRSProjector *>(projector.get());
|
||||
// project latitude and longitude using projector
|
||||
// note that the z is ignored in MGRS projection conventionally
|
||||
projected_gps_point =
|
||||
mgrs_projector->reverse(to_basic_point_3d_pt(local_point), projector_info.mgrs_grid);
|
||||
} else {
|
||||
// project latitude and longitude using projector
|
||||
// note that the original projector such as UTM projector does not compensate for the altitude
|
||||
// offset
|
||||
projected_gps_point = projector->reverse(to_basic_point_3d_pt(local_point));
|
||||
|
||||
// correct altitude based on the map origin
|
||||
// note that the converted altitude in local point is in the same vertical datum as the geo
|
||||
// point
|
||||
projected_gps_point.ele = local_point.z + projector_info.map_origin.altitude;
|
||||
}
|
||||
|
||||
GeoPoint geo_point;
|
||||
geo_point.latitude = projected_gps_point.lat;
|
||||
geo_point.longitude = projected_gps_point.lon;
|
||||
geo_point.altitude = projected_gps_point.ele;
|
||||
return geo_point;
|
||||
}
|
||||
|
||||
} // namespace autoware::geography_utils
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright 2023 TIER IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/geography_utils/height.hpp"
|
||||
#include "autoware/geography_utils/lanelet2_projector.hpp"
|
||||
#include "autoware/geography_utils/projection.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
bool result = RUN_ALL_TESTS();
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright 2023 TIER IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <autoware/geography_utils/height.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
// Test case to verify if same source and target datums return original height
|
||||
TEST(GeographyUtils, SameSourceTargetDatum)
|
||||
{
|
||||
const double height = 10.0;
|
||||
const double latitude = 35.0;
|
||||
const double longitude = 139.0;
|
||||
const std::string datum = "WGS84";
|
||||
|
||||
double converted_height =
|
||||
autoware::geography_utils::convert_height(height, latitude, longitude, datum, datum);
|
||||
|
||||
EXPECT_DOUBLE_EQ(height, converted_height);
|
||||
}
|
||||
|
||||
// Test case to verify valid source and target datums
|
||||
TEST(GeographyUtils, ValidSourceTargetDatum)
|
||||
{
|
||||
// Calculated with
|
||||
// https://www.unavco.org/software/geodetic-utilities/geoid-height-calculator/geoid-height-calculator.html
|
||||
const double height = 10.0;
|
||||
const double latitude = 35.0;
|
||||
const double longitude = 139.0;
|
||||
const double target_height = -30.18;
|
||||
|
||||
double converted_height =
|
||||
autoware::geography_utils::convert_height(height, latitude, longitude, "WGS84", "EGM2008");
|
||||
|
||||
EXPECT_NEAR(target_height, converted_height, 0.1);
|
||||
}
|
||||
|
||||
// Test case to verify invalid source and target datums
|
||||
TEST(GeographyUtils, InvalidSourceTargetDatum)
|
||||
{
|
||||
const double height = 10.0;
|
||||
const double latitude = 35.0;
|
||||
const double longitude = 139.0;
|
||||
|
||||
EXPECT_THROW(
|
||||
autoware::geography_utils::convert_height(height, latitude, longitude, "INVALID1", "INVALID2"),
|
||||
std::invalid_argument);
|
||||
}
|
||||
|
||||
// Test case to verify invalid source datums
|
||||
TEST(GeographyUtils, InvalidSourceDatum)
|
||||
{
|
||||
const double height = 10.0;
|
||||
const double latitude = 35.0;
|
||||
const double longitude = 139.0;
|
||||
|
||||
EXPECT_THROW(
|
||||
autoware::geography_utils::convert_height(height, latitude, longitude, "INVALID1", "WGS84"),
|
||||
std::invalid_argument);
|
||||
}
|
||||
|
||||
// Test case to verify invalid target datums
|
||||
TEST(GeographyUtils, InvalidTargetDatum)
|
||||
{
|
||||
const double height = 10.0;
|
||||
const double latitude = 35.0;
|
||||
const double longitude = 139.0;
|
||||
|
||||
EXPECT_THROW(
|
||||
autoware::geography_utils::convert_height(height, latitude, longitude, "WGS84", "INVALID2"),
|
||||
std::invalid_argument);
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
// Copyright 2023 TIER IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <autoware/geography_utils/projection.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
TEST(GeographyUtilsProjection, ProjectForwardToMGRS)
|
||||
{
|
||||
// source point
|
||||
geographic_msgs::msg::GeoPoint geo_point;
|
||||
geo_point.latitude = 35.62426;
|
||||
geo_point.longitude = 139.74252;
|
||||
geo_point.altitude = 10.0;
|
||||
|
||||
// target point
|
||||
geometry_msgs::msg::Point local_point;
|
||||
local_point.x = 86128.0;
|
||||
local_point.y = 43002.0;
|
||||
local_point.z = 10.0;
|
||||
|
||||
// projector info
|
||||
tier4_map_msgs::msg::MapProjectorInfo projector_info;
|
||||
projector_info.projector_type = tier4_map_msgs::msg::MapProjectorInfo::MGRS;
|
||||
projector_info.mgrs_grid = "54SUE";
|
||||
projector_info.vertical_datum = tier4_map_msgs::msg::MapProjectorInfo::WGS84;
|
||||
|
||||
// conversion
|
||||
const geometry_msgs::msg::Point converted_point =
|
||||
autoware::geography_utils::project_forward(geo_point, projector_info);
|
||||
|
||||
EXPECT_NEAR(converted_point.x, local_point.x, 1.0);
|
||||
EXPECT_NEAR(converted_point.y, local_point.y, 1.0);
|
||||
EXPECT_NEAR(converted_point.z, local_point.z, 1.0);
|
||||
}
|
||||
|
||||
TEST(GeographyUtilsProjection, ProjectReverseFromMGRS)
|
||||
{
|
||||
// source point
|
||||
geometry_msgs::msg::Point local_point;
|
||||
local_point.x = 86128.0;
|
||||
local_point.y = 43002.0;
|
||||
local_point.z = 10.0;
|
||||
|
||||
// target point
|
||||
geographic_msgs::msg::GeoPoint geo_point;
|
||||
geo_point.latitude = 35.62426;
|
||||
geo_point.longitude = 139.74252;
|
||||
geo_point.altitude = 10.0;
|
||||
|
||||
// projector info
|
||||
tier4_map_msgs::msg::MapProjectorInfo projector_info;
|
||||
projector_info.projector_type = tier4_map_msgs::msg::MapProjectorInfo::MGRS;
|
||||
projector_info.mgrs_grid = "54SUE";
|
||||
projector_info.vertical_datum = tier4_map_msgs::msg::MapProjectorInfo::WGS84;
|
||||
|
||||
// conversion
|
||||
const geographic_msgs::msg::GeoPoint converted_point =
|
||||
autoware::geography_utils::project_reverse(local_point, projector_info);
|
||||
|
||||
EXPECT_NEAR(converted_point.latitude, geo_point.latitude, 0.0001);
|
||||
EXPECT_NEAR(converted_point.longitude, geo_point.longitude, 0.0001);
|
||||
EXPECT_NEAR(converted_point.altitude, geo_point.altitude, 0.0001);
|
||||
}
|
||||
|
||||
TEST(GeographyUtilsProjection, ProjectForwardAndReverseMGRS)
|
||||
{
|
||||
// source point
|
||||
geographic_msgs::msg::GeoPoint geo_point;
|
||||
geo_point.latitude = 35.62426;
|
||||
geo_point.longitude = 139.74252;
|
||||
geo_point.altitude = 10.0;
|
||||
|
||||
// projector info
|
||||
tier4_map_msgs::msg::MapProjectorInfo projector_info;
|
||||
projector_info.projector_type = tier4_map_msgs::msg::MapProjectorInfo::MGRS;
|
||||
projector_info.mgrs_grid = "54SUE";
|
||||
projector_info.vertical_datum = tier4_map_msgs::msg::MapProjectorInfo::WGS84;
|
||||
|
||||
// conversion
|
||||
const geometry_msgs::msg::Point converted_local_point =
|
||||
autoware::geography_utils::project_forward(geo_point, projector_info);
|
||||
const geographic_msgs::msg::GeoPoint converted_geo_point =
|
||||
autoware::geography_utils::project_reverse(converted_local_point, projector_info);
|
||||
|
||||
EXPECT_NEAR(converted_geo_point.latitude, geo_point.latitude, 0.0001);
|
||||
EXPECT_NEAR(converted_geo_point.longitude, geo_point.longitude, 0.0001);
|
||||
EXPECT_NEAR(converted_geo_point.altitude, geo_point.altitude, 0.0001);
|
||||
}
|
||||
|
||||
TEST(GeographyUtilsProjection, ProjectForwardToLocalCartesianUTMOrigin)
|
||||
{
|
||||
// source point
|
||||
geographic_msgs::msg::GeoPoint geo_point;
|
||||
geo_point.latitude = 35.62406;
|
||||
geo_point.longitude = 139.74252;
|
||||
geo_point.altitude = 10.0;
|
||||
|
||||
// target point
|
||||
geometry_msgs::msg::Point local_point;
|
||||
local_point.x = 0.0;
|
||||
local_point.y = -22.18;
|
||||
local_point.z = 20.0;
|
||||
|
||||
// projector info
|
||||
tier4_map_msgs::msg::MapProjectorInfo projector_info;
|
||||
projector_info.projector_type = tier4_map_msgs::msg::MapProjectorInfo::LOCAL_CARTESIAN_UTM;
|
||||
projector_info.vertical_datum = tier4_map_msgs::msg::MapProjectorInfo::WGS84;
|
||||
projector_info.map_origin.latitude = 35.62426;
|
||||
projector_info.map_origin.longitude = 139.74252;
|
||||
projector_info.map_origin.altitude = -10.0;
|
||||
|
||||
// conversion
|
||||
const geometry_msgs::msg::Point converted_point =
|
||||
autoware::geography_utils::project_forward(geo_point, projector_info);
|
||||
|
||||
EXPECT_NEAR(converted_point.x, local_point.x, 1.0);
|
||||
EXPECT_NEAR(converted_point.y, local_point.y, 1.0);
|
||||
EXPECT_NEAR(converted_point.z, local_point.z, 1.0);
|
||||
}
|
||||
|
||||
TEST(GeographyUtilsProjection, ProjectForwardAndReverseLocalCartesianUTMOrigin)
|
||||
{
|
||||
// source point
|
||||
geographic_msgs::msg::GeoPoint geo_point;
|
||||
geo_point.latitude = 35.62426;
|
||||
geo_point.longitude = 139.74252;
|
||||
geo_point.altitude = 10.0;
|
||||
|
||||
// projector info
|
||||
tier4_map_msgs::msg::MapProjectorInfo projector_info;
|
||||
projector_info.projector_type = tier4_map_msgs::msg::MapProjectorInfo::LOCAL_CARTESIAN_UTM;
|
||||
projector_info.vertical_datum = tier4_map_msgs::msg::MapProjectorInfo::WGS84;
|
||||
projector_info.map_origin.latitude = 35.0;
|
||||
projector_info.map_origin.longitude = 139.0;
|
||||
projector_info.map_origin.altitude = 0.0;
|
||||
|
||||
// conversion
|
||||
const geometry_msgs::msg::Point converted_local_point =
|
||||
autoware::geography_utils::project_forward(geo_point, projector_info);
|
||||
const geographic_msgs::msg::GeoPoint converted_geo_point =
|
||||
autoware::geography_utils::project_reverse(converted_local_point, projector_info);
|
||||
|
||||
EXPECT_NEAR(converted_geo_point.latitude, geo_point.latitude, 0.0001);
|
||||
EXPECT_NEAR(converted_geo_point.longitude, geo_point.longitude, 0.0001);
|
||||
EXPECT_NEAR(converted_geo_point.altitude, geo_point.altitude, 0.0001);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(autoware_grid_map_utils)
|
||||
|
||||
if(NOT CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
endif()
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
add_compile_options(-Wall -Wextra -Wpedantic)
|
||||
endif()
|
||||
|
||||
find_package(autoware_cmake REQUIRED)
|
||||
autoware_package()
|
||||
find_package(ament_cmake REQUIRED)
|
||||
|
||||
ament_auto_add_library(${PROJECT_NAME} SHARED
|
||||
DIRECTORY src
|
||||
)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME})
|
||||
|
||||
if(BUILD_TESTING)
|
||||
find_package(ament_lint_auto REQUIRED)
|
||||
ament_lint_auto_find_test_dependencies()
|
||||
|
||||
ament_add_gtest(test_${PROJECT_NAME}
|
||||
test/test_polygon_iterator.cpp
|
||||
)
|
||||
target_link_libraries(test_${PROJECT_NAME}
|
||||
${PROJECT_NAME}
|
||||
)
|
||||
|
||||
find_package(OpenCV REQUIRED)
|
||||
add_executable(benchmark test/benchmark.cpp)
|
||||
target_link_libraries(benchmark
|
||||
${PROJECT_NAME}
|
||||
${OpenCV_LIBS}
|
||||
)
|
||||
endif()
|
||||
|
||||
ament_auto_package()
|
||||
@@ -0,0 +1,51 @@
|
||||
# Grid Map Utils
|
||||
|
||||
## Overview
|
||||
|
||||
This packages contains a re-implementation of the `grid_map::PolygonIterator` used to iterate over
|
||||
all cells of a grid map contained inside some polygon.
|
||||
|
||||
## Algorithm
|
||||
|
||||
This implementation uses the [scan line algorithm](https://en.wikipedia.org/wiki/Scanline_rendering),
|
||||
a common algorithm used to draw polygons on a rasterized image.
|
||||
The main idea of the algorithm adapted to a grid map is as follow:
|
||||
|
||||
- calculate intersections between rows of the grid map and the edges of the polygon edges;
|
||||
- calculate for each row the column between each pair of intersections;
|
||||
- the resulting `(row, column)` indexes are inside of the polygon.
|
||||
|
||||
More details on the scan line algorithm can be found in the References.
|
||||
|
||||
## API
|
||||
|
||||
The `autoware::grid_map_utils::PolygonIterator` follows the same API as the original [`grid_map::PolygonIterator`](https://docs.ros.org/en/kinetic/api/grid_map_core/html/classgrid__map_1_1PolygonIterator.html).
|
||||
|
||||
## Assumptions
|
||||
|
||||
The behavior of the `autoware::grid_map_utils::PolygonIterator` is only guaranteed to match the `grid_map::PolygonIterator` if edges of the polygon do not _exactly_ cross any cell center.
|
||||
In such a case, whether the crossed cell is considered inside or outside of the polygon can vary due to floating precision error.
|
||||
|
||||
## Performances
|
||||
|
||||
Benchmarking code is implemented in `test/benchmarking.cpp` and is also used to validate that the `autoware::grid_map_utils::PolygonIterator` behaves exactly like the `grid_map::PolygonIterator`.
|
||||
|
||||
The following figure shows a comparison of the runtime between the implementation of this package (`autoware_grid_map_utils`) and the original implementation (`grid_map`).
|
||||
The time measured includes the construction of the iterator and the iteration over all indexes and is shown using a logarithmic scale.
|
||||
Results were obtained varying the side size of a square grid map with `100 <= n <= 1000` (size=`n` means a grid of `n x n` cells),
|
||||
random polygons with a number of vertices `3 <= m <= 100` and with each parameter `(n,m)` repeated 10 times.
|
||||
|
||||

|
||||
|
||||
## Future improvements
|
||||
|
||||
There exists variations of the scan line algorithm for multiple polygons.
|
||||
These can be implemented if we want to iterate over the cells contained in at least one of multiple polygons.
|
||||
|
||||
The current implementation imitate the behavior of the original `grid_map::PolygonIterator` where a cell is selected if its center position is inside the polygon.
|
||||
This behavior could be changed for example to only return all cells overlapped by the polygon.
|
||||
|
||||
## References
|
||||
|
||||
- <https://en.wikipedia.org/wiki/Scanline_rendering>
|
||||
- <https://web.cs.ucdavis.edu/~ma/ECS175_S00/Notes/0411_b.pdf>
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
// Copyright 2022 Tier IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef AUTOWARE__GRID_MAP_UTILS__POLYGON_ITERATOR_HPP_
|
||||
#define AUTOWARE__GRID_MAP_UTILS__POLYGON_ITERATOR_HPP_
|
||||
|
||||
#include "grid_map_core/TypeDefs.hpp"
|
||||
|
||||
#include <grid_map_core/GridMap.hpp>
|
||||
#include <grid_map_core/GridMapMath.hpp>
|
||||
#include <grid_map_core/Polygon.hpp>
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace autoware::grid_map_utils
|
||||
{
|
||||
|
||||
/// @brief Representation of a polygon edge made of 2 vertices
|
||||
struct Edge
|
||||
{
|
||||
grid_map::Position first;
|
||||
grid_map::Position second;
|
||||
|
||||
Edge(grid_map::Position f, grid_map::Position s) : first(std::move(f)), second(std::move(s)) {}
|
||||
|
||||
/// @brief Sorting operator resulting in edges sorted from highest to lowest x values
|
||||
bool operator<(const Edge & e)
|
||||
{
|
||||
return first.x() > e.first.x() || (first.x() == e.first.x() && second.x() > e.second.x());
|
||||
}
|
||||
};
|
||||
|
||||
/** @brief A polygon iterator for grid_map::GridMap based on the scan line algorithm.
|
||||
@details This iterator allows to iterate over all cells whose center is inside a polygon. \
|
||||
This reproduces the behavior of the original grid_map::PolygonIterator which uses\
|
||||
a "point in polygon" check for each cell of the gridmap, making it very expensive\
|
||||
to run on large maps. In comparison, the scan line algorithm implemented here is \
|
||||
much more scalable.
|
||||
*/
|
||||
class PolygonIterator
|
||||
{
|
||||
public:
|
||||
/// @brief Constructor.
|
||||
/// @details Calculate the indexes of the gridmap that are inside the polygon using the scan line
|
||||
/// algorithm.
|
||||
/// @param grid_map the grid map to iterate on.
|
||||
/// @param polygon the polygonal area to iterate on.
|
||||
PolygonIterator(const grid_map::GridMap & grid_map, const grid_map::Polygon & polygon);
|
||||
/// @brief Compare to another iterator.
|
||||
/// @param other other iterator.
|
||||
/// @return whether the current iterator points to a different address than the other one.
|
||||
bool operator!=(const PolygonIterator & other) const;
|
||||
/// @brief Dereference the iterator with const.
|
||||
/// @return the value to which the iterator is pointing.
|
||||
const grid_map::Index & operator*() const;
|
||||
/// @brief Increase the iterator to the next element.
|
||||
/// @return a reference to the updated iterator.
|
||||
PolygonIterator & operator++();
|
||||
/// @brief Indicates if iterator is past end.
|
||||
/// @return true if iterator is out of scope, false if end has not been reached.
|
||||
[[nodiscard]] bool isPastEnd() const;
|
||||
|
||||
private:
|
||||
/** @brief Calculate sorted edges of the given polygon.
|
||||
@details Vertices in an edge are ordered from higher to lower x.
|
||||
Edges are sorted in reverse lexicographical order of x.
|
||||
@param polygon Polygon for which edges are calculated.
|
||||
@return Sorted edges of the polygon.
|
||||
*/
|
||||
static std::vector<Edge> calculateSortedEdges(const grid_map::Polygon & polygon);
|
||||
|
||||
/// @brief Calculates intersections between lines (i.e., center of rows) and the polygon edges.
|
||||
/// @param edges Edges of the polygon.
|
||||
/// @param from_to_row ranges of lines to use for intersection.
|
||||
/// @param origin Position of the top-left cell in the grid map.
|
||||
/// @param grid_map grid map.
|
||||
/// @return for each row the vector of y values with an intersection.
|
||||
static std::vector<std::vector<double>> calculateIntersectionsPerLine(
|
||||
const std::vector<Edge> & edges, const std::pair<int, int> from_to_row,
|
||||
const grid_map::Position & origin, const grid_map::GridMap & grid_map);
|
||||
|
||||
/// @brief Calculates the range of rows covering the given edges.
|
||||
/// @details The rows are calculated without any shift that might exist in the grid map.
|
||||
/// @param edges Edges of the polygon.
|
||||
/// @param origin Position of the top-left cell in the grid map.
|
||||
/// @param grid_map grid map.
|
||||
/// @return the range of rows as a pair {first row, last row}.
|
||||
static std::pair<int, int> calculateRowRange(
|
||||
const std::vector<Edge> & edges, const grid_map::Position & origin,
|
||||
const grid_map::GridMap & grid_map);
|
||||
|
||||
// Helper functions
|
||||
/// @brief Increment the current_line_ to the line with intersections
|
||||
void goToNextLine();
|
||||
/// @brief Calculate the initial current_col_ and the current_to_col_ for the current intersection
|
||||
void calculateColumnIndexes();
|
||||
/// @brief Calculate the current_index_ from the current_line_ and current_col_
|
||||
void calculateIndex();
|
||||
|
||||
/// Gridmap info
|
||||
int row_of_first_line_;
|
||||
grid_map::Index map_start_idx_;
|
||||
grid_map::Size map_size_;
|
||||
double map_resolution_;
|
||||
double map_origin_y_;
|
||||
/// Intersections between scan lines and the polygon
|
||||
std::vector<std::vector<double>> intersections_per_line_;
|
||||
std::vector<double>::const_iterator intersection_iter_;
|
||||
/// current indexes
|
||||
grid_map::Index current_index_;
|
||||
size_t current_line_;
|
||||
int current_col_;
|
||||
int current_to_col_;
|
||||
};
|
||||
} // namespace autoware::grid_map_utils
|
||||
|
||||
#endif // AUTOWARE__GRID_MAP_UTILS__POLYGON_ITERATOR_HPP_
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="3">
|
||||
<name>autoware_grid_map_utils</name>
|
||||
<version>0.0.0</version>
|
||||
<description>Utilities for the grid_map library</description>
|
||||
<maintainer email="maxime.clement@tier4.jp">Maxime CLEMENT</maintainer>
|
||||
<license>Apache License 2.0</license>
|
||||
|
||||
<buildtool_depend>autoware_cmake</buildtool_depend>
|
||||
<buildtool_depend>eigen3_cmake_module</buildtool_depend>
|
||||
|
||||
<depend>autoware_universe_utils</depend>
|
||||
<depend>grid_map_core</depend>
|
||||
<depend>grid_map_cv</depend>
|
||||
<depend>libopencv-dev</depend>
|
||||
|
||||
<test_depend>ament_cmake_gtest</test_depend>
|
||||
<test_depend>ament_lint_auto</test_depend>
|
||||
<test_depend>autoware_lint_common</test_depend>
|
||||
|
||||
<export>
|
||||
<build_type>ament_cmake</build_type>
|
||||
</export>
|
||||
</package>
|
||||
@@ -0,0 +1,217 @@
|
||||
// Copyright 2022 Tier IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/grid_map_utils/polygon_iterator.hpp"
|
||||
|
||||
#include "grid_map_core/GridMap.hpp"
|
||||
#include "grid_map_core/Polygon.hpp"
|
||||
#include "grid_map_core/TypeDefs.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
namespace autoware::grid_map_utils
|
||||
{
|
||||
|
||||
std::vector<Edge> PolygonIterator::calculateSortedEdges(const grid_map::Polygon & polygon)
|
||||
{
|
||||
std::vector<Edge> edges;
|
||||
edges.reserve(polygon.nVertices());
|
||||
const auto & vertices = polygon.getVertices();
|
||||
for (auto vertex = vertices.cbegin(); std::next(vertex) != vertices.cend(); ++vertex) {
|
||||
// order pair by decreasing x and ignore horizontal edges (when x is equal)
|
||||
if (vertex->x() > std::next(vertex)->x())
|
||||
edges.emplace_back(*vertex, *std::next(vertex));
|
||||
else if (vertex->x() < std::next(vertex)->x())
|
||||
edges.emplace_back(*std::next(vertex), *vertex);
|
||||
}
|
||||
std::sort(edges.begin(), edges.end());
|
||||
edges.shrink_to_fit();
|
||||
return edges;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> PolygonIterator::calculateIntersectionsPerLine(
|
||||
const std::vector<Edge> & edges, const std::pair<int, int> from_to_row,
|
||||
const grid_map::Position & origin, const grid_map::GridMap & grid_map)
|
||||
{
|
||||
const auto from_row = from_to_row.first;
|
||||
const auto to_row = from_to_row.second;
|
||||
// calculate for each line the y value intersecting with the polygon in decreasing order
|
||||
std::vector<std::vector<double>> y_intersections_per_line;
|
||||
y_intersections_per_line.reserve(to_row - from_row + 1);
|
||||
for (auto row = from_row; row <= to_row; ++row) {
|
||||
std::vector<double> y_intersections;
|
||||
const auto line_x = origin.x() - grid_map.getResolution() * row;
|
||||
for (const auto & edge : edges) {
|
||||
// special case when exactly touching a vertex: only count edge for its lowest x
|
||||
// up-down edge (\/) case: count the vertex twice
|
||||
// down-down edge case: count the vertex only once
|
||||
if (edge.second.x() == line_x) {
|
||||
y_intersections.push_back(edge.second.y());
|
||||
} else if (edge.first.x() >= line_x && edge.second.x() < line_x) {
|
||||
const auto diff = edge.first - edge.second;
|
||||
const auto y = edge.second.y() + (line_x - edge.second.x()) * diff.y() / diff.x();
|
||||
y_intersections.push_back(y);
|
||||
} else if (edge.first.x() < line_x) { // edge below the line
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::sort(y_intersections.begin(), y_intersections.end(), std::greater());
|
||||
// remove pairs outside of map
|
||||
auto iter = y_intersections.cbegin();
|
||||
while (iter != y_intersections.cend() && std::next(iter) != y_intersections.cend() &&
|
||||
*iter >= origin.y() && *std::next(iter) >= origin.y()) {
|
||||
iter = y_intersections.erase(iter);
|
||||
iter = y_intersections.erase(iter);
|
||||
}
|
||||
iter = std::lower_bound(
|
||||
y_intersections.cbegin(), y_intersections.cend(),
|
||||
origin.y() - (grid_map.getSize()(1) - 1) * grid_map.getResolution(), std::greater());
|
||||
while (iter != y_intersections.cend() && std::next(iter) != y_intersections.cend()) {
|
||||
iter = y_intersections.erase(iter);
|
||||
iter = y_intersections.erase(iter);
|
||||
}
|
||||
y_intersections_per_line.push_back(y_intersections);
|
||||
}
|
||||
return y_intersections_per_line;
|
||||
}
|
||||
|
||||
std::pair<int, int> PolygonIterator::calculateRowRange(
|
||||
const std::vector<Edge> & edges, const grid_map::Position & origin,
|
||||
const grid_map::GridMap & grid_map)
|
||||
{
|
||||
const auto min_vertex_x =
|
||||
std::min_element(edges.cbegin(), edges.cend(), [](const Edge & e1, const Edge & e2) {
|
||||
return e1.second.x() < e2.second.x();
|
||||
})->second.x();
|
||||
const auto max_vertex_x = edges.front().first.x();
|
||||
|
||||
const auto dist_min_to_origin = origin.x() - min_vertex_x + grid_map.getResolution();
|
||||
const auto dist_max_to_origin = origin.x() - max_vertex_x + grid_map.getResolution();
|
||||
const auto min_row = std::clamp(
|
||||
static_cast<int>(dist_max_to_origin / grid_map.getResolution()), 0, grid_map.getSize()(0) - 1);
|
||||
const auto max_row = std::clamp(
|
||||
static_cast<int>(dist_min_to_origin / grid_map.getResolution()), 0, grid_map.getSize()(0) - 1);
|
||||
|
||||
return {min_row, max_row};
|
||||
}
|
||||
|
||||
PolygonIterator::PolygonIterator(
|
||||
const grid_map::GridMap & grid_map, const grid_map::Polygon & polygon)
|
||||
{
|
||||
auto poly = polygon;
|
||||
if (poly.nVertices() < 3) return;
|
||||
// repeat the first vertex to get the last edge [last vertex, first vertex]
|
||||
if (poly.getVertex(0) != poly.getVertex(poly.nVertices() - 1)) poly.addVertex(poly.getVertex(0));
|
||||
|
||||
map_start_idx_ = grid_map.getStartIndex();
|
||||
map_resolution_ = grid_map.getResolution();
|
||||
map_size_ = grid_map.getSize();
|
||||
const auto origin = [&]() {
|
||||
grid_map::Position origin;
|
||||
grid_map.getPosition(map_start_idx_, origin);
|
||||
return origin;
|
||||
}();
|
||||
map_origin_y_ = origin.y();
|
||||
|
||||
// We make line scan left -> right / up -> down *in the index frame* (idx[0,0] is pos[up, left]).
|
||||
// In the position frame, this corresponds to high -> low Y values and high -> low X values.
|
||||
const std::vector<Edge> edges = calculateSortedEdges(poly);
|
||||
if (edges.empty()) return;
|
||||
const auto from_to_row = calculateRowRange(edges, origin, grid_map);
|
||||
intersections_per_line_ = calculateIntersectionsPerLine(edges, from_to_row, origin, grid_map);
|
||||
|
||||
row_of_first_line_ = from_to_row.first;
|
||||
current_col_ = 0;
|
||||
current_to_col_ = -1;
|
||||
current_line_ = -1; // goToNextLine() increments the line so assign -1 to start from 0
|
||||
|
||||
// Initialize iterator to the first (row,column) inside the Polygon
|
||||
if (!intersections_per_line_.empty()) {
|
||||
goToNextLine();
|
||||
if (!isPastEnd()) {
|
||||
calculateColumnIndexes();
|
||||
calculateIndex();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PolygonIterator::operator!=(const PolygonIterator & other) const
|
||||
{
|
||||
return current_line_ != other.current_line_ || current_col_ != other.current_col_;
|
||||
}
|
||||
|
||||
const grid_map::Index & PolygonIterator::operator*() const
|
||||
{
|
||||
return current_index_;
|
||||
}
|
||||
|
||||
void PolygonIterator::goToNextLine()
|
||||
{
|
||||
++current_line_;
|
||||
while (current_line_ < intersections_per_line_.size() &&
|
||||
intersections_per_line_[current_line_].size() < 2)
|
||||
++current_line_;
|
||||
if (!isPastEnd()) intersection_iter_ = intersections_per_line_[current_line_].cbegin();
|
||||
}
|
||||
|
||||
void PolygonIterator::calculateColumnIndexes()
|
||||
{
|
||||
const auto dist_from_origin = map_origin_y_ - *intersection_iter_ + map_resolution_;
|
||||
current_col_ =
|
||||
std::clamp(static_cast<int>(dist_from_origin / map_resolution_), 0, map_size_(1) - 1);
|
||||
++intersection_iter_;
|
||||
const auto dist_to_origin = map_origin_y_ - *intersection_iter_;
|
||||
current_to_col_ =
|
||||
std::clamp(static_cast<int>(dist_to_origin / map_resolution_), 0, map_size_(1) - 1);
|
||||
// Case where intersections do not encompass the center of a cell: iterate again
|
||||
if (current_to_col_ < current_col_) {
|
||||
operator++();
|
||||
}
|
||||
}
|
||||
|
||||
void PolygonIterator::calculateIndex()
|
||||
{
|
||||
current_index_(0) = map_start_idx_(0) + row_of_first_line_ + static_cast<int>(current_line_);
|
||||
grid_map::wrapIndexToRange(current_index_(0), map_size_(0));
|
||||
current_index_(1) = map_start_idx_(1) + current_col_;
|
||||
grid_map::wrapIndexToRange(current_index_(1), map_size_(1));
|
||||
}
|
||||
|
||||
PolygonIterator & PolygonIterator::operator++()
|
||||
{
|
||||
++current_col_;
|
||||
if (current_col_ > current_to_col_) {
|
||||
++intersection_iter_;
|
||||
if (
|
||||
intersection_iter_ == intersections_per_line_[current_line_].cend() ||
|
||||
std::next(intersection_iter_) == intersections_per_line_[current_line_].cend()) {
|
||||
goToNextLine();
|
||||
}
|
||||
if (!isPastEnd()) {
|
||||
calculateColumnIndexes();
|
||||
}
|
||||
}
|
||||
if (!isPastEnd()) {
|
||||
calculateIndex();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool PolygonIterator::isPastEnd() const
|
||||
{
|
||||
return current_line_ >= intersections_per_line_.size();
|
||||
}
|
||||
} // namespace autoware::grid_map_utils
|
||||
@@ -0,0 +1,182 @@
|
||||
// Copyright 2022 Tier IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/grid_map_utils/polygon_iterator.hpp"
|
||||
#include "grid_map_core/TypeDefs.hpp"
|
||||
#include "grid_map_cv/GridMapCvConverter.hpp"
|
||||
#include "grid_map_cv/GridMapCvProcessing.hpp"
|
||||
|
||||
#include <autoware/universe_utils/system/stop_watch.hpp>
|
||||
#include <grid_map_core/iterators/PolygonIterator.hpp>
|
||||
#include <grid_map_cv/grid_map_cv.hpp>
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
bool visualize = false;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
const auto arg = std::string(argv[i]);
|
||||
if (arg == "-v" || arg == "--visualize") {
|
||||
visualize = true;
|
||||
}
|
||||
}
|
||||
std::ofstream result_file;
|
||||
result_file.open("benchmark_results.csv");
|
||||
result_file
|
||||
<< "#Size PolygonVertices PolygonIndexes grid_map_utils_constructor grid_map_utils_iteration "
|
||||
"grid_map_constructor grid_map_iteration\n";
|
||||
autoware::universe_utils::StopWatch<std::chrono::milliseconds> stopwatch;
|
||||
|
||||
constexpr auto nb_iterations = 10;
|
||||
constexpr auto polygon_side_vertices =
|
||||
25; // number of vertex per side of the square base_polygon
|
||||
const auto grid_map_length = grid_map::Length(10.0, 10.0);
|
||||
std::random_device r;
|
||||
std::default_random_engine engine(0);
|
||||
// TODO(Maxime CLEMENT): moving breaks the polygon visualization
|
||||
std::uniform_real_distribution move_dist(-2.0, 2.0);
|
||||
std::uniform_real_distribution poly_x_offset(-2.0, 2.0);
|
||||
std::uniform_real_distribution poly_y_offset(-2.0, 2.0);
|
||||
|
||||
grid_map::Polygon base_polygon;
|
||||
const auto top_left = grid_map::Position(-grid_map_length.x() / 2, grid_map_length.y() / 2);
|
||||
const auto top_right = grid_map::Position(grid_map_length.x() / 2, grid_map_length.y() / 2);
|
||||
const auto bot_right = grid_map::Position(grid_map_length.x() / 2, -grid_map_length.y() / 2);
|
||||
const auto bot_left = grid_map::Position(-grid_map_length.x() / 2, -grid_map_length.y() / 2);
|
||||
const auto top_vector = top_right - top_left;
|
||||
for (double i = 0; i < polygon_side_vertices; ++i) {
|
||||
const auto factor = i / polygon_side_vertices;
|
||||
base_polygon.addVertex(top_left + factor * top_vector);
|
||||
}
|
||||
const auto right_vector = bot_right - top_right;
|
||||
for (double i = 0; i < polygon_side_vertices; ++i) {
|
||||
const auto factor = i / polygon_side_vertices;
|
||||
base_polygon.addVertex(top_right + factor * right_vector);
|
||||
}
|
||||
const auto bot_vector = bot_left - bot_right;
|
||||
for (double i = 0; i < polygon_side_vertices; ++i) {
|
||||
const auto factor = i / polygon_side_vertices;
|
||||
base_polygon.addVertex(bot_right + factor * bot_vector);
|
||||
}
|
||||
const auto left_vector = top_left - bot_left;
|
||||
for (double i = 0; i < polygon_side_vertices; ++i) {
|
||||
const auto factor = i / polygon_side_vertices;
|
||||
base_polygon.addVertex(bot_left + factor * left_vector);
|
||||
}
|
||||
|
||||
for (auto grid_map_size = 100; grid_map_size <= 1000; grid_map_size += 100) {
|
||||
std::cout << "Map of size " << grid_map_size << " by " << grid_map_size << std::endl;
|
||||
const auto resolution = grid_map_length(0) / grid_map_size;
|
||||
grid_map::GridMap map({"layer"});
|
||||
map.setGeometry(grid_map_length, resolution);
|
||||
for (auto vertices = 3ul; vertices <= base_polygon.nVertices(); ++vertices) {
|
||||
auto polygon_indexes = 0.0;
|
||||
std::cout << "\tPolygon with " << vertices << " vertices" << std::endl;
|
||||
|
||||
double grid_map_utils_constructor_duration{};
|
||||
double grid_map_constructor_duration{};
|
||||
double grid_map_utils_iteration_duration{};
|
||||
double grid_map_iteration_duration{};
|
||||
|
||||
for (auto iteration = 0; iteration < nb_iterations; ++iteration) {
|
||||
map.setGeometry(grid_map::Length(10.0, 10.0), resolution, grid_map::Position(0.0, 0.0));
|
||||
const auto move = grid_map::Position(move_dist(engine), move_dist(engine));
|
||||
map.move(move);
|
||||
|
||||
// generate random sub-polygon of base_polygon with some noise
|
||||
grid_map::Polygon polygon;
|
||||
std::vector<size_t> indexes(base_polygon.nVertices());
|
||||
for (size_t i = 0; i <= base_polygon.nVertices(); ++i) indexes[i] = i;
|
||||
std::shuffle(indexes.begin(), indexes.end(), std::default_random_engine(iteration));
|
||||
indexes.resize(vertices);
|
||||
std::sort(indexes.begin(), indexes.end());
|
||||
for (const auto idx : indexes) {
|
||||
const auto offset = grid_map::Position(poly_x_offset(engine), poly_y_offset(engine));
|
||||
polygon.addVertex(base_polygon.getVertex(idx) + offset);
|
||||
}
|
||||
stopwatch.tic("gmu_ctor");
|
||||
autoware::grid_map_utils::PolygonIterator grid_map_utils_iterator(map, polygon);
|
||||
grid_map_utils_constructor_duration += stopwatch.toc("gmu_ctor");
|
||||
stopwatch.tic("gm_ctor");
|
||||
grid_map::PolygonIterator grid_map_iterator(map, polygon);
|
||||
grid_map_constructor_duration += stopwatch.toc("gm_ctor");
|
||||
bool diff = false;
|
||||
while (!grid_map_utils_iterator.isPastEnd() && !grid_map_iterator.isPastEnd()) {
|
||||
stopwatch.tic("gmu_iter");
|
||||
const auto gmu_idx = *grid_map_utils_iterator;
|
||||
++grid_map_utils_iterator;
|
||||
grid_map_utils_iteration_duration += stopwatch.toc("gmu_iter");
|
||||
stopwatch.tic("gm_iter");
|
||||
const auto gm_idx = *grid_map_iterator;
|
||||
++grid_map_iterator;
|
||||
grid_map_iteration_duration += stopwatch.toc("gm_iter");
|
||||
++polygon_indexes;
|
||||
|
||||
if (gmu_idx.x() != gm_idx.x() || gmu_idx.y() != gm_idx.y()) {
|
||||
diff = true;
|
||||
}
|
||||
}
|
||||
if (grid_map_iterator.isPastEnd() != grid_map_utils_iterator.isPastEnd()) {
|
||||
diff = true;
|
||||
}
|
||||
if (diff || visualize) {
|
||||
// Prepare images of the cells selected by the two PolygonIterators
|
||||
auto gridmap = map;
|
||||
for (autoware::grid_map_utils::PolygonIterator iterator(map, polygon);
|
||||
!iterator.isPastEnd(); ++iterator)
|
||||
map.at("layer", *iterator) = 100;
|
||||
for (grid_map::PolygonIterator iterator(gridmap, polygon); !iterator.isPastEnd();
|
||||
++iterator)
|
||||
gridmap.at("layer", *iterator) = 100;
|
||||
|
||||
cv::Mat img;
|
||||
cv::Mat custom_img;
|
||||
cv::Mat gm_img;
|
||||
cv::Mat diff_img;
|
||||
|
||||
grid_map::GridMapCvConverter::toImage<unsigned char, 1>(
|
||||
map, "layer", CV_8UC1, 0.0, 100, img);
|
||||
cv::resize(img, custom_img, cv::Size(500, 500), cv::INTER_LINEAR);
|
||||
grid_map::GridMapCvConverter::toImage<unsigned char, 1>(
|
||||
gridmap, "layer", CV_8UC1, 0.0, 100, img);
|
||||
cv::resize(img, gm_img, cv::Size(500, 500), cv::INTER_LINEAR);
|
||||
cv::compare(custom_img, gm_img, diff_img, cv::CMP_EQ);
|
||||
|
||||
cv::imshow("custom", custom_img);
|
||||
cv::imshow("grid_map", gm_img);
|
||||
cv::imshow("diff", diff_img);
|
||||
cv::waitKey(0);
|
||||
cv::destroyAllWindows();
|
||||
}
|
||||
}
|
||||
// print results to file
|
||||
result_file << grid_map_size << " " << vertices << " " << polygon_indexes / nb_iterations
|
||||
<< " " << grid_map_utils_constructor_duration / nb_iterations << " "
|
||||
<< grid_map_utils_iteration_duration / nb_iterations << " "
|
||||
<< grid_map_constructor_duration / nb_iterations << " "
|
||||
<< grid_map_iteration_duration / nb_iterations << "\n";
|
||||
}
|
||||
}
|
||||
result_file.close();
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
// Copyright 2022 Tier IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/grid_map_utils/polygon_iterator.hpp"
|
||||
|
||||
#include <autoware/universe_utils/system/stop_watch.hpp>
|
||||
#include <grid_map_core/iterators/PolygonIterator.hpp>
|
||||
|
||||
// gtest
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
// Vector
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using grid_map::GridMap;
|
||||
using grid_map::Index;
|
||||
using grid_map::Length;
|
||||
using grid_map::Polygon;
|
||||
using grid_map::Position;
|
||||
|
||||
// Copied from grid_map::PolygonIterator
|
||||
TEST(PolygonIterator, FullCover)
|
||||
{
|
||||
std::vector<std::string> types;
|
||||
types.emplace_back("type");
|
||||
GridMap map(types);
|
||||
map.setGeometry(Length(8.0, 5.0), 1.0, Position(0.0, 0.0)); // bufferSize(8, 5)
|
||||
|
||||
Polygon polygon;
|
||||
polygon.addVertex(Position(-100.0, 100.0));
|
||||
polygon.addVertex(Position(100.0, 100.0));
|
||||
polygon.addVertex(Position(100.0, -100.0));
|
||||
polygon.addVertex(Position(-100.0, -100.0));
|
||||
|
||||
autoware::grid_map_utils::PolygonIterator iterator(map, polygon);
|
||||
|
||||
EXPECT_FALSE(iterator.isPastEnd());
|
||||
EXPECT_EQ(0, (*iterator)(0));
|
||||
EXPECT_EQ(0, (*iterator)(1));
|
||||
|
||||
++iterator;
|
||||
EXPECT_FALSE(iterator.isPastEnd());
|
||||
EXPECT_EQ(0, (*iterator)(0));
|
||||
EXPECT_EQ(1, (*iterator)(1));
|
||||
|
||||
++iterator;
|
||||
EXPECT_FALSE(iterator.isPastEnd());
|
||||
EXPECT_EQ(0, (*iterator)(0));
|
||||
EXPECT_EQ(2, (*iterator)(1));
|
||||
|
||||
for (int i = 0; i < 37; ++i) ++iterator;
|
||||
|
||||
EXPECT_FALSE(iterator.isPastEnd());
|
||||
EXPECT_EQ(7, (*iterator)(0));
|
||||
EXPECT_EQ(4, (*iterator)(1));
|
||||
|
||||
++iterator;
|
||||
EXPECT_TRUE(iterator.isPastEnd());
|
||||
}
|
||||
|
||||
// Copied from grid_map::PolygonIterator
|
||||
TEST(PolygonIterator, Outside)
|
||||
{
|
||||
GridMap map({"types"});
|
||||
map.setGeometry(Length(8.0, 5.0), 1.0, Position(0.0, 0.0)); // bufferSize(8, 5)
|
||||
|
||||
Polygon polygon;
|
||||
polygon.addVertex(Position(99.0, 101.0));
|
||||
polygon.addVertex(Position(101.0, 101.0));
|
||||
polygon.addVertex(Position(101.0, 99.0));
|
||||
polygon.addVertex(Position(99.0, 99.0));
|
||||
|
||||
autoware::grid_map_utils::PolygonIterator iterator(map, polygon);
|
||||
|
||||
EXPECT_TRUE(iterator.isPastEnd());
|
||||
}
|
||||
|
||||
// Copied from grid_map::PolygonIterator
|
||||
TEST(PolygonIterator, Square)
|
||||
{
|
||||
GridMap map({"types"});
|
||||
map.setGeometry(Length(8.0, 5.0), 1.0, Position(0.0, 0.0)); // bufferSize(8, 5)
|
||||
|
||||
Polygon polygon;
|
||||
polygon.addVertex(Position(-1.0, 1.5));
|
||||
polygon.addVertex(Position(1.0, 1.5));
|
||||
polygon.addVertex(Position(1.0, -1.5));
|
||||
polygon.addVertex(Position(-1.0, -1.5));
|
||||
|
||||
autoware::grid_map_utils::PolygonIterator iterator(map, polygon);
|
||||
|
||||
EXPECT_FALSE(iterator.isPastEnd());
|
||||
EXPECT_EQ(3, (*iterator)(0));
|
||||
EXPECT_EQ(1, (*iterator)(1));
|
||||
|
||||
++iterator;
|
||||
EXPECT_FALSE(iterator.isPastEnd());
|
||||
EXPECT_EQ(3, (*iterator)(0));
|
||||
EXPECT_EQ(2, (*iterator)(1));
|
||||
|
||||
++iterator;
|
||||
EXPECT_FALSE(iterator.isPastEnd());
|
||||
EXPECT_EQ(3, (*iterator)(0));
|
||||
EXPECT_EQ(3, (*iterator)(1));
|
||||
|
||||
++iterator;
|
||||
EXPECT_FALSE(iterator.isPastEnd());
|
||||
EXPECT_EQ(4, (*iterator)(0));
|
||||
EXPECT_EQ(1, (*iterator)(1));
|
||||
|
||||
++iterator;
|
||||
EXPECT_FALSE(iterator.isPastEnd());
|
||||
EXPECT_EQ(4, (*iterator)(0));
|
||||
EXPECT_EQ(2, (*iterator)(1));
|
||||
|
||||
++iterator;
|
||||
EXPECT_FALSE(iterator.isPastEnd());
|
||||
EXPECT_EQ(4, (*iterator)(0));
|
||||
EXPECT_EQ(3, (*iterator)(1));
|
||||
|
||||
++iterator;
|
||||
EXPECT_TRUE(iterator.isPastEnd());
|
||||
}
|
||||
|
||||
// Copied from grid_map::PolygonIterator
|
||||
TEST(PolygonIterator, TopLeftTriangle)
|
||||
{
|
||||
GridMap map({"types"});
|
||||
map.setGeometry(Length(8.0, 5.0), 1.0, Position(0.0, 0.0)); // bufferSize(8, 5)
|
||||
|
||||
Polygon polygon;
|
||||
polygon.addVertex(Position(-40.1, 20.6));
|
||||
polygon.addVertex(Position(40.1, 20.4));
|
||||
polygon.addVertex(Position(-40.1, -20.6));
|
||||
|
||||
autoware::grid_map_utils::PolygonIterator iterator(map, polygon);
|
||||
|
||||
EXPECT_FALSE(iterator.isPastEnd());
|
||||
EXPECT_EQ(0, (*iterator)(0));
|
||||
EXPECT_EQ(0, (*iterator)(1));
|
||||
|
||||
++iterator;
|
||||
EXPECT_FALSE(iterator.isPastEnd());
|
||||
EXPECT_EQ(1, (*iterator)(0));
|
||||
EXPECT_EQ(0, (*iterator)(1));
|
||||
}
|
||||
|
||||
// Copied from grid_map::PolygonIterator
|
||||
TEST(PolygonIterator, MoveMap)
|
||||
{
|
||||
GridMap map({"layer"});
|
||||
map.setGeometry(Length(8.0, 5.0), 1.0, Position(0.0, 0.0)); // bufferSize(8, 5)
|
||||
map.move(Position(2.0, 0.0));
|
||||
|
||||
Polygon polygon;
|
||||
polygon.addVertex(Position(6.1, 1.6));
|
||||
polygon.addVertex(Position(0.9, 1.6));
|
||||
polygon.addVertex(Position(0.9, -1.6));
|
||||
polygon.addVertex(Position(6.1, -1.6));
|
||||
autoware::grid_map_utils::PolygonIterator iterator(map, polygon);
|
||||
|
||||
EXPECT_FALSE(iterator.isPastEnd());
|
||||
EXPECT_EQ(6, (*iterator)(0));
|
||||
EXPECT_EQ(1, (*iterator)(1));
|
||||
|
||||
++iterator;
|
||||
EXPECT_FALSE(iterator.isPastEnd());
|
||||
EXPECT_EQ(6, (*iterator)(0));
|
||||
EXPECT_EQ(2, (*iterator)(1));
|
||||
|
||||
for (int i = 0; i < 4; ++i) ++iterator;
|
||||
|
||||
EXPECT_FALSE(iterator.isPastEnd());
|
||||
EXPECT_EQ(7, (*iterator)(0));
|
||||
EXPECT_EQ(3, (*iterator)(1));
|
||||
|
||||
++iterator;
|
||||
EXPECT_FALSE(iterator.isPastEnd());
|
||||
EXPECT_EQ(0, (*iterator)(0));
|
||||
EXPECT_EQ(1, (*iterator)(1));
|
||||
|
||||
for (int i = 0; i < 8; ++i) ++iterator;
|
||||
|
||||
EXPECT_FALSE(iterator.isPastEnd());
|
||||
EXPECT_EQ(2, (*iterator)(0));
|
||||
EXPECT_EQ(3, (*iterator)(1));
|
||||
|
||||
++iterator;
|
||||
EXPECT_TRUE(iterator.isPastEnd());
|
||||
}
|
||||
|
||||
// This test shows a difference when an edge passes exactly through the center of a cell
|
||||
TEST(PolygonIterator, Difference)
|
||||
{
|
||||
GridMap map({"layer"});
|
||||
map.setGeometry(Length(5.0, 5.0), 1.0, Position(0.0, 0.0)); // bufferSize(8, 5)
|
||||
|
||||
// Triangle where the hypotenuse is an exact diagonal of the map: difference.
|
||||
Polygon polygon;
|
||||
polygon.addVertex(Position(2.5, 2.5));
|
||||
polygon.addVertex(Position(-2.5, 2.5));
|
||||
polygon.addVertex(Position(-2.5, -2.5));
|
||||
autoware::grid_map_utils::PolygonIterator iterator(map, polygon);
|
||||
grid_map::PolygonIterator gm_iterator(map, polygon);
|
||||
bool diff = false;
|
||||
while (!iterator.isPastEnd() && !gm_iterator.isPastEnd()) {
|
||||
if ((*gm_iterator)(0) != (*iterator)(0) || (*gm_iterator)(1) != (*iterator)(1)) diff = true;
|
||||
++iterator;
|
||||
++gm_iterator;
|
||||
}
|
||||
if (iterator.isPastEnd() != gm_iterator.isPastEnd()) {
|
||||
diff = true;
|
||||
}
|
||||
EXPECT_TRUE(diff);
|
||||
|
||||
// Triangle where the hypotenuse does not cross any cell center: no difference.
|
||||
polygon.removeVertices();
|
||||
polygon.addVertex(Position(2.5, 2.1));
|
||||
polygon.addVertex(Position(-2.5, 2.5));
|
||||
polygon.addVertex(Position(-2.5, -2.9));
|
||||
iterator = autoware::grid_map_utils::PolygonIterator(map, polygon);
|
||||
gm_iterator = grid_map::PolygonIterator(map, polygon);
|
||||
diff = false;
|
||||
while (!iterator.isPastEnd() && !gm_iterator.isPastEnd()) {
|
||||
if ((*gm_iterator)(0) != (*iterator)(0) || (*gm_iterator)(1) != (*iterator)(1)) diff = true;
|
||||
++iterator;
|
||||
++gm_iterator;
|
||||
}
|
||||
if (iterator.isPastEnd() != gm_iterator.isPastEnd()) {
|
||||
diff = true;
|
||||
}
|
||||
EXPECT_FALSE(diff);
|
||||
}
|
||||
|
||||
TEST(PolygonIterator, SelfCrossingPolygon)
|
||||
{
|
||||
GridMap map({"layer"});
|
||||
map.setGeometry(Length(5.0, 5.0), 1.0, Position(0.0, 0.0)); // bufferSize(8, 5)
|
||||
|
||||
// Hour-glass shape
|
||||
Polygon polygon;
|
||||
polygon.addVertex(Position(2.5, 2.9));
|
||||
polygon.addVertex(Position(2.5, -2.9));
|
||||
polygon.addVertex(Position(-2.5, 2.5));
|
||||
polygon.addVertex(Position(-2.5, -2.5));
|
||||
autoware::grid_map_utils::PolygonIterator iterator(map, polygon);
|
||||
grid_map::PolygonIterator gm_iterator(map, polygon);
|
||||
|
||||
const std::vector<Index> expected_indexes = {
|
||||
Index(0, 0), Index(0, 1), Index(0, 2), Index(0, 3), Index(0, 4), Index(1, 1), Index(1, 2),
|
||||
Index(1, 3), Index(2, 2), Index(3, 2), Index(4, 1), Index(4, 2), Index(4, 3)};
|
||||
bool diff = false;
|
||||
size_t i = 0;
|
||||
while (!iterator.isPastEnd() && !gm_iterator.isPastEnd()) {
|
||||
if ((*gm_iterator)(0) != (*iterator)(0) || (*gm_iterator)(1) != (*iterator)(1)) diff = true;
|
||||
ASSERT_TRUE(i < expected_indexes.size());
|
||||
EXPECT_EQ((*iterator)(0), expected_indexes[i](0));
|
||||
EXPECT_EQ((*iterator)(1), expected_indexes[i](1));
|
||||
++i;
|
||||
++iterator;
|
||||
++gm_iterator;
|
||||
}
|
||||
if (iterator.isPastEnd() != gm_iterator.isPastEnd()) {
|
||||
diff = true;
|
||||
}
|
||||
EXPECT_FALSE(diff);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(autoware_interpolation)
|
||||
|
||||
find_package(autoware_cmake REQUIRED)
|
||||
autoware_package()
|
||||
|
||||
ament_auto_add_library(autoware_interpolation SHARED
|
||||
src/linear_interpolation.cpp
|
||||
src/spline_interpolation.cpp
|
||||
src/spline_interpolation_points_2d.cpp
|
||||
src/spherical_linear_interpolation.cpp
|
||||
)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
file(GLOB_RECURSE test_files test/**/*.cpp)
|
||||
|
||||
ament_add_ros_isolated_gtest(test_interpolation ${test_files})
|
||||
|
||||
target_link_libraries(test_interpolation
|
||||
autoware_interpolation
|
||||
)
|
||||
endif()
|
||||
|
||||
ament_auto_package()
|
||||
@@ -0,0 +1,109 @@
|
||||
# Interpolation package
|
||||
|
||||
This package supplies linear and spline interpolation functions.
|
||||
|
||||
## Linear Interpolation
|
||||
|
||||
`lerp(src_val, dst_val, ratio)` (for scalar interpolation) interpolates `src_val` and `dst_val` with `ratio`.
|
||||
This will be replaced with `std::lerp(src_val, dst_val, ratio)` in `C++20`.
|
||||
|
||||
`lerp(base_keys, base_values, query_keys)` (for vector interpolation) applies linear regression to each two continuous points whose x values are`base_keys` and whose y values are `base_values`.
|
||||
Then it calculates interpolated values on y-axis for `query_keys` on x-axis.
|
||||
|
||||
## Spline Interpolation
|
||||
|
||||
`spline(base_keys, base_values, query_keys)` (for vector interpolation) applies spline regression to each two continuous points whose x values are`base_keys` and whose y values are `base_values`.
|
||||
Then it calculates interpolated values on y-axis for `query_keys` on x-axis.
|
||||
|
||||
### Evaluation of calculation cost
|
||||
|
||||
We evaluated calculation cost of spline interpolation for 100 points, and adopted the best one which is tridiagonal matrix algorithm.
|
||||
Methods except for tridiagonal matrix algorithm exists in `spline_interpolation` package, which has been removed from Autoware.
|
||||
|
||||
| Method | Calculation time |
|
||||
| --------------------------------- | ---------------- |
|
||||
| Tridiagonal Matrix Algorithm | 0.007 [ms] |
|
||||
| Preconditioned Conjugate Gradient | 0.024 [ms] |
|
||||
| Successive Over-Relaxation | 0.074 [ms] |
|
||||
|
||||
### Spline Interpolation Algorithm
|
||||
|
||||
Assuming that the size of `base_keys` ($x_i$) and `base_values` ($y_i$) are $N + 1$, we aim to calculate spline interpolation with the following equation to interpolate between $y_i$ and $y_{i+1}$.
|
||||
|
||||
$$
|
||||
Y_i(x) = a_i (x - x_i)^3 + b_i (x - x_i)^2 + c_i (x - x_i) + d_i \ \ \ (i = 0, \dots, N-1)
|
||||
$$
|
||||
|
||||
Constraints on spline interpolation are as follows.
|
||||
The number of constraints is $4N$, which is equal to the number of variables of spline interpolation.
|
||||
|
||||
$$
|
||||
\begin{align}
|
||||
Y_i (x_i) & = y_i \ \ \ (i = 0, \dots, N-1) \\
|
||||
Y_i (x_{i+1}) & = y_{i+1} \ \ \ (i = 0, \dots, N-1) \\
|
||||
Y'_i (x_{i+1}) & = Y'_{i+1} (x_{i+1}) \ \ \ (i = 0, \dots, N-2) \\
|
||||
Y''_i (x_{i+1}) & = Y''_{i+1} (x_{i+1}) \ \ \ (i = 0, \dots, N-2) \\
|
||||
Y''_0 (x_0) & = 0 \\
|
||||
Y''_{N-1} (x_N) & = 0
|
||||
\end{align}
|
||||
$$
|
||||
|
||||
According to [this article](https://www.mk-mode.com/rails/docs/INTERPOLATION_SPLINE.pdf), spline interpolation is formulated as the following linear equation.
|
||||
|
||||
$$
|
||||
\begin{align}
|
||||
\begin{pmatrix}
|
||||
2(h_0 + h_1) & h_1 \\
|
||||
h_0 & 2 (h_1 + h_2) & h_2 & & O \\
|
||||
& & & \ddots \\
|
||||
O & & & & h_{N-2} & 2 (h_{N-2} + h_{N-1})
|
||||
\end{pmatrix}
|
||||
\begin{pmatrix}
|
||||
v_1 \\ v_2 \\ v_3 \\ \vdots \\ v_{N-1}
|
||||
\end{pmatrix}=
|
||||
\begin{pmatrix}
|
||||
w_1 \\ w_2 \\ w_3 \\ \vdots \\ w_{N-1}
|
||||
\end{pmatrix}
|
||||
\end{align}
|
||||
$$
|
||||
|
||||
where
|
||||
|
||||
$$
|
||||
\begin{align}
|
||||
h_i & = x_{i+1} - x_i \ \ \ (i = 0, \dots, N-1) \\
|
||||
w_i & = 6 \left(\frac{y_{i+1} - y_{i+1}}{h_i} - \frac{y_i - y_{i-1}}{h_{i-1}}\right) \ \ \ (i = 1, \dots, N-1)
|
||||
\end{align}
|
||||
$$
|
||||
|
||||
The coefficient matrix of this linear equation is tridiagonal matrix. Therefore, it can be solve with tridiagonal matrix algorithm, which can solve linear equations without gradient descent methods.
|
||||
|
||||
Solving this linear equation with tridiagonal matrix algorithm, we can calculate coefficients of spline interpolation as follows.
|
||||
|
||||
$$
|
||||
\begin{align}
|
||||
a_i & = \frac{v_{i+1} - v_i}{6 (x_{i+1} - x_i)} \ \ \ (i = 0, \dots, N-1) \\
|
||||
b_i & = \frac{v_i}{2} \ \ \ (i = 0, \dots, N-1) \\
|
||||
c_i & = \frac{y_{i+1} - y_i}{x_{i+1} - x_i} - \frac{1}{6}(x_{i+1} - x_i)(2 v_i + v_{i+1}) \ \ \ (i = 0, \dots, N-1) \\
|
||||
d_i & = y_i \ \ \ (i = 0, \dots, N-1)
|
||||
\end{align}
|
||||
$$
|
||||
|
||||
### Tridiagonal Matrix Algorithm
|
||||
|
||||
We solve tridiagonal linear equation according to [this article](https://www.iist.ac.in/sites/default/files/people/tdma.pdf) where variables of linear equation are expressed as follows in the implementation.
|
||||
|
||||
$$
|
||||
\begin{align}
|
||||
\begin{pmatrix}
|
||||
b_0 & c_0 & & \\
|
||||
a_0 & b_1 & c_2 & O \\
|
||||
& & \ddots \\
|
||||
O & & a_{N-2} & b_{N-1}
|
||||
\end{pmatrix}
|
||||
x =
|
||||
\begin{pmatrix}
|
||||
d_0 \\ d_2 \\ d_3 \\ \vdots \\ d_{N-1}
|
||||
\end{pmatrix}
|
||||
\end{align}
|
||||
$$
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
// Copyright 2021 Tier IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef AUTOWARE__INTERPOLATION__INTERPOLATION_UTILS_HPP_
|
||||
#define AUTOWARE__INTERPOLATION__INTERPOLATION_UTILS_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace autoware::interpolation
|
||||
{
|
||||
inline bool isIncreasing(const std::vector<double> & x)
|
||||
{
|
||||
if (x.empty()) {
|
||||
throw std::invalid_argument("Points is empty.");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < x.size() - 1; ++i) {
|
||||
if (x.at(i) >= x.at(i + 1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool isNotDecreasing(const std::vector<double> & x)
|
||||
{
|
||||
if (x.empty()) {
|
||||
throw std::invalid_argument("Points is empty.");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < x.size() - 1; ++i) {
|
||||
if (x.at(i) > x.at(i + 1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline std::vector<double> validateKeys(
|
||||
const std::vector<double> & base_keys, const std::vector<double> & query_keys)
|
||||
{
|
||||
// when vectors are empty
|
||||
if (base_keys.empty() || query_keys.empty()) {
|
||||
throw std::invalid_argument("Points is empty.");
|
||||
}
|
||||
|
||||
// when size of vectors are less than 2
|
||||
if (base_keys.size() < 2) {
|
||||
throw std::invalid_argument(
|
||||
"The size of points is less than 2. base_keys.size() = " + std::to_string(base_keys.size()));
|
||||
}
|
||||
|
||||
// when indices are not sorted
|
||||
if (!isIncreasing(base_keys) || !isNotDecreasing(query_keys)) {
|
||||
throw std::invalid_argument("Either base_keys or query_keys is not sorted.");
|
||||
}
|
||||
|
||||
// when query_keys is out of base_keys (This function does not allow exterior division.)
|
||||
constexpr double epsilon = 1e-3;
|
||||
if (
|
||||
query_keys.front() < base_keys.front() - epsilon ||
|
||||
base_keys.back() + epsilon < query_keys.back()) {
|
||||
throw std::invalid_argument("query_keys is out of base_keys");
|
||||
}
|
||||
|
||||
// NOTE: Due to calculation error of double, a query key may be slightly out of base keys.
|
||||
// Therefore, query keys are cropped here.
|
||||
auto validated_query_keys = query_keys;
|
||||
validated_query_keys.front() = std::max(validated_query_keys.front(), base_keys.front());
|
||||
validated_query_keys.back() = std::min(validated_query_keys.back(), base_keys.back());
|
||||
|
||||
return validated_query_keys;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void validateKeysAndValues(
|
||||
const std::vector<double> & base_keys, const std::vector<T> & base_values)
|
||||
{
|
||||
// when vectors are empty
|
||||
if (base_keys.empty() || base_values.empty()) {
|
||||
throw std::invalid_argument("Points is empty.");
|
||||
}
|
||||
|
||||
// when size of vectors are less than 2
|
||||
if (base_keys.size() < 2 || base_values.size() < 2) {
|
||||
throw std::invalid_argument(
|
||||
"The size of points is less than 2. base_keys.size() = " + std::to_string(base_keys.size()) +
|
||||
", base_values.size() = " + std::to_string(base_values.size()));
|
||||
}
|
||||
|
||||
// when sizes of indices and values are not same
|
||||
if (base_keys.size() != base_values.size()) {
|
||||
throw std::invalid_argument("The size of base_keys and base_values are not the same.");
|
||||
}
|
||||
}
|
||||
} // namespace autoware::interpolation
|
||||
|
||||
#endif // AUTOWARE__INTERPOLATION__INTERPOLATION_UTILS_HPP_
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
// Copyright 2021 Tier IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef AUTOWARE__INTERPOLATION__LINEAR_INTERPOLATION_HPP_
|
||||
#define AUTOWARE__INTERPOLATION__LINEAR_INTERPOLATION_HPP_
|
||||
|
||||
#include "autoware/interpolation/interpolation_utils.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace autoware::interpolation
|
||||
{
|
||||
double lerp(const double src_val, const double dst_val, const double ratio);
|
||||
|
||||
std::vector<double> lerp(
|
||||
const std::vector<double> & base_keys, const std::vector<double> & base_values,
|
||||
const std::vector<double> & query_keys);
|
||||
|
||||
double lerp(
|
||||
const std::vector<double> & base_keys, const std::vector<double> & base_values,
|
||||
const double query_key);
|
||||
} // namespace autoware::interpolation
|
||||
|
||||
#endif // AUTOWARE__INTERPOLATION__LINEAR_INTERPOLATION_HPP_
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
// Copyright 2022 Tier IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef AUTOWARE__INTERPOLATION__SPHERICAL_LINEAR_INTERPOLATION_HPP_
|
||||
#define AUTOWARE__INTERPOLATION__SPHERICAL_LINEAR_INTERPOLATION_HPP_
|
||||
|
||||
#include "autoware/interpolation/interpolation_utils.hpp"
|
||||
|
||||
#include <geometry_msgs/msg/quaternion.hpp>
|
||||
|
||||
#include <tf2/utils.h>
|
||||
|
||||
#ifdef ROS_DISTRO_GALACTIC
|
||||
#include <tf2_geometry_msgs/tf2_geometry_msgs.h>
|
||||
#else
|
||||
#include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace autoware::interpolation
|
||||
{
|
||||
geometry_msgs::msg::Quaternion slerp(
|
||||
const geometry_msgs::msg::Quaternion & src_quat, const geometry_msgs::msg::Quaternion & dst_quat,
|
||||
const double ratio);
|
||||
|
||||
std::vector<geometry_msgs::msg::Quaternion> slerp(
|
||||
const std::vector<double> & base_keys,
|
||||
const std::vector<geometry_msgs::msg::Quaternion> & base_values,
|
||||
const std::vector<double> & query_keys);
|
||||
|
||||
geometry_msgs::msg::Quaternion lerpOrientation(
|
||||
const geometry_msgs::msg::Quaternion & o_from, const geometry_msgs::msg::Quaternion & o_to,
|
||||
const double ratio);
|
||||
} // namespace autoware::interpolation
|
||||
|
||||
#endif // AUTOWARE__INTERPOLATION__SPHERICAL_LINEAR_INTERPOLATION_HPP_
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
// Copyright 2021 Tier IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef AUTOWARE__INTERPOLATION__SPLINE_INTERPOLATION_HPP_
|
||||
#define AUTOWARE__INTERPOLATION__SPLINE_INTERPOLATION_HPP_
|
||||
|
||||
#include "autoware/interpolation/interpolation_utils.hpp"
|
||||
#include "autoware/universe_utils/geometry/geometry.hpp"
|
||||
|
||||
#include <Eigen/Core>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
|
||||
namespace autoware::interpolation
|
||||
{
|
||||
// static spline interpolation functions
|
||||
std::vector<double> spline(
|
||||
const std::vector<double> & base_keys, const std::vector<double> & base_values,
|
||||
const std::vector<double> & query_keys);
|
||||
std::vector<double> splineByAkima(
|
||||
const std::vector<double> & base_keys, const std::vector<double> & base_values,
|
||||
const std::vector<double> & query_keys);
|
||||
|
||||
// non-static 1-dimensional spline interpolation
|
||||
//
|
||||
// Usage:
|
||||
// ```
|
||||
// SplineInterpolation spline;
|
||||
// // memorize pre-interpolation result internally
|
||||
// spline.calcSplineCoefficients(base_keys, base_values);
|
||||
// const auto interpolation_result1 = spline.getSplineInterpolatedValues(
|
||||
// base_keys, query_keys1);
|
||||
// const auto interpolation_result2 = spline.getSplineInterpolatedValues(
|
||||
// base_keys, query_keys2);
|
||||
// ```
|
||||
class SplineInterpolation
|
||||
{
|
||||
public:
|
||||
SplineInterpolation() = default;
|
||||
SplineInterpolation(
|
||||
const std::vector<double> & base_keys, const std::vector<double> & base_values)
|
||||
{
|
||||
calcSplineCoefficients(base_keys, base_values);
|
||||
}
|
||||
|
||||
//!< @brief get values of spline interpolation on designated sampling points.
|
||||
//!< @details Assuming that query_keys are t vector for sampling, and interpolation is for x,
|
||||
// meaning that spline interpolation was applied to x(t),
|
||||
// return value will be x(t) vector
|
||||
std::vector<double> getSplineInterpolatedValues(const std::vector<double> & query_keys) const;
|
||||
|
||||
//!< @brief get 1st differential values of spline interpolation on designated sampling points.
|
||||
//!< @details Assuming that query_keys are t vector for sampling, and interpolation is for x,
|
||||
// meaning that spline interpolation was applied to x(t),
|
||||
// return value will be dx/dt(t) vector
|
||||
std::vector<double> getSplineInterpolatedDiffValues(const std::vector<double> & query_keys) const;
|
||||
|
||||
//!< @brief get 2nd differential values of spline interpolation on designated sampling points.
|
||||
//!< @details Assuming that query_keys are t vector for sampling, and interpolation is for x,
|
||||
// meaning that spline interpolation was applied to x(t),
|
||||
// return value will be d^2/dt^2(t) vector
|
||||
std::vector<double> getSplineInterpolatedQuadDiffValues(
|
||||
const std::vector<double> & query_keys) const;
|
||||
|
||||
size_t getSize() const { return base_keys_.size(); }
|
||||
|
||||
private:
|
||||
Eigen::VectorXd a_;
|
||||
Eigen::VectorXd b_;
|
||||
Eigen::VectorXd c_;
|
||||
Eigen::VectorXd d_;
|
||||
|
||||
std::vector<double> base_keys_;
|
||||
|
||||
void calcSplineCoefficients(
|
||||
const std::vector<double> & base_keys, const std::vector<double> & base_values);
|
||||
|
||||
Eigen::Index get_index(const double & key) const;
|
||||
};
|
||||
} // namespace autoware::interpolation
|
||||
|
||||
#endif // AUTOWARE__INTERPOLATION__SPLINE_INTERPOLATION_HPP_
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
// Copyright 2021 Tier IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef AUTOWARE__INTERPOLATION__SPLINE_INTERPOLATION_POINTS_2D_HPP_
|
||||
#define AUTOWARE__INTERPOLATION__SPLINE_INTERPOLATION_POINTS_2D_HPP_
|
||||
|
||||
#include "autoware/interpolation/spline_interpolation.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace autoware::interpolation
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
std::vector<double> splineYawFromPoints(const std::vector<T> & points);
|
||||
|
||||
// non-static points spline interpolation
|
||||
// NOTE: We can calculate yaw from the x and y by interpolation derivatives.
|
||||
//
|
||||
// Usage:
|
||||
// ```
|
||||
// SplineInterpolationPoints2d spline;
|
||||
// // memorize pre-interpolation result internally
|
||||
// spline.calcSplineCoefficients(base_keys, base_values);
|
||||
// const auto interpolation_result1 = spline.getSplineInterpolatedPoint(
|
||||
// base_keys, query_keys1);
|
||||
// const auto interpolation_result2 = spline.getSplineInterpolatedPoint(
|
||||
// base_keys, query_keys2);
|
||||
// const auto yaw_interpolation_result = spline.getSplineInterpolatedYaw(
|
||||
// base_keys, query_keys1);
|
||||
// ```
|
||||
class SplineInterpolationPoints2d
|
||||
{
|
||||
public:
|
||||
SplineInterpolationPoints2d() = default;
|
||||
template <typename T>
|
||||
explicit SplineInterpolationPoints2d(const std::vector<T> & points)
|
||||
{
|
||||
std::vector<geometry_msgs::msg::Point> points_inner;
|
||||
for (const auto & p : points) {
|
||||
points_inner.push_back(autoware::universe_utils::getPoint(p));
|
||||
}
|
||||
calcSplineCoefficientsInner(points_inner);
|
||||
}
|
||||
|
||||
// TODO(murooka) implement these functions
|
||||
// std::vector<geometry_msgs::msg::Point> getSplineInterpolatedPoints(const double width);
|
||||
// std::vector<geometry_msgs::msg::Pose> getSplineInterpolatedPoses(const double width);
|
||||
|
||||
// pose (= getSplineInterpolatedPoint + getSplineInterpolatedYaw)
|
||||
geometry_msgs::msg::Pose getSplineInterpolatedPose(const size_t idx, const double s) const;
|
||||
|
||||
// point
|
||||
geometry_msgs::msg::Point getSplineInterpolatedPoint(const size_t idx, const double s) const;
|
||||
|
||||
// yaw
|
||||
double getSplineInterpolatedYaw(const size_t idx, const double s) const;
|
||||
std::vector<double> getSplineInterpolatedYaws() const;
|
||||
|
||||
// curvature
|
||||
double getSplineInterpolatedCurvature(const size_t idx, const double s) const;
|
||||
std::vector<double> getSplineInterpolatedCurvatures() const;
|
||||
|
||||
size_t getSize() const { return base_s_vec_.size(); }
|
||||
size_t getOffsetIndex(const size_t idx, const double offset) const;
|
||||
double getAccumulatedLength(const size_t idx) const;
|
||||
|
||||
private:
|
||||
void calcSplineCoefficientsInner(const std::vector<geometry_msgs::msg::Point> & points);
|
||||
SplineInterpolation spline_x_;
|
||||
SplineInterpolation spline_y_;
|
||||
SplineInterpolation spline_z_;
|
||||
|
||||
std::vector<double> base_s_vec_;
|
||||
};
|
||||
} // namespace autoware::interpolation
|
||||
|
||||
#endif // AUTOWARE__INTERPOLATION__SPLINE_INTERPOLATION_POINTS_2D_HPP_
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
// Copyright 2022 Tier IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef AUTOWARE__INTERPOLATION__ZERO_ORDER_HOLD_HPP_
|
||||
#define AUTOWARE__INTERPOLATION__ZERO_ORDER_HOLD_HPP_
|
||||
|
||||
#include "autoware/interpolation/interpolation_utils.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace autoware::interpolation
|
||||
{
|
||||
inline std::vector<size_t> calc_closest_segment_indices(
|
||||
const std::vector<double> & base_keys, const std::vector<double> & query_keys,
|
||||
const double overlap_threshold = 1e-3)
|
||||
{
|
||||
// throw exception for invalid arguments
|
||||
const auto validated_query_keys = validateKeys(base_keys, query_keys);
|
||||
|
||||
std::vector<size_t> closest_segment_indices(validated_query_keys.size());
|
||||
size_t closest_segment_idx = 0;
|
||||
for (size_t i = 0; i < validated_query_keys.size(); ++i) {
|
||||
// Check if query_key is closes to the terminal point of the base keys
|
||||
if (base_keys.back() - overlap_threshold < validated_query_keys.at(i)) {
|
||||
closest_segment_idx = base_keys.size() - 1;
|
||||
} else {
|
||||
for (size_t j = base_keys.size() - 1; j > closest_segment_idx; --j) {
|
||||
if (
|
||||
base_keys.at(j - 1) - overlap_threshold < validated_query_keys.at(i) &&
|
||||
validated_query_keys.at(i) < base_keys.at(j)) {
|
||||
// find closest segment in base keys
|
||||
closest_segment_idx = j - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closest_segment_indices.at(i) = closest_segment_idx;
|
||||
}
|
||||
|
||||
return closest_segment_indices;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::vector<T> zero_order_hold(
|
||||
const std::vector<double> & base_keys, const std::vector<T> & base_values,
|
||||
const std::vector<size_t> & closest_segment_indices)
|
||||
{
|
||||
// throw exception for invalid arguments
|
||||
validateKeysAndValues(base_keys, base_values);
|
||||
|
||||
std::vector<T> query_values(closest_segment_indices.size());
|
||||
for (size_t i = 0; i < closest_segment_indices.size(); ++i) {
|
||||
query_values.at(i) = base_values.at(closest_segment_indices.at(i));
|
||||
}
|
||||
|
||||
return query_values;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::vector<T> zero_order_hold(
|
||||
const std::vector<double> & base_keys, const std::vector<T> & base_values,
|
||||
const std::vector<double> & query_keys, const double overlap_threshold = 1e-3)
|
||||
{
|
||||
return zero_order_hold(
|
||||
base_keys, base_values, calc_closest_segment_indices(base_keys, query_keys, overlap_threshold));
|
||||
}
|
||||
} // namespace autoware::interpolation
|
||||
|
||||
#endif // AUTOWARE__INTERPOLATION__ZERO_ORDER_HOLD_HPP_
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="3">
|
||||
<name>autoware_interpolation</name>
|
||||
<version>0.1.0</version>
|
||||
<description>The spline interpolation package</description>
|
||||
<maintainer email="fumiya.watanabe@tier4.jp">Fumiya Watanabe</maintainer>
|
||||
<maintainer email="takayuki.murooka@tier4.jp">Takayuki Murooka</maintainer>
|
||||
<license>Apache License 2.0</license>
|
||||
|
||||
<buildtool_depend>ament_cmake_auto</buildtool_depend>
|
||||
<buildtool_depend>autoware_cmake</buildtool_depend>
|
||||
|
||||
<depend>autoware_universe_utils</depend>
|
||||
<depend>eigen</depend>
|
||||
|
||||
<test_depend>ament_cmake_ros</test_depend>
|
||||
<test_depend>ament_lint_auto</test_depend>
|
||||
<test_depend>autoware_lint_common</test_depend>
|
||||
|
||||
<export>
|
||||
<build_type>ament_cmake</build_type>
|
||||
</export>
|
||||
</package>
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright 2021 Tier IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/interpolation/linear_interpolation.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace autoware::interpolation
|
||||
{
|
||||
double lerp(const double src_val, const double dst_val, const double ratio)
|
||||
{
|
||||
return src_val + (dst_val - src_val) * ratio;
|
||||
}
|
||||
|
||||
std::vector<double> lerp(
|
||||
const std::vector<double> & base_keys, const std::vector<double> & base_values,
|
||||
const std::vector<double> & query_keys)
|
||||
{
|
||||
// throw exception for invalid arguments
|
||||
const auto validated_query_keys = validateKeys(base_keys, query_keys);
|
||||
validateKeysAndValues(base_keys, base_values);
|
||||
|
||||
// calculate linear interpolation
|
||||
std::vector<double> query_values;
|
||||
size_t key_index = 0;
|
||||
for (const auto query_key : validated_query_keys) {
|
||||
while (base_keys.at(key_index + 1) < query_key) {
|
||||
++key_index;
|
||||
}
|
||||
|
||||
const double src_val = base_values.at(key_index);
|
||||
const double dst_val = base_values.at(key_index + 1);
|
||||
const double ratio = (query_key - base_keys.at(key_index)) /
|
||||
(base_keys.at(key_index + 1) - base_keys.at(key_index));
|
||||
|
||||
const double interpolated_val = lerp(src_val, dst_val, ratio);
|
||||
query_values.push_back(interpolated_val);
|
||||
}
|
||||
|
||||
return query_values;
|
||||
}
|
||||
|
||||
double lerp(
|
||||
const std::vector<double> & base_keys, const std::vector<double> & base_values, double query_key)
|
||||
{
|
||||
return lerp(base_keys, base_values, std::vector<double>{query_key}).front();
|
||||
}
|
||||
} // namespace autoware::interpolation
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
// Copyright 2022 Tier IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/interpolation/spherical_linear_interpolation.hpp"
|
||||
|
||||
namespace autoware::interpolation
|
||||
{
|
||||
geometry_msgs::msg::Quaternion slerp(
|
||||
const geometry_msgs::msg::Quaternion & src_quat, const geometry_msgs::msg::Quaternion & dst_quat,
|
||||
const double ratio)
|
||||
{
|
||||
tf2::Quaternion src_tf;
|
||||
tf2::Quaternion dst_tf;
|
||||
tf2::fromMsg(src_quat, src_tf);
|
||||
tf2::fromMsg(dst_quat, dst_tf);
|
||||
const auto interpolated_quat = tf2::slerp(src_tf, dst_tf, ratio);
|
||||
return tf2::toMsg(interpolated_quat);
|
||||
}
|
||||
|
||||
std::vector<geometry_msgs::msg::Quaternion> slerp(
|
||||
const std::vector<double> & base_keys,
|
||||
const std::vector<geometry_msgs::msg::Quaternion> & base_values,
|
||||
const std::vector<double> & query_keys)
|
||||
{
|
||||
// throw exception for invalid arguments
|
||||
const auto validated_query_keys = validateKeys(base_keys, query_keys);
|
||||
validateKeysAndValues(base_keys, base_values);
|
||||
|
||||
// calculate linear interpolation
|
||||
std::vector<geometry_msgs::msg::Quaternion> query_values;
|
||||
size_t key_index = 0;
|
||||
for (const auto query_key : validated_query_keys) {
|
||||
while (base_keys.at(key_index + 1) < query_key) {
|
||||
++key_index;
|
||||
}
|
||||
|
||||
const auto src_quat = base_values.at(key_index);
|
||||
const auto dst_quat = base_values.at(key_index + 1);
|
||||
const double ratio = (query_key - base_keys.at(key_index)) /
|
||||
(base_keys.at(key_index + 1) - base_keys.at(key_index));
|
||||
|
||||
const auto interpolated_quat = slerp(src_quat, dst_quat, ratio);
|
||||
query_values.push_back(interpolated_quat);
|
||||
}
|
||||
|
||||
return query_values;
|
||||
}
|
||||
|
||||
geometry_msgs::msg::Quaternion lerpOrientation(
|
||||
const geometry_msgs::msg::Quaternion & o_from, const geometry_msgs::msg::Quaternion & o_to,
|
||||
const double ratio)
|
||||
{
|
||||
tf2::Quaternion q_from, q_to;
|
||||
tf2::fromMsg(o_from, q_from);
|
||||
tf2::fromMsg(o_to, q_to);
|
||||
|
||||
const auto q_interpolated = q_from.slerp(q_to, ratio);
|
||||
return tf2::toMsg(q_interpolated);
|
||||
}
|
||||
} // namespace autoware::interpolation
|
||||
@@ -0,0 +1,247 @@
|
||||
// Copyright 2021 Tier IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/interpolation/spline_interpolation.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace autoware::interpolation
|
||||
{
|
||||
Eigen::VectorXd solve_tridiagonal_matrix_algorithm(
|
||||
const Eigen::Ref<const Eigen::VectorXd> & a, const Eigen::Ref<const Eigen::VectorXd> & b,
|
||||
const Eigen::Ref<const Eigen::VectorXd> & c, const Eigen::Ref<const Eigen::VectorXd> & d)
|
||||
{
|
||||
const auto n = d.size();
|
||||
|
||||
if (n == 1) {
|
||||
return d.array() / b.array();
|
||||
}
|
||||
|
||||
Eigen::VectorXd c_prime = Eigen::VectorXd::Zero(n);
|
||||
Eigen::VectorXd d_prime = Eigen::VectorXd::Zero(n);
|
||||
Eigen::VectorXd x = Eigen::VectorXd::Zero(n);
|
||||
|
||||
// Forward sweep
|
||||
c_prime(0) = c(0) / b(0);
|
||||
d_prime(0) = d(0) / b(0);
|
||||
|
||||
for (auto i = 1; i < n; i++) {
|
||||
const double m = 1.0 / (b(i) - a(i - 1) * c_prime(i - 1));
|
||||
c_prime(i) = i < n - 1 ? c(i) * m : 0;
|
||||
d_prime(i) = (d(i) - a(i - 1) * d_prime(i - 1)) * m;
|
||||
}
|
||||
|
||||
// Back substitution
|
||||
x(n - 1) = d_prime(n - 1);
|
||||
|
||||
for (int64_t i = n - 2; i >= 0; i--) {
|
||||
x(i) = d_prime(i) - c_prime(i) * x(i + 1);
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
std::vector<double> spline(
|
||||
const std::vector<double> & base_keys, const std::vector<double> & base_values,
|
||||
const std::vector<double> & query_keys)
|
||||
{
|
||||
// calculate spline coefficients
|
||||
SplineInterpolation interpolator(base_keys, base_values);
|
||||
|
||||
// interpolate base_keys at query_keys
|
||||
return interpolator.getSplineInterpolatedValues(query_keys);
|
||||
}
|
||||
|
||||
std::vector<double> splineByAkima(
|
||||
const std::vector<double> & base_keys, const std::vector<double> & base_values,
|
||||
const std::vector<double> & query_keys)
|
||||
{
|
||||
constexpr double epsilon = 1e-5;
|
||||
|
||||
// calculate m
|
||||
std::vector<double> m_values;
|
||||
for (size_t i = 0; i < base_keys.size() - 1; ++i) {
|
||||
const double m_val =
|
||||
(base_values.at(i + 1) - base_values.at(i)) / (base_keys.at(i + 1) - base_keys.at(i));
|
||||
m_values.push_back(m_val);
|
||||
}
|
||||
|
||||
// calculate s
|
||||
std::vector<double> s_values;
|
||||
for (size_t i = 0; i < base_keys.size(); ++i) {
|
||||
if (i == 0) {
|
||||
s_values.push_back(m_values.front());
|
||||
continue;
|
||||
} else if (i == base_keys.size() - 1) {
|
||||
s_values.push_back(m_values.back());
|
||||
continue;
|
||||
} else if (i == 1 || i == base_keys.size() - 2) {
|
||||
const double s_val = (m_values.at(i - 1) + m_values.at(i)) / 2.0;
|
||||
s_values.push_back(s_val);
|
||||
continue;
|
||||
}
|
||||
|
||||
const double denom = std::abs(m_values.at(i + 1) - m_values.at(i)) +
|
||||
std::abs(m_values.at(i - 1) - m_values.at(i - 2));
|
||||
if (std::abs(denom) < epsilon) {
|
||||
const double s_val = (m_values.at(i - 1) + m_values.at(i)) / 2.0;
|
||||
s_values.push_back(s_val);
|
||||
continue;
|
||||
}
|
||||
|
||||
const double s_val = (std::abs(m_values.at(i + 1) - m_values.at(i)) * m_values.at(i - 1) +
|
||||
std::abs(m_values.at(i - 1) - m_values.at(i - 2)) * m_values.at(i)) /
|
||||
denom;
|
||||
s_values.push_back(s_val);
|
||||
}
|
||||
|
||||
// calculate cubic coefficients
|
||||
std::vector<double> a;
|
||||
std::vector<double> b;
|
||||
std::vector<double> c;
|
||||
std::vector<double> d;
|
||||
for (size_t i = 0; i < base_keys.size() - 1; ++i) {
|
||||
a.push_back(
|
||||
(s_values.at(i) + s_values.at(i + 1) - 2.0 * m_values.at(i)) /
|
||||
std::pow(base_keys.at(i + 1) - base_keys.at(i), 2));
|
||||
b.push_back(
|
||||
(3.0 * m_values.at(i) - 2.0 * s_values.at(i) - s_values.at(i + 1)) /
|
||||
(base_keys.at(i + 1) - base_keys.at(i)));
|
||||
c.push_back(s_values.at(i));
|
||||
d.push_back(base_values.at(i));
|
||||
}
|
||||
|
||||
// interpolate
|
||||
std::vector<double> res;
|
||||
size_t j = 0;
|
||||
for (const auto & query_key : query_keys) {
|
||||
while (base_keys.at(j + 1) < query_key) {
|
||||
++j;
|
||||
}
|
||||
|
||||
const double ds = query_key - base_keys.at(j);
|
||||
res.push_back(d.at(j) + (c.at(j) + (b.at(j) + a.at(j) * ds) * ds) * ds);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
Eigen::Index SplineInterpolation::get_index(const double & key) const
|
||||
{
|
||||
const auto it = std::lower_bound(base_keys_.begin(), base_keys_.end(), key);
|
||||
return std::clamp(
|
||||
static_cast<int>(std::distance(base_keys_.begin(), it)) - 1, 0,
|
||||
static_cast<int>(base_keys_.size()) - 2);
|
||||
}
|
||||
|
||||
void SplineInterpolation::calcSplineCoefficients(
|
||||
const std::vector<double> & base_keys, const std::vector<double> & base_values)
|
||||
{
|
||||
// throw exceptions for invalid arguments
|
||||
autoware::interpolation::validateKeysAndValues(base_keys, base_values);
|
||||
const Eigen::VectorXd x = Eigen::Map<const Eigen::VectorXd>(
|
||||
base_keys.data(), static_cast<Eigen::Index>(base_keys.size()));
|
||||
const Eigen::VectorXd y = Eigen::Map<const Eigen::VectorXd>(
|
||||
base_values.data(), static_cast<Eigen::Index>(base_values.size()));
|
||||
|
||||
const auto n = x.size();
|
||||
|
||||
if (n == 2) {
|
||||
a_ = Eigen::VectorXd::Zero(1);
|
||||
b_ = Eigen::VectorXd::Zero(1);
|
||||
c_ = Eigen::VectorXd::Zero(1);
|
||||
d_ = Eigen::VectorXd::Zero(1);
|
||||
c_[0] = (y[1] - y[0]) / (x[1] - x[0]);
|
||||
d_[0] = y[0];
|
||||
base_keys_ = base_keys;
|
||||
return;
|
||||
}
|
||||
|
||||
// Create Tridiagonal matrix
|
||||
Eigen::VectorXd v(n);
|
||||
const Eigen::VectorXd h = x.segment(1, n - 1) - x.segment(0, n - 1);
|
||||
const Eigen::VectorXd a = h.segment(1, n - 3);
|
||||
const Eigen::VectorXd b = 2 * (h.segment(0, n - 2) + h.segment(1, n - 2));
|
||||
const Eigen::VectorXd c = h.segment(1, n - 3);
|
||||
const Eigen::VectorXd y_diff = y.segment(1, n - 1) - y.segment(0, n - 1);
|
||||
const Eigen::VectorXd d = 6 * (y_diff.segment(1, n - 2).array() / h.tail(n - 2).array() -
|
||||
y_diff.segment(0, n - 2).array() / h.head(n - 2).array());
|
||||
|
||||
// Solve tridiagonal matrix
|
||||
v.segment(1, n - 2) = solve_tridiagonal_matrix_algorithm(a, b, c, d);
|
||||
v[0] = 0;
|
||||
v[n - 1] = 0;
|
||||
|
||||
// Calculate spline coefficients
|
||||
a_ = (v.tail(n - 1) - v.head(n - 1)).array() / 6.0 / (x.tail(n - 1) - x.head(n - 1)).array();
|
||||
b_ = v.segment(0, n - 1) / 2.0;
|
||||
c_ = (y.tail(n - 1) - y.head(n - 1)).array() / (x.tail(n - 1) - x.head(n - 1)).array() -
|
||||
(x.tail(n - 1) - x.head(n - 1)).array() *
|
||||
(2 * v.segment(0, n - 1).array() + v.segment(1, n - 1).array()) / 6.0;
|
||||
d_ = y.head(n - 1);
|
||||
base_keys_ = base_keys;
|
||||
}
|
||||
|
||||
std::vector<double> SplineInterpolation::getSplineInterpolatedValues(
|
||||
const std::vector<double> & query_keys) const
|
||||
{
|
||||
// throw exceptions for invalid arguments
|
||||
const auto validated_query_keys = autoware::interpolation::validateKeys(base_keys_, query_keys);
|
||||
std::vector<double> interpolated_values;
|
||||
interpolated_values.reserve(query_keys.size());
|
||||
|
||||
for (const auto & key : query_keys) {
|
||||
const auto idx = get_index(key);
|
||||
const auto dx = key - base_keys_[idx];
|
||||
interpolated_values.emplace_back(
|
||||
a_[idx] * dx * dx * dx + b_[idx] * dx * dx + c_[idx] * dx + d_[idx]);
|
||||
}
|
||||
|
||||
return interpolated_values;
|
||||
}
|
||||
|
||||
std::vector<double> SplineInterpolation::getSplineInterpolatedDiffValues(
|
||||
const std::vector<double> & query_keys) const
|
||||
{
|
||||
// throw exceptions for invalid arguments
|
||||
const auto validated_query_keys = autoware::interpolation::validateKeys(base_keys_, query_keys);
|
||||
std::vector<double> interpolated_diff_values;
|
||||
interpolated_diff_values.reserve(query_keys.size());
|
||||
|
||||
for (const auto & key : query_keys) {
|
||||
const auto idx = get_index(key);
|
||||
const auto dx = key - base_keys_[idx];
|
||||
interpolated_diff_values.emplace_back(3 * a_[idx] * dx * dx + 2 * b_[idx] * dx + c_[idx]);
|
||||
}
|
||||
|
||||
return interpolated_diff_values;
|
||||
}
|
||||
|
||||
std::vector<double> SplineInterpolation::getSplineInterpolatedQuadDiffValues(
|
||||
const std::vector<double> & query_keys) const
|
||||
{
|
||||
// throw exceptions for invalid arguments
|
||||
const auto validated_query_keys = autoware::interpolation::validateKeys(base_keys_, query_keys);
|
||||
std::vector<double> interpolated_quad_diff_values;
|
||||
interpolated_quad_diff_values.reserve(query_keys.size());
|
||||
|
||||
for (const auto & key : query_keys) {
|
||||
const auto idx = get_index(key);
|
||||
const auto dx = key - base_keys_[idx];
|
||||
interpolated_quad_diff_values.emplace_back(6 * a_[idx] * dx + 2 * b_[idx]);
|
||||
}
|
||||
|
||||
return interpolated_quad_diff_values;
|
||||
}
|
||||
} // namespace autoware::interpolation
|
||||
+212
@@ -0,0 +1,212 @@
|
||||
// Copyright 2021 Tier IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/interpolation/spline_interpolation_points_2d.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace autoware::interpolation
|
||||
{
|
||||
std::vector<double> calcEuclidDist(const std::vector<double> & x, const std::vector<double> & y)
|
||||
{
|
||||
if (x.size() != y.size()) {
|
||||
return std::vector<double>{};
|
||||
}
|
||||
|
||||
std::vector<double> dist_v;
|
||||
dist_v.push_back(0.0);
|
||||
for (size_t i = 0; i < x.size() - 1; ++i) {
|
||||
const double dx = x.at(i + 1) - x.at(i);
|
||||
const double dy = y.at(i + 1) - y.at(i);
|
||||
dist_v.push_back(dist_v.at(i) + std::hypot(dx, dy));
|
||||
}
|
||||
|
||||
return dist_v;
|
||||
}
|
||||
|
||||
std::array<std::vector<double>, 4> getBaseValues(
|
||||
const std::vector<geometry_msgs::msg::Point> & points)
|
||||
{
|
||||
// calculate x, y
|
||||
std::vector<double> base_x;
|
||||
std::vector<double> base_y;
|
||||
std::vector<double> base_z;
|
||||
for (size_t i = 0; i < points.size(); i++) {
|
||||
const auto & current_pos = points.at(i);
|
||||
if (i > 0) {
|
||||
const auto & prev_pos = points.at(i - 1);
|
||||
if (
|
||||
std::fabs(current_pos.x - prev_pos.x) < 1e-6 &&
|
||||
std::fabs(current_pos.y - prev_pos.y) < 1e-6) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
base_x.push_back(current_pos.x);
|
||||
base_y.push_back(current_pos.y);
|
||||
base_z.push_back(current_pos.z);
|
||||
}
|
||||
|
||||
// calculate base_keys, base_values
|
||||
if (base_x.size() < 2 || base_y.size() < 2 || base_z.size() < 2) {
|
||||
throw std::logic_error("The number of unique points is not enough.");
|
||||
}
|
||||
|
||||
const std::vector<double> base_s = calcEuclidDist(base_x, base_y);
|
||||
|
||||
return {base_s, base_x, base_y, base_z};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<double> splineYawFromPoints(const std::vector<T> & points)
|
||||
{
|
||||
// calculate spline coefficients
|
||||
SplineInterpolationPoints2d interpolator(points);
|
||||
|
||||
// interpolate base_keys at query_keys
|
||||
std::vector<double> yaw_vec;
|
||||
for (size_t i = 0; i < points.size(); ++i) {
|
||||
const double yaw = interpolator.getSplineInterpolatedYaw(i, 0.0);
|
||||
yaw_vec.push_back(yaw);
|
||||
}
|
||||
return yaw_vec;
|
||||
}
|
||||
template std::vector<double> splineYawFromPoints(
|
||||
const std::vector<geometry_msgs::msg::Point> & points);
|
||||
|
||||
geometry_msgs::msg::Pose SplineInterpolationPoints2d::getSplineInterpolatedPose(
|
||||
const size_t idx, const double s) const
|
||||
{
|
||||
geometry_msgs::msg::Pose pose;
|
||||
pose.position = getSplineInterpolatedPoint(idx, s);
|
||||
pose.orientation =
|
||||
autoware::universe_utils::createQuaternionFromYaw(getSplineInterpolatedYaw(idx, s));
|
||||
return pose;
|
||||
}
|
||||
|
||||
geometry_msgs::msg::Point SplineInterpolationPoints2d::getSplineInterpolatedPoint(
|
||||
const size_t idx, const double s) const
|
||||
{
|
||||
if (base_s_vec_.size() <= idx) {
|
||||
throw std::out_of_range("idx is out of range.");
|
||||
}
|
||||
|
||||
double whole_s = base_s_vec_.at(idx) + s;
|
||||
if (whole_s < base_s_vec_.front()) {
|
||||
whole_s = base_s_vec_.front();
|
||||
}
|
||||
if (whole_s > base_s_vec_.back()) {
|
||||
whole_s = base_s_vec_.back();
|
||||
}
|
||||
|
||||
const double x = spline_x_.getSplineInterpolatedValues({whole_s}).at(0);
|
||||
const double y = spline_y_.getSplineInterpolatedValues({whole_s}).at(0);
|
||||
const double z = spline_z_.getSplineInterpolatedValues({whole_s}).at(0);
|
||||
|
||||
geometry_msgs::msg::Point geom_point;
|
||||
geom_point.x = x;
|
||||
geom_point.y = y;
|
||||
geom_point.z = z;
|
||||
return geom_point;
|
||||
}
|
||||
|
||||
double SplineInterpolationPoints2d::getSplineInterpolatedYaw(const size_t idx, const double s) const
|
||||
{
|
||||
if (base_s_vec_.size() <= idx) {
|
||||
throw std::out_of_range("idx is out of range.");
|
||||
}
|
||||
|
||||
const double whole_s =
|
||||
std::clamp(base_s_vec_.at(idx) + s, base_s_vec_.front(), base_s_vec_.back());
|
||||
|
||||
const double diff_x = spline_x_.getSplineInterpolatedDiffValues({whole_s}).at(0);
|
||||
const double diff_y = spline_y_.getSplineInterpolatedDiffValues({whole_s}).at(0);
|
||||
|
||||
return std::atan2(diff_y, diff_x);
|
||||
}
|
||||
|
||||
std::vector<double> SplineInterpolationPoints2d::getSplineInterpolatedYaws() const
|
||||
{
|
||||
std::vector<double> yaw_vec;
|
||||
for (size_t i = 0; i < spline_x_.getSize(); ++i) {
|
||||
const double yaw = getSplineInterpolatedYaw(i, 0.0);
|
||||
yaw_vec.push_back(yaw);
|
||||
}
|
||||
return yaw_vec;
|
||||
}
|
||||
|
||||
double SplineInterpolationPoints2d::getSplineInterpolatedCurvature(
|
||||
const size_t idx, const double s) const
|
||||
{
|
||||
if (base_s_vec_.size() <= idx) {
|
||||
throw std::out_of_range("idx is out of range.");
|
||||
}
|
||||
|
||||
const double whole_s =
|
||||
std::clamp(base_s_vec_.at(idx) + s, base_s_vec_.front(), base_s_vec_.back());
|
||||
|
||||
const double diff_x = spline_x_.getSplineInterpolatedDiffValues({whole_s}).at(0);
|
||||
const double diff_y = spline_y_.getSplineInterpolatedDiffValues({whole_s}).at(0);
|
||||
|
||||
const double quad_diff_x = spline_x_.getSplineInterpolatedQuadDiffValues({whole_s}).at(0);
|
||||
const double quad_diff_y = spline_y_.getSplineInterpolatedQuadDiffValues({whole_s}).at(0);
|
||||
|
||||
return (diff_x * quad_diff_y - quad_diff_x * diff_y) /
|
||||
std::pow(std::pow(diff_x, 2) + std::pow(diff_y, 2), 1.5);
|
||||
}
|
||||
|
||||
std::vector<double> SplineInterpolationPoints2d::getSplineInterpolatedCurvatures() const
|
||||
{
|
||||
std::vector<double> curvature_vec;
|
||||
for (size_t i = 0; i < spline_x_.getSize(); ++i) {
|
||||
const double curvature = getSplineInterpolatedCurvature(i, 0.0);
|
||||
curvature_vec.push_back(curvature);
|
||||
}
|
||||
return curvature_vec;
|
||||
}
|
||||
|
||||
size_t SplineInterpolationPoints2d::getOffsetIndex(const size_t idx, const double offset) const
|
||||
{
|
||||
const double whole_s = base_s_vec_.at(idx) + offset;
|
||||
for (size_t s_idx = 0; s_idx < base_s_vec_.size(); ++s_idx) {
|
||||
if (whole_s < base_s_vec_.at(s_idx)) {
|
||||
return s_idx;
|
||||
}
|
||||
}
|
||||
return base_s_vec_.size() - 1;
|
||||
}
|
||||
|
||||
double SplineInterpolationPoints2d::getAccumulatedLength(const size_t idx) const
|
||||
{
|
||||
if (base_s_vec_.size() <= idx) {
|
||||
throw std::out_of_range("idx is out of range.");
|
||||
}
|
||||
return base_s_vec_.at(idx);
|
||||
}
|
||||
|
||||
void SplineInterpolationPoints2d::calcSplineCoefficientsInner(
|
||||
const std::vector<geometry_msgs::msg::Point> & points)
|
||||
{
|
||||
const auto base = getBaseValues(points);
|
||||
|
||||
base_s_vec_ = base.at(0);
|
||||
const auto & base_x_vec = base.at(1);
|
||||
const auto & base_y_vec = base.at(2);
|
||||
const auto & base_z_vec = base.at(3);
|
||||
|
||||
// calculate spline coefficients
|
||||
spline_x_ = SplineInterpolation(base_s_vec_, base_x_vec);
|
||||
spline_y_ = SplineInterpolation(base_s_vec_, base_y_vec);
|
||||
spline_z_ = SplineInterpolation(base_s_vec_, base_z_vec);
|
||||
}
|
||||
} // namespace autoware::interpolation
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright 2021 TierIV
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
// Copyright 2021 Tier IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/interpolation/interpolation_utils.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
constexpr double epsilon = 1e-6;
|
||||
|
||||
TEST(interpolation_utils, isIncreasing)
|
||||
{
|
||||
// empty
|
||||
const std::vector<double> empty_vec;
|
||||
EXPECT_THROW(autoware::interpolation::isIncreasing(empty_vec), std::invalid_argument);
|
||||
|
||||
// increase
|
||||
const std::vector<double> increasing_vec{0.0, 1.5, 3.0, 4.5, 6.0};
|
||||
EXPECT_EQ(autoware::interpolation::isIncreasing(increasing_vec), true);
|
||||
|
||||
// not decrease
|
||||
const std::vector<double> not_increasing_vec{0.0, 1.5, 1.5, 4.5, 6.0};
|
||||
EXPECT_EQ(autoware::interpolation::isIncreasing(not_increasing_vec), false);
|
||||
|
||||
// decrease
|
||||
const std::vector<double> decreasing_vec{0.0, 1.5, 1.2, 4.5, 6.0};
|
||||
EXPECT_EQ(autoware::interpolation::isIncreasing(decreasing_vec), false);
|
||||
}
|
||||
|
||||
TEST(interpolation_utils, isNotDecreasing)
|
||||
{
|
||||
// empty
|
||||
const std::vector<double> empty_vec;
|
||||
EXPECT_THROW(autoware::interpolation::isNotDecreasing(empty_vec), std::invalid_argument);
|
||||
|
||||
// increase
|
||||
const std::vector<double> increasing_vec{0.0, 1.5, 3.0, 4.5, 6.0};
|
||||
EXPECT_EQ(autoware::interpolation::isNotDecreasing(increasing_vec), true);
|
||||
|
||||
// not decrease
|
||||
const std::vector<double> not_increasing_vec{0.0, 1.5, 1.5, 4.5, 6.0};
|
||||
EXPECT_EQ(autoware::interpolation::isNotDecreasing(not_increasing_vec), true);
|
||||
|
||||
// decrease
|
||||
const std::vector<double> decreasing_vec{0.0, 1.5, 1.2, 4.5, 6.0};
|
||||
EXPECT_EQ(autoware::interpolation::isNotDecreasing(decreasing_vec), false);
|
||||
}
|
||||
|
||||
TEST(interpolation_utils, validateKeys)
|
||||
{
|
||||
using autoware::interpolation::validateKeys;
|
||||
|
||||
const std::vector<double> base_keys{0.0, 1.0, 2.0, 3.0};
|
||||
const std::vector<double> query_keys{0.0, 1.0, 2.0, 3.0};
|
||||
|
||||
// valid
|
||||
EXPECT_NO_THROW(validateKeys(base_keys, query_keys));
|
||||
|
||||
// empty
|
||||
const std::vector<double> empty_vec;
|
||||
EXPECT_THROW(validateKeys(empty_vec, query_keys), std::invalid_argument);
|
||||
EXPECT_THROW(validateKeys(base_keys, empty_vec), std::invalid_argument);
|
||||
|
||||
// size is less than 2
|
||||
const std::vector<double> short_vec{0.0};
|
||||
EXPECT_THROW(validateKeys(short_vec, query_keys), std::invalid_argument);
|
||||
|
||||
// partly not increase
|
||||
const std::vector<double> partly_not_increasing_vec{0.0, 0.0, 2.0, 3.0};
|
||||
// NOTE: base_keys must be strictly monotonous increasing vector
|
||||
EXPECT_THROW(validateKeys(partly_not_increasing_vec, query_keys), std::invalid_argument);
|
||||
// NOTE: query_keys is allowed to be monotonous non-decreasing vector
|
||||
EXPECT_NO_THROW(validateKeys(base_keys, partly_not_increasing_vec));
|
||||
|
||||
// decrease
|
||||
const std::vector<double> decreasing_vec{0.0, -1.0, 2.0, 3.0};
|
||||
EXPECT_THROW(validateKeys(decreasing_vec, query_keys), std::invalid_argument);
|
||||
EXPECT_THROW(validateKeys(base_keys, decreasing_vec), std::invalid_argument);
|
||||
|
||||
// out of range
|
||||
const std::vector<double> front_out_query_keys{-1.0, 1.0, 2.0, 3.0};
|
||||
EXPECT_THROW(validateKeys(base_keys, front_out_query_keys), std::invalid_argument);
|
||||
|
||||
const std::vector<double> back_out_query_keys{0.0, 1.0, 2.0, 4.0};
|
||||
EXPECT_THROW(validateKeys(base_keys, back_out_query_keys), std::invalid_argument);
|
||||
|
||||
{ // validated key check in normal case
|
||||
const std::vector<double> normal_query_keys{0.5, 1.5, 3.0};
|
||||
const auto validated_query_keys = validateKeys(base_keys, normal_query_keys);
|
||||
for (size_t i = 0; i < normal_query_keys.size(); ++i) {
|
||||
EXPECT_EQ(normal_query_keys.at(i), validated_query_keys.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
{ // validated key check in case slightly out of range
|
||||
constexpr double slightly_out_of_range_epsilon = 1e-6;
|
||||
const std::vector<double> slightly_out_of_range__query_keys{
|
||||
0.0 - slightly_out_of_range_epsilon, 3.0 + slightly_out_of_range_epsilon};
|
||||
const auto validated_query_keys = validateKeys(base_keys, slightly_out_of_range__query_keys);
|
||||
EXPECT_NEAR(validated_query_keys.at(0), 0.0, 1e-10);
|
||||
EXPECT_NEAR(validated_query_keys.at(1), 3.0, 1e-10);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(interpolation_utils, validateKeysAndValues)
|
||||
{
|
||||
using autoware::interpolation::validateKeysAndValues;
|
||||
|
||||
const std::vector<double> base_keys{0.0, 1.0, 2.0, 3.0};
|
||||
const std::vector<double> base_values{0.0, 1.0, 2.0, 3.0};
|
||||
|
||||
// valid
|
||||
EXPECT_NO_THROW(validateKeysAndValues(base_keys, base_values));
|
||||
|
||||
// empty
|
||||
const std::vector<double> empty_vec;
|
||||
EXPECT_THROW(validateKeysAndValues(empty_vec, base_values), std::invalid_argument);
|
||||
EXPECT_THROW(validateKeysAndValues(base_keys, empty_vec), std::invalid_argument);
|
||||
|
||||
// size is less than 2
|
||||
const std::vector<double> short_vec{0.0};
|
||||
EXPECT_THROW(validateKeysAndValues(short_vec, base_values), std::invalid_argument);
|
||||
EXPECT_THROW(validateKeysAndValues(base_keys, short_vec), std::invalid_argument);
|
||||
|
||||
// size is different
|
||||
const std::vector<double> different_size_base_values{0.0, 1.0, 2.0};
|
||||
EXPECT_THROW(validateKeysAndValues(base_keys, different_size_base_values), std::invalid_argument);
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
// Copyright 2021 Tier IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/interpolation/linear_interpolation.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
constexpr double epsilon = 1e-6;
|
||||
|
||||
TEST(linear_interpolation, lerp_scalar)
|
||||
{
|
||||
EXPECT_EQ(autoware::interpolation::lerp(0.0, 1.0, 0.3), 0.3);
|
||||
EXPECT_EQ(autoware::interpolation::lerp(-0.5, 12.3, 0.3), 3.34);
|
||||
}
|
||||
|
||||
TEST(linear_interpolation, lerp_vector)
|
||||
{
|
||||
{ // straight: query_keys is same as base_keys
|
||||
const std::vector<double> base_keys{0.0, 1.0, 2.0, 3.0, 4.0};
|
||||
const std::vector<double> base_values{0.0, 1.5, 3.0, 4.5, 6.0};
|
||||
const std::vector<double> query_keys = base_keys;
|
||||
const std::vector<double> ans = base_values;
|
||||
|
||||
const auto query_values = autoware::interpolation::lerp(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // straight: query_keys is random
|
||||
const std::vector<double> base_keys{0.0, 1.0, 2.0, 3.0, 4.0};
|
||||
const std::vector<double> base_values{0.0, 1.5, 3.0, 4.5, 6.0};
|
||||
const std::vector<double> query_keys{0.0, 0.7, 1.9, 4.0};
|
||||
const std::vector<double> ans{0.0, 1.05, 2.85, 6.0};
|
||||
|
||||
const auto query_values = autoware::interpolation::lerp(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // curve: query_keys is same as base_keys
|
||||
const std::vector<double> base_keys{-1.5, 1.0, 5.0, 10.0, 15.0, 20.0};
|
||||
const std::vector<double> base_values{-1.2, 0.5, 1.0, 1.2, 2.0, 1.0};
|
||||
const std::vector<double> query_keys = base_keys;
|
||||
const std::vector<double> ans = base_values;
|
||||
|
||||
const auto query_values = autoware::interpolation::lerp(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // curve: query_keys is same as random
|
||||
const std::vector<double> base_keys{-1.5, 1.0, 5.0, 10.0, 15.0, 20.0};
|
||||
const std::vector<double> base_values{-1.2, 0.5, 1.0, 1.2, 2.0, 1.0};
|
||||
const std::vector<double> query_keys{0.0, 8.0, 18.0};
|
||||
const std::vector<double> ans{-0.18, 1.12, 1.4};
|
||||
|
||||
const auto query_values = autoware::interpolation::lerp(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(linear_interpolation, lerp_scalar_query)
|
||||
{
|
||||
{ // curve: query_keys is same as random
|
||||
const std::vector<double> base_keys{-1.5, 1.0, 5.0, 10.0, 15.0, 20.0};
|
||||
const std::vector<double> base_values{-1.2, 0.5, 1.0, 1.2, 2.0, 1.0};
|
||||
const std::vector<double> query_keys{0.0, 8.0, 18.0};
|
||||
const std::vector<double> ans{-0.18, 1.12, 1.4};
|
||||
|
||||
for (size_t i = 0; i < query_keys.size(); ++i) {
|
||||
const auto query_value =
|
||||
autoware::interpolation::lerp(base_keys, base_values, query_keys.at(i));
|
||||
EXPECT_NEAR(query_value, ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
// Copyright 2021 Tier IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/interpolation/spherical_linear_interpolation.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
constexpr double epsilon = 1e-6;
|
||||
|
||||
namespace
|
||||
{
|
||||
inline geometry_msgs::msg::Quaternion createQuaternionFromRPY(
|
||||
const double roll, const double pitch, const double yaw)
|
||||
{
|
||||
tf2::Quaternion q;
|
||||
q.setRPY(roll, pitch, yaw);
|
||||
return tf2::toMsg(q);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(slerp, spline_scalar)
|
||||
{
|
||||
using autoware::interpolation::slerp;
|
||||
|
||||
// Same value
|
||||
{
|
||||
const double src_yaw = 0.0;
|
||||
const double dst_yaw = 0.0;
|
||||
const auto src_quat = createQuaternionFromRPY(0.0, 0.0, src_yaw);
|
||||
const auto dst_quat = createQuaternionFromRPY(0.0, 0.0, dst_yaw);
|
||||
|
||||
const auto ans_quat = createQuaternionFromRPY(0.0, 0.0, 0.0);
|
||||
|
||||
for (double ratio = -2.0; ratio < 2.0 + epsilon; ratio += 0.1) {
|
||||
const auto interpolated_quat = slerp(src_quat, dst_quat, ratio);
|
||||
EXPECT_NEAR(ans_quat.x, interpolated_quat.x, epsilon);
|
||||
EXPECT_NEAR(ans_quat.y, interpolated_quat.y, epsilon);
|
||||
EXPECT_NEAR(ans_quat.z, interpolated_quat.z, epsilon);
|
||||
EXPECT_NEAR(ans_quat.w, interpolated_quat.w, epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
// Random Value
|
||||
{
|
||||
const double src_yaw = 0.0;
|
||||
const double dst_yaw = M_PI;
|
||||
const auto src_quat = createQuaternionFromRPY(0.0, 0.0, src_yaw);
|
||||
const auto dst_quat = createQuaternionFromRPY(0.0, 0.0, dst_yaw);
|
||||
|
||||
for (double ratio = -2.0; ratio < 2.0 + epsilon; ratio += 0.1) {
|
||||
const auto interpolated_quat = slerp(src_quat, dst_quat, ratio);
|
||||
|
||||
const double ans_yaw = M_PI * ratio;
|
||||
tf2::Quaternion ans;
|
||||
ans.setRPY(0, 0, ans_yaw);
|
||||
const geometry_msgs::msg::Quaternion ans_quat = tf2::toMsg(ans);
|
||||
|
||||
EXPECT_NEAR(ans_quat.x, interpolated_quat.x, epsilon);
|
||||
EXPECT_NEAR(ans_quat.y, interpolated_quat.y, epsilon);
|
||||
EXPECT_NEAR(ans_quat.z, interpolated_quat.z, epsilon);
|
||||
EXPECT_NEAR(ans_quat.w, interpolated_quat.w, epsilon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(slerp, spline_vector)
|
||||
{
|
||||
using autoware::interpolation::slerp;
|
||||
|
||||
// query keys are same as base keys
|
||||
{
|
||||
const std::vector<double> base_keys{0.0, 1.0, 2.0, 3.0, 4.0};
|
||||
std::vector<geometry_msgs::msg::Quaternion> base_values;
|
||||
for (size_t i = 0; i < 5; ++i) {
|
||||
const auto quat = createQuaternionFromRPY(0.0, 0.0, i * M_PI / 5.0);
|
||||
base_values.push_back(quat);
|
||||
}
|
||||
const std::vector<double> query_keys = base_keys;
|
||||
const auto ans = base_values;
|
||||
|
||||
const auto results = slerp(base_keys, base_values, query_keys);
|
||||
|
||||
for (size_t i = 0; i < results.size(); ++i) {
|
||||
const auto interpolated_quat = results.at(i);
|
||||
const auto ans_quat = ans.at(i);
|
||||
|
||||
EXPECT_NEAR(ans_quat.x, interpolated_quat.x, epsilon);
|
||||
EXPECT_NEAR(ans_quat.y, interpolated_quat.y, epsilon);
|
||||
EXPECT_NEAR(ans_quat.z, interpolated_quat.z, epsilon);
|
||||
EXPECT_NEAR(ans_quat.w, interpolated_quat.w, epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
// random
|
||||
{
|
||||
const std::vector<double> base_keys{0.0, 1.0, 2.0, 3.0, 4.0};
|
||||
std::vector<geometry_msgs::msg::Quaternion> base_values;
|
||||
for (size_t i = 0; i < 5; ++i) {
|
||||
const auto quat = createQuaternionFromRPY(0.0, 0.0, i * M_PI / 5.0);
|
||||
base_values.push_back(quat);
|
||||
}
|
||||
const std::vector<double> query_keys = {0.0, 0.1, 1.5, 2.6, 3.1, 3.8};
|
||||
std::vector<geometry_msgs::msg::Quaternion> ans(query_keys.size());
|
||||
ans.at(0) = createQuaternionFromRPY(0.0, 0.0, 0.0);
|
||||
ans.at(1) = createQuaternionFromRPY(0.0, 0.0, 0.1 * M_PI / 5.0);
|
||||
ans.at(2) = createQuaternionFromRPY(0.0, 0.0, 0.5 * M_PI / 5.0 + M_PI / 5.0);
|
||||
ans.at(3) = createQuaternionFromRPY(0.0, 0.0, 0.6 * M_PI / 5.0 + 2.0 * M_PI / 5.0);
|
||||
ans.at(4) = createQuaternionFromRPY(0.0, 0.0, 0.1 * M_PI / 5.0 + 3.0 * M_PI / 5.0);
|
||||
ans.at(5) = createQuaternionFromRPY(0.0, 0.0, 0.8 * M_PI / 5.0 + 3.0 * M_PI / 5.0);
|
||||
|
||||
const auto results = slerp(base_keys, base_values, query_keys);
|
||||
|
||||
for (size_t i = 0; i < results.size(); ++i) {
|
||||
const auto interpolated_quat = results.at(i);
|
||||
const auto ans_quat = ans.at(i);
|
||||
|
||||
EXPECT_NEAR(ans_quat.x, interpolated_quat.x, epsilon);
|
||||
EXPECT_NEAR(ans_quat.y, interpolated_quat.y, epsilon);
|
||||
EXPECT_NEAR(ans_quat.z, interpolated_quat.z, epsilon);
|
||||
EXPECT_NEAR(ans_quat.w, interpolated_quat.w, epsilon);
|
||||
}
|
||||
}
|
||||
}
|
||||
+279
@@ -0,0 +1,279 @@
|
||||
// Copyright 2021 Tier IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/interpolation/spline_interpolation.hpp"
|
||||
#include "autoware/universe_utils/geometry/geometry.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
constexpr double epsilon = 1e-6;
|
||||
|
||||
using autoware::interpolation::SplineInterpolation;
|
||||
|
||||
TEST(spline_interpolation, spline)
|
||||
{
|
||||
{ // straight: query_keys is same as base_keys
|
||||
const std::vector<double> base_keys{0.0, 1.0, 2.0, 3.0, 4.0};
|
||||
const std::vector<double> base_values{0.0, 1.5, 3.0, 4.5, 6.0};
|
||||
const std::vector<double> query_keys = base_keys;
|
||||
const std::vector<double> ans = base_values;
|
||||
|
||||
const auto query_values = autoware::interpolation::spline(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // straight: query_keys is random
|
||||
const std::vector<double> base_keys{0.0, 1.0, 2.0, 3.0, 4.0};
|
||||
const std::vector<double> base_values{0.0, 1.5, 3.0, 4.5, 6.0};
|
||||
const std::vector<double> query_keys{0.0, 0.7, 1.9, 4.0};
|
||||
const std::vector<double> ans{0.0, 1.05, 2.85, 6.0};
|
||||
|
||||
const auto query_values = autoware::interpolation::spline(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // curve: query_keys is same as base_keys
|
||||
const std::vector<double> base_keys{-1.5, 1.0, 5.0, 10.0, 15.0, 20.0};
|
||||
const std::vector<double> base_values{-1.2, 0.5, 1.0, 1.2, 2.0, 1.0};
|
||||
const std::vector<double> query_keys = base_keys;
|
||||
const std::vector<double> ans = base_values;
|
||||
|
||||
const auto query_values = autoware::interpolation::spline(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // curve: query_keys is random
|
||||
const std::vector<double> base_keys{-1.5, 1.0, 5.0, 10.0, 15.0, 20.0};
|
||||
const std::vector<double> base_values{-1.2, 0.5, 1.0, 1.2, 2.0, 1.0};
|
||||
const std::vector<double> query_keys{0.0, 8.0, 18.0};
|
||||
const std::vector<double> ans{-0.076114, 1.001217, 1.573640};
|
||||
|
||||
const auto query_values = autoware::interpolation::spline(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // straight: size of base_keys is 2 (edge case in the implementation)
|
||||
const std::vector<double> base_keys{0.0, 1.0};
|
||||
const std::vector<double> base_values{0.0, 1.5};
|
||||
const std::vector<double> query_keys = base_keys;
|
||||
const std::vector<double> ans = base_values;
|
||||
|
||||
const auto query_values = autoware::interpolation::spline(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // straight: size of base_keys is 3 (edge case in the implementation)
|
||||
const std::vector<double> base_keys{0.0, 1.0, 2.0};
|
||||
const std::vector<double> base_values{0.0, 1.5, 3.0};
|
||||
const std::vector<double> query_keys = base_keys;
|
||||
const std::vector<double> ans = base_values;
|
||||
|
||||
const auto query_values = autoware::interpolation::spline(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // curve: query_keys is random. size of base_keys is 3 (edge case in the implementation)
|
||||
const std::vector<double> base_keys{-1.5, 1.0, 5.0};
|
||||
const std::vector<double> base_values{-1.2, 0.5, 1.0};
|
||||
const std::vector<double> query_keys{-1.0, 0.0, 4.0};
|
||||
const std::vector<double> ans{-0.808769, -0.077539, 1.035096};
|
||||
|
||||
const auto query_values = autoware::interpolation::spline(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // When the query keys changes suddenly (edge case of spline interpolation).
|
||||
const std::vector<double> base_keys = {0.0, 1.0, 1.0001, 2.0, 3.0, 4.0};
|
||||
const std::vector<double> base_values = {0.0, 0.0, 0.1, 0.1, 0.1, 0.1};
|
||||
const std::vector<double> query_keys = {0.0, 1.0, 1.5, 2.0, 3.0, 4.0};
|
||||
const std::vector<double> ans = {0.0, 0.0, 158.738293, 0.1, 0.1, 0.1};
|
||||
|
||||
const auto query_values = autoware::interpolation::spline(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(spline_interpolation, splineByAkima)
|
||||
{
|
||||
{ // straight: query_keys is same as base_keys
|
||||
const std::vector<double> base_keys{0.0, 1.0, 2.0, 3.0, 4.0};
|
||||
const std::vector<double> base_values{0.0, 1.5, 3.0, 4.5, 6.0};
|
||||
const std::vector<double> query_keys = base_keys;
|
||||
const std::vector<double> ans = base_values;
|
||||
|
||||
const auto query_values =
|
||||
autoware::interpolation::splineByAkima(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // straight: query_keys is random
|
||||
const std::vector<double> base_keys{0.0, 1.0, 2.0, 3.0, 4.0};
|
||||
const std::vector<double> base_values{0.0, 1.5, 3.0, 4.5, 6.0};
|
||||
const std::vector<double> query_keys{0.0, 0.7, 1.9, 4.0};
|
||||
const std::vector<double> ans{0.0, 1.05, 2.85, 6.0};
|
||||
|
||||
const auto query_values =
|
||||
autoware::interpolation::splineByAkima(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // curve: query_keys is same as base_keys
|
||||
const std::vector<double> base_keys{-1.5, 1.0, 5.0, 10.0, 15.0, 20.0};
|
||||
const std::vector<double> base_values{-1.2, 0.5, 1.0, 1.2, 2.0, 1.0};
|
||||
const std::vector<double> query_keys = base_keys;
|
||||
const std::vector<double> ans = base_values;
|
||||
|
||||
const auto query_values =
|
||||
autoware::interpolation::splineByAkima(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // curve: query_keys is random
|
||||
const std::vector<double> base_keys{-1.5, 1.0, 5.0, 10.0, 15.0, 20.0};
|
||||
const std::vector<double> base_values{-1.2, 0.5, 1.0, 1.2, 2.0, 1.0};
|
||||
const std::vector<double> query_keys{0.0, 8.0, 18.0};
|
||||
const std::vector<double> ans{-0.0801, 1.110749, 1.4864};
|
||||
|
||||
const auto query_values =
|
||||
autoware::interpolation::splineByAkima(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // straight: size of base_keys is 2 (edge case in the implementation)
|
||||
const std::vector<double> base_keys{0.0, 1.0};
|
||||
const std::vector<double> base_values{0.0, 1.5};
|
||||
const std::vector<double> query_keys = base_keys;
|
||||
const std::vector<double> ans = base_values;
|
||||
|
||||
const auto query_values =
|
||||
autoware::interpolation::splineByAkima(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // straight: size of base_keys is 3 (edge case in the implementation)
|
||||
const std::vector<double> base_keys{0.0, 1.0, 2.0};
|
||||
const std::vector<double> base_values{0.0, 1.5, 3.0};
|
||||
const std::vector<double> query_keys = base_keys;
|
||||
const std::vector<double> ans = base_values;
|
||||
|
||||
const auto query_values =
|
||||
autoware::interpolation::splineByAkima(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // curve: query_keys is random. size of base_keys is 3 (edge case in the implementation)
|
||||
const std::vector<double> base_keys{-1.5, 1.0, 5.0};
|
||||
const std::vector<double> base_values{-1.2, 0.5, 1.0};
|
||||
const std::vector<double> query_keys{-1.0, 0.0, 4.0};
|
||||
const std::vector<double> ans{-0.8378, -0.0801, 0.927031};
|
||||
|
||||
const auto query_values =
|
||||
autoware::interpolation::splineByAkima(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // When the query keys changes suddenly (edge case of spline interpolation).
|
||||
const std::vector<double> base_keys = {0.0, 1.0, 1.0001, 2.0, 3.0, 4.0};
|
||||
const std::vector<double> base_values = {0.0, 0.0, 0.1, 0.1, 0.1, 0.1};
|
||||
const std::vector<double> query_keys = {0.0, 1.0, 1.5, 2.0, 3.0, 4.0};
|
||||
const std::vector<double> ans = {0.0, 0.0, 0.1, 0.1, 0.1, 0.1};
|
||||
|
||||
const auto query_values =
|
||||
autoware::interpolation::splineByAkima(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(spline_interpolation, SplineInterpolation)
|
||||
{
|
||||
{
|
||||
// curve: query_keys is random
|
||||
const std::vector<double> base_keys{-1.5, 1.0, 5.0, 10.0, 15.0, 20.0};
|
||||
const std::vector<double> base_values{-1.2, 0.5, 1.0, 1.2, 2.0, 1.0};
|
||||
const std::vector<double> query_keys{0.0, 8.0, 18.0};
|
||||
const std::vector<double> ans{-0.076114, 1.001217, 1.573640};
|
||||
|
||||
SplineInterpolation s(base_keys, base_values);
|
||||
const std::vector<double> query_values = s.getSplineInterpolatedValues(query_keys);
|
||||
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// getSplineInterpolatedDiffValues
|
||||
const std::vector<double> base_keys{-1.5, 1.0, 5.0, 10.0, 15.0, 20.0};
|
||||
const std::vector<double> base_values{-1.2, 0.5, 1.0, 1.2, 2.0, 1.0};
|
||||
const std::vector<double> query_keys{0.0, 8.0, 12.0, 18.0};
|
||||
const std::vector<double> ans{0.671343, 0.049289, 0.209471, -0.253746};
|
||||
|
||||
SplineInterpolation s(base_keys, base_values);
|
||||
const std::vector<double> query_values = s.getSplineInterpolatedDiffValues(query_keys);
|
||||
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// getSplineInterpolatedQuadDiffValues
|
||||
const std::vector<double> base_keys{-1.5, 1.0, 5.0, 10.0, 15.0, 20.0};
|
||||
const std::vector<double> base_values{-1.2, 0.5, 1.0, 1.2, 2.0, 1.0};
|
||||
const std::vector<double> query_keys{0.0, 8.0, 12.0, 18.0};
|
||||
const std::vector<double> ans{-0.155829, 0.043097, -0.011143, -0.049611};
|
||||
|
||||
SplineInterpolation s(base_keys, base_values);
|
||||
const std::vector<double> query_values = s.getSplineInterpolatedQuadDiffValues(query_keys);
|
||||
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
}
|
||||
+223
@@ -0,0 +1,223 @@
|
||||
// Copyright 2023 TIER IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/interpolation/spline_interpolation.hpp"
|
||||
#include "autoware/interpolation/spline_interpolation_points_2d.hpp"
|
||||
#include "autoware/universe_utils/geometry/geometry.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
constexpr double epsilon = 1e-6;
|
||||
|
||||
using autoware::interpolation::SplineInterpolationPoints2d;
|
||||
|
||||
TEST(spline_interpolation, splineYawFromPoints)
|
||||
{
|
||||
using autoware::universe_utils::createPoint;
|
||||
|
||||
{ // straight
|
||||
std::vector<geometry_msgs::msg::Point> points;
|
||||
points.push_back(createPoint(0.0, 0.0, 0.0));
|
||||
points.push_back(createPoint(1.0, 1.5, 0.0));
|
||||
points.push_back(createPoint(2.0, 3.0, 0.0));
|
||||
points.push_back(createPoint(3.0, 4.5, 0.0));
|
||||
points.push_back(createPoint(4.0, 6.0, 0.0));
|
||||
|
||||
const std::vector<double> ans{0.9827937, 0.9827937, 0.9827937, 0.9827937, 0.9827937};
|
||||
|
||||
const auto yaws = autoware::interpolation::splineYawFromPoints(points);
|
||||
for (size_t i = 0; i < yaws.size(); ++i) {
|
||||
EXPECT_NEAR(yaws.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // curve
|
||||
std::vector<geometry_msgs::msg::Point> points;
|
||||
points.push_back(createPoint(-2.0, -10.0, 0.0));
|
||||
points.push_back(createPoint(2.0, 1.5, 0.0));
|
||||
points.push_back(createPoint(3.0, 3.0, 0.0));
|
||||
points.push_back(createPoint(5.0, 10.0, 0.0));
|
||||
points.push_back(createPoint(10.0, 12.5, 0.0));
|
||||
|
||||
const std::vector<double> ans{1.368174, 0.961318, 1.086098, 0.938357, 0.278594};
|
||||
const auto yaws = autoware::interpolation::splineYawFromPoints(points);
|
||||
for (size_t i = 0; i < yaws.size(); ++i) {
|
||||
EXPECT_NEAR(yaws.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // size of base_keys is 1 (infeasible to interpolate)
|
||||
std::vector<geometry_msgs::msg::Point> points;
|
||||
points.push_back(createPoint(1.0, 0.0, 0.0));
|
||||
|
||||
EXPECT_THROW(autoware::interpolation::splineYawFromPoints(points), std::logic_error);
|
||||
}
|
||||
|
||||
{ // straight: size of base_keys is 2 (edge case in the implementation)
|
||||
std::vector<geometry_msgs::msg::Point> points;
|
||||
points.push_back(createPoint(1.0, 0.0, 0.0));
|
||||
points.push_back(createPoint(2.0, 1.5, 0.0));
|
||||
|
||||
const std::vector<double> ans{0.9827937, 0.9827937};
|
||||
|
||||
const auto yaws = autoware::interpolation::splineYawFromPoints(points);
|
||||
for (size_t i = 0; i < yaws.size(); ++i) {
|
||||
EXPECT_NEAR(yaws.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // straight: size of base_keys is 3 (edge case in the implementation)
|
||||
std::vector<geometry_msgs::msg::Point> points;
|
||||
points.push_back(createPoint(1.0, 0.0, 0.0));
|
||||
points.push_back(createPoint(2.0, 1.5, 0.0));
|
||||
points.push_back(createPoint(3.0, 3.0, 0.0));
|
||||
|
||||
const std::vector<double> ans{0.9827937, 0.9827937, 0.9827937};
|
||||
|
||||
const auto yaws = autoware::interpolation::splineYawFromPoints(points);
|
||||
for (size_t i = 0; i < yaws.size(); ++i) {
|
||||
EXPECT_NEAR(yaws.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(spline_interpolation, SplineInterpolationPoints2d)
|
||||
{
|
||||
using autoware::universe_utils::createPoint;
|
||||
|
||||
// curve
|
||||
std::vector<geometry_msgs::msg::Point> points;
|
||||
points.push_back(createPoint(-2.0, -10.0, 0.0));
|
||||
points.push_back(createPoint(2.0, 1.5, 0.0));
|
||||
points.push_back(createPoint(3.0, 3.0, 0.0));
|
||||
points.push_back(createPoint(5.0, 10.0, 0.0));
|
||||
points.push_back(createPoint(10.0, 12.5, 0.0));
|
||||
|
||||
SplineInterpolationPoints2d s(points);
|
||||
|
||||
{ // point
|
||||
// front
|
||||
const auto front_point = s.getSplineInterpolatedPoint(0, 0.0);
|
||||
EXPECT_NEAR(front_point.x, -2.0, epsilon);
|
||||
EXPECT_NEAR(front_point.y, -10.0, epsilon);
|
||||
|
||||
// back
|
||||
const auto back_point = s.getSplineInterpolatedPoint(4, 0.0);
|
||||
EXPECT_NEAR(back_point.x, 10.0, epsilon);
|
||||
EXPECT_NEAR(back_point.y, 12.5, epsilon);
|
||||
|
||||
// random
|
||||
const auto random_point = s.getSplineInterpolatedPoint(3, 0.5);
|
||||
EXPECT_NEAR(random_point.x, 5.28974, epsilon);
|
||||
EXPECT_NEAR(random_point.y, 10.3450319, epsilon);
|
||||
|
||||
// out of range of total length
|
||||
const auto front_out_point = s.getSplineInterpolatedPoint(0.0, -0.1);
|
||||
EXPECT_NEAR(front_out_point.x, -2.0, epsilon);
|
||||
EXPECT_NEAR(front_out_point.y, -10.0, epsilon);
|
||||
|
||||
const auto back_out_point = s.getSplineInterpolatedPoint(4.0, 0.1);
|
||||
EXPECT_NEAR(back_out_point.x, 10.0, epsilon);
|
||||
EXPECT_NEAR(back_out_point.y, 12.5, epsilon);
|
||||
|
||||
// out of range of index
|
||||
EXPECT_THROW(s.getSplineInterpolatedPoint(-1, 0.0), std::out_of_range);
|
||||
EXPECT_THROW(s.getSplineInterpolatedPoint(5, 0.0), std::out_of_range);
|
||||
}
|
||||
|
||||
{ // yaw
|
||||
// front
|
||||
EXPECT_NEAR(s.getSplineInterpolatedYaw(0, 0.0), 1.368174, epsilon);
|
||||
|
||||
// back
|
||||
EXPECT_NEAR(s.getSplineInterpolatedYaw(4, 0.0), 0.278594, epsilon);
|
||||
|
||||
// random
|
||||
EXPECT_NEAR(s.getSplineInterpolatedYaw(3, 0.5), 0.808580, epsilon);
|
||||
|
||||
// out of range of total length
|
||||
EXPECT_NEAR(s.getSplineInterpolatedYaw(0.0, -0.1), 1.368174, epsilon);
|
||||
EXPECT_NEAR(s.getSplineInterpolatedYaw(4, 0.1), 0.278594, epsilon);
|
||||
|
||||
// out of range of index
|
||||
EXPECT_THROW(s.getSplineInterpolatedYaw(-1, 0.0), std::out_of_range);
|
||||
EXPECT_THROW(s.getSplineInterpolatedYaw(5, 0.0), std::out_of_range);
|
||||
}
|
||||
|
||||
{ // curvature
|
||||
// front
|
||||
EXPECT_NEAR(s.getSplineInterpolatedCurvature(0, 0.0), 0.0, epsilon);
|
||||
|
||||
// back
|
||||
EXPECT_NEAR(s.getSplineInterpolatedCurvature(4, 0.0), 0.0, epsilon);
|
||||
|
||||
// random
|
||||
EXPECT_NEAR(s.getSplineInterpolatedCurvature(3, 0.5), -0.271073, epsilon);
|
||||
|
||||
// out of range of total length
|
||||
EXPECT_NEAR(s.getSplineInterpolatedCurvature(0.0, -0.1), 0.0, epsilon);
|
||||
EXPECT_NEAR(s.getSplineInterpolatedCurvature(4, 0.1), 0.0, epsilon);
|
||||
|
||||
// out of range of index
|
||||
EXPECT_THROW(s.getSplineInterpolatedCurvature(-1, 0.0), std::out_of_range);
|
||||
EXPECT_THROW(s.getSplineInterpolatedCurvature(5, 0.0), std::out_of_range);
|
||||
}
|
||||
|
||||
{ // accumulated distance
|
||||
// front
|
||||
EXPECT_NEAR(s.getAccumulatedLength(0), 0.0, epsilon);
|
||||
|
||||
// back
|
||||
EXPECT_NEAR(s.getAccumulatedLength(4), 26.8488511, epsilon);
|
||||
|
||||
// random
|
||||
EXPECT_NEAR(s.getAccumulatedLength(3), 21.2586811, epsilon);
|
||||
|
||||
// out of range of index
|
||||
EXPECT_THROW(s.getAccumulatedLength(-1), std::out_of_range);
|
||||
EXPECT_THROW(s.getAccumulatedLength(5), std::out_of_range);
|
||||
}
|
||||
|
||||
// size of base_keys is 1 (infeasible to interpolate)
|
||||
std::vector<geometry_msgs::msg::Point> single_points;
|
||||
single_points.push_back(createPoint(1.0, 0.0, 0.0));
|
||||
EXPECT_THROW(SplineInterpolationPoints2d{single_points}, std::logic_error);
|
||||
}
|
||||
|
||||
TEST(spline_interpolation, SplineInterpolationPoints2dPolymorphism)
|
||||
{
|
||||
using autoware::universe_utils::createPoint;
|
||||
using autoware_planning_msgs::msg::TrajectoryPoint;
|
||||
|
||||
std::vector<geometry_msgs::msg::Point> points;
|
||||
points.push_back(createPoint(-2.0, -10.0, 0.0));
|
||||
points.push_back(createPoint(2.0, 1.5, 0.0));
|
||||
points.push_back(createPoint(3.0, 3.0, 0.0));
|
||||
|
||||
std::vector<TrajectoryPoint> trajectory_points;
|
||||
for (const auto & p : points) {
|
||||
TrajectoryPoint tp;
|
||||
tp.pose.position = p;
|
||||
trajectory_points.push_back(tp);
|
||||
}
|
||||
|
||||
SplineInterpolationPoints2d s_point(points);
|
||||
s_point.getSplineInterpolatedPoint(0, 0.);
|
||||
|
||||
SplineInterpolationPoints2d s_traj_point(trajectory_points);
|
||||
s_traj_point.getSplineInterpolatedPoint(0, 0.);
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
// Copyright 2022 Tier IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/interpolation/zero_order_hold.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
constexpr double epsilon = 1e-6;
|
||||
|
||||
TEST(zero_order_hold_interpolation, vector_interpolation)
|
||||
{
|
||||
{ // straight: query_keys is same as base_keys
|
||||
const std::vector<double> base_keys{0.0, 1.0, 2.0, 3.0, 4.0};
|
||||
const std::vector<double> base_values{0.0, 1.5, 2.5, 3.5, 0.0};
|
||||
const std::vector<double> query_keys = base_keys;
|
||||
const std::vector<double> ans = base_values;
|
||||
|
||||
const auto query_values =
|
||||
autoware::interpolation::zero_order_hold(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // straight: query_keys is random
|
||||
const std::vector<double> base_keys{0.0, 1.0, 2.0, 3.0, 4.0};
|
||||
const std::vector<double> base_values{0.0, 1.5, 3.0, 4.5, 6.0};
|
||||
const std::vector<double> query_keys{0.0, 0.7, 1.9, 4.0};
|
||||
const std::vector<double> ans{0.0, 0.0, 1.5, 6.0};
|
||||
|
||||
const auto query_values =
|
||||
autoware::interpolation::zero_order_hold(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // curve: query_keys is same as base_keys
|
||||
const std::vector<double> base_keys{-1.5, 1.0, 5.0, 10.0, 15.0, 20.0};
|
||||
const std::vector<double> base_values{-1.2, 0.5, 1.0, 1.2, 2.0, 1.0};
|
||||
const std::vector<double> query_keys = base_keys;
|
||||
const std::vector<double> ans = base_values;
|
||||
|
||||
const auto query_values =
|
||||
autoware::interpolation::zero_order_hold(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // curve: query_keys is same as random
|
||||
const std::vector<double> base_keys{-1.5, 1.0, 5.0, 10.0, 15.0, 20.0};
|
||||
const std::vector<double> base_values{-1.2, 0.5, 1.0, 1.2, 2.0, 1.0};
|
||||
const std::vector<double> query_keys{0.0, 8.0, 18.0};
|
||||
const std::vector<double> ans{-1.2, 1.0, 2.0};
|
||||
|
||||
const auto query_values =
|
||||
autoware::interpolation::zero_order_hold(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Boundary Condition
|
||||
const std::vector<double> base_keys{0.0, 1.0, 2.0, 3.0, 4.0};
|
||||
const std::vector<double> base_values{0.0, 1.5, 2.5, 3.5, 0.0};
|
||||
const std::vector<double> query_keys{0.0, 1.0, 2.0, 3.0, 4.0 - 0.001};
|
||||
const std::vector<double> ans = {0.0, 1.5, 2.5, 3.5, 3.5};
|
||||
|
||||
const auto query_values =
|
||||
autoware::interpolation::zero_order_hold(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Boundary Condition
|
||||
const std::vector<double> base_keys{0.0, 1.0, 2.0, 3.0, 4.0};
|
||||
const std::vector<double> base_values{0.0, 1.5, 2.5, 3.5, 0.0};
|
||||
const std::vector<double> query_keys{0.0, 1.0, 2.0, 3.0, 4.0 - 0.0001};
|
||||
const std::vector<double> ans = {0.0, 1.5, 2.5, 3.5, 0.0};
|
||||
|
||||
const auto query_values =
|
||||
autoware::interpolation::zero_order_hold(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(zero_order_hold_interpolation, vector_interpolation_no_double_interpolation)
|
||||
{
|
||||
{ // straight: query_keys is same as base_keys
|
||||
const std::vector<double> base_keys{0.0, 1.0, 2.0, 3.0, 4.0};
|
||||
const std::vector<bool> base_values{true, true, false, true, true};
|
||||
const std::vector<double> query_keys = base_keys;
|
||||
const auto ans = base_values;
|
||||
|
||||
const auto query_values =
|
||||
autoware::interpolation::zero_order_hold(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_EQ(query_values.at(i), ans.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
{ // straight: query_keys is random
|
||||
const std::vector<double> base_keys{0.0, 1.0, 2.0, 3.0, 4.0};
|
||||
const std::vector<double> base_values{true, false, false, true, false};
|
||||
const std::vector<double> query_keys{0.0, 0.7, 1.9, 4.0};
|
||||
const std::vector<bool> ans = {true, true, false, false};
|
||||
|
||||
const auto query_values =
|
||||
autoware::interpolation::zero_order_hold(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_EQ(query_values.at(i), ans.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
{ // Boundary Condition
|
||||
const std::vector<double> base_keys{0.0, 1.0, 2.0, 3.0, 4.0};
|
||||
const std::vector<bool> base_values{true, true, false, true, false};
|
||||
const std::vector<double> query_keys{0.0, 1.0, 2.0, 3.0, 4.0 - 0.001};
|
||||
const std::vector<double> ans = {true, true, false, true, true};
|
||||
|
||||
const auto query_values =
|
||||
autoware::interpolation::zero_order_hold(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Boundary Condition
|
||||
const std::vector<double> base_keys{0.0, 1.0, 2.0, 3.0, 4.0};
|
||||
const std::vector<double> base_values{true, false, true, true, false};
|
||||
const std::vector<double> query_keys{0.0, 1.0, 2.0, 3.0, 4.0 - 0.0001};
|
||||
const std::vector<double> ans = base_values;
|
||||
|
||||
const auto query_values =
|
||||
autoware::interpolation::zero_order_hold(base_keys, base_values, query_keys);
|
||||
for (size_t i = 0; i < query_values.size(); ++i) {
|
||||
EXPECT_NEAR(query_values.at(i), ans.at(i), epsilon);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(autoware_kalman_filter)
|
||||
|
||||
find_package(autoware_cmake REQUIRED)
|
||||
autoware_package()
|
||||
|
||||
find_package(eigen3_cmake_module REQUIRED)
|
||||
find_package(Eigen3 REQUIRED)
|
||||
|
||||
include_directories(
|
||||
SYSTEM
|
||||
${EIGEN3_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
ament_auto_add_library(${PROJECT_NAME} SHARED
|
||||
src/kalman_filter.cpp
|
||||
src/time_delay_kalman_filter.cpp
|
||||
include/autoware/kalman_filter/kalman_filter.hpp
|
||||
include/autoware/kalman_filter/time_delay_kalman_filter.hpp
|
||||
)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
file(GLOB_RECURSE test_files test/*.cpp)
|
||||
ament_add_ros_isolated_gtest(test_${PROJECT_NAME} ${test_files})
|
||||
|
||||
target_link_libraries(test_${PROJECT_NAME} ${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
ament_auto_package()
|
||||
@@ -0,0 +1,9 @@
|
||||
# kalman_filter
|
||||
|
||||
## Purpose
|
||||
|
||||
This common package contains the kalman filter with time delay and the calculation of the kalman filter.
|
||||
|
||||
## Assumptions / Known limits
|
||||
|
||||
TBD.
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
// Copyright 2018-2019 Autoware Foundation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef AUTOWARE__KALMAN_FILTER__KALMAN_FILTER_HPP_
|
||||
#define AUTOWARE__KALMAN_FILTER__KALMAN_FILTER_HPP_
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/LU>
|
||||
|
||||
namespace autoware::kalman_filter
|
||||
{
|
||||
|
||||
/**
|
||||
* @file kalman_filter.h
|
||||
* @brief kalman filter class
|
||||
* @author Takamasa Horibe
|
||||
* @date 2019.05.01
|
||||
*/
|
||||
|
||||
class KalmanFilter
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief No initialization constructor.
|
||||
*/
|
||||
KalmanFilter();
|
||||
|
||||
/**
|
||||
* @brief constructor with initialization
|
||||
* @param x initial state
|
||||
* @param A coefficient matrix of x for process model
|
||||
* @param B coefficient matrix of u for process model
|
||||
* @param C coefficient matrix of x for measurement model
|
||||
* @param Q covariance matrix for process model
|
||||
* @param R covariance matrix for measurement model
|
||||
* @param P initial covariance of estimated state
|
||||
*/
|
||||
KalmanFilter(
|
||||
const Eigen::MatrixXd & x, const Eigen::MatrixXd & A, const Eigen::MatrixXd & B,
|
||||
const Eigen::MatrixXd & C, const Eigen::MatrixXd & Q, const Eigen::MatrixXd & R,
|
||||
const Eigen::MatrixXd & P);
|
||||
|
||||
/**
|
||||
* @brief destructor
|
||||
*/
|
||||
~KalmanFilter();
|
||||
|
||||
/**
|
||||
* @brief initialization of kalman filter
|
||||
* @param x initial state
|
||||
* @param A coefficient matrix of x for process model
|
||||
* @param B coefficient matrix of u for process model
|
||||
* @param C coefficient matrix of x for measurement model
|
||||
* @param Q covariance matrix for process model
|
||||
* @param R covariance matrix for measurement model
|
||||
* @param P initial covariance of estimated state
|
||||
*/
|
||||
bool init(
|
||||
const Eigen::MatrixXd & x, const Eigen::MatrixXd & A, const Eigen::MatrixXd & B,
|
||||
const Eigen::MatrixXd & C, const Eigen::MatrixXd & Q, const Eigen::MatrixXd & R,
|
||||
const Eigen::MatrixXd & P);
|
||||
|
||||
/**
|
||||
* @brief initialization of kalman filter
|
||||
* @param x initial state
|
||||
* @param P initial covariance of estimated state
|
||||
*/
|
||||
bool init(const Eigen::MatrixXd & x, const Eigen::MatrixXd & P0);
|
||||
|
||||
/**
|
||||
* @brief set A of process model
|
||||
* @param A coefficient matrix of x for process model
|
||||
*/
|
||||
void setA(const Eigen::MatrixXd & A);
|
||||
|
||||
/**
|
||||
* @brief set B of process model
|
||||
* @param B coefficient matrix of u for process model
|
||||
*/
|
||||
void setB(const Eigen::MatrixXd & B);
|
||||
|
||||
/**
|
||||
* @brief set C of measurement model
|
||||
* @param C coefficient matrix of x for measurement model
|
||||
*/
|
||||
void setC(const Eigen::MatrixXd & C);
|
||||
|
||||
/**
|
||||
* @brief set covariance matrix Q for process model
|
||||
* @param Q covariance matrix for process model
|
||||
*/
|
||||
void setQ(const Eigen::MatrixXd & Q);
|
||||
|
||||
/**
|
||||
* @brief set covariance matrix R for measurement model
|
||||
* @param R covariance matrix for measurement model
|
||||
*/
|
||||
void setR(const Eigen::MatrixXd & R);
|
||||
|
||||
/**
|
||||
* @brief get current kalman filter state
|
||||
* @param x kalman filter state
|
||||
*/
|
||||
void getX(Eigen::MatrixXd & x) const;
|
||||
|
||||
/**
|
||||
* @brief get current kalman filter covariance
|
||||
* @param P kalman filter covariance
|
||||
*/
|
||||
void getP(Eigen::MatrixXd & P) const;
|
||||
|
||||
/**
|
||||
* @brief get component of current kalman filter state
|
||||
* @param i index of kalman filter state
|
||||
* @return value of i's component of the kalman filter state x[i]
|
||||
*/
|
||||
double getXelement(unsigned int i) const;
|
||||
|
||||
/**
|
||||
* @brief calculate kalman filter state and covariance by prediction model with A, B, Q matrix.
|
||||
* This is mainly for EKF with variable matrix.
|
||||
* @param u input for model
|
||||
* @param A coefficient matrix of x for process model
|
||||
* @param B coefficient matrix of u for process model
|
||||
* @param Q covariance matrix for process model
|
||||
* @return bool to check matrix operations are being performed properly
|
||||
*/
|
||||
bool predict(
|
||||
const Eigen::MatrixXd & u, const Eigen::MatrixXd & A, const Eigen::MatrixXd & B,
|
||||
const Eigen::MatrixXd & Q);
|
||||
|
||||
/**
|
||||
* @brief calculate kalman filter covariance with prediction model with x, A, Q matrix. This is
|
||||
* mainly for EKF with variable matrix.
|
||||
* @param x_next predicted state
|
||||
* @param A coefficient matrix of x for process model
|
||||
* @param Q covariance matrix for process model
|
||||
* @return bool to check matrix operations are being performed properly
|
||||
*/
|
||||
bool predict(
|
||||
const Eigen::MatrixXd & x_next, const Eigen::MatrixXd & A, const Eigen::MatrixXd & Q);
|
||||
|
||||
/**
|
||||
* @brief calculate kalman filter covariance with prediction model with x, A, Q matrix. This is
|
||||
* mainly for EKF with variable matrix.
|
||||
* @param x_next predicted state
|
||||
* @param A coefficient matrix of x for process model
|
||||
* @return bool to check matrix operations are being performed properly
|
||||
*/
|
||||
bool predict(const Eigen::MatrixXd & x_next, const Eigen::MatrixXd & A);
|
||||
|
||||
/**
|
||||
* @brief calculate kalman filter state by prediction model with A, B and Q being class member
|
||||
* variables.
|
||||
* @param u input for the model
|
||||
* @return bool to check matrix operations are being performed properly
|
||||
*/
|
||||
bool predict(const Eigen::MatrixXd & u);
|
||||
|
||||
/**
|
||||
* @brief calculate kalman filter state by measurement model with y_pred, C and R matrix. This is
|
||||
* mainly for EKF with variable matrix.
|
||||
* @param y measured values
|
||||
* @param y output values expected from measurement model
|
||||
* @param C coefficient matrix of x for measurement model
|
||||
* @param R covariance matrix for measurement model
|
||||
* @return bool to check matrix operations are being performed properly
|
||||
*/
|
||||
bool update(
|
||||
const Eigen::MatrixXd & y, const Eigen::MatrixXd & y_pred, const Eigen::MatrixXd & C,
|
||||
const Eigen::MatrixXd & R);
|
||||
|
||||
/**
|
||||
* @brief calculate kalman filter state by measurement model with C and R matrix. This is mainly
|
||||
* for EKF with variable matrix.
|
||||
* @param y measured values
|
||||
* @param C coefficient matrix of x for measurement model
|
||||
* @param R covariance matrix for measurement model
|
||||
* @return bool to check matrix operations are being performed properly
|
||||
*/
|
||||
bool update(const Eigen::MatrixXd & y, const Eigen::MatrixXd & C, const Eigen::MatrixXd & R);
|
||||
|
||||
/**
|
||||
* @brief calculate kalman filter state by measurement model with C and R being class member
|
||||
* variables.
|
||||
* @param y measured values
|
||||
* @return bool to check matrix operations are being performed properly
|
||||
*/
|
||||
bool update(const Eigen::MatrixXd & y);
|
||||
|
||||
protected:
|
||||
Eigen::MatrixXd x_; //!< @brief current estimated state
|
||||
Eigen::MatrixXd
|
||||
A_; //!< @brief coefficient matrix of x for process model x[k+1] = A*x[k] + B*u[k]
|
||||
Eigen::MatrixXd
|
||||
B_; //!< @brief coefficient matrix of u for process model x[k+1] = A*x[k] + B*u[k]
|
||||
Eigen::MatrixXd C_; //!< @brief coefficient matrix of x for measurement model y[k] = C * x[k]
|
||||
Eigen::MatrixXd Q_; //!< @brief covariance matrix for process model x[k+1] = A*x[k] + B*u[k]
|
||||
Eigen::MatrixXd R_; //!< @brief covariance matrix for measurement model y[k] = C * x[k]
|
||||
Eigen::MatrixXd P_; //!< @brief covariance of estimated state
|
||||
};
|
||||
} // namespace autoware::kalman_filter
|
||||
#endif // AUTOWARE__KALMAN_FILTER__KALMAN_FILTER_HPP_
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
// Copyright 2018-2019 Autoware Foundation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef AUTOWARE__KALMAN_FILTER__TIME_DELAY_KALMAN_FILTER_HPP_
|
||||
#define AUTOWARE__KALMAN_FILTER__TIME_DELAY_KALMAN_FILTER_HPP_
|
||||
|
||||
#include "autoware/kalman_filter/kalman_filter.hpp"
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/LU>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace autoware::kalman_filter
|
||||
{
|
||||
/**
|
||||
* @file time_delay_kalman_filter.h
|
||||
* @brief kalman filter with delayed measurement class
|
||||
* @author Takamasa Horibe
|
||||
* @date 2019.05.01
|
||||
*/
|
||||
|
||||
class TimeDelayKalmanFilter : public KalmanFilter
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief No initialization constructor.
|
||||
*/
|
||||
TimeDelayKalmanFilter();
|
||||
|
||||
/**
|
||||
* @brief initialization of kalman filter
|
||||
* @param x initial state
|
||||
* @param P0 initial covariance of estimated state
|
||||
* @param max_delay_step Maximum number of delay steps, which determines the dimension of the
|
||||
* extended kalman filter
|
||||
*/
|
||||
void init(const Eigen::MatrixXd & x, const Eigen::MatrixXd & P, const int max_delay_step);
|
||||
|
||||
/**
|
||||
* @brief get latest time estimated state
|
||||
*/
|
||||
Eigen::MatrixXd getLatestX() const;
|
||||
|
||||
/**
|
||||
* @brief get latest time estimation covariance
|
||||
*/
|
||||
Eigen::MatrixXd getLatestP() const;
|
||||
|
||||
/**
|
||||
* @brief calculate kalman filter covariance by precision model with time delay. This is mainly
|
||||
* for EKF of nonlinear process model.
|
||||
* @param x_next predicted state by prediction model
|
||||
* @param A coefficient matrix of x for process model
|
||||
* @param Q covariance matrix for process model
|
||||
*/
|
||||
bool predictWithDelay(
|
||||
const Eigen::MatrixXd & x_next, const Eigen::MatrixXd & A, const Eigen::MatrixXd & Q);
|
||||
|
||||
/**
|
||||
* @brief calculate kalman filter covariance by measurement model with time delay. This is mainly
|
||||
* for EKF of nonlinear process model.
|
||||
* @param y measured values
|
||||
* @param C coefficient matrix of x for measurement model
|
||||
* @param R covariance matrix for measurement model
|
||||
* @param delay_step measurement delay
|
||||
*/
|
||||
bool updateWithDelay(
|
||||
const Eigen::MatrixXd & y, const Eigen::MatrixXd & C, const Eigen::MatrixXd & R,
|
||||
const int delay_step);
|
||||
|
||||
private:
|
||||
int max_delay_step_; //!< @brief maximum number of delay steps
|
||||
int dim_x_; //!< @brief dimension of latest state
|
||||
int dim_x_ex_; //!< @brief dimension of extended state with dime delay
|
||||
};
|
||||
} // namespace autoware::kalman_filter
|
||||
#endif // AUTOWARE__KALMAN_FILTER__TIME_DELAY_KALMAN_FILTER_HPP_
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="3">
|
||||
<name>autoware_kalman_filter</name>
|
||||
<version>0.1.0</version>
|
||||
<description>The kalman filter package</description>
|
||||
<maintainer email="yukihiro.saito@tier4.jp">Yukihiro Saito</maintainer>
|
||||
<maintainer email="takeshi.ishita@tier4.jp">Takeshi Ishita</maintainer>
|
||||
<maintainer email="koji.minoda@tier4.jp">Koji Minoda</maintainer>
|
||||
<license>Apache License 2.0</license>
|
||||
|
||||
<author email="takamasa.horibe@tier4.jp">Takamasa Horibe</author>
|
||||
|
||||
<buildtool_depend>ament_cmake_auto</buildtool_depend>
|
||||
<buildtool_depend>autoware_cmake</buildtool_depend>
|
||||
|
||||
<build_depend>eigen</build_depend>
|
||||
<build_depend>eigen3_cmake_module</build_depend>
|
||||
|
||||
<test_depend>ament_cmake_cppcheck</test_depend>
|
||||
<test_depend>ament_cmake_ros</test_depend>
|
||||
<test_depend>ament_lint_auto</test_depend>
|
||||
<test_depend>autoware_lint_common</test_depend>
|
||||
|
||||
<export>
|
||||
<build_type>ament_cmake</build_type>
|
||||
</export>
|
||||
</package>
|
||||
@@ -0,0 +1,161 @@
|
||||
// Copyright 2018-2019 Autoware Foundation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/kalman_filter/kalman_filter.hpp"
|
||||
|
||||
namespace autoware::kalman_filter
|
||||
{
|
||||
KalmanFilter::KalmanFilter()
|
||||
{
|
||||
}
|
||||
KalmanFilter::KalmanFilter(
|
||||
const Eigen::MatrixXd & x, const Eigen::MatrixXd & A, const Eigen::MatrixXd & B,
|
||||
const Eigen::MatrixXd & C, const Eigen::MatrixXd & Q, const Eigen::MatrixXd & R,
|
||||
const Eigen::MatrixXd & P)
|
||||
{
|
||||
init(x, A, B, C, Q, R, P);
|
||||
}
|
||||
KalmanFilter::~KalmanFilter()
|
||||
{
|
||||
}
|
||||
bool KalmanFilter::init(
|
||||
const Eigen::MatrixXd & x, const Eigen::MatrixXd & A, const Eigen::MatrixXd & B,
|
||||
const Eigen::MatrixXd & C, const Eigen::MatrixXd & Q, const Eigen::MatrixXd & R,
|
||||
const Eigen::MatrixXd & P)
|
||||
{
|
||||
if (
|
||||
x.cols() == 0 || x.rows() == 0 || A.cols() == 0 || A.rows() == 0 || B.cols() == 0 ||
|
||||
B.rows() == 0 || C.cols() == 0 || C.rows() == 0 || Q.cols() == 0 || Q.rows() == 0 ||
|
||||
R.cols() == 0 || R.rows() == 0 || P.cols() == 0 || P.rows() == 0) {
|
||||
return false;
|
||||
}
|
||||
x_ = x;
|
||||
A_ = A;
|
||||
B_ = B;
|
||||
C_ = C;
|
||||
Q_ = Q;
|
||||
R_ = R;
|
||||
P_ = P;
|
||||
return true;
|
||||
}
|
||||
bool KalmanFilter::init(const Eigen::MatrixXd & x, const Eigen::MatrixXd & P0)
|
||||
{
|
||||
if (x.cols() == 0 || x.rows() == 0 || P0.cols() == 0 || P0.rows() == 0) {
|
||||
return false;
|
||||
}
|
||||
x_ = x;
|
||||
P_ = P0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void KalmanFilter::setA(const Eigen::MatrixXd & A)
|
||||
{
|
||||
A_ = A;
|
||||
}
|
||||
void KalmanFilter::setB(const Eigen::MatrixXd & B)
|
||||
{
|
||||
B_ = B;
|
||||
}
|
||||
void KalmanFilter::setC(const Eigen::MatrixXd & C)
|
||||
{
|
||||
C_ = C;
|
||||
}
|
||||
void KalmanFilter::setQ(const Eigen::MatrixXd & Q)
|
||||
{
|
||||
Q_ = Q;
|
||||
}
|
||||
void KalmanFilter::setR(const Eigen::MatrixXd & R)
|
||||
{
|
||||
R_ = R;
|
||||
}
|
||||
void KalmanFilter::getX(Eigen::MatrixXd & x) const
|
||||
{
|
||||
x = x_;
|
||||
}
|
||||
void KalmanFilter::getP(Eigen::MatrixXd & P) const
|
||||
{
|
||||
P = P_;
|
||||
}
|
||||
double KalmanFilter::getXelement(unsigned int i) const
|
||||
{
|
||||
return x_(i);
|
||||
}
|
||||
|
||||
bool KalmanFilter::predict(
|
||||
const Eigen::MatrixXd & x_next, const Eigen::MatrixXd & A, const Eigen::MatrixXd & Q)
|
||||
{
|
||||
if (
|
||||
x_.rows() != x_next.rows() || A.cols() != P_.rows() || Q.cols() != Q.rows() ||
|
||||
A.rows() != Q.cols()) {
|
||||
return false;
|
||||
}
|
||||
x_ = x_next;
|
||||
P_ = A * P_ * A.transpose() + Q;
|
||||
return true;
|
||||
}
|
||||
bool KalmanFilter::predict(const Eigen::MatrixXd & x_next, const Eigen::MatrixXd & A)
|
||||
{
|
||||
return predict(x_next, A, Q_);
|
||||
}
|
||||
|
||||
bool KalmanFilter::predict(
|
||||
const Eigen::MatrixXd & u, const Eigen::MatrixXd & A, const Eigen::MatrixXd & B,
|
||||
const Eigen::MatrixXd & Q)
|
||||
{
|
||||
if (A.cols() != x_.rows() || B.cols() != u.rows()) {
|
||||
return false;
|
||||
}
|
||||
const Eigen::MatrixXd x_next = A * x_ + B * u;
|
||||
return predict(x_next, A, Q);
|
||||
}
|
||||
bool KalmanFilter::predict(const Eigen::MatrixXd & u)
|
||||
{
|
||||
return predict(u, A_, B_, Q_);
|
||||
}
|
||||
|
||||
bool KalmanFilter::update(
|
||||
const Eigen::MatrixXd & y, const Eigen::MatrixXd & y_pred, const Eigen::MatrixXd & C,
|
||||
const Eigen::MatrixXd & R)
|
||||
{
|
||||
if (
|
||||
P_.cols() != C.cols() || R.rows() != R.cols() || R.rows() != C.rows() ||
|
||||
y.rows() != y_pred.rows() || y.rows() != C.rows()) {
|
||||
return false;
|
||||
}
|
||||
const Eigen::MatrixXd PCT = P_ * C.transpose();
|
||||
const Eigen::MatrixXd K = PCT * ((R + C * PCT).inverse());
|
||||
|
||||
if (isnan(K.array()).any() || isinf(K.array()).any()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
x_ = x_ + K * (y - y_pred);
|
||||
P_ = P_ - K * (C * P_);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KalmanFilter::update(
|
||||
const Eigen::MatrixXd & y, const Eigen::MatrixXd & C, const Eigen::MatrixXd & R)
|
||||
{
|
||||
if (C.cols() != x_.rows()) {
|
||||
return false;
|
||||
}
|
||||
const Eigen::MatrixXd y_pred = C * x_;
|
||||
return update(y, y_pred, C, R);
|
||||
}
|
||||
bool KalmanFilter::update(const Eigen::MatrixXd & y)
|
||||
{
|
||||
return update(y, C_, R_);
|
||||
}
|
||||
} // namespace autoware::kalman_filter
|
||||
@@ -0,0 +1,107 @@
|
||||
// Copyright 2018-2019 Autoware Foundation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/kalman_filter/time_delay_kalman_filter.hpp"
|
||||
|
||||
namespace autoware::kalman_filter
|
||||
{
|
||||
TimeDelayKalmanFilter::TimeDelayKalmanFilter()
|
||||
{
|
||||
}
|
||||
|
||||
void TimeDelayKalmanFilter::init(
|
||||
const Eigen::MatrixXd & x, const Eigen::MatrixXd & P0, const int max_delay_step)
|
||||
{
|
||||
max_delay_step_ = max_delay_step;
|
||||
dim_x_ = x.rows();
|
||||
dim_x_ex_ = dim_x_ * max_delay_step;
|
||||
|
||||
x_ = Eigen::MatrixXd::Zero(dim_x_ex_, 1);
|
||||
P_ = Eigen::MatrixXd::Zero(dim_x_ex_, dim_x_ex_);
|
||||
|
||||
for (int i = 0; i < max_delay_step_; ++i) {
|
||||
x_.block(i * dim_x_, 0, dim_x_, 1) = x;
|
||||
P_.block(i * dim_x_, i * dim_x_, dim_x_, dim_x_) = P0;
|
||||
}
|
||||
}
|
||||
|
||||
Eigen::MatrixXd TimeDelayKalmanFilter::getLatestX() const
|
||||
{
|
||||
return x_.block(0, 0, dim_x_, 1);
|
||||
}
|
||||
|
||||
Eigen::MatrixXd TimeDelayKalmanFilter::getLatestP() const
|
||||
{
|
||||
return P_.block(0, 0, dim_x_, dim_x_);
|
||||
}
|
||||
|
||||
bool TimeDelayKalmanFilter::predictWithDelay(
|
||||
const Eigen::MatrixXd & x_next, const Eigen::MatrixXd & A, const Eigen::MatrixXd & Q)
|
||||
{
|
||||
/*
|
||||
* time delay model:
|
||||
*
|
||||
* [A 0 0] [P11 P12 P13] [Q 0 0]
|
||||
* A = [I 0 0], P = [P21 P22 P23], Q = [0 0 0]
|
||||
* [0 I 0] [P31 P32 P33] [0 0 0]
|
||||
*
|
||||
* covariance calculation in prediction : P = A * P * A' + Q
|
||||
*
|
||||
* [A*P11*A'*+Q A*P11 A*P12]
|
||||
* P = [ P11*A' P11 P12]
|
||||
* [ P21*A' P21 P22]
|
||||
*/
|
||||
|
||||
const int d_dim_x = dim_x_ex_ - dim_x_;
|
||||
|
||||
/* slide states in the time direction */
|
||||
Eigen::MatrixXd x_tmp = Eigen::MatrixXd::Zero(dim_x_ex_, 1);
|
||||
x_tmp.block(0, 0, dim_x_, 1) = x_next;
|
||||
x_tmp.block(dim_x_, 0, d_dim_x, 1) = x_.block(0, 0, d_dim_x, 1);
|
||||
x_ = x_tmp;
|
||||
|
||||
/* update P with delayed measurement A matrix structure */
|
||||
Eigen::MatrixXd P_tmp = Eigen::MatrixXd::Zero(dim_x_ex_, dim_x_ex_);
|
||||
P_tmp.block(0, 0, dim_x_, dim_x_) = A * P_.block(0, 0, dim_x_, dim_x_) * A.transpose() + Q;
|
||||
P_tmp.block(0, dim_x_, dim_x_, d_dim_x) = A * P_.block(0, 0, dim_x_, d_dim_x);
|
||||
P_tmp.block(dim_x_, 0, d_dim_x, dim_x_) = P_.block(0, 0, d_dim_x, dim_x_) * A.transpose();
|
||||
P_tmp.block(dim_x_, dim_x_, d_dim_x, d_dim_x) = P_.block(0, 0, d_dim_x, d_dim_x);
|
||||
P_ = P_tmp;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TimeDelayKalmanFilter::updateWithDelay(
|
||||
const Eigen::MatrixXd & y, const Eigen::MatrixXd & C, const Eigen::MatrixXd & R,
|
||||
const int delay_step)
|
||||
{
|
||||
if (delay_step >= max_delay_step_) {
|
||||
std::cerr << "delay step is larger than max_delay_step. ignore update." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
const int dim_y = y.rows();
|
||||
|
||||
/* set measurement matrix */
|
||||
Eigen::MatrixXd C_ex = Eigen::MatrixXd::Zero(dim_y, dim_x_ex_);
|
||||
C_ex.block(0, dim_x_ * delay_step, dim_y, dim_x_) = C;
|
||||
|
||||
/* update */
|
||||
if (!update(y, C_ex, R)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace autoware::kalman_filter
|
||||
@@ -0,0 +1,96 @@
|
||||
// Copyright 2023 The Autoware Foundation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/kalman_filter/kalman_filter.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using autoware::kalman_filter::KalmanFilter;
|
||||
|
||||
TEST(kalman_filter, kf)
|
||||
{
|
||||
KalmanFilter kf_;
|
||||
|
||||
Eigen::MatrixXd x_t(2, 1);
|
||||
x_t << 1, 2;
|
||||
|
||||
Eigen::MatrixXd P_t(2, 2);
|
||||
P_t << 1, 0, 0, 1;
|
||||
|
||||
Eigen::MatrixXd Q_t(2, 2);
|
||||
Q_t << 0.01, 0, 0, 0.01;
|
||||
|
||||
Eigen::MatrixXd R_t(2, 2);
|
||||
R_t << 0.09, 0, 0, 0.09;
|
||||
|
||||
Eigen::MatrixXd C_t(2, 2);
|
||||
C_t << 1, 0, 0, 1;
|
||||
|
||||
Eigen::MatrixXd A_t(2, 2);
|
||||
A_t << 1, 0, 0, 1;
|
||||
|
||||
Eigen::MatrixXd B_t(2, 2);
|
||||
B_t << 1, 0, 0, 1;
|
||||
|
||||
// Initialize the filter and check if initialization was successful
|
||||
EXPECT_TRUE(kf_.init(x_t, A_t, B_t, C_t, Q_t, R_t, P_t));
|
||||
|
||||
// Perform prediction
|
||||
Eigen::MatrixXd u_t(2, 1);
|
||||
u_t << 0.1, 0.1;
|
||||
EXPECT_TRUE(kf_.predict(u_t));
|
||||
|
||||
// Check the updated state and covariance matrix
|
||||
Eigen::MatrixXd x_predict_expected = A_t * x_t + B_t * u_t;
|
||||
Eigen::MatrixXd P_predict_expected = A_t * P_t * A_t.transpose() + Q_t;
|
||||
|
||||
Eigen::MatrixXd x_predict;
|
||||
kf_.getX(x_predict);
|
||||
Eigen::MatrixXd P_predict;
|
||||
kf_.getP(P_predict);
|
||||
|
||||
EXPECT_NEAR(x_predict(0, 0), x_predict_expected(0, 0), 1e-5);
|
||||
EXPECT_NEAR(x_predict(1, 0), x_predict_expected(1, 0), 1e-5);
|
||||
EXPECT_NEAR(P_predict(0, 0), P_predict_expected(0, 0), 1e-5);
|
||||
EXPECT_NEAR(P_predict(1, 1), P_predict_expected(1, 1), 1e-5);
|
||||
|
||||
// Perform update
|
||||
Eigen::MatrixXd y_t(2, 1);
|
||||
y_t << 1.05, 2.05;
|
||||
EXPECT_TRUE(kf_.update(y_t));
|
||||
|
||||
// Check the updated state and covariance matrix
|
||||
const Eigen::MatrixXd PCT_t = P_predict_expected * C_t.transpose();
|
||||
const Eigen::MatrixXd K_t = PCT_t * ((R_t + C_t * PCT_t).inverse());
|
||||
const Eigen::MatrixXd y_pred = C_t * x_predict_expected;
|
||||
Eigen::MatrixXd x_update_expected = x_predict_expected + K_t * (y_t - y_pred);
|
||||
Eigen::MatrixXd P_update_expected = P_predict_expected - K_t * (C_t * P_predict_expected);
|
||||
|
||||
Eigen::MatrixXd x_update;
|
||||
kf_.getX(x_update);
|
||||
Eigen::MatrixXd P_update;
|
||||
kf_.getP(P_update);
|
||||
|
||||
EXPECT_NEAR(x_update(0, 0), x_update_expected(0, 0), 1e-5);
|
||||
EXPECT_NEAR(x_update(1, 0), x_update_expected(1, 0), 1e-5);
|
||||
EXPECT_NEAR(P_update(0, 0), P_update_expected(0, 0), 1e-5);
|
||||
EXPECT_NEAR(P_update(1, 1), P_update_expected(1, 1), 1e-5);
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
bool result = RUN_ALL_TESTS();
|
||||
return result;
|
||||
}
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
// Copyright 2023 The Autoware Foundation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/kalman_filter/time_delay_kalman_filter.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using autoware::kalman_filter::TimeDelayKalmanFilter;
|
||||
|
||||
TEST(time_delay_kalman_filter, td_kf)
|
||||
{
|
||||
TimeDelayKalmanFilter td_kf_;
|
||||
|
||||
Eigen::MatrixXd x_t(3, 1);
|
||||
x_t << 1.0, 2.0, 3.0;
|
||||
Eigen::MatrixXd P_t(3, 3);
|
||||
P_t << 0.1, 0.0, 0.0, 0.0, 0.2, 0.0, 0.0, 0.0, 0.3;
|
||||
const int max_delay_step = 5;
|
||||
const int dim_x = x_t.rows();
|
||||
const int dim_x_ex = dim_x * max_delay_step;
|
||||
// Initialize the filter
|
||||
td_kf_.init(x_t, P_t, max_delay_step);
|
||||
|
||||
// Check if initialization was successful
|
||||
Eigen::MatrixXd x_init = td_kf_.getLatestX();
|
||||
Eigen::MatrixXd P_init = td_kf_.getLatestP();
|
||||
Eigen::MatrixXd x_ex_t = Eigen::MatrixXd::Zero(dim_x_ex, 1);
|
||||
Eigen::MatrixXd P_ex_t = Eigen::MatrixXd::Zero(dim_x_ex, dim_x_ex);
|
||||
for (int i = 0; i < max_delay_step; ++i) {
|
||||
x_ex_t.block(i * dim_x, 0, dim_x, 1) = x_t;
|
||||
P_ex_t.block(i * dim_x, i * dim_x, dim_x, dim_x) = P_t;
|
||||
}
|
||||
|
||||
EXPECT_EQ(x_init.rows(), 3);
|
||||
EXPECT_EQ(x_init.cols(), 1);
|
||||
EXPECT_EQ(P_init.rows(), 3);
|
||||
EXPECT_EQ(P_init.cols(), 3);
|
||||
EXPECT_NEAR(x_init(0, 0), x_t(0, 0), 1e-5);
|
||||
EXPECT_NEAR(x_init(1, 0), x_t(1, 0), 1e-5);
|
||||
EXPECT_NEAR(x_init(2, 0), x_t(2, 0), 1e-5);
|
||||
EXPECT_NEAR(P_init(0, 0), P_t(0, 0), 1e-5);
|
||||
EXPECT_NEAR(P_init(1, 1), P_t(1, 1), 1e-5);
|
||||
EXPECT_NEAR(P_init(2, 2), P_t(2, 2), 1e-5);
|
||||
|
||||
// Define prediction parameters
|
||||
Eigen::MatrixXd A_t(3, 3);
|
||||
A_t << 2.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 2.0;
|
||||
Eigen::MatrixXd Q_t(3, 3);
|
||||
Q_t << 0.01, 0.0, 0.0, 0.0, 0.02, 0.0, 0.0, 0.0, 0.03;
|
||||
Eigen::MatrixXd x_next(3, 1);
|
||||
x_next << 2.0, 4.0, 6.0;
|
||||
|
||||
// Perform prediction
|
||||
EXPECT_TRUE(td_kf_.predictWithDelay(x_next, A_t, Q_t));
|
||||
|
||||
// Check the prediction state and covariance matrix
|
||||
Eigen::MatrixXd x_predict = td_kf_.getLatestX();
|
||||
Eigen::MatrixXd P_predict = td_kf_.getLatestP();
|
||||
Eigen::MatrixXd x_tmp = Eigen::MatrixXd::Zero(dim_x_ex, 1);
|
||||
x_tmp.block(0, 0, dim_x, 1) = A_t * x_t;
|
||||
x_tmp.block(dim_x, 0, dim_x_ex - dim_x, 1) = x_ex_t.block(0, 0, dim_x_ex - dim_x, 1);
|
||||
x_ex_t = x_tmp;
|
||||
Eigen::MatrixXd x_predict_expected = x_ex_t.block(0, 0, dim_x, 1);
|
||||
Eigen::MatrixXd P_tmp = Eigen::MatrixXd::Zero(dim_x_ex, dim_x_ex);
|
||||
P_tmp.block(0, 0, dim_x, dim_x) = A_t * P_ex_t.block(0, 0, dim_x, dim_x) * A_t.transpose() + Q_t;
|
||||
P_tmp.block(0, dim_x, dim_x, dim_x_ex - dim_x) =
|
||||
A_t * P_ex_t.block(0, 0, dim_x, dim_x_ex - dim_x);
|
||||
P_tmp.block(dim_x, 0, dim_x_ex - dim_x, dim_x) =
|
||||
P_ex_t.block(0, 0, dim_x_ex - dim_x, dim_x) * A_t.transpose();
|
||||
P_tmp.block(dim_x, dim_x, dim_x_ex - dim_x, dim_x_ex - dim_x) =
|
||||
P_ex_t.block(0, 0, dim_x_ex - dim_x, dim_x_ex - dim_x);
|
||||
P_ex_t = P_tmp;
|
||||
Eigen::MatrixXd P_predict_expected = P_ex_t.block(0, 0, dim_x, dim_x);
|
||||
EXPECT_NEAR(x_predict(0, 0), x_predict_expected(0, 0), 1e-5);
|
||||
EXPECT_NEAR(x_predict(1, 0), x_predict_expected(1, 0), 1e-5);
|
||||
EXPECT_NEAR(x_predict(2, 0), x_predict_expected(2, 0), 1e-5);
|
||||
EXPECT_NEAR(P_predict(0, 0), P_predict_expected(0, 0), 1e-5);
|
||||
EXPECT_NEAR(P_predict(1, 1), P_predict_expected(1, 1), 1e-5);
|
||||
EXPECT_NEAR(P_predict(2, 2), P_predict_expected(2, 2), 1e-5);
|
||||
|
||||
// Define update parameters
|
||||
Eigen::MatrixXd C_t(3, 3);
|
||||
C_t << 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5;
|
||||
Eigen::MatrixXd R_t(3, 3);
|
||||
R_t << 0.001, 0.0, 0.0, 0.0, 0.002, 0.0, 0.0, 0.0, 0.003;
|
||||
Eigen::MatrixXd y_t(3, 1);
|
||||
y_t << 1.05, 2.05, 3.05;
|
||||
const int delay_step = 2; // Choose an appropriate delay step
|
||||
const int dim_y = y_t.rows();
|
||||
|
||||
// Perform update
|
||||
EXPECT_TRUE(td_kf_.updateWithDelay(y_t, C_t, R_t, delay_step));
|
||||
|
||||
// Check the updated state and covariance matrix
|
||||
Eigen::MatrixXd x_update = td_kf_.getLatestX();
|
||||
Eigen::MatrixXd P_update = td_kf_.getLatestP();
|
||||
|
||||
Eigen::MatrixXd C_ex_t = Eigen::MatrixXd::Zero(dim_y, dim_x_ex);
|
||||
const Eigen::MatrixXd PCT_t = P_ex_t * C_ex_t.transpose();
|
||||
const Eigen::MatrixXd K_t = PCT_t * ((R_t + C_ex_t * PCT_t).inverse());
|
||||
const Eigen::MatrixXd y_pred = C_ex_t * x_ex_t;
|
||||
x_ex_t = x_ex_t + K_t * (y_t - y_pred);
|
||||
P_ex_t = P_ex_t - K_t * (C_ex_t * P_ex_t);
|
||||
Eigen::MatrixXd x_update_expected = x_ex_t.block(0, 0, dim_x, 1);
|
||||
Eigen::MatrixXd P_update_expected = P_ex_t.block(0, 0, dim_x, dim_x);
|
||||
EXPECT_NEAR(x_update(0, 0), x_update_expected(0, 0), 1e-5);
|
||||
EXPECT_NEAR(x_update(1, 0), x_update_expected(1, 0), 1e-5);
|
||||
EXPECT_NEAR(x_update(2, 0), x_update_expected(2, 0), 1e-5);
|
||||
EXPECT_NEAR(P_update(0, 0), P_update_expected(0, 0), 1e-5);
|
||||
EXPECT_NEAR(P_update(1, 1), P_update_expected(1, 1), 1e-5);
|
||||
EXPECT_NEAR(P_update(2, 2), P_update_expected(2, 2), 1e-5);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(autoware_motion_utils)
|
||||
|
||||
option(BUILD_EXAMPLES "Build examples" OFF)
|
||||
|
||||
find_package(autoware_cmake REQUIRED)
|
||||
autoware_package()
|
||||
|
||||
find_package(Boost REQUIRED)
|
||||
|
||||
ament_auto_add_library(autoware_motion_utils SHARED
|
||||
DIRECTORY src
|
||||
)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
find_package(ament_cmake_ros REQUIRED)
|
||||
|
||||
file(GLOB_RECURSE test_files test/**/*.cpp)
|
||||
|
||||
ament_add_ros_isolated_gtest(test_autoware_motion_utils ${test_files})
|
||||
|
||||
target_link_libraries(test_autoware_motion_utils
|
||||
autoware_motion_utils
|
||||
)
|
||||
endif()
|
||||
|
||||
if(BUILD_EXAMPLES)
|
||||
message(STATUS "Building examples")
|
||||
|
||||
include(FetchContent)
|
||||
fetchcontent_declare(
|
||||
matplotlibcpp17
|
||||
GIT_REPOSITORY https://github.com/soblin/matplotlibcpp17.git
|
||||
GIT_TAG master
|
||||
)
|
||||
fetchcontent_makeavailable(matplotlibcpp17)
|
||||
|
||||
file(GLOB_RECURSE example_files examples/*.cpp)
|
||||
|
||||
foreach(example_file ${example_files})
|
||||
get_filename_component(example_name ${example_file} NAME_WE)
|
||||
ament_auto_add_executable(${example_name} ${example_file})
|
||||
set_source_files_properties(${example_file} PROPERTIES COMPILE_FLAGS -Wno-error -Wno-attributes -Wno-unused-parameter)
|
||||
target_link_libraries(${example_name}
|
||||
autoware_motion_utils
|
||||
matplotlibcpp17::matplotlibcpp17
|
||||
)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
ament_auto_package()
|
||||
@@ -0,0 +1,104 @@
|
||||
# Motion Utils package
|
||||
|
||||
## Definition of terms
|
||||
|
||||
### Segment
|
||||
|
||||
`Segment` in Autoware is the line segment between two successive points as follows.
|
||||
|
||||
{: style="width:600px"}
|
||||
|
||||
The nearest segment index and nearest point index to a certain position is not always th same.
|
||||
Therefore, we prepare two different utility functions to calculate a nearest index for points and segments.
|
||||
|
||||
## Nearest index search
|
||||
|
||||
In this section, the nearest index and nearest segment index search is explained.
|
||||
|
||||
We have the same functions for the nearest index search and nearest segment index search.
|
||||
Taking for the example the nearest index search, we have two types of functions.
|
||||
|
||||
The first function finds the nearest index with distance and yaw thresholds.
|
||||
|
||||
```cpp
|
||||
template <class T>
|
||||
size_t findFirstNearestIndexWithSoftConstraints(
|
||||
const T & points, const geometry_msgs::msg::Pose & pose,
|
||||
const double dist_threshold = std::numeric_limits<double>::max(),
|
||||
const double yaw_threshold = std::numeric_limits<double>::max());
|
||||
```
|
||||
|
||||
This function finds the first local solution within thresholds.
|
||||
The reason to find the first local one is to deal with some edge cases explained in the next subsection.
|
||||
|
||||
There are default parameters for thresholds arguments so that you can decide which thresholds to pass to the function.
|
||||
|
||||
1. When both the distance and yaw thresholds are given.
|
||||
- First, try to find the nearest index with both the distance and yaw thresholds.
|
||||
- If not found, try to find again with only the distance threshold.
|
||||
- If not found, find without any thresholds.
|
||||
2. When only distance are given.
|
||||
- First, try to find the nearest index the distance threshold.
|
||||
- If not found, find without any thresholds.
|
||||
3. When no thresholds are given.
|
||||
- Find the nearest index.
|
||||
|
||||
The second function finds the nearest index in the lane whose id is `lane_id`.
|
||||
|
||||
```cpp
|
||||
size_t findNearestIndexFromLaneId(
|
||||
const tier4_planning_msgs::msg::PathWithLaneId & path,
|
||||
const geometry_msgs::msg::Point & pos, const int64_t lane_id);
|
||||
```
|
||||
|
||||
### Application to various object
|
||||
|
||||
Many node packages often calculate the nearest index of objects.
|
||||
We will explain the recommended method to calculate it.
|
||||
|
||||
#### Nearest index for the ego
|
||||
|
||||
Assuming that the path length before the ego is short enough, we expect to find the correct nearest index in the following edge cases by `findFirstNearestIndexWithSoftConstraints` with both distance and yaw thresholds.
|
||||
Blue circles describes the distance threshold from the base link position and two blue lines describe the yaw threshold against the base link orientation.
|
||||
Among points in these cases, the correct nearest point which is red can be found.
|
||||
|
||||

|
||||
|
||||
Therefore, the implementation is as follows.
|
||||
|
||||
```cpp
|
||||
const size_t ego_nearest_idx = findFirstNearestIndexWithSoftConstraints(points, ego_pose, ego_nearest_dist_threshold, ego_nearest_yaw_threshold);
|
||||
const size_t ego_nearest_seg_idx = findFirstNearestIndexWithSoftConstraints(points, ego_pose, ego_nearest_dist_threshold, ego_nearest_yaw_threshold);
|
||||
```
|
||||
|
||||
#### Nearest index for dynamic objects
|
||||
|
||||
For the ego nearest index, the orientation is considered in addition to the position since the ego is supposed to follow the points.
|
||||
However, for the dynamic objects (e.g., predicted object), sometimes its orientation may be different from the points order, e.g. the dynamic object driving backward although the ego is driving forward.
|
||||
|
||||
Therefore, the yaw threshold should not be considered for the dynamic object.
|
||||
The implementation is as follows.
|
||||
|
||||
```cpp
|
||||
const size_t dynamic_obj_nearest_idx = findFirstNearestIndexWithSoftConstraints(points, dynamic_obj_pose, dynamic_obj_nearest_dist_threshold);
|
||||
const size_t dynamic_obj_nearest_seg_idx = findFirstNearestIndexWithSoftConstraints(points, dynamic_obj_pose, dynamic_obj_nearest_dist_threshold);
|
||||
```
|
||||
|
||||
#### Nearest index for traffic objects
|
||||
|
||||
In lanelet maps, traffic objects belong to the specific lane.
|
||||
With this specific lane's id, the correct nearest index can be found.
|
||||
|
||||
The implementation is as follows.
|
||||
|
||||
```cpp
|
||||
// first extract `lane_id` which the traffic object belong to.
|
||||
const size_t traffic_obj_nearest_idx = findNearestIndexFromLaneId(path_with_lane_id, traffic_obj_pos, lane_id);
|
||||
const size_t traffic_obj_nearest_seg_idx = findNearestSegmentIndexFromLaneId(path_with_lane_id, traffic_obj_pos, lane_id);
|
||||
```
|
||||
|
||||
## For developers
|
||||
|
||||
Some of the template functions in `trajectory.hpp` are mostly used for specific types (`autoware_planning_msgs::msg::PathPoint`, `autoware_planning_msgs::msg::PathPoint`, `autoware_planning_msgs::msg::TrajectoryPoint`), so they are exported as `extern template` functions to speed-up compilation time.
|
||||
|
||||
`autoware_motion_utils.hpp` header file was removed because the source files that directly/indirectly include this file took a long time for preprocessing.
|
||||
@@ -0,0 +1,169 @@
|
||||
# vehicle utils
|
||||
|
||||
Vehicle utils provides a convenient library used to check vehicle status.
|
||||
|
||||
## Feature
|
||||
|
||||
The library contains following classes.
|
||||
|
||||
### vehicle_stop_checker
|
||||
|
||||
This class check whether the vehicle is stopped or not based on localization result.
|
||||
|
||||
#### Subscribed Topics
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------------------------------- | ------------------------- | ---------------- |
|
||||
| `/localization/kinematic_state` | `nav_msgs::msg::Odometry` | vehicle odometry |
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Default Value | Explanation |
|
||||
| -------------------------- | ------ | ------------- | --------------------------- |
|
||||
| `velocity_buffer_time_sec` | double | 10.0 | odometry buffering time [s] |
|
||||
|
||||
#### Member functions
|
||||
|
||||
```c++
|
||||
bool isVehicleStopped(const double stop_duration)
|
||||
```
|
||||
|
||||
- Check simply whether the vehicle is stopped based on the localization result.
|
||||
- Returns `true` if the vehicle is stopped, even if system outputs a non-zero target velocity.
|
||||
|
||||
#### Example Usage
|
||||
|
||||
Necessary includes:
|
||||
|
||||
```c++
|
||||
#include <autoware/universe_utils/vehicle/vehicle_state_checker.hpp>
|
||||
```
|
||||
|
||||
1.Create a checker instance.
|
||||
|
||||
```c++
|
||||
class SampleNode : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
SampleNode() : Node("sample_node")
|
||||
{
|
||||
vehicle_stop_checker_ = std::make_unique<VehicleStopChecker>(this);
|
||||
}
|
||||
|
||||
std::unique_ptr<VehicleStopChecker> vehicle_stop_checker_;
|
||||
|
||||
bool sampleFunc();
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
2.Check the vehicle state.
|
||||
|
||||
```c++
|
||||
|
||||
bool SampleNode::sampleFunc()
|
||||
{
|
||||
...
|
||||
|
||||
const auto result_1 = vehicle_stop_checker_->isVehicleStopped();
|
||||
|
||||
...
|
||||
|
||||
const auto result_2 = vehicle_stop_checker_->isVehicleStopped(3.0);
|
||||
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### vehicle_arrival_checker
|
||||
|
||||
This class check whether the vehicle arrive at stop point based on localization and planning result.
|
||||
|
||||
#### Subscribed Topics
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---------------------------------------- | ----------------------------------------- | ---------------- |
|
||||
| `/localization/kinematic_state` | `nav_msgs::msg::Odometry` | vehicle odometry |
|
||||
| `/planning/scenario_planning/trajectory` | `autoware_planning_msgs::msg::Trajectory` | trajectory |
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Default Value | Explanation |
|
||||
| -------------------------- | ------ | ------------- | ---------------------------------------------------------------------- |
|
||||
| `velocity_buffer_time_sec` | double | 10.0 | odometry buffering time [s] |
|
||||
| `th_arrived_distance_m` | double | 1.0 | threshold distance to check if vehicle has arrived at target point [m] |
|
||||
|
||||
#### Member functions
|
||||
|
||||
```c++
|
||||
bool isVehicleStopped(const double stop_duration)
|
||||
```
|
||||
|
||||
- Check simply whether the vehicle is stopped based on the localization result.
|
||||
- Returns `true` if the vehicle is stopped, even if system outputs a non-zero target velocity.
|
||||
|
||||
```c++
|
||||
bool isVehicleStoppedAtStopPoint(const double stop_duration)
|
||||
```
|
||||
|
||||
- Check whether the vehicle is stopped at stop point based on the localization and planning result.
|
||||
- Returns `true` if the vehicle is not only stopped but also arrived at stop point.
|
||||
|
||||
#### Example Usage
|
||||
|
||||
Necessary includes:
|
||||
|
||||
```c++
|
||||
#include <autoware/universe_utils/vehicle/vehicle_state_checker.hpp>
|
||||
```
|
||||
|
||||
1.Create a checker instance.
|
||||
|
||||
```c++
|
||||
class SampleNode : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
SampleNode() : Node("sample_node")
|
||||
{
|
||||
vehicle_arrival_checker_ = std::make_unique<VehicleArrivalChecker>(this);
|
||||
}
|
||||
|
||||
std::unique_ptr<VehicleArrivalChecker> vehicle_arrival_checker_;
|
||||
|
||||
bool sampleFunc();
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
2.Check the vehicle state.
|
||||
|
||||
```c++
|
||||
|
||||
bool SampleNode::sampleFunc()
|
||||
{
|
||||
...
|
||||
|
||||
const auto result_1 = vehicle_arrival_checker_->isVehicleStopped();
|
||||
|
||||
...
|
||||
|
||||
const auto result_2 = vehicle_arrival_checker_->isVehicleStopped(3.0);
|
||||
|
||||
...
|
||||
|
||||
const auto result_3 = vehicle_arrival_checker_->isVehicleStoppedAtStopPoint();
|
||||
|
||||
...
|
||||
|
||||
const auto result_4 = vehicle_arrival_checker_->isVehicleStoppedAtStopPoint(3.0);
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## Assumptions / Known limits
|
||||
|
||||
`vehicle_stop_checker` and `vehicle_arrival_checker` cannot check whether the vehicle is stopped more than `velocity_buffer_time_sec` second.
|
||||
@@ -0,0 +1,116 @@
|
||||
// Copyright 2024 Tier IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "autoware/motion_utils/trajectory_container/interpolator/akima_spline.hpp"
|
||||
#include "autoware/motion_utils/trajectory_container/interpolator/cubic_spline.hpp"
|
||||
#include "autoware/motion_utils/trajectory_container/interpolator/interpolator.hpp"
|
||||
#include "autoware/motion_utils/trajectory_container/interpolator/linear.hpp"
|
||||
#include "autoware/motion_utils/trajectory_container/interpolator/nearest_neighbor.hpp"
|
||||
|
||||
#include <autoware/motion_utils/trajectory_container/interpolator.hpp>
|
||||
|
||||
#include <matplotlibcpp17/pyplot.h>
|
||||
|
||||
#include <random>
|
||||
#include <vector>
|
||||
|
||||
int main()
|
||||
{
|
||||
pybind11::scoped_interpreter guard{};
|
||||
auto plt = matplotlibcpp17::pyplot::import();
|
||||
|
||||
// create random values
|
||||
std::vector<double> bases = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0};
|
||||
std::vector<double> values;
|
||||
std::random_device seed_gen;
|
||||
std::mt19937 engine(seed_gen());
|
||||
std::uniform_real_distribution<> dist(-1.0, 1.0);
|
||||
for (size_t i = 0; i < bases.size(); ++i) {
|
||||
values.push_back(dist(engine));
|
||||
}
|
||||
// Scatter Data
|
||||
plt.scatter(Args(bases, values));
|
||||
|
||||
using autoware::motion_utils::trajectory_container::interpolator::InterpolatorInterface;
|
||||
// Linear Interpolator
|
||||
{
|
||||
using autoware::motion_utils::trajectory_container::interpolator::Linear;
|
||||
auto interpolator = *Linear::Builder{}.set_bases(bases).set_values(values).build();
|
||||
std::vector<double> x;
|
||||
std::vector<double> y;
|
||||
for (double i = bases.front(); i < bases.back(); i += 0.01) {
|
||||
x.push_back(i);
|
||||
y.push_back(interpolator.compute(i));
|
||||
}
|
||||
plt.plot(Args(x, y), Kwargs("label"_a = "Linear"));
|
||||
}
|
||||
|
||||
// AkimaSpline Interpolator
|
||||
{
|
||||
using autoware::motion_utils::trajectory_container::interpolator::AkimaSpline;
|
||||
|
||||
auto interpolator = *AkimaSpline::Builder{}.set_bases(bases).set_values(values).build();
|
||||
std::vector<double> x;
|
||||
std::vector<double> y;
|
||||
for (double i = bases.front(); i < bases.back(); i += 0.01) {
|
||||
x.push_back(i);
|
||||
y.push_back(interpolator.compute(i));
|
||||
}
|
||||
plt.plot(Args(x, y), Kwargs("label"_a = "AkimaSpline"));
|
||||
}
|
||||
|
||||
// CubicSpline Interpolator
|
||||
{
|
||||
using autoware::motion_utils::trajectory_container::interpolator::CubicSpline;
|
||||
auto interpolator = *CubicSpline::Builder{}.set_bases(bases).set_values(values).build();
|
||||
std::vector<double> x;
|
||||
std::vector<double> y;
|
||||
for (double i = bases.front(); i < bases.back(); i += 0.01) {
|
||||
x.push_back(i);
|
||||
y.push_back(interpolator.compute(i));
|
||||
}
|
||||
plt.plot(Args(x, y), Kwargs("label"_a = "CubicSpline"));
|
||||
}
|
||||
|
||||
// NearestNeighbor Interpolator
|
||||
{
|
||||
using autoware::motion_utils::trajectory_container::interpolator::NearestNeighbor;
|
||||
auto interpolator =
|
||||
*NearestNeighbor<double>::Builder{}.set_bases(bases).set_values(values).build();
|
||||
std::vector<double> x;
|
||||
std::vector<double> y;
|
||||
for (double i = bases.front(); i < bases.back(); i += 0.01) {
|
||||
x.push_back(i);
|
||||
y.push_back(interpolator.compute(i));
|
||||
}
|
||||
plt.plot(Args(x, y), Kwargs("label"_a = "NearestNeighbor"));
|
||||
}
|
||||
|
||||
// Stairstep Interpolator
|
||||
{
|
||||
using autoware::motion_utils::trajectory_container::interpolator::Stairstep;
|
||||
auto interpolator = *Stairstep<double>::Builder{}.set_bases(bases).set_values(values).build();
|
||||
std::vector<double> x;
|
||||
std::vector<double> y;
|
||||
for (double i = bases.front(); i < bases.back(); i += 0.01) {
|
||||
x.push_back(i);
|
||||
y.push_back(interpolator.compute(i));
|
||||
}
|
||||
plt.plot(Args(x, y), Kwargs("label"_a = "Stairstep"));
|
||||
}
|
||||
|
||||
plt.legend();
|
||||
plt.show();
|
||||
return 0;
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// Copyright 2022 TIER IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef AUTOWARE__MOTION_UTILS__CONSTANTS_HPP_
|
||||
#define AUTOWARE__MOTION_UTILS__CONSTANTS_HPP_
|
||||
|
||||
namespace autoware::motion_utils
|
||||
{
|
||||
constexpr double overlap_threshold = 0.1;
|
||||
} // namespace autoware::motion_utils
|
||||
|
||||
#endif // AUTOWARE__MOTION_UTILS__CONSTANTS_HPP_
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
// Copyright 2023 TIER IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef AUTOWARE__MOTION_UTILS__DISTANCE__DISTANCE_HPP_
|
||||
#define AUTOWARE__MOTION_UTILS__DISTANCE__DISTANCE_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
namespace autoware::motion_utils
|
||||
{
|
||||
std::optional<double> calcDecelDistWithJerkAndAccConstraints(
|
||||
const double current_vel, const double target_vel, const double current_acc, const double acc_min,
|
||||
const double jerk_acc, const double jerk_dec);
|
||||
|
||||
} // namespace autoware::motion_utils
|
||||
|
||||
#endif // AUTOWARE__MOTION_UTILS__DISTANCE__DISTANCE_HPP_
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
|
||||
// Copyright 2022-2024 TIER IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef AUTOWARE__MOTION_UTILS__FACTOR__VELOCITY_FACTOR_INTERFACE_HPP_
|
||||
#define AUTOWARE__MOTION_UTILS__FACTOR__VELOCITY_FACTOR_INTERFACE_HPP_
|
||||
|
||||
#include <autoware_adapi_v1_msgs/msg/planning_behavior.hpp>
|
||||
#include <autoware_adapi_v1_msgs/msg/velocity_factor.hpp>
|
||||
#include <autoware_adapi_v1_msgs/msg/velocity_factor_array.hpp>
|
||||
#include <geometry_msgs/msg/pose.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace autoware::motion_utils
|
||||
{
|
||||
using autoware_adapi_v1_msgs::msg::PlanningBehavior;
|
||||
using autoware_adapi_v1_msgs::msg::VelocityFactor;
|
||||
using VelocityFactorBehavior = VelocityFactor::_behavior_type;
|
||||
using VelocityFactorStatus = VelocityFactor::_status_type;
|
||||
using geometry_msgs::msg::Pose;
|
||||
|
||||
class VelocityFactorInterface
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] VelocityFactor get() const { return velocity_factor_; }
|
||||
void init(const VelocityFactorBehavior & behavior) { behavior_ = behavior; }
|
||||
void reset() { velocity_factor_.behavior = PlanningBehavior::UNKNOWN; }
|
||||
|
||||
template <class PointType>
|
||||
void set(
|
||||
const std::vector<PointType> & points, const Pose & curr_pose, const Pose & stop_pose,
|
||||
const VelocityFactorStatus status, const std::string & detail = "");
|
||||
|
||||
private:
|
||||
VelocityFactorBehavior behavior_{VelocityFactor::UNKNOWN};
|
||||
VelocityFactor velocity_factor_{};
|
||||
};
|
||||
|
||||
} // namespace autoware::motion_utils
|
||||
|
||||
#endif // AUTOWARE__MOTION_UTILS__FACTOR__VELOCITY_FACTOR_INTERFACE_HPP_
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
// Copyright 2021 Tier IV, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef AUTOWARE__MOTION_UTILS__MARKER__MARKER_HELPER_HPP_
|
||||
#define AUTOWARE__MOTION_UTILS__MARKER__MARKER_HELPER_HPP_
|
||||
|
||||
#include <rclcpp/time.hpp>
|
||||
|
||||
#include <visualization_msgs/msg/marker_array.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace autoware::motion_utils
|
||||
{
|
||||
using geometry_msgs::msg::Pose;
|
||||
|
||||
visualization_msgs::msg::MarkerArray createStopVirtualWallMarker(
|
||||
const Pose & pose, const std::string & module_name, const rclcpp::Time & now, const int32_t id,
|
||||
const double longitudinal_offset = 0.0, const std::string & ns_prefix = "",
|
||||
const bool is_driving_forward = true);
|
||||
|
||||
visualization_msgs::msg::MarkerArray createSlowDownVirtualWallMarker(
|
||||
const Pose & pose, const std::string & module_name, const rclcpp::Time & now, const int32_t id,
|
||||
const double longitudinal_offset = 0.0, const std::string & ns_prefix = "",
|
||||
const bool is_driving_forward = true);
|
||||
|
||||
visualization_msgs::msg::MarkerArray createDeadLineVirtualWallMarker(
|
||||
const Pose & pose, const std::string & module_name, const rclcpp::Time & now, const int32_t id,
|
||||
const double longitudinal_offset = 0.0, const std::string & ns_prefix = "",
|
||||
const bool is_driving_forward = true);
|
||||
|
||||
visualization_msgs::msg::MarkerArray createDeletedStopVirtualWallMarker(
|
||||
const rclcpp::Time & now, const int32_t id);
|
||||
|
||||
visualization_msgs::msg::MarkerArray createDeletedSlowDownVirtualWallMarker(
|
||||
const rclcpp::Time & now, const int32_t id);
|
||||
} // namespace autoware::motion_utils
|
||||
|
||||
#endif // AUTOWARE__MOTION_UTILS__MARKER__MARKER_HELPER_HPP_
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user