Skip to content

Commit 174d8cc

Browse files
committed
ekf2/odometry: add VehicleOdometry acceleration and ROS 2 translation
- extend VehicleOdometry.msg to v1 with float32[3] acceleration in NED, defined as the derivative of NED velocity averaged over the odometry publish interval - read _ekf.getVelocityDerivative() once in EKF2::Run(), pass it to PublishLocalPosition() and PublishOdometry(), and reset the accumulation once after both publishers consume it - archive VehicleOdometryV0.msg in px4_msgs_old and add VehicleOdometryV1Translation to translation_node - preserve ROS 2 interoperability between v0 and v1 clients: v0 -> v1 fills acceleration with NaN, and v1 -> v0 drops it This follows the review direction to extend VehicleOdometry instead of adding VehicleFullState, and avoids mixed-rate aliasing or double consumption of the velocity derivative. Tested: - make px4_sitl_default -j4 - colcon build --packages-select px4_msgs - colcon build --packages-select px4_msgs_old translation_node - colcon test --packages-select translation_node --ctest-args -R translation_node_unit_tests Signed-off-by: evannsmc <evannsmcuadrado@gmail.com>
1 parent 197a1a6 commit 174d8cc

6 files changed

Lines changed: 103 additions & 9 deletions

File tree

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Vehicle odometry data
2+
#
3+
# Fits ROS REP 147 for aerial vehicles
4+
5+
uint32 MESSAGE_VERSION = 0
6+
7+
uint64 timestamp # [us] Time since system start
8+
uint64 timestamp_sample # [us] Timestamp sample
9+
10+
uint8 pose_frame # [@enum POSE_FRAME] Position and orientation frame of reference
11+
uint8 POSE_FRAME_UNKNOWN = 0 # Unknown frame
12+
uint8 POSE_FRAME_NED = 1 # North-East-Down (NED) navigation frame. Aligned with True North.
13+
uint8 POSE_FRAME_FRD = 2 # Forward-Right-Down (FRD) frame. Constant arbitrary heading offset from True North. Z is down.
14+
15+
float32[3] position # [m] [@frame local frame] [@invalid NaN If invalid/unknown] Position. Origin is position of GC at startup.
16+
float32[4] q # [-] [@invalid NaN First value if invalid/unknown] Attitude (expressed as a quaternion) relative to pose reference frame at current location. Follows the Hamiltonian convention (w, x, y, z, right-handed, passive rotations from body to world)
17+
18+
uint8 velocity_frame # [@enum VELOCITY_FRAME] Reference frame of the velocity data
19+
uint8 VELOCITY_FRAME_UNKNOWN = 0 # Unknown frame
20+
uint8 VELOCITY_FRAME_NED = 1 # NED navigation frame at current position.
21+
uint8 VELOCITY_FRAME_FRD = 2 # FRD navigation frame at current position. Constant arbitrary heading offset from True North. Z is down.
22+
uint8 VELOCITY_FRAME_BODY_FRD = 3 # FRD body-fixed frame
23+
24+
float32[3] velocity # [m/s] [@frame @velocity_frame] [@invalid NaN If invalid/unknown] Velocity.
25+
float32[3] angular_velocity # [rad/s] [@frame @VELOCITY_FRAME_BODY_FRD] [@invalid NaN If invalid/unknown] Angular velocity in body-fixed frame
26+
27+
float32[3] position_variance # [m^2] Variance of position error
28+
float32[3] orientation_variance # [rad^2] Variance of orientation/attitude error (expressed in body frame)
29+
float32[3] velocity_variance # [m^2/s^2] Variance of velocity error
30+
31+
uint8 reset_counter # [-] Reset counter. Counts reset events on attitude, velocity and position.
32+
int8 quality # [-] [@invalid 0] Quality. Unused.
33+
34+
# TOPICS vehicle_odometry vehicle_mocap_odometry vehicle_visual_odometry
35+
# TOPICS estimator_odometry

