photonlibpy 2025.0.0b5__tar.gz → 2025.0.0b6__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/PKG-INFO +2 -2
  2. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/networktables/NTTopicSet.py +5 -4
  3. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/simulation/photonCameraSim.py +38 -36
  4. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/simulation/simCameraProperties.py +6 -7
  5. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/simulation/visionSystemSim.py +3 -2
  6. photonlibpy-2025.0.0b6/photonlibpy/version.py +2 -0
  7. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy.egg-info/PKG-INFO +2 -2
  8. photonlibpy-2025.0.0b5/photonlibpy/version.py +0 -2
  9. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/__init__.py +0 -0
  10. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/estimatedRobotPose.py +0 -0
  11. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/estimation/__init__.py +0 -0
  12. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/estimation/cameraTargetRelation.py +0 -0
  13. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/estimation/openCVHelp.py +0 -0
  14. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/estimation/rotTrlTransform3d.py +0 -0
  15. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/estimation/targetModel.py +0 -0
  16. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/estimation/visionEstimation.py +0 -0
  17. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/generated/MultiTargetPNPResultSerde.py +0 -0
  18. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/generated/PhotonPipelineMetadataSerde.py +0 -0
  19. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/generated/PhotonPipelineResultSerde.py +0 -0
  20. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/generated/PhotonTrackedTargetSerde.py +0 -0
  21. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/generated/PnpResultSerde.py +0 -0
  22. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/generated/TargetCornerSerde.py +0 -0
  23. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/generated/__init__.py +0 -0
  24. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/networktables/__init__.py +0 -0
  25. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/packet.py +0 -0
  26. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/photonCamera.py +0 -0
  27. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/photonPoseEstimator.py +0 -0
  28. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/py.typed +0 -0
  29. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/simulation/__init__.py +0 -0
  30. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/simulation/videoSimUtil.py +0 -0
  31. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/simulation/visionTargetSim.py +0 -0
  32. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/targeting/TargetCorner.py +0 -0
  33. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/targeting/__init__.py +0 -0
  34. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/targeting/multiTargetPNPResult.py +0 -0
  35. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/targeting/photonPipelineResult.py +0 -0
  36. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy/targeting/photonTrackedTarget.py +0 -0
  37. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy.egg-info/SOURCES.txt +0 -0
  38. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy.egg-info/dependency_links.txt +0 -0
  39. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy.egg-info/requires.txt +0 -0
  40. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/photonlibpy.egg-info/top_level.txt +0 -0
  41. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/pyproject.toml +0 -0
  42. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/setup.cfg +0 -0
  43. {photonlibpy-2025.0.0b5 → photonlibpy-2025.0.0b6}/setup.py +0 -0
@@ -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.0b6
4
+ Summary: Pure-python implementation of PhotonLib for interfacing with PhotonVision on coprocessors. Implemented with PhotonVision version v2025.0.0-beta-6 .
5
5
  Home-page: https://photonvision.org
6
6
  Author: Photonvision Development Team
7
7
  Description-Content-Type: text/markdown
@@ -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()
@@ -0,0 +1,2 @@
1
+ PHOTONLIB_VERSION="v2025.0.0.beta.6"
2
+ PHOTONVISION_VERSION="v2025.0.0-beta-6"
@@ -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.0b6
4
+ Summary: Pure-python implementation of PhotonLib for interfacing with PhotonVision on coprocessors. Implemented with PhotonVision version v2025.0.0-beta-6 .
5
5
  Home-page: https://photonvision.org
6
6
  Author: Photonvision Development Team
7
7
  Description-Content-Type: text/markdown
@@ -1,2 +0,0 @@
1
- PHOTONLIB_VERSION="v2025.0.0.beta.5"
2
- PHOTONVISION_VERSION="v2025.0.0-beta-5"