Go to the documentation of this file.00001
00002
00003 import rospy
00004 import time, socket, os
00005 from math import fabs
00006 import threading
00007 import re
00008
00009 from sound_play.libsoundplay import SoundClient
00010
00011 from diagnostic_msgs.msg import DiagnosticArray, DiagnosticStatus
00012 from fetch_driver_msgs.msg import RobotState
00013 from geometry_msgs.msg import Twist
00014 from power_msgs.msg import BatteryState, BreakerState
00015 from power_msgs.srv import BreakerCommand, BreakerCommandRequest
00016
00017
00018 import ctypes
00019 def terminate_thread(thread):
00020 """Terminates a python thread from another thread.
00021
00022 :param thread: a threading.Thread instance
00023 """
00024 if not thread.isAlive():
00025 return
00026
00027 exc = ctypes.py_object(SystemExit)
00028 res = ctypes.pythonapi.PyThreadState_SetAsyncExc(
00029 ctypes.c_long(thread.ident), exc)
00030 if res == 0:
00031 raise ValueError("nonexistent thread id")
00032 elif res > 1:
00033
00034
00035 ctypes.pythonapi.PyThreadState_SetAsyncExc(thread.ident, None)
00036 raise SystemError("PyThreadState_SetAsyncExc failed")
00037
00038 class DiagnosticsSpeakThread(threading.Thread):
00039 def __init__(self, error_status):
00040 threading.Thread.__init__(self)
00041 self.error_status = error_status
00042 self.start()
00043
00044 def run(self):
00045 global sound
00046 for status in self.error_status:
00047
00048 if status.message == "Joystick not open." :
00049 continue
00050 if status.name == "supply_breaker" and status.message == "Disabled." :
00051 continue
00052
00053 text = "Error on {}, {}".format(status.name, status.message)
00054 rospy.loginfo(text)
00055 text = text.replace('_', ', ')
00056 sound.say(text, 'voice_kal_diphone')
00057 time.sleep(5)
00058
00059 def stop(self):
00060 terminate_thread(self)
00061 self.join()
00062
00063 class Warning:
00064 def __init__(self):
00065 time.sleep(1)
00066 self.battery_sub = rospy.Subscriber("battery_state", BatteryState, self.battery_callback, queue_size = 1)
00067 self.cmd_vel_sub = rospy.Subscriber("base_controller/command", Twist, self.cmd_vel_callback, queue_size = 1)
00068 self.robot_state_sub = rospy.Subscriber("robot_state", RobotState, self.robot_state_callback, queue_size = 1)
00069 self.diagnostics_status_sub = rospy.Subscriber("diagnostics", DiagnosticArray, self.diagnostics_status_callback, queue_size = 1)
00070 self.base_breaker = rospy.ServiceProxy('base_breaker', BreakerCommand)
00071
00072 self.robot_state_msgs = RobotState()
00073 self.battery_state_msgs = BatteryState()
00074 self.twist_msgs = Twist()
00075
00076 self.diagnostics_speak_thread = {}
00077
00078 def robot_state_callback(self, msg):
00079 self.robot_state_msgs = msg
00080
00081 def battery_callback(self, msg):
00082 self.battery_state_msgs = msg
00083
00084 if msg.is_charging == False and msg.charge_level < 0.1:
00085 sound.play(2)
00086 time.sleep(2)
00087 sound.play(5)
00088 time.sleep(5)
00089
00090 def cmd_vel_callback(self, msg):
00091
00092 rospy.logdebug("cmd_vel : x:{} y:{} z:{}, battery.is_charning {}".format(msg.linear.x,msg.linear.y,msg.angular.z,self.battery_state_msgs.is_charging))
00093 breaker_enabled = True
00094 try:
00095 breaker_status = filter(lambda n: n.name=='base_breaker', self.robot_state_msgs.breakers)[0]
00096 breaker_enabled = breaker_status.state == BreakerState.STATE_ENABLED
00097 except Exception as e:
00098 rospy.logerr("Failed to fetch breaker status: %s" % str(e))
00099
00100 if ( fabs(msg.linear.x) > 0 or fabs(msg.linear.y) > 0 or fabs(msg.angular.z) > 0 ) and \
00101 self.battery_state_msgs.is_charging == True and breaker_enabled:
00102 rospy.logerr("Try to run while charging!")
00103 self.base_breaker(BreakerCommandRequest(enable=False))
00104 sound.play(4)
00105 time.sleep(5)
00106 self.base_breaker(BreakerCommandRequest(enable=True))
00107
00108 self.twist_msgs = msg
00109
00110 def diagnostics_status_callback(self, msg):
00111
00112 self.diagnostic_status_msgs = msg.status
00113
00114
00115 callerid = msg._connection_header['callerid']
00116 if not self.diagnostics_speak_thread.has_key(callerid):
00117 self.diagnostics_speak_thread[callerid] = None
00118 error_status = filter(lambda n: n.level in [DiagnosticStatus.WARN, DiagnosticStatus.ERROR, DiagnosticStatus.STALE], msg.status)
00119
00120 if self.robot_state_msgs.runstopped:
00121 error_status = filter(lambda n: not (re.match("\w*_(mcb|breaker)",n.name) or (n.name == "Mainboard" and n.message == "Runstop pressed")), error_status)
00122 if not error_status :
00123 if self.diagnostics_speak_thread[callerid] and self.diagnostics_speak_thread[callerid].is_alive():
00124 self.diagnostics_speak_thread[callerid].stop()
00125 return
00126
00127 if self.diagnostics_speak_thread[callerid] and not self.diagnostics_speak_thread[callerid].is_alive():
00128 self.diagnostics_speak_thread[callerid] = None
00129
00130 if self.diagnostics_speak_thread[callerid] is None:
00131 self.diagnostics_speak_thread[callerid] = DiagnosticsSpeakThread(error_status)
00132
00133 if __name__ == "__main__":
00134 global sound
00135 rospy.init_node("cable_warning")
00136 sound = SoundClient()
00137 w = Warning()
00138 rospy.spin()
00139
00140
00141
00142