22
33import time
44import threading
5+ import signal
56import 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