mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-27 02:01:40 +00:00
Compare commits
16 Commits
v2026.1.0-
...
v2026.1.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7a0fad54c | ||
|
|
e73420d62a | ||
|
|
12f74423d9 | ||
|
|
6c9a142622 | ||
|
|
149c214897 | ||
|
|
a952bab4c9 | ||
|
|
bc208bca85 | ||
|
|
dbd6eea4e9 | ||
|
|
afb73b3918 | ||
|
|
9011e285d2 | ||
|
|
8a141904a6 | ||
|
|
121433fd90 | ||
|
|
22567dea74 | ||
|
|
ba4eb621c3 | ||
|
|
43608c5113 | ||
|
|
021053d43e |
34
.github/workflows/build.yml
vendored
34
.github/workflows/build.yml
vendored
@@ -555,32 +555,32 @@ jobs:
|
||||
minimum_free_mb: ${{ matrix.minimum_free_mb }}
|
||||
root_location: ${{ matrix.root_location || 'partition=2' }}
|
||||
shrink_image: ${{ matrix.shrink_image || 'yes' }}
|
||||
commands: |
|
||||
chmod +x scripts/armrunner.sh
|
||||
./scripts/armrunner.sh
|
||||
java -jar *.jar --smoketest --platform=${{ matrix.plat_override }}
|
||||
commands: ./scripts/armrunner.sh
|
||||
|
||||
- name: Compress image
|
||||
# Compress the standard images
|
||||
if: ${{ ! startsWith(matrix.image_suffix, 'rubik') }}
|
||||
run: |
|
||||
set -ex
|
||||
new_jar=$(realpath $(find . -name photonvision\*-linuxarm64.jar))
|
||||
new_image_name=$(basename "${new_jar/.jar/_${{ matrix.image_suffix }}.img}")
|
||||
sudo mv ${{ steps.generate_image.outputs.image }} $new_image_name
|
||||
sudo xz -T 0 -v $new_image_name
|
||||
sudo xz -T 0 -kv $new_image_name
|
||||
echo "smoketest_image_loc=${new_image_name}" >> $GITHUB_ENV
|
||||
|
||||
- name: Tar built image
|
||||
- name: Tar built image (Rubik)
|
||||
# Build the RubikPi3-specific tar file
|
||||
if: ${{ startsWith(matrix.image_suffix, 'rubik') }}
|
||||
run: |
|
||||
set -ex
|
||||
new_jar=$(realpath $(find . -name photonvision\*-linuxarm64.jar))
|
||||
new_image_name=$(basename "${new_jar/.jar/_${{ matrix.image_suffix }}.img}")
|
||||
|
||||
tardir=$(basename "${new_jar/.jar/_${{ matrix.image_suffix }}.img}")
|
||||
imagedir=$(dirname ${{ steps.generate_image.outputs.image }})
|
||||
tardir=${new_image_name}
|
||||
sudo mkdir --parents ${tardir}
|
||||
sudo mv ${imagedir}/* ${tardir}/
|
||||
sudo tar -I 'xz -T0' -cf ${new_image_name}.tar.xz ${tardir} --checkpoint=10000 --checkpoint-action=echo='%T'
|
||||
sudo cp ${imagedir}/* ${tardir}/
|
||||
sudo tar -I 'xz -T0' -cf ${tardir}.tar.xz ${tardir} --checkpoint=10000 --checkpoint-action=echo='%T'
|
||||
# Point smoketest to the old image
|
||||
echo "smoketest_image_loc=${{ steps.generate_image.outputs.image }}" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/upload-artifact@v6
|
||||
name: Upload image
|
||||
@@ -588,6 +588,16 @@ jobs:
|
||||
name: image-${{ matrix.image_suffix }}
|
||||
path: photonvision*.xz
|
||||
|
||||
# This is done after uploading the image to avoid contaminating the image with logs, caches, etc.
|
||||
- uses: photonvision/photon-image-runner@HEAD
|
||||
name: Smoketest Image
|
||||
with:
|
||||
image_url: file://${{ env.smoketest_image_loc }}
|
||||
minimum_free_mb: ${{ matrix.minimum_free_mb }}
|
||||
root_location: ${{ matrix.root_location || 'partition=2' }}
|
||||
shrink_image: ${{ matrix.shrink_image || 'yes' }}
|
||||
commands: java -jar *.jar --smoketest --platform=${{ matrix.plat_override }}
|
||||
|
||||
matrix-checker:
|
||||
# This job always runs last to set the overall result based on the matrix jobs. If any matrix job failed, this job will fail.
|
||||
# This makes it so that we don't need to add each matrix job individually to CI checks.
|
||||
@@ -600,7 +610,7 @@ jobs:
|
||||
release:
|
||||
# Require smoketest-native so that if those fail, we don't release broken artifacts
|
||||
needs: [build-photonlib-vendorjson, build-image, combine, build-package-linux, build-package-macos, build-package-windows, run-smoketest-native]
|
||||
if: github.ref == ('refs/heads/main' || startsWith(github.ref, 'refs/tags/v')) && github.repository == 'PhotonVision/photonvision'
|
||||
if: (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')) && github.repository == 'PhotonVision/photonvision'
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
# Download all fat JARs
|
||||
|
||||
100
.github/workflows/python.yml
vendored
100
.github/workflows/python.yml
vendored
@@ -12,7 +12,7 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
build-py:
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
steps:
|
||||
@@ -29,38 +29,57 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install setuptools wheel pytest mypy
|
||||
pip install setuptools wheel
|
||||
|
||||
- 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: Run mypy type checking
|
||||
run: mypy --show-column-numbers --config-file photon-lib/py/pyproject.toml photon-lib
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v6
|
||||
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/
|
||||
test-py:
|
||||
needs: build-py
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
permissions:
|
||||
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.14
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install pytest mypy
|
||||
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: dist
|
||||
path: dist/
|
||||
|
||||
- name: Install package
|
||||
shell: bash
|
||||
run: pip install --no-cache-dir dist/*.whl
|
||||
|
||||
- name: Run Unit Tests
|
||||
shell: bash
|
||||
run: pytest --import-mode=importlib photon-lib/py/test/
|
||||
|
||||
- name: Run mypy type checking
|
||||
run: mypy --show-column-numbers --config-file photon-lib/py/pyproject.toml photon-lib
|
||||
|
||||
build-python-examples:
|
||||
needs: build-py
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-24.04, windows-2022, macos-14]
|
||||
@@ -81,28 +100,18 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install setuptools wheel pytest mypy
|
||||
|
||||
- name: Build wheel
|
||||
working-directory: ./photon-lib/py
|
||||
run: python setup.py sdist bdist_wheel
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: dist
|
||||
path: ./photon-lib/py/dist/
|
||||
|
||||
- name: Build and configure PhotonLibPy
|
||||
working-directory: ./photon-lib/py
|
||||
shell: bash
|
||||
run: |
|
||||
./buildAndTest.sh
|
||||
./enableUsingDevBuilds.sh
|
||||
|
||||
- name: Run Unit Tests
|
||||
- name: Install PhotonLibPy package
|
||||
working-directory: ./photon-lib/py
|
||||
shell: bash
|
||||
run: |
|
||||
pip install --no-cache-dir dist/*.whl
|
||||
pytest
|
||||
|
||||
- name: Run mypy type checking
|
||||
run: mypy --show-column-numbers --config-file photon-lib/py/pyproject.toml photon-lib
|
||||
|
||||
- name: Build Python examples
|
||||
working-directory: photonlib-python-examples
|
||||
@@ -113,3 +122,24 @@ jobs:
|
||||
echo $folder
|
||||
./run.sh $folder
|
||||
done
|
||||
|
||||
deploy:
|
||||
needs: [test-py, build-python-examples]
|
||||
runs-on: ubuntu-24.04
|
||||
# Only upload on tags
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: dist
|
||||
path: dist/
|
||||
|
||||
- name: Publish package distributions to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
packages-dir: ./dist/
|
||||
|
||||
permissions:
|
||||
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
|
||||
|
||||
@@ -4,7 +4,7 @@ plugins {
|
||||
id "cpp"
|
||||
id "com.diffplug.spotless" version "8.1.0"
|
||||
id "edu.wpi.first.wpilib.repositories.WPILibRepositoriesPlugin" version "2020.2"
|
||||
id "edu.wpi.first.GradleRIO" version "2026.1.1"
|
||||
id "edu.wpi.first.GradleRIO" version "2026.2.1"
|
||||
id 'org.photonvision.tools.WpilibTools' version '2.3.3-photon'
|
||||
id 'com.google.protobuf' version '0.9.3' apply false
|
||||
id 'edu.wpi.first.GradleJni' version '1.1.0'
|
||||
@@ -32,7 +32,7 @@ ext.allOutputsFolder = file("$project.buildDir/outputs")
|
||||
apply from: "versioningHelper.gradle"
|
||||
|
||||
ext {
|
||||
wpilibVersion = "2026.1.1"
|
||||
wpilibVersion = "2026.2.1"
|
||||
wpimathVersion = wpilibVersion
|
||||
openCVYear = "2025"
|
||||
openCVversion = "4.10.0-3"
|
||||
|
||||
@@ -83,7 +83,7 @@ Details about a particular calibration can be viewed by clicking on that resolut
|
||||
More info on what these parameters mean can be found in [OpenCV's docs](https://docs.opencv.org/4.8.0/d4/d94/tutorial_camera_calibration.html)
|
||||
:::
|
||||
|
||||
- Fx/Fy: Estimated camera focal length, in mm
|
||||
- Fx/Fy: Estimated camera focal length, in pixels
|
||||
- Fx/Cy: Estimated camera optical center, in pixels. This should be at about the center of the image
|
||||
- Distortion: OpenCV camera model distortion coefficients
|
||||
- FOV: calculated using estimated focal length and image size. Useful for gut-checking calibration results
|
||||
|
||||
@@ -108,7 +108,7 @@ When taking in a result from a `PhotonCamera`, PhotonPoseEstimator offers nine p
|
||||
flat on the floor. This computation takes place on the RoboRIO, and should not take more than 2ms.
|
||||
This also requires addHeadingData to be called every frame so heading data is up to date.
|
||||
|
||||
Calling one of the `estimate<strategy>Pose()` methods on your `PhotonPoseEstimator` will return an `Optional<EstimatedRobotPose>`, which includes a `Pose3d` of the latest estimated pose (using the selected strategy) along with a `double` of the timestamp when the robot pose was estimated. The recommended way to use the estimatePose methods is to
|
||||
Calling one of the `estimate<strategy>Pose()` methods on your `PhotonPoseEstimator` will return an `Optional<EstimatedRobotPose>`, which will be empty if there are no detected tags, not enough detected tags (for multi-tag strategies), missing data (typically heading data), or if the internal solvers failed (this is a rare scenario). `EstimatedRobotPose` includes a `Pose3d` of the latest estimated pose (using the selected strategy) along with a `double` of the timestamp when the robot pose was estimated. The recommended way to use the estimatePose methods is to
|
||||
1. do estimation with one of MultiTag methods, check if the result is empty, then
|
||||
2. fallback to single tag estimation using a method like `estimateLowestAmbiguityPose`.
|
||||
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
|
||||
## Coprocessor with regulator
|
||||
|
||||
1. **IT IS STRONGLY RECOMMENDED** to use one of the recommended power regulators to prevent vision from cutting out from voltage drops while operating the robot. We recommend wiring the regulator directly to the power header pins or using a locking USB C cable. In any case we recommend hot gluing the connector.
|
||||
1. **IT IS STRONGLY RECOMMENDED** to use one of the recommended power regulators to prevent vision from cutting out from voltage drops while operating the robot. We recommend wiring the regulator directly to the power header pins using either of the two methods listed below or using a locking USB C cable.
|
||||
* Method 1: Soldering to GPIO Header Pins
|
||||
* Using 20 AWG or preferably 18 AWG wires, solder two wires from the regulator to the power header pins on the coprocessor and cover with heat-shrink tubing.
|
||||
* Method 2: Using a Wire-to-Board Connector
|
||||
* Using a wire-to-board connector with 20 AWG or preferably 18 AWG wires, connect two wires from the regulator to the power header pins on the coprocessor. To prevent the connector from becoming unseated, we recommend applying hot glue to the connector.
|
||||
|
||||
2. Run an ethernet cable from your coprocessor to your network switch / radio.
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@ const patternHeight = ref(8);
|
||||
const boardType = ref<CalibrationBoardTypes>(CalibrationBoardTypes.Charuco);
|
||||
const useOldPattern = ref(false);
|
||||
const tagFamily = ref<CalibrationTagFamilies>(CalibrationTagFamilies.Dict_4X4_1000);
|
||||
const requestedVideoFormatIndex = ref(0);
|
||||
|
||||
// Emperical testing - with stack size limit of 1MB, we can handle at -least- 700k points
|
||||
const tooManyPoints = computed(
|
||||
@@ -191,6 +192,7 @@ const startCalibration = () => {
|
||||
useCameraSettingsStore().currentCameraSettings.currentPipelineIndex = WebsocketPipelineType.Calib3d;
|
||||
// isCalibrating.value = true;
|
||||
calibCanceled.value = false;
|
||||
requestedVideoFormatIndex.value = useStateStore().calibrationData.videoFormatIndex;
|
||||
};
|
||||
const showCalibEndDialog = ref(false);
|
||||
const calibCanceled = ref(false);
|
||||
@@ -559,7 +561,7 @@ const setSelectedVideoFormat = (format: VideoFormat) => {
|
||||
{{
|
||||
useCameraSettingsStore().currentCameraSettings.validVideoFormats.map((f) =>
|
||||
getResolutionString(f.resolution)
|
||||
)[useStateStore().calibrationData.videoFormatIndex]
|
||||
)[requestedVideoFormatIndex]
|
||||
}}!
|
||||
</v-card-text>
|
||||
</template>
|
||||
|
||||
@@ -187,7 +187,7 @@ const viewingImg = ref(0);
|
||||
.getCalibrationCoeffs(props.videoFormat.resolution)
|
||||
?.cameraIntrinsics.data[0].toFixed(2) || 0.0
|
||||
}}
|
||||
mm
|
||||
px
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -198,7 +198,7 @@ const viewingImg = ref(0);
|
||||
.getCalibrationCoeffs(props.videoFormat.resolution)
|
||||
?.cameraIntrinsics.data[4].toFixed(2) || 0.0
|
||||
}}
|
||||
mm
|
||||
px
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -26,7 +26,7 @@ const importWidth = ref<number | null>(null);
|
||||
const importVersion = ref<string | null>(null);
|
||||
|
||||
// TODO gray out the button when model is uploading
|
||||
const handleImport = async () => {
|
||||
const handleImport = () => {
|
||||
if (importModelFile.value === null) return;
|
||||
|
||||
const formData = new FormData();
|
||||
@@ -72,13 +72,13 @@ const handleImport = async () => {
|
||||
importVersion.value = null;
|
||||
};
|
||||
|
||||
const deleteModel = async (model: ObjectDetectionModelProperties) => {
|
||||
const deleteModel = (model: ObjectDetectionModelProperties) => {
|
||||
axiosPost("/objectdetection/delete", "delete an object detection model", {
|
||||
modelPath: model.modelPath
|
||||
});
|
||||
};
|
||||
|
||||
const renameModel = async (model: ObjectDetectionModelProperties, newName: string) => {
|
||||
const renameModel = (model: ObjectDetectionModelProperties, newName: string) => {
|
||||
useStateStore().showSnackbarMessage({
|
||||
message: "Renaming Object Detection Model...",
|
||||
color: "secondary",
|
||||
|
||||
@@ -22,7 +22,7 @@ export const statusCheck = async (timeout: number, ip?: string): Promise<boolean
|
||||
while (pollLimit > 0) {
|
||||
try {
|
||||
pollLimit--;
|
||||
await axios.get(ip ? `http://${ip}/status` : "/status");
|
||||
await axios.get(ip ? `http://${ip}/api/status` : "/status");
|
||||
return true;
|
||||
} catch {
|
||||
// Backend not ready yet, wait and retry
|
||||
|
||||
@@ -146,7 +146,7 @@ public class NeuralNetworkModelManager {
|
||||
"vase",
|
||||
"scissors",
|
||||
"teddy bear",
|
||||
"hair drier",
|
||||
"hair drier", // Typo in official COCO documentation
|
||||
"toothbrush"));
|
||||
|
||||
nnProps.addModelProperties(
|
||||
|
||||
@@ -26,7 +26,7 @@ import org.photonvision.vision.pipeline.result.CVPipelineResult;
|
||||
|
||||
public abstract class CVPipeline<R extends CVPipelineResult, S extends CVPipelineSettings>
|
||||
implements Releasable {
|
||||
static final int MAX_MULTI_TARGET_RESULTS = 10;
|
||||
static final int MAX_MULTI_TARGET_RESULTS = 50;
|
||||
|
||||
protected S settings;
|
||||
protected FrameStaticProperties frameStaticProperties;
|
||||
|
||||
@@ -271,6 +271,9 @@ class PhotonCameraSim:
|
||||
camRt = RotTrlTransform3d.makeRelativeTo(cameraPose)
|
||||
|
||||
for tgt in targets:
|
||||
if len(detectableTgts) >= 50:
|
||||
break
|
||||
|
||||
# pose isn't visible, skip to next
|
||||
if not self.canSeeTargetPose(cameraPose, tgt):
|
||||
continue
|
||||
|
||||
@@ -4,15 +4,13 @@ import subprocess
|
||||
from setuptools import find_packages, setup
|
||||
|
||||
gitDescribeResult = (
|
||||
subprocess.check_output(
|
||||
["git", "describe", "--tags", "--match=v*", "--exclude=*rc*", "--always"]
|
||||
)
|
||||
subprocess.check_output(["git", "describe", "--tags", "--match=v*", "--always"])
|
||||
.decode("utf-8")
|
||||
.strip()
|
||||
)
|
||||
|
||||
m = re.search(
|
||||
r"(v[0-9]{4}\.[0-9]{1}\.[0-9]{1})-?((?:beta)?(?:alpha)?)-?([0-9\.]*)",
|
||||
r"v([0-9]{4}\.[0-9]{1}\.[0-9]{1})-?((?:beta|alpha|rc)?)-?([0-9\.]*)",
|
||||
gitDescribeResult,
|
||||
)
|
||||
|
||||
@@ -26,7 +24,7 @@ if m:
|
||||
prefix = m.group(1)
|
||||
maturity = m.group(2)
|
||||
suffix = m.group(3).replace(".", "")
|
||||
versionString = f"{prefix}.{maturity}.{suffix}"
|
||||
versionString = f"{prefix}{maturity}{suffix}"
|
||||
else:
|
||||
split = gitDescribeResult.split("-")
|
||||
if len(split) == 3:
|
||||
@@ -35,8 +33,7 @@ if m:
|
||||
versionString = f"{year[1:]}post{commits}"
|
||||
print("using dev release " + versionString)
|
||||
else:
|
||||
year = gitDescribeResult
|
||||
versionString = year[1:]
|
||||
versionString = gitDescribeResult[1:]
|
||||
print("using full release " + versionString)
|
||||
|
||||
|
||||
@@ -60,12 +57,12 @@ setup(
|
||||
package_data={"photonlibpy": ["py.typed"]},
|
||||
version=versionString,
|
||||
install_requires=[
|
||||
"numpy~=2.4",
|
||||
"wpilib==2026.1.1",
|
||||
"robotpy-wpimath==2026.1.1",
|
||||
"robotpy-apriltag==2026.1.1",
|
||||
"robotpy-cscore==2026.1.1",
|
||||
"pyntcore==2026.1.1",
|
||||
"numpy~=2.3",
|
||||
"wpilib>=2026.2.1,<2027",
|
||||
"robotpy-wpimath>=2026.2.1,<2027",
|
||||
"robotpy-apriltag>=2026.2.1,<2027",
|
||||
"robotpy-cscore>=2026.2.1,<2027",
|
||||
"pyntcore>=2026.2.1,<2027",
|
||||
"opencv-python;platform_machine!='roborio'",
|
||||
],
|
||||
description=descriptionStr,
|
||||
|
||||
@@ -78,6 +78,35 @@ def test_VisibilityCupidShuffle() -> None:
|
||||
assert camera.getLatestResult().hasTargets()
|
||||
|
||||
|
||||
def test_bunchaTargets() -> None:
|
||||
visionSysSim = VisionSystemSim("Test")
|
||||
camera = PhotonCamera("camera")
|
||||
cameraSim = PhotonCameraSim(camera)
|
||||
visionSysSim.addCamera(cameraSim, Transform3d())
|
||||
|
||||
cameraSim.prop.setCalibrationFromFOV(640, 480, fovDiag=Rotation2d.fromDegrees(80.0))
|
||||
|
||||
for i in range(100):
|
||||
targetPose = Pose3d(
|
||||
Translation3d(15.98 + i * 0.1, 0.0, 2.0), Rotation3d(0, 0, math.pi)
|
||||
)
|
||||
visionSysSim.addVisionTargets(
|
||||
[
|
||||
VisionTargetSim(
|
||||
targetPose,
|
||||
TargetModel.createPlanar(width=1.0, height=1.0),
|
||||
4774 + i,
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
robotPose = Pose2d(Translation2d(2.0, 0.0), Rotation2d.fromDegrees(5.0))
|
||||
|
||||
visionSysSim.update(robotPose)
|
||||
|
||||
assert len(camera.getLatestResult().getTargets()) == 50
|
||||
|
||||
|
||||
def test_NotVisibleVert1() -> None:
|
||||
targetPose = Pose3d(Translation3d(15.98, 0.0, 2.0), Rotation3d(0, 0, math.pi))
|
||||
|
||||
|
||||
@@ -45,7 +45,6 @@ import edu.wpi.first.wpilibj.Alert;
|
||||
import edu.wpi.first.wpilibj.Alert.AlertType;
|
||||
import edu.wpi.first.wpilibj.DriverStation;
|
||||
import edu.wpi.first.wpilibj.Timer;
|
||||
import edu.wpi.first.wpilibj.util.WPILibVersion;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -189,50 +188,6 @@ public class PhotonCamera implements AutoCloseable {
|
||||
|
||||
static void verifyDependencies() {
|
||||
// spotless:off
|
||||
if (!WPILibVersion.Version.equals(PhotonVersion.wpilibTargetVersion)) {
|
||||
String bfw = """
|
||||
|
||||
|
||||
|
||||
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\s
|
||||
>>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\s
|
||||
>>> \s
|
||||
>>> You are running an incompatible version \s
|
||||
>>> of PhotonVision ! \s
|
||||
>>> \s
|
||||
>>> PhotonLib """
|
||||
+ PhotonVersion.versionString
|
||||
+ " is built for WPILib "
|
||||
+ PhotonVersion.wpilibTargetVersion
|
||||
+ "\n"
|
||||
+ ">>> but you are using WPILib "
|
||||
+ WPILibVersion.Version
|
||||
+ """
|
||||
\n>>> \s
|
||||
>>> This is neither tested nor supported. \s
|
||||
>>> You MUST update WPILib, PhotonLib, or both.
|
||||
>>> Check `./gradlew dependencies` and ensure\s
|
||||
>>> all mentions of OpenCV match the version \s
|
||||
>>> that PhotonLib was built for. If you find a
|
||||
>>> a mismatched version in a dependency, you\s
|
||||
>>> must take steps to update the version of \s
|
||||
>>> OpenCV used in that dependency. If you do\s
|
||||
>>> not control that dependency and an updated\s
|
||||
>>> version is not available, contact the \s
|
||||
>>> developers of that dependency. \s
|
||||
>>> \s
|
||||
>>> Your code will now crash. \s
|
||||
>>> We hope your day gets better. \s
|
||||
>>> \s
|
||||
>>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\s
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\s
|
||||
""";
|
||||
|
||||
DriverStation.reportWarning(bfw, false);
|
||||
DriverStation.reportError(bfw, false);
|
||||
throw new UnsupportedOperationException(bfw);
|
||||
}
|
||||
if (!Core.VERSION.equals(PhotonVersion.opencvTargetVersion)) {
|
||||
String bfw = """
|
||||
|
||||
|
||||
@@ -686,7 +686,7 @@ public class PhotonPoseEstimator {
|
||||
*
|
||||
* @param cameraResult A pipeline result from the camera.
|
||||
* @return An {@link EstimatedRobotPose} with an estimated pose, timestamp, and targets used to
|
||||
* create the estimate.
|
||||
* create the estimate, or an empty optional if there's no targets or heading data.
|
||||
*/
|
||||
public Optional<EstimatedRobotPose> estimatePnpDistanceTrigSolvePose(
|
||||
PhotonPipelineResult cameraResult) {
|
||||
@@ -758,7 +758,8 @@ public class PhotonPoseEstimator {
|
||||
* @param headingScaleFactor If headingFree is false, this weights the cost of changing our robot
|
||||
* heading estimate against the tag corner reprojection error cont.
|
||||
* @return An {@link EstimatedRobotPose} with an estimated pose, timestamp, and targets used to
|
||||
* create the estimate.
|
||||
* create the estimate, or an empty optional if there's no targets or heading data, or if the
|
||||
* solver fails to solve the problem.
|
||||
*/
|
||||
public Optional<EstimatedRobotPose> estimateConstrainedSolvepnpPose(
|
||||
PhotonPipelineResult cameraResult,
|
||||
@@ -770,6 +771,18 @@ public class PhotonPoseEstimator {
|
||||
if (!shouldEstimate(cameraResult)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
// Need heading if heading fixed
|
||||
if (!headingFree) {
|
||||
if (headingBuffer.getSample(cameraResult.getTimestampSeconds()).isEmpty()) {
|
||||
return Optional.empty();
|
||||
} else {
|
||||
// If heading fixed, force rotation component
|
||||
seedPose =
|
||||
new Pose3d(
|
||||
seedPose.getTranslation(),
|
||||
new Rotation3d(headingBuffer.getSample(cameraResult.getTimestampSeconds()).get()));
|
||||
}
|
||||
}
|
||||
var pnpResult =
|
||||
VisionEstimation.estimateRobotPoseConstrainedSolvepnp(
|
||||
cameraMatrix,
|
||||
@@ -799,7 +812,8 @@ public class PhotonPoseEstimator {
|
||||
*
|
||||
* @param cameraResult A pipeline result from the camera.
|
||||
* @return An {@link EstimatedRobotPose} with an estimated pose, timestamp, and targets used to
|
||||
* create the estimate.
|
||||
* create the estimate, or an empty optional if there's no targets, no multi-tag results, or
|
||||
* multi-tag is disabled in the web UI.
|
||||
*/
|
||||
public Optional<EstimatedRobotPose> estimateCoprocMultiTagPose(
|
||||
PhotonPipelineResult cameraResult) {
|
||||
@@ -829,7 +843,8 @@ public class PhotonPoseEstimator {
|
||||
* @param cameraMatrix Camera intrinsics from camera calibration data
|
||||
* @param distCoeffs Distortion coefficients from camera calibration data.
|
||||
* @return An {@link EstimatedRobotPose} with an estimated pose, timestamp, and targets used to
|
||||
* create the estimate.
|
||||
* create the estimate, or an empty optional if there's less than 2 targets visible or
|
||||
* SolvePnP fails.
|
||||
*/
|
||||
public Optional<EstimatedRobotPose> estimateRioMultiTagPose(
|
||||
PhotonPipelineResult cameraResult, Matrix<N3, N3> cameraMatrix, Matrix<N8, N1> distCoeffs) {
|
||||
@@ -861,7 +876,7 @@ public class PhotonPoseEstimator {
|
||||
*
|
||||
* @param cameraResult A pipeline result from the camera.
|
||||
* @return An {@link EstimatedRobotPose} with an estimated pose, timestamp, and targets used to
|
||||
* create the estimate.
|
||||
* create the estimate, or an empty optional if there's no targets.
|
||||
*/
|
||||
public Optional<EstimatedRobotPose> estimateLowestAmbiguityPose(
|
||||
PhotonPipelineResult cameraResult) {
|
||||
@@ -911,7 +926,7 @@ public class PhotonPoseEstimator {
|
||||
*
|
||||
* @param cameraResult A pipeline result from the camera.
|
||||
* @return An {@link EstimatedRobotPose} with an estimated pose, timestamp, and targets used to
|
||||
* create the estimate.
|
||||
* create the estimate, or an empty optional if there's no targets.
|
||||
*/
|
||||
public Optional<EstimatedRobotPose> estimateClosestToCameraHeightPose(
|
||||
PhotonPipelineResult cameraResult) {
|
||||
@@ -989,7 +1004,7 @@ public class PhotonPoseEstimator {
|
||||
* @param cameraResult A pipeline result from the camera.
|
||||
* @param referencePose reference pose to check vector magnitude difference against.
|
||||
* @return An {@link EstimatedRobotPose} with an estimated pose, timestamp, and targets used to
|
||||
* create the estimate.
|
||||
* create the estimate, or an empty optional if there's no targets.
|
||||
*/
|
||||
public Optional<EstimatedRobotPose> estimateClosestToReferencePose(
|
||||
PhotonPipelineResult cameraResult, Pose3d referencePose) {
|
||||
@@ -1062,7 +1077,7 @@ public class PhotonPoseEstimator {
|
||||
*
|
||||
* @param cameraResult A pipeline result from the camera.
|
||||
* @return An {@link EstimatedRobotPose} with an estimated pose, timestamp, and targets used to
|
||||
* create the estimate.
|
||||
* create the estimate, or an empty optional if there's no targets.
|
||||
*/
|
||||
public Optional<EstimatedRobotPose> estimateAverageBestTargetsPose(
|
||||
PhotonPipelineResult cameraResult) {
|
||||
|
||||
@@ -442,6 +442,10 @@ public class PhotonCameraSim implements AutoCloseable {
|
||||
Mat.zeros(videoFrameSize, CvType.CV_8UC1).assignTo(videoSimFrameRaw);
|
||||
|
||||
for (var tgt : targets) {
|
||||
if (detectableTgts.size() >= 50) {
|
||||
break;
|
||||
}
|
||||
|
||||
// pose isn't visible, skip to next
|
||||
if (!canSeeTargetPose(cameraPose, tgt)) continue;
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <WPILibVersion.h>
|
||||
#include <frc/Errors.h>
|
||||
#include <frc/RobotController.h>
|
||||
#include <frc/Timer.h>
|
||||
@@ -47,48 +46,6 @@ static constexpr units::second_t WARN_DEBOUNCE_SEC = 5_s;
|
||||
static constexpr units::second_t HEARTBEAT_DEBOUNCE_SEC = 500_ms;
|
||||
|
||||
inline void verifyDependencies() {
|
||||
if (!(std::string_view{GetWPILibVersion()} ==
|
||||
std::string_view{photon::PhotonVersion::wpilibTargetVersion})) {
|
||||
std::string bfw =
|
||||
"\n\n\n\n\n"
|
||||
">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
|
||||
">>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
||||
">>> \n"
|
||||
">>> You are running an incompatible version \n"
|
||||
">>> of PhotonVision ! \n"
|
||||
">>> \n"
|
||||
">>> PhotonLib ";
|
||||
bfw += photon::PhotonVersion::versionString;
|
||||
bfw += " is built for WPILib ";
|
||||
bfw += photon::PhotonVersion::wpilibTargetVersion;
|
||||
bfw +=
|
||||
"\n"
|
||||
">>> but you are using WPILib ";
|
||||
bfw += GetWPILibVersion();
|
||||
bfw +=
|
||||
"\n>>> \n"
|
||||
">>> This is neither tested nor supported. \n"
|
||||
">>> You MUST update WPILib, PhotonLib, or both.\n"
|
||||
">>> Check `./gradlew dependencies` and ensure\n"
|
||||
">>> all mentions of WPILib match the version \n"
|
||||
">>> that PhotonLib was built for. If you find a"
|
||||
">>> a mismatched version in a dependency, you\n"
|
||||
">>> must take steps to update the version of \n"
|
||||
">>> WPILib used in that dependency. If you do\n"
|
||||
">>> not control that dependency and an updated\n"
|
||||
">>> version is not available, contact the \n"
|
||||
">>> developers of that dependency. \n"
|
||||
">>> \n"
|
||||
">>> Your code will now crash. \n"
|
||||
">>> We hope your day gets better. \n"
|
||||
">>> \n"
|
||||
">>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
||||
">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n";
|
||||
|
||||
FRC_ReportWarning(bfw);
|
||||
FRC_ReportError(frc::err::Error, bfw);
|
||||
throw new std::runtime_error(std::string{bfw});
|
||||
}
|
||||
if (!(std::string_view{cv::getVersionString()} ==
|
||||
std::string_view{photon::PhotonVersion::opencvTargetVersion})) {
|
||||
std::string bfw =
|
||||
|
||||
@@ -634,13 +634,18 @@ PhotonPoseEstimator::EstimateConstrainedSolvepnpPose(
|
||||
if (!ShouldEstimate(cameraResult)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
// Need heading if heading fixed
|
||||
if (!headingFree) {
|
||||
seedPose = frc::Pose3d{
|
||||
seedPose.Translation(),
|
||||
frc::Rotation3d{
|
||||
headingBuffer.Sample(cameraResult.GetTimestamp()).value()}};
|
||||
if (!headingBuffer.Sample(cameraResult.GetTimestamp())) {
|
||||
return std::nullopt;
|
||||
} else {
|
||||
// If heading fixed, force rotation component
|
||||
seedPose = frc::Pose3d{
|
||||
seedPose.Translation(),
|
||||
frc::Rotation3d{
|
||||
headingBuffer.Sample(cameraResult.GetTimestamp()).value()}};
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<photon::PhotonTrackedTarget> targets{
|
||||
cameraResult.GetTargets().begin(), cameraResult.GetTargets().end()};
|
||||
|
||||
|
||||
@@ -131,6 +131,10 @@ PhotonPipelineResult PhotonCameraSim::Process(
|
||||
blankFrame.assignTo(videoSimFrameRaw);
|
||||
|
||||
for (const auto& tgt : targets) {
|
||||
if (detectableTgts.size() >= 50) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!CanSeeTargetPose(cameraPose, tgt)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ class PhotonPoseEstimator {
|
||||
*
|
||||
* @param cameraResult A pipeline result from the camera.
|
||||
* @return An EstimatedRobotPose with an estimated pose, timestamp, and
|
||||
* targets used to create the estimate.
|
||||
* targets used to create the estimate, or std::nullopt if there's no targets.
|
||||
*/
|
||||
std::optional<EstimatedRobotPose> EstimateLowestAmbiguityPose(
|
||||
PhotonPipelineResult cameraResult);
|
||||
@@ -306,7 +306,7 @@ class PhotonPoseEstimator {
|
||||
*
|
||||
* @param cameraResult A pipeline result from the camera.
|
||||
* @return An EstimatedRobotPose with an estimated pose, timestamp and
|
||||
* targets used to create the estimate.
|
||||
* targets used to create the estimate, or std::nullopt if there's no targets.
|
||||
*/
|
||||
std::optional<EstimatedRobotPose> EstimateClosestToCameraHeightPose(
|
||||
PhotonPipelineResult cameraResult);
|
||||
@@ -319,7 +319,7 @@ class PhotonPoseEstimator {
|
||||
* @param referencePose reference pose to check vector magnitude difference
|
||||
* against.
|
||||
* @return An EstimatedRobotPose with an estimated pose, timestamp, and
|
||||
* targets used to create the estimate.
|
||||
* targets used to create the estimate, or std::nullopt if there's no targets.
|
||||
*/
|
||||
std::optional<EstimatedRobotPose> EstimateClosestToReferencePose(
|
||||
PhotonPipelineResult cameraResult, frc::Pose3d referencePose);
|
||||
@@ -331,7 +331,8 @@ class PhotonPoseEstimator {
|
||||
*
|
||||
* @param cameraResult A pipeline result from the camera.
|
||||
* @return An EstimatedRobotPose with an estimated pose, timestamp, and
|
||||
* targets used to create the estimate.
|
||||
* targets used to create the estimate or std::nullopt if there's no targets,
|
||||
* no multi-tag results, or multi-tag is disabled in the web UI.
|
||||
*/
|
||||
std::optional<EstimatedRobotPose> EstimateCoprocMultiTagPose(
|
||||
PhotonPipelineResult cameraResult);
|
||||
@@ -345,7 +346,8 @@ class PhotonPoseEstimator {
|
||||
* @param cameraMatrix Camera intrinsics from camera calibration data.
|
||||
* @param distCoeffs Distortion coefficients from camera calibration data.
|
||||
* @return An EstimatedRobotPose with an estimated pose, timestamp, and
|
||||
* targets used to create the estimate.
|
||||
* targets used to create the estimate, or std::nullopt if there's less than 2
|
||||
* targets visible or SolvePnP fails.
|
||||
*/
|
||||
std::optional<EstimatedRobotPose> EstimateRioMultiTagPose(
|
||||
PhotonPipelineResult cameraResult, PhotonCamera::CameraMatrix camMat,
|
||||
@@ -363,7 +365,8 @@ class PhotonPoseEstimator {
|
||||
*
|
||||
* @param cameraResult A pipeline result from the camera.
|
||||
* @return An EstimatedRobotPose with an estimated pose, timestamp, and
|
||||
* targets used to create the estimate.
|
||||
* targets used to create the estimate, or std::nullopt if there's no targets
|
||||
* or heading data.
|
||||
*/
|
||||
std::optional<EstimatedRobotPose> EstimatePnpDistanceTrigSolvePose(
|
||||
PhotonPipelineResult cameraResult);
|
||||
@@ -372,7 +375,7 @@ class PhotonPoseEstimator {
|
||||
* Return the average of the best target poses using ambiguity as weight.
|
||||
* @param cameraResult A pipeline result from the camera.
|
||||
* @return An EstimatedRobotPose with an estimated pose, timestamp, and
|
||||
* targets used to create the estimate.
|
||||
* targets used to create the estimate, or std::nullopt if there's no targets.
|
||||
*/
|
||||
std::optional<EstimatedRobotPose> EstimateAverageBestTargetsPose(
|
||||
PhotonPipelineResult cameraResult);
|
||||
@@ -401,7 +404,8 @@ class PhotonPoseEstimator {
|
||||
* changing our robot heading estimate against the tag corner reprojection
|
||||
* error cost.
|
||||
* @return An EstimatedRobotPose with an estimated pose, timestamp, and
|
||||
* targets used to create the estimate.
|
||||
* targets used to create the estimate, or std::nullopt if there's no targets
|
||||
* or heading data, or if the solver fails to solve the problem.
|
||||
*/
|
||||
std::optional<EstimatedRobotPose> EstimateConstrainedSolvepnpPose(
|
||||
photon::PhotonPipelineResult cameraResult,
|
||||
|
||||
@@ -179,6 +179,28 @@ class VisionSystemSimTest {
|
||||
assertTrue(result.hasTargets());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBunchaTargets() {
|
||||
var visionSysSim = new VisionSystemSim("Test");
|
||||
var camera = new PhotonCamera(inst, "camera");
|
||||
var cameraSim = new PhotonCameraSim(camera);
|
||||
visionSysSim.addCamera(cameraSim, new Transform3d());
|
||||
cameraSim.prop.setCalibration(640, 480, Rotation2d.fromDegrees(80));
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
final var targetPose =
|
||||
new Pose3d(new Translation3d(15.98 + i * 0.1, 0, 1), new Rotation3d(0, 0, Math.PI));
|
||||
visionSysSim.addVisionTargets(new VisionTargetSim(targetPose, new TargetModel(0.5, 0.5), i));
|
||||
}
|
||||
|
||||
var robotPose = new Pose2d(new Translation2d(5, 0), Rotation2d.fromDegrees(5));
|
||||
visionSysSim.update(robotPose);
|
||||
|
||||
var res = waitForSequenceNumber(camera, 1);
|
||||
|
||||
assertEquals(50, res.getTargets().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotVisibleVert1() {
|
||||
final var targetPose =
|
||||
|
||||
@@ -117,6 +117,29 @@ TEST_F(VisionSystemSimTest, TestVisibilityCupidShuffle) {
|
||||
ASSERT_TRUE(camera.GetLatestResult().HasTargets());
|
||||
}
|
||||
|
||||
TEST_F(VisionSystemSimTest, TestBunchaTargets) {
|
||||
photon::VisionSystemSim visionSysSim{"Test"};
|
||||
photon::PhotonCamera camera{"camera"};
|
||||
photon::PhotonCameraSim cameraSim{&camera};
|
||||
visionSysSim.AddCamera(&cameraSim, frc::Transform3d{});
|
||||
cameraSim.prop.SetCalibration(640, 480, frc::Rotation2d{80_deg});
|
||||
|
||||
std::vector<photon::VisionTargetSim> targets;
|
||||
for (int i = 0; i < 100; i++) {
|
||||
targets.emplace_back(
|
||||
frc::Pose3d{
|
||||
frc::Translation3d{15.98_m + i * 0.1_m, 0_m, 1_m},
|
||||
frc::Rotation3d{0_rad, 0_rad, units::radian_t{std::numbers::pi}}},
|
||||
photon::TargetModel{0.5_m, 0.5_m}, i);
|
||||
}
|
||||
visionSysSim.AddVisionTargets(targets);
|
||||
|
||||
frc::Pose2d robotPose{frc::Translation2d{5_m, 0_m}, frc::Rotation2d{5_deg}};
|
||||
visionSysSim.Update(robotPose);
|
||||
|
||||
ASSERT_EQ(camera.GetLatestResult().targets.size(), 50u);
|
||||
}
|
||||
|
||||
TEST_F(VisionSystemSimTest, TestNotVisibleVert1) {
|
||||
frc::Pose3d targetPose{
|
||||
frc::Translation3d{15.98_m, 0_m, 1_m},
|
||||
|
||||
@@ -852,6 +852,12 @@ public class RequestHandler {
|
||||
ctx.result("There was an error while saving the uploaded object detection models");
|
||||
logger.error("There was an error while saving the uploaded object detection models");
|
||||
}
|
||||
|
||||
DataChangeService.getInstance()
|
||||
.publishEvent(
|
||||
new OutgoingUIEvent<>(
|
||||
"fullsettings",
|
||||
UIPhotonConfiguration.programStateToUi(ConfigManager.getInstance().getConfig())));
|
||||
}
|
||||
|
||||
private record DeleteObjectDetectionModelRequest(Path modelPath) {}
|
||||
@@ -898,17 +904,17 @@ public class RequestHandler {
|
||||
|
||||
ctx.status(200).result("Successfully deleted object detection model");
|
||||
|
||||
DataChangeService.getInstance()
|
||||
.publishEvent(
|
||||
new OutgoingUIEvent<>(
|
||||
"fullsettings",
|
||||
UIPhotonConfiguration.programStateToUi(ConfigManager.getInstance().getConfig())));
|
||||
|
||||
} catch (Exception e) {
|
||||
ctx.status(500);
|
||||
ctx.result("Error deleting object detection model: " + e.getMessage());
|
||||
logger.error("Error deleting object detection model", e);
|
||||
}
|
||||
|
||||
DataChangeService.getInstance()
|
||||
.publishEvent(
|
||||
new OutgoingUIEvent<>(
|
||||
"fullsettings",
|
||||
UIPhotonConfiguration.programStateToUi(ConfigManager.getInstance().getConfig())));
|
||||
}
|
||||
|
||||
private record RenameObjectDetectionModelRequest(Path modelPath, String newName) {}
|
||||
@@ -951,6 +957,12 @@ public class RequestHandler {
|
||||
|
||||
NeuralNetworkModelManager.getInstance().discoverModels();
|
||||
ctx.status(200).result("Successfully renamed object detection model");
|
||||
|
||||
DataChangeService.getInstance()
|
||||
.publishEvent(
|
||||
new OutgoingUIEvent<>(
|
||||
"fullsettings",
|
||||
UIPhotonConfiguration.programStateToUi(ConfigManager.getInstance().getConfig())));
|
||||
} catch (Exception e) {
|
||||
ctx.status(500);
|
||||
ctx.result("Error renaming object detection model: " + e.getMessage());
|
||||
@@ -970,6 +982,12 @@ public class RequestHandler {
|
||||
ctx.result("Error clearing object detection models: " + e.getMessage());
|
||||
logger.error("Error clearing object detection models", e);
|
||||
}
|
||||
|
||||
DataChangeService.getInstance()
|
||||
.publishEvent(
|
||||
new OutgoingUIEvent<>(
|
||||
"fullsettings",
|
||||
UIPhotonConfiguration.programStateToUi(ConfigManager.getInstance().getConfig())));
|
||||
}
|
||||
|
||||
public static void onDeviceRestartRequest(Context ctx) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id "cpp"
|
||||
id "google-test-test-suite"
|
||||
id "edu.wpi.first.GradleRIO" version "2026.1.1"
|
||||
id "edu.wpi.first.GradleRIO" version "2026.2.1"
|
||||
}
|
||||
|
||||
repositories {
|
||||
@@ -11,8 +11,8 @@ repositories {
|
||||
|
||||
wpi.maven.useLocal = false
|
||||
wpi.maven.useDevelopment = false
|
||||
wpi.versions.wpilibVersion = "2026.1.1"
|
||||
wpi.versions.wpimathVersion = "2026.1.1"
|
||||
wpi.versions.wpilibVersion = "2026.2.1"
|
||||
wpi.versions.wpimathVersion = "2026.2.1"
|
||||
|
||||
// Define my targets (RoboRIO) and artifacts (deployable files)
|
||||
// This is added by GradleRIO's backing project DeployUtils.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id "cpp"
|
||||
id "google-test-test-suite"
|
||||
id "edu.wpi.first.GradleRIO" version "2026.1.1"
|
||||
id "edu.wpi.first.GradleRIO" version "2026.2.1"
|
||||
}
|
||||
|
||||
repositories {
|
||||
@@ -11,8 +11,8 @@ repositories {
|
||||
|
||||
wpi.maven.useLocal = false
|
||||
wpi.maven.useDevelopment = false
|
||||
wpi.versions.wpilibVersion = "2026.1.1"
|
||||
wpi.versions.wpimathVersion = "2026.1.1"
|
||||
wpi.versions.wpilibVersion = "2026.2.1"
|
||||
wpi.versions.wpimathVersion = "2026.2.1"
|
||||
|
||||
// Define my targets (RoboRIO) and artifacts (deployable files)
|
||||
// This is added by GradleRIO's backing project DeployUtils.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id "cpp"
|
||||
id "google-test-test-suite"
|
||||
id "edu.wpi.first.GradleRIO" version "2026.1.1"
|
||||
id "edu.wpi.first.GradleRIO" version "2026.2.1"
|
||||
}
|
||||
|
||||
repositories {
|
||||
@@ -11,8 +11,8 @@ repositories {
|
||||
|
||||
wpi.maven.useLocal = false
|
||||
wpi.maven.useDevelopment = false
|
||||
wpi.versions.wpilibVersion = "2026.1.1"
|
||||
wpi.versions.wpimathVersion = "2026.1.1"
|
||||
wpi.versions.wpilibVersion = "2026.2.1"
|
||||
wpi.versions.wpimathVersion = "2026.2.1"
|
||||
|
||||
// Define my targets (RoboRIO) and artifacts (deployable files)
|
||||
// This is added by GradleRIO's backing project DeployUtils.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
plugins {
|
||||
id "java"
|
||||
id "edu.wpi.first.GradleRIO" version "2026.1.1"
|
||||
id "edu.wpi.first.GradleRIO" version "2026.2.1"
|
||||
}
|
||||
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
@@ -13,8 +13,8 @@ repositories {
|
||||
}
|
||||
|
||||
wpi.maven.useDevelopment = true
|
||||
wpi.versions.wpilibVersion = "2026.1.1"
|
||||
wpi.versions.wpimathVersion = "2026.1.1"
|
||||
wpi.versions.wpilibVersion = "2026.2.1"
|
||||
wpi.versions.wpimathVersion = "2026.2.1"
|
||||
|
||||
|
||||
// Define my targets (RoboRIO) and artifacts (deployable files)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
plugins {
|
||||
id "java"
|
||||
id "edu.wpi.first.GradleRIO" version "2026.1.1"
|
||||
id "edu.wpi.first.GradleRIO" version "2026.2.1"
|
||||
}
|
||||
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
@@ -9,8 +9,8 @@ targetCompatibility = JavaVersion.VERSION_17
|
||||
def ROBOT_MAIN_CLASS = "frc.robot.Main"
|
||||
|
||||
wpi.maven.useDevelopment = true
|
||||
wpi.versions.wpilibVersion = "2026.1.1"
|
||||
wpi.versions.wpimathVersion = "2026.1.1"
|
||||
wpi.versions.wpilibVersion = "2026.2.1"
|
||||
wpi.versions.wpimathVersion = "2026.2.1"
|
||||
|
||||
|
||||
// Define my targets (RoboRIO) and artifacts (deployable files)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
plugins {
|
||||
id "java"
|
||||
id "edu.wpi.first.GradleRIO" version "2026.1.1"
|
||||
id "edu.wpi.first.GradleRIO" version "2026.2.1"
|
||||
}
|
||||
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
@@ -9,8 +9,8 @@ targetCompatibility = JavaVersion.VERSION_17
|
||||
def ROBOT_MAIN_CLASS = "frc.robot.Main"
|
||||
|
||||
wpi.maven.useDevelopment = true
|
||||
wpi.versions.wpilibVersion = "2026.1.1"
|
||||
wpi.versions.wpimathVersion = "2026.1.1"
|
||||
wpi.versions.wpilibVersion = "2026.2.1"
|
||||
wpi.versions.wpimathVersion = "2026.2.1"
|
||||
|
||||
|
||||
// Define my targets (RoboRIO) and artifacts (deployable files)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
[tool.robotpy]
|
||||
|
||||
# Version of robotpy this project depends on
|
||||
robotpy_version = "2026.1.1"
|
||||
robotpy_version = "2026.2.1"
|
||||
|
||||
# Which extra RobotPy components should be installed
|
||||
# -> equivalent to `pip install robotpy[extra1, ...]
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
[tool.robotpy]
|
||||
|
||||
# Version of robotpy this project depends on
|
||||
robotpy_version = "2026.1.1"
|
||||
robotpy_version = "2026.2.1"
|
||||
|
||||
# Which extra RobotPy components should be installed
|
||||
# -> equivalent to `pip install robotpy[extra1, ...]
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
[tool.robotpy]
|
||||
|
||||
# Version of robotpy this project depends on
|
||||
robotpy_version = "2026.1.1"
|
||||
robotpy_version = "2026.2.1"
|
||||
|
||||
# Which extra RobotPy components should be installed
|
||||
# -> equivalent to `pip install robotpy[extra1, ...]
|
||||
|
||||
@@ -5,19 +5,6 @@ if [ $# -eq 0 ]
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# To run any example, we want to use photonlib out of this repo
|
||||
# Build the wheel first
|
||||
pushd ../photon-lib/py
|
||||
if [ -d build ]
|
||||
then rm -rdf build
|
||||
fi
|
||||
python3 setup.py bdist_wheel
|
||||
popd
|
||||
|
||||
# Add the output directory to PYTHONPATH to make sure it gets picked up
|
||||
export PHOTONLIBPY_ROOT=../photon-lib/py
|
||||
export PYTHONPATH=$PHOTONLIBPY_ROOT
|
||||
|
||||
# Move to the right example folder
|
||||
cd $1
|
||||
|
||||
|
||||
0
scripts/armrunner.sh
Normal file → Executable file
0
scripts/armrunner.sh
Normal file → Executable file
@@ -33,6 +33,27 @@
|
||||
],
|
||||
"id": "500d656b7cc0ebd7"
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"#### *Numpy Fix* - Important for Google Colab Users\n",
|
||||
"\n",
|
||||
"Google Colab comes with an incompatible version of Numpy installed. To fix this, please run the following cells below and **restart your session** when prompted."
|
||||
],
|
||||
"id": "b3a9e1a334bce144"
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
"cell_type": "code",
|
||||
"outputs": [],
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"%pip uninstall numpy -y\n",
|
||||
"%pip install \"numpy==1.26.4\""
|
||||
],
|
||||
"id": "7156e69495f48f49"
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
"cell_type": "markdown",
|
||||
@@ -41,7 +62,7 @@
|
||||
"\n",
|
||||
"Please run the cell below to be able to use the `create_onnx` and `create_rknn` functions."
|
||||
],
|
||||
"id": "798298b1dbe33d2d"
|
||||
"id": "51566ff74470e57"
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
@@ -132,6 +153,7 @@
|
||||
" os.path.join(ultralytics_folder_name_yolov5, \"requirements.txt\"),\n",
|
||||
" \"torch<2.6.0\",\n",
|
||||
" \"onnx==1.18.0\",\n",
|
||||
" \"numpy==1.26.4\",\n",
|
||||
" \"onnxscript\",\n",
|
||||
" ]\n",
|
||||
" )\n",
|
||||
@@ -172,7 +194,7 @@
|
||||
"def run_onnx_conversion_no_anchor(model_path):\n",
|
||||
" check_or_clone_rockchip_repo(yolo_non_anchor_repo)\n",
|
||||
" run_pip_install_or_else_exit(\n",
|
||||
" [\"-e\", ultralytics_default_folder_name, \"onnx==1.18.0\", \"onnxscript\"]\n",
|
||||
" [\"-e\", ultralytics_default_folder_name, \"onnx==1.18.0\", \"numpy==1.26.4\", \"onnxscript\"]\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" sys.path.insert(0, os.path.abspath(ultralytics_default_folder_name))\n",
|
||||
@@ -384,28 +406,7 @@
|
||||
" except SystemExit:\n",
|
||||
" print(\"RKNN Conversion failed, see output above\")\n"
|
||||
],
|
||||
"id": "ea6869140a61126d"
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"#### *Numpy Fix* - Important for Google Colab Users\n",
|
||||
"\n",
|
||||
"Google Colab comes with an incompatible version of Numpy installed. To fix this, please run the following cells below and **restart your session** when prompted."
|
||||
],
|
||||
"id": "b3a9e1a334bce144"
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
"cell_type": "code",
|
||||
"outputs": [],
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"%pip uninstall numpy -y\n",
|
||||
"%pip install \"numpy>=1.23.0,<2.0.0\""
|
||||
],
|
||||
"id": "7156e69495f48f49"
|
||||
"id": "4d7a8adee7a03377"
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
|
||||
Reference in New Issue
Block a user