@@ -141,89 +141,50 @@ hardware_interface::CallbackReturn VescHardware::on_init(
141141 return hardware_interface::CallbackReturn::ERROR ;
142142 }
143143
144- const auto & joint = info_.joints [0 ];
145-
146- // Initialize list of supported interfaces
144+ // Initialize list of supported interfaces
147145 populate_state_definitions ();
148146 populate_command_definitions ();
149147
150- // Check which state interfaces are requested
151- std::set<std::string> state_interfaces_requested;
152- for (const auto & state_interface : joint.state_interfaces ) {
153- auto it = state_interface_groups_.find (state_interface.name );
154- if (it == state_interface_groups_.end ()) {
155- RCLCPP_FATAL (get_logger (),
156- " Unsupported state interface '%s' requested for joint '%s'" ,
157- state_interface.name .c_str (), joint.name .c_str ());
158- return hardware_interface::CallbackReturn::ERROR ;
159- }
160- if (state_interfaces_requested.count (state_interface.name ) > 0 ) {
161- RCLCPP_FATAL (
162- get_logger (),
163- " Duplicate state interface '%s' requested for joint '%s'" ,
164- state_interface.name .c_str (), joint.name .c_str ());
165- return hardware_interface::CallbackReturn::ERROR ;
166- }
167- state_interfaces_requested.insert (state_interface.name );
168- // mark as requested all of the interfaces whose name matches the requested interface or is part of the requested group
169- for (auto & [name, data] : state_interfaces_) {
170- if (name == state_interface.name || name.rfind (state_interface.name + " ." , 0 ) == 0 ) {
171- data.requested = true ;
148+ auto validate_component = [this ](const hardware_interface::ComponentInfo & component) {
149+ // Validate and mark requested state interfaces
150+ if ((validate_and_mark_requested_state_interfaces (component) !=
151+ hardware_interface::CallbackReturn::SUCCESS ) ||
152+ (validate_and_mark_requested_command_interfaces (component) !=
153+ hardware_interface::CallbackReturn::SUCCESS ))
154+ {
155+ return hardware_interface::CallbackReturn::ERROR ;
172156 }
173- RCLCPP_INFO (get_logger (), " State interface '%s' requested" ,
174- state_interface.name .c_str ());
175- }
176- }
157+ return hardware_interface::CallbackReturn::SUCCESS ;
158+ };
177159
178- // Check which command interfaces are requested
179- for (const auto & command_interface : joint.command_interfaces ) {
180- auto it = command_interfaces_.find (command_interface.name );
181- if (it == command_interfaces_.end ()) {
182- RCLCPP_FATAL (
183- get_logger (),
184- " Unsupported command interface '%s' requested for joint '%s'" ,
185- command_interface.name .c_str (), joint.name .c_str ());
160+ // process joints
161+ for (const auto & component : info_.joints ) {
162+ if (validate_component (component) != hardware_interface::CallbackReturn::SUCCESS ) {
186163 return hardware_interface::CallbackReturn::ERROR ;
187164 }
188- if (it->second .requested ) {
189- RCLCPP_FATAL (
190- get_logger (),
191- " Duplicate command interface '%s' requested for joint '%s'" ,
192- command_interface.name .c_str (), joint.name .c_str ());
193- return hardware_interface::CallbackReturn::ERROR ;
194- }
195- it->second .requested = true ;
196- RCLCPP_INFO (get_logger (), " Command interface '%s' requested" ,
197- command_interface.name .c_str ());
198165 }
199166
200- // Check that at least one interface is requested
201- bool has_state_interface = false ;
202- for (const auto & [name, data] : state_interfaces_) {
203- if (data.requested ) {
204- has_state_interface = true ;
205- break ;
167+ // process sensors
168+ for (const auto & component : info_.sensors ) {
169+ if (validate_component (component) != hardware_interface::CallbackReturn::SUCCESS ) {
170+ return hardware_interface::CallbackReturn::ERROR ;
206171 }
207172 }
208173
209- bool has_command_interface = false ;
174+ // check if more than one command interface from the same control group was requested
175+ std::unordered_set<VescHardware::ControlGroup> control_groups_seen;
210176 for (const auto & [name, data] : command_interfaces_) {
211177 if (data.requested ) {
212- has_command_interface = true ;
213- break ;
178+ if (control_groups_seen.find (data.control_group ) != control_groups_seen.end ()) {
179+ RCLCPP_FATAL (get_logger (),
180+ " Multiple mutually exclusive command interfaces requested for control group %s" ,
181+ (data.control_group == ControlGroup::ROTOR ? " ROTOR" : " SERVO" ));
182+ return hardware_interface::CallbackReturn::ERROR ;
183+ }
184+ control_groups_seen.insert (data.control_group );
214185 }
215186 }
216187
217- if (!has_state_interface) {
218- RCLCPP_WARN (get_logger (), " No state interfaces requested for joint '%s'" ,
219- joint.name .c_str ());
220- }
221-
222- if (!has_command_interface) {
223- RCLCPP_WARN (get_logger (), " No command interfaces requested for joint '%s'" ,
224- joint.name .c_str ());
225- }
226-
227188 // Initialize state storage
228189 hw_state_position_ = 0.0 ;
229190 hw_state_velocity_ = 0.0 ;
@@ -531,52 +492,147 @@ void VescHardware::populate_state_definitions()
531492 false ,
532493 [this ]() {return hw_imu_magnetic_field_z_.load (std::memory_order_relaxed);}
533494 };
495+ }
496+
497+ std::unordered_set<std::string> VescHardware::get_state_interface_groups () const
498+ {
499+ // Create a set of state interface group names
500+ std::unordered_set<std::string> state_interface_groups;
534501
535- // create a vector of state interface group names
536- const auto get_group_name = [this ](const auto & pair) {
502+ const auto get_group_name = [](const auto & pair) {
537503 const auto & name = pair.first ;
538504 if (name.find (' .' ) != std::string::npos) {
539- // This is a grouped interface, extract the group name
540- std::string group_name = name.substr (0 , name.find (' .' ));
541- return group_name;
505+ // This is a grouped interface, extract the group name
506+ return name.substr (0 , name.find (' .' ));
542507 } else {
543- // This is a single interface, add it directly
508+ // This is a single interface, add it directly
544509 return name;
545510 }
546511 };
547512
548- state_interface_groups_.clear ();
549513 std::for_each (state_interfaces_.begin (), state_interfaces_.end (),
550- [this , &get_group_name](const auto & pair) {
551- state_interface_groups_ .insert (get_group_name (pair));
514+ [&state_interface_groups , &get_group_name](const auto & pair) {
515+ state_interface_groups .insert (get_group_name (pair));
552516 });
517+
518+ return state_interface_groups;
519+ }
520+
521+ hardware_interface::CallbackReturn VescHardware::validate_and_mark_requested_state_interfaces (
522+ const hardware_interface::ComponentInfo & joint)
523+ {
524+ // Get state interface groups for validation
525+ auto state_interface_groups = get_state_interface_groups ();
526+
527+ // Check which state interfaces are requested
528+ for (const auto & state_interface : joint.state_interfaces ) {
529+ // check that it's a valid interface name or group
530+ auto it = state_interface_groups.find (state_interface.name );
531+ if (it == state_interface_groups.end ()) {
532+ RCLCPP_FATAL (get_logger (),
533+ " Unsupported state interface '%s' requested for joint '%s'" ,
534+ state_interface.name .c_str (), joint.name .c_str ());
535+ return hardware_interface::CallbackReturn::ERROR ;
536+ }
537+ // mark as requested all of the interfaces whose name matches the
538+ // requested interface or is part of the requested group. Check if it was previously
539+ // registered
540+ for (auto & [name, data] : state_interfaces_) {
541+ if (name == state_interface.name || name.rfind (state_interface.name + " ." , 0 ) == 0 ) {
542+ // if it was already requested, this is a duplicate request
543+ if (data.requested ) {
544+ RCLCPP_FATAL (get_logger (),
545+ " Duplicate state interface '%s' requested for joint '%s'" ,
546+ state_interface.name .c_str (), joint.name .c_str ());
547+ return hardware_interface::CallbackReturn::ERROR ;
548+ }
549+ data.requested = true ;
550+ }
551+ RCLCPP_INFO (get_logger (), " State interface '%s' requested" ,
552+ state_interface.name .c_str ());
553+ }
554+ }
555+
556+ // Check that at least one interface is requested
557+ bool has_state_interface = std::any_of (state_interfaces_.begin (), state_interfaces_.end (),
558+ [](const auto & pair) {return pair.second .requested ;});
559+
560+ if (!has_state_interface) {
561+ RCLCPP_WARN (get_logger (), " No state interfaces requested for joint '%s'" ,
562+ joint.name .c_str ());
563+ }
564+
565+ return hardware_interface::CallbackReturn::SUCCESS ;
566+ }
567+
568+ hardware_interface::CallbackReturn VescHardware::validate_and_mark_requested_command_interfaces (
569+ const hardware_interface::ComponentInfo & joint)
570+ {
571+ // Check which command interfaces are requested
572+ for (const auto & command_interface : joint.command_interfaces ) {
573+ // check that it's a valid interface name
574+ auto it = command_interfaces_.find (command_interface.name );
575+ if (it == command_interfaces_.end ()) {
576+ RCLCPP_FATAL (
577+ get_logger (),
578+ " Unsupported command interface '%s' requested for joint '%s'" ,
579+ command_interface.name .c_str (), joint.name .c_str ());
580+ return hardware_interface::CallbackReturn::ERROR ;
581+ }
582+ // check that it was not previously requested
583+ if (it->second .requested ) {
584+ RCLCPP_FATAL (
585+ get_logger (),
586+ " Duplicate command interface '%s' requested for joint '%s'" ,
587+ command_interface.name .c_str (), joint.name .c_str ());
588+ return hardware_interface::CallbackReturn::ERROR ;
589+ }
590+ it->second .requested = true ;
591+ RCLCPP_INFO (get_logger (), " Command interface '%s' requested" ,
592+ command_interface.name .c_str ());
593+ }
594+
595+ // Check that at least one interface is requested
596+ bool has_command_interface = std::any_of (command_interfaces_.begin (), command_interfaces_.end (),
597+ [](const auto & pair) {return pair.second .requested ;});
598+
599+ if (!has_command_interface) {
600+ RCLCPP_WARN (get_logger (), " No command interfaces requested for joint '%s'" ,
601+ joint.name .c_str ());
602+ }
603+
604+ return hardware_interface::CallbackReturn::SUCCESS ;
553605}
554606
555607void VescHardware::populate_command_definitions ()
556608{
557609 command_interfaces_[hardware_interface::HW_IF_POSITION ] = {
558610 false ,
611+ ControlGroup::ROTOR ,
559612 [this ](double value) {
560613 double vesc_position = convertMechanicalRadToDeg (value);
561614 vesc_interface_->setPosition (vesc_position);
562615 }
563616 };
564617 command_interfaces_[hardware_interface::HW_IF_VELOCITY ] = {
565618 false ,
619+ ControlGroup::ROTOR ,
566620 [this ](double value) {
567621 double vesc_erpm = convertMechanicalRadSecToERPM (value);
568622 vesc_interface_->setSpeed (vesc_erpm);
569623 }
570624 };
571625 command_interfaces_[CUSTOM_HW_IF_SERVO ] = {
572626 false ,
627+ ControlGroup::SERVO ,
573628 [this ](double value) {
574629 hw_command_servo_ = value;
575630 vesc_interface_->setServo (hw_command_servo_);
576631 }
577632 };
578633 command_interfaces_[CUSTOM_HW_IF_DUTY_CYCLE ] = {
579634 false ,
635+ ControlGroup::ROTOR ,
580636 [this ](double value) {
581637 // Clamp duty cycle to [0, 1] range
582638 double clamped_duty_cycle = std::clamp (value, 0.0 , 1.0 );
@@ -585,12 +641,14 @@ void VescHardware::populate_command_definitions()
585641 };
586642 command_interfaces_[hardware_interface::HW_IF_CURRENT ] = {
587643 false ,
644+ ControlGroup::ROTOR ,
588645 [this ](double value) {
589646 vesc_interface_->setCurrent (value);
590647 }
591648 };
592649 command_interfaces_[CUSTOM_HW_IF_BRAKE ] = {
593650 false ,
651+ ControlGroup::ROTOR ,
594652 [this ](double value) {
595653 vesc_interface_->setBrake (value);
596654 }
0 commit comments