Compare commits

...

7 Commits

Author SHA1 Message Date
Matt
d542190187 Merge branch 'master' of github.com:mcm001/photonvision 2024-01-15 22:23:30 -05:00
Matt
e1f550a751 Load libquadmath on Windows (#1163)
Nobody reads these, right? This probably won't make things worse. Surely.
2024-01-15 18:44:58 -05:00
Ryan Blue
a40e4049d4 Update spotless to fix exception spam (#1162) 2024-01-15 15:44:43 -05:00
Matt
152888f216 Bind-mount repo in image builder (#1157)
Reduces built image size by not accidentally copying source in
2024-01-14 13:31:12 -05:00
ArchB1W
b729d9e917 [photon-lib java] Implement ProtobufSerializable (#1156)
* [photon-lib java] Fix classes with protobuf support not "announcing it"

Since they didn't implement `ProtobufSerializable` this meant that most other software didn't even know protobufs were even implemented.
In AdvantageKit for example this would cause it to not work it all and crash.

* Run `spotlessJavaApply`
2024-01-13 22:35:57 -05:00
Thad House
6917ec8401 Fix vendordep including all wpilib libraries (#1155)
* Fix vendordep including all wpilib libraries. Without this fix, users were consuming a massively oversized .jar
2024-01-13 18:57:56 -06:00
Matt
44a2aff38e Restart server on general settings change 2024-01-08 12:51:17 -05:00
15 changed files with 282 additions and 124 deletions

View File

@@ -307,6 +307,8 @@ jobs:
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

View File

@@ -1,5 +1,7 @@
import edu.wpi.first.toolchain.*
plugins {
id "com.diffplug.spotless" version "6.22.0"
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.1.1"
@@ -96,3 +98,7 @@ spotless {
wrapper {
gradleVersion '8.4'
}
ext.getCurrentArch = {
return NativePlatforms.desktop
}

View File

@@ -1,7 +1,31 @@
plugins {
id 'edu.wpi.first.WpilibTools' version '1.3.0'
}
import java.nio.file.Path
apply from: "${rootDir}/shared/common.gradle"
wpilibTools.deps.wpilibVersion = wpi.versions.wpilibVersion.get()
def nativeConfigName = 'wpilibNatives'
def nativeConfig = configurations.create(nativeConfigName)
def nativeTasks = wpilibTools.createExtractionTasks {
configurationName = nativeConfigName
}
nativeTasks.addToSourceSetResources(sourceSets.main)
nativeConfig.dependencies.add wpilibTools.deps.wpilib("wpimath")
nativeConfig.dependencies.add wpilibTools.deps.wpilib("wpinet")
nativeConfig.dependencies.add wpilibTools.deps.wpilib("wpiutil")
nativeConfig.dependencies.add wpilibTools.deps.wpilib("ntcore")
nativeConfig.dependencies.add wpilibTools.deps.wpilib("cscore")
nativeConfig.dependencies.add wpilibTools.deps.wpilib("apriltag")
nativeConfig.dependencies.add wpilibTools.deps.wpilib("hal")
nativeConfig.dependencies.add wpilibTools.deps.wpilibOpenCv("frc" + wpi.frcYear.get(), wpi.versions.opencvVersion.get())
dependencies {
// JOGL stuff (currently we only distribute for aarch64, which is Pi 4)
implementation "org.jogamp.gluegen:gluegen-rt:$joglVersion"

View File

@@ -40,6 +40,7 @@ public class MrCalJNILoader extends PhotonJNICommon {
"libccolamd",
"openblas",
"libgcc_s_seh-1",
"libquadmath-0",
"libgfortran-5",
"liblapack",
"libcholmod",

View File

@@ -1,9 +1,3 @@
plugins {
id 'edu.wpi.first.WpilibTools' version '1.3.0'
}
apply plugin: "edu.wpi.first.NativeUtils"
import java.nio.file.Path
ext {
@@ -13,9 +7,125 @@ ext {
generatedHeaders = "src/generate/native/include"
}
apply from: "${rootDir}/shared/javacpp/setupBuild.gradle"
apply plugin: 'cpp'
apply plugin: 'google-test-test-suite'
apply plugin: 'edu.wpi.first.NativeUtils'
apply from: "${rootDir}/shared/config.gradle"
apply from: "${rootDir}/shared/javacommon.gradle"
apply from: "${rootDir}/versioningHelper.gradle"
nativeUtils {
exportsConfigs {
"${nativeName}" {}
}
}
model {
components {
"${nativeName}"(NativeLibrarySpec) {
sources {
cpp {
source {
srcDirs 'src/main/native/cpp', "$buildDir/generated/source/proto/main/cpp"
include '**/*.cpp', '**/*.cc'
}
exportedHeaders {
srcDirs 'src/main/native/include', "$buildDir/generated/source/proto/main/cpp"
if (project.hasProperty('generatedHeaders')) {
srcDir generatedHeaders
}
include "**/*.h"
}
}
}
binaries.all {
it.tasks.withType(CppCompile) {
it.dependsOn generateProto
}
if(project.hasProperty('includePhotonTargeting')) {
lib project: ':photon-targeting', library: 'photontargeting', linkage: 'shared'
}
}
nativeUtils.useRequiredLibrary(it, "wpilib_shared")
nativeUtils.useRequiredLibrary(it, "apriltag_shared")
nativeUtils.useRequiredLibrary(it, "opencv_shared")
}
}
testSuites {
"${nativeName}Test"(GoogleTestTestSuiteSpec) {
for(NativeComponentSpec c : $.components) {
if (c.name == nativeName) {
testing c
break
}
}
sources {
cpp {
source {
srcDirs 'src/test/native/cpp'
include '**/*.cpp'
}
exportedHeaders {
srcDirs 'src/test/native/include', "$buildDir/generated/source/proto/main/cpp"
}
}
}
binaries.all {
it.tasks.withType(CppCompile) {
it.dependsOn generateProto
}
if(project.hasProperty('includePhotonTargeting')) {
lib project: ':photon-targeting', library: 'photontargeting', linkage: 'shared'
}
}
nativeUtils.useRequiredLibrary(it, "cscore_shared")
nativeUtils.useRequiredLibrary(it, "cameraserver_shared")
nativeUtils.useRequiredLibrary(it, "wpilib_executable_shared")
nativeUtils.useRequiredLibrary(it, "googletest_static")
nativeUtils.useRequiredLibrary(it, "apriltag_shared")
nativeUtils.useRequiredLibrary(it, "opencv_shared")
}
}
tasks {
def c = $.testSuites
project.tasks.create('runCpp', Exec) {
description = "Run the photon-lib executable"
def found = false
def systemArch = getCurrentArch()
c.each {
if (it in GoogleTestTestSuiteSpec && it.name == "${nativeName}Test") {
it.binaries.each {
if (!found) {
def arch = it.targetPlatform.name
if (arch == systemArch) {
dependsOn it.tasks.install
commandLine it.tasks.install.runScriptFile.get().asFile.toString()
def filePath = it.tasks.install.installDirectory.get().toString() + File.separatorChar + 'lib'
test.dependsOn it.tasks.install
test.systemProperty 'java.library.path', filePath
test.environment 'LD_LIBRARY_PATH', filePath
test.environment 'DYLD_LIBRARY_PATH', filePath
test.workingDir filePath
found = true
}
}
}
}
}
}
}
}
apply from: "${rootDir}/shared/javacpp/publish.gradle"
// Include the version file in the distributed sources
cppHeadersZip {
from('src/generate/native/include') {

View File

@@ -26,31 +26,23 @@ package org.photonvision;
import static org.junit.jupiter.api.Assertions.*;
import edu.wpi.first.apriltag.jni.AprilTagJNI;
import edu.wpi.first.cscore.CameraServerCvJNI;
import edu.wpi.first.cscore.CameraServerJNI;
import edu.wpi.first.hal.JNIWrapper;
import edu.wpi.first.math.MathUtil;
import edu.wpi.first.math.geometry.Pose3d;
import edu.wpi.first.math.geometry.Rotation2d;
import edu.wpi.first.math.geometry.Rotation3d;
import edu.wpi.first.math.geometry.Transform3d;
import edu.wpi.first.math.geometry.Translation3d;
import edu.wpi.first.net.WPINetJNI;
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.networktables.NetworkTablesJNI;
import edu.wpi.first.util.CombinedRuntimeLoader;
import edu.wpi.first.util.WPIUtilJNI;
import java.io.IOException;
import java.util.List;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.opencv.core.Core;
import org.photonvision.estimation.CameraTargetRelation;
import org.photonvision.estimation.OpenCVHelp;
import org.photonvision.estimation.RotTrlTransform3d;
import org.photonvision.estimation.TargetModel;
import org.photonvision.simulation.SimCameraProperties;
import org.photonvision.simulation.VisionSystemSim;
import org.photonvision.simulation.VisionTargetSim;
public class OpenCVTest {
@@ -84,28 +76,8 @@ public class OpenCVTest {
private static final SimCameraProperties prop = new SimCameraProperties();
@BeforeAll
public static void setUp() {
JNIWrapper.Helper.setExtractOnStaticLoad(false);
WPIUtilJNI.Helper.setExtractOnStaticLoad(false);
NetworkTablesJNI.Helper.setExtractOnStaticLoad(false);
WPINetJNI.Helper.setExtractOnStaticLoad(false);
CameraServerJNI.Helper.setExtractOnStaticLoad(false);
CameraServerCvJNI.Helper.setExtractOnStaticLoad(false);
AprilTagJNI.Helper.setExtractOnStaticLoad(false);
try {
CombinedRuntimeLoader.loadLibraries(
VisionSystemSim.class,
"wpiutiljni",
"ntcorejni",
"wpinetjni",
"wpiHaljni",
Core.NATIVE_LIBRARY_NAME,
"cscorejni",
"apriltagjni");
} catch (Exception e) {
e.printStackTrace();
}
public static void setUp() throws IOException {
CameraServerCvJNI.forceLoad();
// NT live for debug purposes
NetworkTableInstance.getDefault().startServer();

View File

@@ -30,17 +30,11 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import edu.wpi.first.apriltag.AprilTag;
import edu.wpi.first.apriltag.AprilTagFieldLayout;
import edu.wpi.first.hal.JNIWrapper;
import edu.wpi.first.math.geometry.Pose3d;
import edu.wpi.first.math.geometry.Rotation3d;
import edu.wpi.first.math.geometry.Transform3d;
import edu.wpi.first.math.geometry.Translation3d;
import edu.wpi.first.math.util.Units;
import edu.wpi.first.net.WPINetJNI;
import edu.wpi.first.networktables.NetworkTablesJNI;
import edu.wpi.first.util.CombinedRuntimeLoader;
import edu.wpi.first.util.WPIUtilJNI;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -56,19 +50,6 @@ class PhotonPoseEstimatorTest {
@BeforeAll
public static void init() {
JNIWrapper.Helper.setExtractOnStaticLoad(false);
WPIUtilJNI.Helper.setExtractOnStaticLoad(false);
NetworkTablesJNI.Helper.setExtractOnStaticLoad(false);
WPINetJNI.Helper.setExtractOnStaticLoad(false);
try {
CombinedRuntimeLoader.loadLibraries(
PhotonPoseEstimatorTest.class, "wpiutiljni", "ntcorejni", "wpinetjni", "wpiHaljni");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
List<AprilTag> tagList = new ArrayList<>(2);
tagList.add(new AprilTag(0, new Pose3d(3, 3, 3, new Rotation3d())));
tagList.add(new AprilTag(1, new Pose3d(5, 5, 5, new Rotation3d())));

View File

@@ -30,10 +30,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import edu.wpi.first.apriltag.AprilTag;
import edu.wpi.first.apriltag.AprilTagFieldLayout;
import edu.wpi.first.apriltag.jni.AprilTagJNI;
import edu.wpi.first.cscore.CameraServerCvJNI;
import edu.wpi.first.cscore.CameraServerJNI;
import edu.wpi.first.hal.JNIWrapper;
import edu.wpi.first.math.geometry.Pose2d;
import edu.wpi.first.math.geometry.Pose3d;
import edu.wpi.first.math.geometry.Rotation2d;
@@ -42,11 +38,7 @@ import edu.wpi.first.math.geometry.Transform3d;
import edu.wpi.first.math.geometry.Translation2d;
import edu.wpi.first.math.geometry.Translation3d;
import edu.wpi.first.math.util.Units;
import edu.wpi.first.net.WPINetJNI;
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.networktables.NetworkTablesJNI;
import edu.wpi.first.util.CombinedRuntimeLoader;
import edu.wpi.first.util.WPIUtilJNI;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
@@ -58,7 +50,6 @@ 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;
import org.opencv.core.Core;
import org.photonvision.estimation.TargetModel;
import org.photonvision.estimation.VisionEstimation;
import org.photonvision.simulation.PhotonCameraSim;
@@ -85,28 +76,6 @@ class VisionSystemSimTest {
@BeforeAll
public static void setUp() {
JNIWrapper.Helper.setExtractOnStaticLoad(false);
WPIUtilJNI.Helper.setExtractOnStaticLoad(false);
NetworkTablesJNI.Helper.setExtractOnStaticLoad(false);
WPINetJNI.Helper.setExtractOnStaticLoad(false);
CameraServerJNI.Helper.setExtractOnStaticLoad(false);
CameraServerCvJNI.Helper.setExtractOnStaticLoad(false);
AprilTagJNI.Helper.setExtractOnStaticLoad(false);
try {
CombinedRuntimeLoader.loadLibraries(
VisionSystemSim.class,
"wpiutiljni",
"ntcorejni",
"wpinetjni",
"wpiHaljni",
Core.NATIVE_LIBRARY_NAME,
"cscorejni",
"apriltagjni");
} catch (Exception e) {
e.printStackTrace();
}
// NT live for debug purposes
NetworkTableInstance.getDefault().startServer();

View File

@@ -26,14 +26,8 @@ package org.photonvision.estimation;
import edu.wpi.first.apriltag.AprilTagFieldLayout;
import edu.wpi.first.apriltag.AprilTagFields;
import edu.wpi.first.cscore.CameraServerCvJNI;
import edu.wpi.first.hal.JNIWrapper;
import edu.wpi.first.math.geometry.Transform3d;
import edu.wpi.first.net.WPINetJNI;
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.networktables.NetworkTablesJNI;
import edu.wpi.first.util.CombinedRuntimeLoader;
import edu.wpi.first.util.WPIUtilJNI;
import edu.wpi.first.wpilibj.smartdashboard.Field2d;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
import java.io.IOException;
@@ -44,25 +38,6 @@ import org.photonvision.PhotonPoseEstimator;
public class ApriltagWorkbenchTest {
@BeforeAll
public static void setUp() {
JNIWrapper.Helper.setExtractOnStaticLoad(false);
WPIUtilJNI.Helper.setExtractOnStaticLoad(false);
NetworkTablesJNI.Helper.setExtractOnStaticLoad(false);
WPINetJNI.Helper.setExtractOnStaticLoad(false);
CameraServerCvJNI.Helper.setExtractOnStaticLoad(false);
try {
CombinedRuntimeLoader.loadLibraries(
ApriltagWorkbenchTest.class,
"wpiutiljni",
"ntcorejni",
"wpinetjni",
"wpiHaljni",
"cscorejnicvstatic");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// No version check for testing
PhotonCamera.setVersionCheckEnabled(false);
}

View File

@@ -1,9 +1,122 @@
plugins {
id 'edu.wpi.first.WpilibTools' version '1.3.0'
}
ext {
nativeName = "photontargeting"
}
apply from: "${rootDir}/shared/javacpp/setupBuild.gradle"
apply plugin: 'cpp'
apply plugin: 'google-test-test-suite'
apply plugin: 'edu.wpi.first.NativeUtils'
apply from: "${rootDir}/shared/config.gradle"
apply from: "${rootDir}/shared/javacommon.gradle"
apply from: "${rootDir}/versioningHelper.gradle"
nativeUtils {
exportsConfigs {
"${nativeName}" {}
}
}
model {
components {
"${nativeName}"(NativeLibrarySpec) {
sources {
cpp {
source {
srcDirs 'src/main/native/cpp', "$buildDir/generated/source/proto/main/cpp"
include '**/*.cpp', '**/*.cc'
}
exportedHeaders {
srcDirs 'src/main/native/include', "$buildDir/generated/source/proto/main/cpp"
if (project.hasProperty('generatedHeaders')) {
srcDir generatedHeaders
}
include "**/*.h"
}
}
}
binaries.all {
it.tasks.withType(CppCompile) {
it.dependsOn generateProto
}
if(project.hasProperty('includePhotonTargeting')) {
lib project: ':photon-targeting', library: 'photontargeting', linkage: 'shared'
}
}
nativeUtils.useRequiredLibrary(it, "wpilib_shared")
nativeUtils.useRequiredLibrary(it, "apriltag_shared")
nativeUtils.useRequiredLibrary(it, "opencv_shared")
}
}
testSuites {
"${nativeName}Test"(GoogleTestTestSuiteSpec) {
for(NativeComponentSpec c : $.components) {
if (c.name == nativeName) {
testing c
break
}
}
sources {
cpp {
source {
srcDirs 'src/test/native/cpp'
include '**/*.cpp'
}
exportedHeaders {
srcDirs 'src/test/native/include', "$buildDir/generated/source/proto/main/cpp"
}
}
}
binaries.all {
it.tasks.withType(CppCompile) {
it.dependsOn generateProto
}
if(project.hasProperty('includePhotonTargeting')) {
lib project: ':photon-targeting', library: 'photontargeting', linkage: 'shared'
}
}
nativeUtils.useRequiredLibrary(it, "cscore_shared")
nativeUtils.useRequiredLibrary(it, "cameraserver_shared")
nativeUtils.useRequiredLibrary(it, "wpilib_executable_shared")
nativeUtils.useRequiredLibrary(it, "googletest_static")
nativeUtils.useRequiredLibrary(it, "apriltag_shared")
nativeUtils.useRequiredLibrary(it, "opencv_shared")
}
}
tasks {
def c = $.testSuites
project.tasks.create('runCpp', Exec) {
description = "Run the photon-lib executable"
def found = false
def systemArch = getCurrentArch()
c.each {
if (it in GoogleTestTestSuiteSpec && it.name == "${nativeName}Test") {
it.binaries.each {
if (!found) {
def arch = it.targetPlatform.name
if (arch == systemArch) {
dependsOn it.tasks.install
commandLine it.tasks.install.runScriptFile.get().asFile.toString()
def filePath = it.tasks.install.installDirectory.get().toString() + File.separatorChar + 'lib'
test.dependsOn it.tasks.install
test.systemProperty 'java.library.path', filePath
test.environment 'LD_LIBRARY_PATH', filePath
test.environment 'DYLD_LIBRARY_PATH', filePath
test.workingDir filePath
found = true
}
}
}
}
}
}
}
}
apply from: "${rootDir}/shared/javacpp/publish.gradle"

View File

@@ -17,13 +17,14 @@
package org.photonvision.targeting;
import edu.wpi.first.util.protobuf.ProtobufSerializable;
import java.util.ArrayList;
import java.util.List;
import org.photonvision.common.dataflow.structures.Packet;
import org.photonvision.common.dataflow.structures.PacketSerde;
import org.photonvision.targeting.proto.MultiTargetPNPResultProto;
public class MultiTargetPNPResult {
public class MultiTargetPNPResult implements ProtobufSerializable {
// Seeing 32 apriltags at once seems like a sane limit
private static final int MAX_IDS = 32;

View File

@@ -18,6 +18,7 @@
package org.photonvision.targeting;
import edu.wpi.first.math.geometry.Transform3d;
import edu.wpi.first.util.protobuf.ProtobufSerializable;
import org.photonvision.common.dataflow.structures.Packet;
import org.photonvision.common.dataflow.structures.PacketSerde;
import org.photonvision.targeting.proto.PNPResultProto;
@@ -32,7 +33,7 @@ import org.photonvision.utils.PacketUtils;
* <p>Note that the coordinate frame of these transforms depends on the implementing solvePnP
* method.
*/
public class PNPResult {
public class PNPResult implements ProtobufSerializable {
/**
* If this result is valid. A false value indicates there was an error in estimation, and this
* result should not be used.

View File

@@ -17,6 +17,7 @@
package org.photonvision.targeting;
import edu.wpi.first.util.protobuf.ProtobufSerializable;
import java.util.ArrayList;
import java.util.List;
import org.photonvision.common.dataflow.structures.Packet;
@@ -24,7 +25,7 @@ import org.photonvision.common.dataflow.structures.PacketSerde;
import org.photonvision.targeting.proto.PhotonPipelineResultProto;
/** Represents a pipeline result from a PhotonCamera. */
public class PhotonPipelineResult {
public class PhotonPipelineResult implements ProtobufSerializable {
private static boolean HAS_WARNED = false;
// Targets to store.

View File

@@ -18,6 +18,7 @@
package org.photonvision.targeting;
import edu.wpi.first.math.geometry.Transform3d;
import edu.wpi.first.util.protobuf.ProtobufSerializable;
import java.util.ArrayList;
import java.util.List;
import org.photonvision.common.dataflow.structures.Packet;
@@ -25,7 +26,7 @@ import org.photonvision.common.dataflow.structures.PacketSerde;
import org.photonvision.targeting.proto.PhotonTrackedTargetProto;
import org.photonvision.utils.PacketUtils;
public class PhotonTrackedTarget {
public class PhotonTrackedTarget implements ProtobufSerializable {
private static final int MAX_CORNERS = 8;
private final double yaw;

View File

@@ -17,6 +17,7 @@
package org.photonvision.targeting;
import edu.wpi.first.util.protobuf.ProtobufSerializable;
import java.util.Objects;
import org.photonvision.common.dataflow.structures.Packet;
import org.photonvision.common.dataflow.structures.PacketSerde;
@@ -26,7 +27,7 @@ import org.photonvision.targeting.proto.TargetCornerProto;
* Represents a point in an image at the corner of the minimum-area bounding rectangle, in pixels.
* Origin at the top left, plus-x to the right, plus-y down.
*/
public class TargetCorner {
public class TargetCorner implements ProtobufSerializable {
public final double x;
public final double y;