Skip to content

Commit ccafc03

Browse files
committed
Merge branch 'clearpathrobotics-indigo' into kinetic
2 parents bbc2595 + cee0e96 commit ccafc03

File tree

5 files changed

+1026
-15
lines changed

5 files changed

+1026
-15
lines changed

bag_tools/CMakeLists.txt

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,26 @@ install(TARGETS
3131
)
3232

3333
install(PROGRAMS
34-
scripts/stereo_sequence_publisher.py
35-
scripts/replace_msg_time_with_hdr.py
36-
scripts/remove_tf.py
37-
scripts/make_video.py
38-
scripts/image_sequence_publisher.py
39-
scripts/gps_to_std_gt.py
40-
scripts/extract_topics.py
41-
scripts/cut.py
42-
scripts/check_delay.py
43-
scripts/change_topics.py
44-
scripts/change_frame_id.py
45-
scripts/change_camera_info.py
46-
scripts/camera_info_parser.py
47-
scripts/batch_process.py
48-
scripts/bag_add_time_offset.py
4934
scripts/add_header_time_offset.py
35+
scripts/bag_add_time_offset.py
36+
scripts/batch_process.py
37+
scripts/camera_info_parser.py
38+
scripts/change_camera_info.py
39+
scripts/change_frame_id.py
40+
scripts/change_topics.py
41+
scripts/check_delay.py
42+
scripts/check_drop.py
43+
scripts/cut.py
44+
scripts/extract_topics.py
45+
scripts/gps_to_std_gt.py
46+
scripts/image_sequence_publisher.py
47+
scripts/make_video.py
48+
scripts/merge.py
49+
scripts/plot.py
50+
scripts/remove_tf.py
51+
scripts/replace_msg_time_with_hdr.py
52+
scripts/stereo_sequence_publisher.py
53+
scripts/transform_tf.py
5054
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
5155
)
5256

