|
32 | 32 | )
|
33 | 33 | from controller_manager.controller_manager_services import ServiceNotFoundError
|
34 | 34 |
|
| 35 | +from filelock import Timeout, FileLock |
35 | 36 | import rclpy
|
36 | 37 | from rclpy.node import Node
|
37 | 38 | from rclpy.signals import SignalHandlerOptions
|
@@ -169,34 +170,61 @@ def main(args=None):
|
169 | 170 | if not os.path.isfile(param_file):
|
170 | 171 | raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), param_file)
|
171 | 172 |
|
172 |
| - node = Node("spawner_" + controller_names[0]) |
| 173 | + try: |
| 174 | + spawner_node_name = "spawner_" + controller_names[0] |
| 175 | + lock = FileLock("/tmp/ros2-control-controller-spawner.lock") |
| 176 | + max_retries = 5 |
| 177 | + retry_delay = 3 # seconds |
| 178 | + for attempt in range(max_retries): |
| 179 | + tmp_logger = rclpy.logging.get_logger(spawner_node_name) |
| 180 | + try: |
| 181 | + tmp_logger.debug( |
| 182 | + bcolors.OKGREEN + "Waiting for the spawner lock to be acquired!" + bcolors.ENDC |
| 183 | + ) |
| 184 | + # timeout after 20 seconds and try again |
| 185 | + lock.acquire(timeout=20) |
| 186 | + tmp_logger.debug(bcolors.OKGREEN + "Spawner lock acquired!" + bcolors.ENDC) |
| 187 | + break |
| 188 | + except Timeout: |
| 189 | + tmp_logger.warn( |
| 190 | + bcolors.WARNING |
| 191 | + + f"Attempt {attempt+1} failed. Retrying in {retry_delay} seconds..." |
| 192 | + + bcolors.ENDC |
| 193 | + ) |
| 194 | + time.sleep(retry_delay) |
| 195 | + else: |
| 196 | + tmp_logger.error( |
| 197 | + bcolors.ERROR + "Failed to acquire lock after multiple attempts." + bcolors.ENDC |
| 198 | + ) |
| 199 | + return 1 |
173 | 200 |
|
174 |
| - if node.get_namespace() != "/" and args.namespace: |
175 |
| - raise RuntimeError( |
176 |
| - f"Setting namespace through both '--namespace {args.namespace}' arg and the ROS 2 standard way " |
177 |
| - f"'--ros-args -r __ns:={node.get_namespace()}' is not allowed!" |
178 |
| - ) |
| 201 | + node = Node(spawner_node_name) |
179 | 202 |
|
180 |
| - if args.namespace: |
181 |
| - warnings.filterwarnings("always") |
182 |
| - warnings.warn( |
183 |
| - "The '--namespace' argument is deprecated and will be removed in future releases." |
184 |
| - " Use the ROS 2 standard way of setting the node namespacing using --ros-args -r __ns:=<namespace>", |
185 |
| - DeprecationWarning, |
186 |
| - ) |
| 203 | + if node.get_namespace() != "/" and args.namespace: |
| 204 | + raise RuntimeError( |
| 205 | + f"Setting namespace through both '--namespace {args.namespace}' arg and the ROS 2 standard way " |
| 206 | + f"'--ros-args -r __ns:={node.get_namespace()}' is not allowed!" |
| 207 | + ) |
187 | 208 |
|
188 |
| - spawner_namespace = args.namespace if args.namespace else node.get_namespace() |
| 209 | + if args.namespace: |
| 210 | + warnings.filterwarnings("always") |
| 211 | + warnings.warn( |
| 212 | + "The '--namespace' argument is deprecated and will be removed in future releases." |
| 213 | + " Use the ROS 2 standard way of setting the node namespacing using --ros-args -r __ns:=<namespace>", |
| 214 | + DeprecationWarning, |
| 215 | + ) |
189 | 216 |
|
190 |
| - if not spawner_namespace.startswith("/"): |
191 |
| - spawner_namespace = f"/{spawner_namespace}" |
| 217 | + spawner_namespace = args.namespace if args.namespace else node.get_namespace() |
192 | 218 |
|
193 |
| - if not controller_manager_name.startswith("/"): |
194 |
| - if spawner_namespace and spawner_namespace != "/": |
195 |
| - controller_manager_name = f"{spawner_namespace}/{controller_manager_name}" |
196 |
| - else: |
197 |
| - controller_manager_name = f"/{controller_manager_name}" |
| 219 | + if not spawner_namespace.startswith("/"): |
| 220 | + spawner_namespace = f"/{spawner_namespace}" |
| 221 | + |
| 222 | + if not controller_manager_name.startswith("/"): |
| 223 | + if spawner_namespace and spawner_namespace != "/": |
| 224 | + controller_manager_name = f"{spawner_namespace}/{controller_manager_name}" |
| 225 | + else: |
| 226 | + controller_manager_name = f"/{controller_manager_name}" |
198 | 227 |
|
199 |
| - try: |
200 | 228 | for controller_name in controller_names:
|
201 | 229 |
|
202 | 230 | if is_controller_loaded(
|
@@ -375,6 +403,7 @@ def main(args=None):
|
375 | 403 | return 1
|
376 | 404 | finally:
|
377 | 405 | node.destroy_node()
|
| 406 | + lock.release() |
378 | 407 | rclpy.shutdown()
|
379 | 408 |
|
380 | 409 |
|
|
0 commit comments