_update_functions.py
Go to the documentation of this file.
00001 # -*- coding: utf-8 -*-
00002 
00003 """ diagnostic_updater for Python.
00004 @author Brice Rebsamen <brice [dot] rebsamen [gmail]>
00005 """
00006 
00007 import roslib
00008 roslib.load_manifest('diagnostic_updater')
00009 import rospy
00010 from ._diagnostic_updater import *
00011 
00012 
00013 class FrequencyStatusParam:
00014     """A structure that holds the constructor parameters for the FrequencyStatus
00015     class.
00016 
00017     Implementation note: the min_freq and max_freq parameters in the C += 1 code
00018     are stored as pointers, so that if they are updated, the new values are used.
00019     To emulate this behavior, we here use a dictionary to hold them: {'min','max'}
00020 
00021     freq_bound is a dictionary with keys 'min' and 'max', containing the min
00022     and max acceptable frequencies.
00023 
00024     tolerance is the tolerance with which bounds must be satisfied. Acceptable
00025     values are from freq_bound['min'] * (1 - torelance) to
00026     freq_bound['max'] * (1 + tolerance). Common use cases are to set
00027     tolerance to zero, or to assign the same value to freq_bound['min'] and
00028     freq_bound['max']
00029 
00030     window_size is the number of events to consider in the statistics.
00031     """
00032 
00033     def __init__(self, freq_bound, tolerance = 0.1, window_size = 5):
00034         """Creates a filled-out FrequencyStatusParam."""
00035         self.freq_bound = freq_bound
00036         self.tolerance = tolerance
00037         self.window_size = window_size
00038 
00039 
00040 class FrequencyStatus(DiagnosticTask):
00041     """A diagnostic task that monitors the frequency of an event.
00042 
00043     This diagnostic task monitors the frequency of calls to its tick method,
00044     and creates corresponding diagnostics. It will report a warning if the
00045     frequency is outside acceptable bounds, and report an error if there have
00046     been no events in the latest window.
00047     """
00048 
00049     def __init__(self, params):
00050         """Constructs a FrequencyStatus class with the given parameters."""
00051         DiagnosticTask.__init__(self, "Frequency Status")
00052         self.params = params
00053         self.lock = threading.Lock()
00054         self.clear()
00055 
00056     def clear(self):
00057         """Resets the statistics."""
00058         with self.lock:
00059             self.count = 0
00060             curtime = rospy.Time.now()
00061             self.times = [curtime for i in range(self.params.window_size)]
00062             self.seq_nums = [0 for i in range(self.params.window_size)]
00063             self.hist_indx = 0
00064 
00065     def tick(self):
00066         """Signals that an event has occurred."""
00067         with self.lock:
00068             #rospy.logdebug("TICK %i" % self.count)
00069             self.count += 1
00070 
00071     def run(self, stat):
00072         with self.lock:
00073             curtime = rospy.Time.now()
00074             curseq = self.count
00075             events = curseq - self.seq_nums[self.hist_indx]
00076             window = (curtime - self.times[self.hist_indx]).to_sec()
00077             freq = events / window
00078             self.seq_nums[self.hist_indx] = curseq
00079             self.times[self.hist_indx] = curtime
00080             self.hist_indx = (self.hist_indx + 1) % self.params.window_size
00081 
00082             if events == 0:
00083                 stat.summary(2, "No events recorded.")
00084             elif freq < self.params.freq_bound['min'] * (1 - self.params.tolerance):
00085                 stat.summary(1, "Frequency too low.")
00086             elif freq > self.params.freq_bound['max'] * (1 + self.params.tolerance):
00087                 stat.summary(1, "Frequency too high.")
00088             else:
00089                 stat.summary(0, "Desired frequency met")
00090 
00091             stat.add("Events in window", "%d" % events)
00092             stat.add("Events since startup", "%d" % self.count)
00093             stat.add("Duration of window (s)", "%f" % window)
00094             stat.add("Actual frequency (Hz)", "%f" % freq)
00095             if self.params.freq_bound['min'] == self.params.freq_bound['max']:
00096                 stat.add("Target frequency (Hz)", "%f" % self.params.freq_bound['min'])
00097             if self.params.freq_bound['min'] > 0:
00098                 stat.add("Minimum acceptable frequency (Hz)", "%f" % (self.params.freq_bound['min'] * (1 - self.params.tolerance)))
00099             if self.params.freq_bound['max']:
00100                 stat.add("Maximum acceptable frequency (Hz)", "%f" % (self.params.freq_bound['max'] * (1 + self.params.tolerance)))
00101 
00102         return stat
00103 
00104 
00105 class TimeStampStatusParam:
00106     """A structure that holds the constructor parameters for the TimeStampStatus class.
00107 
00108     max_acceptable: maximum acceptable difference between two timestamps.
00109     min_acceptable: minimum acceptable difference between two timestamps.
00110     """
00111 
00112     def __init__(self, min_acceptable = -1, max_acceptable = 5):
00113         """Creates a filled-out TimeStampStatusParam."""
00114         self.max_acceptable = max_acceptable
00115         self.min_acceptable = min_acceptable
00116 
00117 
00118 class TimeStampStatus(DiagnosticTask):
00119     """Diagnostic task to monitor the interval between events.
00120 
00121     This diagnostic task monitors the difference between consecutive events,
00122     and creates corresponding diagnostics. An error occurs if the interval
00123     between consecutive events is too large or too small. An error condition
00124     will only be reported during a single diagnostic report unless it
00125     persists. Tallies of errors are also maintained to keep track of errors
00126     in a more persistent way.
00127     """
00128 
00129     def __init__(self, params = TimeStampStatusParam()):
00130         """Constructs the TimeStampStatus with the given parameters."""
00131         DiagnosticTask.__init__(self, "Timestamp Status")
00132         self.params = params
00133         self.lock = threading.Lock()
00134         self.early_count = 0
00135         self.late_count = 0
00136         self.zero_count = 0
00137         self.zero_seen = False
00138         self.max_delta = 0
00139         self.min_delta = 0
00140         self.deltas_valid = False
00141 
00142     def tick(self, stamp):
00143         """Signals an event.
00144         @param stamp The timestamp of the event that will be used in computing
00145         intervals. Can be either a double or a ros::Time.
00146         """
00147         if isinstance(stamp, rospy.Time):
00148             stamp = stamp.to_sec()
00149 
00150         with self.lock:
00151             if stamp == 0:
00152                 self.zero_seen = True
00153             else:
00154                 delta = rospy.Time.now().to_sec() - stamp
00155                 if not self.deltas_valid or delta > self.max_delta:
00156                     self.max_delta = delta
00157                 if not self.deltas_valid or delta < self.min_delta:
00158                     self.min_delta = delta
00159                 self.deltas_valid = True
00160 
00161     def run(self, stat):
00162         with self.lock:
00163 
00164             stat.summary(0, "Timestamps are reasonable.")
00165             if not self.deltas_valid:
00166                 stat.summary(1, "No data since last update.")
00167             else:
00168                 if self.min_delta < self.params.min_acceptable:
00169                     stat.summary(2, "Timestamps too far in future seen.")
00170                     self.early_count += 1
00171                 if self.max_delta > self.params.max_acceptable:
00172                     stat.summary(2, "Timestamps too far in past seen.")
00173                     self.late_count += 1
00174                 if self.zero_seen:
00175                     stat.summary(2, "Zero timestamp seen.")
00176                     self.zero_count += 1
00177 
00178             stat.add("Earliest timestamp delay:", "%f" % self.min_delta)
00179             stat.add("Latest timestamp delay:", "%f" % self.max_delta)
00180             stat.add("Earliest acceptable timestamp delay:", "%f" % self.params.min_acceptable)
00181             stat.add("Latest acceptable timestamp delay:", "%f" % self.params.max_acceptable)
00182             stat.add("Late diagnostic update count:", "%i" % self.late_count)
00183             stat.add("Early diagnostic update count:", "%i" % self.early_count)
00184             stat.add("Zero seen diagnostic update count:", "%i" % self.zero_count)
00185 
00186             self.deltas_valid = False
00187             self.min_delta = 0
00188             self.max_delta = 0
00189             self.zero_seen = False
00190 
00191         return stat


diagnostic_updater
Author(s): Jeremy Leibs, Blaise Gassend, Brice Rebsamen
autogenerated on Fri Jan 3 2014 11:18:57