Skip to content

Commit 1e1d921

Browse files
committed
added changes to account for imus that cancel gravity, added a yaml for real world with some calib for imu bias
1 parent d602153 commit 1e1d921

8 files changed

Lines changed: 155 additions & 11 deletions

File tree

navigation/eskf/config/eskf_params.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,8 @@
2020
publish_tf: true
2121
publish_pose: true
2222
publish_twist: true
23-
publish_rate_ms: 1
23+
publish_rate_ms: 5
24+
add_gravity_to_imu: false
25+
initial_gyro_bias: [0.0, 0.0, 0.0]
26+
initial_accel_bias: [0.0, 0.0, 0.0]
27+
publish_biases: false
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**:
2+
eskf_node:
3+
ros__parameters:
4+
diag_Q_std: [0.05, 0.05, 0.1, 0.01, 0.01, 0.02, 0.001, 0.001, 0.001, 0.0001, 0.0001, 0.0001]
5+
diag_p_init: [1.0, 1.0, 1.0, 0.5, 0.5, 0.5, 0.1, 0.1, 0.1, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001]
6+
transform:
7+
imu_frame_r: [ 1.0, 0.0, 0.0,
8+
0.0, 1.0, 0.0,
9+
0.0, 0.0, 1.0 ]
10+
imu_frame_t: [ 0.0, 0.0, 0.0 ]
11+
12+
dvl_frame_r: [ 0.0, -1.0, 0.0,
13+
1.0, 0.0, 0.0,
14+
0.0, 0.0, 1.0 ]
15+
16+
dvl_frame_t: [ 0.4, 0.0, 0.2 ]
17+
18+
depth_frame_t: [ 0.0, 0.0, 0.0 ]
19+
use_tf_transforms: false
20+
publish_tf: true
21+
publish_pose: true
22+
publish_twist: true
23+
publish_rate_ms: 5
24+
add_gravity_to_imu: true
25+
initial_gyro_bias: [0.0, 0.0, 0.0]
26+
initial_accel_bias: [3.53e-2, 0.0, -0.0533]
27+
publish_biases: true
28+
29+
# USED SENSORS
30+
# IMU: Kongsberg mini MRU
31+
# DVL & Depth: Nucleus 1000

