Skip to content

Commit dc82fb7

Browse files
committed
merged landmark egomotion into eskf package. LandmarkESKF now inherits from ESKF directly. Fixed quaternion error to use right perturbation
1 parent 9691490 commit dc82fb7

File tree

6 files changed

+47
-127
lines changed

6 files changed

+47
-127
lines changed

navigation/eskf/CMakeLists.txt

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,15 @@ add_library(${PROJECT_NAME}::${CORE_LIB_NAME} ALIAS ${CORE_LIB_NAME})
5656

5757
set(COMPONENT_LIB_NAME "${PROJECT_NAME}_component")
5858

59+
set(LANDMARK_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../landmark_egomotion")
60+
5961
add_library(${COMPONENT_LIB_NAME} SHARED
6062
src/ros/eskf_ros.cpp
63+
${LANDMARK_DIR}/src/lib/landmark_egomotion.cpp
64+
)
65+
66+
target_include_directories(${COMPONENT_LIB_NAME} PRIVATE
67+
${LANDMARK_DIR}/include
6168
)
6269

6370
ament_target_dependencies(${COMPONENT_LIB_NAME}
@@ -78,14 +85,6 @@ ament_target_dependencies(${COMPONENT_LIB_NAME}
7885

7986
target_link_libraries(${COMPONENT_LIB_NAME} ${PROJECT_NAME})
8087

81-
find_package(landmark_egomotion QUIET)
82-
if(landmark_egomotion_FOUND)
83-
target_compile_definitions(${COMPONENT_LIB_NAME} PRIVATE HAVE_LANDMARK_EGOMOTION=1)
84-
target_link_libraries(${COMPONENT_LIB_NAME} landmark_egomotion::landmark_egomotion_lib)
85-
else()
86-
message(STATUS "landmark_egomotion not found — building eskf without landmark egomotion support")
87-
endif()
88-
8988
rclcpp_components_register_node(
9089
${COMPONENT_LIB_NAME}
9190
PLUGIN "ESKFNode"
@@ -106,6 +105,11 @@ install(
106105
DESTINATION include
107106
)
108107

108+
install(
109+
DIRECTORY ${LANDMARK_DIR}/include/
110+
DESTINATION include
111+
)
112+
109113
install(DIRECTORY
110114
launch
111115
config

navigation/eskf/include/eskf/ros/eskf_ros.hpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,9 @@
2424
#include "eskf/lib/typedefs.hpp"
2525
#include "spdlog/spdlog.h"
2626

27-
#ifdef HAVE_LANDMARK_EGOMOTION
2827
#include <vortex_msgs/msg/landmark_array.hpp>
2928
#include "landmark_egomotion/lib/landmark_egomotion.hpp"
3029
#include "landmark_egomotion/lib/landmark_typedefs.hpp"
31-
#endif
3230

3331
class ESKFNode : public rclcpp::Node {
3432
public:
@@ -60,7 +58,6 @@ class ESKFNode : public rclcpp::Node {
6058
// @brief broadcast the State as a TF
6159
void publish_tf(const StateQuat& nom_state);
6260

63-
#ifdef HAVE_LANDMARK_EGOMOTION
6461
void setup_vo(const EskfParams& eskf_params);
6562

6663
void landmark_callback(
@@ -76,7 +73,6 @@ class ESKFNode : public rclcpp::Node {
7673
bool have_last_marker_{false};
7774
uint16_t last_marker_id_{0};
7875
int vo_rejects_limit_{0};
79-
#endif
8076

8177
// Subscribers and Publishers
8278

navigation/eskf/src/ros/eskf_ros.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -132,17 +132,13 @@ void ESKFNode::set_parameters() {
132132
EskfParams eskf_params{.Q = Q, .P = P};
133133

134134
eskf_ = std::make_unique<ESKF>(eskf_params);
135-
spdlog::info("Landmark egomotion enabled?");
136-
#ifdef HAVE_LANDMARK_EGOMOTION
137-
spdlog::info("Landmark egomotion enabled");
135+
138136
this->declare_parameter<bool>("use_landmark_egomotion");
139137
if (this->get_parameter("use_landmark_egomotion").as_bool()) {
140138
setup_vo(eskf_params);
141139
}
142-
#endif
143140
}
144141

145-
#ifdef HAVE_LANDMARK_EGOMOTION
146142
void ESKFNode::setup_vo(const EskfParams& eskf_params) {
147143
auto landmark_eskf = std::make_unique<LandmarkESKF>(eskf_params);
148144
landmark_eskf_ = landmark_eskf.get();
@@ -289,7 +285,6 @@ void ESKFNode::landmark_callback(
289285
spdlog::warn("VO gating: {} consecutive reject(s)", rejects_after);
290286
}
291287
}
292-
#endif // HAVE_LANDMARK_EGOMOTION
293288

294289
void ESKFNode::imu_callback(const sensor_msgs::msg::Imu::SharedPtr msg) {
295290
rclcpp::Time current_time = msg->header.stamp;

navigation/landmark_egomotion/CMakeLists.txt

Lines changed: 0 additions & 57 deletions
This file was deleted.

navigation/landmark_egomotion/package.xml

Lines changed: 0 additions & 18 deletions
This file was deleted.

navigation/landmark_egomotion/src/lib/landmark_egomotion.cpp

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ LandmarkESKF::LandmarkESKF(const EskfParams& params) : ESKF(params) {
2222
Eigen::Vector3d LandmarkESKF::compute_quaternion_error(
2323
const Eigen::Quaterniond& q_meas,
2424
const Eigen::Quaterniond& q_est) {
25-
Eigen::Quaterniond q_err = (q_meas * q_est.inverse()).normalized();
25+
Eigen::Quaterniond q_err = (q_est.inverse() * q_meas).normalized();
2626

2727
if (q_err.w() < 0.0) {
2828
q_err.coeffs() = -q_err.coeffs();
@@ -202,10 +202,42 @@ void LandmarkESKF::landmark_update(const LandmarkMeasurement& landmark_meas) {
202202
return;
203203
}
204204

205-
// Transform VO measurement to navigation frame
205+
// Transform raw VO measurement to navigation frame
206206
Eigen::Vector3d p_nav = p_nav_vo_ + q_nav_vo_ * landmark_meas.pos;
207207
Eigen::Quaterniond q_nav = (q_nav_vo_ * landmark_meas.quat).normalized();
208208

209+
// Measurement Jacobian
210+
Eigen::Matrix<double, 6, 15> H = Eigen::Matrix<double, 6, 15>::Zero();
211+
H.block<3, 3>(0, 0) = Eigen::Matrix3d::Identity();
212+
H.block<3, 3>(3, 6) = Eigen::Matrix3d::Identity();
213+
214+
// Measurement noise with floors applied
215+
Eigen::Matrix<double, 6, 6> R = landmark_meas.R;
216+
const double p_floor_sq = vo_cfg_.pos_floor * vo_cfg_.pos_floor;
217+
const double a_floor_sq = vo_cfg_.att_floor * vo_cfg_.att_floor;
218+
for (int i = 0; i < 3; ++i) {
219+
R(i, i) = std::max(R(i, i), p_floor_sq);
220+
}
221+
for (int i = 3; i < 6; ++i) {
222+
R(i, i) = std::max(R(i, i), a_floor_sq);
223+
}
224+
225+
// Gate on raw measurement
226+
const Eigen::Matrix15d P = current_error_state_.covariance;
227+
const Eigen::Matrix<double, 6, 6> S = H * P * H.transpose() + R;
228+
229+
Eigen::Matrix<double, 6, 1> y_raw;
230+
y_raw.head<3>() = p_nav - current_nom_state_.pos;
231+
y_raw.segment<3>(3) =
232+
compute_quaternion_error(q_nav, current_nom_state_.quat);
233+
234+
const double gate = !gating_enabled_ ? 1e9 : vo_cfg_.nis_gate_pose;
235+
if (compute_nis(y_raw, S) > gate) {
236+
consecutive_rejects_++;
237+
return;
238+
}
239+
240+
// Measurement passed gating
209241
if (vo_cfg_.use_sw) {
210242
sw_add(landmark_meas.stamp, p_nav, q_nav);
211243
sw_prune(landmark_meas.stamp);
@@ -239,41 +271,9 @@ void LandmarkESKF::landmark_update(const LandmarkMeasurement& landmark_meas) {
239271
have_prev_ = true;
240272

241273
Eigen::Matrix<double, 6, 1> y;
242-
243-
// Position innovation
244274
y.head<3>() = p_nav - current_nom_state_.pos;
245275
y.segment<3>(3) = compute_quaternion_error(q_nav, current_nom_state_.quat);
246276

247-
// Measurement Jacobian
248-
Eigen::Matrix<double, 6, 15> H = Eigen::Matrix<double, 6, 15>::Zero();
249-
H.block<3, 3>(0, 0) = Eigen::Matrix3d::Identity();
250-
H.block<3, 3>(3, 6) = Eigen::Matrix3d::Identity();
251-
252-
// Measurement noise floors
253-
Eigen::Matrix<double, 6, 6> R = landmark_meas.R;
254-
255-
const double p_floor_sq = vo_cfg_.pos_floor * vo_cfg_.pos_floor;
256-
const double a_floor_sq = vo_cfg_.att_floor * vo_cfg_.att_floor;
257-
258-
for (int i = 0; i < 3; ++i) {
259-
R(i, i) = std::max(R(i, i), p_floor_sq);
260-
}
261-
for (int i = 3; i < 6; ++i) {
262-
R(i, i) = std::max(R(i, i), a_floor_sq);
263-
}
264-
265-
// Innovation covariance and NIS
266-
const Eigen::Matrix15d P = current_error_state_.covariance;
267-
const Eigen::Matrix<double, 6, 6> S = H * P * H.transpose() + R;
268-
const double nis = compute_nis(y, S);
269-
270-
const double gate = !gating_enabled_ ? 1e9 : vo_cfg_.nis_gate_pose;
271-
272-
if (nis > gate) {
273-
consecutive_rejects_++;
274-
return;
275-
}
276-
277277
Eigen::Matrix<double, 15, 6> K = P * H.transpose() * S.inverse();
278278
current_error_state_.set_from_vector(K * y);
279279

0 commit comments

Comments
 (0)