35 """ diagnostic_updater for Python. 36 @author Brice Rebsamen <brice [dot] rebsamen [gmail]> 40 from ._diagnostic_updater
import *
44 """A structure that holds the constructor parameters for the FrequencyStatus 47 Implementation note: the min_freq and max_freq parameters in the C += 1 code 48 are stored as pointers, so that if they are updated, the new values are used. 49 To emulate this behavior, we here use a dictionary to hold them: {'min','max'} 51 freq_bound is a dictionary with keys 'min' and 'max', containing the min 52 and max acceptable frequencies. 54 tolerance is the tolerance with which bounds must be satisfied. Acceptable 55 values are from freq_bound['min'] * (1 - torelance) to 56 freq_bound['max'] * (1 + tolerance). Common use cases are to set 57 tolerance to zero, or to assign the same value to freq_bound['min'] and 60 window_size is the number of events to consider in the statistics. 63 def __init__(self, freq_bound, tolerance = 0.1, window_size = 5):
64 """Creates a filled-out FrequencyStatusParam.""" 71 """A diagnostic task that monitors the frequency of an event. 73 This diagnostic task monitors the frequency of calls to its tick method, 74 and creates corresponding diagnostics. It will report a warning if the 75 frequency is outside acceptable bounds, and report an error if there have 76 been no events in the latest window. 79 def __init__(self, params, name = "FrequencyStatus"):
80 """Constructs a FrequencyStatus class with the given parameters.""" 81 DiagnosticTask.__init__(self, name)
83 self.
lock = threading.Lock()
87 """Resets the statistics.""" 90 curtime = rospy.Time.now()
91 self.
times = [curtime
for i
in range(self.params.window_size)]
92 self.
seq_nums = [0
for i
in range(self.params.window_size)]
96 """Signals that an event has occurred.""" 102 curtime = rospy.Time.now()
106 freq = events / window
112 stat.summary(2,
"No events recorded.")
113 elif freq < self.params.freq_bound[
'min'] * (1 - self.params.tolerance):
114 stat.summary(1,
"Frequency too low.")
115 elif self.params.freq_bound.has_key(
'max')
and freq > self.params.freq_bound[
'max'] * (1 + self.params.tolerance):
116 stat.summary(1,
"Frequency too high.")
118 stat.summary(0,
"Desired frequency met")
120 stat.add(
"Events in window",
"%d" % events)
121 stat.add(
"Events since startup",
"%d" % self.
count)
122 stat.add(
"Duration of window (s)",
"%f" % window)
123 stat.add(
"Actual frequency (Hz)",
"%f" % freq)
124 if self.params.freq_bound.has_key(
'max')
and self.params.freq_bound[
'min'] == self.params.freq_bound[
'max']:
125 stat.add(
"Target frequency (Hz)",
"%f" % self.params.freq_bound[
'min'])
126 if self.params.freq_bound[
'min'] > 0:
127 stat.add(
"Minimum acceptable frequency (Hz)",
"%f" % (self.params.freq_bound[
'min'] * (1 - self.params.tolerance)))
128 if self.params.freq_bound.has_key(
'max'):
129 stat.add(
"Maximum acceptable frequency (Hz)",
"%f" % (self.params.freq_bound[
'max'] * (1 + self.params.tolerance)))
135 """A structure that holds the constructor parameters for the TimeStampStatus class. 137 max_acceptable: maximum acceptable difference between two timestamps. 138 min_acceptable: minimum acceptable difference between two timestamps. 141 def __init__(self, min_acceptable = -1, max_acceptable = 5):
142 """Creates a filled-out TimeStampStatusParam.""" 148 """Diagnostic task to monitor the interval between events. 150 This diagnostic task monitors the difference between consecutive events, 151 and creates corresponding diagnostics. An error occurs if the interval 152 between consecutive events is too large or too small. An error condition 153 will only be reported during a single diagnostic report unless it 154 persists. Tallies of errors are also maintained to keep track of errors 155 in a more persistent way. 158 def __init__(self, params = TimeStampStatusParam(), name =
"Timestamp Status"):
159 """Constructs the TimeStampStatus with the given parameters.""" 160 DiagnosticTask.__init__(self, name)
173 @param stamp The timestamp of the event that will be used in computing 174 intervals. Can be either a double or a ros::Time. 176 if not isinstance(stamp, float):
177 stamp = stamp.to_sec()
183 delta = rospy.Time.now().to_sec() - stamp
193 stat.summary(0,
"Timestamps are reasonable.")
195 stat.summary(1,
"No data since last update.")
197 if self.
min_delta < self.params.min_acceptable:
198 stat.summary(2,
"Timestamps too far in future seen.")
200 if self.
max_delta > self.params.max_acceptable:
201 stat.summary(2,
"Timestamps too far in past seen.")
204 stat.summary(2,
"Zero timestamp seen.")
207 stat.add(
"Earliest timestamp delay:",
"%f" % self.
min_delta)
208 stat.add(
"Latest timestamp delay:",
"%f" % self.
max_delta)
209 stat.add(
"Earliest acceptable timestamp delay:",
"%f" % self.params.min_acceptable)
210 stat.add(
"Latest acceptable timestamp delay:",
"%f" % self.params.max_acceptable)
211 stat.add(
"Late diagnostic update count:",
"%i" % self.
late_count)
212 stat.add(
"Early diagnostic update count:",
"%i" % self.
early_count)
213 stat.add(
"Zero seen diagnostic update count:",
"%i" % self.
zero_count)
224 """Diagnostic task to monitor whether a node is alive 226 This diagnostic task always reports as OK and 'Alive' when it runs 230 """Constructs a HeartBeat""" 231 DiagnosticTask.__init__(self,
"Heartbeat")
234 stat.summary(0,
"Alive")
def __init__(self, params=TimeStampStatusParam(), name="Timestamp Status")
def __init__(self, params, name="FrequencyStatus")
def __init__(self, min_acceptable=-1, max_acceptable=5)
def __init__(self, freq_bound, tolerance=0.1, window_size=5)