msg/translation_node/translations/all_translations.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "translation_vehicle_attitude_setpoint_v1.h"
2020
#include "translation_vehicle_command_ack_v1.h"
2121
#include "translation_vehicle_local_position_v1.h"
22+
#include "translation_vehicle_odometry_v1.h"
2223
#include "translation_vehicle_status_v1.h"
2324
#include "translation_vehicle_status_v2.h"
2425
#include "translation_vehicle_status_v3.h"
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/****************************************************************************
2+
* Copyright (c) 2025 PX4 Development Team.
3+
* SPDX-License-Identifier: BSD-3-Clause
4+
****************************************************************************/
5+
#pragma once
6+
7+
// Translate VehicleOdometry v0 <--> v1
8+
#include <limits>
9+
#include <px4_msgs_old/msg/vehicle_odometry_v0.hpp>
10+
#include <px4_msgs/msg/vehicle_odometry.hpp>
11+
12+
class VehicleOdometryV1Translation {
13+
public:
14+
using MessageOlder = px4_msgs_old::msg::VehicleOdometryV0;
15+
static_assert(MessageOlder::MESSAGE_VERSION == 0);
16+
17+
using MessageNewer = px4_msgs::msg::VehicleOdometry;
18+
static_assert(MessageNewer::MESSAGE_VERSION == 1);
19+
20+
static constexpr const char* kTopic = "fmu/out/vehicle_odometry";
21+
22+
#define COMMON_VEHICLE_ODOMETRY_FIELDS(FUNCTION) \
23+
FUNCTION(timestamp) \
24+
FUNCTION(timestamp_sample) \
25+
FUNCTION(pose_frame) \
26+
FUNCTION(position) \
27+
FUNCTION(q) \
28+
FUNCTION(velocity_frame) \
29+
FUNCTION(velocity) \
30+
FUNCTION(angular_velocity) \
31+
FUNCTION(position_variance) \
32+
FUNCTION(orientation_variance) \
33+
FUNCTION(velocity_variance) \
34+
FUNCTION(reset_counter) \
35+
FUNCTION(quality)
36+
37+
#define COPY_FIELD_FROM_OLDER(field) msg_newer.field = msg_older.field;
38+
#define COPY_FIELD_TO_OLDER(field) msg_older.field = msg_newer.field;
39+
40+
static void fromOlder(const MessageOlder &msg_older, MessageNewer &msg_newer) {
41+
COMMON_VEHICLE_ODOMETRY_FIELDS(COPY_FIELD_FROM_OLDER)
42+
msg_newer.acceleration.fill(std::numeric_limits<float>::quiet_NaN());
43+
}
44+
45+
static void toOlder(const MessageNewer &msg_newer, MessageOlder &msg_older) {
46+
COMMON_VEHICLE_ODOMETRY_FIELDS(COPY_FIELD_TO_OLDER)
47+
}
48+
49+
#undef COPY_FIELD_FROM_OLDER
50+
#undef COPY_FIELD_TO_OLDER
51+
#undef COMMON_VEHICLE_ODOMETRY_FIELDS
52+
};
53+
54+
REGISTER_TOPIC_TRANSLATION_DIRECT(VehicleOdometryV1Translation);

msg/versioned/VehicleOdometry.msg

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#
33
# Fits ROS REP 147 for aerial vehicles
44

5-
uint32 MESSAGE_VERSION = 0
5+
uint32 MESSAGE_VERSION = 1
66

77
uint64 timestamp # [us] Time since system start
88
uint64 timestamp_sample # [us] Timestamp sample
@@ -22,6 +22,7 @@ uint8 VELOCITY_FRAME_FRD = 2 # FRD navigation frame at current position. C
2222
uint8 VELOCITY_FRAME_BODY_FRD = 3 # FRD body-fixed frame
2323

2424
float32[3] velocity # [m/s] [@frame @velocity_frame] [@invalid NaN If invalid/unknown] Velocity.
25+
float32[3] acceleration # [m/s^2] [@frame local frame] [@invalid NaN If invalid/unknown] Acceleration of body origin in local NED frame.
2526
float32[3] angular_velocity # [rad/s] [@frame @VELOCITY_FRAME_BODY_FRD] [@invalid NaN If invalid/unknown] Angular velocity in body-fixed frame
2627

