37 A node to check the TF tree 39 A big chunk of the code was copied from tfwtf, the wtf plugin for tf. 42 import roslib; roslib.load_manifest(
'diagnostic_common_diagnostics')
44 import diagnostic_updater
as DIAG
59 for m, stamp, callerid
in _msgs:
60 for t
in m.transforms:
61 d = t.header.stamp - stamp
64 if callerid
in deltas:
65 if abs(secs) > abs(deltas[callerid]):
66 deltas[callerid] = secs
68 deltas[callerid] = secs
71 for k, v
in deltas.iteritems():
72 errors.append(
"receiving transform from [%s] that differed from ROS time by %ss"%(k, v))
78 for m, stamp, callerid
in _msgs:
79 for t
in m.transforms:
80 frame_id = t.child_frame_id
81 parent_id = t.header.frame_id
82 if frame_id
in parent_id_map
and parent_id_map[frame_id] != parent_id:
83 msg =
"reparenting of [%s] to [%s] by [%s]"%(frame_id, parent_id, callerid)
84 parent_id_map[frame_id] = parent_id
88 parent_id_map[frame_id] = parent_id
95 for m, stamp, callerid
in _msgs:
96 for t
in m.transforms:
97 frame_id = t.child_frame_id
98 parent_id = t.header.frame_id
99 parent_id_map[frame_id] = parent_id
101 for frame
in parent_id_map:
103 current_frame = frame
105 while count < max_depth + 2:
107 frame_list.append(current_frame)
109 current_frame = parent_id_map[current_frame]
112 if current_frame == frame:
113 errors.append(
"Frame %s is in a loop. It's loop has elements:\n%s"% (frame,
" -> ".join(frame_list)))
122 for m, stamp, callerid
in _msgs:
123 for t
in m.transforms:
124 frame_id = t.child_frame_id
125 parent_id = t.header.frame_id
126 if frame_id
in authority_map
and authority_map[frame_id] != callerid:
127 msg =
"node [%s] publishing transform [%s] with parent [%s] already published by node [%s]"%(callerid, frame_id, parent_id, authority_map[frame_id])
128 authority_map[frame_id] = callerid
129 if msg
not in errors:
132 authority_map[frame_id] = callerid
140 _msgs.append((msg, rospy.get_rostime(), msg._connection_header[
'callerid']))
148 '''A diagnostic function generator''' 151 stat.summary(0, okmsg)
154 if isinstance(res, bool):
156 stat.summary(errlvl, errmsg)
157 elif isinstance(res, list):
159 stat.summary(errlvl, errmsg)
160 for i,r
in enumerate(res):
161 stat.add(
"Error %d" % (i+1), r)
168 rospy.init_node(
'tf_monitor')
171 diag_updater = DIAG.Updater()
172 diag_updater.setHardwareID(
'none')
173 diag_updater.add(
'Messaging status',
make_diag_fn(no_msgs, DIAG.WARN,
'No tf messages received') )
174 diag_updater.add(
'Time status',
make_diag_fn(rostime_delta, DIAG.WARN,
'Received out-of-date/future transforms') )
175 diag_updater.add(
'Reparenting status',
make_diag_fn(reparenting, DIAG.ERROR,
'TF re-parenting contention') )
176 diag_updater.add(
'Cycle status',
make_diag_fn(cycle_detection, DIAG.ERROR,
'TF cycle detection') )
177 diag_updater.add(
'Multiple authority status',
make_diag_fn(multiple_authority, DIAG.ERROR,
'TF multiple authority contention') )
180 while not rospy.is_shutdown():
182 sub1 = rospy.Subscriber(
'/tf', tf.msg.tfMessage, _tf_handle)
185 diag_updater.update()
def make_diag_fn(fn, errlvl, errmsg, okmsg="OK")
def multiple_authority(ctx)