Skip to content

Commit e70a7c5

Browse files
committed
Fixed play button issues
1 parent 8a4b875 commit e70a7c5

1 file changed

Lines changed: 43 additions & 4 deletions

File tree

mirte_robot/robot.py

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import time
66
import signal
77
import sys
8+
import threading
89
import weakref
910
from typing import TYPE_CHECKING, Literal, Optional, overload
1011

@@ -36,6 +37,18 @@
3637
)
3738
from rcl_interfaces.srv import ListParameters
3839

40+
#####
41+
#
42+
# There are 4 use cases that should exit the user code:
43+
#
44+
# 1) Running "while true" (and CTRL-C) from commandline
45+
# 2) Running "for 10" from commandline
46+
# 3) Running "while true" (and stop/CTRL-C) from web interface
47+
# 4) Running "for 10" from web interface
48+
#
49+
#####
50+
51+
3952
mirte = {}
4053

4154
# No QoS Profiles are set, but this might not be required, since they might already behave like ROS 1 persistant.
@@ -101,6 +114,8 @@ def __init__(
101114

102115
# Stop robot when exited
103116
rclpy.get_default_context().on_shutdown(self._at_exit)
117+
self._stopping = False
118+
self._lock = threading.Lock()
104119

105120
self.CONTROLLER = "diffbot_base_controller"
106121

@@ -181,6 +196,7 @@ def __init__(
181196
SetMotorSpeed,
182197
self._hardware_namespace + "/motor/" + motor + "/set_speed",
183198
)
199+
self.motor_services[motor].wait_for_service()
184200

185201
# Service for motor speed
186202

@@ -211,6 +227,7 @@ def finalize(node: rclpy.node.Node, motors: dict[str, rclpy.client.Client]):
211227
SetServoAngle,
212228
self._hardware_namespace + "/servo/" + servo + "/set_angle",
213229
)
230+
self.servo_services[servo].wait_for_service()
214231

215232
## Sensors
216233
## The sensors are now just using a blocking service call. This is intentionally
@@ -238,6 +255,7 @@ def finalize(node: rclpy.node.Node, motors: dict[str, rclpy.client.Client]):
238255
GetRange,
239256
self._hardware_namespace + "/distance/" + sensor + "/get_range",
240257
)
258+
self.distance_services[sensor].wait_for_service()
241259

242260
# Services for oled
243261
oled_future = list_parameters.call_async(
@@ -264,6 +282,8 @@ def finalize(node: rclpy.node.Node, motors: dict[str, rclpy.client.Client]):
264282
self._hardware_namespace + "/oled/" + oled + "/set_file",
265283
),
266284
}
285+
self.oled_services[oled]["text"].wait_for_service()
286+
self.oled_services[oled]["file"].wait_for_service()
267287

268288
# Services for intensity sensors (TODO: how to expose the digital version?)
269289
intensity_future = list_parameters.call_async(
@@ -302,6 +322,7 @@ def finalize(node: rclpy.node.Node, motors: dict[str, rclpy.client.Client]):
302322
+ sensor
303323
+ "/get_analog",
304324
)
325+
self.intensity_services[sensor].wait_for_service()
305326
if (
306327
self._hardware_namespace + "/intensity/" + sensor + "/get_digital"
307328
in service_list
@@ -318,6 +339,7 @@ def finalize(node: rclpy.node.Node, motors: dict[str, rclpy.client.Client]):
318339
+ "/get_digital",
319340
)
320341
)
342+
self.intensity_services[sensor + "_digital"].wait_for_service()
321343

322344
# Services for encoder sensors
323345
encoder_future = list_parameters.call_async(
@@ -338,6 +360,7 @@ def finalize(node: rclpy.node.Node, motors: dict[str, rclpy.client.Client]):
338360
GetEncoder,
339361
self._hardware_namespace + "/encoder/" + sensor + "/get_encoder",
340362
)
363+
self.encoder_services[sensor].wait_for_service()
341364

342365
# Services for keypad sensors
343366
keypad_future = list_parameters.call_async(
@@ -358,6 +381,7 @@ def finalize(node: rclpy.node.Node, motors: dict[str, rclpy.client.Client]):
358381
GetKeypad,
359382
self._hardware_namespace + "/keypad/" + sensor + "/get_key",
360383
)
384+
self.keypad_services[sensor].wait_for_service()
361385

362386
# Services for color sensors
363387
color_future = list_parameters.call_async(
@@ -384,6 +408,9 @@ def finalize(node: rclpy.node.Node, motors: dict[str, rclpy.client.Client]):
384408
self._hardware_namespace + "/color/" + sensor + "/get_hsl",
385409
),
386410
}
411+
self.color_services[sensor]["RGBW"].wait_for_service()
412+
self.color_services[sensor]["HSL"].wait_for_service()
413+
387414

388415
self._node.destroy_client(list_parameters)
389416

@@ -409,10 +436,17 @@ def finalize(node: rclpy.node.Node, motors: dict[str, rclpy.client.Client]):
409436
def _call_service(
410437
self, client: rclpy.client.Client, request: rclpy.client.SrvTypeRequest
411438
) -> rclpy.client.SrvTypeResponse:
412-
client.wait_for_service()
413439

414-
future_response = client.call_async(request)
415-
rclpy.spin_until_future_complete(self._node, future_response)
440+
with self._lock:
441+
future_response = client.call_async(request)
442+
while not future_response.done() and not self._stopping:
443+
rclpy.spin_once(self._node, timeout_sec=0.1)
444+
445+
if self._stopping:
446+
with self._lock:
447+
self._stopping = False
448+
self._at_exit()
449+
416450
return future_response.result()
417451

418452
# FIXME: Check if services are available, if not don't hard error on:
@@ -824,8 +858,13 @@ def stop(self) -> None:
824858
for motor in self.motors:
825859
self.setMotorSpeed(motor, 0)
826860

861+
827862
def _signal_handler(self, sig, frame):
828-
self._at_exit()
863+
self._stopping = True
864+
865+
if (not self._lock.locked()):
866+
self._at_exit()
867+
829868

830869
def _at_exit(self) -> None:
831870
self.stop()

0 commit comments

Comments
 (0)