@@ -157,51 +157,55 @@ URPositionHardwareInterface::on_init(const hardware_interface::HardwareComponent
157157 trajectory_joint_accelerations_.reserve (32768 );
158158
159159 for (const hardware_interface::ComponentInfo& joint : info_.joints ) {
160- if (joint.command_interfaces .size () != 3 ) {
160+ auto has_cmd_interface = [](const hardware_interface::ComponentInfo& joint, const std::string& interface_name) {
161+ auto it = find_if (
162+ joint.command_interfaces .begin (), joint.command_interfaces .end (),
163+ [&interface_name](const hardware_interface::InterfaceInfo& obj) { return obj.name == interface_name; });
164+ return it != joint.command_interfaces .end ();
165+ };
166+
167+ if (!has_cmd_interface (joint, hardware_interface::HW_IF_POSITION)) {
161168 RCLCPP_FATAL (rclcpp::get_logger (" URPositionHardwareInterface" ),
162- " Joint '%s' has %zu command interfaces found. 3 expected ." , joint.name .c_str (),
163- joint. command_interfaces . size () );
169+ " Joint '%s' does not contain a '%s' command interface ." , joint.name .c_str (),
170+ hardware_interface::HW_IF_POSITION );
164171 return hardware_interface::CallbackReturn::ERROR;
165172 }
166173
167- if (joint. command_interfaces [ 0 ]. name != hardware_interface::HW_IF_POSITION ) {
174+ if (! has_cmd_interface ( joint, hardware_interface::HW_IF_VELOCITY) ) {
168175 RCLCPP_FATAL (rclcpp::get_logger (" URPositionHardwareInterface" ),
169- " Joint '%s' have %s command interfaces found as first command interface. '%s' expected. " ,
170- joint. name . c_str (), joint. command_interfaces [ 0 ]. name . c_str (), hardware_interface::HW_IF_POSITION );
176+ " Joint '%s' does not contain a '%s' command interface. " , joint. name . c_str () ,
177+ hardware_interface::HW_IF_VELOCITY );
171178 return hardware_interface::CallbackReturn::ERROR;
172179 }
173180
174- if (joint.command_interfaces [1 ].name != hardware_interface::HW_IF_VELOCITY) {
175- RCLCPP_FATAL (rclcpp::get_logger (" URPositionHardwareInterface" ),
176- " Joint '%s' have %s command interfaces found as second command interface. '%s' expected." ,
177- joint.name .c_str (), joint.command_interfaces [1 ].name .c_str (), hardware_interface::HW_IF_VELOCITY);
178- return hardware_interface::CallbackReturn::ERROR;
179- }
181+ // We treat the torque command interface as optional here for now. This should ensure backwards
182+ // compatibility with older descriptions.
180183
181- if (joint.state_interfaces .size () != 3 ) {
182- RCLCPP_FATAL (rclcpp::get_logger (" URPositionHardwareInterface" ), " Joint '%s' has %zu state interface. 3 expected." ,
183- joint.name .c_str (), joint.state_interfaces .size ());
184- return hardware_interface::CallbackReturn::ERROR;
185- }
184+ auto has_state_interface = [](const hardware_interface::ComponentInfo& joint, const std::string& interface_name) {
185+ auto it = find_if (
186+ joint.state_interfaces .begin (), joint.state_interfaces .end (),
187+ [&interface_name](const hardware_interface::InterfaceInfo& obj) { return obj.name == interface_name; });
188+ return it != joint.state_interfaces .end ();
189+ };
186190
187- if (joint. state_interfaces [ 0 ]. name != hardware_interface::HW_IF_POSITION) {
191+ if (! has_state_interface ( joint, hardware_interface::HW_IF_POSITION) ) {
188192 RCLCPP_FATAL (rclcpp::get_logger (" URPositionHardwareInterface" ),
189- " Joint '%s' have %s state interface as first state interface. '%s' expected ." , joint.name .c_str (),
190- joint. state_interfaces [ 0 ]. name . c_str (), hardware_interface::HW_IF_POSITION);
193+ " Joint '%s' does not contain a '%s' state interface ." , joint.name .c_str (),
194+ hardware_interface::HW_IF_POSITION);
191195 return hardware_interface::CallbackReturn::ERROR;
192196 }
193197
194- if (joint. state_interfaces [ 1 ]. name != hardware_interface::HW_IF_VELOCITY) {
198+ if (! has_state_interface ( joint, hardware_interface::HW_IF_VELOCITY) ) {
195199 RCLCPP_FATAL (rclcpp::get_logger (" URPositionHardwareInterface" ),
196- " Joint '%s' have %s state interface as second state interface. '%s' expected ." , joint.name .c_str (),
197- joint. state_interfaces [ 1 ]. name . c_str (), hardware_interface::HW_IF_VELOCITY);
200+ " Joint '%s' does not contain a '%s' state interface ." , joint.name .c_str (),
201+ hardware_interface::HW_IF_VELOCITY);
198202 return hardware_interface::CallbackReturn::ERROR;
199203 }
200204
201- if (joint. state_interfaces [ 2 ]. name != hardware_interface::HW_IF_EFFORT) {
205+ if (! has_state_interface ( joint, hardware_interface::HW_IF_EFFORT) ) {
202206 RCLCPP_FATAL (rclcpp::get_logger (" URPositionHardwareInterface" ),
203- " Joint '%s' have %s state interface as third state interface. '%s' expected ." , joint.name .c_str (),
204- joint. state_interfaces [ 2 ]. name . c_str (), hardware_interface::HW_IF_EFFORT);
207+ " Joint '%s' does not contain a '%s' state interface ." , joint.name .c_str (),
208+ hardware_interface::HW_IF_EFFORT);
205209 return hardware_interface::CallbackReturn::ERROR;
206210 }
207211 }
@@ -335,6 +339,12 @@ std::vector<hardware_interface::StateInterface> URPositionHardwareInterface::exp
335339
336340std::vector<hardware_interface::CommandInterface> URPositionHardwareInterface::export_command_interfaces ()
337341{
342+ auto has_cmd_interface = [](const hardware_interface::ComponentInfo& joint, const std::string& interface_name) {
343+ auto it =
344+ find_if (joint.command_interfaces .begin (), joint.command_interfaces .end (),
345+ [&interface_name](const hardware_interface::InterfaceInfo& obj) { return obj.name == interface_name; });
346+ return it != joint.command_interfaces .end ();
347+ };
338348 std::vector<hardware_interface::CommandInterface> command_interfaces;
339349 for (size_t i = 0 ; i < info_.joints .size (); ++i) {
340350 command_interfaces.emplace_back (hardware_interface::CommandInterface (
@@ -343,8 +353,10 @@ std::vector<hardware_interface::CommandInterface> URPositionHardwareInterface::e
343353 command_interfaces.emplace_back (hardware_interface::CommandInterface (
344354 info_.joints [i].name , hardware_interface::HW_IF_VELOCITY, &urcl_velocity_commands_[i]));
345355
346- command_interfaces.emplace_back (hardware_interface::CommandInterface (
347- info_.joints [i].name , hardware_interface::HW_IF_EFFORT, &urcl_torque_commands_[i]));
356+ if (has_cmd_interface (info_.joints [i], hardware_interface::HW_IF_EFFORT)) {
357+ command_interfaces.emplace_back (hardware_interface::CommandInterface (
358+ info_.joints [i].name , hardware_interface::HW_IF_EFFORT, &urcl_torque_commands_[i]));
359+ }
348360 }
349361 // Obtain the tf_prefix from the urdf so that we can have the general interface multiple times
350362 // NOTE using the tf_prefix at this point is some kind of workaround. One should actually go through the list of gpio
@@ -646,11 +658,11 @@ URPositionHardwareInterface::on_configure(const rclcpp_lifecycle::State& previou
646658 }
647659
648660 // Export version information to state interfaces
649- urcl::VersionInformation version_info = ur_driver_->getVersion ();
650- get_robot_software_version_major_ = version_info .major ;
651- get_robot_software_version_minor_ = version_info .minor ;
652- get_robot_software_version_build_ = version_info .build ;
653- get_robot_software_version_bugfix_ = version_info .bugfix ;
661+ version_info_ = ur_driver_->getVersion ();
662+ get_robot_software_version_major_ = version_info_ .major ;
663+ get_robot_software_version_minor_ = version_info_ .minor ;
664+ get_robot_software_version_build_ = version_info_ .build ;
665+ get_robot_software_version_bugfix_ = version_info_ .bugfix ;
654666
655667 async_thread_ = std::make_shared<std::thread>(&URPositionHardwareInterface::asyncThread, this );
656668
@@ -1200,6 +1212,19 @@ hardware_interface::return_type URPositionHardwareInterface::prepare_command_mod
12001212 }
12011213 }
12021214
1215+ // effort control is only available from 5.23.0 / 10.10.0
1216+ if (std::any_of (start_modes_.begin (), start_modes_.end (), [&](const std::vector<std::string>& modes) {
1217+ return std::any_of (modes.begin (), modes.end (),
1218+ [&](const std::string& mode) { return mode == hardware_interface::HW_IF_EFFORT; });
1219+ })) {
1220+ if ((version_info_.major == 5 && version_info_.minor < 23 ) ||
1221+ (version_info_.major == 10 && version_info_.minor < 10 ) || version_info_.major < 5 ) {
1222+ RCLCPP_ERROR (get_logger (), " Requested to use effort interface on a robot version that doesn't support it. Torque "
1223+ " control is available from robot software 5.23.0 / 10.10.0 on." );
1224+ return hardware_interface::return_type::ERROR;
1225+ }
1226+ }
1227+
12031228 if (!std::all_of (start_modes_.begin () + 1 , start_modes_.end (),
12041229 [&](const std::vector<std::string>& other) { return other == start_modes_[0 ]; })) {
12051230 RCLCPP_ERROR (get_logger (), " Start modes of all joints have to be the same." );
0 commit comments