Skip to content

Commit e44bed5

Browse files
committed
Expand the R3PTAR example to show better threading practices
1 parent d6acf0f commit e44bed5

File tree

1 file changed

+36
-11
lines changed

1 file changed

+36
-11
lines changed

demo/R3PTAR/r3ptar.py

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,24 @@
22

33
import time
44
import threading
5+
import signal
56
import ev3dev.ev3 as ev3
67

7-
def tail_waggler():
8+
def tail_waggler(done):
89
"""
910
This is the first thread of execution that will be responsible for waggling
1011
r3ptar's tail every couple of seconds.
1112
"""
1213
m = ev3.MediumMotor(); assert m.connected
1314

14-
while True:
15+
while not done.is_set():
1516
m.run_timed(speed_sp=90, time_sp=1000, stop_action='coast')
1617
time.sleep(1)
1718
ev3.Sound.play('rattle-snake.wav').wait()
1819
m.run_timed(speed_sp=-90, time_sp=1000, stop_action='coast')
1920
time.sleep(2)
2021

21-
def hand_biter():
22+
def hand_biter(done):
2223
"""
2324
This is the second thread of execution. It will constantly poll the
2425
infrared sensor for proximity info and bite anything that gets too close.
@@ -28,9 +29,11 @@ def hand_biter():
2829

2930
m.run_timed(speed_sp=-200, time_sp=1000, stop_action='brake')
3031

31-
while True:
32+
while not done.is_set():
3233
# Wait until something (a hand?!) gets too close:
33-
while s.proximity() > 30: time.sleep(0.1)
34+
while s.proximity() > 30:
35+
if done.is_set(): return
36+
time.sleep(0.1)
3437

3538
# Bite it! Also, don't forget to hiss:
3639
ev3.Sound.play('snake-hiss.wav')
@@ -39,10 +42,32 @@ def hand_biter():
3942
m.run_timed(speed_sp=-200, time_sp=500, stop_action='brake')
4043
time.sleep(1)
4144

45+
# The 'done' event will be used to signal the threads to stop:
46+
done = threading.Event()
4247

43-
# Now that we have the worker functions defined, lets start them both in
44-
# separate threads.
45-
# Actually, we could run just one of those in a separate thread, and call the
46-
# other from our own (master) thread, but this way seems to be more symmetric:
47-
threading.Thread(target=tail_waggler).start()
48-
threading.Thread(target=hand_biter).start()
48+
# We also need to catch SIGINT (keyboard interrup) and SIGTERM (termination
49+
# signal from brickman) and exit gracefully:
50+
def signal_handler(signal, frame):
51+
done.set()
52+
53+
signal.signal(signal.SIGINT, signal_handler)
54+
signal.signal(signal.SIGTERM, signal_handler)
55+
56+
# Now that we have the worker functions defined, lets run those in separate
57+
# threads.
58+
tail = threading.Thread(target=tail_waggler, args=(done,))
59+
head = threading.Thread(target=hand_biter, args=(done,))
60+
61+
tail.start()
62+
head.start()
63+
64+
# The main thread will wait for the 'back' button to be pressed. When that
65+
# happens, it will signal the worker threads to stop and wait for their
66+
# completion.
67+
btn = ev3.Button()
68+
while not btn.backspace and not done.is_set():
69+
time.sleep(0.1)
70+
71+
done.set()
72+
tail.join()
73+
head.join()

0 commit comments

Comments
 (0)