diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 000000000..60f72803a --- /dev/null +++ b/.github/labeler.yml @@ -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/** diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index a03b1d1c6..704a41b1a 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -13,6 +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 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 84d5e5f85..497bac00b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -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: 22 - - 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,11 +582,12 @@ 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 **/*linux*.jar @@ -562,38 +595,12 @@ jobs: **/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') diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 000000000..526323cea --- /dev/null +++ b/.github/workflows/labeler.yml @@ -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 diff --git a/.github/workflows/lint-format.yml b/.github/workflows/lint-format.yml index 39e475930..350bf3886 100644 --- a/.github/workflows/lint-format.yml +++ b/.github/workflows/lint-format.yml @@ -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==2025.33 + 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: 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 diff --git a/.github/workflows/photon-api-docs.yml b/.github/workflows/photon-api-docs.yml index 0f3de5cae..17ea98cce 100644 --- a/.github/workflows/photon-api-docs.yml +++ b/.github/workflows/photon-api-docs.yml @@ -3,12 +3,7 @@ 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: - branches: [ main ] - tags: - - 'v*' pull_request: - branches: [ main ] - merge_group: concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} @@ -21,6 +16,12 @@ permissions: 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: @@ -29,14 +30,20 @@ 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: 22 + cache: pnpm + cache-dependency-path: photon-client/pnpm-lock.yaml - name: Install Dependencies - run: npm ci + run: pnpm i --frozen-lockfile - name: Build Production Client - run: npm run build-demo + run: pnpm run build-demo - uses: actions/upload-artifact@v4 with: name: demo @@ -44,6 +51,7 @@ jobs: run_java_cpp_docs: name: Build Java and C++ API Docs + needs: [validation] runs-on: "ubuntu-22.04" steps: - name: Checkout code diff --git a/.github/workflows/photonvision-rtd.yml b/.github/workflows/photonvision-rtd.yml index ed9e8f2ec..7f02b87c2 100644 --- a/.github/workflows/photonvision-rtd.yml +++ b/.github/workflows/photonvision-rtd.yml @@ -2,10 +2,7 @@ name: PhotonVision ReadTheDocs Checks on: push: - branches: [ main ] pull_request: - branches: [ main ] - merge_group: concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index c56eb96fd..676e5ed6d 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -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 diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml index ff2acaaa7..d22898140 100644 --- a/.github/workflows/website.yml +++ b/.github/workflows/website.yml @@ -2,13 +2,7 @@ name: Website on: push: - # For now, run on all commits to main - branches: [ main ] - tags: - - 'v*' pull_request: - branches: [ main ] - merge_group: jobs: rsync: @@ -16,13 +10,21 @@ jobs: 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: npm ci + run: pnpm i --frozen-lockfile working-directory: website - name: Build project - run: npm run build + run: pnpm run build working-directory: website - uses: up9cloud/action-rsync@v1.4 if: github.ref == 'refs/heads/main' @@ -38,11 +40,19 @@ jobs: 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: npm ci + run: pnpm i --frozen-lockfile working-directory: website - name: Run Formatting Check - run: npx prettier -c . + run: pnpm prettier -c . working-directory: website diff --git a/.gitignore b/.gitignore index 920c55008..cc7feb687 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,8 @@ __pycache__/ /.vs backend/settings/ -.vscode/ +.vscode/* +!.vscode/settings.json # Docs _build # Compiled class file @@ -150,3 +151,4 @@ components.d.ts # Py docs stuff photon-lib/py/docs/build +photon-server/src/main/resources/web/index.html diff --git a/.python-version b/.python-version new file mode 100644 index 000000000..2c0733315 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.11 diff --git a/.styleguide b/.styleguide index 94517f39b..7259f0408 100644 --- a/.styleguide +++ b/.styleguide @@ -19,6 +19,7 @@ modifiableFileExclude { \.webp$ \.ico$ \.rknn$ + \.tflite$ \.mp4$ \.ttf$ \.woff2$ diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..376e6c941 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true, + "python.testing.cwd": "photon-lib/py" +} \ No newline at end of file diff --git a/README.md b/README.md index fe6ddf617..14e5b7313 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ If you are interested in contributing code or documentation to the project, plea ## 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). @@ -42,6 +42,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` diff --git a/build.gradle b/build.gradle index 3ec1fd50b..1f0d90b7d 100644 --- a/build.gradle +++ b/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,9 +36,10 @@ ext { wpimathVersion = wpilibVersion openCVYear = "2025" openCVversion = "4.10.0-3" - 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"; @@ -101,7 +101,7 @@ spotless { } wrapper { - gradleVersion '8.11' + gradleVersion = '8.14.3' } ext.getCurrentArch = { diff --git a/devTools/calibrationUtils.py b/devTools/calibrationUtils.py index 340a7b982..6d16fe41a 100644 --- a/devTools/calibrationUtils.py +++ b/devTools/calibrationUtils.py @@ -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") diff --git a/docs/.styleguide b/docs/.styleguide index 6236e908d..a3bf6f6ac 100644 --- a/docs/.styleguide +++ b/docs/.styleguide @@ -11,6 +11,7 @@ modifiableFileExclude { \.webp$ \.ico$ \.rknn$ + \.tflite$ \.svg$ \.woff2$ gradlew diff --git a/docs/requirements.txt b/docs/requirements.txt index 9fcfa2fe1..0b5d4d04d 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -24,7 +24,7 @@ pbr==6.1.1 pipreqs==0.5.0 Pygments==2.19.1 PyYAML==6.0.2 -requests==2.32.3 +requests==2.32.4 restructuredtext-lint==1.4.0 roman-numerals-py==3.1.0 setuptools==80.3.1 @@ -49,10 +49,10 @@ sphinxcontrib-qthelp==2.0.0 sphinxcontrib-serializinghtml==2.0.0 sphinxext-opengraph==0.10.0 sphinxext-remoteliteralinclude==0.5.0 -starlette==0.46.2 +starlette==0.47.2 stevedore==5.4.1 typing_extensions==4.13.2 -urllib3==2.4.0 +urllib3==2.5.0 uvicorn==0.34.2 watchfiles==1.0.5 websockets==15.0.1 diff --git a/docs/source/conf.py b/docs/source/conf.py index 77b1669ef..8d4b6b6db 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -30,7 +30,6 @@ extensions = [ "sphinx_rtd_theme", "sphinx.ext.autosectionlabel", "sphinx.ext.todo", - "sphinx_tabs.tabs", "notfound.extension", "sphinxext.remoteliteralinclude", "sphinxext.opengraph", @@ -67,6 +66,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". @@ -144,7 +147,11 @@ 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: diff --git a/docs/source/docs/apriltag-pipelines/multitag.md b/docs/source/docs/apriltag-pipelines/multitag.md index e894b955c..bee81fbb2 100644 --- a/docs/source/docs/apriltag-pipelines/multitag.md +++ b/docs/source/docs/apriltag-pipelines/multitag.md @@ -28,7 +28,7 @@ This multi-target pose estimate can be accessed using PhotonLib. We suggest usin ```{eval-rst} .. tab-set-code:: - .. code-block:: Java + .. code-block:: java var results = camera.getAllUnreadResults(); for (var result : results) { @@ -39,7 +39,7 @@ This multi-target pose estimate can be accessed using PhotonLib. We suggest usin } - .. code-block:: C++ + .. code-block:: c++ auto results = camera.GetAllUnreadResults(); for (auto &result : results) @@ -51,7 +51,7 @@ This multi-target pose estimate can be accessed using PhotonLib. We suggest usin } - .. code-block:: Python + .. code-block:: python results = camera.getAllUnreadResults() for result in results: diff --git a/docs/source/docs/benchmarks/index.md b/docs/source/docs/benchmarks/index.md new file mode 100644 index 000000000..95763b18e --- /dev/null +++ b/docs/source/docs/benchmarks/index.md @@ -0,0 +1,8 @@ +# Performance Benchmarks + +```{toctree} +:maxdepth: 0 +:titlesonly: true + +rknn-model-benchmarks +``` diff --git a/docs/source/docs/benchmarks/rknn-model-benchmarks.md b/docs/source/docs/benchmarks/rknn-model-benchmarks.md new file mode 100644 index 000000000..94395c007 --- /dev/null +++ b/docs/source/docs/benchmarks/rknn-model-benchmarks.md @@ -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. diff --git a/docs/source/docs/camera-specific-configuration/index.md b/docs/source/docs/camera-specific-configuration/index.md index 4881a5720..bee8b9c28 100644 --- a/docs/source/docs/camera-specific-configuration/index.md +++ b/docs/source/docs/camera-specific-configuration/index.md @@ -1,4 +1,4 @@ -# Camera-Specifc Configuration +# Camera-Specific Configuration ```{toctree} :maxdepth: 2 diff --git a/docs/source/docs/contributing/building-photon.md b/docs/source/docs/contributing/building-photon.md index fe0cc8692..b9a296ef8 100644 --- a/docs/source/docs/contributing/building-photon.md +++ b/docs/source/docs/contributing/building-photon.md @@ -12,7 +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 22.15.0 is required. To install Node JS follow the instructions for your platform [on the official Node JS website](https://nodejs.org/en/download/). + 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/). + +**pnpm:** + + [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 @@ -36,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 @@ -64,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. @@ -77,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`` ``` @@ -95,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. @@ -117,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`` @@ -147,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`` ``` @@ -197,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. @@ -279,3 +275,9 @@ Using the [GitHub CLI](https://cli.github.com/), we can download artifacts from 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. diff --git a/docs/source/docs/examples/aimandrange.md b/docs/source/docs/examples/aimandrange.md index 417c44a3b..192f3c23e 100644 --- a/docs/source/docs/examples/aimandrange.md +++ b/docs/source/docs/examples/aimandrange.md @@ -14,8 +14,10 @@ To do this, we'll use the _pitch_ of the target in the camera image and trigonom ```{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,6 +44,7 @@ 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 diff --git a/docs/source/docs/examples/aimingatatarget.md b/docs/source/docs/examples/aimingatatarget.md index 45b23b7e4..d00719bda 100644 --- a/docs/source/docs/examples/aimingatatarget.md +++ b/docs/source/docs/examples/aimingatatarget.md @@ -19,8 +19,10 @@ In this example, while the operator holds a button down, the robot will turn tow ```{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 diff --git a/docs/source/docs/examples/poseest.md b/docs/source/docs/examples/poseest.md index 19d24d138..e31d165c5 100644 --- a/docs/source/docs/examples/poseest.md +++ b/docs/source/docs/examples/poseest.md @@ -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. diff --git a/docs/source/docs/integration/advancedStrategies.md b/docs/source/docs/integration/advancedStrategies.md index 54f66f124..1fb3067c8 100644 --- a/docs/source/docs/integration/advancedStrategies.md +++ b/docs/source/docs/integration/advancedStrategies.md @@ -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; diff --git a/docs/source/docs/objectDetection/about-object-detection.md b/docs/source/docs/objectDetection/about-object-detection.md index a155a2f98..3b062c952 100644 --- a/docs/source/docs/objectDetection/about-object-detection.md +++ b/docs/source/docs/objectDetection/about-object-detection.md @@ -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 ` and the {ref}`Rubik Pi 3 `. -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