Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 import rospy, rostopic
00016 from std_msgs.msg import String
00017
00018 class GlassMonitor:
00019 '''Class to monitor desired topics and feilds and send out messages
00020 when the value on that topic exceeds a defined threshold value
00021 in order to build the monitor it requires the needed information
00022 to be input as a parameter when the node is launched
00023 The input contains a list of dictonaries that have each of the following defined
00024
00025 topic: The rostopic to monitor
00026 field: The fully named field within the message to check
00027 op: Comparison to make can be one of the following: gt, lt, eq, ne,within, outside
00028 val: The value to check against
00029 msg: The message to display when the check has been violated
00030
00031 And example .launch input is below:
00032
00033 <node name="monitor" type="glass_monitor.py" pkg="ros_glass_tools" output="s
00034 <rosparam param="monitors">
00035 [
00036 { topic: '/a/pose', field: 'translation/x', op: 'gt', val : 2 , msg: 'UAV is too far to the left'},
00037 { topic: '/a/pose', field: 'translation/z', op: 'gt', val : 2 , msg: 'UAV is too high!'}
00038 ]
00039 </rosparam>
00040 </node>
00041 '''
00042
00043 def __init__(self):
00044
00045 rospy.init_node("glass_monitor")
00046 self.warn_pub = rospy.Publisher('/glass_warn', String)
00047
00048 input_list = rospy.get_param('~monitors', None)
00049 self.monitor_list = self.process_input(input_list)
00050
00051
00052
00053 def process_input(self, input_list):
00054 '''this method takes the input parameter to create the monitors
00055 the topic must already be published so that this method
00056 can determine the message type
00057 '''
00058 sub_list = []
00059 for monitor in input_list:
00060 msg_type = rostopic.get_topic_class(monitor['topic'])[0]
00061
00062
00063
00064 if msg_type != None:
00065 sub_list.append(rospy.Subscriber(monitor['topic'],msg_type, self.callback, monitor))
00066 rospy.logerr('Started for topic %s', monitor['topic'])
00067 else:
00068 rospy.logerr("Cannot determine type of topic %s", monitor['topic'])
00069 return sub_list
00070
00071 def callback(self, msg, info):
00072 '''generic callback for the monitor topics
00073 this will get the desired comparison and check that value
00074 if it is violated than the node will publish warning message
00075 to the glass topic'''
00076
00077 data = float(self.get_msg_data(msg, info['field']) )
00078 op = info['op']
00079 check_val = float(info['val'])
00080
00081 if op == 'lt':
00082 if data < check_val:
00083 st = String(info['msg'])
00084 self.warn_pub.publish(st)
00085
00086 elif op == 'gt':
00087 if data > check_val:
00088 st = String(info['msg'])
00089 self.warn_pub.publish(st)
00090
00091 elif op == 'ne':
00092 if data != check_val:
00093 st = String(info['msg'])
00094 self.warn_pub.publish(st)
00095
00096 elif op == 'eq':
00097 if data == check_val:
00098 st = String(info['msg'])
00099 self.warn_pub.publish(st)
00100 elif op == 'within':
00101 if abs(data) > check_val:
00102 st = String(info['msg'])
00103 self.warn_pub.publish(st)
00104 elif op == 'outside':
00105 if abs(data) < check_val:
00106 st = String(info['msg'])
00107 self.warn_pub.publish(st)
00108 else:
00109 rospy.logerr("Invalid operation %s", info['op'])
00110
00111
00112 def get_msg_data(self, msg, key):
00113 '''Have to slpit the keys up and recursivly call to get
00114 the desired information out of all the messages'''
00115 idx = key.find('/')
00116 if idx == -1:
00117 return msg.__getattribute__(key)
00118 else:
00119
00120 sub_key = key[idx+1:]
00121 key = key[:idx]
00122 msg = msg.__getattribute__(key)
00123 return self.get_msg_data(msg, sub_key)
00124
00125
00126
00127 if __name__ == '__main__':
00128 rm =GlassMonitor()
00129 rospy.spin();