Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Ardupilot
GitHub Repository: Ardupilot/ardupilot
Path: blob/master/Tools/Replay/CheckLogs.py
9465 views
1
#!/usr/bin/env python3
2
3
# flake8: noqa
4
5
'''
6
run Replay over a set of logs to check for code regressions
7
'''
8
9
import optparse, os, sys
10
11
parser = optparse.OptionParser("CheckLogs")
12
parser.add_option("--logdir", type='string', default='testlogs', help='directory of logs to use')
13
parser.add_option("--create-checked-logs", action='store_true', default=False, help="created logs with CHEK messages")
14
parser.add_option("--tolerance-euler", type=float, default=3, help="tolerance for euler angles in degrees");
15
parser.add_option("--tolerance-pos", type=float, default=2, help="tolerance for position angles in meters");
16
parser.add_option("--tolerance-vel", type=float, default=2, help="tolerance for velocity in meters/second");
17
18
opts, args = parser.parse_args()
19
20
def run_cmd(cmd, dir=".", show=False, output=False, checkfail=True):
21
'''run a shell command'''
22
from subprocess import call, check_call,Popen, PIPE
23
if show:
24
print("Running: '%s' in '%s'" % (cmd, dir))
25
if output:
26
return Popen([cmd], shell=True, stdout=PIPE, cwd=dir).communicate()[0]
27
elif checkfail:
28
return check_call(cmd, shell=True, cwd=dir)
29
else:
30
return call(cmd, shell=True, cwd=dir)
31
32
def run_replay(logfile):
33
'''run Replay on one logfile'''
34
print("Processing %s" % logfile)
35
cmd = "./Replay.elf -- --check %s --tolerance-euler=%f --tolerance-pos=%f --tolerance-vel=%f " % (
36
logfile,
37
opts.tolerance_euler,
38
opts.tolerance_pos,
39
opts.tolerance_vel)
40
run_cmd(cmd, checkfail=False)
41
42
def get_log_list():
43
'''get a list of log files to process'''
44
import glob, sys
45
pattern = os.path.join(opts.logdir, "*-checked.bin")
46
file_list = glob.glob(pattern)
47
print("Found %u logs to process" % len(file_list))
48
if len(file_list) == 0:
49
print("No logs to process matching %s" % pattern)
50
sys.exit(1)
51
return file_list
52
53
def create_html_results():
54
'''create a HTML file with results'''
55
error_count = 0
56
57
git_version = run_cmd('git log --pretty=oneline HEAD~1..HEAD', output=True)
58
59
f = open("replay_results.html", "w")
60
f.write(
61
'''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
62
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
63
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
64
<head>
65
<title>Replay results</title>
66
<meta charset="utf-8"/>
67
</head>
68
<body>
69
<h1>Replay Results</h1>
70
Git version: %s
71
<p>
72
<table border="1">
73
<tr bgcolor="lightgrey">
74
<th>Filename</th>
75
<th>RollError(deg)</th>
76
<th>PitchError(deg)</th>
77
<th>YawError(deg)</th>
78
<th>PosError(m)</th>
79
<th>VelError(m/s)</th>
80
</tr>
81
''' % git_version)
82
infile = open("replay_results.txt", "r")
83
84
line_count = 0
85
line_errors = 0
86
87
for line in infile:
88
line = line.strip()
89
line_count += 1
90
a = line.split("\t")
91
if len(a) != 6:
92
print("Invalid line: %s" % line)
93
error_count += 1
94
continue
95
tolerances = [opts.tolerance_euler,
96
opts.tolerance_euler,
97
opts.tolerance_euler,
98
opts.tolerance_pos,
99
opts.tolerance_vel]
100
f.write('''<tr><td><a href="%s">%s</a></td>''' % (a[0],a[0]))
101
error_in_this_log = False
102
for i in range(1,6):
103
tol = tolerances[i-1]
104
if a[i] == "FPE":
105
bgcolor = "red"
106
error_count += 1
107
error_in_this_log = True
108
elif float(a[i]) > tol:
109
bgcolor = "red"
110
error_count += 1
111
error_in_this_log = True
112
else:
113
bgcolor = "white"
114
f.write('''<td bgcolor="%s" align="right">%s</td>\n''' % (bgcolor, a[i]))
115
116
if error_in_this_log:
117
line_errors += 1
118
f.write('''</tr>\n''')
119
120
f.write('''</table>\n''')
121
122
# write summary
123
f.write(
124
'''<h2>Summary</h2>
125
<p>Processed %u logs<br/>
126
%u errors from %u logs<br/>
127
<hr>
128
<p>Tolerance Euler: %.3f degrees<br/>
129
Tolerance Position: %.3f meters<br/>
130
Tolerance Velocity: %.3f meters/second
131
''' % (line_count, error_count, line_errors,
132
opts.tolerance_euler,
133
opts.tolerance_pos,
134
opts.tolerance_vel))
135
136
# add trailer
137
f.write(
138
'''
139
</body>
140
</html>
141
''')
142
f.close()
143
infile.close()
144
145
def check_logs():
146
'''run log checking'''
147
log_list = get_log_list()
148
149
# remove old results file
150
try:
151
os.unlink("replay_results.txt")
152
except Exception as ex:
153
print(ex)
154
155
for logfile in log_list:
156
run_replay(logfile)
157
158
create_html_results()
159
160
def create_checked_logs():
161
'''create a set of CHEK logs'''
162
import glob, sys
163
if os.path.isfile(opts.logdir):
164
full_file_list = [opts.logdir]
165
else:
166
pattern = os.path.join(opts.logdir, "*.bin")
167
full_file_list = glob.glob(pattern)
168
file_list = []
169
for f in full_file_list:
170
if not f.endswith("-checked.bin"):
171
file_list.append(f)
172
if len(file_list) == 0:
173
print("No files to process")
174
sys.exit(1)
175
for f in file_list:
176
print("Processing %s" % f)
177
log_list_current = set(glob.glob("logs/*.BIN"))
178
cmd = "./Replay.elf -- --check-generate %s" % f
179
run_cmd(cmd, checkfail=True)
180
log_list_after = set(glob.glob("logs/*.BIN"))
181
changed = log_list_after.difference(log_list_current)
182
if len(changed) != 1:
183
print("Failed to generate log for %s" % f)
184
sys.exit(1)
185
outlog = list(changed)[0]
186
name, ext = os.path.splitext(f)
187
newname = name + '-checked.bin'
188
os.rename(outlog, newname)
189
print("Created %s" % newname)
190
191
if opts.create_checked_logs:
192
create_checked_logs()
193
sys.exit(0)
194
195
check_logs()
196
197