photonlibpy 2025.0.0b5__py3-none-any.whl → 2025.0.0b7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- photonlibpy/networktables/NTTopicSet.py +5 -4
- photonlibpy/simulation/photonCameraSim.py +38 -36
- photonlibpy/simulation/simCameraProperties.py +6 -7
- photonlibpy/simulation/visionSystemSim.py +3 -2
- photonlibpy/version.py +2 -2
- {photonlibpy-2025.0.0b5.dist-info → photonlibpy-2025.0.0b7.dist-info}/METADATA +2 -2
- {photonlibpy-2025.0.0b5.dist-info → photonlibpy-2025.0.0b7.dist-info}/RECORD +9 -9
- {photonlibpy-2025.0.0b5.dist-info → photonlibpy-2025.0.0b7.dist-info}/WHEEL +1 -1
- {photonlibpy-2025.0.0b5.dist-info → photonlibpy-2025.0.0b7.dist-info}/top_level.txt +0 -0
@@ -17,10 +17,11 @@ class NTTopicSet:
|
|
17
17
|
different for sim vs. real camera
|
18
18
|
"""
|
19
19
|
|
20
|
-
def __init__(
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
def __init__(
|
21
|
+
self,
|
22
|
+
ntSubTable: nt.NetworkTable,
|
23
|
+
) -> None:
|
24
|
+
self.subTable = ntSubTable
|
24
25
|
|
25
26
|
def updateEntries(self) -> None:
|
26
27
|
options = nt.PubSubOptions()
|
@@ -60,11 +60,10 @@ class PhotonCameraSim:
|
|
60
60
|
self.videoSimRawEnabled: bool = False
|
61
61
|
self.videoSimWireframeEnabled: bool = False
|
62
62
|
self.videoSimWireframeResolution: float = 0.1
|
63
|
-
|
64
|
-
|
65
|
-
)
|
63
|
+
# TODO switch this back to default True when the functionality is enabled
|
64
|
+
self.videoSimProcEnabled: bool = False
|
66
65
|
self.heartbeatCounter: int = 0
|
67
|
-
self.nextNtEntryTime =
|
66
|
+
self.nextNtEntryTime = wpilib.Timer.getFPGATimestamp()
|
68
67
|
self.tagLayout = AprilTagFieldLayout.loadField(AprilTagField.k2024Crescendo)
|
69
68
|
|
70
69
|
self.cam = camera
|
@@ -95,7 +94,7 @@ class PhotonCameraSim:
|
|
95
94
|
(self.prop.getResWidth(), self.prop.getResHeight())
|
96
95
|
)
|
97
96
|
|
98
|
-
self.ts = NTTopicSet(
|
97
|
+
self.ts = NTTopicSet(self.cam._cameraTable)
|
99
98
|
self.ts.updateEntries()
|
100
99
|
|
101
100
|
# Handle this last explicitly for this function signature because the other constructor is called in the initialiser list
|
@@ -173,20 +172,20 @@ class PhotonCameraSim:
|
|
173
172
|
def consumeNextEntryTime(self) -> float | None:
|
174
173
|
"""Determine if this camera should process a new frame based on performance metrics and the time
|
175
174
|
since the last update. This returns an Optional which is either empty if no update should occur
|
176
|
-
or a
|
175
|
+
or a float of the timestamp in seconds of when the frame which should be received by NT. If
|
177
176
|
a timestamp is returned, the last frame update time becomes that timestamp.
|
178
177
|
|
179
|
-
:returns: Optional
|
178
|
+
:returns: Optional float which is empty while blocked or the NT entry timestamp in seconds if
|
180
179
|
ready
|
181
180
|
"""
|
182
181
|
# check if this camera is ready for another frame update
|
183
|
-
now =
|
184
|
-
timestamp = 0
|
182
|
+
now = wpilib.Timer.getFPGATimestamp()
|
183
|
+
timestamp = 0.0
|
185
184
|
iter = 0
|
186
185
|
# prepare next latest update
|
187
186
|
while now >= self.nextNtEntryTime:
|
188
|
-
timestamp =
|
189
|
-
frameTime =
|
187
|
+
timestamp = self.nextNtEntryTime
|
188
|
+
frameTime = self.prop.estSecUntilNextFrame()
|
190
189
|
self.nextNtEntryTime += frameTime
|
191
190
|
|
192
191
|
# if frame time is very small, avoid blocking
|
@@ -432,7 +431,9 @@ class PhotonCameraSim:
|
|
432
431
|
)
|
433
432
|
|
434
433
|
def submitProcessedFrame(
|
435
|
-
self,
|
434
|
+
self,
|
435
|
+
result: PhotonPipelineResult,
|
436
|
+
receiveTimestamp_us: float | None = None,
|
436
437
|
):
|
437
438
|
"""Simulate one processed frame of vision data, putting one result to NT. Image capture timestamp
|
438
439
|
overrides :meth:`.PhotonPipelineResult.getTimestampSeconds` for more
|
@@ -441,44 +442,45 @@ class PhotonCameraSim:
|
|
441
442
|
:param result: The pipeline result to submit
|
442
443
|
:param receiveTimestamp: The (sim) timestamp when this result was read by NT in microseconds. If not passed image capture time is assumed be (current time - latency)
|
443
444
|
"""
|
444
|
-
if
|
445
|
-
|
446
|
-
|
445
|
+
if receiveTimestamp_us is None:
|
446
|
+
receiveTimestamp_us = wpilib.Timer.getFPGATimestamp() * 1e6
|
447
|
+
receiveTimestamp_us = int(receiveTimestamp_us)
|
447
448
|
|
448
|
-
self.ts.latencyMillisEntry.set(result.getLatencyMillis(),
|
449
|
+
self.ts.latencyMillisEntry.set(result.getLatencyMillis(), receiveTimestamp_us)
|
449
450
|
|
450
451
|
newPacket = PhotonPipelineResult.photonStruct.pack(result)
|
451
|
-
self.ts.rawBytesEntry.set(newPacket.getData(),
|
452
|
+
self.ts.rawBytesEntry.set(newPacket.getData(), receiveTimestamp_us)
|
452
453
|
|
453
454
|
hasTargets = result.hasTargets()
|
454
|
-
self.ts.hasTargetEntry.set(hasTargets,
|
455
|
+
self.ts.hasTargetEntry.set(hasTargets, receiveTimestamp_us)
|
455
456
|
if not hasTargets:
|
456
|
-
self.ts.targetPitchEntry.set(0.0,
|
457
|
-
self.ts.targetYawEntry.set(0.0,
|
458
|
-
self.ts.targetAreaEntry.set(0.0,
|
459
|
-
self.ts.targetPoseEntry.set(Transform3d(),
|
460
|
-
self.ts.targetSkewEntry.set(0.0,
|
457
|
+
self.ts.targetPitchEntry.set(0.0, receiveTimestamp_us)
|
458
|
+
self.ts.targetYawEntry.set(0.0, receiveTimestamp_us)
|
459
|
+
self.ts.targetAreaEntry.set(0.0, receiveTimestamp_us)
|
460
|
+
self.ts.targetPoseEntry.set(Transform3d(), receiveTimestamp_us)
|
461
|
+
self.ts.targetSkewEntry.set(0.0, receiveTimestamp_us)
|
461
462
|
else:
|
462
463
|
bestTarget = result.getBestTarget()
|
463
464
|
assert bestTarget
|
464
465
|
|
465
|
-
self.ts.targetPitchEntry.set(bestTarget.getPitch(),
|
466
|
-
self.ts.targetYawEntry.set(bestTarget.getYaw(),
|
467
|
-
self.ts.targetAreaEntry.set(bestTarget.getArea(),
|
468
|
-
self.ts.targetSkewEntry.set(bestTarget.getSkew(),
|
466
|
+
self.ts.targetPitchEntry.set(bestTarget.getPitch(), receiveTimestamp_us)
|
467
|
+
self.ts.targetYawEntry.set(bestTarget.getYaw(), receiveTimestamp_us)
|
468
|
+
self.ts.targetAreaEntry.set(bestTarget.getArea(), receiveTimestamp_us)
|
469
|
+
self.ts.targetSkewEntry.set(bestTarget.getSkew(), receiveTimestamp_us)
|
469
470
|
|
470
471
|
self.ts.targetPoseEntry.set(
|
471
|
-
bestTarget.getBestCameraToTarget(),
|
472
|
+
bestTarget.getBestCameraToTarget(), receiveTimestamp_us
|
472
473
|
)
|
473
474
|
|
474
|
-
|
475
|
-
|
476
|
-
|
475
|
+
intrinsics = self.prop.getIntrinsics()
|
476
|
+
intrinsicsView = intrinsics.flatten().tolist()
|
477
|
+
self.ts.cameraIntrinsicsPublisher.set(intrinsicsView, receiveTimestamp_us)
|
477
478
|
|
478
|
-
|
479
|
-
|
480
|
-
|
479
|
+
distortion = self.prop.getDistCoeffs()
|
480
|
+
distortionView = distortion.flatten().tolist()
|
481
|
+
self.ts.cameraDistortionPublisher.set(distortionView, receiveTimestamp_us)
|
481
482
|
|
482
|
-
|
483
|
+
self.ts.heartbeatPublisher.set(self.heartbeatCounter, receiveTimestamp_us)
|
484
|
+
self.heartbeatCounter += 1
|
483
485
|
|
484
|
-
|
486
|
+
self.ts.subTable.getInstance().flush()
|
@@ -4,6 +4,7 @@ import typing
|
|
4
4
|
|
5
5
|
import cv2 as cv
|
6
6
|
import numpy as np
|
7
|
+
import numpy.typing as npt
|
7
8
|
from wpimath.geometry import Rotation2d, Rotation3d, Translation3d
|
8
9
|
from wpimath.units import hertz, seconds
|
9
10
|
|
@@ -31,8 +32,8 @@ class SimCameraProperties:
|
|
31
32
|
"""Default constructor which is the same as {@link #PERFECT_90DEG}"""
|
32
33
|
self.resWidth: int = -1
|
33
34
|
self.resHeight: int = -1
|
34
|
-
self.camIntrinsics: np.
|
35
|
-
self.distCoeffs: np.
|
35
|
+
self.camIntrinsics: npt.NDArray[np.floating] = np.zeros((3, 3)) # [3,3]
|
36
|
+
self.distCoeffs: npt.NDArray[np.floating] = np.zeros((8, 1)) # [8,1]
|
36
37
|
self.avgErrorPx: float = 0.0
|
37
38
|
self.errorStdDevPx: float = 0.0
|
38
39
|
self.frameSpeed: seconds = 0.0
|
@@ -80,7 +81,6 @@ class SimCameraProperties:
|
|
80
81
|
newCamIntrinsics: np.ndarray,
|
81
82
|
newDistCoeffs: np.ndarray,
|
82
83
|
) -> None:
|
83
|
-
|
84
84
|
self.resWidth = width
|
85
85
|
self.resHeight = height
|
86
86
|
self.camIntrinsics = newCamIntrinsics
|
@@ -173,10 +173,10 @@ class SimCameraProperties:
|
|
173
173
|
def getAspectRatio(self) -> float:
|
174
174
|
return 1.0 * self.resWidth / self.resHeight
|
175
175
|
|
176
|
-
def getIntrinsics(self) -> np.
|
176
|
+
def getIntrinsics(self) -> npt.NDArray[np.floating]:
|
177
177
|
return self.camIntrinsics
|
178
178
|
|
179
|
-
def getDistCoeffs(self) -> np.
|
179
|
+
def getDistCoeffs(self) -> npt.NDArray[np.floating]:
|
180
180
|
return self.distCoeffs
|
181
181
|
|
182
182
|
def getFPS(self) -> hertz:
|
@@ -355,7 +355,6 @@ class SimCameraProperties:
|
|
355
355
|
|
356
356
|
# find intersections
|
357
357
|
for i, normal in enumerate(self.viewplanes):
|
358
|
-
|
359
358
|
# // we want to know the value of t when the line intercepts this plane
|
360
359
|
# // parametrized: v = t * ab + a, where v lies on the plane
|
361
360
|
# // we can find the projection of a onto the plane normal
|
@@ -467,7 +466,7 @@ class SimCameraProperties:
|
|
467
466
|
|
468
467
|
def estSecUntilNextFrame(self) -> seconds:
|
469
468
|
"""
|
470
|
-
:returns: Estimate how long until the next frame should be processed in
|
469
|
+
:returns: Estimate how long until the next frame should be processed in seconds
|
471
470
|
"""
|
472
471
|
# // exceptional processing latency blocks the next frame
|
473
472
|
return self.frameSpeed + max(0.0, self.estLatency() - self.frameSpeed)
|
@@ -305,7 +305,7 @@ class VisionSystemSim:
|
|
305
305
|
timestampNt = optTimestamp
|
306
306
|
latency = camSim.prop.estLatency()
|
307
307
|
# the image capture timestamp in seconds of this result
|
308
|
-
timestampCapture = timestampNt
|
308
|
+
timestampCapture = timestampNt - latency
|
309
309
|
|
310
310
|
# use camera pose from the image capture timestamp
|
311
311
|
lateRobotPose = self.getRobotPose(timestampCapture)
|
@@ -318,7 +318,8 @@ class VisionSystemSim:
|
|
318
318
|
# process a PhotonPipelineResult with visible targets
|
319
319
|
camResult = camSim.process(latency, lateCameraPose, allTargets)
|
320
320
|
# publish this info to NT at estimated timestamp of receive
|
321
|
-
|
321
|
+
# needs a timestamp in microseconds
|
322
|
+
camSim.submitProcessedFrame(camResult, timestampNt * 1.0e6)
|
322
323
|
# display debug results
|
323
324
|
for tgt in camResult.getTargets():
|
324
325
|
trf = tgt.getBestCameraToTarget()
|
photonlibpy/version.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
PHOTONLIB_VERSION="v2025.0.0.beta.
|
2
|
-
PHOTONVISION_VERSION="v2025.0.0-beta-
|
1
|
+
PHOTONLIB_VERSION="v2025.0.0.beta.7"
|
2
|
+
PHOTONVISION_VERSION="v2025.0.0-beta-7"
|
@@ -1,7 +1,7 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: photonlibpy
|
3
|
-
Version: 2025.0.
|
4
|
-
Summary: Pure-python implementation of PhotonLib for interfacing with PhotonVision on coprocessors. Implemented with PhotonVision version v2025.0.0-beta-
|
3
|
+
Version: 2025.0.0b7
|
4
|
+
Summary: Pure-python implementation of PhotonLib for interfacing with PhotonVision on coprocessors. Implemented with PhotonVision version v2025.0.0-beta-7 .
|
5
5
|
Home-page: https://photonvision.org
|
6
6
|
Author: Photonvision Development Team
|
7
7
|
Description-Content-Type: text/markdown
|
@@ -4,7 +4,7 @@ photonlibpy/packet.py,sha256=5YomViVFwOljL2FGOetWM9FbPc_yCQ15ylzkYlgLIs8,9724
|
|
4
4
|
photonlibpy/photonCamera.py,sha256=ENBHp959it4aLnFtV66rHoAIYCvK4bTflZMrGSCwnZ8,12905
|
5
5
|
photonlibpy/photonPoseEstimator.py,sha256=2iMqxPFsQHTsq95yv-WCSv1a6wXNcHPqOyMc4Bu6IG0,12584
|
6
6
|
photonlibpy/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
7
|
-
photonlibpy/version.py,sha256=
|
7
|
+
photonlibpy/version.py,sha256=BYilKcVVr0-QNCDokqtB4odE1QfHYAG5R7_A_PA2O-I,77
|
8
8
|
photonlibpy/estimation/__init__.py,sha256=pZ-d6fN1DJvT-lRl4FfIos5HAvlzmetIOrGIinrdv7k,223
|
9
9
|
photonlibpy/estimation/cameraTargetRelation.py,sha256=i7DPBXtkZve4ToXQscEIe-5F1oGQ1Qmf5QBaE__EeMQ,1158
|
10
10
|
photonlibpy/estimation/openCVHelp.py,sha256=O1dV7v7RHSyw7l5L0QXbal6t9K7iyvEG76tG-t4AFVg,12388
|
@@ -18,20 +18,20 @@ photonlibpy/generated/PhotonTrackedTargetSerde.py,sha256=-6vKir_ABDVBGbg8ktM48IK
|
|
18
18
|
photonlibpy/generated/PnpResultSerde.py,sha256=YoTKdQ51oSdxC-7Poy6hunL0-zkMKvP5uedqaHWPudY,2693
|
19
19
|
photonlibpy/generated/TargetCornerSerde.py,sha256=kziD_rQIwyhzPfgOaDgn-3d87tvtXiAYbBjzu76biYU,2190
|
20
20
|
photonlibpy/generated/__init__.py,sha256=mElM8M88---wxTWO-SRqIJ4EfxN0fdIUwZBZ-UIGuRw,428
|
21
|
-
photonlibpy/networktables/NTTopicSet.py,sha256=
|
21
|
+
photonlibpy/networktables/NTTopicSet.py,sha256=29wPgXcuqT-u72-YXwSjRHWhECNzU8eDsexcqlA8KQ0,2967
|
22
22
|
photonlibpy/networktables/__init__.py,sha256=o_LxTdyIylAszMy_zhUtTkXHyu6jqxccccj78d44OrI,35
|
23
23
|
photonlibpy/simulation/__init__.py,sha256=HKJV02of5d8bOnuI7syLzSYtOYge7XUrHSaLvawh99M,227
|
24
|
-
photonlibpy/simulation/photonCameraSim.py,sha256=
|
25
|
-
photonlibpy/simulation/simCameraProperties.py,sha256=
|
24
|
+
photonlibpy/simulation/photonCameraSim.py,sha256=8ELLcOXUtDftV_OYzGG03wigANimJs2SehV-fluWy3k,19907
|
25
|
+
photonlibpy/simulation/simCameraProperties.py,sha256=ODVxnylF8zw9HZSbw0PzG_OEtUo9ChRo-G_iEgADOCg,27195
|
26
26
|
photonlibpy/simulation/videoSimUtil.py,sha256=xMuTvJ2Jx9IoQqmAJi_zUm06MdEwhVpIz9OyzYQp0k4,29
|
27
|
-
photonlibpy/simulation/visionSystemSim.py,sha256=
|
27
|
+
photonlibpy/simulation/visionSystemSim.py,sha256=GmKs0d32WE8B020YEWnj-0dQuCnVv1ScGdcFl1fOsKo,13835
|
28
28
|
photonlibpy/simulation/visionTargetSim.py,sha256=FH85fKE4NntowUvssfgZ1KlE-I_3Z-QuAgb2bFqvfdY,2219
|
29
29
|
photonlibpy/targeting/TargetCorner.py,sha256=ouKj3E5uD76OZSNHHuSDzKOY65a8HqtcOsuejH-MVsU,276
|
30
30
|
photonlibpy/targeting/__init__.py,sha256=YzINSpq6A0cjr-yAQcFqHoiYdLGKPFXThlVYlMjY11w,295
|
31
31
|
photonlibpy/targeting/multiTargetPNPResult.py,sha256=Y9rweHtMzoCZ6mv6F8CutQi2Thq5pHN0ydBWvTCsOwY,806
|
32
32
|
photonlibpy/targeting/photonPipelineResult.py,sha256=MbaSyHZTJpoKTtLOZztpSGSt9xWWFqhzgwj8medObVA,2732
|
33
33
|
photonlibpy/targeting/photonTrackedTarget.py,sha256=zCoFp32hX-3GmBYEmsYBQieBoMzXtP2F_55_q0zPOXA,1956
|
34
|
-
photonlibpy-2025.0.
|
35
|
-
photonlibpy-2025.0.
|
36
|
-
photonlibpy-2025.0.
|
37
|
-
photonlibpy-2025.0.
|
34
|
+
photonlibpy-2025.0.0b7.dist-info/METADATA,sha256=1_kdzX3qorgdxPyPEFtZa2ZbKddOjmQbCC4A91OKNes,689
|
35
|
+
photonlibpy-2025.0.0b7.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
36
|
+
photonlibpy-2025.0.0b7.dist-info/top_level.txt,sha256=T8Xc6U6he2VjKUAca6zawSkHdUZuLanxYIc4nxw2ctc,12
|
37
|
+
photonlibpy-2025.0.0b7.dist-info/RECORD,,
|
File without changes
|