@@ -22,6 +22,7 @@ ESKFNode::ESKFNode(const rclcpp::NodeOptions& options)
2222 if (!frame_prefix_.empty () && frame_prefix_.back () == ' /' ) {
2323 frame_prefix_.pop_back ();
2424 }
25+ spdlog::info (" frame_prefix set to '{}'" , frame_prefix_);
2526
2627 publish_tf_ = this ->declare_parameter <bool >(" publish_tf" );
2728 if (publish_tf_) {
@@ -32,6 +33,8 @@ ESKFNode::ESKFNode(const rclcpp::NodeOptions& options)
3233 publish_pose_ = this ->declare_parameter <bool >(" publish_pose" );
3334 publish_twist_ = this ->declare_parameter <bool >(" publish_twist" );
3435
36+ publish_biases_ = this ->declare_parameter <bool >(" publish_biases" );
37+
3538 // Declare these here so they appear in `ros2 param list` from startup,
3639 // even though they are read in complete_initialization().
3740 this ->declare_parameter <int >(" publish_rate_ms" );
@@ -95,6 +98,15 @@ void ESKFNode::set_subscribers_and_publisher() {
9598 qos_sensor_data);
9699 }
97100
101+ if (publish_biases_) {
102+ accel_bias_pub_ =
103+ this ->create_publisher <geometry_msgs::msg::Vector3Stamped>(
104+ " eskf/accel_bias" , qos_sensor_data);
105+ gyro_bias_pub_ =
106+ this ->create_publisher <geometry_msgs::msg::Vector3Stamped>(
107+ " eskf/gyro_bias" , qos_sensor_data);
108+ }
109+
98110#ifndef NDEBUG
99111 nis_dvl_pub_ = create_publisher<std_msgs::msg::Float64>(
100112 " eskf/nis_dvl" , vortex::utils::qos_profiles::reliable_profile ());
@@ -111,6 +123,11 @@ void ESKFNode::set_parameters() {
111123 R_imu_eskf_ = Eigen::Map<Eigen::Matrix<double , 3 , 3 , Eigen::RowMajor>>(
112124 R_imu_correction.data ());
113125
126+ std::vector<double > T_imu_correction =
127+ this ->declare_parameter <std::vector<double >>(
128+ " transform.imu_frame_t" );
129+ T_imu_eskf_ = Eigen::Map<Eigen::Vector3d>(T_imu_correction.data ());
130+
114131 std::vector<double > R_dvl_correction =
115132 this ->declare_parameter <std::vector<double >>(
116133 " transform.dvl_frame_r" );
@@ -152,9 +169,37 @@ void ESKFNode::set_parameters() {
152169
153170 Eigen::Vector3d g_vec (0.0 , 0.0 , this ->gravity );
154171
155- EskfParams eskf_params{.Q = Q, .P = P, .g_ = g_vec};
172+ std::vector<double > initial_gyro_bias =
173+ this ->declare_parameter <std::vector<double >>(
174+ " initial_gyro_bias" , std::vector<double >{0.0 , 0.0 , 0.0 });
175+ spdlog::info (" initial_gyro_bias: [{}, {}, {}]" , initial_gyro_bias[0 ],
176+ initial_gyro_bias[1 ], initial_gyro_bias[2 ]);
177+ if (initial_gyro_bias.size () != 3 ) {
178+ throw std::runtime_error (" initial_gyro_bias must have length 3" );
179+ }
180+
181+ std::vector<double > initial_accel_bias =
182+ this ->declare_parameter <std::vector<double >>(
183+ " initial_accel_bias" , std::vector<double >{0.0 , 0.0 , 0.0 });
184+ spdlog::info (" initial_accel_bias: [{}, {}, {}]" , initial_accel_bias[0 ],
185+ initial_accel_bias[1 ], initial_accel_bias[2 ]);
186+ if (initial_accel_bias.size () != 3 ) {
187+ throw std::runtime_error (" initial_accel_bias must have length 3" );
188+ }
189+
190+ EskfParams eskf_params{
191+ .Q = Q,
192+ .P = P,
193+ .g_ = g_vec,
194+ .initial_gyro_bias =
195+ Eigen::Map<Eigen::Vector3d>(initial_gyro_bias.data ()),
196+ .initial_accel_bias =
197+ Eigen::Map<Eigen::Vector3d>(initial_accel_bias.data ())};
156198
157199 eskf_ = std::make_unique<ESKF >(eskf_params);
200+
201+ add_gravity_to_imu_ = this ->declare_parameter <bool >(" add_gravity_to_imu" );
202+ spdlog::info (" add_gravity_to_imu: {}" , add_gravity_to_imu_);
158203}
159204
160205void ESKFNode::imu_callback (const sensor_msgs::msg::Imu::SharedPtr msg) {
@@ -192,7 +237,14 @@ void ESKFNode::imu_callback(const sensor_msgs::msg::Imu::SharedPtr msg) {
192237
193238 // a_corrected = a_meas - omega x (omega x T)
194239 Eigen::Vector3d centripetal_accel = omega.cross (omega.cross (T_imu_eskf_));
195- imu_measurement.accel = accel_aligned - centripetal_accel;
240+ accel_aligned -= centripetal_accel;
241+
242+ if (add_gravity_to_imu_) {
243+ Eigen::Matrix3d R = nom_state.quat .normalized ().toRotationMatrix ();
244+ accel_aligned -= R.transpose () * eskf_->get_gravity ();
245+ }
246+
247+ imu_measurement.accel = accel_aligned;
196248
197249 // save latest gyro readings (used for DVL correction and odom output)
198250 latest_gyro_measurement_ = imu_measurement.gyro ;
@@ -334,13 +386,36 @@ void ESKFNode::publish_odom() {
334386 if (publish_tf_) {
335387 publish_tf (nom_state, current_time);
336388 }
389+
390+ if (publish_biases_) {
391+ geometry_msgs::msg::Vector3Stamped accel_bias_msg;
392+ accel_bias_msg.header .stamp = current_time;
393+ accel_bias_msg.header .frame_id =
394+ frame (" base_link" ); // Biases are in the body frame
395+
396+ accel_bias_msg.vector .x = nom_state.accel_bias .x ();
397+ accel_bias_msg.vector .y = nom_state.accel_bias .y ();
398+ accel_bias_msg.vector .z = nom_state.accel_bias .z ();
399+
400+ accel_bias_pub_->publish (accel_bias_msg);
401+
402+ geometry_msgs::msg::Vector3Stamped gyro_bias_msg;
403+ gyro_bias_msg.header = accel_bias_msg.header ;
404+
405+ gyro_bias_msg.vector .x = nom_state.gyro_bias .x ();
406+ gyro_bias_msg.vector .y = nom_state.gyro_bias .y ();
407+ gyro_bias_msg.vector .z = nom_state.gyro_bias .z ();
408+
409+ gyro_bias_pub_->publish (gyro_bias_msg);
410+ }
337411}
338412
339413void ESKFNode::lookup_static_transforms () {
340414 try {
341415 Tf_base_imu_ = tf2::transformToEigen (tf_buffer_->lookupTransform (
342416 frame (" base_link" ), frame (" imu_link" ), tf2::TimePointZero));
343417 R_imu_eskf_ = Tf_base_imu_.rotation ();
418+ T_imu_eskf_ = Tf_base_imu_.translation ();
344419
345420 Tf_base_dvl_ = tf2::transformToEigen (tf_buffer_->lookupTransform (
346421 frame (" base_link" ), frame (" dvl_link" ), tf2::TimePointZero));
0 commit comments