Compare commits
168 Commits
v2025.3.1
...
v2026.0.0-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f6d8caf48 | ||
|
|
3cbac8117e | ||
|
|
8e88a9a780 | ||
|
|
7cb3b7a37b | ||
|
|
054ed8b6a1 | ||
|
|
d44480ddad | ||
|
|
c71921c41e | ||
|
|
ee4501f1d6 | ||
|
|
d9b86a718e | ||
|
|
1ac185c247 | ||
|
|
7170c29efe | ||
|
|
4f549ba579 | ||
|
|
b531fe6b81 | ||
|
|
373ed2ff05 | ||
|
|
115bc09f2e | ||
|
|
7497566f56 | ||
|
|
85f155c77b | ||
|
|
797936865f | ||
|
|
831df409f7 | ||
|
|
b89ab49d34 | ||
|
|
099c88e0b7 | ||
|
|
1ee2ecb608 | ||
|
|
82d6b6b845 | ||
|
|
8ec041493a | ||
|
|
da608a5070 | ||
|
|
17c23b0390 | ||
|
|
e486ff5a50 | ||
|
|
e84e3e7c7c | ||
|
|
a1d06a9920 | ||
|
|
04e9bffeb7 | ||
|
|
4b01b66ab7 | ||
|
|
ee56bf7597 | ||
|
|
058ca19262 | ||
|
|
b43d0dde20 | ||
|
|
3300b90823 | ||
|
|
f58416fe16 | ||
|
|
62eb66a493 | ||
|
|
fcbc392d83 | ||
|
|
7d927aca3b | ||
|
|
bd2c5062f9 | ||
|
|
354f4e945e | ||
|
|
2eb224a55f | ||
|
|
2ab7a2e389 | ||
|
|
27a1cfcb12 | ||
|
|
c7f5edc262 | ||
|
|
6fe96316a4 | ||
|
|
b32d9c6ee3 | ||
|
|
7766d99ca6 | ||
|
|
81a5a48ac4 | ||
|
|
29e183660f | ||
|
|
8676649ebc | ||
|
|
35dcc3ce5a | ||
|
|
9277960018 | ||
|
|
e23df8c9a4 | ||
|
|
22490b8c38 | ||
|
|
3ac509b40d | ||
|
|
0ea108e17f | ||
|
|
da715244cb | ||
|
|
ab854e91e5 | ||
|
|
a930852bee | ||
|
|
65c214ac2d | ||
|
|
bf8073ab26 | ||
|
|
2bf166bc3f | ||
|
|
2c98d10a92 | ||
|
|
923f9564dc | ||
|
|
ad64bfeaa9 | ||
|
|
ffd4d1f80e | ||
|
|
1310640e10 | ||
|
|
753123844b | ||
|
|
ba1c0db7e1 | ||
|
|
fce54d12c1 | ||
|
|
3e19cd45cc | ||
|
|
6b49e92d00 | ||
|
|
29e24bbac2 | ||
|
|
cefaa313df | ||
|
|
4b5bc6ae84 | ||
|
|
758fbb9110 | ||
|
|
02e6b6d3e2 | ||
|
|
af689b61d5 | ||
|
|
8215cafbae | ||
|
|
ed58f69275 | ||
|
|
a62d5e0eee | ||
|
|
2e97c95be1 | ||
|
|
6610b21b6e | ||
|
|
ef5e6463cb | ||
|
|
7f6edcd567 | ||
|
|
d7e536dda9 | ||
|
|
dbbb00f955 | ||
|
|
78f57600cc | ||
|
|
d341ebbadf | ||
|
|
d88ea4a75d | ||
|
|
46ac1baa69 | ||
|
|
f802e8c10c | ||
|
|
647c238987 | ||
|
|
4a648b302a | ||
|
|
cc7923eeb4 | ||
|
|
a9c26202a0 | ||
|
|
783d9d73be | ||
|
|
efc997dfbd | ||
|
|
3df58485c2 | ||
|
|
25851525ce | ||
|
|
4b740a5485 | ||
|
|
413cf8c4af | ||
|
|
d2193037f9 | ||
|
|
52125067ac | ||
|
|
db591f720c | ||
|
|
c81d4addb9 | ||
|
|
aa0760e97a | ||
|
|
74322affde | ||
|
|
bec8092660 | ||
|
|
29f76bc1c3 | ||
|
|
35c79b138c | ||
|
|
73cd2ab62c | ||
|
|
ae9f73130f | ||
|
|
c1b0c8a831 | ||
|
|
99b4dc8725 | ||
|
|
0c9502d8b9 | ||
|
|
c15c62698a | ||
|
|
7bbfe6f05b | ||
|
|
5349cae965 | ||
|
|
3ea9100845 | ||
|
|
ad1f51ba06 | ||
|
|
1b1f8029c8 | ||
|
|
1bb861545b | ||
|
|
a4295275ed | ||
|
|
0dfca8c04f | ||
|
|
3ed8d3a4f3 | ||
|
|
7f7d80bc3b | ||
|
|
89c0cc3a01 | ||
|
|
e514071094 | ||
|
|
38ee450117 | ||
|
|
23d5e5b34f | ||
|
|
75dee20d77 | ||
|
|
ed7fc6bbcc | ||
|
|
8a2c9f2ae0 | ||
|
|
c45c2a0a1f | ||
|
|
b86217a59a | ||
|
|
4ffd1fc600 | ||
|
|
a42aed1e7f | ||
|
|
20e2fe46ba | ||
|
|
1fb02a477d | ||
|
|
09f8d1c2a5 | ||
|
|
e754f5944e | ||
|
|
089233f4be | ||
|
|
b1f8598a03 | ||
|
|
b8d74522bd | ||
|
|
5ff025fdbf | ||
|
|
537cd7c564 | ||
|
|
1c42755451 | ||
|
|
63b1ff242c | ||
|
|
be490a7dea | ||
|
|
44893b14b0 | ||
|
|
d22abdfd76 | ||
|
|
cbdea5d0f1 | ||
|
|
9a88e565fb | ||
|
|
925defc868 | ||
|
|
843c1fed17 | ||
|
|
781126719a | ||
|
|
a93be9c816 | ||
|
|
1af3dab37a | ||
|
|
163dbe58e4 | ||
|
|
c26a7cc5ac | ||
|
|
6170958be9 | ||
|
|
ea9bd4ac93 | ||
|
|
aa15eedc7a | ||
|
|
1798b67dd3 | ||
|
|
f92cf62a54 | ||
|
|
3c332db4bf |
1
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -22,6 +22,7 @@ If applicable, add screenshots to help explain your problem. Additionally, provi
|
||||
|
||||
**Platform:**
|
||||
- Hardware Platform (ex. Raspberry Pi 4, Windows x64):
|
||||
- How is it powered? (ex. Zinc-V, Pololu Buck Converter, Battery Bank):
|
||||
- Network Configuration (Connection between the Radio and any devices in between, such as a Network Switch):
|
||||
- PhotonVision Version:
|
||||
- Browser (with Version) (Chrome, Edge, Firefox, etc.):
|
||||
|
||||
17
.github/ISSUE_TEMPLATE/docs_issue.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Documentation Request
|
||||
about: Something needs to be documented/updated in the documentation
|
||||
title: ''
|
||||
labels: documentation
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Are you requesting documentation for a new feature, or updated documentation for an old feature?**
|
||||
Put the feature you are requesting documentation for here, along with whether the documentation is stale and needs to be updated, or whether the documentation does not exist, and needs to be created.
|
||||
|
||||
**Where is it?**
|
||||
Put the location of the documentation that needs to be updated here. If you're requesting documenation for a new feature, put where you think it should go.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
15
.github/labeler.yml
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
"backend":
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: [photon-core/**, photon-server/**]
|
||||
"documentation":
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: [docs/**, photon-docs/**]
|
||||
"frontend":
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: photon-client/**
|
||||
"photonlib":
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: photon-lib*/**
|
||||
"website":
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: website/**
|
||||
3
.github/pull_request_template.md
vendored
@@ -13,5 +13,6 @@ Merge checklist:
|
||||
- [ ] The description documents the _what_ and _why_
|
||||
- [ ] If this PR changes behavior or adds a feature, user documentation is updated
|
||||
- [ ] If this PR touches photon-serde, all messages have been regenerated and hashes have not changed unexpectedly
|
||||
- [ ] If this PR touches configuration, this is backwards compatible with settings back to v2024.3.1
|
||||
- [ ] If this PR touches configuration, this is backwards compatible with settings back to v2025.3.2
|
||||
- [ ] If this PR touches pipeline settings or anything related to data exchange, the frontend typing is updated
|
||||
- [ ] If this PR addresses a bug, a regression test for it is added
|
||||
|
||||
222
.github/workflows/build.yml
vendored
@@ -3,38 +3,23 @@ name: Build
|
||||
on:
|
||||
# Run on pushes to main and pushed tags, and on pull requests against main, but ignore the docs folder
|
||||
push:
|
||||
branches: [ main ]
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
merge_group:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
IMAGE_VERSION: v2026.0.4
|
||||
|
||||
jobs:
|
||||
build-client:
|
||||
name: "PhotonClient Build"
|
||||
defaults:
|
||||
run:
|
||||
working-directory: photon-client
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
validation:
|
||||
name: "Validation"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Install Dependencies
|
||||
run: npm ci
|
||||
- name: Build Production Client
|
||||
run: npm run build
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: built-client
|
||||
path: photon-client/dist/
|
||||
- uses: gradle/actions/wrapper-validation@v4
|
||||
build-examples:
|
||||
|
||||
strategy:
|
||||
@@ -49,6 +34,7 @@ jobs:
|
||||
|
||||
name: "Photonlib - Build Examples - ${{ matrix.os }}"
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs: [validation]
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
@@ -76,6 +62,7 @@ jobs:
|
||||
build-gradle:
|
||||
name: "Gradle Build"
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [validation]
|
||||
steps:
|
||||
# Checkout code.
|
||||
- name: Checkout code
|
||||
@@ -89,22 +76,22 @@ jobs:
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: temurin
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
- name: Install mrcal deps
|
||||
run: sudo apt-get update && sudo apt-get install -y libcholmod3 liblapack3 libsuitesparseconfig5
|
||||
- name: Gradle Build
|
||||
run: ./gradlew photon-targeting:build photon-core:build photon-server:build -x check
|
||||
- name: Gradle Tests
|
||||
run: ./gradlew testHeadless -i --stacktrace
|
||||
run: ./gradlew testHeadless --stacktrace
|
||||
- name: Gradle Coverage
|
||||
run: ./gradlew jacocoTestReport
|
||||
- name: Publish Coverage Report
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
file: ./photon-server/build/reports/jacoco/test/jacocoTestReport.xml
|
||||
- name: Publish Core Coverage Report
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
file: ./photon-core/build/reports/jacoco/test/jacocoTestReport.xml
|
||||
build-offline-docs:
|
||||
name: "Build Offline Docs"
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -135,6 +122,7 @@ jobs:
|
||||
build-photonlib-vendorjson:
|
||||
name: "Build Vendor JSON"
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [validation]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -179,6 +167,7 @@ jobs:
|
||||
|
||||
name: "Photonlib - Build Host - ${{ matrix.artifact-name }}"
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs: [validation]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -190,7 +179,7 @@ jobs:
|
||||
distribution: temurin
|
||||
architecture: ${{ matrix.architecture }}
|
||||
- run: git fetch --tags --force
|
||||
- run: ./gradlew photon-targeting:build photon-lib:build -i
|
||||
- run: ./gradlew photon-targeting:build photon-lib:build
|
||||
name: Build with Gradle
|
||||
- run: ./gradlew photon-lib:publish photon-targeting:publish
|
||||
name: Publish
|
||||
@@ -222,6 +211,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
container: ${{ matrix.container }}
|
||||
name: "Photonlib - Build Docker - ${{ matrix.artifact-name }}"
|
||||
needs: [validation]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -231,7 +221,7 @@ jobs:
|
||||
git config --global --add safe.directory /__w/photonvision/photonvision
|
||||
- name: Build PhotonLib
|
||||
# We don't need to run tests, since we specify only non-native platforms
|
||||
run: ./gradlew photon-targeting:build photon-lib:build ${{ matrix.build-options }} -i -x test
|
||||
run: ./gradlew photon-targeting:build photon-lib:build ${{ matrix.build-options }} -x test
|
||||
- name: Publish
|
||||
run: ./gradlew photon-lib:publish photon-targeting:publish ${{ matrix.build-options }}
|
||||
env:
|
||||
@@ -270,7 +260,7 @@ jobs:
|
||||
path: output/*.zip
|
||||
|
||||
build-package:
|
||||
needs: [build-client, build-gradle, build-offline-docs]
|
||||
needs: [build-gradle, build-offline-docs]
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -310,21 +300,19 @@ jobs:
|
||||
java-version: 17
|
||||
distribution: temurin
|
||||
architecture: ${{ matrix.architecture }}
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
cache-dependency-path: photon-client/pnpm-lock.yaml
|
||||
- name: Install Arm64 Toolchain
|
||||
run: ./gradlew installArm64Toolchain
|
||||
if: ${{ (matrix.artifact-name) == 'LinuxArm64' }}
|
||||
- run: |
|
||||
rm -rf photon-server/src/main/resources/web/*
|
||||
mkdir -p photon-server/src/main/resources/web/docs
|
||||
if: ${{ (matrix.os) != 'windows-latest' }}
|
||||
- run: |
|
||||
del photon-server\src\main\resources\web\*.*
|
||||
mkdir photon-server\src\main\resources\web\docs
|
||||
if: ${{ (matrix.os) == 'windows-latest' }}
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: built-client
|
||||
path: photon-server/src/main/resources/web/
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: built-docs
|
||||
@@ -374,7 +362,7 @@ jobs:
|
||||
- run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --yes libcholmod3 liblapack3 libsuitesparseconfig5
|
||||
if: ${{ (matrix.os) == 'ubuntu-22.04' }}
|
||||
if: ${{ (matrix.os) == 'ubuntu-24.04' }}
|
||||
# and actually run the jar
|
||||
- run: java -jar ${{ matrix.extraOpts }} *.jar --smoketest
|
||||
if: ${{ (matrix.os) != 'windows-latest' }}
|
||||
@@ -388,10 +376,10 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-24.04
|
||||
artifact-name: LinuxArm64
|
||||
image_suffix: RaspberryPi
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/v2025.0.3/photonvision_raspi.img.xz
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_raspi.img.xz
|
||||
cpu: cortex-a7
|
||||
image_additional_mb: 0
|
||||
extraOpts: -Djdk.lang.Process.launchMechanism=vfork
|
||||
@@ -427,69 +415,81 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-24.04
|
||||
artifact-name: LinuxArm64
|
||||
image_suffix: RaspberryPi
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/v2025.0.3/photonvision_raspi.img.xz
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_raspi.img.xz
|
||||
cpu: cortex-a7
|
||||
image_additional_mb: 0
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-24.04
|
||||
artifact-name: LinuxArm64
|
||||
image_suffix: limelight2
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/v2025.0.3/photonvision_limelight.img.xz
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_limelight.img.xz
|
||||
cpu: cortex-a7
|
||||
image_additional_mb: 0
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-24.04
|
||||
artifact-name: LinuxArm64
|
||||
image_suffix: limelight3
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/v2025.0.3/photonvision_limelight3.img.xz
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_limelight3.img.xz
|
||||
cpu: cortex-a7
|
||||
image_additional_mb: 0
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-24.04
|
||||
artifact-name: LinuxArm64
|
||||
image_suffix: limelight3G
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/v2025.0.3/photonvision_limelight3g.img.xz
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_limelight3g.img.xz
|
||||
cpu: cortex-a7
|
||||
image_additional_mb: 0
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-24.04
|
||||
artifact-name: LinuxArm64
|
||||
image_suffix: limelight4
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_limelight4.img.xz
|
||||
cpu: cortex-a76
|
||||
image_additional_mb: 0
|
||||
- os: ubuntu-24.04
|
||||
artifact-name: LinuxArm64
|
||||
image_suffix: luma_p1
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_luma_p1.img.xz
|
||||
cpu: cortex-a76
|
||||
image_additional_mb: 0
|
||||
- os: ubuntu-24.04
|
||||
artifact-name: LinuxArm64
|
||||
image_suffix: orangepi5
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/v2025.0.3/photonvision_opi5.img.xz
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_opi5.img.xz
|
||||
cpu: cortex-a8
|
||||
image_additional_mb: 1024
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-24.04
|
||||
artifact-name: LinuxArm64
|
||||
image_suffix: orangepi5b
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/v2025.0.3/photonvision_opi5b.img.xz
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_opi5b.img.xz
|
||||
cpu: cortex-a8
|
||||
image_additional_mb: 1024
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-24.04
|
||||
artifact-name: LinuxArm64
|
||||
image_suffix: orangepi5plus
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/v2025.0.3/photonvision_opi5plus.img.xz
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_opi5plus.img.xz
|
||||
cpu: cortex-a8
|
||||
image_additional_mb: 1024
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-24.04
|
||||
artifact-name: LinuxArm64
|
||||
image_suffix: orangepi5pro
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/v2025.0.3/photonvision_opi5pro.img.xz
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_opi5pro.img.xz
|
||||
cpu: cortex-a8
|
||||
image_additional_mb: 1024
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-24.04
|
||||
artifact-name: LinuxArm64
|
||||
image_suffix: orangepi5max
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/v2025.0.3/photonvision_opi5max.img.xz
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_opi5max.img.xz
|
||||
cpu: cortex-a8
|
||||
image_additional_mb: 1024
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-24.04
|
||||
artifact-name: LinuxArm64
|
||||
image_suffix: rock5c
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/v2025.0.3/photonvision_rock5c.img.xz
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_rock5c.img.xz
|
||||
cpu: cortex-a8
|
||||
image_additional_mb: 1024
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
name: "Build image - ${{ matrix.image_url }}"
|
||||
name: "Build image - ${{ matrix.image_suffix }}"
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
@@ -523,8 +523,40 @@ jobs:
|
||||
with:
|
||||
name: image-${{ matrix.image_suffix }}
|
||||
path: photonvision*.xz
|
||||
build-rubik-image:
|
||||
needs: [build-package]
|
||||
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
|
||||
runs-on: ubuntu-24.04
|
||||
name: "Build image - Rubik Pi 3"
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: jar-LinuxArm64
|
||||
- name: Generate image
|
||||
run: |
|
||||
wget https://raw.githubusercontent.com/PhotonVision/photon-image-modifier/refs/tags/$IMAGE_VERSION/mount_rubikpi3.sh
|
||||
chmod +x mount_rubikpi3.sh
|
||||
./mount_rubikpi3.sh https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_rubikpi3.tar.xz /tmp/build/scripts/armrunner.sh
|
||||
- name: Compress image
|
||||
run: |
|
||||
new_jar=$(realpath $(find . -name photonvision\*-linuxarm64.jar))
|
||||
new_image_name=$(basename "${new_jar/.jar/_rubikpi3.img}")
|
||||
mv photonvision_rubikpi3 $new_image_name
|
||||
tar -I 'xz -T0' -cf ${new_image_name}.tar.xz $new_image_name --checkpoint=10000 --checkpoint-action=echo='%T'
|
||||
- uses: actions/upload-artifact@v4
|
||||
name: Upload image
|
||||
with:
|
||||
name: image-rubikpi3
|
||||
path: photonvision*.xz
|
||||
release:
|
||||
needs: [build-package, build-image, combine]
|
||||
needs: [build-photonlib-vendorjson, build-package, build-image, build-rubik-image, combine]
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
# Download all fat JARs
|
||||
@@ -550,49 +582,25 @@ jobs:
|
||||
|
||||
- run: find
|
||||
# Push to dev release
|
||||
- uses: pyTooling/Actions/releaser@r0
|
||||
- uses: pyTooling/Actions/releaser@r6
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
tag: 'Dev'
|
||||
rm: true
|
||||
snapshots: false
|
||||
files: |
|
||||
**/*.xz
|
||||
**/*.jar
|
||||
**/*linux*.jar
|
||||
**/*win*.jar
|
||||
**/photonlib*.json
|
||||
**/photonlib*.zip
|
||||
if: github.event_name == 'push'
|
||||
# Upload all jars and xz archives
|
||||
# Split into two uploads to work around max size limits in action-gh-releases
|
||||
# https://github.com/softprops/action-gh-release/issues/353
|
||||
- uses: softprops/action-gh-release@v2.0.9
|
||||
with:
|
||||
files: |
|
||||
**/@(*orangepi5*|*rock5*).xz
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: softprops/action-gh-release@v2.0.9
|
||||
with:
|
||||
files: |
|
||||
**/!(*orangepi5*|*rock5*).xz
|
||||
**/*.jar
|
||||
**/photonlib*.json
|
||||
**/photonlib*.zip
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
dispatch:
|
||||
name: dispatch
|
||||
needs: [build-photonlib-vendorjson, release]
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: peter-evans/repository-dispatch@v3
|
||||
if: |
|
||||
github.repository == 'PhotonVision/photonvision' &&
|
||||
startsWith(github.ref, 'refs/tags/v')
|
||||
- name: Create Vendor JSON Repo PR
|
||||
uses: wpilibsuite/vendor-json-repo/.github/actions/add_vendordep@main
|
||||
with:
|
||||
repo: PhotonVision/vendor-json-repo
|
||||
token: ${{ secrets.VENDOR_JSON_REPO_PUSH_TOKEN }}
|
||||
repository: PhotonVision/vendor-json-repo
|
||||
event-type: tag
|
||||
client-payload: '{"run_id": "${{ github.run_id }}", "package_version": "${{ github.ref_name }}"}'
|
||||
vendordep_file: ${{ github.workspace }}/photonlib-${{ github.ref_name }}.json
|
||||
pr_title: Update photonlib to ${{ github.ref_name }}
|
||||
pr_branch: photonlib-${{ github.ref_name }}
|
||||
if: github.repository == 'PhotonVision/photonvision' && startsWith(github.ref, 'refs/tags/v')
|
||||
|
||||
17
.github/workflows/cut-new-tag.yml
vendored
@@ -1,17 +0,0 @@
|
||||
name: Cut a new tag
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag_name:
|
||||
type: string
|
||||
description: The full name of the new tag to push to the latest commit to main
|
||||
|
||||
jobs:
|
||||
push_tag:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: git tag ${{ github.event.inputs.tag_name }}
|
||||
- run: git push origin ${{ github.event.inputs.tag_name }}
|
||||
14
.github/workflows/labeler.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
name: "Pull Request Labeler"
|
||||
on:
|
||||
- pull_request_target
|
||||
|
||||
jobs:
|
||||
labeler:
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/labeler@v5
|
||||
with:
|
||||
sync-labels: true
|
||||
40
.github/workflows/lint-format.yml
vendored
@@ -3,18 +3,19 @@ name: Lint and Format
|
||||
on:
|
||||
# Run on pushes to main and pushed tags, and on pull requests against main, but ignore the docs folder
|
||||
push:
|
||||
branches: [ main ]
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
merge_group:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
validation:
|
||||
name: "Validation"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: gradle/actions/wrapper-validation@v4
|
||||
wpiformat:
|
||||
name: "wpiformat"
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -30,7 +31,7 @@ jobs:
|
||||
with:
|
||||
python-version: 3.11
|
||||
- name: Install wpiformat
|
||||
run: pip3 install wpiformat==2024.45
|
||||
run: pip3 install wpiformat==2025.34
|
||||
- name: Run
|
||||
run: wpiformat
|
||||
- name: Check output
|
||||
@@ -45,6 +46,7 @@ jobs:
|
||||
if: ${{ failure() }}
|
||||
javaformat:
|
||||
name: "Java Formatting"
|
||||
needs: [validation]
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -65,25 +67,19 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
cache-dependency-path: photon-client/pnpm-lock.yaml
|
||||
- name: Install Dependencies
|
||||
run: npm ci
|
||||
run: pnpm i --frozen-lockfile
|
||||
- name: Check Linting
|
||||
run: npm run lint-ci
|
||||
run: pnpm run lint-ci
|
||||
- name: Check Formatting
|
||||
run: npm run format-ci
|
||||
server-index:
|
||||
name: "Check server index.html not changed"
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Fetch all history and metadata
|
||||
run: |
|
||||
git fetch --prune --unshallow
|
||||
git checkout -b pr
|
||||
git branch -f main origin/main
|
||||
- name: Check index.html not changed
|
||||
run: git --no-pager diff --exit-code origin/main photon-server/src/main/resources/web/index.html
|
||||
run: pnpm run format-ci
|
||||
|
||||
120
.github/workflows/photon-api-docs.yml
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
name: Photon API Documentation
|
||||
|
||||
on:
|
||||
# Run on pushes to main and pushed tags, and on pull requests against main, but ignore the docs folder
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
validation:
|
||||
name: "Validation"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: gradle/actions/wrapper-validation@v4
|
||||
build_demo:
|
||||
name: Build PhotonClient Demo
|
||||
defaults:
|
||||
run:
|
||||
working-directory: photon-client
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
cache-dependency-path: photon-client/pnpm-lock.yaml
|
||||
- name: Install Dependencies
|
||||
run: pnpm i --frozen-lockfile
|
||||
- name: Build Production Client
|
||||
run: pnpm run build-demo
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: built-demo
|
||||
path: photon-client/dist/
|
||||
|
||||
run_java_cpp_docs:
|
||||
name: Build Java and C++ API Docs
|
||||
needs: [validation]
|
||||
runs-on: "ubuntu-22.04"
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Fetch tags
|
||||
run: git fetch --tags --force
|
||||
- name: Install Java 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: temurin
|
||||
- name: Build javadocs/doxygen
|
||||
run: |
|
||||
chmod +x gradlew
|
||||
./gradlew photon-docs:generateJavaDocs photon-docs:doxygen
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: docs-java-cpp
|
||||
path: photon-docs/build/docs
|
||||
|
||||
publish_api_docs:
|
||||
name: Publish API Docs
|
||||
needs: [run_java_cpp_docs]
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
# Download docs artifact
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: docs-*
|
||||
- run: find .
|
||||
- name: Publish Docs To Development
|
||||
if: github.ref == 'refs/heads/main'
|
||||
uses: up9cloud/action-rsync@v1.4
|
||||
env:
|
||||
HOST: ${{ secrets.WEBMASTER_SSH_HOST }}
|
||||
USER: ${{ secrets.WEBMASTER_SSH_USERNAME }}
|
||||
KEY: ${{secrets.WEBMASTER_SSH_KEY}}
|
||||
TARGET: /var/www/html/photonvision-docs/development/
|
||||
- name: Publish Docs To Release
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
uses: up9cloud/action-rsync@v1.4
|
||||
env:
|
||||
HOST: ${{ secrets.WEBMASTER_SSH_HOST }}
|
||||
USER: ${{ secrets.WEBMASTER_SSH_USERNAME }}
|
||||
KEY: ${{ secrets.WEBMASTER_SSH_KEY }}
|
||||
TARGET: /var/www/html/photonvision-docs/release/
|
||||
|
||||
publish_demo:
|
||||
name: Publish PhotonClient Demo
|
||||
needs: [build_demo]
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: built-demo
|
||||
- run: find .
|
||||
- name: Publish demo
|
||||
if: github.ref == 'refs/heads/main'
|
||||
uses: up9cloud/action-rsync@v1.4
|
||||
env:
|
||||
HOST: ${{ secrets.WEBMASTER_SSH_HOST }}
|
||||
USER: ${{ secrets.WEBMASTER_SSH_USERNAME }}
|
||||
KEY: ${{ secrets.WEBMASTER_SSH_KEY }}
|
||||
TARGET: /var/www/html/photonvision-demo
|
||||
89
.github/workflows/photon-code-docs.yml
vendored
@@ -1,89 +0,0 @@
|
||||
name: Photon Code Documentation
|
||||
|
||||
on:
|
||||
# Run on pushes to main and pushed tags, and on pull requests against main, but ignore the docs folder
|
||||
push:
|
||||
branches: [ main ]
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
merge_group:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
build-client:
|
||||
name: "PhotonClient Build"
|
||||
defaults:
|
||||
run:
|
||||
working-directory: photon-client
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Install Dependencies
|
||||
run: npm ci
|
||||
- name: Build Production Client
|
||||
run: npm run build-demo
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: built-client
|
||||
path: photon-client/dist/
|
||||
|
||||
run_docs:
|
||||
runs-on: "ubuntu-22.04"
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Fetch tags
|
||||
run: git fetch --tags --force
|
||||
- name: Install Java 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: temurin
|
||||
|
||||
- name: Build javadocs/doxygen
|
||||
run: |
|
||||
chmod +x gradlew
|
||||
./gradlew photon-docs:generateJavaDocs photon-docs:doxygen
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: built-docs
|
||||
path: photon-docs/build/docs
|
||||
|
||||
release:
|
||||
needs: [build-client, run_docs]
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
|
||||
# Download literally every single artifact.
|
||||
- uses: actions/download-artifact@v4
|
||||
|
||||
- run: find .
|
||||
- name: copy file via ssh password
|
||||
if: github.ref == 'refs/heads/main'
|
||||
uses: appleboy/scp-action@v0.1.7
|
||||
with:
|
||||
host: ${{ secrets.WEBMASTER_SSH_HOST }}
|
||||
username: ${{ secrets.WEBMASTER_SSH_USERNAME }}
|
||||
password: ${{ secrets.WEBMASTER_SSH_KEY }}
|
||||
port: ${{ secrets.WEBMASTER_SSH_PORT }}
|
||||
source: "*"
|
||||
target: /var/www/html/photonvision-docs/
|
||||
@@ -1,11 +1,8 @@
|
||||
name: PhotonVision Sphinx Documentation Checks
|
||||
name: PhotonVision ReadTheDocs Checks
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
merge_group:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
|
||||
@@ -16,6 +13,7 @@ env:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build and Check Docs
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
20
.github/workflows/python.yml
vendored
@@ -5,12 +5,7 @@ permissions:
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
merge_group:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
|
||||
@@ -47,13 +42,14 @@ jobs:
|
||||
pip install --no-cache-dir dist/*.whl
|
||||
pytest
|
||||
|
||||
- name: Run mypy type checking
|
||||
uses: liskin/gh-problem-matcher-wrap@v3
|
||||
with:
|
||||
linters: mypy
|
||||
run: |
|
||||
mypy --show-column-numbers --config-file photon-lib/py/pyproject.toml photon-lib
|
||||
|
||||
# Disable due to robotpy issue. See
|
||||
# https://github.com/PhotonVision/photonvision/issues/1968
|
||||
# - name: Run mypy type checking
|
||||
# uses: liskin/gh-problem-matcher-wrap@v3
|
||||
# with:
|
||||
# linters: mypy
|
||||
# run: |
|
||||
# mypy --show-column-numbers --config-file photon-lib/py/pyproject.toml photon-lib
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
|
||||
58
.github/workflows/website.yml
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
name: Website
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
rsync:
|
||||
name: Build and Sync Files
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
cache-dependency-path: website/pnpm-lock.yaml
|
||||
- name: Install packages
|
||||
run: pnpm i --frozen-lockfile
|
||||
working-directory: website
|
||||
- name: Build project
|
||||
run: pnpm run build
|
||||
working-directory: website
|
||||
- uses: up9cloud/action-rsync@v1.4
|
||||
if: github.ref == 'refs/heads/main'
|
||||
env:
|
||||
HOST: ${{ secrets.WEBMASTER_SSH_HOST }}
|
||||
USER: ${{ secrets.WEBMASTER_SSH_USERNAME }}
|
||||
KEY: ${{secrets.WEBMASTER_SSH_KEY}}
|
||||
SOURCE: website/dist/*
|
||||
TARGET: /var/www/html/photonvision-website
|
||||
|
||||
format-check:
|
||||
name: Check Formatting
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
cache-dependency-path: website/pnpm-lock.yaml
|
||||
- name: Install Packages
|
||||
run: pnpm i --frozen-lockfile
|
||||
working-directory: website
|
||||
- name: Run Formatting Check
|
||||
run: pnpm prettier -c .
|
||||
working-directory: website
|
||||
25
.gitignore
vendored
@@ -1,19 +1,14 @@
|
||||
Python/__pycache__/WebSiteHandler\.cpython-37\.pyc
|
||||
|
||||
\.idea/
|
||||
|
||||
*.pyc
|
||||
|
||||
Python/app/__pycache__/
|
||||
|
||||
Python/app/handlers/__pycache__/
|
||||
|
||||
\.vscode/
|
||||
__pycache__/
|
||||
|
||||
/.vs
|
||||
|
||||
backend/settings/
|
||||
/.vscode/
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
# Docs
|
||||
_build
|
||||
# Compiled class file
|
||||
*.class
|
||||
|
||||
@@ -109,7 +104,6 @@ fabric.properties
|
||||
|
||||
# Temporary build files
|
||||
**/.gradle
|
||||
**/target
|
||||
**/src/main/java/META-INF
|
||||
**/.settings
|
||||
**/.classpath
|
||||
@@ -125,8 +119,6 @@ compile_commands.json
|
||||
.clangd/
|
||||
.cache/
|
||||
|
||||
New client/photon-client/*
|
||||
|
||||
*.prefs
|
||||
*.jfr
|
||||
.DS_Store
|
||||
@@ -146,8 +138,13 @@ photonlib-cpp-examples/*/vendordeps/*
|
||||
photonlib-cpp-examples/*/networktables.json.bck
|
||||
photonlib-java-examples/*/networktables.json.bck
|
||||
*.sqlite
|
||||
photon-server/src/main/resources/web/*
|
||||
venv
|
||||
.venv/*
|
||||
.venv
|
||||
networktables.json
|
||||
# Web stuff
|
||||
photon-server/src/main/resources/web/*
|
||||
node_modules
|
||||
dist
|
||||
components.d.ts
|
||||
photon-server/src/main/resources/web/index.html
|
||||
|
||||
1
.python-version
Normal file
@@ -0,0 +1 @@
|
||||
3.11
|
||||
@@ -19,6 +19,10 @@ modifiableFileExclude {
|
||||
\.webp$
|
||||
\.ico$
|
||||
\.rknn$
|
||||
\.tflite$
|
||||
\.mp4$
|
||||
\.ttf$
|
||||
\.woff2$
|
||||
gradlew
|
||||
photon-lib/py/photonlibpy/generated/
|
||||
photon-targeting/src/main/native/cpp/photon/constrained_solvepnp/generate/
|
||||
|
||||
5
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"python.testing.unittestEnabled": false,
|
||||
"python.testing.pytestEnabled": true,
|
||||
"python.testing.cwd": "photon-lib/py"
|
||||
}
|
||||
10
README.md
@@ -17,13 +17,13 @@ If you are interested in contributing code or documentation to the project, plea
|
||||
## Documentation
|
||||
|
||||
- Our main documentation page: [docs.photonvision.org](https://docs.photonvision.org)
|
||||
- Photon UI demo: [http://photonvision.global/](http://photonvision.global/) (or [manual link](https://photonvision.github.io/photonvision/built-client/))
|
||||
- Javadocs: [javadocs.photonvision.org](https://javadocs.photonvision.org) (or [manual link](https://photonvision.github.io/photonvision/built-docs/javadoc/))
|
||||
- C++ Doxygen [cppdocs.photonvision.org](https://cppdocs.photonvision.org) (or [manual link](https://photonvision.github.io/photonvision/built-docs/doxygen/html/))
|
||||
- Photon UI demo: [http://photonvision.global/](http://photonvision.global/)
|
||||
- Javadocs: [javadocs.photonvision.org](https://javadocs.photonvision.org)
|
||||
- C++ Doxygen [cppdocs.photonvision.org](https://cppdocs.photonvision.org)
|
||||
|
||||
## Building
|
||||
|
||||
Gradle is used for all C++ and Java code, and NPM is used for the web UI. Instructions to compile PhotonVision yourself can be found [in our docs](https://docs.photonvision.org/en/latest/docs/contributing/building-photon.html#compiling-instructions).
|
||||
Gradle is used for all C++ and Java code, and pnpm is used for the web UI. Instructions to compile PhotonVision yourself can be found [in our docs](https://docs.photonvision.org/en/latest/docs/contributing/building-photon.html#compiling-instructions).
|
||||
|
||||
You can run one of the many built in examples straight from the command line, too! They contain a fully featured robot project, and some include simulation support. The projects can be found inside the [`photonlib-java-examples`](photonlib-java-examples) and [`photonlib-cpp-examples`](photonlib-cpp-examples) subdirectories, respectively. Instructions for running these examples directly from the repo are found [in the docs](https://docs.photonvision.org/en/latest/docs/contributing/building-photon.html#running-examples).
|
||||
|
||||
@@ -41,6 +41,8 @@ Note that these are case sensitive!
|
||||
* linuxarm64
|
||||
* linuxathena
|
||||
- `-PtgtIP`: Specifies where `./gradlew deploy` should try to copy the fat JAR to
|
||||
- `-PtgtUser`: Specifies custom username for `./gradlew deploy` to SSH into
|
||||
- `-PtgtPw`: Specifies custom password for `./gradlew deploy` to SSH into
|
||||
- `-Pprofile`: enables JVM profiling
|
||||
- `-PwithSanitizers`: On Linux, enables `-fsanitize=address,undefined,leak`
|
||||
|
||||
|
||||
13
build.gradle
@@ -8,10 +8,9 @@ plugins {
|
||||
id 'edu.wpi.first.WpilibTools' version '1.3.0'
|
||||
id 'com.google.protobuf' version '0.9.3' apply false
|
||||
id 'edu.wpi.first.GradleJni' version '1.1.0'
|
||||
id "org.ysb33r.doxygen" version "1.0.4" apply false
|
||||
id "org.ysb33r.doxygen" version "2.0.0" apply false
|
||||
id 'com.gradleup.shadow' version '8.3.4' apply false
|
||||
id "com.github.node-gradle.node" version "7.0.1" apply false
|
||||
id "org.hidetake.ssh" version "2.11.2" apply false
|
||||
}
|
||||
|
||||
allprojects {
|
||||
@@ -37,10 +36,10 @@ ext {
|
||||
wpimathVersion = wpilibVersion
|
||||
openCVYear = "2025"
|
||||
openCVversion = "4.10.0-3"
|
||||
joglVersion = "2.4.0"
|
||||
javalinVersion = "5.6.2"
|
||||
libcameraDriverVersion = "v2025.0.3"
|
||||
rknnVersion = "dev-v2025.0.0-1-g33b6263"
|
||||
javalinVersion = "6.7.0"
|
||||
libcameraDriverVersion = "v2025.0.4"
|
||||
rknnVersion = "dev-v2025.0.0-5-g666c0c6"
|
||||
rubikVersion = "dev-v2025.1.0-8-g067a316"
|
||||
frcYear = "2025"
|
||||
mrcalVersion = "v2025.0.0";
|
||||
|
||||
@@ -102,7 +101,7 @@ spotless {
|
||||
}
|
||||
|
||||
wrapper {
|
||||
gradleVersion '8.11'
|
||||
gradleVersion = '8.14.3'
|
||||
}
|
||||
|
||||
ext.getCurrentArch = {
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import argparse
|
||||
import base64
|
||||
import json
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
|
||||
import cv2
|
||||
import mrcal
|
||||
import numpy as np
|
||||
from wpimath.geometry import Quaternion as _Quat
|
||||
@@ -12,8 +10,8 @@ from wpimath.geometry import Quaternion as _Quat
|
||||
|
||||
@dataclass
|
||||
class Size:
|
||||
width: int
|
||||
height: int
|
||||
width: float
|
||||
height: float
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -24,14 +22,6 @@ class JsonMatOfDoubles:
|
||||
data: list[float]
|
||||
|
||||
|
||||
@dataclass
|
||||
class JsonMat:
|
||||
rows: int
|
||||
cols: int
|
||||
type: int
|
||||
data: str # Base64-encoded PNG data
|
||||
|
||||
|
||||
@dataclass
|
||||
class Point2:
|
||||
x: float
|
||||
@@ -84,8 +74,7 @@ class Observation:
|
||||
# If we should use this observation when re-calculating camera calibration
|
||||
includeObservationInCalibration: bool
|
||||
snapshotName: str
|
||||
# The actual image the snapshot is from
|
||||
snapshotData: JsonMat
|
||||
snapshotDataLocation: str
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -97,6 +86,7 @@ class CameraCalibration:
|
||||
calobjectWarp: list[float]
|
||||
calobjectSize: Size
|
||||
calobjectSpacing: float
|
||||
lensmodel: str
|
||||
|
||||
|
||||
def __convert_cal_to_mrcal_cameramodel(
|
||||
@@ -127,6 +117,13 @@ def __convert_cal_to_mrcal_cameramodel(
|
||||
]
|
||||
return np.concatenate((r, t))
|
||||
|
||||
imagersize = (int(cal.resolution.width), int(cal.resolution.height))
|
||||
|
||||
def fill_missing_corners(observations: list[list[float]], width: int, height: int):
|
||||
num_corners = width * height
|
||||
observations += [[0, 0, -1] for x in range(num_corners - len(observations))]
|
||||
return observations
|
||||
|
||||
imagersize = (cal.resolution.width, cal.resolution.height)
|
||||
|
||||
# Always weight=1 for Photon data
|
||||
@@ -135,8 +132,12 @@ def __convert_cal_to_mrcal_cameramodel(
|
||||
[
|
||||
# note that we expect row-major observations here. I think this holds
|
||||
np.array(
|
||||
list(map(lambda it: [it.x, it.y, WEIGHT], o.locationInImageSpace))
|
||||
).reshape((cal.calobjectSize.width, cal.calobjectSize.height, 3))
|
||||
fill_missing_corners(
|
||||
list(map(lambda it: [it.x, it.y, WEIGHT], o.locationInImageSpace)),
|
||||
int(cal.calobjectSize.width),
|
||||
int(cal.calobjectSize.height),
|
||||
)
|
||||
).reshape((int(cal.calobjectSize.width), int(cal.calobjectSize.height), 3))
|
||||
for o in cal.observations
|
||||
]
|
||||
)
|
||||
@@ -206,14 +207,6 @@ def convert_photon_to_mrcal(photon_cal_json_path: str, output_folder: str):
|
||||
if not os.path.exists(output_folder):
|
||||
os.makedirs(output_folder)
|
||||
|
||||
# Decode each image and save it as a png
|
||||
for obs in camera_cal_data.observations:
|
||||
image = obs.snapshotData.data
|
||||
decoded_data = base64.b64decode(image)
|
||||
np_data = np.frombuffer(decoded_data, np.uint8)
|
||||
img = cv2.imdecode(np_data, cv2.IMREAD_UNCHANGED)
|
||||
cv2.imwrite(f"{output_folder}/{obs.snapshotName}", img)
|
||||
|
||||
# And create a VNL file for use with mrcal
|
||||
with open(f"{output_folder}/corners.vnl", "w+") as vnl_file:
|
||||
vnl_file.write("# filename x y level\n")
|
||||
|
||||
9
docs/.gitignore
vendored
@@ -1,9 +0,0 @@
|
||||
build/*
|
||||
.DS_Store
|
||||
.vscode/*
|
||||
.idea/*
|
||||
source/_build
|
||||
source/docs/_build
|
||||
|
||||
venv/*
|
||||
.venv/*
|
||||
@@ -11,6 +11,7 @@ modifiableFileExclude {
|
||||
\.webp$
|
||||
\.ico$
|
||||
\.rknn$
|
||||
\.tflite$
|
||||
\.svg$
|
||||
\.woff2$
|
||||
gradlew
|
||||
|
||||
@@ -1,44 +1,59 @@
|
||||
alabaster==0.7.13
|
||||
Babel==2.13.1
|
||||
beautifulsoup4==4.12.2
|
||||
certifi==2023.11.17
|
||||
charset-normalizer==3.3.2
|
||||
alabaster==0.7.16
|
||||
anyio==4.9.0
|
||||
babel==2.17.0
|
||||
beautifulsoup4==4.13.4
|
||||
certifi==2025.4.26
|
||||
charset-normalizer==3.4.2
|
||||
click==8.1.8
|
||||
colorama==0.4.6
|
||||
doc8==0.11.2
|
||||
doc8==1.1.2
|
||||
docopt==0.6.2
|
||||
docutils==0.18.1
|
||||
furo==2023.9.10
|
||||
idna==3.4
|
||||
docutils==0.20.1
|
||||
furo==2024.8.6
|
||||
h11==0.16.0
|
||||
idna==3.10
|
||||
imagesize==1.4.1
|
||||
Jinja2==3.0.3
|
||||
MarkupSafe==2.1.3
|
||||
packaging==23.2
|
||||
pbr==6.0.0
|
||||
pipreqs==0.4.13
|
||||
Pygments==2.17.1
|
||||
requests==2.31.0
|
||||
Jinja2==3.1.6
|
||||
markdown-it-py==3.0.0
|
||||
MarkupSafe==3.0.2
|
||||
mdit-py-plugins==0.4.2
|
||||
mdurl==0.1.2
|
||||
myst-parser==4.0.1
|
||||
packaging==25.0
|
||||
pbr==6.1.1
|
||||
pipreqs==0.5.0
|
||||
Pygments==2.19.1
|
||||
PyYAML==6.0.2
|
||||
requests==2.32.4
|
||||
restructuredtext-lint==1.4.0
|
||||
six==1.16.0
|
||||
snowballstemmer==2.2.0
|
||||
soupsieve==2.5
|
||||
Sphinx==7.2.6
|
||||
roman-numerals-py==3.1.0
|
||||
setuptools==80.3.1
|
||||
six==1.17.0
|
||||
sniffio==1.3.1
|
||||
snowballstemmer==3.0.0.1
|
||||
soupsieve==2.7
|
||||
Sphinx==8.1.3
|
||||
sphinx-autobuild==2024.10.3
|
||||
sphinx-basic-ng==1.0.0b2
|
||||
sphinx-notfound-page==1.0.0
|
||||
sphinx-rtd-theme==1.3.0
|
||||
sphinx-tabs==3.4.4
|
||||
sphinx_design==0.5.0
|
||||
sphinxcontrib-applehelp==1.0.7
|
||||
sphinxcontrib-devhelp==1.0.5
|
||||
sphinx-notfound-page==1.1.0
|
||||
sphinx-rtd-theme==3.0.2
|
||||
sphinx-tabs==3.4.7
|
||||
sphinx_design==0.6.1
|
||||
sphinxcontrib-applehelp==2.0.0
|
||||
sphinxcontrib-devhelp==2.0.0
|
||||
sphinxcontrib-ghcontributors==0.2.3
|
||||
sphinxcontrib-htmlhelp==2.0.4
|
||||
sphinxcontrib-htmlhelp==2.1.0
|
||||
sphinxcontrib-jquery==4.1
|
||||
sphinxcontrib-jsmath==1.0.1
|
||||
sphinxcontrib-qthelp==1.0.6
|
||||
sphinxcontrib-serializinghtml==1.1.9
|
||||
sphinxext-opengraph==0.9.0
|
||||
sphinxext-remoteliteralinclude==0.4.0
|
||||
stevedore==5.1.0
|
||||
urllib3==2.1.0
|
||||
sphinxcontrib-qthelp==2.0.0
|
||||
sphinxcontrib-serializinghtml==2.0.0
|
||||
sphinxext-opengraph==0.10.0
|
||||
sphinxext-remoteliteralinclude==0.5.0
|
||||
starlette==0.47.2
|
||||
stevedore==5.4.1
|
||||
typing_extensions==4.13.2
|
||||
urllib3==2.5.0
|
||||
uvicorn==0.34.2
|
||||
watchfiles==1.0.5
|
||||
websockets==15.0.1
|
||||
yarg==0.1.9
|
||||
sphinx-autobuild==2024.4.16
|
||||
myst_parser==3.0.1
|
||||
|
||||
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 12 KiB |
@@ -1,74 +0,0 @@
|
||||
{# Import the theme's layout. #}
|
||||
{% extends '!layout.html' %}
|
||||
|
||||
{%- block extrahead %}
|
||||
<script>
|
||||
if (localStorage.getItem("colorTheme") === "dark") {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
} else if (localStorage.getItem("colorTheme") === "light") {
|
||||
document.documentElement.setAttribute('data-theme', 'light');
|
||||
} else {
|
||||
var userPrefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
if (userPrefersDark) {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
} else {
|
||||
document.documentElement.setAttribute('data-theme', 'light');
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
{# Call the parent block #}
|
||||
{{ super() }}
|
||||
{% endblock %}
|
||||
|
||||
{%- block extrafooter %}
|
||||
{# Add custom things to the head HTML tag #}
|
||||
|
||||
<div class="dark-mode-toggle-container">
|
||||
<strong class="light-label md-icon"></strong>
|
||||
|
||||
<div class="dark-mode-toggle">
|
||||
<input type="checkbox" id="switch" name="theme"/><label class="toggle" for="switch">Toggle</label>
|
||||
</div>
|
||||
|
||||
<strong class="dark-label md-icon"></strong>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var checkbox = document.querySelector('input[name=theme]');
|
||||
|
||||
var element = document.documentElement.getAttribute('data-theme');
|
||||
|
||||
if (element == 'dark') {
|
||||
// Auto check the checkbox if the set theme is "dark".
|
||||
checkbox.checked = true;
|
||||
}
|
||||
|
||||
checkbox.addEventListener('change', function() {
|
||||
if (this.checked) {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
localStorage.setItem("colorTheme", "dark");
|
||||
} else {
|
||||
document.documentElement.setAttribute('data-theme', 'light');
|
||||
localStorage.setItem("colorTheme", "light");
|
||||
}
|
||||
});
|
||||
|
||||
window.matchMedia('(prefers-color-scheme: dark)')
|
||||
.addEventListener('change', event => {
|
||||
if (event.matches) {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
localStorage.setItem("colorTheme", "dark");
|
||||
checkbox.checked = true;
|
||||
} else {
|
||||
document.documentElement.setAttribute('data-theme', 'light');
|
||||
localStorage.setItem("colorTheme", "light");
|
||||
checkbox.checked = false;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{# Call the parent block #}
|
||||
{{ super() }}
|
||||
{%- endblock %}
|
||||
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 12 KiB |
@@ -21,6 +21,29 @@ project = "PhotonVision"
|
||||
copyright = "2024, PhotonVision"
|
||||
author = "Banks Troutman, Matt Morley"
|
||||
|
||||
# -- Git configuration -----------------------------------------------------
|
||||
import subprocess
|
||||
|
||||
try:
|
||||
# Use closest tag
|
||||
git_tag_ref = (
|
||||
subprocess.check_output(
|
||||
[
|
||||
"git",
|
||||
"describe",
|
||||
"--tags",
|
||||
],
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
.strip()
|
||||
.decode()
|
||||
)
|
||||
except subprocess.CalledProcessError:
|
||||
# Couldn't find closest tag, fallback to main
|
||||
git_tag_ref = "main"
|
||||
|
||||
myst_substitutions = {"git_tag_ref": git_tag_ref}
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
@@ -30,7 +53,6 @@ extensions = [
|
||||
"sphinx_rtd_theme",
|
||||
"sphinx.ext.autosectionlabel",
|
||||
"sphinx.ext.todo",
|
||||
"sphinx_tabs.tabs",
|
||||
"notfound.extension",
|
||||
"sphinxext.remoteliteralinclude",
|
||||
"sphinxext.opengraph",
|
||||
@@ -47,9 +69,6 @@ ogp_site_url = "https://docs.photonvision.org/en/latest/"
|
||||
ogp_site_name = "PhotonVision Documentation"
|
||||
ogp_image = "https://raw.githubusercontent.com/PhotonVision/photonvision-docs/main/source/assets/RectLogo.png"
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ["_templates"]
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
@@ -70,6 +89,10 @@ html_title = "PhotonVision Docs"
|
||||
html_theme = "furo"
|
||||
html_favicon = "assets/RoundLogo.png"
|
||||
|
||||
# Specify canonical root
|
||||
# This tells search engines that this domain is preferred
|
||||
html_baseurl = "https://docs.photonvision.org/en/latest/"
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
@@ -87,6 +110,9 @@ pygments_style = "sphinx"
|
||||
|
||||
html_theme_options = {
|
||||
"sidebar_hide_name": True,
|
||||
"top_of_page_buttons": ["view", "edit"],
|
||||
"source_edit_link": "https://github.com/PhotonVision/photonvision/edit/main/docs/source/{filename}",
|
||||
"source_view_link": "https://github.com/PhotonVision/photonvision/blob/main/docs/source/{filename}",
|
||||
"light_logo": "assets/PhotonVision-Header-onWhite.png",
|
||||
"dark_logo": "assets/PhotonVision-Header-noBG.png",
|
||||
"light_css_variables": {
|
||||
@@ -144,11 +170,15 @@ sphinx_tabs_valid_builders = ["epub", "linkcheck"]
|
||||
|
||||
# Excluded links for linkcheck
|
||||
# These should be periodically checked by hand to ensure that they are still functional
|
||||
linkcheck_ignore = [R"https://www.raspberrypi.com/software/", R"http://10\..+"]
|
||||
linkcheck_ignore = [
|
||||
R"https://www.raspberrypi.com/software/",
|
||||
R"http://10\..+",
|
||||
R"https://www.gnu.org/",
|
||||
]
|
||||
|
||||
token = os.environ.get("GITHUB_TOKEN", None)
|
||||
if token:
|
||||
linkcheck_auth = [(R"https://github.com/.+", token)]
|
||||
|
||||
# MyST configuration (https://myst-parser.readthedocs.io/en/latest/configuration.html)
|
||||
myst_enable_extensions = ["colon_fence"]
|
||||
myst_enable_extensions = ["colon_fence", "substitution"]
|
||||
|
||||
@@ -7,10 +7,14 @@
|
||||
- Some time before the competition, lock down the version you are using and do not upgrade unless you encounter a critical bug.
|
||||
- Have a copy of the installation image for the version you are using on your programming laptop, in case re-imaging (without internet) is needed.
|
||||
- Extensively test at your home setup. Practice tuning from scratch under different lighting conditions.
|
||||
- Use SmartDashboard / Shuffleboard to view your camera streams during practice.
|
||||
- Confirm you have followed all the recommendations under the Networking section in installation (network switch and static IP).
|
||||
- Confirm you have followed all the recommendations under the {ref}`Networking<docs/quick-start/networking:Networking>` documentation (network switch and static IP).
|
||||
- Only use high quality ethernet cables that have been rigorously tested.
|
||||
- Set up RIO USB port forwarding using the guide in the Networking section in installation.
|
||||
|
||||
## Camera Streaming
|
||||
- All camera streams are published under the NetworkTables table `CameraPublisher`.
|
||||
- The only subtable under `CameraPublisher` that will work for viewing a driver mode camera stream is the one that contains `Output` in the name.
|
||||
- To view a camera stream in a dashboard, drag the correct subtable from the NetworkTables tree into your dashboard.
|
||||
- Use the latest driver dashboard recommended by [WPILib](https://docs.wpilib.org/en/stable/docs/software/dashboards/dashboard-intro.html) on your driver station laptop.
|
||||
|
||||
## During the Competition
|
||||
|
||||
@@ -19,7 +23,7 @@
|
||||
- Make sure the field has match-accurate lighting conditions active.
|
||||
- Turn on your robot and pull up the dashboard on your driver station.
|
||||
- Point your robot at the targets and ensure you get a consistent tracking (you hold one targets consistently, the ceiling lights aren't detected, etc.).
|
||||
- If you have problems with your pipeline, go to the pipeline tuning section and retune the pipeline using the guide there.
|
||||
- If you have problems with your pipeline, retune the pipeline following the {ref}`camera tuning <docs/pipelines/input:Camera Tuning / Input>` documentation.
|
||||
- Move the robot close, far, angled, and around the field to ensure no extra targets are found.
|
||||
- Monitor camera feeds during a practice match to ensure everything is working correctly.
|
||||
- After field calibration, use the "Export Settings" button in the "Settings" page to create a backup.
|
||||
|
||||
|
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 139 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 427 KiB After Width: | Height: | Size: 304 KiB |
|
Before Width: | Height: | Size: 451 KiB After Width: | Height: | Size: 324 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 5.4 KiB |
@@ -23,30 +23,41 @@ Ensure that your camera is calibrated and 3D mode is enabled. Navigate to the Ou
|
||||
By default, enabling multi-target will disable calculating camera-to-target transforms for each observed AprilTag target to increase performance; the X/Y/angle numbers shown in the target table of the UI are instead calculated using the tag's expected location (per the field layout JSON) and the field-to-camera transform calculated using MultiTag. If you additionally want the individual camera-to-target transform calculated using SolvePNP for each target, enable "Always Do Single-Target Estimation".
|
||||
:::
|
||||
|
||||
This multi-target pose estimate can be accessed using PhotonLib. We suggest using {ref}`the PhotonPoseEstimator class <docs/programming/photonlib/robot-pose-estimator:AprilTags and PhotonPoseEstimator>` with the `MULTI_TAG_PNP_ON_COPROCESSOR` strategy to simplify code, but the transform can be directly accessed using `getMultiTagResult`/`MultiTagResult()` (Java/C++).
|
||||
This multi-target pose estimate can be accessed using PhotonLib. We suggest using {ref}`the PhotonPoseEstimator class <docs/programming/photonlib/robot-pose-estimator:AprilTags and PhotonPoseEstimator>` with the `MULTI_TAG_PNP_ON_COPROCESSOR` strategy to simplify code, but the transform can be directly accessed using `getMultiTagResult`/`MultiTagResult()`/`multitagResult` (Java/C++/Python).
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
|
||||
.. code-block:: Java
|
||||
.. code-block:: java
|
||||
|
||||
var result = camera.getLatestResult();
|
||||
if (result.getMultiTagResult().estimatedPose.isPresent) {
|
||||
Transform3d fieldToCamera = result.getMultiTagResult().estimatedPose.best;
|
||||
var results = camera.getAllUnreadResults();
|
||||
for (var result : results) {
|
||||
var multiTagResult = result.getMultiTagResult();
|
||||
if (multiTagResult.isPresent()) {
|
||||
var fieldToCamera = multiTagResult.get().estimatedPose.best;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.. code-block:: C++
|
||||
.. code-block:: c++
|
||||
|
||||
auto result = camera.GetLatestResult();
|
||||
if (result.MultiTagResult().result.isPresent) {
|
||||
frc::Transform3d fieldToCamera = result.MultiTagResult().result.best;
|
||||
auto results = camera.GetAllUnreadResults();
|
||||
for (auto &result : results)
|
||||
{
|
||||
auto multiTagResult = result.MultiTagResult();
|
||||
if (multiTagResult.has_value()) {
|
||||
frc::Transform3d fieldToCamera = multiTagResult->estimatedPose.best;
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: Python
|
||||
|
||||
# Coming Soon!
|
||||
.. code-block:: python
|
||||
|
||||
results = camera.getAllUnreadResults()
|
||||
for result in results:
|
||||
multitagResult = result.multitagResult
|
||||
if multitagResult is not None:
|
||||
fieldToCamera = multitagResult.estimatedPose.best
|
||||
```
|
||||
|
||||
:::{note}
|
||||
|
||||
|
Before Width: | Height: | Size: 143 KiB |
8
docs/source/docs/benchmarks/index.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# Performance Benchmarks
|
||||
|
||||
```{toctree}
|
||||
:maxdepth: 0
|
||||
:titlesonly: true
|
||||
|
||||
rknn-model-benchmarks
|
||||
```
|
||||
125
docs/source/docs/benchmarks/rknn-model-benchmarks.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# RKNN Benchmarks
|
||||
|
||||
## Description
|
||||
This benchmark compares the performance of four object detection models: YOLOv5, YOLOv5u, YOLOv8, and YOLOv11 on the [COCO 2017 Validation Set](http://images.cocodataset.org/zips/val2017.zip). The main purpose is to assess and compare the inference speed and detection accuracy of these models when deployed on the Orange Pi devices using the RKNN framework and int8 quantization.
|
||||
|
||||
## Methodology
|
||||
- **Dataset**: [COCO 2017 Validation Set](http://images.cocodataset.org/zips/val2017.zip) (5,000 images)
|
||||
|
||||
- **Platform**: Orange Pi 5 with RK3588
|
||||
|
||||
- **Quantization**: int8 using 20 randomly selected images from the validation set
|
||||
|
||||
- **Framework**: RKNN Toolkit 2
|
||||
|
||||
## Operator-Level Benchmark Results
|
||||
|
||||
The following tables break down the average CPU time, NPU time, and total execution time (in microseconds) for each operator used by the models. Each value represents the mean ± standard deviation across 5,000 inferences.
|
||||
|
||||
### YOLOv5
|
||||
|
||||
| OpType | CPU Time (μs) | NPU Time (μs) | Total Time (μs) | Time Ratio (%) | Number of Times Called |
|
||||
|-----------------|---------------------|----------------------|-----------------------|---------------------|-----------------------|
|
||||
| ConvExSwish | 0.00 ± 0.00 | 10968.81 ± 1126.00 | 10968.81 ± 1126.00 | 73.06 ± 0.94 | 57 |
|
||||
| ConvSigmoid | 0.00 ± 0.00 | 1243.49 ± 67.66 | 1243.49 ± 67.66 | 8.33 ± 0.57 | 3 |
|
||||
| Concat | 0.00 ± 0.00 | 1080.68 ± 259.40 | 1080.68 ± 259.40 | 7.09 ± 0.87 | 13 |
|
||||
| Conv | 0.00 ± 0.00 | 732.15 ± 29.42 | 732.15 ± 29.42 | 4.92 ± 0.42 | 1 |
|
||||
| Add | 0.00 ± 0.00 | 473.71 ± 131.48 | 473.71 ± 131.48 | 3.10 ± 0.50 | 7 |
|
||||
| MaxPool | 0.00 ± 0.00 | 272.40 ± 110.52 | 272.40 ± 110.52 | 1.76 ± 0.51 | 6 |
|
||||
| Resize | 0.00 ± 0.00 | 147.61 ± 38.89 | 147.61 ± 38.89 | 0.97 ± 0.15 | 2 |
|
||||
| OutputOperator | 106.60 ± 15.00 | 0.00 ± 0.00 | 106.60 ± 15.00 | 0.72 ± 0.13 | 3 |
|
||||
| InputOperator | 8.64 ± 1.79 | 0.00 ± 0.00 | 8.64 ± 1.79 | 0.06 ± 0.02 | 1 |
|
||||
| **Total** | **115.24 ± 16.16** | **14918.85 ± 1735.45**| **15034.09 ± 1734.28**| | **93** |
|
||||
|
||||
### YOLOv5u
|
||||
|
||||
| OpType | CPU Time (μs) | NPU Time (μs) | Total Time (μs) | Time Ratio (%) | Number of Times Called |
|
||||
|-----------------|---------------------|----------------------|-----------------------|---------------------|-----------------------|
|
||||
| ConvExSwish | 0.00 ± 0.00 | 16828.24 ± 1332.73 | 16828.24 ± 1332.73 | 83.04 ± 1.61 | 69 |
|
||||
| Concat | 0.00 ± 0.00 | 1265.94 ± 250.24 | 1265.94 ± 250.24 | 6.17 ± 0.69 | 13 |
|
||||
| ConvSigmoid | 0.00 ± 0.00 | 613.88 ± 62.97 | 613.88 ± 62.97 | 3.03 ± 0.15 | 3 |
|
||||
| Add | 0.00 ± 0.00 | 553.75 ± 131.17 | 553.75 ± 131.17 | 2.69 ± 0.44 | 7 |
|
||||
| Conv | 0.00 ± 0.00 | 298.61 ± 72.72 | 298.61 ± 72.72 | 1.45 ± 0.25 | 3 |
|
||||
| ConvClip | 0.00 ± 0.00 | 256.02 ± 64.48 | 256.02 ± 64.48 | 1.24 ± 0.23 | 3 |
|
||||
| MaxPool | 0.00 ± 0.00 | 178.68 ± 58.72 | 178.68 ± 58.72 | 0.86 ± 0.23 | 3 |
|
||||
| Resize | 0.00 ± 0.00 | 170.87 ± 40.14 | 170.87 ± 40.14 | 0.83 ± 0.13 | 2 |
|
||||
| OutputOperator | 126.89 ± 16.53 | 0.00 ± 0.00 | 126.89 ± 16.53 | 0.63 ± 0.10 | 9 |
|
||||
| InputOperator | 8.69 ± 1.45 | 0.00 ± 0.00 | 8.69 ± 1.45 | 0.04 ± 0.01 | 1 |
|
||||
| **Total** | **135.57 ± 17.51** | **20165.99 ± 1963.70**| **20301.56 ± 1965.88**| | **113** |
|
||||
|
||||
### YOLOv8
|
||||
|
||||
| OpType | CPU Time (μs) | NPU Time (μs) | Total Time (μs) | Time Ratio (%) | Number of Times Called |
|
||||
|-----------------|---------------------|----------------------|-----------------------|---------------------|-----------------------|
|
||||
| ConvExSwish | 0.00 ± 0.00 | 13017.04 ± 1165.76 | 13017.04 ± 1165.76 | 75.66 ± 1.96 | 57 |
|
||||
| Concat | 0.00 ± 0.00 | 1489.94 ± 257.22 | 1489.94 ± 257.22 | 8.58 ± 0.53 | 13 |
|
||||
| Split | 0.00 ± 0.00 | 681.47 ± 166.62 | 681.47 ± 166.62 | 3.89 ± 0.53 | 8 |
|
||||
| ConvSigmoid | 0.00 ± 0.00 | 596.08 ± 75.01 | 596.08 ± 75.01 | 3.45 ± 0.18 | 3 |
|
||||
| Add | 0.00 ± 0.00 | 443.60 ± 118.05 | 443.60 ± 118.05 | 2.53 ± 0.41 | 6 |
|
||||
| Conv | 0.00 ± 0.00 | 269.61 ± 78.65 | 269.61 ± 78.65 | 1.54 ± 0.30 | 3 |
|
||||
| Resize | 0.00 ± 0.00 | 236.79 ± 37.74 | 236.79 ± 37.74 | 1.37 ± 0.08 | 2 |
|
||||
| ConvClip | 0.00 ± 0.00 | 231.82 ± 68.44 | 231.82 ± 68.44 | 1.32 ± 0.27 | 3 |
|
||||
| MaxPool | 0.00 ± 0.00 | 156.85 ± 56.94 | 156.85 ± 56.94 | 0.89 ± 0.23 | 3 |
|
||||
| OutputOperator | 124.86 ± 20.74 | 0.00 ± 0.00 | 124.86 ± 20.74 | 0.73 ± 0.15 | 9 |
|
||||
| InputOperator | 8.47 ± 1.66 | 0.00 ± 0.00 | 8.47 ± 1.66 | 0.05 ± 0.01 | 1 |
|
||||
| **Total** | **133.33 ± 21.95** | **17123.19 ± 1985.72**| **17256.52 ± 1986.77** | | **108** |
|
||||
|
||||
---
|
||||
|
||||
### YOLOv11
|
||||
|
||||
| OpType | CPU Time (μs) | NPU Time (μs) | Total Time (μs) | Time Ratio (%) | Number of Times Called |
|
||||
|-----------------|---------------------|----------------------|-----------------------|---------------------|-----------------------|
|
||||
| ConvExSwish | 0.00 ± 0.00 | 16034.00 ± 1331.95 | 16034.00 ± 1331.95 | 69.90 ± 1.55 | 77 |
|
||||
| Concat | 0.00 ± 0.00 | 1888.89 ± 293.99 | 1888.89 ± 293.99 | 8.17 ± 0.51 | 17 |
|
||||
| exSDPAttention | 0.00 ± 0.00 | 1210.88 ± 17.73 | 1210.88 ± 17.73 | 5.32 ± 0.52 | 1 |
|
||||
| Split | 0.00 ± 0.00 | 908.30 ± 183.92 | 908.30 ± 183.92 | 3.91 ± 0.45 | 10 |
|
||||
| Add | 0.00 ± 0.00 | 871.64 ± 212.79 | 871.64 ± 212.79 | 3.73 ± 0.60 | 12 |
|
||||
| ConvSigmoid | 0.00 ± 0.00 | 617.61 ± 59.61 | 617.61 ± 59.61 | 2.69 ± 0.16 | 3 |
|
||||
| Conv | 0.00 ± 0.00 | 419.72 ± 89.88 | 419.72 ± 89.88 | 1.80 ± 0.24 | 5 |
|
||||
| Resize | 0.00 ± 0.00 | 272.09 ± 49.91 | 272.09 ± 49.91 | 1.18 ± 0.12 | 2 |
|
||||
| ConvClip | 0.00 ± 0.00 | 260.08 ± 59.12 | 260.08 ± 59.12 | 1.12 ± 0.18 | 3 |
|
||||
| MaxPool | 0.00 ± 0.00 | 181.93 ± 53.32 | 181.93 ± 53.32 | 0.78 ± 0.18 | 3 |
|
||||
| OutputOperator | 131.48 ± 22.93 | 0.00 ± 0.00 | 131.48 ± 22.93 | 0.58 ± 0.12 | 9 |
|
||||
| ConvAdd | 0.00 ± 0.00 | 126.79 ± 35.28 | 126.79 ± 35.28 | 0.54 ± 0.11 | 2 |
|
||||
| Reshape | 0.00 ± 0.00 | 56.61 ± 18.03 | 56.61 ± 18.03 | 0.24 ± 0.06 | 3 |
|
||||
| InputOperator | 8.66 ± 1.59 | 0.00 ± 0.00 | 8.66 ± 1.59 | 0.04 ± 0.01 | 1 |
|
||||
| **Total** | **140.14 ± 24.26** | **22848.54 ± 2351.95**| **22988.68 ± 2355.97**| | **148** |
|
||||
|
||||
|
||||
## Model Summary and Accuracy Metrics
|
||||
|
||||
The table below summarizes the mean average precision (mAP) and total inference time for each model. These metrics provide a high-level view of how each model performs in terms of both detection accuracy and runtime efficiency.
|
||||
|
||||
### Mean Average Precision (mAP) by Model
|
||||
|
||||
| Metric | YOLOv5 | YOLOv5u | YOLOv8 | YOLOv11 |
|
||||
|--------|------------|------------|------------|------------|
|
||||
| **mAP** | 0.2243 | 0.2745 | 0.3051 | 0.3251 |
|
||||
| **mAP50** | 0.3538 | 0.3834 | 0.4145 | 0.4406 |
|
||||
| **mAP75** | 0.2432 | 0.2997 | 0.3349 | 0.3568 |
|
||||
| **mAP85** | 0.3054 | 0.3472 | 0.3867 | 0.4068 |
|
||||
| **mAP95** | 0.3708 | 0.4822 | 0.5483 | 0.5858 |
|
||||
|
||||
### Model Execution Time and Call Frequency
|
||||
|
||||
| Model | Total Time (μs) | Number of Processing Calls |
|
||||
|---------|------------------------|----------------------------|
|
||||
| **YOLOv5** | 15034.09 ± 1734.28 | 93 |
|
||||
| **YOLOv5u** | 20301.56 ± 1965.88 | 113 |
|
||||
| **YOLOv8** | 17256.52 ± 1986.77 | 108 |
|
||||
| **YOLOv11** | 22988.68 ± 2355.97 | 148 |
|
||||
|
||||
## Conclusion
|
||||
|
||||
The benchmark reveals a clear performance trade-off between inference time and detection accuracy:
|
||||
|
||||
- **YOLOv5** is the fastest model with the lowest total inference time, making it well-suited for situations where speed is more important than high detection precision.
|
||||
|
||||
- **YOLOv11** achieves the highest accuracy (mAP) across all IoU thresholds but comes with the longest inference time, which may limit its use in real-time applications.
|
||||
|
||||
- **YOLOv8** offers a strong balance between speed and accuracy, making it a practical choice when both factors matter.
|
||||
|
||||
- **YOLOv5u** improves accuracy compared to YOLOv5 but falls behind YOLOv8 in both speed and detection quality.
|
||||
|
||||
When choosing a model for edge devices like the Orange Pi 5, it’s important to weigh how much latency your system can tolerate versus how much accuracy you need. A faster model may give quicker results, while a more accurate one may offer better detection reliability, but at the cost of speed.
|
||||
@@ -18,7 +18,7 @@ The calibration data collected during calibration is specific to each physical c
|
||||
|
||||
Accurate camera calibration is required in order to get accurate pose measurements when using AprilTags and 3D mode. The tips below should help ensure success:
|
||||
|
||||
01. Ensure your the images you take have the target in different positions and angles, with as big of a difference between angles as possible. It is important to make sure the target overlay still lines up with the board while doing this. Tilt no more than 45 degrees.
|
||||
01. Ensure the images you take have the target in different positions and angles, with as big of a difference between angles as possible. It is important to make sure the target overlay still lines up with the board while doing this. Tilt no more than 45 degrees.
|
||||
02. Use as big of a calibration target as your printer can print.
|
||||
03. Ensure that your printed pattern has enough white border around it.
|
||||
04. Ensure your camera stays in one position during the duration of the calibration.
|
||||
@@ -52,7 +52,7 @@ We'll next select a resolution to calibrate and populate our pattern spacing, ma
|
||||
:::
|
||||
|
||||
:::{note}
|
||||
If you have a [calib.io](https://calib.io/) CharuCo Target you will have to enter the paramaters of your target. For example if your taget says "9x12 | Chceker Size: 30 mm | Marker Size: 22 mm | Dictionary: AruCo DICT 5x5", you would have to set the board type to Dict_5x5_1000, the pattern spacing to 1.1811 in (30 mm converted to inches), the marker size 0.866142 in (22 mm converted to inches), the board width to 12 and the board height to 9. If you chose the wrong tag family the baord wont be detected duting calibration. If you swap the width and height your calibration will have a very high error.
|
||||
If you have a [calib.io](https://calib.io/) CharuCo Target you will have to enter the paramaters of your target. For example if your target says "9x12 | Checker Size: 30 mm | Marker Size: 22 mm | Dictionary: AruCo DICT 5x5", you would have to set the board type to Dict_5x5_1000, the pattern spacing to 1.1811 in (30 mm converted to inches), the marker size 0.866142 in (22 mm converted to inches), the board width to 12 and the board height to 9. If you chose the wrong tag family the board wont be detected during calibration. If you swap the width and height your calibration will have a very high error.
|
||||
:::
|
||||
|
||||
### 4. Take at calibration images from various angles.
|
||||
|
||||
|
Before Width: | Height: | Size: 462 KiB After Width: | Height: | Size: 375 KiB |
|
Before Width: | Height: | Size: 163 KiB After Width: | Height: | Size: 118 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 86 KiB |
8
docs/source/docs/camera-specific-configuration/index.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# Camera-Specific Configuration
|
||||
|
||||
```{toctree}
|
||||
:maxdepth: 2
|
||||
|
||||
arducam-cameras
|
||||
picamconfig
|
||||
```
|
||||
@@ -23,6 +23,7 @@ Windows may report "There is a problem with this drive". This should be ignored.
|
||||
Locate `config.txt` in the folder, and open it with your favorite text editor.
|
||||
|
||||
```{image} images/bootConfigTxt.png
|
||||
|
||||
```
|
||||
|
||||
Within the file, find this block of text:
|
||||
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 334 KiB After Width: | Height: | Size: 197 KiB |
@@ -12,17 +12,11 @@ This section contains the build instructions from the source code available at [
|
||||
|
||||
**Node JS:**
|
||||
|
||||
The UI is written in Node JS. To compile the UI, Node 18.20.4 to Node 20.0.0 is required. To install Node JS follow the instructions for your platform [on the official Node JS website](https://nodejs.org/en/download/). However, modify this line
|
||||
The UI is written in Node JS. To compile the UI, Node 22 or later is required. To install Node JS, follow the instructions for your platform [on the official Node JS website](https://nodejs.org/en/download/).
|
||||
|
||||
```bash
|
||||
nvm install 20
|
||||
```
|
||||
**pnpm:**
|
||||
|
||||
so that it instead reads
|
||||
|
||||
```javascript
|
||||
nvm install 18.20.4
|
||||
```
|
||||
[pnpm](https://pnpm.io/) is the package manager used to download dependencies for the UI. To install pnpm, follow [the instructions on the official pnpm website](https://pnpm.io/installation).
|
||||
|
||||
## Compiling Instructions
|
||||
|
||||
@@ -46,27 +40,7 @@ or alternatively download the source code from GitHub and extract the zip:
|
||||
In the photon-client directory:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
### Build and Copy UI to Java Source
|
||||
|
||||
In the root directory:
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set::
|
||||
|
||||
.. tab-item:: Linux
|
||||
|
||||
``./gradlew buildAndCopyUI``
|
||||
|
||||
.. tab-item:: macOS
|
||||
|
||||
``./gradlew buildAndCopyUI``
|
||||
|
||||
.. tab-item:: Windows (cmd)
|
||||
|
||||
``gradlew buildAndCopyUI``
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### Using hot reload on the UI
|
||||
@@ -74,7 +48,7 @@ In the root directory:
|
||||
In the photon-client directory:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
pnpm run dev
|
||||
```
|
||||
|
||||
This allows you to make UI changes quickly without having to spend time rebuilding the jar. Hot reload is enabled, so changes that you make and save are reflected in the UI immediately. Running this command will give you the URL for accessing the UI, which is on a different port than normal. You must use the printed URL to use hot reload.
|
||||
@@ -87,14 +61,17 @@ To compile and run the project, issue the following command in the root director
|
||||
.. tab-set::
|
||||
|
||||
.. tab-item:: Linux
|
||||
:sync: linux
|
||||
|
||||
``./gradlew run``
|
||||
|
||||
.. tab-item:: macOS
|
||||
:sync: macos
|
||||
|
||||
``./gradlew run``
|
||||
|
||||
.. tab-item:: Windows (cmd)
|
||||
:sync: windows
|
||||
|
||||
``gradlew run``
|
||||
```
|
||||
@@ -105,21 +82,24 @@ Running the following command under the root directory will build the jar under
|
||||
.. tab-set::
|
||||
|
||||
.. tab-item:: Linux
|
||||
:sync: linux
|
||||
|
||||
``./gradlew shadowJar``
|
||||
|
||||
.. tab-item:: macOS
|
||||
:sync: macos
|
||||
|
||||
``./gradlew shadowJar``
|
||||
|
||||
.. tab-item:: Windows (cmd)
|
||||
:sync: windows
|
||||
|
||||
``gradlew shadowJar``
|
||||
```
|
||||
|
||||
### Build and Run PhotonVision on a Raspberry Pi Coprocessor
|
||||
|
||||
As a convenience, the build has a built-in `deploy` command which builds, deploys, and starts the current source code on a coprocessor.
|
||||
As a convenience, the build has a built-in `deploy` command which builds, deploys, and starts the current source code on a coprocessor. It uses [deploy-utils](https://github.com/wpilibsuite/deploy-utils/blob/main/README.md), so it works very similarly to deploys on robot projects.
|
||||
|
||||
An architecture override is required to specify the deploy target's architecture.
|
||||
|
||||
@@ -127,18 +107,21 @@ An architecture override is required to specify the deploy target's architecture
|
||||
.. tab-set::
|
||||
|
||||
.. tab-item:: Linux
|
||||
:sync: linux
|
||||
|
||||
``./gradlew clean``
|
||||
|
||||
``./gradlew deploy -PArchOverride=linuxarm64``
|
||||
|
||||
.. tab-item:: macOS
|
||||
:sync: macos
|
||||
|
||||
``./gradlew clean``
|
||||
|
||||
``./gradlew deploy -PArchOverride=linuxarm64``
|
||||
|
||||
.. tab-item:: Windows (cmd)
|
||||
:sync: windows
|
||||
|
||||
``gradlew clean``
|
||||
|
||||
@@ -157,14 +140,17 @@ The photonlib source can be published to your local maven repository after build
|
||||
.. tab-set::
|
||||
|
||||
.. tab-item:: Linux
|
||||
:sync: linux
|
||||
|
||||
``./gradlew publishToMavenLocal``
|
||||
|
||||
.. tab-item:: macOS
|
||||
:sync: macos
|
||||
|
||||
``./gradlew publishToMavenLocal``
|
||||
|
||||
.. tab-item:: Windows (cmd)
|
||||
:sync: windows
|
||||
|
||||
``gradlew publishToMavenLocal``
|
||||
```
|
||||
@@ -207,7 +193,7 @@ Similarly, a local instance of PhotonVision can be debugged in the same way usin
|
||||
|
||||
Set up a VSCode configuration in {code}`launch.json`
|
||||
|
||||
```
|
||||
```json
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
@@ -283,3 +269,15 @@ Using the [GitHub CLI](https://cli.github.com/), we can download artifacts from
|
||||
```
|
||||
~/photonvision$ gh run download 11759699679 -n jar-Linux
|
||||
```
|
||||
|
||||
#### MacOS Builds
|
||||
|
||||
MacOS builds are not published to releases as MacOS is not an officially
|
||||
supported platform. However, MacOS builds are still available from the MacOS
|
||||
build action, which can be found [here](https://github.com/PhotonVision/photonvision/actions/workflows/build.yml).
|
||||
|
||||
#### Forcing Object Detection in the UI
|
||||
|
||||
In order to force the Object Detection interface to be visible, it's necessary to hardcode the platform that `Platform.java` returns. This can be done by changing the function that detects the RK3588S/QCS6490 platform to always return true, and changing the `getCurrentPlatform()` function to always return the RK3588S/QCS6490 architecture.
|
||||
Alternatively, it's possible to modify the frontend code by changing all instances of `useSettingsStore().general.supportedBackends.length > 0` to `true`, which will force the card to render.
|
||||
Make sure to revert these changes before submitting a Pull Request.
|
||||
|
||||
@@ -4,7 +4,7 @@ Diagrams generated by the [PlantUML UML editor](https://www.plantuml.com/plantum
|
||||
|
||||
## Initial Setup
|
||||
|
||||
When PhotonVision first starts, settings are loaded from disk and [VisionSources](https://javadocs.photonvision.org/org/photonvision/vision/processes/VisionSource.html) are created for every serialized & active [Camera Configuration](https://javadocs.photonvision.org/org/photonvision/common/configuration/CameraConfiguration.html)
|
||||
When PhotonVision first starts, settings are loaded from disk and [VisionSources](https://javadocs.photonvision.org/release/org/photonvision/vision/processes/VisionSource.html) are created for every serialized & active [Camera Configuration](https://javadocs.photonvision.org/release/org/photonvision/common/configuration/CameraConfiguration.html)
|
||||
|
||||

|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 215 KiB After Width: | Height: | Size: 166 KiB |
@@ -11,7 +11,7 @@ PhotonVision has a myriad of advantages over similar solutions, including:
|
||||
|
||||
### Affordable
|
||||
|
||||
Compared to alternatives, PhotonVision is much cheaper to use (at the cost of your coprocessor and camera) compared to alternatives that cost \$400. This allows your team to save money while still being competitive.
|
||||
PhotonVision offers a more affordable solution to vision, with costs being from your coprocessor(s) and camera(s). Teams may choose to run multiple cameras from one coprocessor. This makes it a great solution for teams with limited budgets.
|
||||
|
||||
### Easy to Use User Interface
|
||||
|
||||
|
||||
BIN
docs/source/docs/driver-mode/images/crosshair-switch.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 194 KiB |
BIN
docs/source/docs/driver-mode/images/driver-mode-dashboard.png
Normal file
|
After Width: | Height: | Size: 257 KiB |
27
docs/source/docs/driver-mode/index.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Driver Mode
|
||||
|
||||
Driver Mode is a type of pipeline that doesn't run any vision processing, intended for viewing from a human.
|
||||
|
||||
## Enabling Driver Mode
|
||||
|
||||
To enable Driver Mode, toggle the switch at the top of the Dashboard page for a selected camera.
|
||||
|
||||
```{image} images/driver-mode-dashboard.png
|
||||
:align: center
|
||||
:alt: Driver Mode Toggle in the Dashboard Page
|
||||
```
|
||||
|
||||
Alternatively, visit the camera settings page and toggle the "Driver Mode" switch for a selected camera.
|
||||
|
||||
```{image} images/driver-mode-camera-settings.png
|
||||
:align: center
|
||||
:alt: Driver Mode Toggle in the Camera Settings Page
|
||||
```
|
||||
|
||||
## Hiding the Crosshair
|
||||
When Driver Mode is enabled, a green crosshair will be shown at the center of the camera stream. If you do not want to show the green crosshair at the center of the camera stream, toggle the "Crosshair" switch under the Input tab, as shown in the image below.
|
||||
|
||||
```{image} images/crosshair-switch.png
|
||||
:align: center
|
||||
:alt: Crosshair Switch
|
||||
```
|
||||
@@ -1,6 +1,6 @@
|
||||
# Combining Aiming and Getting in Range
|
||||
|
||||
The following example is from the PhotonLib example repository ([Java](https://github.com/PhotonVision/photonvision/tree/main/photonlib-java-examples/aimandrange)/[C++](https://github.com/PhotonVision/photonvision/tree/main/photonlib-cpp-examples/aimandrange)).
|
||||
The following example is from the PhotonLib example repository ([Java](https://github.com/PhotonVision/photonvision/tree/main/photonlib-java-examples/aimandrange)/[C++](https://github.com/PhotonVision/photonvision/tree/main/photonlib-cpp-examples/aimandrange)/[Python](https://github.com/PhotonVision/photonvision/tree/main/photonlib-python-examples/aimandrange))
|
||||
|
||||
## Knowledge and Equipment Needed
|
||||
|
||||
@@ -10,12 +10,14 @@ The following example is from the PhotonLib example repository ([Java](https://g
|
||||
|
||||
Now that you know how to aim toward the AprilTag, let's also drive the correct distance from the AprilTag.
|
||||
|
||||
To do this, we'll use the *pitch* of the target in the camera image and trigonometry to figure out how far away the robot is from the AprilTag. Then, like before, we'll use the P term of a PID controller to drive the robot to the correct distance.
|
||||
To do this, we'll use the _pitch_ of the target in the camera image and trigonometry to figure out how far away the robot is from the AprilTag. Then, like before, we'll use the P term of a PID controller to drive the robot to the correct distance.
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set::
|
||||
:sync-group: code
|
||||
|
||||
.. tab-item:: Java
|
||||
:sync: java
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-java-examples/aimandrange/src/main/java/frc/robot/Robot.java
|
||||
:language: java
|
||||
@@ -24,6 +26,7 @@ To do this, we'll use the *pitch* of the target in the camera image and trigonom
|
||||
:lineno-start: 84
|
||||
|
||||
.. tab-item:: C++ (Header)
|
||||
:sync: c++
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-cpp-examples/aimandrange/src/main/include/Robot.h
|
||||
:language: c++
|
||||
@@ -32,6 +35,7 @@ To do this, we'll use the *pitch* of the target in the camera image and trigonom
|
||||
:lineno-start: 25
|
||||
|
||||
.. tab-item:: C++ (Source)
|
||||
:sync: c++
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-cpp-examples/aimandrange/src/main/cpp/Robot.cpp
|
||||
:language: c++
|
||||
@@ -40,11 +44,12 @@ To do this, we'll use the *pitch* of the target in the camera image and trigonom
|
||||
:lineno-start: 58
|
||||
|
||||
.. tab-item:: Python
|
||||
:sync: python
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-python-examples/aimandrange/robot.py
|
||||
:language: python
|
||||
:lines: 44-95
|
||||
:lines: 52-91
|
||||
:linenos:
|
||||
:lineno-start: 44
|
||||
:lineno-start: 52
|
||||
|
||||
```
|
||||
|
||||
@@ -13,14 +13,16 @@ The following example is from the PhotonLib example repository ([Java](https://g
|
||||
|
||||
Now that you have properly set up your vision system and have tuned a pipeline, you can now aim your robot at an AprilTag using the data from PhotonVision. The _yaw_ of the target is the critical piece of data that will be needed first.
|
||||
|
||||
Yaw is reported to the roboRIO over Network Tables. PhotonLib, our vender dependency, is the easiest way to access this data. The documentation for the Network Tables API can be found {ref}`here <docs/additional-resources/nt-api:Getting Target Information>` and the documentation for PhotonLib {ref}`here <docs/programming/photonlib/adding-vendordep:What is PhotonLib?>`.
|
||||
Yaw is reported to the roboRIO over Network Tables. PhotonLib, our vendor dependency, is the easiest way to access this data. The documentation for the Network Tables API can be found {ref}`here <docs/additional-resources/nt-api:Getting Target Information>` and the documentation for PhotonLib {ref}`here <docs/programming/photonlib/adding-vendordep:What is PhotonLib?>`.
|
||||
|
||||
In this example, while the operator holds a button down, the robot will turn towards the AprilTag using the P term of a PID loop. To learn more about how PID loops work, how WPILib implements them, and more, visit [Advanced Controls (PID)](https://docs.wpilib.org/en/stable/docs/software/advanced-control/introduction/index.html) and [PID Control in WPILib](https://docs.wpilib.org/en/stable/docs/software/advanced-controls/controllers/pidcontroller.html#pid-control-in-wpilib).
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set::
|
||||
:sync-group: code
|
||||
|
||||
.. tab-item:: Java
|
||||
:sync: java
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-java-examples/aimattarget/src/main/java/frc/robot/Robot.java
|
||||
:language: java
|
||||
@@ -29,6 +31,7 @@ In this example, while the operator holds a button down, the robot will turn tow
|
||||
:lineno-start: 77
|
||||
|
||||
.. tab-item:: C++ (Header)
|
||||
:sync: c++
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-cpp-examples/aimattarget/src/main/include/Robot.h
|
||||
:language: c++
|
||||
@@ -37,6 +40,7 @@ In this example, while the operator holds a button down, the robot will turn tow
|
||||
:lineno-start: 25
|
||||
|
||||
.. tab-item:: C++ (Source)
|
||||
:sync: c++
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-cpp-examples/aimattarget/src/main/cpp/Robot.cpp
|
||||
:language: c++
|
||||
@@ -45,6 +49,7 @@ In this example, while the operator holds a button down, the robot will turn tow
|
||||
:lineno-start: 56
|
||||
|
||||
.. tab-item:: Python
|
||||
:sync: python
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-python-examples/aimattarget/robot.py
|
||||
:language: python
|
||||
|
||||
@@ -21,32 +21,24 @@ Please reference the [WPILib documentation](https://docs.wpilib.org/en/stable/do
|
||||
We use the 2024 game's AprilTag Locations:
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set::
|
||||
.. tab-set-code::
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-java-examples/poseest/src/main/java/frc/robot/Vision.java
|
||||
:language: java
|
||||
:lines: 68-68
|
||||
:linenos:
|
||||
:lineno-start: 68
|
||||
|
||||
.. tab-item:: Java
|
||||
:sync: java
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-cpp-examples/poseest/src/main/include/Constants.h
|
||||
:language: c++
|
||||
:lines: 42-43
|
||||
:linenos:
|
||||
:lineno-start: 42
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-java-examples/poseest/src/main/java/frc/robot/Vision.java
|
||||
:language: java
|
||||
:lines: 68-68
|
||||
:linenos:
|
||||
:lineno-start: 68
|
||||
|
||||
.. tab-item:: C++
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-cpp-examples/poseest/src/main/include/Constants.h
|
||||
:language: c++
|
||||
:lines: 42-43
|
||||
:linenos:
|
||||
:lineno-start: 42
|
||||
|
||||
.. tab-item:: Python
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-python-examples/poseest/robot.py
|
||||
:language: python
|
||||
:lines: 46-46
|
||||
:linenos:
|
||||
:lineno-start: 46
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-python-examples/poseest/robot.py
|
||||
:language: python
|
||||
:lines: 46-46
|
||||
:linenos:
|
||||
:lineno-start: 46
|
||||
|
||||
```
|
||||
|
||||
@@ -56,63 +48,47 @@ To incorporate PhotonVision, we need to create a {code}`PhotonCamera`:
|
||||
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set::
|
||||
.. tab-set-code::
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-java-examples/poseest/src/main/java/frc/robot/Vision.java
|
||||
:language: java
|
||||
:lines: 57-57
|
||||
:linenos:
|
||||
:lineno-start: 57
|
||||
|
||||
.. tab-item:: Java
|
||||
:sync: java
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-cpp-examples/poseest/src/main/include/Vision.h
|
||||
:language: c++
|
||||
:lines: 145-145
|
||||
:linenos:
|
||||
:lineno-start: 145
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-java-examples/poseest/src/main/java/frc/robot/Vision.java
|
||||
:language: java
|
||||
:lines: 57-57
|
||||
:linenos:
|
||||
:lineno-start: 57
|
||||
|
||||
.. tab-item:: C++
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-cpp-examples/poseest/src/main/include/Vision.h
|
||||
:language: c++
|
||||
:lines: 145-145
|
||||
:linenos:
|
||||
:lineno-start: 145
|
||||
|
||||
.. tab-item:: Python
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-python-examples/poseest/robot.py
|
||||
:language: python
|
||||
:lines: 44-44
|
||||
:linenos:
|
||||
:lineno-start: 44
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-python-examples/poseest/robot.py
|
||||
:language: python
|
||||
:lines: 44-44
|
||||
:linenos:
|
||||
:lineno-start: 44
|
||||
```
|
||||
|
||||
During periodic execution, we read back camera results. If we see AprilTags in the image, we calculate the camera-measured pose of the robot and pass it to the {code}`Drivetrain`.
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set::
|
||||
.. tab-set-code::
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-java-examples/poseest/src/main/java/frc/robot/Robot.java
|
||||
:language: java
|
||||
:lines: 64-74
|
||||
:linenos:
|
||||
:lineno-start: 64
|
||||
|
||||
.. tab-item:: Java
|
||||
:sync: java
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-cpp-examples/poseest/src/main/cpp/Robot.cpp
|
||||
:language: c++
|
||||
:lines: 38-46
|
||||
:linenos:
|
||||
:lineno-start: 38
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-java-examples/poseest/src/main/java/frc/robot/Robot.java
|
||||
:language: java
|
||||
:lines: 64-74
|
||||
:linenos:
|
||||
:lineno-start: 64
|
||||
|
||||
.. tab-item:: C++
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-cpp-examples/poseest/src/main/cpp/Robot.cpp
|
||||
:language: c++
|
||||
:lines: 38-46
|
||||
:linenos:
|
||||
:lineno-start: 38
|
||||
|
||||
.. tab-item:: Python
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-python-examples/poseest/robot.py
|
||||
:language: python
|
||||
:lines: 54-56
|
||||
:linenos:
|
||||
:lineno-start: 54
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-python-examples/poseest/robot.py
|
||||
:language: python
|
||||
:lines: 54-56
|
||||
:linenos:
|
||||
:lineno-start: 54
|
||||
|
||||
```
|
||||
|
||||
@@ -121,56 +97,45 @@ During periodic execution, we read back camera results. If we see AprilTags in t
|
||||
First, we create a new {code}`VisionSystemSim` to represent our camera and coprocessor running PhotonVision, and moving around our simulated field.
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set::
|
||||
.. tab-set-code::
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-java-examples/poseest/src/main/java/frc/robot/Vision.java
|
||||
:language: java
|
||||
:lines: 65-69
|
||||
:linenos:
|
||||
:lineno-start: 65
|
||||
|
||||
.. tab-item:: Java
|
||||
:sync: java
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-cpp-examples/poseest/src/main/include/Vision.h
|
||||
:language: c++
|
||||
:lines: 49-52
|
||||
:linenos:
|
||||
:lineno-start: 49
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-java-examples/poseest/src/main/java/frc/robot/Vision.java
|
||||
:language: java
|
||||
:lines: 65-69
|
||||
:linenos:
|
||||
:lineno-start: 65
|
||||
.. code-block:: python
|
||||
|
||||
.. tab-item:: C++
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-cpp-examples/poseest/src/main/include/Vision.h
|
||||
:language: c++
|
||||
:lines: 49-52
|
||||
:linenos:
|
||||
:lineno-start: 49
|
||||
|
||||
.. tab-item:: Python
|
||||
|
||||
# Coming Soon!
|
||||
# Coming Soon!
|
||||
|
||||
```
|
||||
|
||||
Then, we add configure the simulated vision system to match the camera system being simulated.
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set::
|
||||
.. tab-set-code::
|
||||
|
||||
.. tab-item:: Java
|
||||
:sync: java
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-java-examples/poseest/src/main/java/frc/robot/Vision.java
|
||||
:language: java
|
||||
:lines: 69-82
|
||||
:linenos:
|
||||
:lineno-start: 69
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-java-examples/poseest/src/main/java/frc/robot/Vision.java
|
||||
:language: java
|
||||
:lines: 69-82
|
||||
:linenos:
|
||||
:lineno-start: 69
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-cpp-examples/poseest/src/main/include/Vision.h
|
||||
:language: c++
|
||||
:lines: 53-65
|
||||
:linenos:
|
||||
:lineno-start: 53
|
||||
|
||||
.. tab-item:: C++
|
||||
.. code-block:: python
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-cpp-examples/poseest/src/main/include/Vision.h
|
||||
:language: c++
|
||||
:lines: 53-65
|
||||
:linenos:
|
||||
:lineno-start: 53
|
||||
|
||||
.. tab-item:: Python
|
||||
|
||||
# Coming Soon!
|
||||
# Coming Soon!
|
||||
```
|
||||
|
||||
|
||||
@@ -179,28 +144,23 @@ Then, we add configure the simulated vision system to match the camera system be
|
||||
During simulation, we periodically update the simulated vision system.
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set::
|
||||
.. tab-set-code::
|
||||
|
||||
.. tab-item:: Java
|
||||
:sync: java
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-java-examples/poseest/src/main/java/frc/robot/Robot.java
|
||||
:language: java
|
||||
:lines: 114-132
|
||||
:linenos:
|
||||
:lineno-start: 114
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-java-examples/poseest/src/main/java/frc/robot/Robot.java
|
||||
:language: java
|
||||
:lines: 114-132
|
||||
:linenos:
|
||||
:lineno-start: 114
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-cpp-examples/poseest/src/main/cpp/Robot.cpp
|
||||
:language: c++
|
||||
:lines: 95-109
|
||||
:linenos:
|
||||
:lineno-start: 95
|
||||
|
||||
.. tab-item:: C++
|
||||
.. code-block:: python
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/abe95dfaa055bbe3609f72cfcaaba0f96ee7978c/photonlib-cpp-examples/poseest/src/main/cpp/Robot.cpp
|
||||
:language: c++
|
||||
:lines: 95-109
|
||||
:linenos:
|
||||
:lineno-start: 95
|
||||
|
||||
.. tab-item:: Python
|
||||
|
||||
# Coming Soon!
|
||||
# Coming Soon!
|
||||
```
|
||||
|
||||
The rest is done behind the scenes.
|
||||
|
||||
|
Before Width: | Height: | Size: 56 KiB |
@@ -4,6 +4,5 @@
|
||||
:maxdepth: 2
|
||||
|
||||
selecting-hardware
|
||||
picamconfig
|
||||
customhardware
|
||||
```
|
||||
|
||||
@@ -43,7 +43,7 @@ A simple way to use a pose estimate is to activate robot functions automatically
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
|
||||
.. code-block:: Java
|
||||
.. code-block:: java
|
||||
|
||||
Pose3d robotPose;
|
||||
boolean launcherSpinCmd;
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
## How does it work?
|
||||
|
||||
PhotonVision supports object detection using neural network accelerator hardware built into Orange Pi 5/5+ coprocessors. Please note that the Orange Pi 5/5+ are the only coprocessors that are currently supported. The Neural Processing Unit, or NPU, is [used by PhotonVision](https://github.com/PhotonVision/rknn_jni/tree/main) to massively accelerate certain math operations like those needed for running ML-based object detection.
|
||||
PhotonVision supports object detection using neural network accelerator hardware, commonly known as an NPU. The two coprocessors currently supported are the {ref}`Orange Pi 5 <docs/objectDetection/opi:Orange Pi 5 (and variants) Object Detection>` and the {ref}`Rubik Pi 3 <docs/objectDetection/rubik:Rubik Pi 3 Object Detection>`.
|
||||
|
||||
For the 2025 season, PhotonVision ships with a pretrained ALGAE model. A model to detect coral is not currently stable, and interested teams should ask in the Photonvision discord.
|
||||
PhotonVision currently ships with a model trained on the [COCO dataset](https://cocodataset.org/) by [Ultralytics](https://github.com/ultralytics/ultralytics) (this model is licensed under [AGPLv3](https://www.gnu.org/licenses/agpl-3.0.en.html)). This model is meant to be used for testing and other miscellaneous purposes. It is not meant to be used in competition. For the 2025 post-season, PhotonVision also ships with a pretrained ALGAE model. A model to detect coral is available in the PhotonVision discord, but will not be distributed with PhotonVision.
|
||||
|
||||
## Tracking Objects
|
||||
|
||||
@@ -18,7 +18,7 @@ This model output means that while its fairly easy to say that "this rectangle p
|
||||
|
||||
## Tuning and Filtering
|
||||
|
||||
Compared to other pipelines, object detection exposes very few tuning handles. The Confidence slider changes the minimum confidence that the model needs to have in a given detection to consider it valid, as a number between 0 and 1 (with 0 meaning completely uncertain and 1 meaning maximally certain).
|
||||
Compared to other pipelines, object detection exposes very few tuning handles. The Confidence slider changes the minimum confidence that the model needs to have in a given detection to consider it valid, as a number between 0 and 1 (with 0 meaning completely uncertain and 1 meaning maximally certain). The Non-Maximum Suppresion (NMS) Threshold slider is used to filter out overlapping detections. Higher values mean more detections are allowed through, but may result in false positives. It's generally recommended that teams leave this set at the default, unless they find they're unable to get usable results with solely the Confidence slider.
|
||||
|
||||
```{raw} html
|
||||
<video width="85%" controls>
|
||||
@@ -33,23 +33,19 @@ The same area, aspect ratio, and target orientation/sort parameters from {ref}`r
|
||||
|
||||
Photonvision will letterbox your camera frame to 640x640. This means that if you select a resolution that is larger than 640 it will be scaled down to fit inside a 640x640 frame with black bars if needed. Smaller frames will be scaled up with black bars if needed.
|
||||
|
||||
## Training Custom Models
|
||||
It is recommended that you select a resolution that results in the smaller dimension being just greater than, or equal to, 640. Anything above this will not see any increased performance.
|
||||
|
||||
:::{warning}
|
||||
Power users only. This requires some setup, such as obtaining your own dataset and installing various tools. It's additionally advised to have a general knowledge of ML before attempting to train your own model. Additionally, this is not officially supported by Photonvision, and any problems that may arise are not attributable to Photonvision.
|
||||
:::
|
||||
## Custom Models
|
||||
|
||||
Before beginning, it is necessary to install the [rknn-toolkit2](https://github.com/airockchip/rknn-toolkit2). Then, install the relevant [Ultralytics repository](https://github.com/airockchip?tab=repositories&q=yolo&type=&language=&sort=) from this list. After training your model, export it to `rknn`. This will give you an `onnx` file, formatted for conversion. Copy this file to the relevant folder in [rknn_model_zoo](https://github.com/airockchip/rknn_model_zoo), and use the conversion script located there to convert it. If necessary, modify the script to provide the path to your training database for quantization.
|
||||
For information regarding converting custom models and supported models for each platform, refer to the page detailing information about your specific coprocessor.
|
||||
|
||||
## Uploading Custom Models
|
||||
- {ref}`Orange Pi 5 <docs/objectDetection/opi:Orange Pi 5 (and variants) Object Detection>`
|
||||
- {ref}`Rubik Pi 3 <docs/objectDetection/rubik:Rubik Pi 3 Object Detection>`
|
||||
|
||||
:::{warning}
|
||||
PhotonVision currently ONLY supports 640x640 Ultralytics YOLOv5, YOLOv8, and YOLOv11 models trained and converted to `.rknn` format for RK3588 CPUs! Other models require different post-processing code and will NOT work. The model conversion process is also highly particular. Proceed with care.
|
||||
:::
|
||||
### Training Custom Models
|
||||
|
||||
In the settings, under `Device Control`, there's an option to upload a new object detection model. Naming convention
|
||||
should be `name-verticalResolution-horizontalResolution-yolovXXX`. The
|
||||
`name` should only include alphanumeric characters, periods, and underscores. Additionally, the labels
|
||||
file ought to have the same name as the RKNN file, with `-labels` appended to the end. For
|
||||
example, if the RKNN file is named `Algae_1.03.2025-640-640-yolov5s.rknn`, the labels file should be
|
||||
named `Algae_1.03.2025-640-640-yolov5s-labels.txt`.
|
||||
PhotonVision does not offer any support for training custom models, only conversion. For information on which models are supported for a given coprocessor, use the links above.
|
||||
|
||||
### Managing Custom Models
|
||||
|
||||
Custom models can now be managed from the Object Detection tab in settings. You can upload a custom model by clicking the "Upload Model" button, selecting your model file, and filling out the property fields. Models can also be exported, both individually and in bulk. Models exported in bulk can be imported using the `import bulk` button. Models exported individually must be re-imported as an individual model, and all the relevant metadata is stored in the filename of the model.
|
||||
|
||||
|
Before Width: | Height: | Size: 358 KiB After Width: | Height: | Size: 246 KiB |
@@ -1,8 +1,8 @@
|
||||
# Object Detection
|
||||
|
||||
```{toctree}
|
||||
:maxdepth: 0
|
||||
:titlesonly: true
|
||||
|
||||
about-object-detection
|
||||
opi
|
||||
rubik
|
||||
```
|
||||
|
||||
19
docs/source/docs/objectDetection/opi.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Orange Pi 5 (and variants) Object Detection
|
||||
|
||||
## How it works
|
||||
|
||||
PhotonVision runs object detection on the Orange Pi 5 by use of the RKNN model architecture, and [this JNI code](https://github.com/PhotonVision/rknn_jni).
|
||||
|
||||
## Supported models
|
||||
|
||||
PhotonVision currently ONLY supports 640x640 Ultralytics YOLOv5, YOLOv8, and YOLOv11 models trained and converted to `.rknn` format for RK3588 SOCs! Other models require different post-processing code and will NOT work.
|
||||
|
||||
## Converting Custom Models
|
||||
|
||||
:::{warning}
|
||||
Only quantized models are supported, so take care when exporting to select the option for quantization.
|
||||
:::
|
||||
|
||||
PhotonVision now ships with a {{ '[Python Notebook](https://github.com/PhotonVision/photonvision/blob/{}/scripts/rknn_conversion.ipynb)'.format(git_tag_ref) }} that you can use in [Google Colab](https://colab.research.google.com) or in a local environment. In Google Colab, you can simply paste the PhotonVision GitHub URL into the "GitHub" tab and select the `rknn_conversion.ipynb` notebook without needing to manually download anything.
|
||||
|
||||
Please ensure that the model you are attempting to convert is among the {ref}`supported models <docs/objectDetection/opi:Supported Models>` and using the PyTorch format.
|
||||
25
docs/source/docs/objectDetection/rubik.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Rubik Pi 3 Object Detection
|
||||
|
||||
## How it works
|
||||
|
||||
PhotonVision runs object detection on the Rubik Pi 3 by use of [TensorflowLite](https://github.com/tensorflow/tensorflow), and [this JNI code](https://github.com/PhotonVision/rubik_jni).
|
||||
|
||||
## Supported models
|
||||
|
||||
PhotonVision currently ONLY supports 640x640 Ultralytics YOLOv8 and YOLOv11 models trained and converted to `.tflite` format for QCS6490 SOCs! Other models require different post-processing code and will NOT work.
|
||||
|
||||
## Converting Custom Models
|
||||
|
||||
:::{warning}
|
||||
Only quantized models are supported, so take care when exporting to select the option for quantization.
|
||||
:::
|
||||
|
||||
PhotonVision now ships with a {{ '[Python Notebook](https://github.com/PhotonVision/photonvision/blob/{}/scripts/rubik_conversion.ipynb)'.format(git_tag_ref) }} that you can use in [Google Colab](https://colab.research.google.com) or in a local environment. In Google Colab, you can simply paste the PhotonVision GitHub URL into the "GitHub" tab and select the `rubik_conversion.ipynb` notebook without needing to manually download anything.
|
||||
|
||||
Please ensure that the model you are attempting to convert is among the {ref}`supported models <docs/objectDetection/rubik:Supported Models>` and using the PyTorch format.
|
||||
|
||||
## Benchmarking
|
||||
|
||||
Before you can perform benchmarking, it's necessary to install `tensorflow-lite-qcom-apps` with apt.
|
||||
|
||||
By SSHing into your Rubik Pi and running this command, replacing `PATH/TO/MODEL` with the path to your model, `benchmark_model --graph=src/test/resources/yolov8nCoco.tflite --external_delegate_path=/usr/lib/libQnnTFLiteDelegate.so --external_delegate_options=backend_type:htp --external_delegate_options=htp_use_conv_hmx:1 --external_delegate_options=htp_performance_mode:2` you can determine how long it takes for inference to be performed with your model.
|
||||
@@ -10,37 +10,61 @@ A vision pipeline represents a series of steps that are used to acquire an image
|
||||
|
||||
## Types of Pipelines
|
||||
|
||||
### Reflective
|
||||
### AprilTag / AruCo
|
||||
|
||||
This is the most common pipeline type and it is based on detecting targets with retroreflective tape. In the contours tab of this pipeline type, you can filter the area, width/height ratio, fullness, degree of speckle rejection.
|
||||
This pipeline type is based on detecting AprilTag fiducial markers. More information about AprilTags can be found in the [WPILib documentation](https://docs.wpilib.org/en/stable/docs/software/vision-processing/apriltag/apriltag-intro.html). This pipeline provides easy to use 3D pose information which allows localization.
|
||||
|
||||
:::{note}
|
||||
In order to get 3D Pose data about AprilTags, you are required to {ref}`calibrate your camera<docs/calibration/calibration:Calibrating Your Camera>`.
|
||||
:::
|
||||
|
||||
### Object Detection
|
||||
|
||||
This pipeline type is based on detecting objects using a neural network. The object detection pipeline uses a pre-trained model to detect objects in the camera stream.
|
||||
|
||||
:::{note}
|
||||
This pipeline type is only supported on the Orange Pi 5/5+ coprocessors due to its Neural Processing Unit used by PhotonVision to support running ML-based object detection.
|
||||
:::
|
||||
|
||||
### Driver Mode
|
||||
|
||||
Driver Mode is a type of pipeline that doesn't run any vision processing, intended for human viewing. For more information about Driver Mode, see the {ref}`Driver Mode documentation<docs/driver-mode/index:Driver Mode>`.
|
||||
|
||||
### Colored Shape
|
||||
|
||||
This pipeline type is based on detecting different shapes like circles, triangles, quadrilaterals, or a polygon. An example usage would be detecting yellow PowerCells from the 2020 FRC game. You can read more about the specific settings available in the contours page.
|
||||
|
||||
### AprilTag / AruCo
|
||||
### Reflective
|
||||
|
||||
This pipeline type is based on detecting AprilTag fiducial markers. More information about AprilTags can be found in the WPILib documentation. While being more performance intensive than the reflective and colored shape pipeline, it has the benefit of providing easy to use 3D pose information which allows localization.
|
||||
This pipeline type is based on detecting targets with reflective tape. In the contours tab of this pipeline type, you can filter the area, width/height ratio, fullness, degree of speckle rejection.
|
||||
|
||||
:::{note}
|
||||
In order to get 3D Pose data about AprilTags, you are required to {ref}`calibrate your camera<docs/calibration/calibration:Calibrating Your Camera>`.
|
||||
This pipeline type is not used anymore due to FRC's removal of retro-reflective tape from the game. It is still available as a pipeline for legacy purposes.
|
||||
:::
|
||||
|
||||
## Note About Multiple Cameras and Pipelines
|
||||
|
||||
When using more than one camera, it is important to keep in mind that all cameras run one pipeline each, all publish to NT, and all send both streams. This will have a noticeable affect on performance and we recommend users limit themselves to 1-2 cameras per coprocessor.
|
||||
|
||||
## Pipeline Steps
|
||||
## Pipeline Configuration
|
||||
|
||||
Reflective and Colored Shape Pipelines have 4 steps (represented as 4 tabs):
|
||||
Each pipeline has a set of tabs that are used to configure the pipeline. All pipelines follow a similar structure with an Input and Output tab, as well as a set of tabs that are specific to the pipeline type.
|
||||
|
||||
1. Input: This tab allows the raw camera image to be modified before it gets processed. Here, you can set exposure, brightness, gain, orientation, and resolution.
|
||||
2. Threshold (Only Reflective and Colored Shape): This tabs allows you to filter our specific colors/pixels in your camera stream through HSV tuning. The end goal here is having a black and white image that will only have your target lit up.
|
||||
3. Contours: After thresholding, contiguous white pixels are grouped together, and described by a curve that outlines the group. This curve is called a "contour" which represent various targets on your screen. Regardless of type, you can filter how the targets are grouped, their intersection, and how the targets are sorted. Other available filters will change based on different pipeline types.
|
||||
4. Output: Now that you have filtered all of your contours, this allows you to manipulate the detected target via orientation, the offset point, and offset.
|
||||
- Input: This tab allows the raw camera image to be modified before it gets processed. Here, you can set exposure, brightness, gain, orientation, and resolution.
|
||||
|
||||
AprilTag / AruCo Pipelines have 3 steps:
|
||||
- Output: This allows you to manipulate the detected target via the target offset point (for calculating pitch/yaw) and robot (crosshair) offset. In addition, it allows users to send additional (up to 5) outputs through PhotonLib.
|
||||
|
||||
1. Input: This is the same as the above.
|
||||
2. AprilTag: This step include AprilTag specific tuning parameters, such as decimate, blur, threads, pose iterations, and more.
|
||||
3. Output: This is the same as the above.
|
||||
Pipielines also have additional tabs that are specific to the pipeline type. Listed below are the tabs for each pipeline type.
|
||||
|
||||
### AprilTag / AruCo Pipelines
|
||||
|
||||
- AprilTag: This tab includes AprilTag specific tuning parameters, such as decimate, blur, threads, pose iterations, and more.
|
||||
|
||||
### Object Detection Pipelines
|
||||
|
||||
- Object Detection: This tab allows you to filter results from the neural network, such as confidence, area, and width/height ratio. The end goal of this tab is to filter out any false positives.
|
||||
|
||||
### Reflective and Colored Shape Pipelines
|
||||
|
||||
- Threshold: This tab allows you to filter out specific colors/pixels in your camera stream through HSV tuning. The end goal here is having a black and white image that will only have your target lit up.
|
||||
- Contours: After thresholding, contiguous white pixels are grouped together, and described by a curve that outlines the group. This curve is called a "contour" which represent various targets on your screen. Regardless of type, you can filter how the targets are grouped, their intersection, and how the targets are sorted. Other available filters will change based on different pipeline types.
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB |
@@ -8,24 +8,38 @@ PhotonLibPy is a minimal, pure-python implementation of PhotonLib.
|
||||
|
||||
## Online Install - Java/C++
|
||||
|
||||
Click on the WPI icon on the top right of your VS Code window or hit Ctrl+Shift+P (Cmd+Shift+P on macOS) to bring up the command palette. Type, "Manage Vendor Libraries" and select the "WPILib: Manage Vendor Libraries" option. Then, select the "Install new library (online)" option.
|
||||
Click on the WPILib logo in the activity bar to access the Vendor Dependencies interface.
|
||||
|
||||
```{image} images/adding-offline-library.png
|
||||
```{image} images/wpilib-vendor-dependencies.png
|
||||
:scale: 50%
|
||||
:align: center
|
||||
:alt: WPILib Vendor Dependencies
|
||||
```
|
||||
|
||||
Paste the following URL into the box that pops up:
|
||||
Select the install button for the "PhotonLib" dependency.
|
||||
|
||||
`https://maven.photonvision.org/repository/internal/org/photonvision/photonlib-json/1.0/photonlib-json-1.0.json`
|
||||
```{image} images/photonlib-install.png
|
||||
:scale: 50%
|
||||
:align: center
|
||||
:alt: PhotonLib Install Button
|
||||
```
|
||||
|
||||
:::{note}
|
||||
It is recommended to Build Robot Code at least once when connected to the Internet before heading to an area where Internet connectivity is limited (for example, a competition). This ensures that the relevant files are downloaded to your filesystem.
|
||||
The Dependency Manager will automatically build your program when it loses focus. This allows you to use the changed dependencies.
|
||||
:::
|
||||
|
||||
When an update is available for PhotonLib, a "To Latest" button will become available. This will update the vendordep to the latest version of PhotonLib.
|
||||
|
||||
```{image} images/photonlib-to-latest.png
|
||||
:align: center
|
||||
:alt: PhotonLib Update Button
|
||||
```
|
||||
|
||||
Refer to [The WPILib docs](https://docs.wpilib.org/en/stable/docs/software/vscode-overview/3rd-party-libraries.html#installing-libraries) for more details on installing vendor libraries.
|
||||
|
||||
## Offline Install - Java/C++
|
||||
|
||||
Download the latest PhotonLib release from our GitHub releases page (named something like `` photonlib-VERSION.zip` ``), and extract the contents to `$HOME/wpilib/YEAR`. This adds PhotonLib maven artifacts to your local maven repository. PhotonLib will now also appear available in the "install vendor libraries (offline)" menu in WPILib VSCode. Refer to [the WPILib docs](https://docs.wpilib.org/en/stable/docs/software/vscode-overview/3rd-party-libraries.html#installing-libraries) for more details on installing vendor libraries offline.
|
||||
Download the latest PhotonLib release from our [GitHub releases page](https://github.com/PhotonVision/photonvision/releases) (named in the format `photonlib-VERSION.zip`), and extract the contents to `~/wpilib/YYYY/vendordeps` (where YYYY is the year and ~ is `C:\Users\Public` on Windows). This adds PhotonLib maven artifacts to your local maven repository. PhotonLib will now also appear available in the "install vendor libraries (offline)" menu in WPILib VSCode. Refer to [the WPILib docs](https://docs.wpilib.org/en/stable/docs/software/vscode-overview/3rd-party-libraries.html#how-does-it-work) for more details on installing vendor libraries offline.
|
||||
|
||||
## Install - Python
|
||||
|
||||
@@ -44,5 +58,5 @@ See [The WPILib/RobotPy docs](https://docs.wpilib.org/en/stable/docs/software/py
|
||||
|
||||
In cases where you want to test a specific version of PhotonLib, make sure you have finished the steps in Online Install - Java/C++ and then manually change the version string in the PhotonLib vendordep json file(at ``/path/to/your/project/vendordep/photonlib.json``) to your desired version.
|
||||
|
||||
```{image} images/photonlib-vendordep-json.png
|
||||
```{image} images/photonlib-vendordep-json.jpg
|
||||
```
|
||||
|
||||
@@ -4,17 +4,17 @@ You can control the vision LEDs of supported hardware via PhotonLib using the `s
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
.. code-block:: Java
|
||||
.. code-block:: java
|
||||
|
||||
// Blink the LEDs.
|
||||
camera.setLED(VisionLEDMode.kBlink);
|
||||
|
||||
.. code-block:: C++
|
||||
.. code-block:: c++
|
||||
|
||||
// Blink the LEDs.
|
||||
camera.SetLED(photonlib::VisionLEDMode::kBlink);
|
||||
|
||||
.. code-block:: Python
|
||||
.. code-block:: python
|
||||
|
||||
# Coming Soon!
|
||||
```
|
||||
|
||||
@@ -9,17 +9,17 @@ You can use the `setDriverMode()`/`SetDriverMode()` (Java and C++ respectively)
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
|
||||
.. code-block:: Java
|
||||
.. code-block:: java
|
||||
|
||||
// Set driver mode to on.
|
||||
camera.setDriverMode(true);
|
||||
|
||||
.. code-block:: C++
|
||||
.. code-block:: c++
|
||||
|
||||
// Set driver mode to on.
|
||||
camera.SetDriverMode(true);
|
||||
|
||||
.. code-block:: Python
|
||||
.. code-block:: python
|
||||
|
||||
# Coming Soon!
|
||||
```
|
||||
@@ -31,17 +31,17 @@ You can use the `setPipelineIndex()`/`SetPipelineIndex()` (Java and C++ respecti
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
|
||||
.. code-block:: Java
|
||||
.. code-block:: java
|
||||
|
||||
// Change pipeline to 2
|
||||
camera.setPipelineIndex(2);
|
||||
|
||||
.. code-block:: C++
|
||||
.. code-block:: c++
|
||||
|
||||
// Change pipeline to 2
|
||||
camera.SetPipelineIndex(2);
|
||||
|
||||
.. code-block:: Python
|
||||
.. code-block:: python
|
||||
|
||||
# Coming Soon!
|
||||
```
|
||||
@@ -52,17 +52,17 @@ You can also get the pipeline latency from a pipeline result using the `getLaten
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
.. code-block:: Java
|
||||
.. code-block:: java
|
||||
|
||||
// Get the pipeline latency.
|
||||
double latencySeconds = result.getLatencyMillis() / 1000.0;
|
||||
|
||||
.. code-block:: C++
|
||||
.. code-block:: c++
|
||||
|
||||
// Get the pipeline latency.
|
||||
units::second_t latency = result.GetLatency();
|
||||
|
||||
.. code-block:: Python
|
||||
.. code-block:: python
|
||||
|
||||
# Coming Soon!
|
||||
```
|
||||
|
||||
@@ -20,7 +20,7 @@ The `PhotonCamera` class has two constructors: one that takes a `NetworkTable` a
|
||||
:language: c++
|
||||
:lines: 42-43
|
||||
|
||||
.. code-block:: Python
|
||||
.. code-block:: python
|
||||
|
||||
# Change this to match the name of your camera as shown in the web ui
|
||||
self.camera = PhotonCamera("your_camera_name_here")
|
||||
@@ -51,7 +51,7 @@ Use the `getLatestResult()`/`GetLatestResult()` (Java and C++ respectively) to o
|
||||
:language: c++
|
||||
:lines: 35-36
|
||||
|
||||
.. code-block:: Python
|
||||
.. code-block:: python
|
||||
|
||||
# Query the latest result from PhotonVision
|
||||
result = self.camera.getLatestResult()
|
||||
@@ -69,24 +69,24 @@ Each pipeline result has a `hasTargets()`/`HasTargets()` (Java and C++ respectiv
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
.. code-block:: Java
|
||||
.. code-block:: java
|
||||
|
||||
// Check if the latest result has any targets.
|
||||
boolean hasTargets = result.hasTargets();
|
||||
|
||||
.. code-block:: C++
|
||||
.. code-block:: c++
|
||||
|
||||
// Check if the latest result has any targets.
|
||||
bool hasTargets = result.HasTargets();
|
||||
|
||||
.. code-block:: Python
|
||||
.. code-block:: python
|
||||
|
||||
# Check if the latest result has any targets.
|
||||
hasTargets = result.hasTargets()
|
||||
```
|
||||
|
||||
:::{warning}
|
||||
In Java/C++, You must *always* check if the result has a target via `hasTargets()`/`HasTargets()` before getting targets or else you may get a null pointer exception. Further, you must use the same result in every subsequent call in that loop.
|
||||
In Java/C++, You must _always_ check if the result has a target via `hasTargets()`/`HasTargets()` before getting targets or else you may get a null pointer exception. Further, you must use the same result in every subsequent call in that loop.
|
||||
:::
|
||||
|
||||
## Getting a List of Targets
|
||||
@@ -99,17 +99,17 @@ You can get a list of tracked targets using the `getTargets()`/`GetTargets()` (J
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
.. code-block:: Java
|
||||
.. code-block:: java
|
||||
|
||||
// Get a list of currently tracked targets.
|
||||
List<PhotonTrackedTarget> targets = result.getTargets();
|
||||
|
||||
.. code-block:: C++
|
||||
.. code-block:: c++
|
||||
|
||||
// Get a list of currently tracked targets.
|
||||
wpi::ArrayRef<photonlib::PhotonTrackedTarget> targets = result.GetTargets();
|
||||
|
||||
.. code-block:: Python
|
||||
.. code-block:: python
|
||||
|
||||
# Get a list of currently tracked targets.
|
||||
targets = result.getTargets()
|
||||
@@ -121,18 +121,18 @@ You can get the {ref}`best target <docs/reflectiveAndShape/contour-filtering:Con
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
.. code-block:: Java
|
||||
.. code-block:: java
|
||||
|
||||
// Get the current best target.
|
||||
PhotonTrackedTarget target = result.getBestTarget();
|
||||
|
||||
.. code-block:: C++
|
||||
.. code-block:: c++
|
||||
|
||||
// Get the current best target.
|
||||
photonlib::PhotonTrackedTarget target = result.GetBestTarget();
|
||||
|
||||
|
||||
.. code-block:: Python
|
||||
.. code-block:: python
|
||||
|
||||
# Coming Soon!
|
||||
|
||||
@@ -140,7 +140,7 @@ You can get the {ref}`best target <docs/reflectiveAndShape/contour-filtering:Con
|
||||
|
||||
## Getting Data From A Target
|
||||
|
||||
- double `getYaw()`/`GetYaw()`: The yaw of the target in degrees (positive right).
|
||||
- double `getYaw()`/`GetYaw()`: The yaw of the target in degrees (positive left).
|
||||
- double `getPitch()`/`GetPitch()`: The pitch of the target in degrees (positive up).
|
||||
- double `getArea()`/`GetArea()`: The area (how much of the camera feed the bounding box takes up) as a percent (0-100).
|
||||
- double `getSkew()`/`GetSkew()`: The skew of the target in degrees (counter-clockwise positive).
|
||||
@@ -149,7 +149,7 @@ You can get the {ref}`best target <docs/reflectiveAndShape/contour-filtering:Con
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
.. code-block:: Java
|
||||
.. code-block:: java
|
||||
|
||||
// Get information from target.
|
||||
double yaw = target.getYaw();
|
||||
@@ -159,7 +159,7 @@ You can get the {ref}`best target <docs/reflectiveAndShape/contour-filtering:Con
|
||||
Transform2d pose = target.getCameraToTarget();
|
||||
List<TargetCorner> corners = target.getCorners();
|
||||
|
||||
.. code-block:: C++
|
||||
.. code-block:: c++
|
||||
|
||||
// Get information from target.
|
||||
double yaw = target.GetYaw();
|
||||
@@ -169,7 +169,7 @@ You can get the {ref}`best target <docs/reflectiveAndShape/contour-filtering:Con
|
||||
frc::Transform2d pose = target.GetCameraToTarget();
|
||||
wpi::SmallVector<std::pair<double, double>, 4> corners = target.GetCorners();
|
||||
|
||||
.. code-block:: Python
|
||||
.. code-block:: python
|
||||
|
||||
# Get information from target.
|
||||
yaw = target.getYaw()
|
||||
@@ -193,7 +193,7 @@ All of the data above (**except skew**) is available when using AprilTags.
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
.. code-block:: Java
|
||||
.. code-block:: java
|
||||
|
||||
// Get information from target.
|
||||
int targetID = target.getFiducialId();
|
||||
@@ -201,7 +201,7 @@ All of the data above (**except skew**) is available when using AprilTags.
|
||||
Transform3d bestCameraToTarget = target.getBestCameraToTarget();
|
||||
Transform3d alternateCameraToTarget = target.getAlternateCameraToTarget();
|
||||
|
||||
.. code-block:: C++
|
||||
.. code-block:: c++
|
||||
|
||||
// Get information from target.
|
||||
int targetID = target.GetFiducialId();
|
||||
@@ -209,7 +209,7 @@ All of the data above (**except skew**) is available when using AprilTags.
|
||||
frc::Transform3d bestCameraToTarget = target.getBestCameraToTarget();
|
||||
frc::Transform3d alternateCameraToTarget = target.getAlternateCameraToTarget();
|
||||
|
||||
.. code-block:: Python
|
||||
.. code-block:: python
|
||||
|
||||
# Get information from target.
|
||||
targetID = target.getFiducialId()
|
||||
@@ -227,7 +227,7 @@ Images are stored within the PhotonVision configuration directory. Running the "
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
|
||||
.. code-block:: Java
|
||||
.. code-block:: java
|
||||
|
||||
// Capture pre-process camera stream image
|
||||
camera.takeInputSnapshot();
|
||||
@@ -235,7 +235,7 @@ Images are stored within the PhotonVision configuration directory. Running the "
|
||||
// Capture post-process camera stream image
|
||||
camera.takeOutputSnapshot();
|
||||
|
||||
.. code-block:: C++
|
||||
.. code-block:: c++
|
||||
|
||||
// Capture pre-process camera stream image
|
||||
camera.TakeInputSnapshot();
|
||||
@@ -243,7 +243,7 @@ Images are stored within the PhotonVision configuration directory. Running the "
|
||||
// Capture post-process camera stream image
|
||||
camera.TakeOutputSnapshot();
|
||||
|
||||
.. code-block:: Python
|
||||
.. code-block:: python
|
||||
|
||||
# Capture pre-process camera stream image
|
||||
camera.takeInputSnapshot()
|
||||
|
||||
|
Before Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 128 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 357 KiB After Width: | Height: | Size: 357 KiB |
|
After Width: | Height: | Size: 98 KiB |
@@ -4,30 +4,46 @@
|
||||
For more information on how to methods to get AprilTag data, look {ref}`here <docs/programming/photonlib/getting-target-data:Getting AprilTag Data From A Target>`.
|
||||
:::
|
||||
|
||||
PhotonLib includes a `PhotonPoseEstimator` class, which allows you to combine the pose data from all tags in view in order to get a field relative pose. The `PhotonPoseEstimator` class works with one camera per object instance, but more than one instance may be created.
|
||||
PhotonLib includes a `PhotonPoseEstimator` class, which allows you to combine the pose data from all tags in view in order to get a field relative pose. For each camera, a separate instance of the `PhotonPoseEstimator` class should be created.
|
||||
|
||||
## Creating an `AprilTagFieldLayout`
|
||||
|
||||
`AprilTagFieldLayout` is used to represent a layout of AprilTags within a space (field, shop at home, classroom, etc.). WPILib provides a JSON that describes the layout of AprilTags on the field which you can then use in the AprilTagFieldLayout constructor. You can also specify a custom layout.
|
||||
|
||||
The API documentation can be found in here: [Java](https://github.wpilib.org/allwpilib/docs/release/java/edu/wpi/first/apriltag/AprilTagFieldLayout.html) and [C++](https://github.wpilib.org/allwpilib/docs/release/cpp/classfrc_1_1_april_tag_field_layout.html).
|
||||
The API documentation can be found in here: [Java](https://github.wpilib.org/allwpilib/docs/release/java/edu/wpi/first/apriltag/AprilTagFieldLayout.html), [C++](https://github.wpilib.org/allwpilib/docs/release/cpp/classfrc_1_1_april_tag_field_layout.html), and [Python](https://robotpy.readthedocs.io/projects/apriltag/en/stable/robotpy_apriltag/AprilTagFieldLayout.html#robotpy_apriltag.AprilTagFieldLayout).
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
.. code-block:: Java
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/refs/heads/main/photonlib-java-examples/poseest/src/main/java/frc/robot/Constants.java
|
||||
:language: java
|
||||
:lines: 48-49
|
||||
|
||||
// The field from AprilTagFields will be different depending on the game.
|
||||
AprilTagFieldLayout aprilTagFieldLayout = AprilTagFieldLayout.loadField(AprilTagFields.kDefaultField);
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/refs/heads/main/photonlib-cpp-examples/poseest/src/main/include/Constants.h
|
||||
:language: c++
|
||||
:lines: 46-47
|
||||
|
||||
.. code-block:: C++
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/refs/heads/main/photonlib-python-examples/poseest/robot.py
|
||||
:language: python
|
||||
:lines: 46
|
||||
```
|
||||
|
||||
// The parameter for LoadAPrilTagLayoutField will be different depending on the game.
|
||||
frc::AprilTagFieldLayout aprilTagFieldLayout = frc::LoadAprilTagLayoutField(frc::AprilTagField::kDefaultField);
|
||||
## Defining the Robot to Camera `Transform3d`
|
||||
|
||||
.. code-block:: Python
|
||||
Another necessary argument for creating a `PhotonPoseEstimator` is the `Transform3d` representing the robot-relative location and orientation of the camera. A `Transform3d` contains a `Translation3d` and a `Rotation3d`. The `Translation3d` is created in meters and the `Rotation3d` is created with radians. For more information on the coordinate system, please see the {ref}`Coordinate Systems <docs/apriltag-pipelines/coordinate-systems:Coordinate Systems>` documentation.
|
||||
|
||||
# Coming Soon!
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/refs/heads/main/photonlib-java-examples/poseest/src/main/java/frc/robot/Constants.java
|
||||
:language: java
|
||||
:lines: 44-45
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/refs/heads/main/photonlib-cpp-examples/poseest/src/main/include/Constants.h
|
||||
:language: c++
|
||||
:lines: 43-45
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/refs/heads/main/photonlib-python-examples/poseest/robot.py
|
||||
:language: python
|
||||
:lines: 33-36
|
||||
```
|
||||
|
||||
## Creating a `PhotonPoseEstimator`
|
||||
@@ -35,127 +51,116 @@ The API documentation can be found in here: [Java](https://github.wpilib.org/all
|
||||
The PhotonPoseEstimator has a constructor that takes an `AprilTagFieldLayout` (see above), `PoseStrategy`, `PhotonCamera`, and `Transform3d`. `PoseStrategy` has nine possible values:
|
||||
|
||||
- MULTI_TAG_PNP_ON_COPROCESSOR
|
||||
- Calculates a new robot position estimate by combining all visible tag corners. Recommended for all teams as it will be the most accurate.
|
||||
- Must configure the AprilTagFieldLayout properly in the UI, please see {ref}`here <docs/apriltag-pipelines/multitag:multitag localization>` for more information.
|
||||
- Calculates a new robot position estimate by combining all visible tag corners. Recommended for all teams as it will be the most accurate.
|
||||
- Must configure the AprilTagFieldLayout properly in the UI, please see {ref}`here <docs/apriltag-pipelines/multitag:multitag localization>` for more information.
|
||||
- LOWEST_AMBIGUITY
|
||||
- Choose the Pose with the lowest ambiguity.
|
||||
- Choose the Pose with the lowest ambiguity.
|
||||
- CLOSEST_TO_CAMERA_HEIGHT
|
||||
- Choose the Pose which is closest to the camera height.
|
||||
- Choose the Pose which is closest to the camera height.
|
||||
- CLOSEST_TO_REFERENCE_POSE
|
||||
- Choose the Pose which is closest to the pose from setReferencePose().
|
||||
- Choose the Pose which is closest to the pose from setReferencePose().
|
||||
- CLOSEST_TO_LAST_POSE
|
||||
- Choose the Pose which is closest to the last pose calculated.
|
||||
- Choose the Pose which is closest to the last pose calculated.
|
||||
- AVERAGE_BEST_TARGETS
|
||||
- Choose the Pose which is the average of all the poses from each tag.
|
||||
- Choose the Pose which is the average of all the poses from each tag.
|
||||
- MULTI_TAG_PNP_ON_RIO
|
||||
- A slower, older version of MULTI_TAG_PNP_ON_COPROCESSOR, not recommended for use.
|
||||
- A slower, older version of MULTI_TAG_PNP_ON_COPROCESSOR, not recommended for use.
|
||||
- PNP_DISTANCE_TRIG_SOLVE
|
||||
- Use distance data from best visible tag to compute a Pose. This runs on the RoboRIO in order
|
||||
to access the robot's yaw heading, and MUST have addHeadingData called every frame so heading
|
||||
data is up-to-date. Based on a reference implementation by [FRC Team 6328 Mechanical Advantage](https://www.chiefdelphi.com/t/frc-6328-mechanical-advantage-2025-build-thread/477314/98).
|
||||
- Use distance data from best visible tag to compute a Pose. This runs on the RoboRIO in order
|
||||
to access the robot's yaw heading, and MUST have addHeadingData called every frame so heading
|
||||
data is up-to-date. Based on a reference implementation by [FRC Team 6328 Mechanical Advantage](https://www.chiefdelphi.com/t/frc-6328-mechanical-advantage-2025-build-thread/477314/98).
|
||||
- CONSTRAINED_SOLVEPNP
|
||||
- Solve a constrained version of the Perspective-n-Point problem with the robot's drivebase
|
||||
flat on the floor. This computation takes place on the RoboRIO, and should not take more than 2ms.
|
||||
This also requires addHeadingData to be called every frame so heading data is up to date.
|
||||
If Multi-Tag PNP is enabled on the coprocessor, it will be used to provide an initial seed to
|
||||
the optimization algorithm -- otherwise, the multi-tag fallback strategy will be used as the
|
||||
seed.
|
||||
- Solve a constrained version of the Perspective-n-Point problem with the robot's drivebase
|
||||
flat on the floor. This computation takes place on the RoboRIO, and should not take more than 2ms.
|
||||
This also requires addHeadingData to be called every frame so heading data is up to date.
|
||||
If Multi-Tag PNP is enabled on the coprocessor, it will be used to provide an initial seed to
|
||||
the optimization algorithm -- otherwise, the multi-tag fallback strategy will be used as the
|
||||
seed.
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
.. code-block:: Java
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/refs/heads/main/photonlib-java-examples/poseest/src/main/java/frc/robot/Vision.java
|
||||
:language: java
|
||||
:lines: 65-66
|
||||
|
||||
//Forward Camera
|
||||
cam = new PhotonCamera("testCamera");
|
||||
Transform3d robotToCam = new Transform3d(new Translation3d(0.5, 0.0, 0.5), new Rotation3d(0,0,0)); //Cam mounted facing forward, half a meter forward of center, half a meter up from center.
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/refs/heads/main/photonlib-cpp-examples/poseest/src/main/include/Vision.h
|
||||
:language: c++
|
||||
:lines: 150-153
|
||||
|
||||
// Construct PhotonPoseEstimator
|
||||
PhotonPoseEstimator photonPoseEstimator = new PhotonPoseEstimator(aprilTagFieldLayout, PoseStrategy.CLOSEST_TO_REFERENCE_POSE, cam, robotToCam);
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
// Forward Camera
|
||||
std::shared_ptr<photonlib::PhotonCamera> cameraOne =
|
||||
std::make_shared<photonlib::PhotonCamera>("testCamera");
|
||||
// Camera is mounted facing forward, half a meter forward of center, half a
|
||||
// meter up from center.
|
||||
frc::Transform3d robotToCam =
|
||||
frc::Transform3d(frc::Translation3d(0.5_m, 0_m, 0.5_m),
|
||||
frc::Rotation3d(0_rad, 0_rad, 0_rad));
|
||||
|
||||
// ... Add other cameras here
|
||||
|
||||
// Assemble the list of cameras & mount locations
|
||||
std::vector<
|
||||
std::pair<std::shared_ptr<photonlib::PhotonCamera>, frc::Transform3d>>
|
||||
cameras;
|
||||
cameras.push_back(std::make_pair(cameraOne, robotToCam));
|
||||
|
||||
photonlib::RobotPoseEstimator estimator(
|
||||
aprilTags, photonlib::CLOSEST_TO_REFERENCE_POSE, cameras);
|
||||
|
||||
.. code-block:: Python
|
||||
|
||||
kRobotToCam = wpimath.geometry.Transform3d(
|
||||
wpimath.geometry.Translation3d(0.5, 0.0, 0.5),
|
||||
wpimath.geometry.Rotation3d.fromDegrees(0.0, -30.0, 0.0),
|
||||
)
|
||||
|
||||
self.cam = PhotonCamera("YOUR CAMERA NAME")
|
||||
|
||||
self.camPoseEst = PhotonPoseEstimator(
|
||||
loadAprilTagLayoutField(AprilTagField.kDefaultField),
|
||||
PoseStrategy.CLOSEST_TO_REFERENCE_POSE,
|
||||
self.cam,
|
||||
kRobotToCam
|
||||
)
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/refs/heads/main/photonlib-python-examples/poseest/robot.py
|
||||
:language: python
|
||||
:lines: 45-50
|
||||
```
|
||||
|
||||
:::{note}
|
||||
Python still takes a `PhotonCamera` in the constructor, so you must create the camera as shown in the next section and then return and use it to create the `PhotonPoseEstimator`.
|
||||
:::
|
||||
|
||||
## Using a `PhotonPoseEstimator`
|
||||
|
||||
Calling `update()` on your `PhotonPoseEstimator` will return an `EstimatedRobotPose`, which includes a `Pose3d` of the latest estimated pose (using the selected strategy) along with a `double` of the timestamp when the robot pose was estimated. You should be updating your [drivetrain pose estimator](https://docs.wpilib.org/en/latest/docs/software/advanced-controls/state-space/state-space-pose-estimators.html) with the result from the `PhotonPoseEstimator` every loop using `addVisionMeasurement()`.
|
||||
The final prerequisite to using your `PhotonPoseEstimator` is creating a `PhotonCamera`. To do this, you must set the name of your camera in Photon Client. From there you can define the camera in code.
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/357d8a518a93f7a1f8084a79449249e613b605a7/photonlib-java-examples/apriltagExample/src/main/java/frc/robot/PhotonCameraWrapper.java
|
||||
:language: java
|
||||
:lines: 85-88
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
std::pair<frc::Pose2d, units::millisecond_t> getEstimatedGlobalPose(
|
||||
frc::Pose3d prevEstimatedRobotPose) {
|
||||
robotPoseEstimator.SetReferencePose(prevEstimatedRobotPose);
|
||||
units::millisecond_t currentTime = frc::Timer::GetFPGATimestamp();
|
||||
auto result = robotPoseEstimator.Update();
|
||||
if (result.second) {
|
||||
return std::make_pair<>(result.first.ToPose2d(),
|
||||
currentTime - result.second);
|
||||
} else {
|
||||
return std::make_pair(frc::Pose2d(), 0_ms);
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: Python
|
||||
|
||||
# Coming Soon!
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/refs/heads/main/photonlib-java-examples/poseest/src/main/java/frc/robot/Vision.java
|
||||
:language: java
|
||||
:lines: 63
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/refs/heads/main/photonlib-cpp-examples/aimattarget/src/main/include/Robot.h
|
||||
:language: c++
|
||||
:lines: 55
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/refs/heads/main/photonlib-python-examples/poseest/robot.py
|
||||
:language: python
|
||||
:lines: 44
|
||||
```
|
||||
|
||||
You should be updating your [drivetrain pose estimator](https://docs.wpilib.org/en/latest/docs/software/advanced-controls/state-space/state-space-pose-estimators.html) with the result from the `RobotPoseEstimator` every loop using `addVisionMeasurement()`. TODO: add example note
|
||||
Calling `update()` on your `PhotonPoseEstimator` will return an `EstimatedRobotPose`, which includes a `Pose3d` of the latest estimated pose (using the selected strategy) along with a `double` of the timestamp when the robot pose was estimated.
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/refs/heads/main/photonlib-java-examples/poseest/src/main/java/frc/robot/Vision.java
|
||||
:language: java
|
||||
:lines: 93-116
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/refs/heads/main/photonlib-cpp-examples/poseest/src/main/include/Vision.h
|
||||
:language: c++
|
||||
:lines: 80-100
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/refs/heads/main/photonlib-python-examples/poseest/robot.py
|
||||
:language: python
|
||||
:lines: 53
|
||||
```
|
||||
|
||||
You should be updating your [drivetrain pose estimator](https://docs.wpilib.org/en/latest/docs/software/advanced-controls/state-space/state-space-pose-estimators.html) with the result from the `PhotonPoseEstimator` every loop using `addVisionMeasurement()`.
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/refs/heads/main/photonlib-java-examples/poseest/src/main/java/frc/robot/Robot.java
|
||||
:language: java
|
||||
:lines: 49
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/refs/heads/main/photonlib-cpp-examples/poseest/src/main/include/Robot.h
|
||||
:language: c++
|
||||
:lines: 54-57
|
||||
|
||||
.. rli:: https://raw.githubusercontent.com/PhotonVision/photonvision/refs/heads/main/photonlib-python-examples/poseest/robot.py
|
||||
:language: python
|
||||
:lines: 54-57
|
||||
```
|
||||
|
||||
## Complete Examples
|
||||
|
||||
The complete examples for the `PhotonPoseEstimator` can be found in the following locations:
|
||||
|
||||
- [Java](https://github.com/PhotonVision/photonvision/tree/main/photonlib-java-examples/poseest)
|
||||
- [C++](https://github.com/PhotonVision/photonvision/tree/main/photonlib-cpp-examples/poseest)
|
||||
- [Python](https://github.com/PhotonVision/photonvision/tree/main/photonlib-python-examples/poseest)
|
||||
|
||||
## Additional `PhotonPoseEstimator` Methods
|
||||
|
||||
### `setReferencePose(Pose3d referencePose)`
|
||||
For more information on the `PhotonPoseEstimator` class, please see the API documentation.
|
||||
|
||||
Updates the stored reference pose when using the CLOSEST_TO_REFERENCE_POSE strategy.
|
||||
|
||||
### `setLastPose(Pose3d lastPose)`
|
||||
|
||||
Update the stored last pose. Useful for setting the initial estimate when using the CLOSEST_TO_LAST_POSE strategy.
|
||||
|
||||
### `addHeadingData(double timestampSeconds, Rotation2d heading)`
|
||||
|
||||
Adds robot heading data to be stored in buffer. Must be called periodically with a proper timestamp for the PNP_DISTANCE_TRIG_SOLVE and CONSTRAINED_SOLVEPNP strategies
|
||||
- [Java Documentation](https://javadocs.photonvision.org/release/org/photonvision/PhotonPoseEstimator.html)
|
||||
- [C++ Documentation](https://cppdocs.photonvision.org/release/classphoton_1_1_photon_pose_estimator.html)
|
||||
- [Python Documentation](https://pydocs.photonvision.org/release/reference/photonPoseEstimator/)
|
||||
|
||||
@@ -8,17 +8,17 @@ A `PhotonUtils` class with helpful common calculations is included within `Photo
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
.. code-block:: Java
|
||||
.. code-block:: java
|
||||
|
||||
// Calculate robot's field relative pose
|
||||
if (aprilTagFieldLayout.getTagPose(target.getFiducialId()).isPresent()) {
|
||||
Pose3d robotPose = PhotonUtils.estimateFieldToRobotAprilTag(target.getBestCameraToTarget(), aprilTagFieldLayout.getTagPose(target.getFiducialId()).get(), cameraToRobot);
|
||||
}
|
||||
.. code-block:: C++
|
||||
.. code-block:: c++
|
||||
|
||||
//TODO
|
||||
|
||||
.. code-block:: Python
|
||||
.. code-block:: python
|
||||
|
||||
# Coming Soon!
|
||||
```
|
||||
@@ -29,19 +29,19 @@ You can get your robot's `Pose2D` on the field using various camera data, target
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
.. code-block:: Java
|
||||
.. code-block:: java
|
||||
|
||||
// Calculate robot's field relative pose
|
||||
Pose2D robotPose = PhotonUtils.estimateFieldToRobot(
|
||||
kCameraHeight, kTargetHeight, kCameraPitch, kTargetPitch, Rotation2d.fromDegrees(-target.getYaw()), gyro.getRotation2d(), targetPose, cameraToRobot);
|
||||
|
||||
.. code-block:: C++
|
||||
.. code-block:: c++
|
||||
|
||||
// Calculate robot's field relative pose
|
||||
frc::Pose2D robotPose = photonlib::EstimateFieldToRobot(
|
||||
kCameraHeight, kTargetHeight, kCameraPitch, kTargetPitch, frc::Rotation2d(units::degree_t(-target.GetYaw())), frc::Rotation2d(units::degree_t(gyro.GetRotation2d)), targetPose, cameraToRobot);
|
||||
|
||||
.. code-block:: Python
|
||||
.. code-block:: python
|
||||
|
||||
# Coming Soon!
|
||||
|
||||
@@ -54,15 +54,15 @@ If your camera is at a fixed height on your robot and the height of the target i
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
|
||||
.. code-block:: Java
|
||||
.. code-block:: java
|
||||
|
||||
// TODO
|
||||
|
||||
.. code-block:: C++
|
||||
.. code-block:: c++
|
||||
|
||||
// TODO
|
||||
|
||||
.. code-block:: Python
|
||||
.. code-block:: python
|
||||
|
||||
# Coming Soon!
|
||||
|
||||
@@ -78,15 +78,15 @@ The C++ version of PhotonLib uses the Units library. For more information, see [
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
.. code-block:: Java
|
||||
.. code-block:: java
|
||||
|
||||
double distanceToTarget = PhotonUtils.getDistanceToPose(robotPose, targetPose);
|
||||
|
||||
.. code-block:: C++
|
||||
.. code-block:: c++
|
||||
|
||||
//TODO
|
||||
|
||||
.. code-block:: Python
|
||||
.. code-block:: python
|
||||
|
||||
# Coming Soon!
|
||||
```
|
||||
@@ -97,19 +97,19 @@ You can get a [translation](https://docs.wpilib.org/en/latest/docs/software/adva
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
.. code-block:: Java
|
||||
.. code-block:: java
|
||||
|
||||
// Calculate a translation from the camera to the target.
|
||||
Translation2d translation = PhotonUtils.estimateCameraToTargetTranslation(
|
||||
distanceMeters, Rotation2d.fromDegrees(-target.getYaw()));
|
||||
|
||||
.. code-block:: C++
|
||||
.. code-block:: c++
|
||||
|
||||
// Calculate a translation from the camera to the target.
|
||||
frc::Translation2d translation = photonlib::PhotonUtils::EstimateCameraToTargetTranslation(
|
||||
distance, frc::Rotation2d(units::degree_t(-target.GetYaw())));
|
||||
|
||||
.. code-block:: Python
|
||||
.. code-block:: python
|
||||
|
||||
# Coming Soon!
|
||||
|
||||
@@ -125,14 +125,14 @@ We are negating the yaw from the camera from CV (computer vision) conventions to
|
||||
|
||||
```{eval-rst}
|
||||
.. tab-set-code::
|
||||
.. code-block:: Java
|
||||
.. code-block:: java
|
||||
|
||||
Rotation2d targetYaw = PhotonUtils.getYawToPose(robotPose, targetPose);
|
||||
.. code-block:: C++
|
||||
.. code-block:: c++
|
||||
|
||||
//TODO
|
||||
|
||||
.. code-block:: Python
|
||||
.. code-block:: python
|
||||
|
||||
# Coming Soon!
|
||||
```
|
||||
|
||||
41
docs/source/docs/quick-start/camera-matching.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Camera Matching
|
||||
|
||||
## Activating and Deactivating Cameras
|
||||
|
||||
When you first plug in a camera, it will be detected and added to the list of cameras with the "Unassigned" status, as shown below. You can press the "Activate" button to enable PhotonVision to use the camera.
|
||||
|
||||
```{image} images/camera-matching/unassigned-camera.png
|
||||
:scale: 50%
|
||||
```
|
||||
|
||||
If a camera has been activated in the past, it will be listed as "Deactivated" in the camera list. You can press the "Activate" button to enable PhotonVision to use the camera.
|
||||
|
||||
```{image} images/camera-matching/deactivated-camera.png
|
||||
:scale: 50%
|
||||
```
|
||||
|
||||
Once a camera is activated, it will be listed as "Active" in the camera list. You can press the "Deactivate" button to stop PhotonVision from using the camera.
|
||||
|
||||
```{image} images/camera-matching/activated-camera.png
|
||||
:scale: 50%
|
||||
```
|
||||
|
||||
## Deleting Cameras
|
||||
|
||||
If you want to remove a camera from the list, you can press the delete button. This will clear all settings for that particular camera, including the calibration data and any other settings you have configured. It is recommended to make a backup of the camera's settings before deleting it, as this action cannot be undone.
|
||||
|
||||
## Matching Cameras
|
||||
|
||||
When you plug in a camera, PhotonVision will attempt to match it to a previously configured camera based on the physical USB port it is connected to. If you plug another camera into that port, the cameras will have a "Camera Mismatch" status, indicating that the camera is not recognized as the one that was previously configured.
|
||||
|
||||
Additionally, pressing on the Details button will show you the details of the camera mismatch, allowing you to compare the current camera with the previously configured camera.
|
||||
|
||||
```{image} images/camera-matching/camera-mismatch-details.png
|
||||
:scale: 50%
|
||||
```
|
||||
|
||||
```{note}
|
||||
Camera matching is based on the USB ports on the device. If you unplug a camera and plug it into a different port, PhotonVision will attempt to use settings from the camera that was previously configured in that port, causing unexpected behavior.
|
||||
```
|
||||
|
||||
To resolve the camera mismatch, you should ensure each camera is plugged into the same port that you configured it in.
|
||||