2728
float32[3] position_variance # [m^2] Variance of position error

src/modules/ekf2/EKF2.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -815,8 +815,10 @@ void EKF2::Run()
815815
if (_ekf.update()) {
816816
perf_set_elapsed(_ekf_update_perf, hrt_elapsed_time(&ekf_update_start));
817817

818-
PublishLocalPosition(now);
819-
PublishOdometry(now, imu_sample_new);
818+
const Vector3f vel_deriv{_ekf.getVelocityDerivative()};
819+
PublishLocalPosition(now, vel_deriv);
820+
PublishOdometry(now, imu_sample_new, vel_deriv);
821+
_ekf.resetVelocityDerivativeAccumulation();
820822
PublishGlobalPosition(now);
821823
PublishSensorBias(now);
822824

@@ -1580,7 +1582,7 @@ void EKF2::PublishInnovationVariances(const hrt_abstime &timestamp)
15801582
_estimator_innovation_variances_pub.publish(variances);
15811583
}
15821584

1583-
void EKF2::PublishLocalPosition(const hrt_abstime &timestamp)
1585+
void EKF2::PublishLocalPosition(const hrt_abstime &timestamp, const Vector3f &vel_deriv)
15841586
{
15851587
vehicle_local_position_s lpos{};
15861588
// generate vehicle local position data
@@ -1602,8 +1604,6 @@ void EKF2::PublishLocalPosition(const hrt_abstime &timestamp)
16021604
lpos.z_deriv = _ekf.getVerticalPositionDerivative();
16031605

16041606
// Acceleration of body origin in local frame
1605-
const Vector3f vel_deriv{_ekf.getVelocityDerivative()};
1606-
_ekf.resetVelocityDerivativeAccumulation();
16071607
lpos.ax = vel_deriv(0);
16081608
lpos.ay = vel_deriv(1);
16091609
lpos.az = vel_deriv(2);
@@ -1703,7 +1703,7 @@ void EKF2::PublishLocalPosition(const hrt_abstime &timestamp)
17031703
_local_position_pub.publish(lpos);
17041704
}
17051705

1706-
void EKF2::PublishOdometry(const hrt_abstime &timestamp, const imuSample &imu_sample)
1706+
void EKF2::PublishOdometry(const hrt_abstime &timestamp, const imuSample &imu_sample, const Vector3f &vel_deriv)
17071707
{
17081708
// generate vehicle odometry data
17091709
vehicle_odometry_s odom;
@@ -1720,6 +1720,9 @@ void EKF2::PublishOdometry(const hrt_abstime &timestamp, const imuSample &imu_sa
17201720
odom.velocity_frame = vehicle_odometry_s::VELOCITY_FRAME_NED;
17211721
_ekf.getVelocity().copyTo(odom.velocity);
17221722

1723+
// acceleration
1724+
vel_deriv.copyTo(odom.acceleration);
1725+
17231726
// angular_velocity
17241727
_ekf.getAngularVelocityAndResetAccumulator().copyTo(odom.angular_velocity);
17251728

src/modules/ekf2/EKF2.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,8 @@ class EKF2 final : public ModuleParams, public px4::ScheduledWorkItem
192192
void PublishInnovations(const hrt_abstime &timestamp);
193193
void PublishInnovationTestRatios(const hrt_abstime &timestamp);
194194
void PublishInnovationVariances(const hrt_abstime &timestamp);
195-
void PublishLocalPosition(const hrt_abstime &timestamp);
196-
void PublishOdometry(const hrt_abstime &timestamp, const imuSample &imu_sample);
195+
void PublishLocalPosition(const hrt_abstime &timestamp, const matrix::Vector3f &vel_deriv);
196+
void PublishOdometry(const hrt_abstime &timestamp, const imuSample &imu_sample, const matrix::Vector3f &vel_deriv);
197197
void PublishSensorBias(const hrt_abstime &timestamp);
198198
void PublishStates(const hrt_abstime &timestamp);
199199
void PublishStatus(const hrt_abstime &timestamp);

0 commit comments

Comments
 (0)