Skip to content

Commit da8722f

Browse files
authored
Refactor/reference filter dp (#687)
* refactor package structure * waypoint follower class * time step param * use vortex types, moved initial state function * pose as reference api type. Renamed variables * added reference filter ros utils * added mutex to WaypointFollower * move waypoint mode ownership to WaypointFollower * removed measured_pose_vector6 function * clean up step result handling * renamed filter variable from 'x' to state * update documentation * fixed action concurrency issues * join thread in destructor * separate step and convergance check * added local using for ssa util function * added lambdas * comment out unused function args
1 parent d53f2b8 commit da8722f

20 files changed

Lines changed: 1062 additions & 591 deletions

guidance/reference_filter_dp/CMakeLists.txt

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,36 +24,57 @@ find_package(fmt REQUIRED)
2424

2525
include_directories(include)
2626

27-
set(LIB_NAME "${PROJECT_NAME}_component")
27+
set(CORE_LIB_NAME "${PROJECT_NAME}")
2828

29-
add_library(${LIB_NAME} SHARED
30-
src/reference_filter.cpp
31-
src/reference_filter_ros.cpp)
29+
add_library(${CORE_LIB_NAME} SHARED
30+
src/lib/reference_filter.cpp
31+
src/lib/waypoint_utils.cpp
32+
src/lib/waypoint_follower.cpp
33+
)
34+
35+
target_include_directories(${CORE_LIB_NAME}
36+
PUBLIC
37+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
38+
$<INSTALL_INTERFACE:include>
39+
)
40+
41+
ament_target_dependencies(${CORE_LIB_NAME}
42+
Eigen3
43+
vortex_utils
44+
)
45+
46+
set(COMPONENT_LIB_NAME "${PROJECT_NAME}_component")
47+
48+
add_library(${COMPONENT_LIB_NAME} SHARED
49+
src/ros/reference_filter_ros.cpp
50+
)
3251

33-
ament_target_dependencies(${LIB_NAME} PUBLIC
52+
ament_target_dependencies(${COMPONENT_LIB_NAME}
3453
rclcpp
3554
rclcpp_components
3655
rclcpp_action
3756
geometry_msgs
3857
nav_msgs
39-
Eigen3
4058
vortex_msgs
4159
vortex_utils
4260
vortex_utils_ros
4361
spdlog
4462
fmt
4563
)
4664

65+
target_link_libraries(${COMPONENT_LIB_NAME} ${CORE_LIB_NAME})
66+
4767
rclcpp_components_register_node(
48-
${LIB_NAME}
68+
${COMPONENT_LIB_NAME}
4969
PLUGIN "ReferenceFilterNode"
5070
EXECUTABLE ${PROJECT_NAME}_node
5171
)
5272

53-
ament_export_targets(export_${LIB_NAME})
54-
55-
install(TARGETS ${LIB_NAME}
56-
EXPORT export_${LIB_NAME}
73+
install(
74+
TARGETS
75+
${CORE_LIB_NAME}
76+
${COMPONENT_LIB_NAME}
77+
EXPORT export_${PROJECT_NAME}
5778
ARCHIVE DESTINATION lib
5879
LIBRARY DESTINATION lib
5980
RUNTIME DESTINATION bin
@@ -70,6 +91,14 @@ install(DIRECTORY
7091
DESTINATION share/${PROJECT_NAME}/
7192
)
7293

94+
ament_export_targets(export_${PROJECT_NAME} HAS_LIBRARY_TARGET)
95+
ament_export_dependencies(
96+
Eigen3
97+
vortex_utils
98+
)
99+
ament_export_include_directories(include)
100+
ament_export_libraries(${CORE_LIB_NAME})
101+
73102
if(BUILD_TESTING)
74103
add_subdirectory(test)
75104
endif()

guidance/reference_filter_dp/README.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,28 @@ The state at the next time step is calculated using forward Euler integration
3333
x_{i+1} = x_i + \dot{x}_i * dt
3434
```
3535

36+
## Waypoint modes
37+
38+
Each waypoint has a mode that determines which degrees of freedom are controlled by the reference filter. The mode also determines how convergence is measured.
39+
40+
| Mode | Controlled DOFs | Convergence metric |
41+
|---|---|---|
42+
| `FULL_POSE` | All 6 DOF (position + orientation) | Euclidean norm of position and angle errors |
43+
| `ONLY_POSITION` | x, y, z (orientation holds current value) | Euclidean norm of position error |
44+
| `FORWARD_HEADING` | x, y, z + yaw toward target (roll/pitch = 0) | Euclidean norm of position error and yaw error |
45+
| `ONLY_ORIENTATION` | roll, pitch, yaw (position holds current value) | Euclidean norm of angle errors |
46+
47+
For all modes, convergence is reached when the error metric drops below the `convergence_threshold` specified in the action goal.
48+
3649
## Action Server
37-
The action server is responsible for handling goal requests and publishing guidance commands. The server will always prioritize new goal request, and will abort ongoing request when getting a new request. The action definition can be found [here](https://github.com/vortexntnu/vortex-msgs/blob/main/action/ReferenceFilterWaypoint.action).
50+
51+
The action server is responsible for handling goal requests and publishing guidance commands. The server will always prioritize new goal requests, and will abort ongoing requests when getting a new request. The action definition can be found [here](https://github.com/vortexntnu/vortex-msgs/blob/main/action/ReferenceFilterWaypoint.action).
3852

3953
- Action name: /reference_filter
4054
- Goal type: PoseStamped
4155
- Result type: bool
4256
- Guidance topic: /dp/reference
57+
58+
### Overwriting the reference during an action
59+
60+
While an action is executing, the reference goal can be updated at any time by publishing a `geometry_msgs/msg/PoseStamped` to the reference pose topic. This allows external nodes to adjust the target pose mid-action without canceling and resending the goal. The convergence check will use the updated reference, so the action completes when the vehicle reaches the latest reference.

guidance/reference_filter_dp/config/reference_filter_params.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
ros__parameters:
33
zeta: [1., 1., 1., 1., 1., 1.]
44
omega: [0.2, 0.2, 0.2, 0.2, 0.2, 0.2]
5+
time_step_ms: 10

guidance/reference_filter_dp/include/reference_filter_dp/eigen_typedefs.hpp renamed to guidance/reference_filter_dp/include/reference_filter_dp/lib/eigen_typedefs.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
* @brief Contains Eigen typedefs used in this package.
44
*/
55

6-
#ifndef REFERENCE_FILTER_DP__EIGEN_TYPEDEFS_HPP_
7-
#define REFERENCE_FILTER_DP__EIGEN_TYPEDEFS_HPP_
6+
#ifndef REFERENCE_FILTER_DP__LIB__EIGEN_TYPEDEFS_HPP_
7+
#define REFERENCE_FILTER_DP__LIB__EIGEN_TYPEDEFS_HPP_
88

99
#include <eigen3/Eigen/Dense>
1010

@@ -18,4 +18,4 @@ typedef Eigen::Matrix<double, 18, 1> Vector18d;
1818

1919
} // namespace Eigen
2020

21-
#endif // REFERENCE_FILTER_DP__EIGEN_TYPEDEFS_HPP_
21+
#endif // REFERENCE_FILTER_DP__LIB__EIGEN_TYPEDEFS_HPP_

guidance/reference_filter_dp/include/reference_filter_dp/reference_filter.hpp renamed to guidance/reference_filter_dp/include/reference_filter_dp/lib/reference_filter.hpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
#ifndef REFERENCE_FILTER_DP__REFERENCE_FILTER_HPP_
2-
#define REFERENCE_FILTER_DP__REFERENCE_FILTER_HPP_
1+
#ifndef REFERENCE_FILTER_DP__LIB__REFERENCE_FILTER_HPP_
2+
#define REFERENCE_FILTER_DP__LIB__REFERENCE_FILTER_HPP_
33

4-
#include "reference_filter_dp/eigen_typedefs.hpp"
4+
#include "reference_filter_dp/lib/eigen_typedefs.hpp"
55

66
namespace vortex::guidance {
77

@@ -10,6 +10,12 @@ struct ReferenceFilterParams {
1010
Eigen::Vector6d zeta = Eigen::Vector6d::Zero();
1111
};
1212

13+
/**
14+
* @brief Stateless third-order reference filter.
15+
*
16+
* Computes the state derivative x_dot = Ad * x + Bd * r, where the state
17+
* x = [eta, eta_dot, eta_ddot] is 18-dimensional and r is the 6D reference.
18+
*/
1319
class ReferenceFilter {
1420
public:
1521
explicit ReferenceFilter(const ReferenceFilterParams& params);
@@ -41,4 +47,4 @@ class ReferenceFilter {
4147

4248
} // namespace vortex::guidance
4349

44-
#endif // REFERENCE_FILTER_DP__REFERENCE_FILTER_HPP_
50+
#endif // REFERENCE_FILTER_DP__LIB__REFERENCE_FILTER_HPP_
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#ifndef REFERENCE_FILTER_DP__LIB__WAYPOINT_FOLLOWER_HPP_
2+
#define REFERENCE_FILTER_DP__LIB__WAYPOINT_FOLLOWER_HPP_
3+
4+
#include <mutex>
5+
#include <vortex/utils/types.hpp>
6+
#include "reference_filter_dp/lib/eigen_typedefs.hpp"
7+
#include "reference_filter_dp/lib/reference_filter.hpp"
8+
#include "reference_filter_dp/lib/waypoint_types.hpp"
9+
10+
namespace vortex::guidance {
11+
12+
using vortex::utils::types::PoseEuler;
13+
using vortex::utils::types::Twist;
14+
15+
/**
16+
* @brief Manages reference filter state and waypoint following logic.
17+
*
18+
* Thread-safe: all public methods acquire a mutex.
19+
*/
20+
class WaypointFollower {
21+
public:
22+
WaypointFollower(const ReferenceFilterParams& params, double dt_seconds);
23+
24+
/**
25+
* @brief Initialize the follower with the current vehicle state and target.
26+
* @param pose Current vehicle pose.
27+
* @param twist Current vehicle twist (body frame).
28+
* @param waypoint Target waypoint with mode.
29+
* @param convergence_threshold Max error norm to consider target reached.
30+
*/
31+
void start(const PoseEuler& pose,
32+
const Twist& twist,
33+
const Waypoint& waypoint,
34+
double convergence_threshold);
35+
36+
/**
37+
* @brief Advance the filter by one time step.
38+
* @return The updated filter state.
39+
*/
40+
Eigen::Vector18d step();
41+
42+
/**
43+
* @brief Check if the measured pose has converged to the reference goal.
44+
* @param measured_pose Current measured pose.
45+
* @return True if the error norm is within the convergence threshold.
46+
*/
47+
bool within_convergance(const Eigen::Vector6d& measured_pose) const;
48+
49+
/**
50+
* @brief Update the reference goal pose mid-sequence.
51+
* @param reference_goal_pose The new reference pose.
52+
*/
53+
void set_reference(const PoseEuler& reference_goal_pose);
54+
55+
/**
56+
* @brief Snap the position component of the filter state to the reference.
57+
*
58+
* Useful after convergence to eliminate any remaining steady-state offset
59+
*/
60+
void snap_state_to_reference();
61+
62+
/// @brief Get the current 18D filter state.
63+
Eigen::Vector18d state() const;
64+
65+
/// @brief Get the current 6D reference goal pose.
66+
Eigen::Vector6d reference() const;
67+
68+
private:
69+
Eigen::Vector18d compute_initial_state(const PoseEuler& pose,
70+
const Twist& twist);
71+
72+
mutable std::mutex mutex_;
73+
ReferenceFilter filter_;
74+
double dt_seconds_{0.01};
75+
Eigen::Vector18d state_ = Eigen::Vector18d::Zero();
76+
Eigen::Vector6d reference_goal_ = Eigen::Vector6d::Zero();
77+
WaypointMode waypoint_mode_{WaypointMode::FULL_POSE};
78+
double convergence_threshold_{0.1};
79+
};
80+
81+
} // namespace vortex::guidance
82+
83+
#endif // REFERENCE_FILTER_DP__LIB__WAYPOINT_FOLLOWER_HPP_
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#ifndef REFERENCE_FILTER_DP__LIB__WAYPOINT_TYPES_HPP_
2+
#define REFERENCE_FILTER_DP__LIB__WAYPOINT_TYPES_HPP_
3+
4+
#include <cstdint>
5+
#include <vortex/utils/types.hpp>
6+
7+
namespace vortex::guidance {
8+
9+
using vortex::utils::types::PoseEuler;
10+
11+
/**
12+
* @brief Determines which degrees of freedom the reference filter controls.
13+
*
14+
* The mode affects both the reference goal computation (via apply_mode_logic)
15+
* and the convergence check (via has_converged).
16+
*/
17+
enum class WaypointMode : uint8_t {
18+
FULL_POSE = 0, ///< Control all 6 DOF.
19+
ONLY_POSITION = 1, ///< Control x, y, z; hold current orientation.
20+
FORWARD_HEADING = 2, ///< Control x, y, z with yaw toward target.
21+
ONLY_ORIENTATION = 3, ///< Control roll, pitch, yaw; hold current position.
22+
};
23+
24+
/**
25+
* @brief A target pose with an associated waypoint mode.
26+
*/
27+
struct Waypoint {
28+
PoseEuler pose{};
29+
WaypointMode mode = WaypointMode::FULL_POSE;
30+
};
31+
32+
} // namespace vortex::guidance
33+
34+
#endif // REFERENCE_FILTER_DP__LIB__WAYPOINT_TYPES_HPP_
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#ifndef REFERENCE_FILTER_DP__LIB__WAYPOINT_UTILS_HPP_
2+
#define REFERENCE_FILTER_DP__LIB__WAYPOINT_UTILS_HPP_
3+
4+
#include "reference_filter_dp/lib/eigen_typedefs.hpp"
5+
#include "reference_filter_dp/lib/waypoint_types.hpp"
6+
7+
namespace vortex::guidance {
8+
9+
/**
10+
* @brief Apply waypoint mode logic to a reference pose.
11+
*
12+
* For modes that don't control all DOFs, the uncontrolled components are
13+
* replaced with values from @p current_state so the filter holds them steady.
14+
*
15+
* @param r_in The raw reference pose (6D).
16+
* @param mode The waypoint mode.
17+
* @param current_state The current filter state pose (6D).
18+
* @return The adjusted reference pose.
19+
*/
20+
Eigen::Vector6d apply_mode_logic(const Eigen::Vector6d& r_in,
21+
WaypointMode mode,
22+
const Eigen::Vector6d& current_state);
23+
24+
/**
25+
* @brief Check whether the measured pose has converged to the reference.
26+
*
27+
* Only the DOFs relevant to the waypoint mode are included in the error norm.
28+
*
29+
* @param measured_pose The current measured pose (6D).
30+
* @param reference The reference goal pose (6D).
31+
* @param mode The waypoint mode.
32+
* @param convergence_threshold The maximum allowed error norm.
33+
* @return True if the error is below the threshold.
34+
*/
35+
bool has_converged(const Eigen::Vector6d& measured_pose,
36+
const Eigen::Vector6d& reference,
37+
WaypointMode mode,
38+
double convergence_threshold);
39+
40+
} // namespace vortex::guidance
41+
42+
#endif // REFERENCE_FILTER_DP__LIB__WAYPOINT_UTILS_HPP_

0 commit comments

Comments
 (0)