Skip to content

Commit 48dd913

Browse files
committed
modified watchdog to spawn fewer threads. added locks for thread safety
1 parent 1e7778f commit 48dd913

File tree

2 files changed

+70
-10
lines changed

2 files changed

+70
-10
lines changed

src/prpy/base/mico.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from manipulator import Manipulator
3333
from std_msgs.msg import Float64
3434
import rospy
35+
import threading
3536
from ..util import Watchdog
3637

3738
class Mico(Manipulator):
@@ -74,9 +75,10 @@ def __init__(self, sim,
7475
#if not simulation, create publishers for each joint
7576
self.velocity_topic_names = ['vel_j'+str(i)+'_controller/command' for i in range(1,7)]
7677
self.velocity_publishers = [rospy.Publisher(topic_name, Float64, queue_size=1) for topic_name in self.velocity_topic_names]
78+
self.velocity_publisher_lock = threading.Lock()
7779

7880
#create watchdog to send zero velocity
79-
self.servo_watchdog = Watchdog(timeout_duration=0.25, handler=lambda: self.SendVelocitiesToMico([0.,0.,0.,0.,0.,0.,]))
81+
self.servo_watchdog = Watchdog(timeout_duration=0.25, handler=self.SendVelocitiesToMico, args=[[0.,0.,0.,0.,0.,0.,]])
8082

8183
def CloneBindings(self, parent):
8284
super(Mico, self).CloneBindings(parent)
@@ -115,5 +117,6 @@ def Servo(self, velocities):
115117

116118

117119
def SendVelocitiesToMico(self, velocities):
118-
for velocity_publisher,velocity in zip(self.velocity_publishers, velocities):
119-
velocity_publisher.publish(velocity)
120+
with self.velocity_publisher_lock:
121+
for velocity_publisher,velocity in zip(self.velocity_publishers, velocities):
122+
velocity_publisher.publish(velocity)

src/prpy/util.py

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -498,19 +498,76 @@ def get_duration(self):
498498
return self.end - self.start
499499

500500
class Watchdog(object):
501-
def __init__(self, timeout_duration, handler):
501+
'''
502+
Calls specified function after duration, unless reset/stopped beforehand
503+
504+
@param timeout_duration how long to wait before calling handler
505+
@param handler function to call after timeout_duration
506+
@param args for handler
507+
@param kwargs for handler
508+
'''
509+
def __init__(self, timeout_duration, handler, args=(), kwargs={}):
502510
self.timeout_duration = timeout_duration
503511
self.handler = handler
504-
self.timer = threading.Timer(self.timeout_duration, self.handler)
505-
self.timer.start()
512+
self.handler_args = args
513+
self.handler_kwargs = kwargs
514+
515+
self.thread_checking_time = threading.Thread(target=self._check_timer_loop)
516+
self.timer_thread_lock = threading.Lock()
517+
self.start_time = time.time()
518+
self.canceled = False
519+
520+
self.thread_checking_time.start()
521+
#self.timer = threading.Timer(self.timeout_duration, self.handler)
522+
#self.timer.start()
506523

507524
def reset(self):
508-
self.timer.cancel()
509-
self.timer = threading.Timer(self.timeout_duration, self.handler)
510-
self.timer.start()
525+
'''
526+
Resets the timer
527+
528+
Causes the handler function to be called after the next
529+
timeout duration is reached
530+
531+
Also restarts the timer thread if it has existed
532+
'''
533+
with self.timer_thread_lock:
534+
self.start_time = time.time()
535+
self.canceled = False
536+
if not self.thread_checking_time.is_alive():
537+
self.thread_checking_time = threading.Thread(target=self._check_timer_loop)
538+
self.thread_checking_time.start()
539+
540+
#self.timer.cancel()
541+
#self.timer = threading.Timer(self.timeout_duration, self.handler)
542+
#self.timer.start()
511543

512544
def stop(self):
513-
self.timer.cancel()
545+
'''
546+
Stop the watchdog, so it will not call handler
547+
'''
548+
with self.timer_thread_lock:
549+
self.canceled = True
550+
551+
def _check_timer_loop(self):
552+
'''
553+
Internal function for timer thread to loop
554+
555+
If elapsed time has passed, calls the handler function
556+
Exists if watchdog was canceled, or handler was called
557+
'''
558+
while True:
559+
with self.timer_thread_lock:
560+
if self.canceled:
561+
break
562+
elapsed_time = time.time() - self.start_time
563+
if elapsed_time > self.timeout_duration:
564+
self.handler(*self.handler_args, **self.handler_kwargs)
565+
self.canceled = True
566+
break
567+
else:
568+
time.sleep(self.timeout_duration - elapsed_time)
569+
570+
514571

515572

516573
def quadraticPlusJointLimitObjective(dq, J, dx, q, q_min, q_max, delta_joint_penalty=5e-1, lambda_dqdist=0.01, *args):

0 commit comments

Comments
 (0)