@@ -15,9 +15,11 @@ void MultiSpawner::initialize()
1515 controllers_ =
1616 this ->declare_parameter <std::vector<std::string>>( " controllers" , std::vector<std::string>() );
1717 retry_delay_ = this ->declare_parameter <double >( " retry_delay" , 5.0 );
18+ start_delay_ = this ->declare_parameter <double >( " start_delay" , 0.0 );
1819 estop_topic_ = this ->declare_parameter <std::string>( " estop_topic" , " " );
1920 restart_after_estop_deactivation_ =
2021 this ->declare_parameter <bool >( " restart_after_estop_deactivation" , true );
22+ load_groups_one_by_one_ = this ->declare_parameter <bool >( " load_groups_one_by_one" , true );
2123
2224 for ( const auto &ctrl : controllers_ ) {
2325 ControllerCfg cfg;
@@ -39,6 +41,13 @@ void MultiSpawner::initialize()
3941 ss << " estop_topic: '" << estop_topic_ << " '\n " ;
4042 RCLCPP_DEBUG ( get_logger (), " %s" , ss.str ().c_str () );
4143
44+ if ( start_delay_ > 0.0 ) {
45+ RCLCPP_INFO ( get_logger (), " Delaying start sequence by %.1f seconds..." , start_delay_ );
46+ const auto delay = std::chrono::duration_cast<std::chrono::nanoseconds>(
47+ std::chrono::duration<double >( start_delay_ ) );
48+ rclcpp::sleep_for ( delay );
49+ }
50+
4251 // 2) Create service clients
4352 set_hw_state_client_ = this ->create_client <controller_manager_msgs::srv::SetHardwareComponentState>(
4453 " controller_manager/set_hardware_component_state" );
@@ -273,8 +282,8 @@ bool MultiSpawner::ensureControllerState(
273282 }
274283
275284 /* Issue one switch_controller call for this group. */
276- if ( ( group_requested_active && !switchControllersRequest ( group, /* deactivate*/ {} ) ) ||
277- ( !group_requested_active && !switchControllersRequest ( {}, group ) ) ) {
285+ if ( ( group_requested_active && !loadControllerGroup ( group, /* deactivate*/ {} ) ) ||
286+ ( !group_requested_active && !loadControllerGroup ( {}, group ) ) ) {
278287 RCLCPP_ERROR ( get_logger (), " Failed to %s controller group containing '%s'" ,
279288 group_requested_active ? " activate" : " deactivate" ,
280289 vecToString ( group ).c_str () );
@@ -289,14 +298,40 @@ bool MultiSpawner::ensureControllerState(
289298 return success;
290299}
291300
301+ bool MultiSpawner::loadControllerGroup ( const std::vector<std::string> &to_activate,
302+ const std::vector<std::string> &to_deactivate )
303+ {
304+ if ( load_groups_one_by_one_ ) {
305+ // deactivate in reverse order
306+ for ( auto it = to_deactivate.rbegin (); it != to_deactivate.rend (); ++it ) {
307+ const auto &ctrl = *it;
308+ if ( !switchControllersRequest ( {}, { ctrl } ) ) {
309+ RCLCPP_ERROR ( get_logger (), " Deactivated controller: %s" , ctrl.c_str () );
310+ return false ;
311+ }
312+ RCLCPP_DEBUG ( get_logger (), " Deactivated controller: %s" , ctrl.c_str () );
313+ }
314+ // activate in order (in respect to normal dependencies)
315+ for ( const auto &ctrl : to_activate ) {
316+ if ( !switchControllersRequest ( { ctrl }, {} ) ) {
317+ RCLCPP_ERROR ( get_logger (), " Failed to activate controller '%s'" , ctrl.c_str () );
318+ return false ;
319+ }
320+ RCLCPP_DEBUG ( get_logger (), " Activated controller: %s" , ctrl.c_str () );
321+ }
322+ return true ;
323+ }
324+ return switchControllersRequest ( to_activate, to_deactivate );
325+ }
326+
292327bool MultiSpawner::switchControllersRequest ( const std::vector<std::string> &to_activate,
293328 const std::vector<std::string> &to_deactivate )
294329{
295330 if ( !switch_ctrl_client_->wait_for_service ( 2s ) ) {
296331 RCLCPP_ERROR ( get_logger (), " switch_controller service unavailable" );
297332 return false ;
298333 }
299- auto req = std::make_shared<controller_manager_msgs::srv::SwitchController::Request>();
334+ const auto req = std::make_shared<controller_manager_msgs::srv::SwitchController::Request>();
300335 req->activate_controllers = to_activate;
301336 req->deactivate_controllers = to_deactivate;
302337 req->strictness = controller_manager_msgs::srv::SwitchController::Request::BEST_EFFORT;
@@ -317,7 +352,9 @@ void MultiSpawner::parseControllerInfo(
317352
318353 // —— auto-detect chained controllers groups ——
319354 for ( const auto &c : resp.controller ) {
355+ chained_connections_.erase ( c.name );
320356 for ( const auto &conn : c.chain_connections ) {
357+ chained_connections_[c.name ].push_back ( conn.name );
321358 // check if there is a ControllerGroup that includes name or conn.name
322359 bool found = false ;
323360 for ( auto &group : controller_groups_ ) {
@@ -365,6 +402,30 @@ void MultiSpawner::parseControllerInfo(
365402 c.name .c_str (), c.state .c_str () );
366403 }
367404 }
405+ // add recursive chained connections
406+ for ( auto &group : controller_groups_ ) {
407+ bool changed = true ;
408+ while ( changed ) {
409+ changed = false ;
410+ for ( const auto &ctrl : group ) {
411+ for ( const auto &dependent_ctrl : chained_connections_[ctrl] ) {
412+ for ( const auto &dep_dep_ctr : chained_connections_[dependent_ctrl] ) {
413+ if ( std::find ( chained_connections_[ctrl].begin (), chained_connections_[ctrl].end (),
414+ dep_dep_ctr ) == chained_connections_[ctrl].end () ) {
415+ chained_connections_[ctrl].push_back ( dep_dep_ctr );
416+ changed = true ;
417+ }
418+ }
419+ }
420+ }
421+ }
422+ // sort members in group by number of dependent controllers (descending)
423+ std::sort ( group.begin (), group.end (), [this ]( const std::string &a, const std::string &b ) {
424+ const size_t size_a = chained_connections_.count ( a ) ? chained_connections_[a].size () : 0 ;
425+ const size_t size_b = chained_connections_.count ( b ) ? chained_connections_[b].size () : 0 ;
426+ return size_a < size_b;
427+ } );
428+ }
368429}
369430
370431bool MultiSpawner::loadAndActivateHardware ( const std::string &name )
0 commit comments