photonlibpy 2025.0.0b1__py3-none-any.whl → 2025.0.0b3__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.
Files changed (37) hide show
  1. photonlibpy/__init__.py +2 -2
  2. photonlibpy/estimation/__init__.py +5 -0
  3. photonlibpy/estimation/cameraTargetRelation.py +25 -0
  4. photonlibpy/estimation/openCVHelp.py +205 -0
  5. photonlibpy/estimation/rotTrlTransform3d.py +55 -0
  6. photonlibpy/estimation/targetModel.py +120 -0
  7. photonlibpy/estimation/visionEstimation.py +91 -0
  8. photonlibpy/generated/MultiTargetPNPResultSerde.py +7 -1
  9. photonlibpy/generated/PhotonPipelineMetadataSerde.py +6 -1
  10. photonlibpy/generated/PhotonPipelineResultSerde.py +9 -1
  11. photonlibpy/generated/PhotonTrackedTargetSerde.py +7 -1
  12. photonlibpy/generated/PnpResultSerde.py +6 -1
  13. photonlibpy/generated/TargetCornerSerde.py +6 -1
  14. photonlibpy/generated/__init__.py +0 -1
  15. photonlibpy/networktables/NTTopicSet.py +66 -0
  16. photonlibpy/networktables/__init__.py +1 -0
  17. photonlibpy/packet.py +17 -9
  18. photonlibpy/photonCamera.py +10 -7
  19. photonlibpy/photonPoseEstimator.py +3 -3
  20. photonlibpy/simulation/__init__.py +5 -0
  21. photonlibpy/simulation/photonCameraSim.py +378 -0
  22. photonlibpy/simulation/simCameraProperties.py +643 -0
  23. photonlibpy/simulation/videoSimUtil.py +2 -0
  24. photonlibpy/simulation/visionSystemSim.py +242 -0
  25. photonlibpy/simulation/visionTargetSim.py +50 -0
  26. photonlibpy/targeting/TargetCorner.py +5 -1
  27. photonlibpy/targeting/__init__.py +1 -1
  28. photonlibpy/targeting/multiTargetPNPResult.py +8 -13
  29. photonlibpy/targeting/photonPipelineResult.py +8 -4
  30. photonlibpy/targeting/photonTrackedTarget.py +7 -1
  31. photonlibpy/version.py +2 -2
  32. photonlibpy-2025.0.0b3.dist-info/METADATA +17 -0
  33. photonlibpy-2025.0.0b3.dist-info/RECORD +36 -0
  34. photonlibpy-2025.0.0b1.dist-info/METADATA +0 -13
  35. photonlibpy-2025.0.0b1.dist-info/RECORD +0 -22
  36. {photonlibpy-2025.0.0b1.dist-info → photonlibpy-2025.0.0b3.dist-info}/WHEEL +0 -0
  37. {photonlibpy-2025.0.0b1.dist-info → photonlibpy-2025.0.0b3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,242 @@
1
+ import typing
2
+
3
+ import wpilib
4
+ from robotpy_apriltag import AprilTagFieldLayout
5
+ from wpilib import Field2d
6
+ from wpimath.geometry import Pose2d, Pose3d, Transform3d
7
+
8
+ # TODO(auscompgeek): update import path when RobotPy re-exports are fixed
9
+ from wpimath.interpolation._interpolation import TimeInterpolatablePose3dBuffer
10
+ from wpimath.units import seconds
11
+
12
+ from ..estimation import TargetModel
13
+ from .photonCameraSim import PhotonCameraSim
14
+ from .visionTargetSim import VisionTargetSim
15
+
16
+
17
+ class VisionSystemSim:
18
+ def __init__(self, visionSystemName: str):
19
+ self.dbgField: Field2d = Field2d()
20
+ self.bufferLength: seconds = 1.5
21
+
22
+ self.camSimMap: typing.Dict[str, PhotonCameraSim] = {}
23
+ self.camTrfMap: typing.Dict[PhotonCameraSim, TimeInterpolatablePose3dBuffer] = (
24
+ {}
25
+ )
26
+ self.robotPoseBuffer: TimeInterpolatablePose3dBuffer = (
27
+ TimeInterpolatablePose3dBuffer(self.bufferLength)
28
+ )
29
+ self.targetSets: typing.Dict[str, list[VisionTargetSim]] = {}
30
+
31
+ self.tableName: str = "VisionSystemSim-" + visionSystemName
32
+ wpilib.SmartDashboard.putData(self.tableName + "/Sim Field", self.dbgField)
33
+
34
+ def getCameraSim(self, name: str) -> PhotonCameraSim | None:
35
+ return self.camSimMap.get(name, None)
36
+
37
+ def getCameraSims(self) -> list[PhotonCameraSim]:
38
+ return [*self.camSimMap.values()]
39
+
40
+ def addCamera(self, cameraSim: PhotonCameraSim, robotToCamera: Transform3d) -> None:
41
+ name = cameraSim.getCamera().getName()
42
+ if name not in self.camSimMap:
43
+ self.camSimMap[name] = cameraSim
44
+ self.camTrfMap[cameraSim] = TimeInterpolatablePose3dBuffer(
45
+ self.bufferLength
46
+ )
47
+ self.camTrfMap[cameraSim].addSample(
48
+ wpilib.Timer.getFPGATimestamp(), Pose3d() + robotToCamera
49
+ )
50
+
51
+ def clearCameras(self) -> None:
52
+ self.camSimMap.clear()
53
+ self.camTrfMap.clear()
54
+
55
+ def removeCamera(self, cameraSim: PhotonCameraSim) -> bool:
56
+ name = cameraSim.getCamera().getName()
57
+ if name in self.camSimMap:
58
+ del self.camSimMap[name]
59
+ return True
60
+ else:
61
+ return False
62
+
63
+ def getRobotToCamera(
64
+ self,
65
+ cameraSim: PhotonCameraSim,
66
+ time: seconds = wpilib.Timer.getFPGATimestamp(),
67
+ ) -> Transform3d | None:
68
+ if cameraSim in self.camTrfMap:
69
+ trfBuffer = self.camTrfMap[cameraSim]
70
+ sample = trfBuffer.sample(time)
71
+ if sample is None:
72
+ return None
73
+ else:
74
+ return Transform3d(Pose3d(), sample)
75
+ else:
76
+ return None
77
+
78
+ def getCameraPose(
79
+ self,
80
+ cameraSim: PhotonCameraSim,
81
+ time: seconds = wpilib.Timer.getFPGATimestamp(),
82
+ ) -> Pose3d | None:
83
+ robotToCamera = self.getRobotToCamera(cameraSim, time)
84
+ if robotToCamera is None:
85
+ return None
86
+ else:
87
+ pose = self.getRobotPose(time)
88
+ if pose:
89
+ return pose + robotToCamera
90
+ else:
91
+ return None
92
+
93
+ def adjustCamera(
94
+ self, cameraSim: PhotonCameraSim, robotToCamera: Transform3d
95
+ ) -> bool:
96
+ if cameraSim in self.camTrfMap:
97
+ self.camTrfMap[cameraSim].addSample(
98
+ wpilib.Timer.getFPGATimestamp(), Pose3d() + robotToCamera
99
+ )
100
+ return True
101
+ else:
102
+ return False
103
+
104
+ def resetCameraTransforms(self, cameraSim: PhotonCameraSim | None = None) -> None:
105
+ now = wpilib.Timer.getFPGATimestamp()
106
+
107
+ def resetSingleCamera(self, cameraSim: PhotonCameraSim) -> bool:
108
+ if cameraSim in self.camTrfMap:
109
+ trfBuffer = self.camTrfMap[cameraSim]
110
+ lastTrf = Transform3d(Pose3d(), trfBuffer.sample(now))
111
+ trfBuffer.clear()
112
+ self.adjustCamera(cameraSim, lastTrf)
113
+ return True
114
+ else:
115
+ return False
116
+
117
+ if cameraSim is None:
118
+ for camera in self.camTrfMap.keys():
119
+ resetSingleCamera(self, camera)
120
+ else:
121
+ resetSingleCamera(self, cameraSim)
122
+
123
+ def getVisionTargets(self, targetType: str | None = None) -> list[VisionTargetSim]:
124
+ if targetType is None:
125
+ all: list[VisionTargetSim] = []
126
+ for targets in self.targetSets.values():
127
+ for target in targets:
128
+ all.append(target)
129
+ return all
130
+ else:
131
+ return self.targetSets[targetType]
132
+
133
+ def addVisionTargets(
134
+ self, targets: list[VisionTargetSim], targetType: str = "targets"
135
+ ) -> None:
136
+ if targetType not in self.targetSets:
137
+ self.targetSets[targetType] = targets
138
+ else:
139
+ self.targetSets[targetType] += targets
140
+
141
+ def addAprilTags(self, layout: AprilTagFieldLayout) -> None:
142
+ targets: list[VisionTargetSim] = []
143
+ for tag in layout.getTags():
144
+ tag_pose = layout.getTagPose(tag.ID)
145
+ # TODO this was done to make the python gods happy. Confirm that this is desired or if types dont matter
146
+ assert tag_pose is not None
147
+ targets.append(
148
+ VisionTargetSim(tag_pose, TargetModel.AprilTag36h11(), tag.ID)
149
+ )
150
+ self.addVisionTargets(targets, "apriltag")
151
+
152
+ def clearVisionTargets(self) -> None:
153
+ self.targetSets.clear()
154
+
155
+ def clearAprilTags(self) -> None:
156
+ self.removeVisionTargetType("apriltag")
157
+
158
+ def removeVisionTargetType(self, targetType: str) -> None:
159
+ del self.targetSets[targetType]
160
+
161
+ def removeVisionTargets(
162
+ self, targets: list[VisionTargetSim]
163
+ ) -> list[VisionTargetSim]:
164
+ removedList: list[VisionTargetSim] = []
165
+ for target in targets:
166
+ for _, currentTargets in self.targetSets.items():
167
+ if target in currentTargets:
168
+ removedList.append(target)
169
+ currentTargets.remove(target)
170
+ return removedList
171
+
172
+ def getRobotPose(
173
+ self, timestamp: seconds = wpilib.Timer.getFPGATimestamp()
174
+ ) -> Pose3d | None:
175
+ return self.robotPoseBuffer.sample(timestamp)
176
+
177
+ def resetRobotPose(self, robotPose: Pose2d | Pose3d) -> None:
178
+ if type(robotPose) is Pose2d:
179
+ robotPose = Pose3d(robotPose)
180
+ assert type(robotPose) is Pose3d
181
+
182
+ self.robotPoseBuffer.clear()
183
+ self.robotPoseBuffer.addSample(wpilib.Timer.getFPGATimestamp(), robotPose)
184
+
185
+ def getDebugField(self) -> Field2d:
186
+ return self.dbgField
187
+
188
+ def update(self, robotPose: Pose2d | Pose3d) -> None:
189
+ if type(robotPose) is Pose2d:
190
+ robotPose = Pose3d(robotPose)
191
+ assert type(robotPose) is Pose3d
192
+
193
+ for targetType, targets in self.targetSets.items():
194
+ posesToAdd: list[Pose2d] = []
195
+ for target in targets:
196
+ posesToAdd.append(target.getPose().toPose2d())
197
+ self.dbgField.getObject(targetType).setPoses(posesToAdd)
198
+
199
+ now = wpilib.Timer.getFPGATimestamp()
200
+ self.robotPoseBuffer.addSample(now, robotPose)
201
+ self.dbgField.setRobotPose(robotPose.toPose2d())
202
+
203
+ allTargets: list[VisionTargetSim] = []
204
+ for targets in self.targetSets.values():
205
+ for target in targets:
206
+ allTargets.append(target)
207
+
208
+ visTgtPoses2d: list[Pose2d] = []
209
+ cameraPoses2d: list[Pose2d] = []
210
+ processed = False
211
+ for camSim in self.camSimMap.values():
212
+ optTimestamp = camSim.consumeNextEntryTime()
213
+ if optTimestamp is None:
214
+ continue
215
+ else:
216
+ processed = True
217
+
218
+ timestampNt = optTimestamp
219
+ latency = camSim.prop.estLatency()
220
+ timestampCapture = timestampNt * 1.0e-6 - latency
221
+
222
+ lateRobotPose = self.getRobotPose(timestampCapture)
223
+ robotToCamera = self.getRobotToCamera(camSim, timestampCapture)
224
+ if lateRobotPose is None or robotToCamera is None:
225
+ return None
226
+ lateCameraPose = lateRobotPose + robotToCamera
227
+ cameraPoses2d.append(lateCameraPose.toPose2d())
228
+
229
+ camResult = camSim.process(latency, lateCameraPose, allTargets)
230
+ camSim.submitProcessedFrame(camResult, timestampNt)
231
+ for tgt in camResult.getTargets():
232
+ trf = tgt.getBestCameraToTarget()
233
+ if trf == Transform3d():
234
+ continue
235
+
236
+ visTgtPoses2d.append(lateCameraPose.transformBy(trf).toPose2d())
237
+
238
+ if processed:
239
+ self.dbgField.getObject("visibleTargetPoses").setPoses(visTgtPoses2d)
240
+
241
+ if len(cameraPoses2d) != 0:
242
+ self.dbgField.getObject("cameras").setPoses(cameraPoses2d)
@@ -0,0 +1,50 @@
1
+ import math
2
+
3
+ from wpimath.geometry import Pose3d, Translation3d
4
+
5
+ from ..estimation.targetModel import TargetModel
6
+
7
+
8
+ class VisionTargetSim:
9
+ def __init__(self, pose: Pose3d, model: TargetModel, id: int = -1):
10
+ self.pose: Pose3d = pose
11
+ self.model: TargetModel = model
12
+ self.fiducialId: int = id
13
+ self.objDetClassId: int = -1
14
+ self.objDetConf: float = -1.0
15
+
16
+ def __lt__(self, right) -> bool:
17
+ return self.pose.translation().norm() < right.pose.translation().norm()
18
+
19
+ def __eq__(self, other) -> bool:
20
+ # Use 1 inch and 1 degree tolerance
21
+ return (
22
+ abs(self.pose.translation().X() - other.getPose().translation().X())
23
+ < 0.0254
24
+ and abs(self.pose.translation().Y() - other.getPose().translation().Y())
25
+ < 0.0254
26
+ and abs(self.pose.translation().Z() - other.getPose().translation().Z())
27
+ < 0.0254
28
+ and abs(self.pose.rotation().X() - other.getPose().rotation().X())
29
+ < math.radians(1)
30
+ and abs(self.pose.rotation().Y() - other.getPose().rotation().Y())
31
+ < math.radians(1)
32
+ and abs(self.pose.rotation().Z() - other.getPose().rotation().Z())
33
+ < math.radians(1)
34
+ and self.model.getIsPlanar() == other.getModel().getIsPlanar()
35
+ )
36
+
37
+ def setPose(self, newPose: Pose3d) -> None:
38
+ self.pose = newPose
39
+
40
+ def setModel(self, newModel: TargetModel) -> None:
41
+ self.model = newModel
42
+
43
+ def getPose(self) -> Pose3d:
44
+ return self.pose
45
+
46
+ def getModel(self) -> TargetModel:
47
+ return self.model
48
+
49
+ def getFieldVertices(self) -> list[Translation3d]:
50
+ return self.model.getFieldVertices(self.pose)
@@ -1,4 +1,8 @@
1
1
  from dataclasses import dataclass
2
+ from typing import TYPE_CHECKING, ClassVar
3
+
4
+ if TYPE_CHECKING:
5
+ from ..generated.TargetCornerSerde import TargetCornerSerde
2
6
 
3
7
 
4
8
  @dataclass
@@ -6,4 +10,4 @@ class TargetCorner:
6
10
  x: float = 0
7
11
  y: float = 9
8
12
 
9
- photonStruct: "TargetCornerSerde" = None
13
+ photonStruct: ClassVar["TargetCornerSerde"]
@@ -1,6 +1,6 @@
1
1
  # no one but us chickens
2
2
 
3
- from .TargetCorner import TargetCorner # noqa
4
3
  from .multiTargetPNPResult import MultiTargetPNPResult, PnpResult # noqa
5
4
  from .photonPipelineResult import PhotonPipelineMetadata, PhotonPipelineResult # noqa
6
5
  from .photonTrackedTarget import PhotonTrackedTarget # noqa
6
+ from .TargetCorner import TargetCorner # noqa
@@ -1,6 +1,11 @@
1
1
  from dataclasses import dataclass, field
2
+ from typing import TYPE_CHECKING, ClassVar
3
+
2
4
  from wpimath.geometry import Transform3d
3
- from ..packet import Packet
5
+
6
+ if TYPE_CHECKING:
7
+ from ..generated.MultiTargetPNPResultSerde import MultiTargetPNPResultSerde
8
+ from ..generated.PnpResultSerde import PnpResultSerde
4
9
 
5
10
 
6
11
  @dataclass
@@ -11,7 +16,7 @@ class PnpResult:
11
16
  bestReprojErr: float = 0.0
12
17
  altReprojErr: float = 0.0
13
18
 
14
- photonStruct: "PNPResultSerde" = None
19
+ photonStruct: ClassVar["PnpResultSerde"]
15
20
 
16
21
 
17
22
  @dataclass
@@ -21,14 +26,4 @@ class MultiTargetPNPResult:
21
26
  estimatedPose: PnpResult = field(default_factory=PnpResult)
22
27
  fiducialIDsUsed: list[int] = field(default_factory=list)
23
28
 
24
- def createFromPacket(self, packet: Packet) -> Packet:
25
- self.estimatedPose = PnpResult()
26
- self.estimatedPose.createFromPacket(packet)
27
- self.fiducialIDsUsed = []
28
- for _ in range(MultiTargetPNPResult._MAX_IDS):
29
- fidId = packet.decode16()
30
- if fidId >= 0:
31
- self.fiducialIDsUsed.append(fidId)
32
- return packet
33
-
34
- photonStruct: "MultiTargetPNPResultSerde" = None
29
+ photonStruct: ClassVar["MultiTargetPNPResultSerde"]
@@ -1,9 +1,13 @@
1
1
  from dataclasses import dataclass, field
2
- from typing import Optional
2
+ from typing import TYPE_CHECKING, ClassVar, Optional
3
3
 
4
4
  from .multiTargetPNPResult import MultiTargetPNPResult
5
5
  from .photonTrackedTarget import PhotonTrackedTarget
6
6
 
7
+ if TYPE_CHECKING:
8
+ from ..generated.PhotonPipelineMetadataSerde import PhotonPipelineMetadataSerde
9
+ from ..generated.PhotonPipelineResultSerde import PhotonPipelineResultSerde
10
+
7
11
 
8
12
  @dataclass
9
13
  class PhotonPipelineMetadata:
@@ -17,7 +21,7 @@ class PhotonPipelineMetadata:
17
21
 
18
22
  timeSinceLastPong: int = -1
19
23
 
20
- photonStruct: "PhotonPipelineMetadataSerde" = None
24
+ photonStruct: ClassVar["PhotonPipelineMetadataSerde"]
21
25
 
22
26
 
23
27
  @dataclass
@@ -57,7 +61,7 @@ class PhotonPipelineResult:
57
61
  def hasTargets(self) -> bool:
58
62
  return len(self.targets) > 0
59
63
 
60
- def getBestTarget(self) -> PhotonTrackedTarget:
64
+ def getBestTarget(self) -> Optional[PhotonTrackedTarget]:
61
65
  """
62
66
  Returns the best target in this pipeline result. If there are no targets, this method will
63
67
  return null. The best target is determined by the target sort mode in the PhotonVision UI.
@@ -66,4 +70,4 @@ class PhotonPipelineResult:
66
70
  return None
67
71
  return self.getTargets()[0]
68
72
 
69
- photonStruct: "PhotonPipelineResultSerde" = None
73
+ photonStruct: ClassVar["PhotonPipelineResultSerde"]
@@ -1,8 +1,14 @@
1
1
  from dataclasses import dataclass, field
2
+ from typing import TYPE_CHECKING, ClassVar
3
+
2
4
  from wpimath.geometry import Transform3d
5
+
3
6
  from ..packet import Packet
4
7
  from .TargetCorner import TargetCorner
5
8
 
9
+ if TYPE_CHECKING:
10
+ from ..generated.PhotonTrackedTargetSerde import PhotonTrackedTargetSerde
11
+
6
12
 
7
13
  @dataclass
8
14
  class PhotonTrackedTarget:
@@ -57,4 +63,4 @@ class PhotonTrackedTarget:
57
63
  retList.append(TargetCorner(cx, cy))
58
64
  return retList
59
65
 
60
- photonStruct: "PhotonTrackedTargetSerde" = None
66
+ photonStruct: ClassVar["PhotonTrackedTargetSerde"]
photonlibpy/version.py CHANGED
@@ -1,2 +1,2 @@
1
- PHOTONLIB_VERSION="v2025.0.0.beta.1"
2
- PHOTONVISION_VERSION="v2025.0.0-beta-1"
1
+ PHOTONLIB_VERSION="v2025.0.0.beta.3"
2
+ PHOTONVISION_VERSION="v2025.0.0-beta-3"
@@ -0,0 +1,17 @@
1
+ Metadata-Version: 2.1
2
+ Name: photonlibpy
3
+ Version: 2025.0.0b3
4
+ Summary: Pure-python implementation of PhotonLib for interfacing with PhotonVision on coprocessors. Implemented with PhotonVision version v2025.0.0-beta-3 .
5
+ Home-page: https://photonvision.org
6
+ Author: Photonvision Development Team
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: numpy~=2.1
9
+ Requires-Dist: wpilib<2026,>=2025.0.0b1
10
+ Requires-Dist: robotpy-wpimath<2026,>=2025.0.0b1
11
+ Requires-Dist: robotpy-apriltag<2026,>=2025.0.0b1
12
+ Requires-Dist: robotpy-cscore<2026,>=2025.0.0b1
13
+ Requires-Dist: pyntcore<2026,>=2025.0.0b1
14
+ Requires-Dist: opencv-python; platform_machine != "roborio"
15
+ Requires-Dist: robotpy-opencv; platform_machine == "roborio"
16
+
17
+ A Pure-python implementation of PhotonLib
@@ -0,0 +1,36 @@
1
+ photonlibpy/__init__.py,sha256=WW1OGrrcNXwwxaHSZlkxmhH2GYiQIHHxSxGVTJZhZbY,1136
2
+ photonlibpy/estimatedRobotPose.py,sha256=X7wF9xdPXGKSVy0MY0qrWZJOEbuZPd721lYp0KXKlP0,1603
3
+ photonlibpy/packet.py,sha256=5YomViVFwOljL2FGOetWM9FbPc_yCQ15ylzkYlgLIs8,9724
4
+ photonlibpy/photonCamera.py,sha256=061meWm5G36_9vByAUBFCor0fR4G24baw306xt_cWB8,10181
5
+ photonlibpy/photonPoseEstimator.py,sha256=2iMqxPFsQHTsq95yv-WCSv1a6wXNcHPqOyMc4Bu6IG0,12584
6
+ photonlibpy/version.py,sha256=A48GfU-qwEM5vulc7mQd7EH8j_mm-7dL2tuMzcswSqg,77
7
+ photonlibpy/estimation/__init__.py,sha256=pZ-d6fN1DJvT-lRl4FfIos5HAvlzmetIOrGIinrdv7k,223
8
+ photonlibpy/estimation/cameraTargetRelation.py,sha256=i7DPBXtkZve4ToXQscEIe-5F1oGQ1Qmf5QBaE__EeMQ,1158
9
+ photonlibpy/estimation/openCVHelp.py,sha256=6ynO0WbccVxbUCeDu4QgISgipqiqs-erLd14rnSSH-c,6726
10
+ photonlibpy/estimation/rotTrlTransform3d.py,sha256=_5q3oMdbYRVBhzxQt5UwyRE7AXkhT3Fth5Ljrj3gANY,1728
11
+ photonlibpy/estimation/targetModel.py,sha256=ZfuiB0ZDNM8gMum5nuq6KWyEeFts49jYgMo7-oojjY0,3726
12
+ photonlibpy/estimation/visionEstimation.py,sha256=v4WkVtEQd5Q9OWxrcJAseIjP-trMHj_MDzMj4fcfjtw,3019
13
+ photonlibpy/generated/MultiTargetPNPResultSerde.py,sha256=CzsCosHUnzxAoSC_sSAqpsXsDp54KW-BClnIXdzfMPc,2506
14
+ photonlibpy/generated/PhotonPipelineMetadataSerde.py,sha256=9pq5XUEDEoRowCd7sRnuGV7xtugu5HZCRrnwqZG2xXc,2887
15
+ photonlibpy/generated/PhotonPipelineResultSerde.py,sha256=jTf1obU2jPNDsxvt-tl9Ty_qzJws9Wqron3C1QiHkP8,3137
16
+ photonlibpy/generated/PhotonTrackedTargetSerde.py,sha256=-6vKir_ABDVBGbg8ktM48IKm_nBMFBbiyuZLiO_fP9U,4437
17
+ photonlibpy/generated/PnpResultSerde.py,sha256=YoTKdQ51oSdxC-7Poy6hunL0-zkMKvP5uedqaHWPudY,2693
18
+ photonlibpy/generated/TargetCornerSerde.py,sha256=kziD_rQIwyhzPfgOaDgn-3d87tvtXiAYbBjzu76biYU,2190
19
+ photonlibpy/generated/__init__.py,sha256=mElM8M88---wxTWO-SRqIJ4EfxN0fdIUwZBZ-UIGuRw,428
20
+ photonlibpy/networktables/NTTopicSet.py,sha256=NduTI3c3fG4MuVcY2cuLIoV1i1PSxxYzqBOt24ngS9k,2708
21
+ photonlibpy/networktables/__init__.py,sha256=o_LxTdyIylAszMy_zhUtTkXHyu6jqxccccj78d44OrI,35
22
+ photonlibpy/simulation/__init__.py,sha256=HKJV02of5d8bOnuI7syLzSYtOYge7XUrHSaLvawh99M,227
23
+ photonlibpy/simulation/photonCameraSim.py,sha256=BJ870459FdaO1HLkAMfA23W2S8S9axn3rZUPyxQfH40,14078
24
+ photonlibpy/simulation/simCameraProperties.py,sha256=gcRfMOH5zQhv8mBElSo8GT7yOC9dA0EsQoJz-1WsCCw,19960
25
+ photonlibpy/simulation/videoSimUtil.py,sha256=xMuTvJ2Jx9IoQqmAJi_zUm06MdEwhVpIz9OyzYQp0k4,29
26
+ photonlibpy/simulation/visionSystemSim.py,sha256=WZKYdu89IVchcCsXR04AXVQv78F_KgZIQRZ00ocusWE,8814
27
+ photonlibpy/simulation/visionTargetSim.py,sha256=AN7jXW3guQfNUu2EiQl23Jj8Mkgn4gYmRphGXL0-Dqk,1734
28
+ photonlibpy/targeting/TargetCorner.py,sha256=ouKj3E5uD76OZSNHHuSDzKOY65a8HqtcOsuejH-MVsU,276
29
+ photonlibpy/targeting/__init__.py,sha256=YzINSpq6A0cjr-yAQcFqHoiYdLGKPFXThlVYlMjY11w,295
30
+ photonlibpy/targeting/multiTargetPNPResult.py,sha256=Y9rweHtMzoCZ6mv6F8CutQi2Thq5pHN0ydBWvTCsOwY,806
31
+ photonlibpy/targeting/photonPipelineResult.py,sha256=MbaSyHZTJpoKTtLOZztpSGSt9xWWFqhzgwj8medObVA,2732
32
+ photonlibpy/targeting/photonTrackedTarget.py,sha256=zCoFp32hX-3GmBYEmsYBQieBoMzXtP2F_55_q0zPOXA,1956
33
+ photonlibpy-2025.0.0b3.dist-info/METADATA,sha256=C6jySUa1aCRwXFf3ZKZS8l8C_MV4pnnfBS6Ueho98WM,750
34
+ photonlibpy-2025.0.0b3.dist-info/WHEEL,sha256=bFJAMchF8aTQGUgMZzHJyDDMPTO3ToJ7x23SLJa1SVo,92
35
+ photonlibpy-2025.0.0b3.dist-info/top_level.txt,sha256=T8Xc6U6he2VjKUAca6zawSkHdUZuLanxYIc4nxw2ctc,12
36
+ photonlibpy-2025.0.0b3.dist-info/RECORD,,
@@ -1,13 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: photonlibpy
3
- Version: 2025.0.0b1
4
- Summary: Pure-python implementation of PhotonLib for interfacing with PhotonVision on coprocessors. Implemented with PhotonVision version v2025.0.0-beta-1 .
5
- Home-page: https://photonvision.org
6
- Author: Photonvision Development Team
7
- Description-Content-Type: text/markdown
8
- Requires-Dist: wpilib<2025,>=2024.0.0b2
9
- Requires-Dist: robotpy-wpimath<2025,>=2024.0.0b2
10
- Requires-Dist: robotpy-apriltag<2025,>=2024.0.0b2
11
- Requires-Dist: pyntcore<2025,>=2024.0.0b2
12
-
13
- A Pure-python implementation of PhotonLib
@@ -1,22 +0,0 @@
1
- photonlibpy/__init__.py,sha256=JnwWj53fEM263hUjEFGmJ--M3XCX0LYovdrl4wcNRnU,1136
2
- photonlibpy/estimatedRobotPose.py,sha256=X7wF9xdPXGKSVy0MY0qrWZJOEbuZPd721lYp0KXKlP0,1603
3
- photonlibpy/packet.py,sha256=ppNJGN9bgWA4smefFvaxqF56Qwcjj0dnqwSIjP92JlE,9528
4
- photonlibpy/photonCamera.py,sha256=c3Q9AFuccR41AkajkqCRt3mqUtv7a-TNSKOmXBi9p7M,10181
5
- photonlibpy/photonPoseEstimator.py,sha256=vSpPbKR2WB-bNgWnskSP0Os2CcCzqcPGsE1lUVrcSw0,12584
6
- photonlibpy/version.py,sha256=Cac9aJKhHkgx4HcwV63_46tpcc8q-mu8IN_P1THZx2Q,77
7
- photonlibpy/generated/MultiTargetPNPResultSerde.py,sha256=t0hQgz0BvzQTsx-l0EJjr5eRfkY6piQRhu_2N2s2nlw,2342
8
- photonlibpy/generated/PhotonPipelineMetadataSerde.py,sha256=RiSWwu6ftwc19U_5uexu8VjET7NksjrXanzV8GYEHkE,2767
9
- photonlibpy/generated/PhotonPipelineResultSerde.py,sha256=DUrkUj2E6nS-Ru-drY-sX8odAl693VKJx_8lp0U-V9M,2847
10
- photonlibpy/generated/PhotonTrackedTargetSerde.py,sha256=AFuvhmOTBdDtkAOfdS99MRnTk7P-94P0wXi3GHyvJco,4271
11
- photonlibpy/generated/PnpResultSerde.py,sha256=tdHNHs9A7KBkYgqXQ5mUBc2TF3R_w3I_t922-DS6sQw,2586
12
- photonlibpy/generated/TargetCornerSerde.py,sha256=K2GJ_t_Gl91lJX823TeR10dzch1IQEX28tfob3eIftg,2080
13
- photonlibpy/generated/__init__.py,sha256=WdCA9k7QNY1i8B9u5kBilnibajDBg7zfU8GbV7F2H8g,505
14
- photonlibpy/targeting/TargetCorner.py,sha256=iFWTWu5HcpkBQyvhz_klpAB0TEmy-7_SsD1FHeNfnkE,147
15
- photonlibpy/targeting/__init__.py,sha256=1GUy4MC8NbZ-TEcFgsnvSm_X0LYeZ0HZagMMRmGpx8A,295
16
- photonlibpy/targeting/multiTargetPNPResult.py,sha256=G_5Rll-a0wnV2iJhwVpODY1Ag52uOUkzZfsGu5ns04Q,1006
17
- photonlibpy/targeting/photonPipelineResult.py,sha256=jXaZoyJvNYXg8N3senagkk2iduV5m_qsNnqWS3OsHx8,2508
18
- photonlibpy/targeting/photonTrackedTarget.py,sha256=qNPqh8eKTP9IIkBMVvkS_dq7SoVOpIm7d5b1ZUtN8bE,1811
19
- photonlibpy-2025.0.0b1.dist-info/METADATA,sha256=nS1JEF7rUJQSFhyUbfaQsGdook8yknRW74EkZqR0mi0,555
20
- photonlibpy-2025.0.0b1.dist-info/WHEEL,sha256=bFJAMchF8aTQGUgMZzHJyDDMPTO3ToJ7x23SLJa1SVo,92
21
- photonlibpy-2025.0.0b1.dist-info/top_level.txt,sha256=T8Xc6U6he2VjKUAca6zawSkHdUZuLanxYIc4nxw2ctc,12
22
- photonlibpy-2025.0.0b1.dist-info/RECORD,,