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.
@@ -17,10 +17,11 @@ class NTTopicSet:
17
17
  different for sim vs. real camera
18
18
  """
19
19
 
20
- def __init__(self, tableName: str, cameraName: str) -> None:
21
- instance = nt.NetworkTableInstance.getDefault()
22
- photonvision_root_table = instance.getTable(tableName)
23
- self.subTable = photonvision_root_table.getSubTable(cameraName)
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
- self.videoSimProcEnabled: bool = (
64
- False # TODO switch this back to default True when the functionality is enabled
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 = int(wpilib.Timer.getFPGATimestamp() * 1e6)
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("photonvision", self.cam.getName())
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 Long of the timestamp in microseconds of when the frame which should be received by NT. If
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 long which is empty while blocked or the NT entry timestamp in microseconds if
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 = int(wpilib.Timer.getFPGATimestamp() * 1e6)
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 = int(self.nextNtEntryTime)
189
- frameTime = int(self.prop.estSecUntilNextFrame() * 1e6)
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, result: PhotonPipelineResult, receiveTimestamp: float | None
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 receiveTimestamp is None:
445
- receiveTimestamp = wpilib.Timer.getFPGATimestamp() * 1e6
446
- receiveTimestamp = int(receiveTimestamp)
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(), receiveTimestamp)
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(), receiveTimestamp)
452
+ self.ts.rawBytesEntry.set(newPacket.getData(), receiveTimestamp_us)
452
453
 
453
454
  hasTargets = result.hasTargets()
454
- self.ts.hasTargetEntry.set(hasTargets, receiveTimestamp)
455
+ self.ts.hasTargetEntry.set(hasTargets, receiveTimestamp_us)
455
456
  if not hasTargets:
456
- self.ts.targetPitchEntry.set(0.0, receiveTimestamp)
457
- self.ts.targetYawEntry.set(0.0, receiveTimestamp)
458
- self.ts.targetAreaEntry.set(0.0, receiveTimestamp)
459
- self.ts.targetPoseEntry.set(Transform3d(), receiveTimestamp)
460
- self.ts.targetSkewEntry.set(0.0, receiveTimestamp)
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(), receiveTimestamp)
466
- self.ts.targetYawEntry.set(bestTarget.getYaw(), receiveTimestamp)
467
- self.ts.targetAreaEntry.set(bestTarget.getArea(), receiveTimestamp)
468
- self.ts.targetSkewEntry.set(bestTarget.getSkew(), receiveTimestamp)
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(), receiveTimestamp
472
+ bestTarget.getBestCameraToTarget(), receiveTimestamp_us
472
473
  )
473
474
 
474
- intrinsics = self.prop.getIntrinsics()
475
- intrinsicsView = intrinsics.flatten().tolist()
476
- self.ts.cameraIntrinsicsPublisher.set(intrinsicsView, receiveTimestamp)
475
+ intrinsics = self.prop.getIntrinsics()
476
+ intrinsicsView = intrinsics.flatten().tolist()
477
+ self.ts.cameraIntrinsicsPublisher.set(intrinsicsView, receiveTimestamp_us)
477
478
 
478
- distortion = self.prop.getDistCoeffs()
479
- distortionView = distortion.flatten().tolist()
480
- self.ts.cameraDistortionPublisher.set(distortionView, receiveTimestamp)
479
+ distortion = self.prop.getDistCoeffs()
480
+ distortionView = distortion.flatten().tolist()
481
+ self.ts.cameraDistortionPublisher.set(distortionView, receiveTimestamp_us)
481
482
 
482
- self.ts.heartbeatPublisher.set(self.heartbeatCounter, receiveTimestamp)
483
+ self.ts.heartbeatPublisher.set(self.heartbeatCounter, receiveTimestamp_us)
484
+ self.heartbeatCounter += 1
483
485
 
484
- self.ts.subTable.getInstance().flush()
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.ndarray = np.zeros((3, 3)) # [3,3]
35
- self.distCoeffs: np.ndarray = np.zeros((8, 1)) # [8,1]
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.ndarray:
176
+ def getIntrinsics(self) -> npt.NDArray[np.floating]:
177
177
  return self.camIntrinsics
178
178
 
179
- def getDistCoeffs(self) -> np.ndarray:
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 milliseconds
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 * 1.0e-6 - latency
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
- camSim.submitProcessedFrame(camResult, timestampNt)
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.5"
2
- PHOTONVISION_VERSION="v2025.0.0-beta-5"
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.0b5
4
- Summary: Pure-python implementation of PhotonLib for interfacing with PhotonVision on coprocessors. Implemented with PhotonVision version v2025.0.0-beta-5 .
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=6IuHSryBtyyUy01tGUnTVp4WTudFZoF1qjXkZI10_s8,77
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=TXJyVg6S8gONeuRqX_NI0FdxYw51bNLlFIAQ4Y2wyVg,3104
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=5GTPdU7SRAahhtXYHcbm0GJEzARWA7lyBG3v279pqGk,19891
25
- photonlibpy/simulation/simCameraProperties.py,sha256=zh6dZ5SeVvW6qxLDhlMm09o-uScQf-20b_r4K3lutjs,27119
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=ln1TYVMXUreg6nxrVZJ7lw8puvgLbBBde_ciM2CH5G4,13788
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.0b5.dist-info/METADATA,sha256=4ZsDeto_2wGBLbC11F4UxpFEQu2OE6F1DRhfssRZK9w,689
35
- photonlibpy-2025.0.0b5.dist-info/WHEEL,sha256=bFJAMchF8aTQGUgMZzHJyDDMPTO3ToJ7x23SLJa1SVo,92
36
- photonlibpy-2025.0.0b5.dist-info/top_level.txt,sha256=T8Xc6U6he2VjKUAca6zawSkHdUZuLanxYIc4nxw2ctc,12
37
- photonlibpy-2025.0.0b5.dist-info/RECORD,,
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.45.0)
2
+ Generator: bdist_wheel (0.45.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5