-
-
Notifications
You must be signed in to change notification settings - Fork 59
/
ros_readbagfile.py
executable file
·218 lines (176 loc) · 8.76 KB
/
ros_readbagfile.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#!/usr/bin/env python3
# NB: on some systems, you may need to use one of these hash-bang lines above instead:
# #!/usr/bin/python3
# OR:
# #!/usr/local/bin/python3
#
# Run `which python3` to see which Python 3 binary executable your system's environment is
# configured to use by default.
#
# See also:
# https://stackoverflow.com/questions/2429511/why-do-people-write-usr-bin-env-python-on-the-first-line-of-a-python-script
"""
This file is part of eRCaGuy_dotfiles: https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles
Author: Gabriel Staples
INSTALLATION INSTRUCTIONS:
0. Install dependencies:
Source: https://zoomadmin.com/HowToInstall/UbuntuPackage/python-rosbag
sudo apt install python-rosbag # for python2 (deprecated)
sudo apt install python3-rosbag # for python3 (also doesn't seem to work now)
If those two commands above don't work, try these cmds instead.
Source:
1. https://stackoverflow.com/a/64310922/4561887
1. >>>> See also my own answer here <<<<: https://stackoverflow.com/a/69368883/4561887
pip install bagpy
pip3 install bagpy # for python3 (this seems to be the new requirement!) <===
# OR, if the above cmd ultimately fails due to permissions errors, use `sudo` too:
sudo pip3 install bagpy
1. Create a symlink in ~/bin to this script so you can run it from anywhere:
cd /path/to/here
mkdir -p ~/bin
ln -si "${PWD}/ros_readbagfile.py" ~/bin/gs_ros_readbagfile
ln -si "${PWD}/ros_readbagfile.py" ~/bin/ros_readbagfile
2. If this is the first time ever creating the "~/bin" dir, then log out and log back in to your
Ubuntu user account to cause Ubuntu to automatically add your ~/bin dir to your executable PATH.
OR, you can just re-source your Ubuntu `~/.profile` file by running this:
. ~/.profile
- Note: if your terminal still says it cannot find the command when
trying to run it, you may need to ensure `~/bin` is part of your `PATH` variable.
See my answer here for details:
https://answers.ros.org/question/371583/ros_readbagfile-command-not-found/?answer=403354#post-id-403354
- You'll especially need to see my answer above if running either a non-default `~/.profile` file
in Ubuntu, or if running a non-Ubuntu Linux derivative such as Arch Linux.
- If on Ubuntu, you can find a backup copy of the default `~/.profile` file in
`/etc/skel/.profile`. Copy that file to your home (`~`) dir if you'd like to restore your
`~/.profile` file to its default configuration.
3. Now you can use the command `gs_ros_readbagfile` OR `ros_readbagfile` directly
anywhere you like.
TUTORIAL DEMO:
For a usage demo, see this ROS tutorial I wrote here: "Reading messages from a bag file":
http://wiki.ros.org/ROS/Tutorials/reading%20msgs%20from%20a%20bag%20file
References:
1. http://wiki.ros.org/rosbag/Cookbook
1. https://pypi.org/project/pyrosbag/
1. Python2 `rosbag` Code API documentation: https://docs.ros.org/api/rosbag/html/python/
- `read_messages()` API documentation:
https://docs.ros.org/api/rosbag/html/python/rosbag.bag.Bag-class.html#read_messages
1. http://wiki.ros.org/rospy/Overview/Time
1. https://www.geeksforgeeks.org/python-exit-commands-quit-exit-sys-exit-and-os-_exit/
Pros of this script: really easy to use; requires only 1 terminal, and NO `roscore` running.
Cons: this Python implementation runs ~13x slower than "OPTION 1", as described in
"eRCaGuy_dotfiles/git & Linux cmds, help, tips & tricks - Gabriel.txt", so it might take up to
1 to 2+ minutes to process an entire bag file instead of only like 5 to 10 seconds.
TODO:
1. convert this entire Python script to a C++ program using the [C++ rosbag
API](http://wiki.ros.org/rosbag/Code%20API#cpp_api), to hopefully achieve a speed-up of ~13x
or so.
"""
import rosbag
import os
import sys
import textwrap
# `topics=None` means to read ALL topics; see:
# https://docs.ros.org/api/rosbag/html/python/rosbag.bag.Bag-class.html#read_messages
READ_ALL_TOPICS = None
def printHelp():
cmd_name = os.path.basename(sys.argv[0])
help = textwrap.dedent(f"""
Usage: {cmd_name} <mybagfile.bag> [topic1] [topic2] [topic3] [...topicN]
Reads and prints all messages published on the specified topics from the specified ROS bag file. If
no topics are specified, it will print ALL messages published on ALL topics found in the bag file.
For large bag files, on the order of 10 to 20 GB or so, expect the script to take on the order of
1 to 4 minutes or so assuming you have a fast Solid-State Drive (SSD).
TODO: converting this script from Python to C++ could potentially speed this up by an estimated
factor of 13x or so, decreasing the processing time from a couple minutes to perhaps a dozen
seconds.
Examples:
1. Print all messages published to the "/speed", "/vel", and "/dist" topics and stored in the
"mybagfile.bag" ROS bag file to the screen:
{cmd_name} mybagfile.bag /speed /vel /dist
2. Same as above, except also stores the printed output into an output file, "output.yaml" as well:
{cmd_name} mybagfile.bag /speed /vel /dist | tee output.yaml
3. [MY FAVORITE] Same as above, except also times how long the whole process takes:
time {cmd_name} mybagfile.bag /speed /vel /dist | tee output.yaml
Note: for a basic example of how to import YAML files in Python, so you can then import and
manipulate the *.yaml files generated above, see:
https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/tree/master/python/yaml_import
TUTORIAL DEMO:
For a usage demo, see this ROS tutorial I wrote here: "Reading messages from a bag file":
http://wiki.ros.org/ROS/Tutorials/reading%20msgs%20from%20a%20bag%20file
'{cmd_name}' is part of eRCaGuy_dotfiles:
https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles/blob/master/useful_scripts/ros_readbagfile.py
""")
print(help)
class Args:
"""
Argument variables for the `main()` func
"""
bag_file_in = ""
topics_to_read = READ_ALL_TOPICS
def printArgs(args):
print("args.bag_file_in = {}".format(args.bag_file_in))
print("args.topics_to_read = {}".format(args.topics_to_read))
def parseArgs():
print("# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
args = Args()
if len(sys.argv) == 1:
print("# ERROR: no input args; 1 minimum required.")
printHelp()
sys.exit()
if len(sys.argv) >= 2:
if sys.argv[1] == "-h" or sys.argv[1] == "--help":
printHelp()
sys.exit()
args.bag_file_in = sys.argv[1]
if len(sys.argv) >= 3:
args.topics_to_read = sys.argv[2:]
print("# Scanning ROS bag file \"{}\"".format(args.bag_file_in))
print("# for the following topics:")
if not args.topics_to_read:
# list is empty
print("# ALL TOPICS in the bag file")
else:
for topic in args.topics_to_read:
print("# {}".format(topic))
print("# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
return args
def printMsgsInBagFile(args):
no_msgs_found = True
# Establish counters to keep track of the message number being received under each topic name
msg_counters = {} # empty dict
total_count = 0
bag_in = rosbag.Bag(args.bag_file_in)
for topic, msg, t in bag_in.read_messages(args.topics_to_read):
print("\n# =======================================")
total_count += 1
no_msgs_found = False
# Keep track of individual message counters for each message type
if topic not in msg_counters:
msg_counters[topic] = 1;
else:
msg_counters[topic] += 1;
# Print topic name and message receipt info
print("# topic: " + topic)
print("# msg_count: %u" % msg_counters[topic])
# the comma at the end prevents the newline char being printed at the end in Python2; see:
# https://www.geeksforgeeks.org/print-without-newline-python/
print("# timestamp (sec): {:.9f}".format(t.to_sec())),
print("# - - -")
# Print the message
print(msg)
print("")
print("# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
print("# Total messages found: {:>16}".format(total_count))
print("#")
for topic in msg_counters:
print("# {:<30} {:>4}".format(topic + ":", msg_counters[topic]))
if no_msgs_found:
print("# NO MESSAGES FOUND IN THESE TOPICS")
print("#")
print("# DONE.")
print("# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
# If this file is called directly, as opposed to imported, run this:
if __name__ == '__main__':
args = parseArgs()
# printArgs(args) # for debugging
printMsgsInBagFile(args)