navigation/eskf/include/eskf/eskf.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ class ESKF {
2727

2828
inline double get_nis() const { return nis_; }
2929

30+
inline Eigen::Vector3d get_gravity() const { return g_; }
31+
3032
private:
3133
// @brief Predict the nominal state
3234
// @param imu_meas: IMU measurement

navigation/eskf/include/eskf/eskf_ros.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <geometry_msgs/msg/pose_with_covariance_stamped.hpp>
99
#include <geometry_msgs/msg/transform_stamped.hpp>
1010
#include <geometry_msgs/msg/twist_with_covariance_stamped.hpp>
11+
#include <geometry_msgs/msg/vector3_stamped.hpp>
1112
#include <memory>
1213
#include <nav_msgs/msg/odometry.hpp>
1314
#include <rclcpp/rclcpp.hpp>
@@ -81,6 +82,12 @@ class ESKFNode : public rclcpp::Node {
8182

8283
rclcpp::Publisher<std_msgs::msg::Float64>::SharedPtr nis_depth_pub_;
8384

85+
rclcpp::Publisher<geometry_msgs::msg::Vector3Stamped>::SharedPtr
86+
accel_bias_pub_;
87+
88+
rclcpp::Publisher<geometry_msgs::msg::Vector3Stamped>::SharedPtr
89+
gyro_bias_pub_;
90+
8491
// Member variable for the ESKF instance
8592

8693
std::chrono::milliseconds time_step_{1};
@@ -121,6 +128,8 @@ class ESKFNode : public rclcpp::Node {
121128
bool publish_tf_{false};
122129
bool publish_pose_{false};
123130
bool publish_twist_{false};
131+
bool publish_biases_{false};
132+
bool add_gravity_to_imu_{false};
124133

125134
// hold the transfer from Sensor -> Base Link
126135
Eigen::Isometry3d Tf_base_imu_ = Eigen::Isometry3d::Identity();

navigation/eskf/include/eskf/typedefs.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ struct EskfParams {
9999
Eigen::Matrix12d Q = Eigen::Matrix12d::Zero();
100100
Eigen::Matrix15d P = Eigen::Matrix15d::Zero();
101101
Eigen::Vector3d g_{0.0, 0.0, -9.81};
102+
Eigen::Vector3d initial_gyro_bias = Eigen::Vector3d::Zero();
103+
Eigen::Vector3d initial_accel_bias = Eigen::Vector3d::Zero();
102104
};
103105
struct ImuMeasurement {
104106
Eigen::Vector3d accel = Eigen::Vector3d::Zero();

navigation/eskf/launch/eskf.launch.py

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
import os
2-
from os import path
32

43
from ament_index_python.packages import get_package_share_directory
54
from launch import LaunchDescription
6-
from launch.actions import OpaqueFunction
5+
from launch.actions import DeclareLaunchArgument, OpaqueFunction
6+
from launch.substitutions import LaunchConfiguration
77
from launch_ros.actions import Node
88

99
from auv_setup.launch_arg_common import (
1010
declare_drone_and_namespace_args,
1111
resolve_drone_and_namespace,
1212
)
1313

14-
eskf_params = path.join(
15-
get_package_share_directory("eskf"), "config", "eskf_params.yaml"
16-
)
14+
# eskf_params = path.join(
15+
# get_package_share_directory("eskf"), "config", "eskf_params_real_world.yaml"
16+
# )
1717

1818

1919
def launch_setup(context, *args, **kwargs):
@@ -25,6 +25,18 @@ def launch_setup(context, *args, **kwargs):
2525
"robots",
2626
f"{drone}.yaml",
2727
)
28+
29+
use_sim = LaunchConfiguration('use_sim').perform(context).lower() == 'true'
30+
31+
if use_sim:
32+
param_file_name = "eskf_params.yaml"
33+
else:
34+
param_file_name = "eskf_params_real_world.yaml"
35+
36+
eskf_params = os.path.join(
37+
get_package_share_directory("eskf"), "config", param_file_name
38+
)
39+
2840
drone_env_params = os.path.join(
2941
get_package_share_directory("auv_setup"),
3042
"config",
@@ -49,7 +61,13 @@ def launch_setup(context, *args, **kwargs):
4961

5062

5163
def generate_launch_description():
52-
# This function defines WHAT to do, but doesn't execute the logic yet
64+
sim_arg = DeclareLaunchArgument(
65+
'use_sim',
66+
default_value='false',
67+
description='Set to "false" to load real-world hardware parameters.',
68+
)
5369
return LaunchDescription(
54-
declare_drone_and_namespace_args() + [OpaqueFunction(function=launch_setup)]
70+
[sim_arg]
71+
+ declare_drone_and_namespace_args()
72+
+ [OpaqueFunction(function=launch_setup)]
5573
)

navigation/eskf/src/eskf.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ ESKF::ESKF(const EskfParams& params) : Q_(params.Q) {
1919

2020
// Initialize Nominal Quaternion to Identity
2121
current_nom_state_.quat = Eigen::Quaterniond::Identity();
22+
// Initialize nominal bias values
23+
current_nom_state_.gyro_bias = params.initial_gyro_bias;
24+
current_nom_state_.accel_bias = params.initial_accel_bias;
2225
}
2326

2427
std::pair<Eigen::Matrix15d, Eigen::Matrix15d> ESKF::van_loan_discretization(
@@ -205,7 +208,7 @@ Eigen::VectorXd SensorDepth::innovation(const StateQuat& state) const {
205208
return innovation;
206209
}
207210

208-
Eigen::MatrixXd SensorDepth::jacobian(const StateQuat& state) const {
211+
Eigen::MatrixXd SensorDepth::jacobian(const StateQuat& /*state*/) const {
209212
Eigen::MatrixXd H = Eigen::MatrixXd::Zero(1, 15);
210213
H(0, 2) = 1.0;
211214
return H;

navigation/eskf/src/eskf_ros.cpp

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

160205
void 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

339413
void 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

Comments
 (0)