2023-12-16 12:32:49 -06:00
|
|
|
from dataclasses import dataclass, field
|
2024-11-12 16:53:43 +11:00
|
|
|
from typing import TYPE_CHECKING, ClassVar, Optional
|
2023-12-16 12:32:49 -06:00
|
|
|
|
2024-08-31 13:44:19 -04:00
|
|
|
from .multiTargetPNPResult import MultiTargetPNPResult
|
|
|
|
|
from .photonTrackedTarget import PhotonTrackedTarget
|
2023-12-16 12:32:49 -06:00
|
|
|
|
2024-11-12 16:53:43 +11:00
|
|
|
if TYPE_CHECKING:
|
2024-11-14 02:39:02 +11:00
|
|
|
from ..generated.PhotonPipelineMetadataSerde import PhotonPipelineMetadataSerde
|
|
|
|
|
from ..generated.PhotonPipelineResultSerde import PhotonPipelineResultSerde
|
2024-11-12 16:53:43 +11:00
|
|
|
|
2023-12-16 12:32:49 -06:00
|
|
|
|
|
|
|
|
@dataclass
|
2024-08-31 13:44:19 -04:00
|
|
|
class PhotonPipelineMetadata:
|
2024-05-10 14:04:34 -04:00
|
|
|
# Image capture and NT publish timestamp, in microseconds and in the coprocessor timebase. As
|
|
|
|
|
# reported by WPIUtilJNI::now.
|
|
|
|
|
captureTimestampMicros: int = -1
|
|
|
|
|
publishTimestampMicros: int = -1
|
|
|
|
|
|
|
|
|
|
# Mirror of the heartbeat entry -- monotonically increasing
|
|
|
|
|
sequenceID: int = -1
|
|
|
|
|
|
2024-11-08 10:31:21 +11:00
|
|
|
timeSinceLastPong: int = -1
|
|
|
|
|
|
2024-11-14 02:39:02 +11:00
|
|
|
photonStruct: ClassVar["PhotonPipelineMetadataSerde"]
|
2024-05-10 14:04:34 -04:00
|
|
|
|
|
|
|
|
|
2024-08-31 13:44:19 -04:00
|
|
|
@dataclass
|
|
|
|
|
class PhotonPipelineResult:
|
|
|
|
|
# Since we don't trust NT time sync, keep track of when we got this packet into robot code
|
|
|
|
|
ntReceiveTimestampMicros: int = -1
|
2024-01-06 06:17:06 -06:00
|
|
|
|
2024-08-31 13:44:19 -04:00
|
|
|
targets: list[PhotonTrackedTarget] = field(default_factory=list)
|
2024-11-01 23:32:38 -07:00
|
|
|
# Python users beware! We don't currently run a Time Sync Server, so these timestamps are in
|
|
|
|
|
# an arbitrary timebase. This is not true in C++ or Java.
|
2024-08-31 13:44:19 -04:00
|
|
|
metadata: PhotonPipelineMetadata = field(default_factory=PhotonPipelineMetadata)
|
2024-11-09 11:08:57 +11:00
|
|
|
multitagResult: Optional[MultiTargetPNPResult] = None
|
2023-12-16 12:32:49 -06:00
|
|
|
|
|
|
|
|
def getLatencyMillis(self) -> float:
|
2024-08-31 13:44:19 -04:00
|
|
|
return (
|
|
|
|
|
self.metadata.publishTimestampMicros - self.metadata.captureTimestampMicros
|
|
|
|
|
) / 1e3
|
2024-05-10 14:04:34 -04:00
|
|
|
|
|
|
|
|
def getTimestampSeconds(self) -> float:
|
|
|
|
|
"""
|
2024-08-31 13:44:19 -04:00
|
|
|
Returns the estimated time the frame was taken, in the Received system's time base. This is
|
|
|
|
|
calculated as (NT Receive time (robot base) - (publish timestamp, coproc timebase - capture
|
2024-05-10 14:04:34 -04:00
|
|
|
timestamp, coproc timebase))
|
|
|
|
|
"""
|
2024-08-31 13:44:19 -04:00
|
|
|
# TODO - we don't trust NT4 to correctly latency-compensate ntReceiveTimestampMicros
|
2025-08-01 11:04:01 -07:00
|
|
|
latency = (
|
|
|
|
|
self.metadata.publishTimestampMicros - self.metadata.captureTimestampMicros
|
|
|
|
|
)
|
|
|
|
|
return (self.ntReceiveTimestampMicros - latency) / 1e6
|
2023-12-16 12:32:49 -06:00
|
|
|
|
|
|
|
|
def getTargets(self) -> list[PhotonTrackedTarget]:
|
|
|
|
|
return self.targets
|
2024-02-02 14:17:53 -06:00
|
|
|
|
2024-08-31 13:44:19 -04:00
|
|
|
def hasTargets(self) -> bool:
|
|
|
|
|
return len(self.targets) > 0
|
|
|
|
|
|
2024-11-12 16:53:43 +11:00
|
|
|
def getBestTarget(self) -> Optional[PhotonTrackedTarget]:
|
2024-08-31 12:30:09 -04:00
|
|
|
"""
|
|
|
|
|
Returns the best target in this pipeline result. If there are no targets, this method will
|
|
|
|
|
return null. The best target is determined by the target sort mode in the PhotonVision UI.
|
|
|
|
|
"""
|
|
|
|
|
if not self.hasTargets():
|
|
|
|
|
return None
|
|
|
|
|
return self.getTargets()[0]
|
|
|
|
|
|
2024-11-14 02:39:02 +11:00
|
|
|
photonStruct: ClassVar["PhotonPipelineResultSerde"]
|