@@ -271,7 +271,7 @@ class DummySensor : public hardware_interface::SensorInterface
271271 // We can read some voltage level
272272 std::vector<hardware_interface::StateInterface> state_interfaces;
273273 state_interfaces.emplace_back (
274- hardware_interface::StateInterface (" joint1 " , " voltage" , &voltage_level_));
274+ hardware_interface::StateInterface (" sens1 " , " voltage" , &voltage_level_));
275275
276276 return state_interfaces;
277277 }
@@ -332,15 +332,72 @@ class DummySensorDefault : public hardware_interface::SensorInterface
332332
333333 CallbackReturn on_configure (const rclcpp_lifecycle::State & /* previous_state*/ ) override
334334 {
335- for (const auto & [name, descr] : sensor_state_interfaces_)
335+ set_state (" sens1/voltage" , 0.0 );
336+ read_calls_ = 0 ;
337+ return CallbackReturn::SUCCESS;
338+ }
339+
340+ std::string get_name () const override { return " DummySensorDefault" ; }
341+
342+ hardware_interface::return_type read (
343+ const rclcpp::Time & /* time*/ , const rclcpp::Duration & /* period*/ ) override
344+ {
345+ ++read_calls_;
346+ if (read_calls_ == TRIGGER_READ_WRITE_ERROR_CALLS)
347+ {
348+ return hardware_interface::return_type::ERROR;
349+ }
350+
351+ // no-op, static value
352+ set_state (" sens1/voltage" , voltage_level_hw_value_);
353+ return hardware_interface::return_type::OK;
354+ }
355+
356+ CallbackReturn on_error (const rclcpp_lifecycle::State & /* previous_state*/ ) override
357+ {
358+ if (!recoverable_error_happened_)
359+ {
360+ recoverable_error_happened_ = true ;
361+ return CallbackReturn::SUCCESS;
362+ }
363+ else
364+ {
365+ return CallbackReturn::ERROR;
366+ }
367+ return CallbackReturn::FAILURE;
368+ }
369+
370+ private:
371+ double voltage_level_hw_value_ = 0x666 ;
372+
373+ // Helper variables to initiate error on read
374+ int read_calls_ = 0 ;
375+ bool recoverable_error_happened_ = false ;
376+ };
377+
378+ class DummySensorJointDefault : public hardware_interface ::SensorInterface
379+ {
380+ CallbackReturn on_init (const hardware_interface::HardwareInfo & info) override
381+ {
382+ if (
383+ hardware_interface::SensorInterface::on_init (info) !=
384+ hardware_interface::CallbackReturn::SUCCESS)
336385 {
337- set_state (name, 0.0 ) ;
386+ return hardware_interface::CallbackReturn::ERROR ;
338387 }
388+
389+ return CallbackReturn::SUCCESS;
390+ }
391+
392+ CallbackReturn on_configure (const rclcpp_lifecycle::State & /* previous_state*/ ) override
393+ {
394+ set_state (" joint1/position" , 10.0 );
395+ set_state (" sens1/voltage" , 0.0 );
339396 read_calls_ = 0 ;
340397 return CallbackReturn::SUCCESS;
341398 }
342399
343- std::string get_name () const override { return " DummySensorDefault " ; }
400+ std::string get_name () const override { return " DummySensorJointDefault " ; }
344401
345402 hardware_interface::return_type read (
346403 const rclcpp::Time & /* time*/ , const rclcpp::Duration & /* period*/ ) override
@@ -352,7 +409,8 @@ class DummySensorDefault : public hardware_interface::SensorInterface
352409 }
353410
354411 // no-op, static value
355- set_state (" joint1/voltage" , voltage_level_hw_value_);
412+ set_state (" joint1/position" , position_hw_value_);
413+ set_state (" sens1/voltage" , voltage_level_hw_value_);
356414 return hardware_interface::return_type::OK;
357415 }
358416
@@ -371,6 +429,7 @@ class DummySensorDefault : public hardware_interface::SensorInterface
371429 }
372430
373431private:
432+ double position_hw_value_ = 0x777 ;
374433 double voltage_level_hw_value_ = 0x666 ;
375434
376435 // Helper variables to initiate error on read
@@ -907,9 +966,9 @@ TEST(TestComponentInterfaces, dummy_sensor)
907966
908967 auto state_interfaces = sensor_hw.export_state_interfaces ();
909968 ASSERT_EQ (1u , state_interfaces.size ());
910- EXPECT_EQ (" joint1 /voltage" , state_interfaces[0 ]->get_name ());
969+ EXPECT_EQ (" sens1 /voltage" , state_interfaces[0 ]->get_name ());
911970 EXPECT_EQ (" voltage" , state_interfaces[0 ]->get_interface_name ());
912- EXPECT_EQ (" joint1 " , state_interfaces[0 ]->get_prefix_name ());
971+ EXPECT_EQ (" sens1 " , state_interfaces[0 ]->get_prefix_name ());
913972 EXPECT_TRUE (std::isnan (state_interfaces[0 ]->get_value ()));
914973
915974 // Not updated because is is UNCONFIGURED
@@ -948,29 +1007,83 @@ TEST(TestComponentInterfaces, dummy_sensor_default)
9481007 auto state_interfaces = sensor_hw.export_state_interfaces ();
9491008 ASSERT_EQ (1u , state_interfaces.size ());
9501009 {
951- auto [contains, position] =
952- test_components::vector_contains (state_interfaces, " joint1/voltage" );
1010+ auto [contains, position] = test_components::vector_contains (state_interfaces, " sens1/voltage" );
9531011 EXPECT_TRUE (contains);
954- EXPECT_EQ (" joint1 /voltage" , state_interfaces[position]->get_name ());
1012+ EXPECT_EQ (" sens1 /voltage" , state_interfaces[position]->get_name ());
9551013 EXPECT_EQ (" voltage" , state_interfaces[position]->get_interface_name ());
956- EXPECT_EQ (" joint1 " , state_interfaces[position]->get_prefix_name ());
1014+ EXPECT_EQ (" sens1 " , state_interfaces[position]->get_prefix_name ());
9571015 EXPECT_TRUE (std::isnan (state_interfaces[position]->get_value ()));
9581016 }
9591017
9601018 // Not updated because is is UNCONFIGURED
961- auto si_joint1_vol = test_components::vector_contains (state_interfaces, " joint1 /voltage" ).second ;
1019+ auto si_sens1_vol = test_components::vector_contains (state_interfaces, " sens1 /voltage" ).second ;
9621020 sensor_hw.read (TIME, PERIOD);
963- EXPECT_TRUE (std::isnan (state_interfaces[si_joint1_vol ]->get_value ()));
1021+ EXPECT_TRUE (std::isnan (state_interfaces[si_sens1_vol ]->get_value ()));
9641022
9651023 // Updated because is is INACTIVE
9661024 state = sensor_hw.configure ();
9671025 EXPECT_EQ (lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE, state.id ());
9681026 EXPECT_EQ (hardware_interface::lifecycle_state_names::INACTIVE, state.label ());
969- EXPECT_EQ (0.0 , state_interfaces[si_joint1_vol]->get_value ());
1027+ EXPECT_EQ (0.0 , state_interfaces[si_sens1_vol]->get_value ());
1028+
1029+ // It can read now
1030+ sensor_hw.read (TIME, PERIOD);
1031+ EXPECT_EQ (0x666 , state_interfaces[si_sens1_vol]->get_value ());
1032+ }
1033+
1034+ TEST (TestComponentInterfaces, dummy_sensor_default_joint)
1035+ {
1036+ hardware_interface::Sensor sensor_hw (
1037+ std::make_unique<test_components::DummySensorJointDefault>());
1038+
1039+ const std::string urdf_to_test =
1040+ std::string (ros2_control_test_assets::urdf_head) +
1041+ ros2_control_test_assets::valid_urdf_ros2_control_joint_voltage_sensor +
1042+ ros2_control_test_assets::urdf_tail;
1043+ const std::vector<hardware_interface::HardwareInfo> control_resources =
1044+ hardware_interface::parse_control_resources_from_urdf (urdf_to_test);
1045+ const hardware_interface::HardwareInfo sensor_res = control_resources[0 ];
1046+ rclcpp::Node::SharedPtr node = std::make_shared<rclcpp::Node>(" test_system_components" );
1047+ auto state =
1048+ sensor_hw.initialize (sensor_res, node->get_logger (), node->get_node_clock_interface ());
1049+ ASSERT_EQ (lifecycle_msgs::msg::State::PRIMARY_STATE_UNCONFIGURED, state.id ());
1050+ ASSERT_EQ (hardware_interface::lifecycle_state_names::UNCONFIGURED, state.label ());
1051+
1052+ auto state_interfaces = sensor_hw.export_state_interfaces ();
1053+ ASSERT_EQ (2u , state_interfaces.size ());
1054+
1055+ auto [contains_sens1_vol, si_sens1_vol] =
1056+ test_components::vector_contains (state_interfaces, " sens1/voltage" );
1057+ ASSERT_TRUE (contains_sens1_vol);
1058+ EXPECT_EQ (" sens1/voltage" , state_interfaces[si_sens1_vol]->get_name ());
1059+ EXPECT_EQ (" voltage" , state_interfaces[si_sens1_vol]->get_interface_name ());
1060+ EXPECT_EQ (" sens1" , state_interfaces[si_sens1_vol]->get_prefix_name ());
1061+ EXPECT_TRUE (std::isnan (state_interfaces[si_sens1_vol]->get_value ()));
1062+
1063+ auto [contains_joint1_pos, si_joint1_pos] =
1064+ test_components::vector_contains (state_interfaces, " joint1/position" );
1065+ ASSERT_TRUE (contains_joint1_pos);
1066+ EXPECT_EQ (" joint1/position" , state_interfaces[si_joint1_pos]->get_name ());
1067+ EXPECT_EQ (" position" , state_interfaces[si_joint1_pos]->get_interface_name ());
1068+ EXPECT_EQ (" joint1" , state_interfaces[si_joint1_pos]->get_prefix_name ());
1069+ EXPECT_TRUE (std::isnan (state_interfaces[si_joint1_pos]->get_value ()));
1070+
1071+ // Not updated because is is UNCONFIGURED
1072+ sensor_hw.read (TIME, PERIOD);
1073+ EXPECT_TRUE (std::isnan (state_interfaces[si_sens1_vol]->get_value ()));
1074+ EXPECT_TRUE (std::isnan (state_interfaces[si_joint1_pos]->get_value ()));
1075+
1076+ // Updated because is is INACTIVE
1077+ state = sensor_hw.configure ();
1078+ ASSERT_EQ (lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE, state.id ());
1079+ ASSERT_EQ (hardware_interface::lifecycle_state_names::INACTIVE, state.label ());
1080+ EXPECT_EQ (0.0 , state_interfaces[si_sens1_vol]->get_value ());
1081+ EXPECT_EQ (10.0 , state_interfaces[si_joint1_pos]->get_value ());
9701082
9711083 // It can read now
9721084 sensor_hw.read (TIME, PERIOD);
973- EXPECT_EQ (0x666 , state_interfaces[si_joint1_vol]->get_value ());
1085+ EXPECT_EQ (0x666 , state_interfaces[si_sens1_vol]->get_value ());
1086+ EXPECT_EQ (0x777 , state_interfaces[si_joint1_pos]->get_value ());
9741087}
9751088
9761089// BEGIN (Handle export change): for backward compatibility
@@ -1708,7 +1821,7 @@ TEST(TestComponentInterfaces, dummy_sensor_default_read_error_behavior)
17081821 EXPECT_EQ (hardware_interface::lifecycle_state_names::UNCONFIGURED, state.label ());
17091822
17101823 // activate again and expect reset values
1711- auto si_joint1_vol = test_components::vector_contains (state_interfaces, " joint1 /voltage" ).second ;
1824+ auto si_joint1_vol = test_components::vector_contains (state_interfaces, " sens1 /voltage" ).second ;
17121825 state = sensor_hw.configure ();
17131826 EXPECT_EQ (state_interfaces[si_joint1_vol]->get_value (), 0.0 );
17141827
0 commit comments