-
Notifications
You must be signed in to change notification settings - Fork 182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add photonlibpy #1040
Merged
Merged
Add photonlibpy #1040
Changes from 22 commits
Commits
Show all changes
32 commits
Select commit
Hold shift + click to select a range
ce84d07
First pass adding a pure-python implementation of photonlib
gerth2 03bde5c
wip github actions
gerth2 1a1ef91
more wip github
gerth2 514c526
one more...
gerth2 5adcac2
more bugfxes in github workflow
gerth2 177ac92
another one
gerth2 bc93c04
another one
gerth2 6b78555
versioning and dependency tweaks
gerth2 a27f48c
still working to fix issues
gerth2 935c434
minor tweak to trigger CI
gerth2 ddfdfbf
trying even more
gerth2 a1f1ffd
git on github action is poopy
gerth2 4be9004
my cat is fuzzy
gerth2 9364d21
review comments pt 1
gerth2 d63bb2f
better unit test passing
gerth2 e14e69d
missed python workflow update
gerth2 eba7c76
later python?
gerth2 3fb8b8e
wpiformat, better test infrastructure, derive tag name
gerth2 e262b79
whatever bro
gerth2 efa95e4
git describe is not
gerth2 d591c2c
are ya happy wpiformat. Just be happy.
gerth2 e38ecdf
un bork index html
gerth2 816bb5b
added version check
gerth2 083c9fe
wip better
gerth2 c582ea2
tweaked name and moved back to tags
gerth2 4b1af18
ran wpiformat
gerth2 e87c5d9
Baked more detail into the version without violating pep 440
gerth2 90f2a4c
i am asking you once again to run wpiformat
gerth2 9164862
maybe v4 is better
gerth2 fbfe9f8
Merge branch 'master' into master
mcm001 5436791
Merge branch 'master' into master
mcm001 3daf384
Merge branch 'master' into master
mcm001 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
name: Build and Distribute PhotonLibPy | ||
|
||
permissions: | ||
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing | ||
|
||
on: | ||
push: | ||
branches: [ master ] | ||
tags: | ||
- 'v*' | ||
pull_request: | ||
branches: [ master ] | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- name: Checkout code | ||
uses: actions/checkout@v3 | ||
with: | ||
sparse-checkout-cone-mode: false | ||
fetch-tags: true | ||
fetch-depth: 99999 | ||
|
||
- name: Set up Python | ||
uses: actions/setup-python@v5 | ||
with: | ||
python-version: 3.11 | ||
|
||
- name: Install dependencies | ||
run: | | ||
python -m pip install --upgrade pip | ||
pip install setuptools wheel pytest | ||
|
||
- name: Build wheel | ||
working-directory: ./photon-lib/py | ||
run: | | ||
python setup.py sdist bdist_wheel | ||
|
||
- name: Run Unit Tests | ||
working-directory: ./photon-lib/py | ||
run: | | ||
pip install --no-cache-dir dist/*.whl | ||
pytest | ||
|
||
|
||
- name: Upload artifacts | ||
uses: actions/upload-artifact@master | ||
with: | ||
name: dist | ||
path: ./photon-lib/py/dist/ | ||
|
||
pypi-publish: | ||
name: Upload release to PyPI | ||
runs-on: ubuntu-latest | ||
needs: | ||
- build | ||
environment: | ||
name: pypi | ||
url: https://pypi.org/p/photonlibpy | ||
permissions: | ||
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing | ||
steps: | ||
- name: Download all the dists | ||
uses: actions/download-artifact@v3 | ||
with: | ||
name: dist | ||
path: dist/ | ||
- name: Publish package distributions to TestPyPI | ||
# Only upload on tags | ||
if: startsWith(github.ref, 'refs/tags/v') | ||
uses: pypa/gh-action-pypi-publish@release/v1 | ||
with: | ||
repository-url: https://test.pypi.org/legacy/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
photonlibpy.egg-info/ | ||
dist/ | ||
build/ | ||
.eggs/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
:: Uninstall if it already was installed | ||
pip uninstall -y photonlibpy | ||
|
||
:: Build wheel | ||
python setup.py bdist_wheel | ||
|
||
:: Install whatever wheel was made | ||
for %%f in (dist/*.whl) do ( | ||
echo installing dist/%%f | ||
pip install --no-cache-dir dist/%%f | ||
) | ||
|
||
:: Run the test suite | ||
pytest |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# No one here but us chickens |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
from dataclasses import dataclass, field | ||
from wpimath.geometry import Transform3d | ||
from photonlibpy.packet import Packet | ||
|
||
|
||
@dataclass | ||
class PNPResult: | ||
_NUM_BYTES_IN_FLOAT = 8 | ||
PACK_SIZE_BYTES = 1 + (_NUM_BYTES_IN_FLOAT * 7 * 2) + (_NUM_BYTES_IN_FLOAT * 3) | ||
|
||
isPresent: bool = False | ||
best: Transform3d = field(default_factory=Transform3d) | ||
alt: Transform3d = field(default_factory=Transform3d) | ||
gerth2 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
ambiguity: float = 0.0 | ||
bestReprojError: float = 0.0 | ||
altReprojError: float = 0.0 | ||
|
||
def createFromPacket(self, packet: Packet) -> Packet: | ||
self.isPresent = packet.decodeBoolean() | ||
self.best = packet.decodeTransform() | ||
self.alt = packet.decodeTransform() | ||
self.bestReprojError = packet.decodeDouble() | ||
self.altReprojError = packet.decodeDouble() | ||
self.ambiguity = packet.decodeDouble() | ||
return packet | ||
|
||
|
||
@dataclass | ||
class MultiTargetPNPResult: | ||
_MAX_IDS = 32 | ||
# pnpresult + MAX_IDS possible targets (arbitrary upper limit that should never be hit, ideally) | ||
_PACK_SIZE_BYTES = PNPResult.PACK_SIZE_BYTES + (1 * _MAX_IDS) | ||
|
||
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
import struct | ||
from wpimath.geometry import Transform3d, Translation3d, Rotation3d, Quaternion | ||
import wpilib | ||
|
||
|
||
class Packet: | ||
def __init__(self, data: list[int]): | ||
""" | ||
* Constructs an empty packet. | ||
* | ||
* @param self.size The self.size of the packet buffer. | ||
""" | ||
self.packetData = data | ||
self.size = len(data) | ||
self.readPos = 0 | ||
self.outOfBytes = False | ||
|
||
def clear(self): | ||
"""Clears the packet and resets the read and write positions.""" | ||
self.packetData = [0] * self.size | ||
self.readPos = 0 | ||
self.outOfBytes = False | ||
|
||
def getSize(self): | ||
return self.size | ||
|
||
_NO_MORE_BYTES_MESSAGE = """ | ||
Photonlib - Ran out of bytes while decoding. | ||
Make sure the version of photonvision on the coprocessor | ||
matches the version of photonlib running in the robot code. | ||
""" | ||
|
||
def _getNextByte(self) -> int: | ||
retVal = 0x00 | ||
|
||
if not self.outOfBytes: | ||
try: | ||
retVal = 0x00FF & self.packetData[self.readPos] | ||
self.readPos += 1 | ||
except IndexError: | ||
wpilib.reportError(Packet._NO_MORE_BYTES_MESSAGE, True) | ||
self.outOfBytes = True | ||
|
||
return retVal | ||
|
||
def getData(self) -> list[int]: | ||
""" | ||
* Returns the packet data. | ||
* | ||
* @return The packet data. | ||
""" | ||
return self.packetData | ||
|
||
def setData(self, data: list[int]): | ||
""" | ||
* Sets the packet data. | ||
* | ||
* @param data The packet data. | ||
""" | ||
self.clear() | ||
self.packetData = data | ||
self.size = len(self.packetData) | ||
|
||
def _decodeGeneric(self, unpackFormat, numBytes): | ||
# Read ints in from the data buffer | ||
intList = [] | ||
for _ in range(numBytes): | ||
intList.append(self._getNextByte()) | ||
|
||
# Interpret the bytes as a floating point number | ||
value = struct.unpack(unpackFormat, bytes(intList))[0] | ||
|
||
return value | ||
|
||
def decode8(self) -> int: | ||
""" | ||
* Returns a single decoded byte from the packet. | ||
* | ||
* @return A decoded byte from the packet. | ||
""" | ||
return self._decodeGeneric(">b", 1) | ||
|
||
def decode16(self) -> int: | ||
""" | ||
* Returns a single decoded byte from the packet. | ||
* | ||
* @return A decoded byte from the packet. | ||
""" | ||
return self._decodeGeneric(">h", 2) | ||
|
||
def decode32(self) -> int: | ||
""" | ||
* Returns a decoded int (32 bytes) from the packet. | ||
* | ||
* @return A decoded int from the packet. | ||
""" | ||
return self._decodeGeneric(">l", 4) | ||
|
||
def decodeDouble(self) -> float: | ||
""" | ||
* Returns a decoded double from the packet. | ||
* | ||
* @return A decoded double from the packet. | ||
""" | ||
return self._decodeGeneric(">d", 8) | ||
|
||
def decodeBoolean(self) -> bool: | ||
""" | ||
* Returns a decoded boolean from the packet. | ||
* | ||
* @return A decoded boolean from the packet. | ||
""" | ||
return self.decode8() == 1 | ||
|
||
def decodeDoubleArray(self, length: int) -> list[float]: | ||
""" | ||
* Returns a decoded array of floats from the packet. | ||
* | ||
* @return A decoded array of floats from the packet. | ||
""" | ||
ret = [] | ||
for _ in range(length): | ||
ret.append(self.decodeDouble()) | ||
return ret | ||
|
||
def decodeTransform(self) -> Transform3d: | ||
""" | ||
* Returns a decoded Transform3d | ||
* | ||
* @return A decoded Tansform3d from the packet. | ||
""" | ||
x = self.decodeDouble() | ||
y = self.decodeDouble() | ||
z = self.decodeDouble() | ||
translation = Translation3d(x, y, z) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI we implemented getStructTopic, not currently released but it'll be available in the kickoff release. See https://github.com/robotpy/mostrobotpy/blob/main/subprojects/pyntcore/tests/test_struct_topic.py |
||
|
||
w = self.decodeDouble() | ||
x = self.decodeDouble() | ||
y = self.decodeDouble() | ||
z = self.decodeDouble() | ||
rotation = Rotation3d(Quaternion(w, x, y, z)) | ||
|
||
return Transform3d(translation, rotation) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd recommend using
pipx run build
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pipx is currently being very sad about installing for me.... thoughts on leaving this one for later?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, pipx's docs recommend scoop over pip for installing pipx.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd probably specifically recommend https://github.com/hynek/build-and-inspect-python-package in GitHub Actions though