Add OV9281 AE startup quirk (#1814)

## Description

In https://github.com/PhotonVision/photonvision/issues/1771, we
discovered that the OV9281 on Linux seems to sometimes ignore our
exposure requests on first boot if we're in manual mode. Cycling the
camera's auto exposure with pauses in-between seems to fix it, which is
what this PR does.

Tested by [Team 2881 on
Discord](https://discord.com/channels/725836368059826228/725846784131203222/1465098110765105456);
thanks for helping us test this fix out!

## Meta

Closes https://github.com/PhotonVision/photonvision/issues/1771

Merge checklist:
- [x] Pull Request title is [short, imperative
summary](https://cbea.ms/git-commit/) of proposed changes
- [x] The description documents the _what_ and _why_
- [ ] If this PR changes behavior or adds a feature, user documentation
is updated
- [ ] If this PR touches photon-serde, all messages have been
regenerated and hashes have not changed unexpectedly
- [ ] If this PR touches configuration, this is backwards compatible
with settings back to v2024.3.1
- [ ] If this PR addresses a bug, a regression test for it is added

---------

Co-authored-by: Gold856 <117957790+Gold856@users.noreply.github.com>
This commit is contained in:
Matt Morley
2026-01-25 16:11:14 -08:00
committed by GitHub
parent b7a0fad54c
commit 4139566514
2 changed files with 21 additions and 1 deletions

View File

@@ -167,7 +167,27 @@ public class GenericUSBCameraSettables extends VisionSourceSettables {
}
}
@Override
public void setAutoExposure(boolean cameraAutoExposure) {
if (configuration.cameraQuirks.hasQuirk(CameraQuirk.ArduOV9281Controls)
&& !cameraAutoExposure) {
// OV9281 on Linux seems to sometimes ignore our exposure requests on first boot if we're in
// manual mode. Poking the camera into and out of auto exposure seems to fix it.
try {
setAutoExposureImpl(false);
Thread.sleep(2000);
setAutoExposureImpl(true);
Thread.sleep(2000);
setAutoExposureImpl(false);
} catch (InterruptedException e) {
logger.error("Thread interrupted while setting OV9281 exposure!", e);
}
} else {
setAutoExposureImpl(cameraAutoExposure);
}
}
public void setAutoExposureImpl(boolean cameraAutoExposure) {
logger.debug("Setting auto exposure to " + cameraAutoExposure);
if (!cameraAutoExposure) {

View File

@@ -465,13 +465,13 @@ public class VisionModule {
pipelineSettings.cameraExposureRaw = 10; // reasonable default
}
settables.setExposureRaw(pipelineSettings.cameraExposureRaw);
try {
settables.setAutoExposure(pipelineSettings.cameraAutoExposure);
} catch (VideoException e) {
logger.error("Unable to set camera auto exposure!");
logger.error(e.toString());
}
settables.setExposureRaw(pipelineSettings.cameraExposureRaw);
if (cameraQuirks.hasQuirk(CameraQuirk.Gain)) {
// If the gain is disabled for some reason, re-enable it
if (pipelineSettings.cameraGain == -1) pipelineSettings.cameraGain = 75;