bag_tools/scripts/check_drop.py

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
#!/usr/bin/python
2+
"""
3+
Copyright (c) 2015,
4+
Enrique Fernandez Perdomo
5+
Clearpath Robotics, Inc.
6+
All rights reserved.
7+
8+
Redistribution and use in source and binary forms, with or without
9+
modification, are permitted provided that the following conditions are met:
10+
* Redistributions of source code must retain the above copyright
11+
notice, this list of conditions and the following disclaimer.
12+
* Redistributions in binary form must reproduce the above copyright
13+
notice, this list of conditions and the following disclaimer in the
14+
documentation and/or other materials provided with the distribution.
15+
* Neither the name of Systems, Robotics and Vision Group, University of
16+
the Balearican Islands nor the names of its contributors may be used to
17+
endorse or promote products derived from this software without specific
18+
prior written permission.
19+
20+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23+
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
24+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30+
"""
31+
32+
import rospy
33+
import rosbag
34+
35+
import numpy
36+
import argparse
37+
38+
# Workaround to avoid issues with X11 rendering when running on background:
39+
import matplotlib as mpl
40+
mpl.use('Agg')
41+
42+
import matplotlib.pyplot as plt
43+
44+
def check_drop(inbags, plot_format='png'):
45+
# Retrieve msg time, bag time and sequence number for all topics and messages:
46+
msg_time = {}
47+
bag_time = {}
48+
seq = {}
49+
50+
for inbag in inbags:
51+
rospy.loginfo(' Processing input bagfile: %s', inbag)
52+
for topic, msg, t in rosbag.Bag(inbag,'r').read_messages():
53+
if topic == "/tf":
54+
for transform in msg.transforms:
55+
key = "/tf: " + transform.header.frame_id + " -> " + transform.child_frame_id
56+
if key not in msg_time:
57+
msg_time[key] = []
58+
bag_time[key] = []
59+
seq[key] = []
60+
else:
61+
msg_time[key].append(transform.header.stamp.to_sec())
62+
bag_time[key].append(t.to_sec())
63+
seq[key].append(transform.header.seq)
64+
elif msg._has_header:
65+
key = topic
66+
if key not in msg_time:
67+
msg_time[key] = []
68+
bag_time[key] = []
69+
seq[key] = []
70+
else:
71+
msg_time[key].append(msg.header.stamp.to_sec())
72+
bag_time[key].append(t.to_sec())
73+
seq[key].append(msg.header.seq)
74+
75+
# Convert lists to numpy.arrays:
76+
for key in msg_time.iterkeys():
77+
msg_time[key] = numpy.array(msg_time[key])
78+
bag_time[key] = numpy.array(bag_time[key])
79+
seq[key] = numpy.array(seq[key])
80+
81+
# Compute differences:
82+
msg_time_diff = {}
83+
bag_time_diff = {}
84+
seq_diff = {}
85+
86+
min_time = []
87+
for key in msg_time.iterkeys():
88+
msg_time_diff[key] = numpy.diff(msg_time[key])
89+
min_time.append(msg_time[key][0])
90+
bag_time_diff[key] = numpy.diff(bag_time[key])
91+
seq_diff[key] = numpy.diff(seq[key])
92+
93+
min_time = numpy.min(min_time)
94+
95+
# Compute min, max and mean differences:
96+
basename = inbags[0].replace('.bag', '')
97+
98+
max_len = max(len(topic) for topic in msg_time_diff.keys())
99+
topics = msg_time_diff.keys()
100+
topics.sort()
101+
102+
103+
for topic in topics:
104+
msg_time_diff_topic = msg_time_diff[topic]
105+
bag_time_diff_topic = bag_time_diff[topic]
106+
seq_diff_topic = seq_diff[topic]
107+
108+
if len(msg_time_diff_topic) == 0:
109+
rospy.logwarn('%s has no messages', topic.ljust(max_len + 2))
110+
continue
111+
112+
msg_time_diff_min = numpy.min(msg_time_diff_topic)
113+
msg_time_diff_max = numpy.max(msg_time_diff_topic)
114+
msg_time_diff_mean = numpy.mean(msg_time_diff_topic)
115+
msg_time_diff_median = numpy.median(msg_time_diff_topic)
116+
117+
bag_time_diff_min = numpy.min(bag_time_diff_topic)
118+
bag_time_diff_max = numpy.max(bag_time_diff_topic)
119+
bag_time_diff_mean = numpy.mean(bag_time_diff_topic)
120+
bag_time_diff_median = numpy.median(bag_time_diff_topic)
121+
122+
seq_diff_min = numpy.min(seq_diff_topic)
123+
seq_diff_max = numpy.max(seq_diff_topic)
124+
seq_diff_mean = numpy.mean(seq_diff_topic)
125+
seq_diff_median = numpy.median(seq_diff_topic)
126+
127+
rospy.loginfo('%s message time: mean = %s, min = %s, max = %s, median = %s', topic.ljust(max_len + 2), msg_time_diff_mean, msg_time_diff_min, msg_time_diff_max, msg_time_diff_median)
128+
rospy.loginfo('%s bag time: mean = %s, min = %s, max = %s, median = %s', topic.ljust(max_len + 2), bag_time_diff_mean, bag_time_diff_min, bag_time_diff_max, bag_time_diff_median)
129+
rospy.loginfo('%s seq: mean = %s, min = %s, max = %s, median = %s', topic.ljust(max_len + 2), seq_diff_mean, seq_diff_min, seq_diff_max, seq_diff_median)
130+
131+
# Create and save plots:
132+
mt = msg_time[topic][1:] - min_time
133+
134+
try:
135+
fig = plt.figure()
136+
fig.set_size_inches(20, 15)
137+
138+
plt.subplot(311)
139+
plt.title(topic + ' - Message time difference [s]')
140+
plt.plot(mt, msg_time_diff_topic,'b')
141+
plt.plot([mt[0], mt[-1]], [msg_time_diff_min, msg_time_diff_min], 'r--')
142+
plt.plot([mt[0], mt[-1]], [msg_time_diff_max, msg_time_diff_max], 'r--')
143+
plt.plot([mt[0], mt[-1]], [msg_time_diff_mean, msg_time_diff_mean], 'g')
144+
145+
plt.subplot(312)
146+
plt.title(topic + ' - Bag time difference [s]')
147+
plt.plot(mt, bag_time_diff_topic,'b')
148+
plt.plot([mt[0], mt[-1]], [bag_time_diff_min, bag_time_diff_min], 'r--')
149+
plt.plot([mt[0], mt[-1]], [bag_time_diff_max, bag_time_diff_max], 'r--')
150+
plt.plot([mt[0], mt[-1]], [bag_time_diff_mean, bag_time_diff_mean], 'g')
151+
152+
plt.subplot(313)
153+
plt.title(topic + ' - Sequence number difference')
154+
plt.plot(mt, seq_diff_topic, 'b')
155+
plt.plot([mt[0], mt[-1]], [seq_diff_min, seq_diff_min], 'r--')
156+
plt.plot([mt[0], mt[-1]], [seq_diff_max, seq_diff_max], 'r--')
157+
plt.plot([mt[0], mt[-1]], [seq_diff_mean, seq_diff_mean], 'g')
158+
159+
160+
plt.savefig(basename + topic.replace('/', '_').replace(' ', '_').replace(':', '_') + '.' + plot_format)
161+
plt.close(fig)
162+
except OverflowError as e:
163+
rospy.logerr('%s: Failed to save plots as %s image files (try other format, e.g. svg): %s', topic.ljust(max_len + 2), plot_format, e.message)
164+
165+
if __name__ == "__main__":
166+
rospy.init_node('check_drop', anonymous=True)
167+
168+
parser = argparse.ArgumentParser(
169+
description='Checks the header.seq and header.stamp difference to detect '
170+
'message dropping in a bagfile. Prints out min, max and mean '
171+
'differences and all values are shown on a plot.')
172+
parser.add_argument('inbag', help='input bagfile(s)', nargs='+')
173+
parser.add_argument('--plot_format', help='output plot format', default='png')
174+
args = parser.parse_args()
175+
try:
176+
check_drop(args.inbag, args.plot_format)
177+
except Exception, e:
178+
import traceback
179+
traceback.print_exc()

