-
Notifications
You must be signed in to change notification settings - Fork 81
/
rosbag_always.py
executable file
·174 lines (154 loc) · 5.88 KB
/
rosbag_always.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
#!/usr/bin/env python
import rospy
import time
import subprocess
import signal
import os
import sys
import argparse
import re
import shutil
try:
import colorama
except:
print("Please install colorama by pip install colorama")
sys.exit(1)
from colorama import Fore, Style
from jsk_topic_tools.master_util import isMasterAlive
def runROSBag(topics, size, save_dir):
"""
run rosbag and return Popen object
"""
cmd = 'roslaunch jsk_data rosbag_always_run_rosbag.launch'
formatted_topics = [t for t in topics.split(' ') if t]
args = cmd.split(' ') + ["TOPICS:=" + topics + ""] + ["SIZE:=" + size] + ["OUTPUT:=" + save_dir + '/rosbag']
print(args)
return subprocess.Popen(args)
def parseBagFile(bag):
# bag file name is ...
# 'rosbag_YYYY-MM-DD-HH-mm-SS_i.bag'
regexp = 'rosbag_(\d\d\d\d)-(\d\d)-(\d\d)-(\d\d)-(\d\d)-(\d\d)_([\d]+).bag'
result = re.match(regexp, bag)
if not result:
return None
else:
return [result.group(f) for f in range(1, 8)]
def mkdirForBag(root_dir, bag):
# mkdir like ${root_dir}/${YYYY}/${MM}/${DD}/${HH}
parse = parseBagFile(bag)
YYYY = parse[0]
MM = parse[1]
DD = parse[2]
HH = parse[3]
directory = os.path.join(root_dir, YYYY, MM, DD, HH)
if not os.path.exists(directory):
os.makedirs(directory)
return directory
def moveBagFiles(save_dir, bags):
for bag in bags:
move_dir = mkdirForBag(save_dir, bag)
from_file = os.path.join(save_dir, bag)
to_file = os.path.join(move_dir, bag)
print('moving file %s -> %s' % (from_file, to_file))
shutil.move(from_file, to_file)
def watchFileSystem(save_dir, max_size):
files = os.listdir(save_dir)
target_bags = [f for f in files
if f.startswith('rosbag')
and f.endswith('.bag')]
moveBagFiles(save_dir, target_bags)
# check size of directory
checkDirectorySize(save_dir, int(max_size))
def getDirectorySize(start_path = '.'):
"size unit is Mega bytes"
total_size = 0
for dirpath, dirnames, filenames in os.walk(start_path):
for f in filenames:
fp = os.path.join(dirpath, f)
try:
total_size += os.path.getsize(fp)
except:
pass
return total_size / 1000.0 / 1000.0
def keyFuncToSortBag(bag):
parse = parseBagFile(os.path.basename(bag))
parse[len(parse) - 1] = str(int(parse[len(parse) - 1])).zfill(4)
concatenated_string = reduce(lambda x, y: x + y, parse)
return int(concatenated_string)
def listBagsSortedByDate(save_dir):
bags = []
for dirpath, dirnames, filenames in os.walk(save_dir):
for f in filenames:
if f.startswith('rosbag') and (f.endswith('.bag') or f.endswith('.active')):
bags.append(os.path.join(dirpath, f))
return sorted(bags, key=keyFuncToSortBag)
def removeOldFiles(save_dir, max_size, current_size):
files = listBagsSortedByDate(save_dir)
remove_size = current_size - max_size
for f in files:
the_size = os.path.getsize(f)
print(Fore.GREEN + 'removing %s (%d)' % (f, the_size / 1000 / 1000) + Fore.RESET)
os.remove(f)
# Send desktop notification
subprocess.check_output(['notify-send', "Removed %s (%d)" % (f, the_size / 1000 / 1000)])
remove_size = remove_size - the_size / 1000.0 / 1000.0
if remove_size < 0:
return
def checkDirectorySize(save_dir, max_size):
size = getDirectorySize(save_dir)
# print('current directory size is %fM (max is %dM)' % (size, int(max_size)))
if size > max_size:
removeOldFiles(save_dir, max_size, size)
g_rosbag_process = False
def restartROSBag(topics, size, save_dir):
global g_rosbag_process
print('Running rosbag...')
g_rosbag_process = runROSBag(topics, size, save_dir)
def killChildProcesses(ppid):
output = subprocess.check_output(['ps', '--ppid=' + str(ppid), '--no-headers'])
for process_line in output.split('\n'):
strip_process_line = process_line.strip()
if strip_process_line:
pid = strip_process_line.split(' ')[0]
name = strip_process_line.split(' ')[-1]
print('killing %s' % (name))
os.kill(int(pid), signal.SIGINT)
def killROSBag():
global g_rosbag_process
if g_rosbag_process:
print('Killing rosbag ...')
rosbag_pid = g_rosbag_process.pid
try:
killChildProcesses(rosbag_pid)
g_rosbag_process.send_signal(subprocess.signal.SIGINT)
except:
pass
def main(topics, size, save_dir, max_size, rate = 1):
if not os.path.exists(save_dir):
os.makedirs(save_dir)
previous_master_state = None
try:
while True:
master_state = isMasterAlive()
if not master_state and previous_master_state:
print("kill rosbag")
killROSBag()
elif master_state and not previous_master_state:
print("restart rosbag")
restartROSBag(topics, size, save_dir)
watchFileSystem(save_dir, max_size)
previous_master_state = master_state
time.sleep(1.0 / rate)
except Exception as e:
time.sleep(1)
watchFileSystem(save_dir, max_size)
finally:
killROSBag()
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='rosbag record regardless of rosmaster status')
parser.add_argument('--topics', help="topics to record", required=True)
parser.add_argument('--size', help="size of each rosbag", required=True)
parser.add_argument('--save-dir', help="directory to store rosbag", required=True)
parser.add_argument('--max-size', help="maximum size of rosbags in save_dir", required=True, type=int)
args = parser.parse_args()
main(args.topics, args.size, args.save_dir, args.max_size)