Run a Manta at its frame-rate limit, and wait for a DHT11's first reading
A free-running Manta runs at AcquisitionFrameRateAbs, not at its limit: rietschen's RGB camera came set to 0.955 fps and delivered 5 frames in 5.2 s. The gige recipe now writes a short fixed exposure and then the rate, clamped to the camera's maximum (4.7 fps at 60 MB/s), before auto-exposure goes back on. The export summary shows the rate set, not the limit, which had read 4.71 fps for a camera running at 0.96. test hardware env asked for a DHT11 reading at once, but the firmware reads it every 10 s, the first time 2 s after it starts. install-tower --verify failed on rietschen 1.4 s into its run, 36 s after the same test had passed. It now waits one read period for the first reading. Tests 542/542 (mock). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
8850337250
commit
fdb3c50b68
|
|
@ -723,7 +723,7 @@ MTU 8000): RGB (G-1236C), NIR and ACR (both G-1236B). Their firmware
|
||||||
| Program / Alvium | Manta |
|
| Program / Alvium | Manta |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `ExposureTime` | `ExposureTimeAbs` |
|
| `ExposureTime` | `ExposureTimeAbs` |
|
||||||
| `AcquisitionFrameRate` (+ `…Enable`) | `AcquisitionFrameRateAbs`, free-running at `AcquisitionFrameRateLimit` |
|
| `AcquisitionFrameRate` (+ `…Enable`) | `AcquisitionFrameRateAbs` - which a free-running Manta runs at, up to `AcquisitionFrameRateLimit` |
|
||||||
| `IntensityControllerTarget` / `…Tolerance` | `ExposureAutoTarget` / `ExposureAutoAdjustTol` |
|
| `IntensityControllerTarget` / `…Tolerance` | `ExposureAutoTarget` / `ExposureAutoAdjustTol` |
|
||||||
| `DeviceLinkThroughputLimit` | `StreamBytesPerSecond` (max 124 MB/s, shared by every camera on the port) |
|
| `DeviceLinkThroughputLimit` | `StreamBytesPerSecond` (max 124 MB/s, shared by every camera on the port) |
|
||||||
| `BayerRG12p`, chunk data, `DeviceReset` | none |
|
| `BayerRG12p`, chunk data, `DeviceReset` | none |
|
||||||
|
|
@ -732,8 +732,9 @@ The program looks a missing feature up under its older name, so `test camera`
|
||||||
and the telemetry work. `export_camera_profile.py` picks its `gige` recipe by
|
and the telemetry work. `export_camera_profile.py` picks its `gige` recipe by
|
||||||
itself when a camera has `ExposureTimeAbs` and no `ExposureTime`: frame trigger
|
itself when a camera has `ExposureTimeAbs` and no `ExposureTime`: frame trigger
|
||||||
off (the legacy cameras booted with `TriggerMode = On`, `Line1`), `BayerRG8` on
|
off (the legacy cameras booted with `TriggerMode = On`, `Line1`), `BayerRG8` on
|
||||||
the colour camera and `Mono8` on a mono one, 60 MB/s each, and an auto-exposure
|
the colour camera and `Mono8` on a mono one, 60 MB/s each, the frame rate at
|
||||||
target of 50 %. That last one matters: the keep rule waits for the frame mean
|
the camera's maximum (rietschen's RGB camera came set to 0.955 fps), and an
|
||||||
|
auto-exposure target of 50 %. That last one matters: the keep rule waits for the frame mean
|
||||||
to reach 50 %, and at the cameras' old 25 every waypoint ran into
|
to reach 50 %, and at the cameras' old 25 every waypoint ran into
|
||||||
`frame_timeout_ms`.
|
`frame_timeout_ms`.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,13 @@ _GIGE_COMMON = [
|
||||||
("Height", 100000),
|
("Height", 100000),
|
||||||
("PixelFormat", ("BayerRG8", "Mono8")),
|
("PixelFormat", ("BayerRG8", "Mono8")),
|
||||||
("StreamBytesPerSecond", 60000000),
|
("StreamBytesPerSecond", 60000000),
|
||||||
|
# Free-running, a Manta still runs at AcquisitionFrameRateAbs, not at its
|
||||||
|
# limit: rietschen's RGB camera came with 0.955 and delivered 5 frames in
|
||||||
|
# 5.2 s. A short fixed exposure first, so the rate is not capped by the
|
||||||
|
# exposure the camera happens to hold, as in the Alvium recipe.
|
||||||
|
("ExposureAuto", "Off"),
|
||||||
|
("ExposureTimeAbs", 1000.0),
|
||||||
|
("AcquisitionFrameRateAbs", 1000.0), # clamped to the camera's maximum
|
||||||
("ChunkModeActive", False),
|
("ChunkModeActive", False),
|
||||||
# The keep rule waits for the frame mean to reach the camera's target. The
|
# The keep rule waits for the frame mean to reach the camera's target. The
|
||||||
# host starts on its default band of 50 % - rietschen's cameras were set to
|
# host starts on its default band of 50 % - rietschen's cameras were set to
|
||||||
|
|
@ -290,14 +297,13 @@ def main():
|
||||||
refused.append(n)
|
refused.append(n)
|
||||||
|
|
||||||
# What the settings actually cost per frame - the number that decides
|
# What the settings actually cost per frame - the number that decides
|
||||||
# whether this profile can be delivered over the link at all. A
|
# whether this profile can be delivered over the link at all.
|
||||||
# free-running GigE camera reports its ceiling as the rate limit.
|
|
||||||
try:
|
try:
|
||||||
w = cam.get_feature_by_name("Width").get()
|
w = cam.get_feature_by_name("Width").get()
|
||||||
h = cam.get_feature_by_name("Height").get()
|
h = cam.get_feature_by_name("Height").get()
|
||||||
fmt = cam.get_feature_by_name("PixelFormat").get()
|
fmt = cam.get_feature_by_name("PixelFormat").get()
|
||||||
bpp = {"RGB8": 3, "BGR8": 3, "BayerRG12p": 1.5, "BayerRG12": 2}.get(str(fmt), 1)
|
bpp = {"RGB8": 3, "BGR8": 3, "BayerRG12p": 1.5, "BayerRG12": 2}.get(str(fmt), 1)
|
||||||
rate_name = "AcquisitionFrameRateLimit" if family == "gige" else "AcquisitionFrameRate"
|
rate_name = "AcquisitionFrameRateAbs" if family == "gige" else "AcquisitionFrameRate"
|
||||||
rate = cam.get_feature_by_name(rate_name).get()
|
rate = cam.get_feature_by_name(rate_name).get()
|
||||||
mb = w * h * bpp / 1e6
|
mb = w * h * bpp / 1e6
|
||||||
print(f"\nresult : {w}x{h} {fmt} {mb:.1f} MB/frame "
|
print(f"\nresult : {w}x{h} {fmt} {mb:.1f} MB/frame "
|
||||||
|
|
|
||||||
|
|
@ -1097,13 +1097,26 @@ void TestRunner::testHwEnv(TestReport& r) {
|
||||||
}
|
}
|
||||||
|
|
||||||
setProgress(s.id, 2, 2, "reading sensor");
|
setProgress(s.id, 2, 2, "reading sensor");
|
||||||
|
std::optional<EnvSample> sample = hw_.env ? hw_.env->sample() : std::nullopt;
|
||||||
|
// The firmware reads its DHT11 every 10 s, the first time 2 s after it
|
||||||
|
// starts, so a run straight after the host connected may have no reading
|
||||||
|
// yet: install-tower --verify failed on rietschen 1.4 s into its run, 36 s
|
||||||
|
// after the same test had passed. Wait one read period before calling it
|
||||||
|
// missing.
|
||||||
|
if (hw_.env && !sample && on_mcu) {
|
||||||
|
const auto deadline = clock_t_::now() + 12s;
|
||||||
|
while (!sample && clock_t_::now() < deadline && !cancelled()) {
|
||||||
|
std::this_thread::sleep_for(200ms);
|
||||||
|
sample = hw_.env->sample();
|
||||||
|
}
|
||||||
|
}
|
||||||
CheckResult m;
|
CheckResult m;
|
||||||
if (!hw_.env) {
|
if (!hw_.env) {
|
||||||
m.pass = false;
|
m.pass = false;
|
||||||
m.detail = "declared as '" + hw_.declared->env +
|
m.detail = "declared as '" + hw_.declared->env +
|
||||||
"' but no sensor was built -- check [Env] i2c_device; the declaration itself is "
|
"' but no sensor was built -- check [Env] i2c_device; the declaration itself is "
|
||||||
"what enables it";
|
"what enables it";
|
||||||
} else if (auto sample = hw_.env->sample()) {
|
} else if (sample) {
|
||||||
m.detail = "CRC-valid reading from " + hw_.env->name();
|
m.detail = "CRC-valid reading from " + hw_.env->name();
|
||||||
} else if (on_mcu) {
|
} else if (on_mcu) {
|
||||||
m.pass = false;
|
m.pass = false;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue