Auto-generate packet dataclasses with Jinja (#1374)

This commit is contained in:
Matt
2024-08-31 13:44:19 -04:00
committed by GitHub
parent c19d54c633
commit 169595e56e
140 changed files with 4445 additions and 2097 deletions

View File

@@ -0,0 +1,9 @@
from dataclasses import dataclass
@dataclass
class TargetCorner:
x: float = 0
y: float = 9
photonStruct: "TargetCornerSerde" = None

View File

@@ -0,0 +1,6 @@
# no one but us chickens
from .TargetCorner import TargetCorner # noqa
from .multiTargetPNPResult import MultiTargetPNPResult, PnpResult # noqa
from .photonPipelineResult import PhotonPipelineMetadata, PhotonPipelineResult # noqa
from .photonTrackedTarget import PhotonTrackedTarget # noqa

View File

@@ -0,0 +1,34 @@
from dataclasses import dataclass, field
from wpimath.geometry import Transform3d
from ..packet import Packet
@dataclass
class PnpResult:
best: Transform3d = field(default_factory=Transform3d)
alt: Transform3d = field(default_factory=Transform3d)
ambiguity: float = 0.0
bestReprojError: float = 0.0
altReprojError: float = 0.0
photonStruct: "PNPResultSerde" = None
@dataclass
class MultiTargetPNPResult:
_MAX_IDS = 32
estimatedPose: PnpResult = field(default_factory=PnpResult)
fiducialIDsUsed: list[int] = field(default_factory=list)
def createFromPacket(self, packet: Packet) -> Packet:
self.estimatedPose = PnpResult()
self.estimatedPose.createFromPacket(packet)
self.fiducialIDsUsed = []
for _ in range(MultiTargetPNPResult._MAX_IDS):
fidId = packet.decode16()
if fidId >= 0:
self.fiducialIDsUsed.append(fidId)
return packet
photonStruct: "MultiTargetPNPResultSerde" = None

View File

@@ -0,0 +1,65 @@
from dataclasses import dataclass, field
from typing import Optional
from .multiTargetPNPResult import MultiTargetPNPResult
from .photonTrackedTarget import PhotonTrackedTarget
@dataclass
class PhotonPipelineMetadata:
# 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
photonStruct: "PhotonPipelineMetadataSerde" = None
@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
targets: list[PhotonTrackedTarget] = field(default_factory=list)
metadata: PhotonPipelineMetadata = field(default_factory=PhotonPipelineMetadata)
multiTagResult: Optional[MultiTargetPNPResult] = None
def getLatencyMillis(self) -> float:
return (
self.metadata.publishTimestampMicros - self.metadata.captureTimestampMicros
) / 1e3
def getTimestampSeconds(self) -> float:
"""
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
timestamp, coproc timebase))
"""
# TODO - we don't trust NT4 to correctly latency-compensate ntReceiveTimestampMicros
return (
self.ntReceiveTimestampMicros
- (
self.metadata.publishTimestampMicros
- self.metadata.captureTimestampMicros
)
) / 1e6
def getTargets(self) -> list[PhotonTrackedTarget]:
return self.targets
def hasTargets(self) -> bool:
return len(self.targets) > 0
def getBestTarget(self) -> PhotonTrackedTarget:
"""
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]
photonStruct: "PhotonPipelineResultSerde" = None

View File

@@ -0,0 +1,58 @@
from dataclasses import dataclass, field
from wpimath.geometry import Transform3d
from ..packet import Packet
from .TargetCorner import TargetCorner
@dataclass
class PhotonTrackedTarget:
yaw: float = 0.0
pitch: float = 0.0
area: float = 0.0
skew: float = 0.0
fiducialId: int = -1
bestCameraToTarget: Transform3d = field(default_factory=Transform3d)
altCameraToTarget: Transform3d = field(default_factory=Transform3d)
minAreaRectCorners: list[TargetCorner] | None = None
detectedCorners: list[TargetCorner] | None = None
poseAmbiguity: float = 0.0
def getYaw(self) -> float:
return self.yaw
def getPitch(self) -> float:
return self.pitch
def getArea(self) -> float:
return self.area
def getSkew(self) -> float:
return self.skew
def getFiducialId(self) -> int:
return self.fiducialId
def getPoseAmbiguity(self) -> float:
return self.poseAmbiguity
def getMinAreaRectCorners(self) -> list[TargetCorner] | None:
return self.minAreaRectCorners
def getDetectedCorners(self) -> list[TargetCorner] | None:
return self.detectedCorners
def getBestCameraToTarget(self) -> Transform3d:
return self.bestCameraToTarget
def getAlternateCameraToTarget(self) -> Transform3d:
return self.altCameraToTarget
def _decodeTargetList(self, packet: Packet, numTargets: int) -> list[TargetCorner]:
retList = []
for _ in range(numTargets):
cx = packet.decodeDouble()
cy = packet.decodeDouble()
retList.append(TargetCorner(cx, cy))
return retList
photonStruct: "PhotonTrackedTargetSerde" = None