Skip to content

Conversation

@jorgenfj
Copy link
Contributor

Renamed types:
Eta -> PoseEuler
EtaQuat -> Pose
Nu -> Twist

Added generic conversion function when converting to ros types from arbitrary "poselike" types . The types just need to expose accessor functions to their "pose fields" to satisy the requirements for the function.
POD structs that already expose the fields directly as members already satisfy the concepts in "member_concepts.hpp" and expose accessors functions automatically in "accessors.hpp".

This setup gives types like vortex_msgs::msg::ReferenceFilter access to the conversion function, and to add support for more complex Eigen-like types in the future you just need to define its accessor functions.

This concept setup abstracts the accessor function logic away from the simple POD, while still being able to support more complex types in the future, that also don't have to be defined in vortex utils.

@jorgenfj jorgenfj requested a review from Andeshog December 18, 2025 18:40
@jorgenfj jorgenfj changed the title Concept refactor Rename vortex util types Dec 18, 2025
@codecov
Copy link

codecov bot commented Dec 18, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.06%. Comparing base (69391c1) to head (29fd12f).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #22      +/-   ##
==========================================
- Coverage   98.11%   98.06%   -0.06%     
==========================================
  Files           5        5              
  Lines         425      413      -12     
  Branches       97       84      -13     
==========================================
- Hits          417      405      -12     
  Misses          4        4              
  Partials        4        4              
Flag Coverage Δ
unittests 98.06% <100.00%> (-0.06%) ⬇️

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

Files with missing lines Coverage Δ
include/vortex/utils/ros_conversions.hpp 100.00% <100.00%> (ø)
include/vortex/utils/types.hpp 95.58% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@Andeshog Andeshog left a comment

Choose a reason for hiding this comment

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

I still really dont see the need to do this so complicated. We have two types, ROS has a couple, and all of them are pre-known. Why not just use std::variant for example? (eta is used for example only, I support the twist and pose renaming)

Something along these lines

#include <variant>

template <class ... Ts>
struct VisitorOverloader : Ts... { using Ts::operator()...; };

Eigen::Vector<double, 3> get_eta_position(const std::variant<Eta, EtaQuat>& eta_variant) {
    return std::visit(
        VisitorOverloader{
            [](const Eta& eta) {
                return Eigen::Vector3d{eta.x, eta.y, eta.z};
            },
            [](const EtaQuat& eta_quat) {
                return Eigen::Vector3d{eta_quat.x, eta_quat.y, eta_quat.z};
            }
        },
        eta_variant
    );
}

This does what you want, but without the heavy templating, and also means you dont have to define accessors for public members.

@Andeshog
Copy link
Contributor

I still really dont see the need to do this so complicated. We have two types, ROS has a couple, and all of them are pre-known. Why not just use std::variant for example? (eta is used for example only, I support the twist and pose renaming)

Something along these lines

#include <variant>

template <class ... Ts>
struct VisitorOverloader : Ts... { using Ts::operator()...; };

Eigen::Vector<double, 3> get_eta_position(const std::variant<Eta, EtaQuat>& eta_variant) {
    return std::visit(
        VisitorOverloader{
            [](const Eta& eta) {
                return Eigen::Vector3d{eta.x, eta.y, eta.z};
            },
            [](const EtaQuat& eta_quat) {
                return Eigen::Vector3d{eta_quat.x, eta_quat.y, eta_quat.z};
            }
        },
        eta_variant
    );
}

This does what you want, but without the heavy templating, and also means you dont have to define accessors for public members.

If it wasnt clear, this is just used like

// gets eta position
const auto eta = Eta{};
const Eigen::Vector<double, 3> eta_pos = get_eta_position(eta);

// get eta_quat position
const auto eta_quat = EtaQuat{};
const Eigen::Vector<double, 3> eta_quat_pos = get_eta_position(eta_quat);

@jorgenfj
Copy link
Contributor Author

With the current setup there is no need to define the accessors for public members. Also with the current setup the ros conversion function also works for types like vortex_msgs::msg::ReferenceFilter and such.

@jorgenfj
Copy link
Contributor Author

If you are referring to the functions in "views.hpp" then I agree they are not strictly needed, so they can be removed, but I would like to keep the current setup for the ros conversion functions

@chrstrom
Copy link
Member

chrstrom commented Dec 19, 2025

My two cents were requested:

  1. The accessors feel kinda weird to me, as the types are just POD structs and should (?) be used as such?

  2. std::variant / visitor would occur some runtime cost (but idk if that cost is worth considering?)

  3. Concept usage looks lowkey overkill, purely based on the fact that I assume we'd want a unified type system, thus not requiring any new implementations that adhere to the concepts. The compile-time things are nice though

@jorgenfj
Copy link
Contributor Author

The accessors could make sense if we had many templated functions and wanted to support "Eigen like" pose types in the future. As it stands now we probably wouldn't have ended up with that many templated functions anyways, so I agree that they might be overkill with the current functions.

Comment on lines 154 to +155
template <ROSPoseLike T>
inline Eigen::Matrix<double, 6, Eigen::Dynamic> ros_to_eigen6d(const T& msg) {
std::vector<vortex::utils::types::Pose> ros_to_pose_vec(const T& msg) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Seems to me this function is only really meant for PoseArray? Could that be used directly instead of templating here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You'll have to wait and see😉

Comment on lines 22 to 25
/**
* @brief Struct to represent the state vector nu according to eq. 2.5 in
* Fossen, 2021, containing the linear and angular velocities.
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

Cant mark the other docs since they are not changed, but the mention of eta and nu could probably go as well? I think it is sufficient to ref the eq.

/**
 * @brief Struct to represent the velocity vector according to eq. 2.5 in
 * Fossen, 2021, containing the linear and angular velocities.
 */

/**
 * @brief Struct to represent the pose vector according to eq. 2.3 in
 * Fossen, 2021, containing the position and orientation as quaternion.
 */

Copy link
Contributor

@Andeshog Andeshog left a comment

Choose a reason for hiding this comment

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

approval with suggestions

@jorgenfj jorgenfj merged commit 1120672 into main Dec 19, 2025
5 checks passed
@jorgenfj jorgenfj deleted the concept-refactor branch December 19, 2025 12:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants