Skip to content

Commit 74ebd97

Browse files
committed
Diagnose detects discarded frames
1 parent 9096468 commit 74ebd97

File tree

3 files changed

+62
-2
lines changed

3 files changed

+62
-2
lines changed

python/cli/diagnose/diagnose.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ def generateReport(args):
5454
"velocity": [], # ENU
5555
"altitude": [] # WGS-84
5656
}},
57-
'cameras': {}
57+
'cameras': {},
58+
'discardedFrames': []
5859
}
5960

6061
def addMeasurement(type, t, v):
@@ -88,6 +89,7 @@ def addMeasurement(type, t, v):
8889
frames = measurement.get("frames")
8990
metrics = measurement.get("systemMetrics")
9091
vioOutput = measurement if "status" in measurement else None
92+
droppedFrame = measurement.get("droppedFrame")
9193
if frames is None and 'frame' in measurement:
9294
frames = [measurement['frame']]
9395
frames[0]['cameraInd'] = 0
@@ -99,7 +101,8 @@ def addMeasurement(type, t, v):
99101
and metrics is None
100102
and barometer is None
101103
and gnss is None
102-
and vioOutput is None): continue
104+
and vioOutput is None
105+
and droppedFrame is None): continue
103106

104107
if startTime is None:
105108
startTime = time
@@ -184,6 +187,9 @@ def addMeasurement(type, t, v):
184187
vio["global"]["velocity"].append([globalPose["velocity"][c] for c in "xyz"])
185188
vio["global"]["altitude"].append(wgs84["altitude"])
186189

190+
elif droppedFrame:
191+
data['discardedFrames'].append(time)
192+
187193
if nSkipped > 0: print(f'Skipped {nSkipped} lines')
188194

189195
diagnoseCamera(data, output)

python/cli/diagnose/html.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ def generateHtml(output, outputHtml):
192192
for camera in output["cameras"]:
193193
s += generateSensor(camera, 'Camera #{}'.format(camera["ind"]))
194194

195+
if output.get("discardedFrames"):
196+
s += generateSensor(output.get("discardedFrames"), 'Cameras')
197+
195198
for sensor in SENSOR_NAMES:
196199
if sensor not in output: continue
197200
name = sensor.capitalize() if sensor.islower() else sensor

python/cli/diagnose/sensors.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,29 @@ def plotFrame(
7171

7272
return base64(fig)
7373

74+
75+
def plotDiscardedFrames(
76+
start,
77+
end,
78+
data):
79+
import matplotlib.pyplot as plt
80+
from matplotlib.ticker import ScalarFormatter
81+
82+
fig, ax = plt.subplots(figsize=(8, 2))
83+
84+
ax.set_title("Discarded frames")
85+
ax.vlines(data, ymin=0, ymax=1, colors='red', lw=1)
86+
ax.set_xlim(start, end)
87+
ax.set_ylim(0, 1)
88+
ax.set_xlabel("Time (s)")
89+
ax.get_yaxis().set_visible(False)
90+
ax.xaxis.set_major_formatter(ScalarFormatter())
91+
ax.ticklabel_format(style='plain',axis='x',useOffset=False)
92+
fig.tight_layout()
93+
94+
return base64(fig)
95+
96+
7497
class DiagnosisLevel(Enum):
7598
OK = 0
7699
WARNING = 1
@@ -210,6 +233,18 @@ def toPercent(value):
210233
f"Found {invalidTimestamps} ({toPercent(invalidTimestamps)}) "
211234
"timestamps that don't overlap with IMU")
212235

236+
237+
def analyzeDiscardedFrames(self, start_time, end_time, timestamps):
238+
if len(timestamps) == 0: return
239+
self.images.append(plotDiscardedFrames(start_time, end_time, timestamps))
240+
self.__addIssue(DiagnosisLevel.WARNING,
241+
f"Found {len(timestamps)} discarded frames. Typically this happens when disk I/O "
242+
f"is too slow and prevents recording frames leading them to be discarded. You can "
243+
f"alleviate this issue with larger in-memory buffer when recording using FFMpeg. "
244+
f"In <i>vio_config.yaml</i>: <i>ffmpegWriteBufferCapacityMegabytes: 50</i>"
245+
)
246+
247+
213248
def analyzeArrivalTimes(
214249
self,
215250
timestamps,
@@ -652,13 +687,18 @@ def diagnoseCamera(data, output):
652687
sensor = data["cameras"]
653688
output["cameras"] = []
654689

690+
start_time = None
691+
end_time = None
655692
for ind in sensor.keys():
656693
camera = sensor[ind]
657694
timestamps = np.array(camera["t"])
658695
deltaTimes = np.array(camera["td"])
659696

660697
if len(timestamps) == 0: continue
661698

699+
if start_time == None or start_time > timestamps[0]: start_time = timestamps[0]
700+
if end_time == None or end_time < timestamps[-1]: end_time = timestamps[-1]
701+
662702
status = Status()
663703
status.analyzeTimestamps(
664704
timestamps,
@@ -700,6 +740,17 @@ def diagnoseCamera(data, output):
700740
# Camera is required
701741
output["passed"] = False
702742

743+
if len(data["discardedFrames"]) > 0:
744+
status = Status()
745+
status.analyzeDiscardedFrames(start_time, end_time, data["discardedFrames"])
746+
output["discardedFrames"] = {
747+
"diagnosis": status.diagnosis.toString(),
748+
"issues": status.serializeIssues(),
749+
"count": len(timestamps),
750+
"images": status.images
751+
}
752+
753+
703754
def diagnoseAccelerometer(data, output):
704755
ACC_MIN_FREQUENCY_HZ = 50.0
705756
ACC_MAX_FREQUENCY_HZ = 1e4

0 commit comments

Comments
 (0)