Skip to content

Commit e9e0d70

Browse files
committed
Improve Nav2 integration: EKF covariance, IMU remap, optional bond
- fillPoseCovariance: use EKF P matrix when available, fall back to fitness-based estimate for smoother/standard paths - Add /imu topic remapping to base launch file - Add optional Nav2 bond connection (requires nav2_util + bondcpp, auto-detected via CMake find_package QUIET) - Bond starts on activate, stops on deactivate Nav2 checklist: [x] Lifecycle node (configure/activate/deactivate) [x] /initialpose subscription [x] PoseWithCovarianceStamped with covariance [x] map->odom TF (enable_map_odom_tf: true) [x] Nav2 launch file with proper remappings [x] Optional bond for lifecycle manager health monitoring [x] IMU topic remapping
1 parent 6a5adf6 commit e9e0d70

4 files changed

Lines changed: 66 additions & 16 deletions

File tree

CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ find_package(pcl_conversions REQUIRED)
2626
find_package(PCL REQUIRED)
2727
find_package(ndt_omp_ros2 REQUIRED)
2828
find_package(small_gicp QUIET CONFIG)
29+
find_package(nav2_util QUIET)
30+
find_package(bondcpp QUIET)
2931
find_package(OpenMP)
3032

3133
if (OPENMP_FOUND)
@@ -57,6 +59,12 @@ if(small_gicp_FOUND)
5759
target_link_libraries(lidar_localization_component small_gicp::small_gicp)
5860
endif()
5961

62+
if(nav2_util_FOUND AND bondcpp_FOUND)
63+
target_compile_definitions(lidar_localization_component PRIVATE LIDAR_LOCALIZATION_HAVE_NAV2_BOND=1)
64+
ament_target_dependencies(lidar_localization_component nav2_util bondcpp)
65+
message(STATUS "Nav2 bond support enabled")
66+
endif()
67+
6068

6169

