Nav2 Navigation Stack - humble  humble
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 <string>
17 #include <thread>
18 #include <vector>
19 
20 #include "lifecycle_msgs/srv/change_state.hpp"
21 #include "lifecycle_msgs/srv/get_state.hpp"
22 #include "nav2_util/lifecycle_service_client.hpp"
23 
24 using std::string;
25 using lifecycle_msgs::msg::Transition;
26 
27 namespace nav2_util
28 {
29 
30 #define RETRY(fn, retries) \
31  { \
32  int count = 0; \
33  while (true) { \
34  try { \
35  fn; \
36  break; \
37  } catch (std::runtime_error & e) { \
38  ++count; \
39  if (count > (retries)) { \
40  throw e;} \
41  } \
42  } \
43  }
44 
45 static void startupLifecycleNode(
46  const std::string & node_name,
47  const std::chrono::seconds service_call_timeout,
48  const int retries)
49 {
50  LifecycleServiceClient sc(node_name);
51 
52  // Despite waiting for the service to be available and using reliable transport
53  // service calls still frequently hang. To get reliable startup it's necessary
54  // to timeout the service call and retry it when that happens.
55  RETRY(
56  sc.change_state(Transition::TRANSITION_CONFIGURE, service_call_timeout),
57  retries);
58  RETRY(
59  sc.change_state(Transition::TRANSITION_ACTIVATE, service_call_timeout),
60  retries);
61 }
62 
63 void startup_lifecycle_nodes(
64  const std::vector<std::string> & node_names,
65  const std::chrono::seconds service_call_timeout,
66  const int retries)
67 {
68  for (const auto & node_name : node_names) {
69  startupLifecycleNode(node_name, service_call_timeout, retries);
70  }
71 }
72 
73 static void resetLifecycleNode(
74  const std::string & node_name,
75  const std::chrono::seconds service_call_timeout,
76  const int retries)
77 {
78  LifecycleServiceClient sc(node_name);
79 
80  // Despite waiting for the service to be available and using reliable transport
81  // service calls still frequently hang. To get reliable reset it's necessary
82  // to timeout the service call and retry it when that happens.
83  RETRY(
84  sc.change_state(Transition::TRANSITION_DEACTIVATE, service_call_timeout),
85  retries);
86  RETRY(
87  sc.change_state(Transition::TRANSITION_CLEANUP, service_call_timeout),
88  retries);
89 }
90 
91 void reset_lifecycle_nodes(
92  const std::vector<std::string> & node_names,
93  const std::chrono::seconds service_call_timeout,
94  const int retries)
95 {
96  for (const auto & node_name : node_names) {
97  resetLifecycleNode(node_name, service_call_timeout, retries);
98  }
99 }
100 
101 } // namespace nav2_util