00001
00002 import roslib; roslib.load_manifest('husky_bringup')
00003 import rospy
00004
00005 from clearpath_base.msg import SystemStatus, SafetyStatus, PowerStatus
00006 from diagnostic_msgs.msg import DiagnosticArray, DiagnosticStatus, KeyValue
00007
00008
00009 UNDERVOLT_ERROR = 18
00010 UNDERVOLT_WARN = 19
00011 OVERVOLT_ERROR = 30
00012 OVERVOLT_WARN = 29
00013 DRIVER_OVERTEMP_ERROR = 50
00014 DRIVER_OVERTEMP_WARN = 30
00015 MOTOR_OVERTEMP_ERROR = 80
00016 MOTOR_OVERTEMP_WARN = 70
00017 LOWPOWER_ERROR = 0.2
00018 LOWPOWER_WARN = 0.3
00019 SAFETY_TIMEOUT = 0x1
00020 SAFETY_LOCKOUT = 0x2
00021 SAFETY_ESTOP = 0x8
00022 SAFETY_CCI = 0x10
00023 SAFETY_PSU= 0x20
00024 SAFETY_CURRENT = 0x40
00025 SAFETY_WARN = (SAFETY_TIMEOUT | SAFETY_CCI | SAFETY_PSU)
00026 SAFETY_ERROR = (SAFETY_LOCKOUT | SAFETY_ESTOP | SAFETY_CURRENT)
00027
00028 class HuskyDiagnostics():
00029 def __init__(self):
00030 rospy.init_node('husky_diagnostics')
00031 self.diag_pub = rospy.Publisher('/diagnostics', DiagnosticArray)
00032 self.last_diagnostics_time = rospy.get_rostime()
00033 rospy.Subscriber('husky/data/system_status', SystemStatus, self.HandleSystemStatus)
00034 rospy.Subscriber('husky/data/safety_status', SafetyStatus, self.HandleSafetyStatus)
00035 rospy.Subscriber('husky/data/power_status', PowerStatus, self.HandlePowerStatus)
00036
00037 self.stat_estop = []
00038 self.stat_power = []
00039 self.stat_voltage = []
00040 self.stat_temp = []
00041 self.stat_uptime = []
00042
00043
00044
00045 def _publish(self, time):
00046 """ Publishes diagnostic data"""
00047
00048 if (time - self.last_diagnostics_time).to_sec() < 1.0:
00049 return
00050 self.last_diagnostics_time = time
00051 diag = DiagnosticArray()
00052 diag.header.stamp = time
00053
00054
00055 if self.stat_estop:
00056 diag.status.append(self.stat_estop)
00057
00058 if self.stat_power:
00059 diag.status.append(self.stat_power)
00060
00061 if self.stat_voltage:
00062 diag.status.append(self.stat_voltage)
00063
00064 if self.stat_temp:
00065 diag.status.append(self.stat_temp)
00066
00067 if self.stat_uptime:
00068 diag.status.append(self.stat_uptime)
00069
00070
00071 print diag
00072 self.diag_pub.publish(diag)
00073
00074 def HandleSystemStatus(self,data):
00075
00076 self.stat_uptime = DiagnosticStatus(name="Uptime",level=DiagnosticStatus.OK, message="Robot Online")
00077 uptime = data.uptime
00078 self.stat_uptime.values = [KeyValue("Uptime (ms)",str(uptime))]
00079
00080
00081 bus_volt = data.voltages[0]
00082 self.stat_voltage = DiagnosticStatus(name="Voltage",level=DiagnosticStatus.OK, message="Voltage OK")
00083 if bus_volt > OVERVOLT_ERROR:
00084 self.stat_voltage.level = DiagnosticStatus.ERROR
00085 self.stat_voltage.message = "Main bus voltage too high"
00086 elif bus_volt > OVERVOLT_WARN:
00087 self.stat_voltage.level = DiagnosticStatus.WARN
00088 self.stat_voltage.message = "Main bus voltage too high"
00089 elif bus_volt < UNDERVOLT_ERROR:
00090 self.stat_voltage.level = DiagnosticStatus.ERROR
00091 self.stat_voltage.message = "Main bus voltage too low"
00092 elif bus_volt < UNDERVOLT_WARN:
00093 self.stat_voltage.level = DiagnosticStatus.WARN
00094 self.stat_voltage.message = "Main bus voltage too low"
00095
00096 self.stat_voltage.values = [KeyValue("Bus voltage (V)",str(bus_volt))]
00097
00098
00099 self.stat_temp = DiagnosticStatus(name="Temperature",level=DiagnosticStatus.OK, message="OK")
00100 left_drv = data.temperatures[0]
00101 right_drv = data.temperatures[1]
00102 left_mot = data.temperatures[2]
00103 right_mot = data.temperatures[3]
00104 if max(left_drv,right_drv) > DRIVER_OVERTEMP_ERROR:
00105 self.stat_temp.level = DiagnosticStatus.ERROR
00106 self.stat_temp.message = "Motor drivers too hot"
00107 elif max(left_drv,right_drv) > DRIVER_OVERTEMP_WARN:
00108 self.stat_temp.level = DiagnosticStatus.WARN
00109 self.stat_temp.message = "Motor drivers too hot"
00110 if max(left_mot,right_mot) > MOTOR_OVERTEMP_ERROR:
00111 self.stat_temp.level = DiagnosticStatus.ERROR
00112 self.stat_temp.message = "Motors too hot"
00113 elif max(left_mot,right_mot) > MOTOR_OVERTEMP_WARN:
00114 self.stat_temp.level = DiagnosticStatus.WARN
00115 self.stat_temp.message = "Motors too hot"
00116
00117 self.stat_temp.values = [KeyValue("Left motor driver (C)",str(left_drv)),
00118 KeyValue("Right motor driver (C)",str(right_drv)),
00119 KeyValue("Left motor (C)",str(left_mot)),
00120 KeyValue("Right motor (C)",str(right_mot))]
00121
00122
00123 self._publish(data.header.stamp)
00124
00125 def HandleSafetyStatus(self,data):
00126
00127 self.stat_estop = DiagnosticStatus(name="Safety System",level=DiagnosticStatus.OK,
00128 message="OK")
00129 flags = data.flags
00130
00131 if flags & SAFETY_ERROR:
00132 self.stat_estop.level = DiagnosticStatus.ERROR
00133 self.stat_estop.message = "Error"
00134 elif flags & SAFETY_WARN:
00135 self.stat_estop.level = DiagnosticStatus.WARN
00136 self.stat_estop.message = "Warning"
00137
00138 self.stat_estop.values = [KeyValue("Timeout",str(flags & SAFETY_TIMEOUT > 0)),
00139 KeyValue("Lockout",str(flags & SAFETY_LOCKOUT > 0)),
00140 KeyValue("Emergency Stop",str(flags & SAFETY_ESTOP > 0)),
00141 KeyValue("ROS Pause",str(flags & SAFETY_CCI > 0)),
00142 KeyValue("No battery",str(flags & SAFETY_PSU > 0)),
00143 KeyValue("Current limit",str(flags & SAFETY_CURRENT > 0))]
00144
00145
00146 self._publish(data.header.stamp)
00147
00148 def HandlePowerStatus(self,data):
00149
00150 self.stat_power = DiagnosticStatus(name="Power System",level=DiagnosticStatus.OK, message="OK")
00151 charge = data.sources[0].charge
00152 capacity = data.sources[0].capacity
00153 present = data.sources[0].present
00154 bat_type = data.sources[0].description
00155 if charge < LOWPOWER_WARN:
00156 self.stat_power.level = DiagnosticStatus.WARN
00157 self.stat_power.message = "Low power"
00158 if charge < LOWPOWER_ERROR:
00159 self.stat_power.level = DiagnosticStatus.ERROR
00160 self.stat_power.values = [KeyValue("Charge (%)",str(charge)),
00161 KeyValue("Battery Capacity (Wh)",str(capacity))]
00162
00163
00164 self._publish(data.header.stamp)
00165
00166 if __name__ == "__main__":
00167 obj = HuskyDiagnostics()
00168 try:
00169 rospy.spin()
00170 except rospy.ROSInterruptException:
00171 pass