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
00038
00039
00040
00041
00042 import string
00043 import sys
00044 import threading
00045 import time
00046
00047 import roslib.message
00048 import roslib.scriptutil
00049
00050 import rospy
00051
00052 class RosPlotException(Exception): pass
00053
00054
00055
00056
00057
00058 def _get_topic_type(topic):
00059 code, msg, val = roslib.scriptutil.get_master().getPublishedTopics('/', '/')
00060 if code != 1:
00061 raise RosPlotException("unable to get list of topics from master")
00062 matches = [(t, t_type) for t, t_type in val if t == topic or topic.startswith(t+'/')]
00063 if matches:
00064 t, t_type = matches[0]
00065 if t_type == roslib.names.ANYTYPE:
00066 return None, None, None
00067 if t_type == topic:
00068 return t_type, None
00069 return t_type, t, topic[len(t):]
00070 else:
00071 return None, None, None
00072
00073
00074
00075
00076 def get_topic_type(topic):
00077 topic_type, real_topic, rest = _get_topic_type(topic)
00078 if topic_type:
00079 return topic_type, real_topic, rest
00080 else:
00081 print >> sys.stderr, "WARNING: topic [%s] does not appear to be published yet"%topic
00082 while not rospy.is_shutdown():
00083 topic_type, real_topic, rest = _get_topic_type(topic)
00084 if topic_type:
00085 return topic_type, real_topic, rest
00086 else:
00087 time.sleep(0.1)
00088 return None, None, None
00089
00090
00091
00092 class ROSData(object):
00093
00094 def __init__(self, topic, start_time):
00095 self.name = topic
00096 self.start_time = start_time
00097 self.error = None
00098
00099 self.lock = threading.Lock()
00100 self.buff_x = []
00101 self.buff_y = []
00102
00103 topic_type, real_topic, fields = get_topic_type(topic)
00104 self.field_evals = generate_field_evals(fields)
00105 data_class = roslib.message.get_message_class(topic_type)
00106 self.sub = rospy.Subscriber(real_topic, data_class, self._ros_cb)
00107
00108 def close(self):
00109 self.sub.unregister()
00110
00111
00112
00113
00114 def _ros_cb(self, msg):
00115 try:
00116 self.lock.acquire()
00117 try:
00118 self.buff_y.append(self._get_data(msg))
00119
00120 if msg.__class__._has_header:
00121 self.buff_x.append(msg.header.stamp.to_sec() - self.start_time)
00122 else:
00123 self.buff_x.append(rospy.get_time() - self.start_time)
00124
00125 except AttributeError, e:
00126 self.error = RosPlotException("Invalid topic spec [%s]: %s"%(self.name, str(e)))
00127 finally:
00128 self.lock.release()
00129
00130
00131
00132
00133 def next(self):
00134 if self.error:
00135 raise self.error
00136 try:
00137 self.lock.acquire()
00138 buff_x = self.buff_x
00139 buff_y = self.buff_y
00140 self.buff_x = []
00141 self.buff_y = []
00142 finally:
00143 self.lock.release()
00144 return buff_x, buff_y
00145
00146 def _get_data(self, msg):
00147 val = msg
00148 try:
00149 if not self.field_evals:
00150 return float(val)
00151 for f in self.field_evals:
00152 val = f(val)
00153 return float(val)
00154 except TypeError:
00155 print "[%s] value was not numeric: %s"%(self.name, val)
00156
00157 sys.exit(1)
00158
00159 _paused = False
00160 def toggle_ros_pause():
00161 global _paused
00162 _paused = not _paused
00163
00164
00165 _stopped = False
00166 def set_ros_stop():
00167 global _stopped, _paused
00168 _stopped = True
00169 _paused = True
00170
00171 def is_ros_pause():
00172 return _paused
00173 def is_ros_stop():
00174 return _stopped
00175
00176
00177
00178
00179 def _array_eval(field_name, slot_num):
00180 def fn(f):
00181 return getattr(f, field_name).__getitem__(slot_num)
00182 return fn
00183
00184
00185
00186 def _field_eval(field_name):
00187 def fn(f):
00188 return getattr(f, field_name)
00189 return fn
00190
00191 def generate_field_evals(fields):
00192 try:
00193 evals = []
00194 fields = [f for f in fields.split('/') if f]
00195 for f in fields:
00196 if '[' in f:
00197 field_name, rest = f.split('[')
00198 slot_num = string.atoi(rest[:rest.find(']')])
00199 evals.append(_array_eval(field_name, slot_num))
00200 else:
00201 evals.append(_field_eval(f))
00202 return evals
00203 except Exception, e:
00204 raise RosPlotException("cannot parse field reference [%s]: %s"%(fields, str(e)))
00205