CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
Ardupilot

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

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