Skip to content

Refactor/reference filter dp#687

Merged
jorgenfj merged 18 commits into
mainfrom
refactor/reference-filter-dp
Mar 21, 2026
Merged

Refactor/reference filter dp#687
jorgenfj merged 18 commits into
mainfrom
refactor/reference-filter-dp

Conversation

@jorgenfj

Copy link
Copy Markdown
Contributor
  • Restructured the package into a standalone core library (lib/) and a ROS integration layer (ros/)
  • Extracted waypoint following, mode logic, and convergence checking out of the ROS node
  • Fixed action server concurrency race: replaced detached threads + generation counter with a join-before-spawn model guarded by execute_mutex_, ensuring only one thread accesses the follower at a time

@codecov

codecov Bot commented Mar 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 83.64116% with 62 lines in your changes missing coverage. Please review.
✅ Project coverage is 33.47%. Comparing base (d53f2b8) to head (1442967).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...e/reference_filter_dp/test/test_waypoint_utils.cpp 70.88% 0 Missing and 23 partials ⚠️
...ference_filter_dp/src/ros/reference_filter_ros.cpp 82.67% 16 Missing and 6 partials ⚠️
...rence_filter_dp/ros/reference_filter_ros_utils.hpp 72.72% 9 Missing ⚠️
...eference_filter_dp/test/test_waypoint_follower.cpp 88.33% 0 Missing and 7 partials ⚠️
...nce/reference_filter_dp/src/lib/waypoint_utils.cpp 97.61% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #687      +/-   ##
==========================================
+ Coverage   31.54%   33.47%   +1.92%     
==========================================
  Files          63       68       +5     
  Lines        4710     4840     +130     
  Branches     1180     1245      +65     