6270
include_directories(

include/lidar_localization/lidar_localization_component.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@
5151
#include "lidar_localization/twist_gtsam_smoother.hpp"
5252
#include "lidar_localization/imu_gtsam_smoother.hpp"
5353

54+
#ifdef LIDAR_LOCALIZATION_HAVE_NAV2_BOND
55+
#include "bondcpp/bond.hpp"
56+
#endif
57+
5458
using namespace std::chrono_literals;
5559

5660
class PCLLocalization : public rclcpp_lifecycle::LifecycleNode
@@ -135,6 +139,12 @@ class PCLLocalization : public rclcpp_lifecycle::LifecycleNode
135139
double last_imu_stamp_{0.0};
136140
double last_scan_stamp_for_imu_{0.0};
137141

142+
#ifdef LIDAR_LOCALIZATION_HAVE_NAV2_BOND
143+
// Nav2 lifecycle manager bond
144+
std::unique_ptr<bond::Bond> bond_;
145+
bool use_bond_{false};
146+
#endif
147+
138148
// parameters
139149
std::string global_frame_id_;
140150
std::string odom_frame_id_;

launch/lidar_localization.launch.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,17 @@ def generate_launch_description():
4646
twist_topic = launch.substitutions.LaunchConfiguration(
4747
'twist_topic',
4848
default='/twist')
49+
imu_topic = launch.substitutions.LaunchConfiguration(
50+
'imu_topic',
51+
default='/imu')
4952

5053
lidar_localization = launch_ros.actions.LifecycleNode(
5154
name='lidar_localization',
5255
namespace='',
5356
package='lidar_localization_ros2',
5457
executable='lidar_localization_node',
5558
parameters=[localization_param_dir],
56-
remappings=[('/cloud', cloud_topic), ('/twist', twist_topic)],
59+
remappings=[('/cloud', cloud_topic), ('/twist', twist_topic), ('/imu', imu_topic)],
5760
output='screen')
5861

5962
to_inactive = launch.actions.EmitEvent(

src/lidar_localization_component.cpp

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,17 @@ CallbackReturn PCLLocalization::on_activate(const rclcpp_lifecycle::State &)
272272
map_recieved_ = true;
273273
}
274274

275+
// Start Nav2 bond if available
276+
#ifdef LIDAR_LOCALIZATION_HAVE_NAV2_BOND
277+
if (use_bond_) {
278+
bond_ = std::make_unique<bond::Bond>("bond", get_name(), shared_from_this());
279+
bond_->setHeartbeatPeriod(0.1);
280+
bond_->setHeartbeatTimeout(4.0);
281+
bond_->start();
282+
RCLCPP_INFO(get_logger(), "Nav2 bond started");
283+
}
284+
#endif
285+
275286
RCLCPP_INFO(get_logger(), "Activating end");
276287
return CallbackReturn::SUCCESS;
277288
}
@@ -280,6 +291,13 @@ CallbackReturn PCLLocalization::on_deactivate(const rclcpp_lifecycle::State &)
280291
{
281292
RCLCPP_INFO(get_logger(), "Deactivating");
282293

294+
#ifdef LIDAR_LOCALIZATION_HAVE_NAV2_BOND
295+
if (bond_) {
296+
bond_.reset();
297+
RCLCPP_INFO(get_logger(), "Nav2 bond stopped");
298+
}
299+
#endif
300+
283301
pose_pub_->on_deactivate();
284302
path_pub_->on_deactivate();
285303
status_pub_->on_deactivate();
@@ -1322,25 +1340,36 @@ void PCLLocalization::advancePredictionWithoutMeasurement(double stamp_sec)
13221340

13231341
void PCLLocalization::fillPoseCovariance(double fitness_score)
13241342
{
1325-
// Set covariance from fitness score for Nav2 compatibility
1326-
// Nav2 PoseWithCovarianceStamped.pose.covariance is a 6x6 row-major array [36]
1343+
// Nav2 PoseWithCovarianceStamped.pose.covariance: 6x6 row-major [36]
13271344
// Indices: [0]=xx, [7]=yy, [14]=zz, [21]=roll, [28]=pitch, [35]=yaw
13281345
auto & cov = corrent_pose_with_cov_stamped_ptr_->pose.covariance;
13291346
std::fill(cov.begin(), cov.end(), 0.0);
13301347

1331-
// Base uncertainty from fitness score (higher fitness = more uncertainty)
1332-
double scale = std::max(1.0, fitness_score / 1.0);
1333-
double pos_var = 0.01 * scale; // ~0.1m std at fitness=1.0
1334-
double z_var = 0.05 * scale;
1335-
double rp_var = 0.001 * scale; // ~1.8deg std at fitness=1.0
1336-
double yaw_var = 0.0005 * scale; // ~1.3deg std at fitness=1.0
1337-
1338-
cov[0] = pos_var; // x
1339-
cov[7] = pos_var; // y
1340-
cov[14] = z_var; // z
1341-
cov[21] = rp_var; // roll
1342-
cov[28] = rp_var; // pitch
1343-
cov[35] = yaw_var; // yaw
1348+
// Use EKF covariance matrix if available (most accurate)
1349+
if (use_twist_ekf_ && twist_ekf_.isInitialized()) {
1350+
const auto & P = twist_ekf_.covariance();
1351+
// EKF state: [px,py,pz,vx,vy,vz,yaw,gyro_bias,speed_bias]
1352+
cov[0] = P(0, 0); // xx
1353+
cov[1] = P(0, 1); // xy
1354+
cov[6] = P(1, 0); // yx
1355+
cov[7] = P(1, 1); // yy
1356+
cov[14] = P(2, 2); // zz
1357+
cov[35] = P(6, 6); // yaw-yaw
1358+
// roll/pitch not estimated by EKF — use fitness-based estimate
1359+
double scale = std::max(1.0, fitness_score);
1360+
cov[21] = 0.001 * scale;
1361+
cov[28] = 0.001 * scale;
1362+
return;
1363+
}
1364+
1365+
// Fitness-based covariance for smoother / standard paths
1366+
double scale = std::max(1.0, fitness_score);
1367+
cov[0] = 0.01 * scale; // x
1368+
cov[7] = 0.01 * scale; // y
1369+
cov[14] = 0.05 * scale; // z
1370+
cov[21] = 0.001 * scale; // roll
1371+
cov[28] = 0.001 * scale; // pitch
1372+
cov[35] = 0.0005 * scale; // yaw
13441373
}
13451374

13461375
void PCLLocalization::publishAlignmentStatus(

0 commit comments

Comments
 (0)