mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-19 00:41:41 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41dd643746 | ||
|
|
7cec141341 | ||
|
|
ec66645667 | ||
|
|
39aaa34520 | ||
|
|
4a3200d0c0 | ||
|
|
01dc7ea5ce | ||
|
|
2a9502be3d | ||
|
|
39216db143 |
289
.github/workflows/build.yml
vendored
289
.github/workflows/build.yml
vendored
@@ -2,123 +2,14 @@ name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
branches:
|
||||
- master
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
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
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: built-client
|
||||
path: photon-client/dist/
|
||||
build-examples:
|
||||
name: "Build Examples"
|
||||
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
|
||||
# Need to publish to maven local first, so that C++ sim can pick it up
|
||||
# Still haven't figured out how to make the vendordep file be copied before trying to build examples
|
||||
- name: Publish photonlib to maven local
|
||||
run: |
|
||||
chmod +x gradlew
|
||||
./gradlew publishtomavenlocal -x check
|
||||
- name: Build Java examples
|
||||
working-directory: photonlib-java-examples
|
||||
run: |
|
||||
chmod +x gradlew
|
||||
./gradlew copyPhotonlib -x check
|
||||
./gradlew build -x check --max-workers 2
|
||||
- name: Build C++ examples
|
||||
working-directory: photonlib-cpp-examples
|
||||
run: |
|
||||
chmod +x gradlew
|
||||
./gradlew copyPhotonlib -x check
|
||||
./gradlew build -x check --max-workers 2
|
||||
build-gradle:
|
||||
name: "Gradle Build"
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
# Checkout code.
|
||||
- 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@v3
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: temurin
|
||||
- name: Install mrcal deps
|
||||
run: sudo apt-get update && sudo apt-get install -y libcholmod3 liblapack3 libsuitesparseconfig5
|
||||
- name: Gradle Build
|
||||
run: |
|
||||
chmod +x gradlew
|
||||
./gradlew build -x check --max-workers 2
|
||||
- name: Gradle Tests
|
||||
run: ./gradlew testHeadless -i --max-workers 1 --stacktrace
|
||||
- name: Gradle Coverage
|
||||
run: ./gradlew jacocoTestReport --max-workers 1
|
||||
- name: Publish Coverage Report
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
file: ./photon-server/build/reports/jacoco/test/jacocoTestReport.xml
|
||||
- name: Publish Core Coverage Report
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
file: ./photon-core/build/reports/jacoco/test/jacocoTestReport.xml
|
||||
build-offline-docs:
|
||||
name: "Build Offline Docs"
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'PhotonVision/photonvision-docs.git'
|
||||
ref: master
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.9'
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install sphinx sphinx_rtd_theme sphinx-tabs sphinxext-opengraph doc8
|
||||
pip install -r requirements.txt
|
||||
- name: Build the docs
|
||||
run: |
|
||||
make html
|
||||
- uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: built-docs
|
||||
path: build/html
|
||||
build-photonlib-host:
|
||||
env:
|
||||
MACOSX_DEPLOYMENT_TARGET: 12
|
||||
@@ -188,179 +79,3 @@ jobs:
|
||||
env:
|
||||
ARTIFACTORY_API_KEY: ${{ secrets.ARTIFACTORY_API_KEY }}
|
||||
if: github.event_name == 'push'
|
||||
build-package:
|
||||
needs: [build-client, build-gradle, build-offline-docs]
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-latest
|
||||
artifact-name: Win64
|
||||
architecture: x64
|
||||
arch-override: none
|
||||
- os: macos-latest
|
||||
artifact-name: macOS
|
||||
architecture: x64
|
||||
arch-override: none
|
||||
- os: ubuntu-latest
|
||||
artifact-name: Linux
|
||||
architecture: x64
|
||||
arch-override: none
|
||||
- os: macos-latest
|
||||
artifact-name: macOSArm
|
||||
architecture: x64
|
||||
arch-override: macarm64
|
||||
- os: ubuntu-latest
|
||||
artifact-name: LinuxArm32
|
||||
architecture: x64
|
||||
arch-override: linuxarm32
|
||||
- os: ubuntu-latest
|
||||
artifact-name: LinuxArm64
|
||||
architecture: x64
|
||||
arch-override: linuxarm64
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
name: "Build fat JAR - ${{ matrix.artifact-name }}"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Install Java 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: temurin
|
||||
- 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
|
||||
path: photon-server/src/main/resources/web/docs
|
||||
- run: |
|
||||
chmod +x gradlew
|
||||
./gradlew photon-server:shadowJar --max-workers 2 -PArchOverride=${{ matrix.arch-override }}
|
||||
if: ${{ (matrix.arch-override != 'none') }}
|
||||
- run: |
|
||||
chmod +x gradlew
|
||||
./gradlew photon-server:shadowJar --max-workers 2
|
||||
if: ${{ (matrix.arch-override == 'none') }}
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: jar-${{ matrix.artifact-name }}
|
||||
path: photon-server/build/libs
|
||||
build-image:
|
||||
needs: [build-package]
|
||||
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
artifact-name: LinuxArm64
|
||||
image_suffix: RaspberryPi
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/v2024.0.4/photonvision_raspi.img.xz
|
||||
cpu: cortex-a7
|
||||
image_additional_mb: 0
|
||||
- os: ubuntu-latest
|
||||
artifact-name: LinuxArm64
|
||||
image_suffix: limelight2
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/v2024.0.4/photonvision_limelight.img.xz
|
||||
cpu: cortex-a7
|
||||
image_additional_mb: 0
|
||||
- os: ubuntu-latest
|
||||
artifact-name: LinuxArm64
|
||||
image_suffix: limelight3
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/v2024.0.5/photonvision_limelight3.img.xz
|
||||
cpu: cortex-a7
|
||||
image_additional_mb: 0
|
||||
- os: ubuntu-latest
|
||||
artifact-name: LinuxArm64
|
||||
image_suffix: orangepi5
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/v2024.0.6/photonvision_opi5.img.xz
|
||||
cpu: cortex-a8
|
||||
image_additional_mb: 4096
|
||||
- os: ubuntu-latest
|
||||
artifact-name: LinuxArm64
|
||||
image_suffix: orangepi5plus
|
||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/v2024.0.6/photonvision_opi5plus.img.xz
|
||||
cpu: cortex-a8
|
||||
image_additional_mb: 4096
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
name: "Build image - ${{ matrix.image_url }}"
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: jar-${{ matrix.artifact-name }}
|
||||
- uses: pguyot/arm-runner-action@v2
|
||||
name: Generate image
|
||||
id: generate_image
|
||||
with:
|
||||
base_image: ${{ matrix.image_url }}
|
||||
image_additional_mb: ${{ matrix.image_additional_mb }}
|
||||
optimize_image: yes
|
||||
cpu: ${{ matrix.cpu }}
|
||||
# We do _not_ wanna copy photon into the image. Bind mount instead
|
||||
bind_mount_repository: true
|
||||
commands: |
|
||||
chmod +x scripts/armrunner.sh
|
||||
./scripts/armrunner.sh
|
||||
- name: Compress image
|
||||
run: |
|
||||
new_jar=$(realpath $(find . -name photonvision\*-linuxarm64.jar))
|
||||
new_image_name=$(basename "${new_jar/.jar/_${{ matrix.image_suffix }}.img}")
|
||||
mv ${{ steps.generate_image.outputs.image }} $new_image_name
|
||||
sudo xz -T 0 -v $new_image_name
|
||||
- uses: actions/upload-artifact@v4
|
||||
name: Upload image
|
||||
with:
|
||||
name: image-${{ matrix.image_suffix }}
|
||||
path: photonvision*.xz
|
||||
release:
|
||||
needs: [build-package, build-image]
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
# Download literally every single artifact. This also downloads client and docs,
|
||||
# but the filtering below won't pick these up (I hope)
|
||||
- uses: actions/download-artifact@v4
|
||||
- run: find
|
||||
# Push to dev release
|
||||
- uses: pyTooling/Actions/releaser@r0
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
tag: 'Dev'
|
||||
rm: true
|
||||
files: |
|
||||
**/*.xz
|
||||
**/*.jar
|
||||
**/photonlib*.json
|
||||
if: github.event_name == 'push'
|
||||
# Upload all jars and xz archives
|
||||
- uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: |
|
||||
**/*.xz
|
||||
**/*.jar
|
||||
**/photonlib*.json
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
86
.github/workflows/documentation.yml
vendored
86
.github/workflows/documentation.yml
vendored
@@ -1,86 +0,0 @@
|
||||
name: Documentation
|
||||
|
||||
on:
|
||||
push:
|
||||
# For now, run on all commits to master
|
||||
branches: [ master ]
|
||||
# and also all tags starting with v
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
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@v3
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: temurin
|
||||
|
||||
- name: Build javadocs/doxygen
|
||||
run: |
|
||||
chmod +x gradlew
|
||||
./gradlew docs:generateJavaDocs docs:doxygen
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: built-docs
|
||||
path: 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
|
||||
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/
|
||||
88
.github/workflows/lint-format.yml
vendored
88
.github/workflows/lint-format.yml
vendored
@@ -1,88 +0,0 @@
|
||||
name: Lint and Format
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
wpiformat:
|
||||
name: "wpiformat"
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Fetch all history and metadata
|
||||
run: |
|
||||
git fetch --prune --unshallow
|
||||
git checkout -b pr
|
||||
git branch -f master origin/master
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Install wpiformat
|
||||
run: pip3 install wpiformat
|
||||
- name: Run
|
||||
run: wpiformat
|
||||
- name: Check output
|
||||
run: git --no-pager diff --exit-code HEAD
|
||||
- name: Generate diff
|
||||
run: git diff HEAD > wpiformat-fixes.patch
|
||||
if: ${{ failure() }}
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: wpiformat fixes
|
||||
path: wpiformat-fixes.patch
|
||||
if: ${{ failure() }}
|
||||
javaformat:
|
||||
name: "Java Formatting"
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: temurin
|
||||
- run: |
|
||||
chmod +x gradlew
|
||||
./gradlew spotlessCheck
|
||||
|
||||
client-lint-format:
|
||||
name: "PhotonClient Lint and Formatting"
|
||||
defaults:
|
||||
run:
|
||||
working-directory: photon-client
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Install Dependencies
|
||||
run: npm ci
|
||||
- name: Check Linting
|
||||
run: npm 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@v3
|
||||
- name: Fetch all history and metadata
|
||||
run: |
|
||||
git fetch --prune --unshallow
|
||||
git checkout -b pr
|
||||
git branch -f master origin/master
|
||||
- name: Check index.html not changed
|
||||
run: git --no-pager diff --exit-code origin/master photon-server/src/main/resources/web/index.html
|
||||
60
.github/workflows/python.yml
vendored
60
.github/workflows/python.yml
vendored
@@ -1,60 +0,0 @@
|
||||
name: Build and Distribute PhotonLibPy
|
||||
|
||||
permissions:
|
||||
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
buildAndDeploy:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.11
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install setuptools wheel pytest
|
||||
|
||||
- name: Build wheel
|
||||
working-directory: ./photon-lib/py
|
||||
run: |
|
||||
python setup.py sdist bdist_wheel
|
||||
|
||||
- name: Run Unit Tests
|
||||
working-directory: ./photon-lib/py
|
||||
run: |
|
||||
pip install --no-cache-dir dist/*.whl
|
||||
pytest
|
||||
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: dist
|
||||
path: ./photon-lib/py/dist/
|
||||
|
||||
- name: Publish package distributions to TestPyPI
|
||||
# Only upload on tags
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
packages_dir: ./photon-lib/py/dist/
|
||||
|
||||
permissions:
|
||||
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
|
||||
13
build.gradle
13
build.gradle
@@ -4,7 +4,7 @@ plugins {
|
||||
id "com.diffplug.spotless" version "6.24.0"
|
||||
id "edu.wpi.first.NativeUtils" version "2024.6.1" apply false
|
||||
id "edu.wpi.first.wpilib.repositories.WPILibRepositoriesPlugin" version "2020.2"
|
||||
id "edu.wpi.first.GradleRIO" version "2024.2.1"
|
||||
id "edu.wpi.first.GradleRIO" version "2024.3.1"
|
||||
id 'edu.wpi.first.WpilibTools' version '1.3.0'
|
||||
id 'com.google.protobuf' version '0.9.4' apply false
|
||||
}
|
||||
@@ -13,8 +13,9 @@ allprojects {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
maven { url = "https://maven.photonvision.org/repository/internal/" }
|
||||
maven { url = "https://maven.photonvision.org/repository/snapshots/" }
|
||||
maven { url = "https://maven.photonvision.org/releases" }
|
||||
maven { url = "https://maven.photonvision.org/snapshots" }
|
||||
maven { url = "https://jogamp.org/deployment/maven/" }
|
||||
}
|
||||
wpilibRepositories.addAllReleaseRepositories(it)
|
||||
wpilibRepositories.addAllDevelopmentRepositories(it)
|
||||
@@ -24,7 +25,7 @@ allprojects {
|
||||
apply from: "versioningHelper.gradle"
|
||||
|
||||
ext {
|
||||
wpilibVersion = "2024.2.1"
|
||||
wpilibVersion = "2024.3.1"
|
||||
wpimathVersion = wpilibVersion
|
||||
openCVversion = "4.8.0-2"
|
||||
joglVersion = "2.4.0-rc-20200307"
|
||||
@@ -50,6 +51,10 @@ ext {
|
||||
println("Building for platform " + jniPlatform + " wpilib: " + wpilibNativeName)
|
||||
println("Using Wpilib: " + wpilibVersion)
|
||||
println("Using OpenCV: " + openCVversion)
|
||||
|
||||
|
||||
photonMavenURL = 'https://maven.photonvision.org/' + (isDev ? 'snapshots' : 'releases');
|
||||
println("Publishing Photonlib to " + photonMavenURL)
|
||||
}
|
||||
|
||||
spotless {
|
||||
|
||||
@@ -162,9 +162,9 @@ def __convert_cal_to_mrcal_cameramodel(
|
||||
"indices_point_camintrinsics_camextrinsics": None,
|
||||
"lensmodel": model,
|
||||
"imagersizes": np.array([imagersize], dtype=np.int32),
|
||||
"calobject_warp": np.array(cal.calobjectWarp)
|
||||
if len(cal.calobjectWarp) > 0
|
||||
else None,
|
||||
"calobject_warp": (
|
||||
np.array(cal.calobjectWarp) if len(cal.calobjectWarp) > 0 else None
|
||||
),
|
||||
# We always do all the things
|
||||
"do_optimize_intrinsics_core": True,
|
||||
"do_optimize_intrinsics_distortions": True,
|
||||
|
||||
@@ -281,11 +281,29 @@ watchEffect(() => {
|
||||
</v-banner>
|
||||
<pv-switch
|
||||
v-model="tempSettingsStruct.matchCamerasOnlyByPath"
|
||||
label="Match cameras by-path ONLY"
|
||||
tooltip="ONLY match cameras by the USB port they're plugged into + (basename or USB VID/PID), and never only by the device product string"
|
||||
label="Strictly match ONLY known cameras"
|
||||
tooltip="ONLY match cameras by the USB port they're plugged into + (basename or USB VID/PID), and never only by the device product string. Also disables automatic detection of new cameras."
|
||||
class="mt-3 mb-2"
|
||||
:label-cols="4"
|
||||
/>
|
||||
<v-banner
|
||||
v-show="tempSettingsStruct.matchCamerasOnlyByPath"
|
||||
rounded
|
||||
color="red"
|
||||
class="mb-3"
|
||||
text-color="white"
|
||||
icon="mdi-information-outline"
|
||||
>
|
||||
Physical cameras will be strictly matched to camera configurations using physical USB port they are plugged
|
||||
into, in addition to device name and other USB metadata. Additionally, no new cameras are allowed to be added.
|
||||
This setting is useful for guaranteeing that an already known and configured camera can never be matched as an
|
||||
"unknown"/"new" camera, which resets pipelines and calibration data.
|
||||
<p />
|
||||
Cameras will NOT be matched if they change USB ports, and new cameras plugged into this coprocessor will NOT
|
||||
be automatically recognized or configured for vision processing.
|
||||
<p />
|
||||
To add a new camera to this coprocessor, disable this setting, connect the camera, and re-enable.
|
||||
</v-banner>
|
||||
<v-divider class="mb-3" />
|
||||
</v-form>
|
||||
<v-btn
|
||||
|
||||
@@ -41,7 +41,9 @@ public class NetworkConfig {
|
||||
|
||||
/**
|
||||
* If we should ONLY match cameras by path, and NEVER only by base-name. For now default to false
|
||||
* to preserve old matching logic
|
||||
* to preserve old matching logic.
|
||||
*
|
||||
* <p>This also disables creating new CameraConfigurations for detected "new" cameras.
|
||||
*/
|
||||
public boolean matchCamerasOnlyByPath = false;
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ package org.photonvision.vision.camera;
|
||||
import edu.wpi.first.cscore.UsbCameraInfo;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import org.photonvision.common.hardware.Platform;
|
||||
|
||||
public class CameraInfo extends UsbCameraInfo {
|
||||
public final CameraType cameraType;
|
||||
@@ -80,27 +81,41 @@ public class CameraInfo extends UsbCameraInfo {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) return true;
|
||||
if (!(o instanceof UsbCameraInfo || o instanceof CameraInfo)) return false;
|
||||
UsbCameraInfo other = (UsbCameraInfo) o;
|
||||
return path.equals(other.path)
|
||||
// && a.dev == b.dev (dev is not constant in Windows)
|
||||
&& name.equals(other.name)
|
||||
&& productId == other.productId
|
||||
&& vendorId == other.vendorId;
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (obj == null) return false;
|
||||
if (getClass() != obj.getClass()) return false;
|
||||
CameraInfo other = (CameraInfo) obj;
|
||||
|
||||
// Windows device number is not significant. See
|
||||
// https://github.com/wpilibsuite/allwpilib/blob/4b94a64b06057c723d6fcafeb1a45f55a70d179a/cscore/src/main/native/windows/UsbCameraImpl.cpp#L1128
|
||||
if (!Platform.isWindows()) {
|
||||
if (dev != other.dev) return false;
|
||||
}
|
||||
|
||||
if (!path.equals(other.path)) return false;
|
||||
if (!name.equals(other.name)) return false;
|
||||
if (!Arrays.asList(this.otherPaths).containsAll(Arrays.asList(other.otherPaths))) return false;
|
||||
if (vendorId != other.vendorId) return false;
|
||||
if (productId != other.productId) return false;
|
||||
|
||||
// Don't trust super.equals, as it compares references. Should PR this to allwpilib at some
|
||||
// point
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CameraInfo [cameraType="
|
||||
+ cameraType
|
||||
+ "baseName="
|
||||
+ ", baseName="
|
||||
+ getBaseName()
|
||||
+ ", vid="
|
||||
+ vendorId
|
||||
+ ", pid="
|
||||
+ productId
|
||||
+ ", path="
|
||||
+ path
|
||||
+ ", otherPaths="
|
||||
+ Arrays.toString(otherPaths)
|
||||
+ "]";
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) Photon Vision.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.vision.camera;
|
||||
|
||||
import java.util.*;
|
||||
import org.photonvision.common.configuration.CameraConfiguration;
|
||||
import org.photonvision.vision.frame.Frame;
|
||||
import org.photonvision.vision.frame.FrameProvider;
|
||||
import org.photonvision.vision.frame.FrameThresholdType;
|
||||
import org.photonvision.vision.opencv.ImageRotationMode;
|
||||
import org.photonvision.vision.pipe.impl.HSVPipe.HSVParams;
|
||||
import org.photonvision.vision.processes.VisionSource;
|
||||
import org.photonvision.vision.processes.VisionSourceSettables;
|
||||
|
||||
/** Dummy class for unit testing the vision source manager */
|
||||
public class TestSource extends VisionSource {
|
||||
private FrameProvider usbFrameProvider;
|
||||
|
||||
public TestSource(CameraConfiguration config) {
|
||||
super(config);
|
||||
|
||||
if (getCameraConfiguration().cameraQuirks == null)
|
||||
getCameraConfiguration().cameraQuirks =
|
||||
QuirkyCamera.getQuirkyCamera(config.usbVID, config.usbVID, config.baseName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FrameProvider getFrameProvider() {
|
||||
return new FrameProvider() {
|
||||
@Override
|
||||
public Frame get() {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'get'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return cameraConfiguration.uniqueName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestFrameThresholdType(FrameThresholdType type) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'requestFrameThresholdType'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestFrameRotation(ImageRotationMode rotationMode) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'requestFrameRotation'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestFrameCopies(boolean copyInput, boolean copyOutput) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'requestFrameCopies'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestHsvSettings(HSVParams params) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'requestHsvSettings'");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisionSourceSettables getSettables() {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'getSettables'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVendorCamera() {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'isVendorCamera'");
|
||||
}
|
||||
}
|
||||
@@ -57,8 +57,8 @@ public class USBCameraSource extends VisionSource {
|
||||
cvSink = CameraServer.getVideo(this.camera);
|
||||
|
||||
// set vid/pid if not done already for future matching
|
||||
if (config.usbVID < 0) config.usbVID = this.camera.getInfo().vendorId;
|
||||
if (config.usbPID < 0) config.usbPID = this.camera.getInfo().productId;
|
||||
if (config.usbVID <= 0) config.usbVID = this.camera.getInfo().vendorId;
|
||||
if (config.usbPID <= 0) config.usbPID = this.camera.getInfo().productId;
|
||||
|
||||
if (getCameraConfiguration().cameraQuirks == null)
|
||||
getCameraConfiguration().cameraQuirks =
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) Photon Vision.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.vision.processes;
|
||||
|
||||
import java.util.List;
|
||||
import org.photonvision.vision.camera.CameraType;
|
||||
|
||||
public class CameraMatchingOptions {
|
||||
public CameraMatchingOptions(
|
||||
boolean checkUSBPath,
|
||||
boolean checkVidPid,
|
||||
boolean checkBaseName,
|
||||
boolean checkPath,
|
||||
CameraType... allowedTypes) {
|
||||
this.checkUSBPath = checkUSBPath;
|
||||
this.checkVidPid = checkVidPid;
|
||||
this.checkBaseName = checkBaseName;
|
||||
this.checkPath = checkPath;
|
||||
this.allowedTypes = List.of(allowedTypes);
|
||||
}
|
||||
|
||||
public final boolean checkUSBPath;
|
||||
public final boolean checkVidPid;
|
||||
public final boolean checkBaseName;
|
||||
public final boolean checkPath;
|
||||
public final List<CameraType> allowedTypes;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CameraMatchingOptions [checkUSBPath="
|
||||
+ checkUSBPath
|
||||
+ ", checkVidPid="
|
||||
+ checkVidPid
|
||||
+ ", checkBaseName="
|
||||
+ checkBaseName
|
||||
+ ", checkPath="
|
||||
+ checkPath
|
||||
+ ", allowedTypes="
|
||||
+ allowedTypes
|
||||
+ "]";
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,7 @@ import org.photonvision.vision.camera.CameraInfo;
|
||||
import org.photonvision.vision.camera.CameraQuirk;
|
||||
import org.photonvision.vision.camera.CameraType;
|
||||
import org.photonvision.vision.camera.LibcameraGpuSource;
|
||||
import org.photonvision.vision.camera.TestSource;
|
||||
import org.photonvision.vision.camera.USBCameraSource;
|
||||
|
||||
public class VisionSourceManager {
|
||||
@@ -146,8 +147,8 @@ public class VisionSourceManager {
|
||||
}
|
||||
|
||||
// Return no new sources because there are no new sources
|
||||
if (connectedCameras.isEmpty() && !cameraInfos.isEmpty()) {
|
||||
if (hasWarnedNoCameras) {
|
||||
if (connectedCameras.isEmpty()) {
|
||||
if (!hasWarnedNoCameras) {
|
||||
logger.warn(
|
||||
"No cameras were detected! Check that all cameras are connected, and that the path is correct.");
|
||||
hasWarnedNoCameras = true;
|
||||
@@ -186,7 +187,7 @@ public class VisionSourceManager {
|
||||
"Unloaded configs: "
|
||||
+ unmatchedLoadedConfigs.stream()
|
||||
.map(it -> it.nickname)
|
||||
.collect(Collectors.joining()));
|
||||
.collect(Collectors.joining(", ")));
|
||||
hasWarned = true;
|
||||
}
|
||||
|
||||
@@ -195,13 +196,8 @@ public class VisionSourceManager {
|
||||
|
||||
if (matchedCameras.isEmpty()) return null;
|
||||
|
||||
// for unit tests only!
|
||||
if (!createSources) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
// Turn these camera configs into vision sources
|
||||
var sources = loadVisionSourcesFromCamConfigs(matchedCameras);
|
||||
var sources = loadVisionSourcesFromCamConfigs(matchedCameras, createSources);
|
||||
|
||||
// Print info about each vision source
|
||||
for (var src : sources) {
|
||||
@@ -259,6 +255,8 @@ public class VisionSourceManager {
|
||||
matches &= (physicalCamera.path.equals(savedConfig.path));
|
||||
}
|
||||
|
||||
matches &= (physicalCamera.cameraType == savedConfig.cameraType);
|
||||
|
||||
return matches;
|
||||
};
|
||||
}
|
||||
@@ -313,44 +311,79 @@ public class VisionSourceManager {
|
||||
ArrayList<CameraConfiguration> unloadedConfigs =
|
||||
new ArrayList<CameraConfiguration>(loadedCamConfigs);
|
||||
|
||||
if (detectedCameraList.size() > 0 || unloadedConfigs.size() > 0) {
|
||||
logger.info("Matching by usb port & name & USB VID/PID...");
|
||||
cameraConfigurations.addAll(
|
||||
matchCamerasByStrategy(detectedCameraList, unloadedConfigs, true, true, true, false));
|
||||
} else
|
||||
logger.debug("Skipping match by usb port/name/vid/pid, no configs or cameras left to match");
|
||||
logger.info("Matching CSI cameras by port & base name...");
|
||||
cameraConfigurations.addAll(
|
||||
matchCamerasByStrategy(
|
||||
detectedCameraList,
|
||||
unloadedConfigs,
|
||||
new CameraMatchingOptions(false, false, true, true, CameraType.ZeroCopyPicam)));
|
||||
|
||||
logger.info("Matching USB cameras by usb port & name & USB VID/PID...");
|
||||
cameraConfigurations.addAll(
|
||||
matchCamerasByStrategy(
|
||||
detectedCameraList,
|
||||
unloadedConfigs,
|
||||
new CameraMatchingOptions(true, true, true, false, CameraType.UsbCamera)));
|
||||
|
||||
// On windows, the v4l path is actually useful and tells us the port the camera is physically
|
||||
// connected to which is neat
|
||||
if (Platform.isWindows()) {
|
||||
if (detectedCameraList.size() > 0 || unloadedConfigs.size() > 0) {
|
||||
logger.info("Matching by windows-path & USB VID/PID only...");
|
||||
cameraConfigurations.addAll(
|
||||
matchCamerasByStrategy(detectedCameraList, unloadedConfigs, false, true, true, true));
|
||||
} else
|
||||
logger.debug(
|
||||
"Skipping matching by windiws-path/name/vid/pid, no configs or cameras left to match");
|
||||
if (Platform.isWindows() && !matchCamerasOnlyByPath) {
|
||||
logger.info("Matching USB cameras by windows-path & USB VID/PID only...");
|
||||
cameraConfigurations.addAll(
|
||||
matchCamerasByStrategy(
|
||||
detectedCameraList,
|
||||
unloadedConfigs,
|
||||
new CameraMatchingOptions(false, true, true, true, CameraType.UsbCamera)));
|
||||
}
|
||||
|
||||
if (detectedCameraList.size() > 0 || unloadedConfigs.size() > 0) {
|
||||
logger.info("Matching by usb port & USB VID/PID...");
|
||||
cameraConfigurations.addAll(
|
||||
matchCamerasByStrategy(detectedCameraList, unloadedConfigs, true, true, false, false));
|
||||
} else logger.debug("Skipping match by port/vid/pid, no configs or cameras left to match");
|
||||
logger.info("Matching USB cameras by usb port & USB VID/PID...");
|
||||
cameraConfigurations.addAll(
|
||||
matchCamerasByStrategy(
|
||||
detectedCameraList,
|
||||
unloadedConfigs,
|
||||
new CameraMatchingOptions(true, true, false, false, CameraType.UsbCamera)));
|
||||
|
||||
// Legacy migration -- VID/PID will be unset, so we have to try with our most relaxed strategy
|
||||
// at least once. We _should_ still have a valid USB path (assuming cameras have not moved), so
|
||||
// try that first, then fallback to base name only beloow
|
||||
logger.info("Matching USB cameras by base-name & usb port...");
|
||||
cameraConfigurations.addAll(
|
||||
matchCamerasByStrategy(
|
||||
detectedCameraList,
|
||||
unloadedConfigs,
|
||||
new CameraMatchingOptions(true, false, true, false, CameraType.UsbCamera)));
|
||||
|
||||
// handle disabling only-by-base-name matching
|
||||
if (!matchCamerasOnlyByPath) {
|
||||
if (detectedCameraList.size() > 0 || unloadedConfigs.size() > 0) {
|
||||
logger.info("Matching by base-name & USB VID/PID only...");
|
||||
cameraConfigurations.addAll(
|
||||
matchCamerasByStrategy(detectedCameraList, unloadedConfigs, false, true, true, false));
|
||||
} else
|
||||
logger.debug("Skipping match by base-name/viid/pid, no configs or cameras left to match");
|
||||
logger.info("Matching USB cameras by base-name & USB VID/PID only...");
|
||||
cameraConfigurations.addAll(
|
||||
matchCamerasByStrategy(
|
||||
detectedCameraList,
|
||||
unloadedConfigs,
|
||||
new CameraMatchingOptions(false, true, true, false, CameraType.UsbCamera)));
|
||||
|
||||
// Legacy migration for if no USB VID/PID set
|
||||
logger.info("Matching USB cameras by base-name only...");
|
||||
cameraConfigurations.addAll(
|
||||
matchCamerasByStrategy(
|
||||
detectedCameraList,
|
||||
unloadedConfigs,
|
||||
new CameraMatchingOptions(false, false, true, false, CameraType.UsbCamera)));
|
||||
} else logger.info("Skipping match by filepath/vid/pid, disabled by user");
|
||||
|
||||
if (detectedCameraList.size() > 0) {
|
||||
cameraConfigurations.addAll(
|
||||
createConfigsForCameras(detectedCameraList, unloadedConfigs, cameraConfigurations));
|
||||
// handle disabling only-by-base-name matching
|
||||
if (!matchCamerasOnlyByPath) {
|
||||
cameraConfigurations.addAll(
|
||||
createConfigsForCameras(detectedCameraList, unloadedConfigs, cameraConfigurations));
|
||||
} else {
|
||||
logger.warn(
|
||||
"Not creating 'new' Photon CameraConfigurations for ["
|
||||
+ detectedCamInfos.stream()
|
||||
.map(CameraInfo::toString)
|
||||
.collect(Collectors.joining(";"))
|
||||
+ "], disabled by user");
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug("Matched or created " + cameraConfigurations.size() + " camera configs!");
|
||||
@@ -374,41 +407,46 @@ public class VisionSourceManager {
|
||||
private List<CameraConfiguration> matchCamerasByStrategy(
|
||||
List<CameraInfo> detectedCamInfos,
|
||||
List<CameraConfiguration> unloadedConfigs,
|
||||
boolean checkUSBPath,
|
||||
boolean checkVidPid,
|
||||
boolean checkBaseName,
|
||||
boolean checkPath) {
|
||||
CameraMatchingOptions matchingOptions) {
|
||||
List<CameraConfiguration> ret = new ArrayList<CameraConfiguration>();
|
||||
List<CameraConfiguration> unloadedConfigsCopy =
|
||||
new ArrayList<CameraConfiguration>(unloadedConfigs);
|
||||
|
||||
if (unloadedConfigsCopy.isEmpty()) return List.of();
|
||||
|
||||
logger.debug("Matching with options " + matchingOptions.toString());
|
||||
|
||||
for (CameraConfiguration config : unloadedConfigsCopy) {
|
||||
// Only run match path by id if the camera is not a CSI camera.
|
||||
if (config.cameraType != CameraType.ZeroCopyPicam) {
|
||||
// Only run match path by id if the camera type is allowed. This allows us to specify matching
|
||||
// behavior per-camera-type
|
||||
if (matchingOptions.allowedTypes.contains(config.cameraType)) {
|
||||
logger.debug(
|
||||
String.format(
|
||||
"Trying to find a match for loaded camera %s by strategy (path %s vid/pid %s basename %s path %s) with camera config: %s",
|
||||
config.baseName,
|
||||
checkUSBPath,
|
||||
checkVidPid,
|
||||
checkBaseName,
|
||||
checkPath,
|
||||
camCfgToString(config)));
|
||||
"Trying to find a match for loaded camera %s (%s) with camera config: %s",
|
||||
config.baseName, config.uniqueName, camCfgToString(config)));
|
||||
|
||||
// Get matcher and filter against it, picking out the first match
|
||||
Predicate<CameraInfo> matches =
|
||||
getCameraMatcher(config, checkUSBPath, checkVidPid, checkBaseName, checkPath);
|
||||
getCameraMatcher(
|
||||
config,
|
||||
matchingOptions.checkUSBPath,
|
||||
matchingOptions.checkVidPid,
|
||||
matchingOptions.checkBaseName,
|
||||
matchingOptions.checkPath);
|
||||
var cameraInfo = detectedCamInfos.stream().filter(matches).findFirst().orElse(null);
|
||||
|
||||
// If we actually matched a camera to a config, remove that camera from the list
|
||||
// and add it to the output
|
||||
if (cameraInfo != null) {
|
||||
logger.debug("Matched the config for " + config.baseName + " to a physical camera!");
|
||||
logger.debug(
|
||||
"Matched the config for "
|
||||
+ config.uniqueName
|
||||
+ " to the physical camera config above!");
|
||||
ret.add(mergeInfoIntoConfig(config, cameraInfo));
|
||||
detectedCamInfos.remove(cameraInfo);
|
||||
unloadedConfigs.remove(config);
|
||||
} else {
|
||||
logger.debug("No camera found for the config " + config.baseName);
|
||||
logger.debug("No camera found for the config " + config.uniqueName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -425,7 +463,10 @@ public class VisionSourceManager {
|
||||
List<CameraConfiguration> loadedConfigs) {
|
||||
List<CameraConfiguration> ret = new ArrayList<CameraConfiguration>();
|
||||
logger.debug(
|
||||
"After matching loaded configs " + detectedCameraList.size() + " cameras were unmatched.");
|
||||
"After matching loaded configs, these configs remained unmatched: "
|
||||
+ detectedCameraList.stream()
|
||||
.map(n -> String.valueOf(n))
|
||||
.collect(Collectors.joining("-", "{", "}")));
|
||||
for (CameraInfo info : detectedCameraList) {
|
||||
// create new camera config for all new cameras
|
||||
String baseName = info.getBaseName();
|
||||
@@ -434,7 +475,8 @@ public class VisionSourceManager {
|
||||
int suffix = 0;
|
||||
while (containsName(loadedConfigs, uniqueName)
|
||||
|| containsName(uniqueName)
|
||||
|| containsName(unloadedCamConfigs, uniqueName)) {
|
||||
|| containsName(unloadedCamConfigs, uniqueName)
|
||||
|| containsName(ret, uniqueName)) {
|
||||
suffix++;
|
||||
uniqueName = String.format("%s (%d)", uniqueName, suffix);
|
||||
}
|
||||
@@ -514,11 +556,17 @@ public class VisionSourceManager {
|
||||
}
|
||||
|
||||
private static List<VisionSource> loadVisionSourcesFromCamConfigs(
|
||||
List<CameraConfiguration> camConfigs) {
|
||||
List<CameraConfiguration> camConfigs, boolean createSources) {
|
||||
var cameraSources = new ArrayList<VisionSource>();
|
||||
for (var configuration : camConfigs) {
|
||||
logger.debug("Creating VisionSource for " + camCfgToString(configuration));
|
||||
|
||||
// In unit tests, create dummy
|
||||
if (!createSources) {
|
||||
cameraSources.add(new TestSource(configuration));
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean is_pi = Platform.isRaspberryPi();
|
||||
|
||||
if (configuration.cameraType == CameraType.ZeroCopyPicam && is_pi) {
|
||||
|
||||
@@ -21,6 +21,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.photonvision.common.configuration.CameraConfiguration;
|
||||
import org.photonvision.common.configuration.ConfigManager;
|
||||
@@ -271,4 +272,335 @@ public class VisionSourceManagerTest {
|
||||
assertEquals(10, inst.knownCameras.size());
|
||||
assertEquals(0, inst.unmatchedLoadedConfigs.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisableInhibitPathChangeIdenticalCams() {
|
||||
Logger.setLevel(LogGroup.Camera, LogLevel.DEBUG);
|
||||
|
||||
var inst = new VisionSourceManager();
|
||||
ConfigManager.getInstance().clearConfig();
|
||||
ConfigManager.getInstance().load();
|
||||
ConfigManager.getInstance().getConfig().getNetworkConfig().matchCamerasOnlyByPath = false;
|
||||
|
||||
var CAM2_OLD_PATH =
|
||||
new String[] {"/dev/v4l/by-path/platform-fc880000.usb-usb-0:1:1.0-video-index0"};
|
||||
var CAM2_NEW_PATH =
|
||||
new String[] {"/dev/v4l/by-path/platform-fc880080.usb-usb-0:1:1.3-video-index0"};
|
||||
|
||||
var CAM1_OLD_PATHS =
|
||||
new String[] {
|
||||
"/dev/v4l/by-id/usb-Arducam_Technology_Co.__Ltd._Arducam_OV2311_USB_Camera_UC621-video-index0",
|
||||
"/dev/v4l/by-path/platform-fc800000.usb-usb-0:1:1.0-video-index0"
|
||||
};
|
||||
|
||||
var camera1_saved_config =
|
||||
new CameraConfiguration(
|
||||
"Arducam OV2311 USB Camera",
|
||||
"Arducam OV2311 USB Camera",
|
||||
"fromt-left",
|
||||
"/dev/video0",
|
||||
CAM1_OLD_PATHS);
|
||||
camera1_saved_config.usbVID = 3141;
|
||||
camera1_saved_config.usbPID = 25446;
|
||||
var camera2_saved_config =
|
||||
new CameraConfiguration(
|
||||
"Arducam OV2311 USB Camera",
|
||||
"Arducam OV2311 USB Camera (1)",
|
||||
"fromt-left",
|
||||
"/dev/video2",
|
||||
CAM2_OLD_PATH);
|
||||
camera2_saved_config.usbVID = 3141;
|
||||
camera2_saved_config.usbPID = 25446;
|
||||
|
||||
// And load our "old" configs
|
||||
inst.registerLoadedConfigs(camera1_saved_config, camera2_saved_config);
|
||||
|
||||
// Camera attached to new port, but strict matching disabled
|
||||
{
|
||||
CameraInfo info1 =
|
||||
new CameraInfo(
|
||||
0, "/dev/video11", "Arducam OV2311 USB Camera", CAM1_OLD_PATHS, 3141, 25446);
|
||||
CameraInfo info2 =
|
||||
new CameraInfo(
|
||||
0, "/dev/video12", "Arducam OV2311 USB Camera", CAM2_NEW_PATH, 3141, 25446);
|
||||
|
||||
var cameraInfos = new ArrayList<CameraInfo>();
|
||||
cameraInfos.add(info1);
|
||||
cameraInfos.add(info2);
|
||||
List<VisionSource> ret1 = inst.tryMatchCamImpl(cameraInfos);
|
||||
|
||||
// and check the new one got matched got matched
|
||||
assertEquals(2, ret1.size());
|
||||
assertEquals(
|
||||
1, ret1.stream().filter(it -> it.cameraConfiguration.path.equals(info1.path)).count());
|
||||
assertEquals(
|
||||
1, ret1.stream().filter(it -> it.cameraConfiguration.path.equals(info2.path)).count());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInhibitPathChangeIdenticalCams() {
|
||||
Logger.setLevel(LogGroup.Camera, LogLevel.DEBUG);
|
||||
|
||||
var inst = new VisionSourceManager();
|
||||
ConfigManager.getInstance().clearConfig();
|
||||
ConfigManager.getInstance().load();
|
||||
ConfigManager.getInstance().getConfig().getNetworkConfig().matchCamerasOnlyByPath = true;
|
||||
|
||||
var CAM2_OLD_PATH =
|
||||
new String[] {"/dev/v4l/by-path/platform-fc880000.usb-usb-0:1:1.0-video-index0"};
|
||||
var CAM2_NEW_PATH =
|
||||
new String[] {"/dev/v4l/by-path/platform-fc880080.usb-usb-0:1:1.3-video-index0"};
|
||||
|
||||
var CAM1_OLD_PATHS =
|
||||
new String[] {
|
||||
"/dev/v4l/by-id/usb-Arducam_Technology_Co.__Ltd._Arducam_OV2311_USB_Camera_UC621-video-index0",
|
||||
"/dev/v4l/by-path/platform-fc800000.usb-usb-0:1:1.0-video-index0"
|
||||
};
|
||||
|
||||
var camera1_saved_config =
|
||||
new CameraConfiguration(
|
||||
"Arducam OV2311 USB Camera",
|
||||
"Arducam OV2311 USB Camera (1)",
|
||||
"fromt-left",
|
||||
"/dev/video0",
|
||||
CAM1_OLD_PATHS);
|
||||
camera1_saved_config.usbVID = 3141;
|
||||
camera1_saved_config.usbPID = 25446;
|
||||
var camera2_saved_config =
|
||||
new CameraConfiguration(
|
||||
"Arducam OV2311 USB Camera",
|
||||
"Arducam OV2311 USB Camera (1)",
|
||||
"fromt-left",
|
||||
"/dev/video2",
|
||||
CAM2_OLD_PATH);
|
||||
camera2_saved_config.usbVID = 3141;
|
||||
camera2_saved_config.usbPID = 25446;
|
||||
|
||||
// And load our "old" configs
|
||||
inst.registerLoadedConfigs(camera1_saved_config, camera2_saved_config);
|
||||
|
||||
// initial pass with camera in the wrong spot
|
||||
{
|
||||
// Give our cameras new "paths" to fake the windows logic out. this should not
|
||||
// affect strict matching
|
||||
CameraInfo info1 =
|
||||
new CameraInfo(
|
||||
0, "/dev/video11", "Arducam OV2311 USB Camera", CAM1_OLD_PATHS, 3141, 25446);
|
||||
CameraInfo info2 =
|
||||
new CameraInfo(
|
||||
0, "/dev/video12", "Arducam OV2311 USB Camera", CAM2_NEW_PATH, 3141, 25446);
|
||||
|
||||
var cameraInfos = new ArrayList<CameraInfo>();
|
||||
cameraInfos.add(info1);
|
||||
cameraInfos.add(info2);
|
||||
List<VisionSource> ret1 = inst.tryMatchCamImpl(cameraInfos);
|
||||
|
||||
// Our cameras should be "known"
|
||||
assertTrue(inst.knownCameras.contains(info1));
|
||||
assertTrue(inst.knownCameras.contains(info2));
|
||||
assertEquals(2, inst.knownCameras.size());
|
||||
|
||||
// And we should have matched one camera
|
||||
assertEquals(1, ret1.size());
|
||||
// and only matched camera1, not 2
|
||||
assertEquals(
|
||||
1, ret1.stream().filter(it -> it.cameraConfiguration.path.equals(info1.path)).count());
|
||||
assertEquals(
|
||||
0, ret1.stream().filter(it -> it.cameraConfiguration.path.equals(info2.path)).count());
|
||||
}
|
||||
|
||||
// Now move our camera back
|
||||
{
|
||||
CameraInfo info1 =
|
||||
new CameraInfo(
|
||||
0, "/dev/video11", "Arducam OV2311 USB Camera", CAM1_OLD_PATHS, 3141, 25446);
|
||||
CameraInfo info2 =
|
||||
new CameraInfo(
|
||||
0, "/dev/video12", "Arducam OV2311 USB Camera", CAM2_OLD_PATH, 3141, 25446);
|
||||
|
||||
var cameraInfos = new ArrayList<CameraInfo>();
|
||||
cameraInfos.add(info1);
|
||||
cameraInfos.add(info2);
|
||||
List<VisionSource> ret1 = inst.tryMatchCamImpl(cameraInfos);
|
||||
|
||||
// and check the new one got matched got matched
|
||||
assertEquals(1, ret1.size());
|
||||
assertEquals(
|
||||
0, ret1.stream().filter(it -> it.cameraConfiguration.path.equals(info1.path)).count());
|
||||
assertEquals(
|
||||
1, ret1.stream().filter(it -> it.cameraConfiguration.path.equals(info2.path)).count());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCSICameraMatching() {
|
||||
Logger.setLevel(LogGroup.Camera, LogLevel.DEBUG);
|
||||
|
||||
// List of known cameras
|
||||
var cameraInfos = new ArrayList<CameraInfo>();
|
||||
|
||||
var inst = new VisionSourceManager();
|
||||
ConfigManager.getInstance().clearConfig();
|
||||
ConfigManager.getInstance().load();
|
||||
ConfigManager.getInstance().getConfig().getNetworkConfig().matchCamerasOnlyByPath = false;
|
||||
|
||||
CameraInfo info1 =
|
||||
new CameraInfo(
|
||||
-1,
|
||||
"/base/soc/i2c0mux/i2c@0/ov9281@60",
|
||||
"OV9281", // Typically rp1-cfe for unit test changed to CSICAM-DEV
|
||||
new String[] {},
|
||||
-1,
|
||||
-1,
|
||||
CameraType.ZeroCopyPicam);
|
||||
|
||||
CameraInfo info2 =
|
||||
new CameraInfo(
|
||||
-1,
|
||||
"/base/soc/i2c0mux/i2c@1/ov9281@60",
|
||||
"OV9281", // Typically rp1-cfe for unit test changed to CSICAM-DEV
|
||||
new String[] {},
|
||||
-1,
|
||||
-1,
|
||||
CameraType.ZeroCopyPicam);
|
||||
|
||||
var camera1_saved_config =
|
||||
new CameraConfiguration(
|
||||
"OV9281", "OV9281", "test-1", "/base/soc/i2c0mux/i2c@0/ov9281@60", new String[0]);
|
||||
camera1_saved_config.cameraType = CameraType.ZeroCopyPicam;
|
||||
camera1_saved_config.usbVID = -1;
|
||||
camera1_saved_config.usbPID = -1;
|
||||
|
||||
var camera2_saved_config =
|
||||
new CameraConfiguration(
|
||||
"OV9281", "OV9281 (1)", "test-2", "/base/soc/i2c0mux/i2c@1/ov9281@60", new String[0]);
|
||||
camera2_saved_config.usbVID = -1;
|
||||
camera2_saved_config.usbPID = -1;
|
||||
camera2_saved_config.cameraType = CameraType.ZeroCopyPicam;
|
||||
|
||||
cameraInfos.add(info1);
|
||||
cameraInfos.add(info2);
|
||||
|
||||
// Try matching with both cameras being "known"
|
||||
inst.registerLoadedConfigs(camera1_saved_config, camera2_saved_config);
|
||||
var ret1 = inst.tryMatchCamImpl(cameraInfos);
|
||||
|
||||
// Our cameras should be "known"
|
||||
assertTrue(inst.knownCameras.contains(info1));
|
||||
assertTrue(inst.knownCameras.contains(info2));
|
||||
assertEquals(2, inst.knownCameras.size());
|
||||
assertEquals(2, ret1.size());
|
||||
|
||||
// Exactly one camera should have the path we put in
|
||||
for (int i = 0; i < cameraInfos.size(); i++) {
|
||||
var testPath = cameraInfos.get(i).path;
|
||||
assertEquals(
|
||||
1, ret1.stream().filter(it -> testPath.equals(it.cameraConfiguration.path)).count());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIdenticalCameras() {
|
||||
Logger.setLevel(LogGroup.Camera, LogLevel.DEBUG);
|
||||
|
||||
// List of known cameras
|
||||
var cameraInfos = new ArrayList<CameraInfo>();
|
||||
|
||||
var inst = new VisionSourceManager();
|
||||
ConfigManager.getInstance().clearConfig();
|
||||
ConfigManager.getInstance().load();
|
||||
ConfigManager.getInstance().getConfig().getNetworkConfig().matchCamerasOnlyByPath = false;
|
||||
|
||||
// Match empty camera infos
|
||||
inst.tryMatchCamImpl(cameraInfos);
|
||||
|
||||
CameraInfo info1 =
|
||||
new CameraInfo(
|
||||
0,
|
||||
"/dev/video0",
|
||||
"Arducam OV2311 USB Camera",
|
||||
new String[] {
|
||||
"/dev/v4l/by-id/usb-Arducam_Technology_Co.__Ltd._Arducam_OV2311_USB_Camera_UC621-video-index0",
|
||||
"/dev/v4l/by-path/platform-fc800000.usb-usb-0:1:1.0-video-index0"
|
||||
},
|
||||
3141,
|
||||
25446);
|
||||
CameraInfo info2 =
|
||||
new CameraInfo(
|
||||
0,
|
||||
"/dev/video2",
|
||||
"Arducam OV2311 USB Camera",
|
||||
new String[] {
|
||||
"/dev/v4l/by-id/usb-Arducam_Technology_Co.__Ltd._Arducam_OV2311_USB_Camera_UC621-video-index0",
|
||||
"/dev/v4l/by-path/platform-fc880000.usb-usb-0:1:1.0-video-index0"
|
||||
},
|
||||
3141,
|
||||
25446);
|
||||
|
||||
cameraInfos.add(info1);
|
||||
cameraInfos.add(info2);
|
||||
|
||||
// Match two "new" cameras
|
||||
var ret1 = inst.tryMatchCamImpl(cameraInfos);
|
||||
|
||||
// Our cameras should be "known"
|
||||
assertTrue(inst.knownCameras.contains(info1));
|
||||
assertTrue(inst.knownCameras.contains(info2));
|
||||
assertEquals(2, inst.knownCameras.size());
|
||||
assertEquals(2, ret1.size());
|
||||
|
||||
// Exactly one camera should have the path we put in
|
||||
for (int i = 0; i < cameraInfos.size(); i++) {
|
||||
var testPath = cameraInfos.get(i).getUSBPath().get();
|
||||
assertEquals(
|
||||
1,
|
||||
ret1.stream()
|
||||
.filter(it -> testPath.equals(it.cameraConfiguration.getUSBPath().get()))
|
||||
.count());
|
||||
}
|
||||
|
||||
// and the names should be unique
|
||||
for (int i = 0; i < ret1.size(); i++) {
|
||||
var thisName = ret1.get(i).cameraConfiguration.uniqueName;
|
||||
assertEquals(
|
||||
1,
|
||||
ret1.stream().filter(it -> thisName.equals(it.cameraConfiguration.uniqueName)).count());
|
||||
}
|
||||
|
||||
// duplciate cameras, same info, new ref
|
||||
var duplicateCameraInfos = new ArrayList<CameraInfo>();
|
||||
CameraInfo info1_dup =
|
||||
new CameraInfo(
|
||||
0,
|
||||
"/dev/video0",
|
||||
"Arducam OV2311 USB Camera",
|
||||
new String[] {
|
||||
"/dev/v4l/by-id/usb-Arducam_Technology_Co.__Ltd._Arducam_OV2311_USB_Camera_UC621-video-index0",
|
||||
"/dev/v4l/by-path/platform-fc800000.usb-usb-0:1:1.0-video-index0"
|
||||
},
|
||||
3141,
|
||||
25446);
|
||||
CameraInfo info2_dup =
|
||||
new CameraInfo(
|
||||
0,
|
||||
"/dev/video2",
|
||||
"Arducam OV2311 USB Camera",
|
||||
new String[] {
|
||||
"/dev/v4l/by-id/usb-Arducam_Technology_Co.__Ltd._Arducam_OV2311_USB_Camera_UC621-video-index0",
|
||||
"/dev/v4l/by-path/platform-fc880000.usb-usb-0:1:1.0-video-index0"
|
||||
},
|
||||
3141,
|
||||
25446);
|
||||
|
||||
duplicateCameraInfos.add(info1_dup);
|
||||
duplicateCameraInfos.add(info2_dup);
|
||||
|
||||
inst.tryMatchCamImpl(duplicateCameraInfos);
|
||||
|
||||
// Our cameras should be "known", and we should only "know" two cameras still
|
||||
assertTrue(inst.knownCameras.contains(info1_dup));
|
||||
assertTrue(inst.knownCameras.contains(info2_dup));
|
||||
assertEquals(2, inst.knownCameras.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -431,7 +431,7 @@ public class PhotonCameraSim implements AutoCloseable {
|
||||
|
||||
detectableTgts.add(
|
||||
new PhotonTrackedTarget(
|
||||
Math.toDegrees(centerRot.getZ()),
|
||||
-Math.toDegrees(centerRot.getZ()),
|
||||
-Math.toDegrees(centerRot.getY()),
|
||||
areaPercent,
|
||||
Math.toDegrees(centerRot.getX()),
|
||||
|
||||
@@ -260,7 +260,7 @@ class PhotonCameraSim {
|
||||
std::vector<std::pair<double, double>> cornersDouble{cornersFloat.begin(),
|
||||
cornersFloat.end()};
|
||||
detectableTgts.emplace_back(PhotonTrackedTarget{
|
||||
centerRot.Z().convert<units::degrees>().to<double>(),
|
||||
-centerRot.Z().convert<units::degrees>().to<double>(),
|
||||
-centerRot.Y().convert<units::degrees>().to<double>(), areaPercent,
|
||||
centerRot.X().convert<units::degrees>().to<double>(), tgt.fiducialId,
|
||||
pnpSim.best, pnpSim.alt, pnpSim.ambiguity, smallVec, cornersDouble});
|
||||
|
||||
@@ -256,7 +256,8 @@ class VisionSystemSimTest {
|
||||
cameraSim.setMinTargetAreaPixels(0.0);
|
||||
visionSysSim.addVisionTargets(new VisionTargetSim(targetPose, new TargetModel(0.5, 0.5), 3));
|
||||
|
||||
var robotPose = new Pose2d(new Translation2d(10, 0), Rotation2d.fromDegrees(-1.0 * testYaw));
|
||||
// If the robot is rotated x deg (CCW+), the target yaw should be x deg (CW+)
|
||||
var robotPose = new Pose2d(new Translation2d(10, 0), Rotation2d.fromDegrees(testYaw));
|
||||
visionSysSim.update(robotPose);
|
||||
var res = camera.getLatestResult();
|
||||
assertTrue(res.hasTargets());
|
||||
|
||||
@@ -220,8 +220,9 @@ TEST_P(VisionSystemSimTestWithParamsTest, YawAngles) {
|
||||
visionSysSim.AddVisionTargets({photon::VisionTargetSim{
|
||||
targetPose, photon::TargetModel{0.5_m, 0.5_m}, 3}});
|
||||
|
||||
robotPose = frc::Pose2d{frc::Translation2d{10_m, 0_m},
|
||||
frc::Rotation2d{-1 * GetParam()}};
|
||||
// If the robot is rotated x deg (CCW+), the target yaw should be x deg (CW+)
|
||||
robotPose =
|
||||
frc::Pose2d{frc::Translation2d{10_m, 0_m}, frc::Rotation2d{GetParam()}};
|
||||
visionSysSim.Update(robotPose);
|
||||
ASSERT_TRUE(camera.GetLatestResult().HasTargets());
|
||||
ASSERT_NEAR(GetParam().to<double>(),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id "cpp"
|
||||
id "google-test-test-suite"
|
||||
id "edu.wpi.first.GradleRIO" version "2024.2.1"
|
||||
id "edu.wpi.first.GradleRIO" version "2024.3.1"
|
||||
|
||||
id "com.dorongold.task-tree" version "2.1.0"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id "cpp"
|
||||
id "google-test-test-suite"
|
||||
id "edu.wpi.first.GradleRIO" version "2024.2.1"
|
||||
id "edu.wpi.first.GradleRIO" version "2024.3.1"
|
||||
|
||||
id "com.dorongold.task-tree" version "2.1.0"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id "cpp"
|
||||
id "google-test-test-suite"
|
||||
id "edu.wpi.first.GradleRIO" version "2024.2.1"
|
||||
id "edu.wpi.first.GradleRIO" version "2024.3.1"
|
||||
|
||||
id "com.dorongold.task-tree" version "2.1.0"
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ allprojects {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
maven { url = "https://maven.photonvision.org/repository/internal/" }
|
||||
maven { url = "https://maven.photonvision.org/releases" }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id "cpp"
|
||||
id "google-test-test-suite"
|
||||
id "edu.wpi.first.GradleRIO" version "2024.2.1"
|
||||
id "edu.wpi.first.GradleRIO" version "2024.3.1"
|
||||
|
||||
id "com.dorongold.task-tree" version "2.1.0"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id "cpp"
|
||||
id "google-test-test-suite"
|
||||
id "edu.wpi.first.GradleRIO" version "2024.2.1"
|
||||
id "edu.wpi.first.GradleRIO" version "2024.3.1"
|
||||
|
||||
id "com.dorongold.task-tree" version "2.1.0"
|
||||
}
|
||||
@@ -12,8 +12,8 @@ repositories {
|
||||
}
|
||||
|
||||
wpi.maven.useDevelopment = true
|
||||
wpi.versions.wpilibVersion = "2024.2.1"
|
||||
wpi.versions.wpimathVersion = "2024.2.1"
|
||||
wpi.versions.wpilibVersion = "2024.3.1"
|
||||
wpi.versions.wpimathVersion = "2024.3.1"
|
||||
|
||||
apply from: "${rootDir}/../shared/examples_common.gradle"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
plugins {
|
||||
id "java"
|
||||
id "edu.wpi.first.GradleRIO" version "2024.2.1"
|
||||
id "edu.wpi.first.GradleRIO" version "2024.3.1"
|
||||
}
|
||||
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
plugins {
|
||||
id "java"
|
||||
id "edu.wpi.first.GradleRIO" version "2024.2.1"
|
||||
id "edu.wpi.first.GradleRIO" version "2024.3.1"
|
||||
}
|
||||
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
|
||||
@@ -8,7 +8,7 @@ allprojects {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
maven { url = "https://maven.photonvision.org/repository/internal/" }
|
||||
maven { url = "https://maven.photonvision.org/releases" }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
plugins {
|
||||
id "java"
|
||||
id "edu.wpi.first.GradleRIO" version "2024.2.1"
|
||||
id "edu.wpi.first.GradleRIO" version "2024.3.1"
|
||||
}
|
||||
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
plugins {
|
||||
id "java"
|
||||
id "edu.wpi.first.GradleRIO" version "2024.2.1"
|
||||
id "edu.wpi.first.GradleRIO" version "2024.3.1"
|
||||
}
|
||||
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
plugins {
|
||||
id "java"
|
||||
id "edu.wpi.first.GradleRIO" version "2024.2.1"
|
||||
id "edu.wpi.first.GradleRIO" version "2024.3.1"
|
||||
}
|
||||
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
@@ -11,8 +11,8 @@ apply from: "${rootDir}/../shared/examples_common.gradle"
|
||||
def ROBOT_MAIN_CLASS = "frc.robot.Main"
|
||||
|
||||
wpi.maven.useDevelopment = true
|
||||
wpi.versions.wpilibVersion = "2024.2.1"
|
||||
wpi.versions.wpimathVersion = "2024.2.1"
|
||||
wpi.versions.wpilibVersion = "2024.3.1"
|
||||
wpi.versions.wpimathVersion = "2024.3.1"
|
||||
|
||||
|
||||
// Define my targets (RoboRIO) and artifacts (deployable files)
|
||||
|
||||
@@ -80,6 +80,9 @@ if [[ "$DISTRO" = "Ubuntu" && "$INSTALL_NETWORK_MANAGER" != "true" && -z "$QUIET
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Update package list"
|
||||
apt-get update
|
||||
|
||||
echo "Installing curl..."
|
||||
apt-get install --yes curl
|
||||
echo "curl installation complete."
|
||||
@@ -136,6 +139,9 @@ echo "Installing v4l-utils..."
|
||||
apt-get install --yes v4l-utils
|
||||
echo "v4l-utils installation complete."
|
||||
|
||||
echo "Installing sqlite3"
|
||||
apt-get install --yes sqlite3
|
||||
|
||||
echo "Downloading latest stable release of PhotonVision..."
|
||||
mkdir -p /opt/photonvision
|
||||
cd /opt/photonvision
|
||||
|
||||
@@ -79,7 +79,7 @@ publishing {
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url ('https://maven.photonvision.org/repository/' + (isDev ? 'snapshots' : 'internal'))
|
||||
url(photonMavenURL)
|
||||
credentials {
|
||||
username 'ghactions'
|
||||
password System.getenv("ARTIFACTORY_API_KEY")
|
||||
|
||||
@@ -70,7 +70,7 @@ model {
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url ('https://maven.photonvision.org/repository/' + (isDev ? 'snapshots' : 'internal'))
|
||||
url(photonMavenURL)
|
||||
credentials {
|
||||
username 'ghactions'
|
||||
password System.getenv("ARTIFACTORY_API_KEY")
|
||||
|
||||
Reference in New Issue
Block a user