==========================================
+ Hits         1486     1620     +134     
+ Misses       2957     2925      -32     
- Partials      267      295      +28     
Flag Coverage Δ
unittests 33.47% <83.64%> (+1.92%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...e/reference_filter_dp/src/lib/reference_filter.cpp 100.00% <ø> (ø)
.../reference_filter_dp/src/lib/waypoint_follower.cpp 100.00% <100.00%> (ø)
...reference_filter_dp/test/test_reference_filter.cpp 88.88% <ø> (ø)
...nce/reference_filter_dp/src/lib/waypoint_utils.cpp 97.61% <97.61%> (ø)
...eference_filter_dp/test/test_waypoint_follower.cpp 88.33% <88.33%> (ø)
...rence_filter_dp/ros/reference_filter_ros_utils.hpp 72.72% <72.72%> (ø)
...ference_filter_dp/src/ros/reference_filter_ros.cpp 82.67% <82.67%> (ø)
...e/reference_filter_dp/test/test_waypoint_utils.cpp 70.88% <70.88%> (ø)

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jorgenfj jorgenfj requested a review from Andeshog March 20, 2026 21:51
Comment on lines +122 to +130
rclcpp_action::GoalResponse ReferenceFilterNode::handle_goal(
const rclcpp_action::GoalUUID& uuid,
std::shared_ptr<const vortex_msgs::action::ReferenceFilterWaypoint::Goal>
goal) {
(void)uuid;
(void)goal;
spdlog::info("Accepted goal request");
return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I think it looks better to comment out the unused parameters instead of void cast

rclcpp_action::GoalResponse ReferenceFilterNode::handle_goal(
    const rclcpp_action::GoalUUID& /*uuid*/,
    std::shared_ptr<const vortex_msgs::action::ReferenceFilterWaypoint::Goal> /*goal*/) 
{
    spdlog::info("Accepted goal request");
    return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
}

Ref https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#f9-unused-parameters-should-be-unnamed

Comment on lines +132 to +138
rclcpp_action::CancelResponse ReferenceFilterNode::handle_cancel(
const std::shared_ptr<rclcpp_action::ServerGoalHandle<
vortex_msgs::action::ReferenceFilterWaypoint>> goal_handle) {
spdlog::info("Received request to cancel goal");
(void)goal_handle;
return rclcpp_action::CancelResponse::ACCEPT;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rclcpp_action::CancelResponse ReferenceFilterNode::handle_cancel(
    const std::shared_ptr<rclcpp_action::ServerGoalHandle<
        vortex_msgs::action::ReferenceFilterWaypoint>> /*goal_handle*/) {
    spdlog::info("Received request to cancel goal");
    return rclcpp_action::CancelResponse::ACCEPT;
}

Comment on lines +169 to +178
Waypoint wp = waypoint_from_ros(goal_handle->get_goal()->waypoint);

PoseEuler pose;
Twist twist;
{
std::lock_guard<std::mutex> lock(sensor_mutex_);
pose = current_pose_;
twist = current_twist_;
}
follower_->start(pose, twist, wp, convergence_threshold);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could rewrite to something like

const auto wp = waypoint_from_ros(goal_handle->get_goal()->waypoint);

const auto [pose, twist] = [this] {
    std::lock_guard lock(sensor_mutex_);
    return std::pair{current_pose_, current_twist_};
}();

follower_->start(pose, twist, wp, convergence_threshold);

really just a cosmetic change though

Comment on lines +204 to +208
Eigen::Vector6d current_pose_vector;
{
std::lock_guard<std::mutex> lock(sensor_mutex_);
current_pose_vector = current_pose_.to_vector();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using an IIFE here as well

const auto current_pose_vector = [this] {
    std::lock_guard lock(sensor_mutex_);
    return current_pose_.to_vector();
}();

Comment on lines +44 to +60
inline vortex_msgs::msg::ReferenceFilter fill_reference_msg(
const Eigen::Vector18d& x) {
vortex_msgs::msg::ReferenceFilter msg;
msg.x = x(0);
msg.y = x(1);
msg.z = x(2);
msg.roll = vortex::utils::math::ssa(x(3));
msg.pitch = vortex::utils::math::ssa(x(4));
msg.yaw = vortex::utils::math::ssa(x(5));
msg.x_dot = x(6);
msg.y_dot = x(7);
msg.z_dot = x(8);
msg.roll_dot = x(9);
msg.pitch_dot = x(10);
msg.yaw_dot = x(11);
return msg;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could put a using vortex::utils::math::ssa in here just to reduce words

inline vortex_msgs::msg::ReferenceFilter fill_reference_msg(
    const Eigen::Vector18d& x) {
    using vortex::utils::math::ssa;
    vortex_msgs::msg::ReferenceFilter msg;
    msg.x = x(0);
    msg.y = x(1);
    msg.z = x(2);
    msg.roll = ssa(x(3));
    msg.pitch = ssa(x(4));
    msg.yaw = ssa(x(5));
    msg.x_dot = x(6);
    msg.y_dot = x(7);
    msg.z_dot = x(8);
    msg.roll_dot = x(9);
    msg.pitch_dot = x(10);
    msg.yaw_dot = x(11);
    return msg;
}

Comment on lines +50 to +52
ea(0) = vortex::utils::math::ssa(measured_pose(3) - reference(3));
ea(1) = vortex::utils::math::ssa(measured_pose(4) - reference(4));
ea(2) = vortex::utils::math::ssa(measured_pose(5) - reference(5));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could add a local using vortex::utils::math::ssa here too

Comment on lines +54 to +73
double err = 0.0;

switch (mode) {
case WaypointMode::ONLY_POSITION:
err = ep.norm();
break;

case WaypointMode::ONLY_ORIENTATION:
err = ea.norm();
break;

case WaypointMode::FORWARD_HEADING:
err = std::sqrt(ep.squaredNorm() + ea(2) * ea(2));
break;

case WaypointMode::FULL_POSE:
default:
err = std::sqrt(ep.squaredNorm() + ea.squaredNorm());
break;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would drop the default, so that you get a warning/error if a new mode is added, but not supported here.
Also, instead of the "initialize then assign" pattern, you could wrap the switch in an IIFE to assign err once

const double err = [&] {
    switch (mode) {
        case WaypointMode::ONLY_POSITION:
            return ep.norm();
        case WaypointMode::ONLY_ORIENTATION:
            return ea.norm();
        case WaypointMode::FORWARD_HEADING:
            return std::sqrt(ep.squaredNorm() + ea(2) * ea(2));
        case WaypointMode::FULL_POSE:
            return std::sqrt(ep.squaredNorm() + ea.squaredNorm());
    }
}();

Comment on lines +97 to +102
std::bind(&ReferenceFilterNode::handle_goal, this,
std::placeholders::_1, std::placeholders::_2),
std::bind(&ReferenceFilterNode::handle_cancel, this,
std::placeholders::_1),
std::bind(&ReferenceFilterNode::handle_accepted, this,
std::placeholders::_1),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer lambdas over bind 😀

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example like this

action_server_ = rclcpp_action::create_server
    vortex_msgs::action::ReferenceFilterWaypoint>(
    this, action_server_name,
    [this](const auto& uuid, auto goal) {
        return handle_goal(uuid, std::move(goal));
    },
    [this](auto& goal_handle) {
        return handle_cancel(std::move(goal_handle));
    },
    [this](auto& goal_handle) {
        handle_accepted(std::move(goal_handle));
    },
    rcl_action_server_get_default_options());

@jorgenfj jorgenfj merged commit da8722f into main Mar 21, 2026
14 of 19 checks passed
@jorgenfj jorgenfj deleted the refactor/reference-filter-dp branch March 21, 2026 12:23
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 2.7.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants