@@ -443,6 +443,56 @@ TEST_F(SteeringControllersLibraryTest, applies_velocity_limits_to_references)
443443 std::get<1 >(expected_commands)[1 ], 1e-6 );
444444}
445445
446+ TEST_F (SteeringControllersLibraryTest, open_loop_odometry_uses_limited_references)
447+ {
448+ auto node_options = controller_->define_custom_node_options ();
449+ node_options.append_parameter_override (" open_loop" , rclcpp::ParameterValue (true ));
450+ node_options.append_parameter_override (" linear.x.max_velocity" , rclcpp::ParameterValue (0.1 ));
451+ node_options.append_parameter_override (" angular.z.max_velocity" , rclcpp::ParameterValue (0.1 ));
452+ SetUpController (" test_steering_controllers_library" , node_options);
453+
454+ ASSERT_TRUE (configure_succeeds (controller_));
455+ controller_->set_chained_mode (false );
456+ controller_->export_reference_interfaces ();
457+ ASSERT_TRUE (activate_succeeds (controller_));
458+
459+ ControllerReferenceMsg msg;
460+ msg.header .stamp = controller_->get_node ()->now ();
461+ msg.twist .linear .x = 1.5 ;
462+ msg.twist .angular .z = 0.0 ;
463+ controller_->input_ref_ .set (msg);
464+
465+ const double dt = 0.1 ;
466+ ASSERT_EQ (
467+ controller_->update (controller_->get_node ()->now (), rclcpp::Duration::from_seconds (dt)),
468+ controller_interface::return_type::OK );
469+
470+ const double limited_linear = 0.1 ;
471+ const double limited_angular = 0.0 ;
472+
473+ EXPECT_NEAR (controller_->last_linear_velocity_ , limited_linear, 1e-9 );
474+ EXPECT_NEAR (controller_->last_angular_velocity_ , limited_angular, 1e-9 );
475+
476+ // In open-loop mode odometry twist must reflect limited commands, not raw refs.
477+ EXPECT_NEAR (controller_->odom_state_msg_ .twist .twist .linear .x , limited_linear, 1e-6 );
478+ EXPECT_NEAR (controller_->odom_state_msg_ .twist .twist .angular .z , limited_angular, 1e-6 );
479+
480+ // Position integration should use limited open-loop velocity.
481+ EXPECT_NEAR (controller_->odometry_ .get_x (), limited_linear * dt, 1e-6 );
482+ EXPECT_NEAR (controller_->odometry_ .get_y (), 0.0 , 1e-6 );
483+
484+ EXPECT_GT (msg.twist .linear .x , controller_->odom_state_msg_ .twist .twist .linear .x );
485+ EXPECT_DOUBLE_EQ (msg.twist .angular .z , controller_->odom_state_msg_ .twist .twist .angular .z );
486+
487+ msg.header .stamp = controller_->get_node ()->now ();
488+ controller_->input_ref_ .set (msg);
489+ const auto now = controller_->get_node ()->now ();
490+ ASSERT_EQ (
491+ controller_->update (now, rclcpp::Duration::from_seconds (dt)),
492+ controller_interface::return_type::OK );
493+ EXPECT_NEAR (controller_->odometry_ .get_x (), 2.0 * limited_linear * dt, 1e-6 );
494+ }
495+
446496TEST_F (SteeringControllersLibraryTest, test_reset_buffers_clears_limiter_state)
447497{
448498 SetUpController (" test_steering_controllers_library" );
0 commit comments