@@ -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