Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ I'm sure that we'll find a camera that doesn't play nice, because we can't have

Other things to note: This gets us an estimate at when the camera *started* collecting photons. The camera's sensor will remain collecting light for up to the total integration time, plus readout time for rolling shutter cameras.

For the libcamera capture path, PhotonVision now applies a mid-exposure correction using the per-frame `ExposureTime` metadata from libcamera. The published timestamp is the midpoint of the integration window for global-shutter sensors. Rolling-shutter sensors have a residual row-dependent bias not yet corrected. If libcamera does not populate `ExposureTime` for a given frame, the driver returns 0 and the correction is skipped (behaviour matches the pre-correction code path).

## Latency Testing

Here, I've got a RoboRIO with an LED, an Orange Pi 5, and a network switch on a test bench. The LED is assumed to turn on basically instantly once we apply current, and based on DMA testing, the total time to switch a digital output on is on the order of 10uS. The RoboRIO is running a TimeSync Server, and the Orange Pi is running a TimeSync Client.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,19 +85,27 @@ public Frame get() {

var now = LibCameraJNI.getLibcameraTimestamp();
var capture = LibCameraJNI.getFrameCaptureTime(p_ptr);
var exposureUs = LibCameraJNI.getFrameExposureTimeUs(p_ptr);
var latency = (now - capture);

LibCameraJNI.releasePair(p_ptr);

// Know frame is good -- increment sequence
++sequenceID;

// libcamera's SensorTimestamp marks start-of-exposure. The scene the
// detector integrates over spans [SOE, SOE+exposure], so mid-exposure
// is the closest single-instant approximation. When the driver
// returns 0, ExposureTime metadata was unavailable for this frame
// and we leave the timestamp uncorrected.
long midExposureCorrectionNs = exposureUs > 0 ? (exposureUs * 1000L) / 2L : 0L;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What conditions lead to exposureUs being less than zero? Or zero?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://docs.libcamera.org/master/public-api/namespacelibcamera_1_1controls.html#a4e1ca45653b62cd969d4d67a741076eb makes no mention of what happens when "metadata is unavailable or this frame" - the comment states what the expected behavior of libcamera is but I'm not sure I concur.


return new Frame(
sequenceID,
colorMat,
processedMat,
type,
MathUtils.wpiNanoTime() - latency,
MathUtils.wpiNanoTime() - latency + midExposureCorrectionNs,
settables.getFrameStaticProperties().rotate(settables.getRotation()));
}
}
Expand Down