2021-01-16 20:41:47 -08:00
|
|
|
/*
|
2022-01-20 19:35:28 -08:00
|
|
|
* MIT License
|
2021-01-16 20:41:47 -08:00
|
|
|
*
|
2023-04-18 18:49:40 -04:00
|
|
|
* Copyright (c) PhotonVision
|
2021-01-16 20:41:47 -08:00
|
|
|
*
|
2022-01-20 19:35:28 -08:00
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
|
* furnished to do so, subject to the following conditions:
|
2021-01-16 20:41:47 -08:00
|
|
|
*
|
2022-01-20 19:35:28 -08:00
|
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
|
|
|
* copies or substantial portions of the Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
|
* SOFTWARE.
|
2021-01-16 20:41:47 -08:00
|
|
|
*/
|
2022-01-20 19:35:28 -08:00
|
|
|
|
2021-01-16 20:41:47 -08:00
|
|
|
package org.photonvision;
|
|
|
|
|
|
|
|
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
|
|
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
|
|
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
|
|
|
|
2023-07-23 18:32:36 -07:00
|
|
|
import edu.wpi.first.apriltag.AprilTag;
|
|
|
|
|
import edu.wpi.first.apriltag.AprilTagFieldLayout;
|
2023-06-18 15:54:12 -07:00
|
|
|
import edu.wpi.first.apriltag.jni.AprilTagJNI;
|
|
|
|
|
import edu.wpi.first.cscore.CameraServerCvJNI;
|
|
|
|
|
import edu.wpi.first.cscore.CameraServerJNI;
|
2022-12-16 17:05:23 -08:00
|
|
|
import edu.wpi.first.hal.JNIWrapper;
|
2021-11-21 17:22:56 -08:00
|
|
|
import edu.wpi.first.math.geometry.Pose2d;
|
2022-11-03 15:05:37 -05:00
|
|
|
import edu.wpi.first.math.geometry.Pose3d;
|
2021-11-21 17:22:56 -08:00
|
|
|
import edu.wpi.first.math.geometry.Rotation2d;
|
2022-11-03 15:05:37 -05:00
|
|
|
import edu.wpi.first.math.geometry.Rotation3d;
|
|
|
|
|
import edu.wpi.first.math.geometry.Transform3d;
|
2021-11-21 17:22:56 -08:00
|
|
|
import edu.wpi.first.math.geometry.Translation2d;
|
2022-11-03 15:05:37 -05:00
|
|
|
import edu.wpi.first.math.geometry.Translation3d;
|
2021-11-21 17:22:56 -08:00
|
|
|
import edu.wpi.first.math.util.Units;
|
2022-12-16 17:05:23 -08:00
|
|
|
import edu.wpi.first.net.WPINetJNI;
|
2022-11-03 15:05:37 -05:00
|
|
|
import edu.wpi.first.networktables.NetworkTableInstance;
|
2022-12-16 17:05:23 -08:00
|
|
|
import edu.wpi.first.networktables.NetworkTablesJNI;
|
|
|
|
|
import edu.wpi.first.util.CombinedRuntimeLoader;
|
|
|
|
|
import edu.wpi.first.util.WPIUtilJNI;
|
2023-07-23 18:32:36 -07:00
|
|
|
import java.util.ArrayList;
|
2021-01-16 20:41:47 -08:00
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.stream.Stream;
|
2022-11-03 15:05:37 -05:00
|
|
|
import org.junit.jupiter.api.AfterAll;
|
2021-01-16 20:41:47 -08:00
|
|
|
import org.junit.jupiter.api.Assertions;
|
2022-11-03 15:05:37 -05:00
|
|
|
import org.junit.jupiter.api.BeforeAll;
|
2021-01-16 20:41:47 -08:00
|
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
|
import org.junit.jupiter.params.ParameterizedTest;
|
|
|
|
|
import org.junit.jupiter.params.provider.Arguments;
|
|
|
|
|
import org.junit.jupiter.params.provider.MethodSource;
|
|
|
|
|
import org.junit.jupiter.params.provider.ValueSource;
|
2023-06-18 15:54:12 -07:00
|
|
|
import org.opencv.core.Core;
|
|
|
|
|
import org.photonvision.estimation.TargetModel;
|
2023-07-23 18:32:36 -07:00
|
|
|
import org.photonvision.estimation.VisionEstimation;
|
2023-06-18 15:54:12 -07:00
|
|
|
import org.photonvision.simulation.PhotonCameraSim;
|
|
|
|
|
import org.photonvision.simulation.VisionSystemSim;
|
|
|
|
|
import org.photonvision.simulation.VisionTargetSim;
|
2021-01-16 20:41:47 -08:00
|
|
|
import org.photonvision.targeting.PhotonTrackedTarget;
|
|
|
|
|
|
2023-06-18 15:54:12 -07:00
|
|
|
class VisionSystemSimTest {
|
|
|
|
|
private static final double kTrlDelta = 0.005;
|
|
|
|
|
private static final double kRotDeltaDeg = 0.25;
|
|
|
|
|
|
2021-01-16 20:41:47 -08:00
|
|
|
@Test
|
|
|
|
|
public void testEmpty() {
|
|
|
|
|
Assertions.assertDoesNotThrow(
|
|
|
|
|
() -> {
|
2023-06-18 15:54:12 -07:00
|
|
|
var sysUnderTest = new VisionSystemSim("Test");
|
|
|
|
|
sysUnderTest.addVisionTargets(
|
|
|
|
|
new VisionTargetSim(new Pose3d(), new TargetModel(1.0, 1.0)));
|
2021-01-16 20:41:47 -08:00
|
|
|
for (int loopIdx = 0; loopIdx < 100; loopIdx++) {
|
2023-06-18 15:54:12 -07:00
|
|
|
sysUnderTest.update(new Pose2d());
|
2021-01-16 20:41:47 -08:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-03 15:05:37 -05:00
|
|
|
@BeforeAll
|
|
|
|
|
public static void setUp() {
|
2022-12-16 17:05:23 -08:00
|
|
|
JNIWrapper.Helper.setExtractOnStaticLoad(false);
|
|
|
|
|
WPIUtilJNI.Helper.setExtractOnStaticLoad(false);
|
|
|
|
|
NetworkTablesJNI.Helper.setExtractOnStaticLoad(false);
|
|
|
|
|
WPINetJNI.Helper.setExtractOnStaticLoad(false);
|
2023-06-18 15:54:12 -07:00
|
|
|
CameraServerJNI.Helper.setExtractOnStaticLoad(false);
|
|
|
|
|
CameraServerCvJNI.Helper.setExtractOnStaticLoad(false);
|
|
|
|
|
AprilTagJNI.Helper.setExtractOnStaticLoad(false);
|
2022-12-16 17:05:23 -08:00
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
CombinedRuntimeLoader.loadLibraries(
|
2023-06-18 15:54:12 -07:00
|
|
|
VisionSystemSim.class,
|
|
|
|
|
"wpiutiljni",
|
|
|
|
|
"ntcorejni",
|
|
|
|
|
"wpinetjni",
|
|
|
|
|
"wpiHaljni",
|
2023-10-25 20:27:56 -04:00
|
|
|
Core.NATIVE_LIBRARY_NAME,
|
2023-06-18 15:54:12 -07:00
|
|
|
"cscorejni",
|
2023-10-25 20:27:56 -04:00
|
|
|
"apriltagjni");
|
2022-12-16 17:05:23 -08:00
|
|
|
} catch (Exception e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-03 15:05:37 -05:00
|
|
|
// NT live for debug purposes
|
|
|
|
|
NetworkTableInstance.getDefault().startServer();
|
|
|
|
|
|
|
|
|
|
// No version check for testing
|
|
|
|
|
PhotonCamera.setVersionCheckEnabled(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@AfterAll
|
|
|
|
|
public static void shutDown() {}
|
|
|
|
|
|
2022-09-28 18:21:41 -07:00
|
|
|
// @ParameterizedTest
|
|
|
|
|
// @ValueSource(doubles = {5, 10, 15, 20, 25, 30})
|
|
|
|
|
// public void testDistanceAligned(double dist) {
|
2022-11-03 15:05:37 -05:00
|
|
|
// final var targetPose = new Pose2d(new Translation2d(15.98, 0), new Rotation2d());
|
2022-09-28 18:21:41 -07:00
|
|
|
// var sysUnderTest =
|
|
|
|
|
// new SimVisionSystem("Test", 80.0, 0.0, new Transform2d(), 1, 99999, 320, 240, 0);
|
|
|
|
|
// sysUnderTest.addSimVisionTarget(new SimVisionTarget(targetPose, 0.0, 1.0, 1.0));
|
2021-01-16 20:41:47 -08:00
|
|
|
|
2022-09-28 18:21:41 -07:00
|
|
|
// final var robotPose = new Pose2d(new Translation2d(35 - dist, 0), new Rotation2d());
|
|
|
|
|
// sysUnderTest.processFrame(robotPose);
|
2021-01-16 20:41:47 -08:00
|
|
|
|
2022-09-28 18:21:41 -07:00
|
|
|
// var result = sysUnderTest.cam.getLatestResult();
|
2021-01-16 20:41:47 -08:00
|
|
|
|
2022-09-28 18:21:41 -07:00
|
|
|
// assertTrue(result.hasTargets());
|
|
|
|
|
// assertEquals(result.getBestTarget().getCameraToTarget().getTranslation().getNorm(), dist);
|
|
|
|
|
// }
|
2021-01-16 20:41:47 -08:00
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void testVisibilityCupidShuffle() {
|
2022-11-03 15:05:37 -05:00
|
|
|
final var targetPose =
|
|
|
|
|
new Pose3d(new Translation3d(15.98, 0, 2), new Rotation3d(0, 0, Math.PI));
|
2023-06-18 15:54:12 -07:00
|
|
|
var visionSysSim = new VisionSystemSim("Test");
|
|
|
|
|
var camera = new PhotonCamera("camera");
|
|
|
|
|
var cameraSim = new PhotonCameraSim(camera);
|
|
|
|
|
visionSysSim.addCamera(cameraSim, new Transform3d());
|
|
|
|
|
cameraSim.prop.setCalibration(640, 480, Rotation2d.fromDegrees(80));
|
2023-07-23 18:32:36 -07:00
|
|
|
visionSysSim.addVisionTargets(new VisionTargetSim(targetPose, new TargetModel(1.0, 1.0), 3));
|
2021-01-16 20:41:47 -08:00
|
|
|
|
|
|
|
|
// To the right, to the right
|
|
|
|
|
var robotPose = new Pose2d(new Translation2d(5, 0), Rotation2d.fromDegrees(-70));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.update(robotPose);
|
|
|
|
|
assertFalse(camera.getLatestResult().hasTargets());
|
2021-01-16 20:41:47 -08:00
|
|
|
|
|
|
|
|
// To the right, to the right
|
|
|
|
|
robotPose = new Pose2d(new Translation2d(5, 0), Rotation2d.fromDegrees(-95));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.update(robotPose);
|
|
|
|
|
assertFalse(camera.getLatestResult().hasTargets());
|
2021-01-16 20:41:47 -08:00
|
|
|
|
|
|
|
|
// To the left, to the left
|
|
|
|
|
robotPose = new Pose2d(new Translation2d(5, 0), Rotation2d.fromDegrees(90));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.update(robotPose);
|
|
|
|
|
assertFalse(camera.getLatestResult().hasTargets());
|
2021-01-16 20:41:47 -08:00
|
|
|
|
|
|
|
|
// To the left, to the left
|
|
|
|
|
robotPose = new Pose2d(new Translation2d(5, 0), Rotation2d.fromDegrees(65));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.update(robotPose);
|
|
|
|
|
assertFalse(camera.getLatestResult().hasTargets());
|
2021-01-16 20:41:47 -08:00
|
|
|
|
|
|
|
|
// now kick, now kick
|
|
|
|
|
robotPose = new Pose2d(new Translation2d(2, 0), Rotation2d.fromDegrees(5));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.update(robotPose);
|
|
|
|
|
assertTrue(camera.getLatestResult().hasTargets());
|
2021-01-16 20:41:47 -08:00
|
|
|
|
|
|
|
|
// now kick, now kick
|
|
|
|
|
robotPose = new Pose2d(new Translation2d(2, 0), Rotation2d.fromDegrees(-5));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.update(robotPose);
|
|
|
|
|
assertTrue(camera.getLatestResult().hasTargets());
|
2021-01-16 20:41:47 -08:00
|
|
|
|
|
|
|
|
// now walk it by yourself
|
|
|
|
|
robotPose = new Pose2d(new Translation2d(2, 0), Rotation2d.fromDegrees(-179));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.update(robotPose);
|
|
|
|
|
assertFalse(camera.getLatestResult().hasTargets());
|
2021-01-16 20:41:47 -08:00
|
|
|
|
|
|
|
|
// now walk it by yourself
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.adjustCamera(
|
|
|
|
|
cameraSim, new Transform3d(new Translation3d(), new Rotation3d(0, 0, Math.PI)));
|
|
|
|
|
visionSysSim.update(robotPose);
|
|
|
|
|
assertTrue(camera.getLatestResult().hasTargets());
|
2021-01-16 20:41:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void testNotVisibleVert1() {
|
2022-11-03 15:05:37 -05:00
|
|
|
final var targetPose =
|
|
|
|
|
new Pose3d(new Translation3d(15.98, 0, 1), new Rotation3d(0, 0, Math.PI));
|
2023-06-18 15:54:12 -07:00
|
|
|
var visionSysSim = new VisionSystemSim("Test");
|
|
|
|
|
var camera = new PhotonCamera("camera");
|
|
|
|
|
var cameraSim = new PhotonCameraSim(camera);
|
|
|
|
|
visionSysSim.addCamera(cameraSim, new Transform3d());
|
|
|
|
|
cameraSim.prop.setCalibration(640, 480, Rotation2d.fromDegrees(80));
|
|
|
|
|
visionSysSim.addVisionTargets(new VisionTargetSim(targetPose, new TargetModel(1.0, 3.0), 3));
|
2021-01-16 20:41:47 -08:00
|
|
|
|
|
|
|
|
var robotPose = new Pose2d(new Translation2d(5, 0), Rotation2d.fromDegrees(5));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.update(robotPose);
|
|
|
|
|
assertTrue(camera.getLatestResult().hasTargets());
|
2021-01-16 20:41:47 -08:00
|
|
|
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.adjustCamera( // vooop selfie stick
|
|
|
|
|
cameraSim, new Transform3d(new Translation3d(0, 0, 5000), new Rotation3d(0, 0, Math.PI)));
|
|
|
|
|
visionSysSim.update(robotPose);
|
|
|
|
|
assertFalse(camera.getLatestResult().hasTargets());
|
2021-01-16 20:41:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void testNotVisibleVert2() {
|
2022-11-03 15:05:37 -05:00
|
|
|
final var targetPose =
|
|
|
|
|
new Pose3d(new Translation3d(15.98, 0, 2), new Rotation3d(0, 0, Math.PI));
|
|
|
|
|
var robotToCamera =
|
2023-06-18 15:54:12 -07:00
|
|
|
new Transform3d(new Translation3d(0, 0, 1), new Rotation3d(0, -Math.PI / 4, 0));
|
|
|
|
|
var visionSysSim = new VisionSystemSim("Test");
|
|
|
|
|
var camera = new PhotonCamera("camera");
|
|
|
|
|
var cameraSim = new PhotonCameraSim(camera);
|
|
|
|
|
visionSysSim.addCamera(cameraSim, robotToCamera);
|
|
|
|
|
cameraSim.prop.setCalibration(1234, 1234, Rotation2d.fromDegrees(80));
|
|
|
|
|
visionSysSim.addVisionTargets(new VisionTargetSim(targetPose, new TargetModel(1.0, 0.5), 1736));
|
|
|
|
|
|
|
|
|
|
var robotPose = new Pose2d(new Translation2d(13.98, 0), Rotation2d.fromDegrees(5));
|
|
|
|
|
visionSysSim.update(robotPose);
|
|
|
|
|
assertTrue(camera.getLatestResult().hasTargets());
|
2021-01-16 20:41:47 -08:00
|
|
|
|
|
|
|
|
// Pitched back camera should mean target goes out of view below the robot as distance increases
|
|
|
|
|
robotPose = new Pose2d(new Translation2d(0, 0), Rotation2d.fromDegrees(5));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.update(robotPose);
|
|
|
|
|
assertFalse(camera.getLatestResult().hasTargets());
|
2021-01-16 20:41:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void testNotVisibleTgtSize() {
|
2022-11-03 15:05:37 -05:00
|
|
|
final var targetPose =
|
|
|
|
|
new Pose3d(new Translation3d(15.98, 0, 1), new Rotation3d(0, 0, Math.PI));
|
2023-06-18 15:54:12 -07:00
|
|
|
var visionSysSim = new VisionSystemSim("Test");
|
|
|
|
|
var camera = new PhotonCamera("camera");
|
|
|
|
|
var cameraSim = new PhotonCameraSim(camera);
|
|
|
|
|
visionSysSim.addCamera(cameraSim, new Transform3d());
|
|
|
|
|
cameraSim.prop.setCalibration(640, 480, Rotation2d.fromDegrees(80));
|
|
|
|
|
cameraSim.setMinTargetAreaPixels(20.0);
|
|
|
|
|
visionSysSim.addVisionTargets(new VisionTargetSim(targetPose, new TargetModel(0.1, 0.025), 24));
|
2021-01-16 20:41:47 -08:00
|
|
|
|
2022-11-03 15:05:37 -05:00
|
|
|
var robotPose = new Pose2d(new Translation2d(12, 0), Rotation2d.fromDegrees(5));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.update(robotPose);
|
|
|
|
|
assertTrue(camera.getLatestResult().hasTargets());
|
2021-01-16 20:41:47 -08:00
|
|
|
|
|
|
|
|
robotPose = new Pose2d(new Translation2d(0, 0), Rotation2d.fromDegrees(5));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.update(robotPose);
|
|
|
|
|
assertFalse(camera.getLatestResult().hasTargets());
|
2021-01-16 20:41:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void testNotVisibleTooFarForLEDs() {
|
2022-11-03 15:05:37 -05:00
|
|
|
final var targetPose =
|
|
|
|
|
new Pose3d(new Translation3d(15.98, 0, 1), new Rotation3d(0, 0, Math.PI));
|
2023-06-18 15:54:12 -07:00
|
|
|
var visionSysSim = new VisionSystemSim("Test");
|
|
|
|
|
var camera = new PhotonCamera("camera");
|
|
|
|
|
var cameraSim = new PhotonCameraSim(camera);
|
|
|
|
|
visionSysSim.addCamera(cameraSim, new Transform3d());
|
|
|
|
|
cameraSim.prop.setCalibration(640, 480, Rotation2d.fromDegrees(80));
|
|
|
|
|
cameraSim.setMaxSightRange(10);
|
|
|
|
|
cameraSim.setMinTargetAreaPixels(1.0);
|
|
|
|
|
visionSysSim.addVisionTargets(new VisionTargetSim(targetPose, new TargetModel(1.0, 0.25), 78));
|
2021-01-16 20:41:47 -08:00
|
|
|
|
2022-11-03 15:05:37 -05:00
|
|
|
var robotPose = new Pose2d(new Translation2d(10, 0), Rotation2d.fromDegrees(5));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.update(robotPose);
|
|
|
|
|
assertTrue(camera.getLatestResult().hasTargets());
|
2021-01-16 20:41:47 -08:00
|
|
|
|
|
|
|
|
robotPose = new Pose2d(new Translation2d(0, 0), Rotation2d.fromDegrees(5));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.update(robotPose);
|
|
|
|
|
assertFalse(camera.getLatestResult().hasTargets());
|
2021-01-16 20:41:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ParameterizedTest
|
|
|
|
|
@ValueSource(doubles = {-10, -5, -0, -1, -2, 5, 7, 10.23})
|
|
|
|
|
public void testYawAngles(double testYaw) {
|
2022-11-03 15:05:37 -05:00
|
|
|
final var targetPose =
|
|
|
|
|
new Pose3d(new Translation3d(15.98, 0, 1), new Rotation3d(0, 0, 3 * Math.PI / 4));
|
2023-06-18 15:54:12 -07:00
|
|
|
var visionSysSim = new VisionSystemSim("Test");
|
|
|
|
|
var camera = new PhotonCamera("camera");
|
|
|
|
|
var cameraSim = new PhotonCameraSim(camera);
|
|
|
|
|
visionSysSim.addCamera(cameraSim, new Transform3d());
|
|
|
|
|
cameraSim.prop.setCalibration(640, 480, Rotation2d.fromDegrees(80));
|
|
|
|
|
cameraSim.setMinTargetAreaPixels(0.0);
|
|
|
|
|
visionSysSim.addVisionTargets(new VisionTargetSim(targetPose, new TargetModel(0.5, 0.5), 3));
|
2021-01-16 20:41:47 -08:00
|
|
|
|
2022-11-03 15:05:37 -05:00
|
|
|
var robotPose = new Pose2d(new Translation2d(10, 0), Rotation2d.fromDegrees(-1.0 * testYaw));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.update(robotPose);
|
|
|
|
|
var res = camera.getLatestResult();
|
2021-01-16 20:41:47 -08:00
|
|
|
assertTrue(res.hasTargets());
|
|
|
|
|
var tgt = res.getBestTarget();
|
2023-10-15 10:44:47 -07:00
|
|
|
assertEquals(testYaw, tgt.getYaw(), kRotDeltaDeg);
|
2021-01-16 20:41:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ParameterizedTest
|
|
|
|
|
@ValueSource(doubles = {-10, -5, -0, -1, -2, 5, 7, 10.23, 20.21, -19.999})
|
2023-10-15 10:44:47 -07:00
|
|
|
public void testPitchAngles(double testPitch) {
|
2022-11-03 15:05:37 -05:00
|
|
|
final var targetPose =
|
|
|
|
|
new Pose3d(new Translation3d(15.98, 0, 0), new Rotation3d(0, 0, 3 * Math.PI / 4));
|
|
|
|
|
final var robotPose = new Pose2d(new Translation2d(10, 0), new Rotation2d(0));
|
2023-06-18 15:54:12 -07:00
|
|
|
var visionSysSim = new VisionSystemSim("Test");
|
|
|
|
|
var camera = new PhotonCamera("camera");
|
|
|
|
|
var cameraSim = new PhotonCameraSim(camera);
|
|
|
|
|
visionSysSim.addCamera(cameraSim, new Transform3d());
|
|
|
|
|
cameraSim.prop.setCalibration(640, 480, Rotation2d.fromDegrees(120));
|
|
|
|
|
cameraSim.setMinTargetAreaPixels(0.0);
|
|
|
|
|
visionSysSim.addVisionTargets(new VisionTargetSim(targetPose, new TargetModel(0.5, 0.5), 23));
|
2022-11-03 15:05:37 -05:00
|
|
|
|
2023-01-06 17:41:47 -05:00
|
|
|
// Transform is now robot -> camera
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.adjustCamera(
|
|
|
|
|
cameraSim,
|
2022-11-03 15:05:37 -05:00
|
|
|
new Transform3d(
|
|
|
|
|
new Translation3d(), new Rotation3d(0, Units.degreesToRadians(testPitch), 0)));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.update(robotPose);
|
|
|
|
|
var res = camera.getLatestResult();
|
2021-01-16 20:41:47 -08:00
|
|
|
assertTrue(res.hasTargets());
|
|
|
|
|
var tgt = res.getBestTarget();
|
2022-11-03 15:05:37 -05:00
|
|
|
|
2023-01-06 17:41:47 -05:00
|
|
|
// Since the camera is level with the target, a positive-upward point will mean the target is in
|
|
|
|
|
// the
|
|
|
|
|
// lower half of the image
|
|
|
|
|
// which should produce negative pitch.
|
2023-06-18 15:54:12 -07:00
|
|
|
assertEquals(testPitch, tgt.getPitch(), kRotDeltaDeg);
|
2021-01-16 20:41:47 -08:00
|
|
|
}
|
|
|
|
|
|
2023-10-15 10:44:47 -07:00
|
|
|
private static Stream<Arguments> testDistanceCalcArgs() {
|
2021-01-16 20:41:47 -08:00
|
|
|
// Arbitrary and fairly random assortment of distances, camera pitches, and heights
|
|
|
|
|
return Stream.of(
|
2023-06-18 15:54:12 -07:00
|
|
|
Arguments.of(5, -15.98, 0),
|
|
|
|
|
Arguments.of(6, -15.98, 1),
|
|
|
|
|
Arguments.of(10, -15.98, 0),
|
|
|
|
|
Arguments.of(15, -15.98, 2),
|
|
|
|
|
Arguments.of(19.95, -15.98, 0),
|
|
|
|
|
Arguments.of(20, -15.98, 0),
|
|
|
|
|
Arguments.of(5, -42, 1),
|
|
|
|
|
Arguments.of(6, -42, 0),
|
|
|
|
|
Arguments.of(10, -42, 2),
|
|
|
|
|
Arguments.of(15, -42, 0.5),
|
|
|
|
|
Arguments.of(19.42, -15.98, 0),
|
|
|
|
|
Arguments.of(20, -42, 0),
|
|
|
|
|
Arguments.of(5, -35, 2),
|
|
|
|
|
Arguments.of(6, -35, 0),
|
2023-09-19 16:10:04 -07:00
|
|
|
Arguments.of(10, -34, 2.4),
|
2023-06-18 15:54:12 -07:00
|
|
|
Arguments.of(15, -33, 0),
|
|
|
|
|
Arguments.of(19.52, -15.98, 1.1));
|
2021-01-16 20:41:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ParameterizedTest
|
2023-10-15 10:44:47 -07:00
|
|
|
@MethodSource("testDistanceCalcArgs")
|
2021-01-16 20:41:47 -08:00
|
|
|
public void testDistanceCalc(double testDist, double testPitch, double testHeight) {
|
|
|
|
|
// Assume dist along ground and tgt height the same. Iterate over other parameters.
|
|
|
|
|
|
2022-11-03 15:05:37 -05:00
|
|
|
final var targetPose =
|
|
|
|
|
new Pose3d(new Translation3d(15.98, 0, 1), new Rotation3d(0, 0, Math.PI * 0.98));
|
|
|
|
|
final var robotPose =
|
|
|
|
|
new Pose3d(new Translation3d(15.98 - Units.feetToMeters(testDist), 0, 0), new Rotation3d());
|
|
|
|
|
final var robotToCamera =
|
|
|
|
|
new Transform3d(
|
|
|
|
|
new Translation3d(0, 0, Units.feetToMeters(testHeight)),
|
|
|
|
|
new Rotation3d(0, Units.degreesToRadians(testPitch), 0));
|
|
|
|
|
|
2023-06-18 15:54:12 -07:00
|
|
|
var visionSysSim =
|
|
|
|
|
new VisionSystemSim(
|
|
|
|
|
"absurdlylongnamewhichshouldneveractuallyhappenbuteehwelltestitanywaysohowsyourdaygoingihopegoodhaveagreatrestofyourlife!");
|
|
|
|
|
var camera = new PhotonCamera("camera");
|
|
|
|
|
var cameraSim = new PhotonCameraSim(camera);
|
|
|
|
|
visionSysSim.addCamera(cameraSim, new Transform3d());
|
|
|
|
|
cameraSim.prop.setCalibration(640, 480, Rotation2d.fromDegrees(160));
|
|
|
|
|
cameraSim.setMinTargetAreaPixels(0.0);
|
|
|
|
|
visionSysSim.adjustCamera(cameraSim, robotToCamera);
|
|
|
|
|
visionSysSim.addVisionTargets(new VisionTargetSim(targetPose, new TargetModel(0.5, 0.5), 0));
|
|
|
|
|
|
|
|
|
|
visionSysSim.update(robotPose);
|
2023-09-19 16:10:04 -07:00
|
|
|
|
|
|
|
|
// Note that target 2d yaw/pitch accuracy is hindered by two factors in photonvision:
|
|
|
|
|
// 1. These are calculated with the average of the minimum area rectangle, which does not
|
|
|
|
|
// actually find the target center because of perspective distortion.
|
|
|
|
|
// 2. Yaw and pitch are calculated separately which gives incorrect pitch values.
|
2023-06-18 15:54:12 -07:00
|
|
|
var res = camera.getLatestResult();
|
2021-01-16 20:41:47 -08:00
|
|
|
assertTrue(res.hasTargets());
|
|
|
|
|
var tgt = res.getBestTarget();
|
2023-09-19 16:10:04 -07:00
|
|
|
assertEquals(0.0, tgt.getYaw(), 0.5);
|
2023-06-18 15:54:12 -07:00
|
|
|
|
2023-09-19 16:10:04 -07:00
|
|
|
// Distance calculation using this trigonometry may be wildly incorrect when
|
|
|
|
|
// there is not much height difference between the target and the camera.
|
2021-01-16 20:41:47 -08:00
|
|
|
double distMeas =
|
|
|
|
|
PhotonUtils.calculateDistanceToTargetMeters(
|
2022-11-03 15:05:37 -05:00
|
|
|
robotToCamera.getZ(),
|
|
|
|
|
targetPose.getZ(),
|
2023-06-18 15:54:12 -07:00
|
|
|
Units.degreesToRadians(-testPitch),
|
2021-01-16 20:41:47 -08:00
|
|
|
Units.degreesToRadians(tgt.getPitch()));
|
2023-09-19 16:10:04 -07:00
|
|
|
assertEquals(Units.feetToMeters(testDist), distMeas, 0.15);
|
2021-01-16 20:41:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void testMultipleTargets() {
|
2022-11-03 15:05:37 -05:00
|
|
|
final var targetPoseL =
|
|
|
|
|
new Pose3d(new Translation3d(15.98, 2, 0), new Rotation3d(0, 0, Math.PI));
|
|
|
|
|
final var targetPoseC =
|
|
|
|
|
new Pose3d(new Translation3d(15.98, 0, 0), new Rotation3d(0, 0, Math.PI));
|
|
|
|
|
final var targetPoseR =
|
|
|
|
|
new Pose3d(new Translation3d(15.98, -2, 0), new Rotation3d(0, 0, Math.PI));
|
|
|
|
|
|
2023-06-18 15:54:12 -07:00
|
|
|
var visionSysSim = new VisionSystemSim("Test");
|
|
|
|
|
var camera = new PhotonCamera("camera");
|
|
|
|
|
var cameraSim = new PhotonCameraSim(camera);
|
|
|
|
|
visionSysSim.addCamera(cameraSim, new Transform3d());
|
|
|
|
|
cameraSim.prop.setCalibration(640, 480, Rotation2d.fromDegrees(80));
|
|
|
|
|
cameraSim.setMinTargetAreaPixels(20.0);
|
|
|
|
|
|
|
|
|
|
visionSysSim.addVisionTargets(
|
|
|
|
|
new VisionTargetSim(
|
2022-11-03 15:05:37 -05:00
|
|
|
targetPoseL.transformBy(
|
|
|
|
|
new Transform3d(new Translation3d(0, 0, 0.00), new Rotation3d())),
|
2023-06-18 15:54:12 -07:00
|
|
|
TargetModel.kTag16h5,
|
2022-11-03 15:05:37 -05:00
|
|
|
1));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.addVisionTargets(
|
|
|
|
|
new VisionTargetSim(
|
2022-11-03 15:05:37 -05:00
|
|
|
targetPoseC.transformBy(
|
|
|
|
|
new Transform3d(new Translation3d(0, 0, 0.00), new Rotation3d())),
|
2023-06-18 15:54:12 -07:00
|
|
|
TargetModel.kTag16h5,
|
2022-11-03 15:05:37 -05:00
|
|
|
2));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.addVisionTargets(
|
|
|
|
|
new VisionTargetSim(
|
2022-11-03 15:05:37 -05:00
|
|
|
targetPoseR.transformBy(
|
|
|
|
|
new Transform3d(new Translation3d(0, 0, 0.00), new Rotation3d())),
|
2023-06-18 15:54:12 -07:00
|
|
|
TargetModel.kTag16h5,
|
2022-11-03 15:05:37 -05:00
|
|
|
3));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.addVisionTargets(
|
|
|
|
|
new VisionTargetSim(
|
2022-11-03 15:05:37 -05:00
|
|
|
targetPoseL.transformBy(
|
|
|
|
|
new Transform3d(new Translation3d(0, 0, 1.00), new Rotation3d())),
|
2023-06-18 15:54:12 -07:00
|
|
|
TargetModel.kTag16h5,
|
2022-11-03 15:05:37 -05:00
|
|
|
4));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.addVisionTargets(
|
|
|
|
|
new VisionTargetSim(
|
2022-11-03 15:05:37 -05:00
|
|
|
targetPoseC.transformBy(
|
|
|
|
|
new Transform3d(new Translation3d(0, 0, 1.00), new Rotation3d())),
|
2023-06-18 15:54:12 -07:00
|
|
|
TargetModel.kTag16h5,
|
2022-11-03 15:05:37 -05:00
|
|
|
5));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.addVisionTargets(
|
|
|
|
|
new VisionTargetSim(
|
2023-07-23 18:32:36 -07:00
|
|
|
targetPoseR.transformBy(
|
2022-11-03 15:05:37 -05:00
|
|
|
new Transform3d(new Translation3d(0, 0, 1.00), new Rotation3d())),
|
2023-06-18 15:54:12 -07:00
|
|
|
TargetModel.kTag16h5,
|
2022-11-03 15:05:37 -05:00
|
|
|
6));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.addVisionTargets(
|
|
|
|
|
new VisionTargetSim(
|
2022-11-03 15:05:37 -05:00
|
|
|
targetPoseL.transformBy(
|
|
|
|
|
new Transform3d(new Translation3d(0, 0, 0.50), new Rotation3d())),
|
2023-06-18 15:54:12 -07:00
|
|
|
TargetModel.kTag16h5,
|
2022-11-03 15:05:37 -05:00
|
|
|
7));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.addVisionTargets(
|
|
|
|
|
new VisionTargetSim(
|
2022-11-03 15:05:37 -05:00
|
|
|
targetPoseC.transformBy(
|
|
|
|
|
new Transform3d(new Translation3d(0, 0, 0.50), new Rotation3d())),
|
2023-06-18 15:54:12 -07:00
|
|
|
TargetModel.kTag16h5,
|
2022-11-03 15:05:37 -05:00
|
|
|
8));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.addVisionTargets(
|
|
|
|
|
new VisionTargetSim(
|
2022-11-03 15:05:37 -05:00
|
|
|
targetPoseL.transformBy(
|
|
|
|
|
new Transform3d(new Translation3d(0, 0, 0.75), new Rotation3d())),
|
2023-06-18 15:54:12 -07:00
|
|
|
TargetModel.kTag16h5,
|
2022-11-03 15:05:37 -05:00
|
|
|
9));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.addVisionTargets(
|
|
|
|
|
new VisionTargetSim(
|
2022-11-03 15:05:37 -05:00
|
|
|
targetPoseR.transformBy(
|
|
|
|
|
new Transform3d(new Translation3d(0, 0, 0.75), new Rotation3d())),
|
2023-06-18 15:54:12 -07:00
|
|
|
TargetModel.kTag16h5,
|
2022-11-03 15:05:37 -05:00
|
|
|
10));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.addVisionTargets(
|
|
|
|
|
new VisionTargetSim(
|
2022-11-03 15:05:37 -05:00
|
|
|
targetPoseL.transformBy(
|
|
|
|
|
new Transform3d(new Translation3d(0, 0, 0.25), new Rotation3d())),
|
2023-06-18 15:54:12 -07:00
|
|
|
TargetModel.kTag16h5,
|
2022-11-03 15:05:37 -05:00
|
|
|
11));
|
|
|
|
|
|
|
|
|
|
var robotPose = new Pose2d(new Translation2d(6.0, 0), Rotation2d.fromDegrees(0.25));
|
2023-06-18 15:54:12 -07:00
|
|
|
visionSysSim.update(robotPose);
|
|
|
|
|
var res = camera.getLatestResult();
|
2021-01-16 20:41:47 -08:00
|
|
|
assertTrue(res.hasTargets());
|
|
|
|
|
List<PhotonTrackedTarget> tgtList;
|
|
|
|
|
tgtList = res.getTargets();
|
2023-06-18 15:54:12 -07:00
|
|
|
assertEquals(11, tgtList.size());
|
2021-01-16 20:41:47 -08:00
|
|
|
}
|
2023-07-23 18:32:36 -07:00
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void testPoseEstimation() {
|
|
|
|
|
var visionSysSim = new VisionSystemSim("Test");
|
|
|
|
|
var camera = new PhotonCamera("camera");
|
|
|
|
|
var cameraSim = new PhotonCameraSim(camera);
|
|
|
|
|
visionSysSim.addCamera(cameraSim, new Transform3d());
|
|
|
|
|
cameraSim.prop.setCalibration(640, 480, Rotation2d.fromDegrees(90));
|
|
|
|
|
cameraSim.setMinTargetAreaPixels(20.0);
|
|
|
|
|
|
|
|
|
|
List<AprilTag> tagList = new ArrayList<>();
|
|
|
|
|
tagList.add(new AprilTag(0, new Pose3d(12, 3, 1, new Rotation3d(0, 0, Math.PI))));
|
|
|
|
|
tagList.add(new AprilTag(1, new Pose3d(12, 1, -1, new Rotation3d(0, 0, Math.PI))));
|
|
|
|
|
tagList.add(new AprilTag(2, new Pose3d(11, 0, 2, new Rotation3d(0, 0, Math.PI))));
|
|
|
|
|
double fieldLength = Units.feetToMeters(54.0);
|
|
|
|
|
double fieldWidth = Units.feetToMeters(27.0);
|
|
|
|
|
AprilTagFieldLayout layout = new AprilTagFieldLayout(tagList, fieldLength, fieldWidth);
|
|
|
|
|
Pose2d robotPose = new Pose2d(5, 1, Rotation2d.fromDegrees(5));
|
|
|
|
|
|
|
|
|
|
visionSysSim.addVisionTargets(
|
|
|
|
|
new VisionTargetSim(tagList.get(0).pose, TargetModel.kTag16h5, 0));
|
|
|
|
|
|
|
|
|
|
visionSysSim.update(robotPose);
|
|
|
|
|
var results =
|
|
|
|
|
VisionEstimation.estimateCamPosePNP(
|
|
|
|
|
camera.getCameraMatrix().get(),
|
|
|
|
|
camera.getDistCoeffs().get(),
|
|
|
|
|
camera.getLatestResult().getTargets(),
|
|
|
|
|
layout);
|
|
|
|
|
Pose3d pose = new Pose3d().plus(results.best);
|
|
|
|
|
assertEquals(5, pose.getX(), .01);
|
|
|
|
|
assertEquals(1, pose.getY(), .01);
|
|
|
|
|
assertEquals(0, pose.getZ(), .01);
|
|
|
|
|
assertEquals(Math.toRadians(5), pose.getRotation().getZ(), 0.01);
|
|
|
|
|
|
|
|
|
|
visionSysSim.addVisionTargets(
|
|
|
|
|
new VisionTargetSim(tagList.get(1).pose, TargetModel.kTag16h5, 1));
|
|
|
|
|
visionSysSim.addVisionTargets(
|
|
|
|
|
new VisionTargetSim(tagList.get(2).pose, TargetModel.kTag16h5, 2));
|
|
|
|
|
|
|
|
|
|
visionSysSim.update(robotPose);
|
|
|
|
|
results =
|
|
|
|
|
VisionEstimation.estimateCamPosePNP(
|
|
|
|
|
camera.getCameraMatrix().get(),
|
|
|
|
|
camera.getDistCoeffs().get(),
|
|
|
|
|
camera.getLatestResult().getTargets(),
|
|
|
|
|
layout);
|
|
|
|
|
pose = new Pose3d().plus(results.best);
|
|
|
|
|
assertEquals(5, pose.getX(), .01);
|
|
|
|
|
assertEquals(1, pose.getY(), .01);
|
|
|
|
|
assertEquals(0, pose.getZ(), .01);
|
|
|
|
|
assertEquals(Math.toRadians(5), pose.getRotation().getZ(), 0.01);
|
|
|
|
|
}
|
2021-01-16 20:41:47 -08:00
|
|
|
}
|