Nav2 Navigation Stack - kilted  kilted
ROS 2 Navigation Stack
lifecycle_utils.cpp
1 // Copyright (c) 2019 Intel Corporation
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <chrono>
16 #include <stdexcept>
17 #include <string>
18 #include <vector>
19 
20 #include "lifecycle_msgs/msg/transition.hpp"
21 
22 #include "nav2_util/lifecycle_service_client.hpp"
23 
24 namespace nav2_util
25 {
26 
27 #define RETRY(fn, retries) \
28  { \
29  int count = 0; \
30  while (true) { \
31  try { \
32  fn; \
33  break; \
34  } catch (const std::runtime_error & e) { \
35  ++count; \
36  if (count > (retries)) { \
37  throw e;} \
38  } \
39  } \
40  }
41 
42 static void startupLifecycleNode(
43  const std::string & node_name,
44  const std::chrono::seconds service_call_timeout,
45  const int retries)
46 {
47  LifecycleServiceClient sc(node_name);
48 
49  // Despite waiting for the service to be available and using reliable transport
50  // service calls still frequently hang. To get reliable startup it's necessary
51  // to timeout the service call and retry it when that happens.
52  RETRY(
53  sc.change_state(lifecycle_msgs::msg::Transition::TRANSITION_CONFIGURE, service_call_timeout),
54  retries);
55  RETRY(
56  sc.change_state(lifecycle_msgs::msg::Transition::TRANSITION_ACTIVATE, service_call_timeout),
57  retries);
58 }
59 
60 void startup_lifecycle_nodes(
61  const std::vector<std::string> & node_names,
62  const std::chrono::seconds service_call_timeout,
63  const int retries)
64 {
65  for (const auto & node_name : node_names) {
66  startupLifecycleNode(node_name, service_call_timeout, retries);
67  }
68 }
69 
70 static void resetLifecycleNode(
71  const std::string & node_name,
72  const std::chrono::seconds service_call_timeout,
73  const int retries)
74 {
75  LifecycleServiceClient sc(node_name);
76 
77  // Despite waiting for the service to be available and using reliable transport
78  // service calls still frequently hang. To get reliable reset it's necessary
79  // to timeout the service call and retry it when that happens.
80  RETRY(
81  sc.change_state(lifecycle_msgs::msg::Transition::TRANSITION_DEACTIVATE, service_call_timeout),
82  retries);
83  RETRY(
84  sc.change_state(lifecycle_msgs::msg::Transition::TRANSITION_CLEANUP, service_call_timeout),
85  retries);
86 }
87 
88 void reset_lifecycle_nodes(
89  const std::vector<std::string> & node_names,
90  const std::chrono::seconds service_call_timeout,
91  const int retries)
92 {
93  for (const auto & node_name : node_names) {
94  resetLifecycleNode(node_name, service_call_timeout, retries);
95  }
96 }
97 
98 } // namespace nav2_util