Skip to content

Commit e887e24

Browse files
committed
Added ins origin logic. Rotated tf2 dvl frame
1 parent cfa05ed commit e887e24

7 files changed

Lines changed: 52 additions & 38 deletions

File tree

auv_setup/description/nautilus.urdf.xacro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
<joint name="base_to_dvl" type="fixed">
2626
<parent link="base_link"/>
2727
<child link="dvl_link"/>
28-
<origin xyz="-0.130 0.003 0.2414" rpy="0.0 0.0 0.0"/>
28+
<origin xyz="-0.130 0.003 0.2414" rpy="0.0 0.0 3.14159"/>
2929
</joint>
3030

3131
<!-- base to pressure sensor -->

auv_setup/launch/nucleus_odom_transformer.launch.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ def launch_setup(context, *args, **kwargs):
4646
parameters=[
4747
{
4848
"frame_id": f"{namespace}/nucleus_frame",
49+
"qos": "best_effort",
4950
"connection_params.remote_ip": "10.0.0.42",
5051
"connection_params.data_remote_port": 9000,
5152
"connection_params.password": "",
52-
"reset_pose_on_start": True,
5353
"enable_imu": True,
5454
"enable_ins_odom": True,
5555
"enable_dvl": True,
@@ -78,7 +78,7 @@ def launch_setup(context, *args, **kwargs):
7878
"altimeter_settings.power_level": 0, # 0=default
7979
"magnetometer_settings.freq": 75,
8080
"magnetometer_settings.mode": 0,
81-
"instrument_settings.rotxy": 180.0, # Transform currently not working. Maybe fix later
81+
"instrument_settings.rotxy": 0.0, # Transform currently not working. Maybe fix later
8282
"instrument_settings.rotyz": 0.0,
8383
"instrument_settings.rotxz": 0.0,
8484
},
@@ -98,7 +98,6 @@ def launch_setup(context, *args, **kwargs):
9898
"publish_tf": True,
9999
"publish_pose": True,
100100
"publish_twist": True,
101-
"rotate_yaw_180": True,
102101
"topics.input": f"/{namespace}/nucleus/odom",
103102
"topics.output": f"/{namespace}/odom",
104103
"topics.pose": f"/{namespace}/pose",

auv_setup/launch/state_estimation.launch.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,10 @@ def launch_setup(context, *args, **kwargs):
151151
parameters=[
152152
{
153153
"frame_id": f"/{namespace}/nucleus_frame",
154+
"qos": "best_effort",
154155
"connection_params.remote_ip": "10.0.0.42",
155156
"connection_params.data_remote_port": 9000,
156157
"connection_params.password": "",
157-
"reset_pose_on_start": True,
158158
"enable_imu": False,
159159
"enable_ins_odom": False,
160160
"enable_dvl": True,
@@ -183,7 +183,7 @@ def launch_setup(context, *args, **kwargs):
183183
"fast_pressure_settings.sampling_rate": 16,
184184
"magnetometer_settings.freq": 75,
185185
"magnetometer_settings.mode": 0,
186-
"instrument_settings.rotxy": 180.0, # Transform currently not working. Maybe fix later
186+
"instrument_settings.rotxy": 0.0, # Transform currently not working. Maybe fix later
187187
"instrument_settings.rotyz": 0.0,
188188
"instrument_settings.rotxz": 0.0,
189189
}

auv_setup/launch/topside.launch.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
from ament_index_python.packages import get_package_share_directory
44
from launch import LaunchDescription
55
from launch.actions import (
6+
DeclareLaunchArgument,
67
IncludeLaunchDescription,
78
OpaqueFunction,
89
SetEnvironmentVariable,
910
)
1011
from launch.launch_description_sources import PythonLaunchDescriptionSource
12+
from launch.substitutions import LaunchConfiguration
1113
from launch_ros.actions import Node
1214

1315
from auv_setup.launch_arg_common import (
@@ -19,6 +21,7 @@
1921
def launch_setup(context, *args, **kwargs):
2022
"""Set up the topside nodes with drone-specific namespace."""
2123
drone, namespace = resolve_drone_and_namespace(context)
24+
orientation_mode = LaunchConfiguration("orientation_mode").perform(context)
2225

2326
joy_node = Node(
2427
package="joy",
@@ -43,6 +46,7 @@ def launch_setup(context, *args, **kwargs):
4346
launch_arguments={
4447
"drone": drone,
4548
"namespace": namespace,
49+
"orientation_mode": orientation_mode,
4650
}.items(),
4751
)
4852

@@ -68,5 +72,12 @@ def generate_launch_description() -> LaunchDescription:
6872
return LaunchDescription(
6973
[set_env_var]
7074
+ declare_drone_and_namespace_args()
71-
+ [OpaqueFunction(function=launch_setup)]
75+
+ [
76+
DeclareLaunchArgument(
77+
"orientation_mode",
78+
default_value="euler",
79+
description="Reference orientation representation: 'euler' (ReferenceFilter) or 'quat' (ReferenceFilterQuat)",
80+
),
81+
OpaqueFunction(function=launch_setup),
82+
]
7283
)

navigation/odom_transformer/config/odom_transformer_params.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
publish_tf: true
66
publish_pose: true
77
publish_twist: true
8-
rotate_yaw_180: false
98
topics:
109
input: "nucleus/odom"
1110
output: "odom"

navigation/odom_transformer/include/odom_transformer/odom_transformer.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,17 @@ class OdomTransformer : public rclcpp::Node {
4545
Eigen::Matrix3d R_base_sensor_ = Eigen::Matrix3d::Identity();
4646
Eigen::Vector3d t_base_sensor_ = Eigen::Vector3d::Zero();
4747

48+
// Odom origin — first received base_link pose in the sensor's world frame
49+
bool origin_set_{false};
50+
Eigen::Matrix3d R_origin_ = Eigen::Matrix3d::Identity();
51+
Eigen::Vector3d p_origin_ = Eigen::Vector3d::Zero();
52+
4853
std::string frame_prefix_;
4954
std::string sensor_frame_;
5055
bool tf_loaded_{false};
5156
bool publish_tf_{false};
5257
bool publish_pose_{false};
5358
bool publish_twist_{false};
54-
bool rotate_yaw_180_{false};
5559
};
5660

5761
#endif // ODOM_TRANSFORMER__ODOM_TRANSFORMER_HPP_

navigation/odom_transformer/src/odom_transformer.cpp

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ OdomTransformer::OdomTransformer(const rclcpp::NodeOptions& options)
2222
this->declare_parameter<std::string>("topics.output");
2323
this->declare_parameter<std::string>("topics.pose");
2424
this->declare_parameter<std::string>("topics.twist");
25-
rotate_yaw_180_ = this->declare_parameter<bool>("rotate_yaw_180");
26-
2725
tf_buffer_ = std::make_shared<tf2_ros::Buffer>(this->get_clock());
2826
tf_listener_ = std::make_shared<tf2_ros::TransformListener>(*tf_buffer_);
2927
tf_timer_ = this->create_wall_timer(
@@ -40,10 +38,15 @@ void OdomTransformer::lookup_static_transforms() {
4038

4139
tf_loaded_ = true;
4240
tf_timer_->cancel();
41+
42+
Eigen::Vector3d rpy =
43+
R_base_sensor_.eulerAngles(2, 1, 0).reverse() * 180.0 / M_PI;
4344
RCLCPP_INFO(get_logger(),
44-
"Loaded static transform: %s -> %s t=(%.3f, %.3f, %.3f)",
45+
"Loaded static transform: %s -> %s "
46+
"t=(%.3f, %.3f, %.3f) rpy=(%.1f, %.1f, %.1f) deg",
4547
frame("base_link").c_str(), frame(sensor_frame_).c_str(),
46-
t_base_sensor_.x(), t_base_sensor_.y(), t_base_sensor_.z());
48+
t_base_sensor_.x(), t_base_sensor_.y(), t_base_sensor_.z(),
49+
rpy.x(), rpy.y(), rpy.z());
4750
complete_initialization();
4851
} catch (const tf2::TransformException& ex) {
4952
RCLCPP_WARN(get_logger(), "TF lookup failed (will retry): %s",
@@ -96,32 +99,30 @@ void OdomTransformer::odom_callback(
9699
msg->twist.twist.angular.y,
97100
msg->twist.twist.angular.z);
98101

99-
if (rotate_yaw_180_) {
100-
// 180 deg yaw flips X and Y, leaves Z unchanged
101-
q_odom_sensor = Eigen::Quaterniond(
102-
Eigen::AngleAxisd(M_PI, Eigen::Vector3d::UnitZ())) *
103-
q_odom_sensor;
104-
v_sensor.x() = -v_sensor.x();
105-
v_sensor.y() = -v_sensor.y();
106-
omega_sensor.x() = -omega_sensor.x();
107-
omega_sensor.y() = -omega_sensor.y();
108-
msg->pose.pose.position.x = -msg->pose.pose.position.x;
109-
msg->pose.pose.position.y = -msg->pose.pose.position.y;
110-
}
111-
112102
Eigen::Matrix3d R_odom_sensor = q_odom_sensor.toRotationMatrix();
113103

114104
// Orientation: R_odom_base = R_odom_sensor * R_base_sensor^-1
115105
Eigen::Matrix3d R_odom_base = R_odom_sensor * R_base_sensor_.transpose();
116-
Eigen::Quaterniond q_odom_base(R_odom_base);
117-
q_odom_base.normalize();
118106

119107
// Position: p_base = p_sensor - R_odom_base * t_base_sensor
120108
Eigen::Vector3d p_sensor(msg->pose.pose.position.x,
121109
msg->pose.pose.position.y,
122110
msg->pose.pose.position.z);
123111
Eigen::Vector3d p_base = p_sensor - R_odom_base * t_base_sensor_;
124112

113+
// Capture the first base_link pose as the odom frame origin
114+
if (!origin_set_) {
115+
R_origin_ = R_odom_base;
116+
p_origin_ = p_base;
117+
origin_set_ = true;
118+
}
119+
120+
// Express pose relative to origin so t=0 is identity
121+
Eigen::Matrix3d R_out = R_origin_.transpose() * R_odom_base;
122+
Eigen::Vector3d p_out = R_origin_.transpose() * (p_base - p_origin_);
123+
Eigen::Quaterniond q_out(R_out);
124+
q_out.normalize();
125+
125126
// Angular velocity: rotate from sensor frame to base_link frame
126127
Eigen::Vector3d omega_base = R_base_sensor_ * omega_sensor;
127128

@@ -136,13 +137,13 @@ void OdomTransformer::odom_callback(
136137
out->header.frame_id = frame("odom");
137138
out->child_frame_id = frame("base_link");
138139

139-
out->pose.pose.position.x = p_base.x();
140-
out->pose.pose.position.y = p_base.y();
141-
out->pose.pose.position.z = p_base.z();
142-
out->pose.pose.orientation.w = q_odom_base.w();
143-
out->pose.pose.orientation.x = q_odom_base.x();
144-
out->pose.pose.orientation.y = q_odom_base.y();
145-
out->pose.pose.orientation.z = q_odom_base.z();
140+
out->pose.pose.position.x = p_out.x();
141+
out->pose.pose.position.y = p_out.y();
142+
out->pose.pose.position.z = p_out.z();
143+
out->pose.pose.orientation.w = q_out.w();
144+
out->pose.pose.orientation.x = q_out.x();
145+
out->pose.pose.orientation.y = q_out.y();
146+
out->pose.pose.orientation.z = q_out.z();
146147

147148
out->twist.twist.linear.x = v_base.x();
148149
out->twist.twist.linear.y = v_base.y();
@@ -176,9 +177,9 @@ void OdomTransformer::odom_callback(
176177
tf_msg.header.stamp = msg->header.stamp;
177178
tf_msg.header.frame_id = frame("odom");
178179
tf_msg.child_frame_id = frame("base_link");
179-
tf_msg.transform.translation.x = p_base.x();
180-
tf_msg.transform.translation.y = p_base.y();
181-
tf_msg.transform.translation.z = p_base.z();
180+
tf_msg.transform.translation.x = p_out.x();
181+
tf_msg.transform.translation.y = p_out.y();
182+
tf_msg.transform.translation.z = p_out.z();
182183
tf_msg.transform.rotation = out->pose.pose.orientation;
183184
tf_broadcaster_->sendTransform(tf_msg);
184185
}

0 commit comments

Comments
 (0)