Go to the documentation of this file.00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 from __future__ import with_statement
00038 
00039 PKG='continuous_ops_alerts'
00040 import roslib; roslib.load_manifest(PKG)
00041 
00042 import rospy
00043 from googlevoice import Voice
00044 from googlevoice.util import input
00045 
00046 import tf2
00047 import tf2_ros
00048 
00049 import math
00050 
00051 from geometry_msgs.msg import PoseStamped
00052 from pr2_msgs.msg import PowerState
00053 from std_msgs.msg import Bool
00054 import tf2_geometry_msgs
00055 
00056 import threading
00057 
00058 class ContinuousOpsMonitor:
00059     def __init__(self, voice):
00060         self.voice = voice
00061         self.tf_client = tf2_ros.BufferClient('tf2_buffer_server')
00062         rospy.loginfo('Continuous ops monitor waiting for tf server')
00063         self.tf_client.wait_for_server()
00064         rospy.loginfo('Continuous ops monitor connected to tf server')
00065 
00066         self.move_distance = rospy.get_param('~move_distance', 2.0)
00067         self.move_timeout = rospy.get_param('~move_timeout', 300.0)
00068         
00069         self.phone_numbers = ['5107100513', '6505294522']
00070         
00071         self.last_pose = PoseStamped()
00072         self.last_pose.header.stamp = rospy.Time.now()
00073 
00074         self.mutex = threading.Lock()
00075         self.plugged_in = True
00076 
00077         self.power_sub = rospy.Subscriber('power_state', PowerState, self.power_cb)
00078         self.motor_sub = rospy.Subscriber('pr2_etherCAT/motors_halted', Bool, self.motor_cb)
00079         self.motors_halted = False
00080 
00081 
00082     def motor_cb(self, msg):
00083         with self.mutex:
00084             if msg.data:
00085                 if not self.motors_halted:
00086                     self.send_sms('My leg hurts, by casters suck, my motors halted... ')
00087                 self.motors_halted = True
00088             else:
00089                 self.motors_halted = False
00090 
00091     def power_cb(self, msg):
00092         with self.mutex:
00093             if msg.AC_present == 0:
00094                 if self.plugged_in:
00095                     self.last_pose.header.stamp = rospy.Time.now()
00096                 self.plugged_in = False
00097                 
00098             else:
00099                 self.plugged_in = True
00100 
00101     def distance(self, p1, p2):
00102         dx = p1.pose.position.x - p2.pose.position.x
00103         dy = p1.pose.position.y - p2.pose.position.y
00104         distance = math.sqrt(dx * dx + dy * dy)
00105         return distance
00106 
00107     def distance_check(self):
00108         base_pose = PoseStamped()
00109         base_pose.header.stamp = rospy.Time(0.0)
00110         base_pose.header.frame_id = 'base_link'
00111         base_pose.pose.orientation.w = 1.0
00112 
00113         try:
00114             map_pose = self.tf_client.transform(base_pose, 'map')
00115             dist = self.distance(map_pose, self.last_pose)
00116 
00117             
00118             if dist > self.move_distance:
00119                 self.last_pose = map_pose
00120                 return
00121 
00122             
00123             if self.last_pose.header.stamp + rospy.Duration(self.move_timeout) < rospy.Time.now():
00124                 self.send_sms('Robot has not moved in %s seconds, please check if it needs help.' % self.move_timeout)
00125                 
00126                 self.last_pose.header.stamp = rospy.Time.now()
00127 
00128         except tf2.TransformException as e:
00129             rospy.logerr("%s" % e)
00130 
00131     def send_sms(self, text):
00132         for number in self.phone_numbers:
00133             self.voice.send_sms(number, text)
00134 
00135     def run(self):
00136         r = rospy.Rate(0.1)
00137         while not rospy.is_shutdown():
00138             with self.mutex:
00139                 if not self.plugged_in:
00140                     
00141                     self.distance_check()
00142             r.sleep()
00143 
00144 if __name__ == '__main__':
00145     rospy.init_node('continuous_ops_alert')
00146     voice = Voice()
00147     voice.login()
00148     com = ContinuousOpsMonitor(voice)
00149 
00150     try:
00151         com.run()
00152     except rospy.ROSInterruptException: pass
00153