bag_tools/scripts/merge.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#!/usr/bin/python
2+
"""
3+
Copyright (c) 2015,
4+
Enrique Fernandez Perdomo
5+
Clearpath Robotics, Inc.
6+
All rights reserved.
7+
8+
Redistribution and use in source and binary forms, with or without
9+
modification, are permitted provided that the following conditions are met:
10+
* Redistributions of source code must retain the above copyright
11+
notice, this list of conditions and the following disclaimer.
12+
* Redistributions in binary form must reproduce the above copyright
13+
notice, this list of conditions and the following disclaimer in the
14+
documentation and/or other materials provided with the distribution.
15+
* Neither the name of Systems, Robotics and Vision Group, University of
16+
the Balearican Islands nor the names of its contributors may be used to
17+
endorse or promote products derived from this software without specific
18+
prior written permission.
19+
20+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23+
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
24+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30+
"""
31+
32+
from __future__ import print_function
33+
34+
import rosbag
35+
36+
import argparse
37+
import os
38+
import sys
39+
40+
def merge(inbags, outbag='output.bag', topics=None, exclude_topics=[], raw=True):
41+
# Open output bag file:
42+
try:
43+
out = rosbag.Bag(outbag, 'a' if os.path.exists(outbag) else 'w')
44+
except IOError as e:
45+
print('Failed to open output bag file %s!: %s' % (outbag, e.message), file=sys.stderr)
46+
return 127
47+
48+
# Write the messages from the input bag files into the output one:
49+
for inbag in inbags:
50+
try:
51+
print(' Processing input bagfile: %s' % inbag)
52+
for topic, msg, t in rosbag.Bag(inbag, 'r').read_messages(topics=topics, raw=raw):
53+
if topic not in args.exclude_topics:
54+
out.write(topic, msg, t, raw=raw)
55+
except IOError as e:
56+
print('Failed to open input bag file %s!: %s' % (inbag, e.message), file=sys.stderr)
57+
return 127
58+
59+
out.close()
60+
61+
return 0
62+
63+
64+
if __name__ == "__main__":
65+
parser = argparse.ArgumentParser(
66+
description='Merge multiple bag files into a single one.')
67+
parser.add_argument('inbag', help='input bagfile(s)', nargs='+')
68+
parser.add_argument('--output', help='output bag file', default='output.bag')
69+
parser.add_argument('--topics', help='topics to merge from the input bag files', nargs='+', default=None)
70+
parser.add_argument('--exclude_topics', help='topics not to merge from the input bag files', nargs='+', default=[])
71+
args = parser.parse_args()
72+
73+
try:
74+
sys.exit(merge(args.inbag, args.output, args.topics, args.exclude_topics))
75+
except Exception, e:
76+
import traceback
77+
traceback.print_exc()

0 commit comments

Comments
 (0)