mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-20 00:51:41 +00:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
72717cecf0 | ||
|
|
971ff3ac40 | ||
|
|
b80e436f02 | ||
|
|
be1a053cbe | ||
|
|
f4555dc545 | ||
|
|
54fdd1db51 | ||
|
|
1805785cc6 | ||
|
|
e62f6419b5 | ||
|
|
fa7824c616 | ||
|
|
9090aa6bcc | ||
|
|
5655ca6890 | ||
|
|
50fdfd8bce | ||
|
|
3120a6439b | ||
|
|
ab3e8c8db7 | ||
|
|
5144819ce2 | ||
|
|
d779fe23f0 | ||
|
|
b2a3f34433 | ||
|
|
b09a6d6a2d | ||
|
|
9893cf1f7e | ||
|
|
fc91daf397 | ||
|
|
a3e205cb6f |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -143,3 +143,4 @@ build/*
|
||||
build
|
||||
photon-lib/src/main/java/org/photonvision/PhotonVersion.java
|
||||
/photonlib-java-examples/bin/
|
||||
photon-lib/src/generate/native/include/PhotonVersion.h
|
||||
|
||||
@@ -25,7 +25,3 @@ includeOtherLibs {
|
||||
^units/
|
||||
^wpi/
|
||||
}
|
||||
|
||||
licenseUpdateExclude {
|
||||
\.java$
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) Photon Vision.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
@@ -47,7 +47,6 @@ spotless {
|
||||
}
|
||||
java {
|
||||
target "**/*.java"
|
||||
licenseHeaderFile "$rootDir/LicenseHeader.txt"
|
||||
targetExclude("photon-core/src/main/java/org/photonvision/PhotonVersion.java")
|
||||
targetExclude("photon-lib/src/main/java/org/photonvision/PhotonVersion.java")
|
||||
}
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
:mandatory="true"
|
||||
>
|
||||
<v-radio
|
||||
v-for="(name,index) in list"
|
||||
v-for="(radioName,index) in list"
|
||||
:key="index"
|
||||
color="#ffd843"
|
||||
:label="name"
|
||||
:label="radioName"
|
||||
:value="index"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
hide-details
|
||||
class="align-center"
|
||||
dark
|
||||
color="accent"
|
||||
:color="inverted ? 'rgba(255, 255, 255, 0.2)' : 'accent'"
|
||||
:track-color="inverted ? 'accent' : undefined"
|
||||
thumb-color="accent"
|
||||
:step="step"
|
||||
@input="handleInput"
|
||||
@mousedown="$emit('rollback', localValue)"
|
||||
@@ -76,7 +78,7 @@ export default {
|
||||
TooltippedLabel,
|
||||
},
|
||||
// eslint-disable-next-line vue/require-prop-types
|
||||
props: ["name", "min", "max", "value", "step", "tooltip", "disabled"],
|
||||
props: ["name", "min", "max", "value", "step", "tooltip", "disabled", "inverted"],
|
||||
data() {
|
||||
return {
|
||||
prependFocused: false,
|
||||
|
||||
@@ -6,8 +6,10 @@ function initColorPicker() {
|
||||
canvas = document.createElement('canvas');
|
||||
|
||||
image = document.querySelector('#normal-stream');
|
||||
canvas.width = image.width;
|
||||
canvas.height = image.height;
|
||||
if (image !== null) {
|
||||
canvas.width = image.width;
|
||||
canvas.height = image.height;
|
||||
}
|
||||
}
|
||||
|
||||
//Called on click of the image,
|
||||
|
||||
@@ -19,6 +19,8 @@ export default new Vuex.Store({
|
||||
connected: false,
|
||||
address: "",
|
||||
clients: 0,
|
||||
},
|
||||
networkInfo: {
|
||||
possibleRios: ["Loading..."],
|
||||
deviceips: ["Loading..."],
|
||||
},
|
||||
@@ -55,7 +57,8 @@ export default new Vuex.Store({
|
||||
// Settings that apply to all pipeline types
|
||||
cameraExposure: 1,
|
||||
cameraBrightness: 2,
|
||||
cameraGain: 3,
|
||||
cameraRedGain: 3,
|
||||
cameraBlueGain: 4,
|
||||
inputImageRotationMode: 0,
|
||||
cameraVideoModeIndex: 0,
|
||||
streamingFrameDivisor: 0,
|
||||
@@ -64,10 +67,13 @@ export default new Vuex.Store({
|
||||
hsvHue: [0, 15],
|
||||
hsvSaturation: [0, 15],
|
||||
hsvValue: [0, 25],
|
||||
hueInverted: false,
|
||||
contourArea: [0, 12],
|
||||
contourRatio: [0, 12],
|
||||
contourFullness: [0, 12],
|
||||
contourSpecklePercentage: 5,
|
||||
contourFilterRangeX: 5,
|
||||
contourFilterRangeY: 5,
|
||||
contourGroupingMode: 0,
|
||||
contourIntersection: 0,
|
||||
contourSortMode: 0,
|
||||
@@ -151,6 +157,7 @@ export default new Vuex.Store({
|
||||
calibrationData: set('calibrationData'),
|
||||
metrics: set('metrics'),
|
||||
ntConnectionInfo: set('ntConnectionInfo'),
|
||||
networkInfo: set('networkInfo'),
|
||||
backendConnected: set('backendConnected'),
|
||||
logString: (state, newStr) => {
|
||||
const str = state.logMessages;
|
||||
|
||||
@@ -196,13 +196,24 @@
|
||||
@input="e => handlePipelineUpdate('cameraBrightness', e)"
|
||||
/>
|
||||
<CVslider
|
||||
v-if="$store.getters.currentPipelineSettings.cameraGain !== -1"
|
||||
v-model="$store.getters.currentPipelineSettings.cameraGain"
|
||||
name="Gain"
|
||||
:min="0"
|
||||
:max="100"
|
||||
slider-cols="8"
|
||||
@input="e => handlePipelineUpdate('cameraGain', e)"
|
||||
v-if="$store.getters.currentPipelineSettings.cameraRedGain !== -1"
|
||||
v-model="$store.getters.currentPipelineSettings.cameraRedGain"
|
||||
name="Red AWB Gain"
|
||||
min="0"
|
||||
max="100"
|
||||
tooltip="Controls red automatic white balance gain, which affects how the camera captures colors in different conditions"
|
||||
:slider-cols="8"
|
||||
@input="e => handlePipelineData('cameraRedGain', e)"
|
||||
/>
|
||||
<CVslider
|
||||
v-if="$store.getters.currentPipelineSettings.cameraBlueGain !== -1"
|
||||
v-model="$store.getters.currentPipelineSettings.cameraBlueGain"
|
||||
name="Blue AWB Gain"
|
||||
min="0"
|
||||
max="100"
|
||||
tooltip="Controls blue automatic white balance gain, which affects how the camera captures colors in different conditions"
|
||||
:slider-cols="8"
|
||||
@input="e => handlePipelineData('cameraBlueGain', e)"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
name="Area"
|
||||
min="0"
|
||||
max="100"
|
||||
step="0.1"
|
||||
step="0.01"
|
||||
@input="handlePipelineData('contourArea')"
|
||||
/>
|
||||
<CVrangeSlider
|
||||
@@ -18,6 +18,14 @@
|
||||
step="0.1"
|
||||
@input="handlePipelineData('contourRatio')"
|
||||
/>
|
||||
<CVselect
|
||||
v-model="contourTargetOrientation"
|
||||
name="Target Orientation"
|
||||
tooltip="Used to determine how to calculate target landmarks, as well as aspect ratio"
|
||||
:list="['Portrait', 'Landscape']"
|
||||
@input="handlePipelineData('contourTargetOrientation')"
|
||||
@rollback="e=> rollback('contourTargetOrientation', e)"
|
||||
/>
|
||||
<CVrangeSlider
|
||||
v-if="currentPipelineType() !== 3"
|
||||
v-model="contourFullness"
|
||||
@@ -46,6 +54,26 @@
|
||||
@input="handlePipelineData('contourSpecklePercentage')"
|
||||
/>
|
||||
<template v-if="currentPipelineType() !== 3">
|
||||
<CVslider
|
||||
v-model="contourFilterRangeX"
|
||||
name="X filter tightness"
|
||||
tooltip="Rejects contours whose center X is further than X standard deviations above/below the mean X location"
|
||||
min="0.1"
|
||||
max="4"
|
||||
step="0.1"
|
||||
:slider-cols="largeBox"
|
||||
@input="handlePipelineData('contourFilterRangeX')"
|
||||
/>
|
||||
<CVslider
|
||||
v-model="contourFilterRangeY"
|
||||
name="Y filter tightness"
|
||||
tooltip="Rejects contours whose center Y is further than X standard deviations above/below the mean Y location"
|
||||
min="0.1"
|
||||
max="4"
|
||||
step="0.1"
|
||||
:slider-cols="largeBox"
|
||||
@input="handlePipelineData('contourFilterRangeY')"
|
||||
/>
|
||||
<CVselect
|
||||
v-model="contourGroupingMode"
|
||||
name="Target Grouping"
|
||||
@@ -121,7 +149,7 @@
|
||||
v-model="circleAccuracy"
|
||||
:disabled="currentPipelineSettings().contourShape !== 0"
|
||||
name="Circle Accuracy"
|
||||
min="0"
|
||||
min="1"
|
||||
max="100"
|
||||
:slider-cols="largeBox"
|
||||
@input="handlePipelineData('circleAccuracy')"
|
||||
@@ -183,6 +211,14 @@ export default {
|
||||
this.$store.commit("mutatePipeline", {"contourRatio": val});
|
||||
}
|
||||
},
|
||||
contourTargetOrientation: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.contourTargetOrientation
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"contourTargetOrientation": val});
|
||||
}
|
||||
},
|
||||
contourFullness: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.contourFullness
|
||||
@@ -207,6 +243,25 @@ export default {
|
||||
this.$store.commit("mutatePipeline", {"contourSpecklePercentage": val});
|
||||
}
|
||||
},
|
||||
contourFilterRangeX: {
|
||||
get() {
|
||||
console.log(this.$store.getters.currentPipelineSettings.contourFilterRangeX)
|
||||
return this.$store.getters.currentPipelineSettings.contourFilterRangeX
|
||||
},
|
||||
set(val) {
|
||||
console.log("set")
|
||||
console.log(val)
|
||||
this.$store.commit("mutatePipeline", {"contourFilterRangeX": val});
|
||||
}
|
||||
},
|
||||
contourFilterRangeY: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.contourFilterRangeY
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"contourFilterRangeY": val});
|
||||
}
|
||||
},
|
||||
contourGroupingMode: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.contourGroupingMode
|
||||
|
||||
@@ -22,15 +22,26 @@
|
||||
@rollback="e => rollback('cameraBrightness', e)"
|
||||
/>
|
||||
<CVslider
|
||||
v-if="cameraGain !== -1"
|
||||
v-model="cameraGain"
|
||||
name="Gain"
|
||||
v-if="cameraRedGain !== -1"
|
||||
v-model="cameraRedGain"
|
||||
name="Red AWB Gain"
|
||||
min="0"
|
||||
max="100"
|
||||
tooltip="Controls automatic white balance gain, which affects how the camera captures colors in different conditions"
|
||||
tooltip="Controls red automatic white balance gain, which affects how the camera captures colors in different conditions"
|
||||
:slider-cols="largeBox"
|
||||
@input="handlePipelineData('cameraGain')"
|
||||
@rollback="e => rollback('cameraGain', e)"
|
||||
@input="handlePipelineData('cameraRedGain')"
|
||||
@rollback="e => rollback('cameraRedGain', e)"
|
||||
/>
|
||||
<CVslider
|
||||
v-if="cameraBlueGain !== -1"
|
||||
v-model="cameraBlueGain"
|
||||
name="Blue AWB Gain"
|
||||
min="0"
|
||||
max="100"
|
||||
tooltip="Controls blue automatic white balance gain, which affects how the camera captures colors in different conditions"
|
||||
:slider-cols="largeBox"
|
||||
@input="handlePipelineData('cameraBlueGain')"
|
||||
@rollback="e => rollback('cameraBlueGain', e)"
|
||||
/>
|
||||
<CVselect
|
||||
v-model="inputImageRotationMode"
|
||||
@@ -105,12 +116,20 @@
|
||||
this.$store.commit("mutatePipeline", {"cameraBrightness": parseInt(val)});
|
||||
}
|
||||
},
|
||||
cameraGain: {
|
||||
cameraRedGain: {
|
||||
get() {
|
||||
return parseInt(this.$store.getters.currentPipelineSettings.cameraGain)
|
||||
return parseInt(this.$store.getters.currentPipelineSettings.cameraRedGain)
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"cameraGain": parseInt(val)});
|
||||
this.$store.commit("mutatePipeline", {"cameraRedGain": parseInt(val)});
|
||||
}
|
||||
},
|
||||
cameraBlueGain: {
|
||||
get() {
|
||||
return parseInt(this.$store.getters.currentPipelineSettings.cameraBlueGain)
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"cameraBlueGain": parseInt(val)});
|
||||
}
|
||||
},
|
||||
inputImageRotationMode: {
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
targetList: ['2020 High Goal Outer', '2020 High Goal Inner', '2019 Dual Target', 'Power Cell (7in)', '2016 High Goal'], //Keep in sync with TargetModel.java
|
||||
targetList: ['2020 High Goal Outer', '2020 High Goal Inner', '2019 Dual Target', '2020 Power Cell (7in)','2022 Cargo Ball (9.5in)', '2016 High Goal'], //Keep in sync with TargetModel.java
|
||||
snackbar: {
|
||||
color: "Success",
|
||||
text: ""
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
<template>
|
||||
<div>
|
||||
<div :style="{'--averageHue': averageHue}">
|
||||
<CVrangeSlider
|
||||
id="hue-slider"
|
||||
v-model="hsvHue"
|
||||
:class="hueInverted ? 'inverted-slider' : 'normal-slider'"
|
||||
name="Hue"
|
||||
tooltip="Describes color"
|
||||
:min="0"
|
||||
:max="180"
|
||||
:inverted="hueInverted"
|
||||
@input="handlePipelineData('hsvHue')"
|
||||
@rollback="e => rollback('hue',e)"
|
||||
/>
|
||||
<CVrangeSlider
|
||||
id="sat-slider"
|
||||
v-model="hsvSaturation"
|
||||
class="normal-slider"
|
||||
name="Saturation"
|
||||
tooltip="Describes colorfulness; the smaller this value the 'whiter' the color becomes"
|
||||
:min="0"
|
||||
@@ -19,7 +24,9 @@
|
||||
@rollback="e => rollback('saturation',e)"
|
||||
/>
|
||||
<CVrangeSlider
|
||||
id="value-slider"
|
||||
v-model="hsvValue"
|
||||
class="normal-slider"
|
||||
name="Value"
|
||||
tooltip="Describes lightness; the smaller this value the 'blacker' the color becomes"
|
||||
:min="0"
|
||||
@@ -27,6 +34,13 @@
|
||||
@input="handlePipelineData('hsvValue')"
|
||||
@rollback="e => rollback('value',e)"
|
||||
/>
|
||||
<CVSwitch
|
||||
v-model="hueInverted"
|
||||
name="Invert hue"
|
||||
tooltip="Selects the hue range outside of the hue slider bounds instead of inside"
|
||||
@input="handlePipelineData('hueInverted')"
|
||||
@rollback="e => rollback('hueInverted',e)"
|
||||
/>
|
||||
<template v-if="currentPipelineType() === 3">
|
||||
<CVSwitch
|
||||
v-model="erode"
|
||||
@@ -59,7 +73,7 @@
|
||||
color="accent"
|
||||
class="ma-2 black--text"
|
||||
small
|
||||
@click="setFunction(3)"
|
||||
@click="setFunction(hueInverted ? 2 : 3)"
|
||||
>
|
||||
<v-icon left>
|
||||
mdi-minus
|
||||
@@ -75,13 +89,13 @@
|
||||
<v-icon left>
|
||||
mdi-plus-minus
|
||||
</v-icon>
|
||||
Set To Average
|
||||
{{ hueInverted ? "Exclude" : "Set to" }} Average
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="accent"
|
||||
class="ma-2 black--text"
|
||||
small
|
||||
@click="setFunction(2)"
|
||||
@click="setFunction(hueInverted ? 3: 2)"
|
||||
>
|
||||
<v-icon left>
|
||||
mdi-plus
|
||||
@@ -133,9 +147,41 @@ export default {
|
||||
this.$store.commit("mutatePipeline", {"hsvHue": val})
|
||||
}
|
||||
},
|
||||
averageHue: {
|
||||
get() {
|
||||
var isInverted = this.$store.getters.currentPipelineSettings.hueInverted;
|
||||
const arr = this.$store.getters.currentPipelineSettings.hsvHue;
|
||||
var retVal = 0;
|
||||
|
||||
if (Array.isArray(arr)) {
|
||||
retVal = (arr[0] + arr[1]);
|
||||
} else {
|
||||
retVal = (arr.first + arr.second);
|
||||
}
|
||||
|
||||
if(isInverted){
|
||||
retVal += 180;
|
||||
}
|
||||
|
||||
if(retVal > 360){
|
||||
retVal -= 360;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
|
||||
},
|
||||
},
|
||||
hueInverted: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.hueInverted;
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"hueInverted": val});
|
||||
}
|
||||
},
|
||||
hsvSaturation: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.hsvSaturation
|
||||
return this.$store.getters.currentPipelineSettings.hsvSaturation;
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"hsvSaturation": val})
|
||||
@@ -143,15 +189,15 @@ export default {
|
||||
},
|
||||
hsvValue: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.hsvValue
|
||||
return this.$store.getters.currentPipelineSettings.hsvValue;
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"hsvValue": val})
|
||||
this.$store.commit("mutatePipeline", {"hsvValue": val});
|
||||
}
|
||||
},
|
||||
erode: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.erode
|
||||
return this.$store.getters.currentPipelineSettings.erode;
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"erode": val});
|
||||
@@ -159,7 +205,7 @@ export default {
|
||||
},
|
||||
dilate: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.dilate
|
||||
return this.$store.getters.currentPipelineSettings.dilate;
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"dilate": val});
|
||||
@@ -233,3 +279,31 @@ export default {
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
#hue-slider >>> .v-slider {
|
||||
background: linear-gradient( to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100% );
|
||||
border-radius: 10px;
|
||||
box-shadow: 0px 0px 5px #333, inset 0px 0px 3px #333;
|
||||
}
|
||||
#sat-slider >>> .v-slider {
|
||||
background: linear-gradient( to right, #fff 0%, hsl(var(--averageHue), 100%, 50%) 100% );
|
||||
border-radius: 10px;
|
||||
box-shadow: 0px 0px 5px #333, inset 0px 0px 3px #333;
|
||||
}
|
||||
#value-slider >>> .v-slider {
|
||||
background: linear-gradient( to right, #000 0%, hsl(var(--averageHue), 100%, 50%) 100% );
|
||||
border-radius: 10px;
|
||||
box-shadow: 0px 0px 5px #333, inset 0px 0px 3px #333;
|
||||
}
|
||||
>>> .v-slider__thumb {
|
||||
outline: black solid thin;
|
||||
}
|
||||
.normal-slider >>> .v-slider__track-fill {
|
||||
outline: black solid thin;
|
||||
}
|
||||
|
||||
.inverted-slider >>> .v-slider__track-background {
|
||||
outline: black solid thin;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="(value, index) in $store.state.ntConnectionInfo.deviceips"
|
||||
v-for="(value, index) in $store.state.networkInfo.deviceips"
|
||||
:key="index"
|
||||
>
|
||||
<td>{{ value }}</td>
|
||||
@@ -115,7 +115,7 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="(value, index) in $store.state.ntConnectionInfo.possibleRios"
|
||||
v-for="(value, index) in $store.state.networkInfo.possibleRios"
|
||||
:key="index"
|
||||
>
|
||||
<td>{{ value }}</td>
|
||||
|
||||
@@ -25,7 +25,8 @@ dependencies {
|
||||
}
|
||||
|
||||
task writeCurrentVersionJava {
|
||||
writePhotonVersionFile(Path.of("$projectDir", "src", "main", "java", "org", "photonvision", "PhotonVersion.java"),
|
||||
def versionFileIn = file("${rootDir}/shared/PhotonVersion.java.in")
|
||||
writePhotonVersionFile(versionFileIn, Path.of("$projectDir", "src", "main", "java", "org", "photonvision", "PhotonVersion.java"),
|
||||
versionString)
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common;
|
||||
|
||||
public enum ProgramStatus {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.configuration;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.configuration;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
@@ -31,7 +32,6 @@ import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import org.photonvision.common.logging.LogGroup;
|
||||
import org.photonvision.common.logging.Logger;
|
||||
import org.photonvision.common.util.TimedTaskManager;
|
||||
import org.photonvision.common.util.file.FileUtils;
|
||||
import org.photonvision.common.util.file.JacksonUtils;
|
||||
import org.photonvision.vision.pipeline.CVPipelineSettings;
|
||||
@@ -56,6 +56,7 @@ public class ConfigManager {
|
||||
final File configDirectoryFile;
|
||||
|
||||
private long saveRequestTimestamp = -1;
|
||||
private Thread settingsSaveThread;
|
||||
|
||||
public static ConfigManager getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
@@ -96,7 +97,8 @@ public class ConfigManager {
|
||||
new File(Path.of(configDirectoryFile.toString(), NET_SET_FNAME).toUri());
|
||||
this.camerasFolder = new File(Path.of(configDirectoryFile.toString(), "cameras").toUri());
|
||||
|
||||
TimedTaskManager.getInstance().addTask("ConfigManager", this::checkSaveAndWrite, 1000);
|
||||
settingsSaveThread = new Thread(this::saveAndWriteTask);
|
||||
settingsSaveThread.start();
|
||||
}
|
||||
|
||||
public void load() {
|
||||
@@ -424,12 +426,24 @@ public class ConfigManager {
|
||||
saveRequestTimestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
private void checkSaveAndWrite() {
|
||||
private void saveAndWriteTask() {
|
||||
// Only save if 1 second has past since the request was made
|
||||
if (saveRequestTimestamp > 0 && (System.currentTimeMillis() - saveRequestTimestamp) > 1000L) {
|
||||
saveRequestTimestamp = -1;
|
||||
logger.debug("Saving to disk...");
|
||||
saveToDisk();
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
if (saveRequestTimestamp > 0 && (System.currentTimeMillis() - saveRequestTimestamp) > 1000L) {
|
||||
saveRequestTimestamp = -1;
|
||||
logger.debug("Saving to disk...");
|
||||
saveToDisk();
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("Exception waiting for settings semaphor", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void unloadCameraConfigs() {
|
||||
this.config.getCameraConfigurations().clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.configuration;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.configuration;
|
||||
|
||||
public class HardwareSettings {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.configuration;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.configuration;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.dataflow;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.dataflow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.dataflow;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.dataflow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.dataflow;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.dataflow.events;
|
||||
|
||||
import org.photonvision.common.dataflow.DataChangeDestination;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.dataflow.events;
|
||||
|
||||
import org.photonvision.common.dataflow.DataChangeDestination;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.dataflow.events;
|
||||
|
||||
import io.javalin.websocket.WsContext;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.dataflow.events;
|
||||
|
||||
import io.javalin.websocket.WsContext;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.dataflow.networktables;
|
||||
|
||||
import edu.wpi.first.networktables.EntryListenerFlags;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.dataflow.networktables;
|
||||
|
||||
import edu.wpi.first.networktables.EntryNotification;
|
||||
|
||||
@@ -14,22 +14,15 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.dataflow.networktables;
|
||||
|
||||
import edu.wpi.first.cscore.CameraServerJNI;
|
||||
import edu.wpi.first.networktables.LogMessage;
|
||||
import edu.wpi.first.networktables.NetworkTable;
|
||||
import edu.wpi.first.networktables.NetworkTableInstance;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import org.photonvision.PhotonVersion;
|
||||
import org.photonvision.common.configuration.ConfigManager;
|
||||
import org.photonvision.common.configuration.NetworkConfig;
|
||||
import org.photonvision.common.dataflow.DataChangeService;
|
||||
import org.photonvision.common.dataflow.events.OutgoingUIEvent;
|
||||
@@ -86,6 +79,7 @@ public class NetworkTablesManager {
|
||||
private void broadcastConnectedStatusImpl() {
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
var subMap = new HashMap<String, Object>();
|
||||
|
||||
subMap.put("connected", ntInstance.isConnected());
|
||||
if (ntInstance.isConnected()) {
|
||||
var connections = getInstance().ntInstance.getConnections();
|
||||
@@ -98,73 +92,6 @@ public class NetworkTablesManager {
|
||||
map.put("ntConnectionInfo", subMap);
|
||||
DataChangeService.getInstance()
|
||||
.publishEvent(new OutgoingUIEvent<>("networkTablesConnected", map));
|
||||
|
||||
// Seperate from the above so we don't hold stuff up
|
||||
System.setProperty("java.net.preferIPv4Stack", "true");
|
||||
subMap.put(
|
||||
"deviceips",
|
||||
Arrays.stream(CameraServerJNI.getNetworkInterfaces())
|
||||
.filter(it -> !it.equals("0.0.0.0"))
|
||||
.toArray());
|
||||
logger.info("Searching for rios");
|
||||
List<String> possibleRioList = new ArrayList<>();
|
||||
for (var ip : CameraServerJNI.getNetworkInterfaces()) {
|
||||
logger.info("Trying " + ip);
|
||||
var possibleRioAddr = getPossibleRioAddress(ip);
|
||||
if (possibleRioAddr != null) {
|
||||
logger.info("Maybe found " + ip);
|
||||
searchForHost(possibleRioList, possibleRioAddr);
|
||||
} else {
|
||||
logger.info("Didn't match RIO IP");
|
||||
}
|
||||
}
|
||||
String name =
|
||||
"roboRIO-"
|
||||
+ ConfigManager.getInstance().getConfig().getNetworkConfig().teamNumber
|
||||
+ "-FRC.local";
|
||||
searchForHost(possibleRioList, name);
|
||||
name =
|
||||
"roboRIO-"
|
||||
+ ConfigManager.getInstance().getConfig().getNetworkConfig().teamNumber
|
||||
+ "-FRC.lan";
|
||||
searchForHost(possibleRioList, name);
|
||||
name =
|
||||
"roboRIO-"
|
||||
+ ConfigManager.getInstance().getConfig().getNetworkConfig().teamNumber
|
||||
+ "-FRC.frc-field.local";
|
||||
searchForHost(possibleRioList, name);
|
||||
subMap.put("possibleRios", possibleRioList.toArray());
|
||||
DataChangeService.getInstance()
|
||||
.publishEvent(new OutgoingUIEvent<>("networkTablesConnected", map));
|
||||
}
|
||||
|
||||
String getPossibleRioAddress(String ip) {
|
||||
try {
|
||||
InetAddress addr = InetAddress.getByName(ip);
|
||||
var address = addr.getAddress();
|
||||
if (address[0] != (byte) (10 & 0xff)) return null;
|
||||
address[3] = (byte) (2 & 0xff);
|
||||
return InetAddress.getByAddress(address).getHostAddress();
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void searchForHost(List<String> list, String hostname) {
|
||||
try {
|
||||
logger.info("Looking up " + hostname);
|
||||
InetAddress testAddr = InetAddress.getByName(hostname);
|
||||
logger.info("Pinging " + hostname);
|
||||
var canContact = testAddr.isReachable(500);
|
||||
if (canContact) {
|
||||
logger.info("Was able to connect to " + hostname);
|
||||
if (!list.contains(hostname)) list.add(hostname);
|
||||
} else {
|
||||
logger.info("Unable to reach " + hostname);
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private void broadcastVersion() {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.dataflow.websocket;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.hardware.GPIO;
|
||||
|
||||
import org.photonvision.common.configuration.HardwareConfig;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.hardware.GPIO;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.hardware.GPIO.pi;
|
||||
|
||||
@SuppressWarnings("SpellCheckingInspection")
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.hardware.GPIO.pi;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.hardware.GPIO.pi;
|
||||
|
||||
import static org.photonvision.common.hardware.GPIO.pi.PigpioException.*;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.hardware.GPIO.pi;
|
||||
|
||||
public class PigpioPulse {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.hardware.GPIO.pi;
|
||||
|
||||
import static org.photonvision.common.hardware.GPIO.pi.PigpioException.*;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.hardware.GPIO.pi;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.hardware;
|
||||
|
||||
import edu.wpi.first.networktables.NetworkTableEntry;
|
||||
|
||||
@@ -14,13 +14,14 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.hardware;
|
||||
|
||||
public enum PiVersion {
|
||||
PI_B("Pi Model B"),
|
||||
COMPUTE_MODULE("Compute Module Rev"),
|
||||
ZERO_W("Pi Zero W Rev 1.1"),
|
||||
ZERO_2_W("Raspberry Pi Zero 2 W"),
|
||||
ZERO_2_W("Raspberry Pi Zero 2"),
|
||||
PI_3("Pi 3"),
|
||||
PI_4("Pi 4"),
|
||||
COMPUTE_MODULE_3("Compute Module 3"),
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.hardware;
|
||||
|
||||
import edu.wpi.first.util.RuntimeDetector;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.hardware;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.hardware;
|
||||
|
||||
import edu.wpi.first.networktables.EntryNotification;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.hardware.metrics;
|
||||
|
||||
public class CPUMetrics extends MetricsBase {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.hardware.metrics;
|
||||
|
||||
public class DiskMetrics extends MetricsBase {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.hardware.metrics;
|
||||
|
||||
public class GPUMetrics extends MetricsBase {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.hardware.metrics;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.hardware.metrics;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.hardware.metrics;
|
||||
|
||||
public class RAMMetrics extends MetricsBase {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.logging;
|
||||
|
||||
public enum LogGroup {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.logging;
|
||||
|
||||
public enum LogLevel {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.logging;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.networking;
|
||||
|
||||
import java.net.InterfaceAddress;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.networking;
|
||||
|
||||
import org.photonvision.common.configuration.ConfigManager;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.networking;
|
||||
|
||||
public enum NetworkMode {
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (C) Photon Vision.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.networking;
|
||||
|
||||
import edu.wpi.first.cscore.CameraServerJNI;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import org.photonvision.common.dataflow.DataChangeService;
|
||||
import org.photonvision.common.dataflow.events.OutgoingUIEvent;
|
||||
import org.photonvision.common.logging.LogGroup;
|
||||
import org.photonvision.common.logging.Logger;
|
||||
|
||||
public class RoborioFinder {
|
||||
private static RoborioFinder instance;
|
||||
private static final Logger logger = new Logger(RoborioFinder.class, LogGroup.General);
|
||||
|
||||
public static RoborioFinder getInstance() {
|
||||
if (instance == null) instance = new RoborioFinder();
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void findRios() {
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
var subMap = new HashMap<String, Object>();
|
||||
// Seperate from the above so we don't hold stuff up
|
||||
System.setProperty("java.net.preferIPv4Stack", "true");
|
||||
subMap.put(
|
||||
"deviceips",
|
||||
Arrays.stream(CameraServerJNI.getNetworkInterfaces())
|
||||
.filter(it -> !it.equals("0.0.0.0"))
|
||||
.toArray());
|
||||
logger.info("Searching for rios");
|
||||
List<String> possibleRioList = new ArrayList<>();
|
||||
for (var ip : CameraServerJNI.getNetworkInterfaces()) {
|
||||
logger.info("Trying " + ip);
|
||||
var possibleRioAddr = getPossibleRioAddress(ip);
|
||||
if (possibleRioAddr != null) {
|
||||
logger.info("Maybe found " + ip);
|
||||
searchForHost(possibleRioList, possibleRioAddr);
|
||||
} else {
|
||||
logger.info("Didn't match RIO IP");
|
||||
}
|
||||
}
|
||||
|
||||
// String name =
|
||||
// "roboRIO-"
|
||||
// +
|
||||
// ConfigManager.getInstance().getConfig().getNetworkConfig().teamNumber
|
||||
// + "-FRC.local";
|
||||
// searchForHost(possibleRioList, name);
|
||||
// name =
|
||||
// "roboRIO-"
|
||||
// +
|
||||
// ConfigManager.getInstance().getConfig().getNetworkConfig().teamNumber
|
||||
// + "-FRC.lan";
|
||||
// searchForHost(possibleRioList, name);
|
||||
// name =
|
||||
// "roboRIO-"
|
||||
// +
|
||||
// ConfigManager.getInstance().getConfig().getNetworkConfig().teamNumber
|
||||
// + "-FRC.frc-field.local";
|
||||
// searchForHost(possibleRioList, name);
|
||||
// subMap.put("possibleRios", possibleRioList.toArray());
|
||||
|
||||
subMap.put("possibleRios", possibleRioList.toArray());
|
||||
map.put("networkInfo", subMap);
|
||||
DataChangeService.getInstance().publishEvent(new OutgoingUIEvent<>("deviceIpInfo", map));
|
||||
}
|
||||
|
||||
String getPossibleRioAddress(String ip) {
|
||||
try {
|
||||
InetAddress addr = InetAddress.getByName(ip);
|
||||
var address = addr.getAddress();
|
||||
if (address[0] != (byte) (10 & 0xff)) return null;
|
||||
address[3] = (byte) (2 & 0xff);
|
||||
return InetAddress.getByAddress(address).getHostAddress();
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void searchForHost(List<String> list, String hostname) {
|
||||
try {
|
||||
logger.info("Looking up " + hostname);
|
||||
InetAddress testAddr = InetAddress.getByName(hostname);
|
||||
logger.info("Pinging " + hostname);
|
||||
var canContact = testAddr.isReachable(500);
|
||||
if (canContact) {
|
||||
logger.info("Was able to connect to " + hostname);
|
||||
if (!list.contains(hostname)) list.add(hostname);
|
||||
} else {
|
||||
logger.info("Unable to reach " + hostname);
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.scripting;
|
||||
|
||||
public enum ScriptCommandType {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.scripting;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.scripting;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.scripting;
|
||||
|
||||
public enum ScriptEventType {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.scripting;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.util;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.util;
|
||||
|
||||
public class MemoryManager {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.util;
|
||||
|
||||
public class ReflectionUtils {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.util;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.util;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.util;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.util.file;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.util.file;
|
||||
|
||||
import com.fasterxml.jackson.core.json.JsonReadFeature;
|
||||
@@ -33,7 +34,7 @@ import java.nio.file.Path;
|
||||
|
||||
public class JacksonUtils {
|
||||
public static <T> void serialize(Path path, T object) throws IOException {
|
||||
serialize(path, object, false);
|
||||
serialize(path, object, true);
|
||||
}
|
||||
|
||||
public static <T> void serialize(Path path, T object, boolean forceSync) throws IOException {
|
||||
@@ -79,7 +80,7 @@ public class JacksonUtils {
|
||||
|
||||
public static <T> void serialize(Path path, T object, Class<T> ref, StdSerializer<T> serializer)
|
||||
throws IOException {
|
||||
serialize(path, object, ref, serializer, false);
|
||||
serialize(path, object, ref, serializer, true);
|
||||
}
|
||||
|
||||
public static <T> void serialize(
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.util.file;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.util.java;
|
||||
|
||||
public interface TriConsumer<T, U, V> {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.util.math;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -14,9 +14,12 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.util.math;
|
||||
|
||||
import edu.wpi.first.util.WPIUtilJNI;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class MathUtils {
|
||||
MathUtils() {}
|
||||
@@ -63,6 +66,58 @@ public class MathUtils {
|
||||
return (int) Math.floor(map((double) value, inMin, inMax, outMin, outMax) + 0.5);
|
||||
}
|
||||
|
||||
public static long wpiNanoTime() {
|
||||
return microsToNanos(WPIUtilJNI.now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the nTh percentile of a list
|
||||
*
|
||||
* @param list The list to evaluate
|
||||
* @param p The percentile, in [0,100]
|
||||
* @return
|
||||
*/
|
||||
public static double getPercentile(List<Double> list, double p) {
|
||||
if ((p > 100) || (p <= 0)) {
|
||||
throw new IllegalArgumentException("invalid quantile value: " + p);
|
||||
}
|
||||
|
||||
if (list.size() == 0) {
|
||||
return Double.NaN;
|
||||
}
|
||||
if (list.size() == 1) {
|
||||
return list.get(0); // always return single value for n = 1
|
||||
}
|
||||
|
||||
// Sort array. We avoid a third copy here by just creating the
|
||||
// list directly.
|
||||
double[] sorted = new double[list.size()];
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
sorted[i] = list.get(i);
|
||||
}
|
||||
Arrays.sort(sorted);
|
||||
|
||||
return evaluateSorted(sorted, p);
|
||||
}
|
||||
|
||||
private static double evaluateSorted(final double[] sorted, final double p) {
|
||||
double n = sorted.length;
|
||||
double pos = p * (n + 1) / 100;
|
||||
double fpos = Math.floor(pos);
|
||||
int intPos = (int) fpos;
|
||||
double dif = pos - fpos;
|
||||
|
||||
if (pos < 1) {
|
||||
return sorted[0];
|
||||
}
|
||||
if (pos >= n) {
|
||||
return sorted[sorted.length - 1];
|
||||
}
|
||||
double lower = sorted[intPos - 1];
|
||||
double upper = sorted[intPos];
|
||||
return lower + dif * (upper - lower);
|
||||
}
|
||||
|
||||
/**
|
||||
* Linearly interpolates between two values.
|
||||
*
|
||||
@@ -75,8 +130,4 @@ public class MathUtils {
|
||||
public static double lerp(double startValue, double endValue, double t) {
|
||||
return startValue + (endValue - startValue) * t;
|
||||
}
|
||||
|
||||
public static long wpiNanoTime() {
|
||||
return microsToNanos(WPIUtilJNI.now());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.util.numbers;
|
||||
|
||||
import org.opencv.core.Point;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.util.numbers;
|
||||
|
||||
public class IntegerCouple extends NumberCouple<Integer> {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.util.numbers;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.common.util.numbers;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.raspi;
|
||||
|
||||
import java.io.File;
|
||||
@@ -85,7 +86,7 @@ public class PicamJNI {
|
||||
|
||||
public static boolean isSupported() {
|
||||
return libraryLoaded
|
||||
&& !isVCSMSupported()
|
||||
&& isVCSMSupported()
|
||||
&& getSensorModel() != SensorModel.Disconnected
|
||||
&& Platform.isRaspberryPi()
|
||||
&& (Platform.currentPiVersion == PiVersion.PI_3
|
||||
@@ -133,12 +134,18 @@ public class PicamJNI {
|
||||
public static native void setThresholds(
|
||||
double hL, double sL, double vL, double hU, double sU, double vU);
|
||||
|
||||
public static native void setInvertHue(boolean shouldInvert);
|
||||
|
||||
public static native boolean setExposure(int exposure);
|
||||
|
||||
public static native boolean setBrightness(int brightness);
|
||||
|
||||
// This adjusts the analog gain (normalized to 0-100); ignores the digital gain
|
||||
public static native boolean setGain(int gain);
|
||||
|
||||
// Adjusts the auto white balance gains, which are normalized 0-100 in the native code
|
||||
public static native boolean setAwbGain(int red, int blue);
|
||||
|
||||
public static native boolean setRotation(int rotation);
|
||||
|
||||
public static native void setShouldCopyColor(boolean shouldCopyColor);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.vision.calibration;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.vision.calibration;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.vision.camera;
|
||||
|
||||
public enum CameraQuirk {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.vision.camera;
|
||||
|
||||
public enum CameraType {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.vision.camera;
|
||||
|
||||
import edu.wpi.first.cscore.VideoMode;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.vision.camera;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.vision.camera;
|
||||
|
||||
import edu.wpi.first.cameraserver.CameraServer;
|
||||
|
||||
@@ -14,9 +14,11 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.vision.camera;
|
||||
|
||||
import edu.wpi.first.cscore.VideoMode;
|
||||
import edu.wpi.first.math.Pair;
|
||||
import java.util.HashMap;
|
||||
import org.photonvision.common.configuration.CameraConfiguration;
|
||||
import org.photonvision.common.configuration.ConfigManager;
|
||||
@@ -83,9 +85,10 @@ public class ZeroCopyPicamSource extends VisionSource {
|
||||
|
||||
public static class PicamSettables extends VisionSourceSettables {
|
||||
private FPSRatedVideoMode currentVideoMode;
|
||||
private double lastExposure;
|
||||
private int lastBrightness;
|
||||
private int lastGain;
|
||||
private double lastExposure = 50;
|
||||
private int lastBrightness = 50;
|
||||
private int lastGain = 50;
|
||||
private Pair<Integer, Integer> lastAwbGains = new Pair(18, 18);
|
||||
|
||||
public PicamSettables(CameraConfiguration configuration) {
|
||||
super(configuration);
|
||||
@@ -117,9 +120,9 @@ public class ZeroCopyPicamSource extends VisionSource {
|
||||
videoModes.put(
|
||||
1, new FPSRatedVideoMode(VideoMode.PixelFormat.kUnknown, 640, 480, 85, 90, 1));
|
||||
videoModes.put(
|
||||
2, new FPSRatedVideoMode(VideoMode.PixelFormat.kUnknown, 960, 720, 45, 60, 1));
|
||||
2, new FPSRatedVideoMode(VideoMode.PixelFormat.kUnknown, 960, 720, 45, 49, 0.74));
|
||||
videoModes.put(
|
||||
3, new FPSRatedVideoMode(VideoMode.PixelFormat.kUnknown, 1280, 720, 30, 45, 0.92));
|
||||
3, new FPSRatedVideoMode(VideoMode.PixelFormat.kUnknown, 1280, 720, 30, 45, 0.91));
|
||||
videoModes.put(
|
||||
4, new FPSRatedVideoMode(VideoMode.PixelFormat.kUnknown, 1920, 1080, 15, 20, 0.72));
|
||||
}
|
||||
@@ -136,21 +139,38 @@ public class ZeroCopyPicamSource extends VisionSource {
|
||||
public void setExposure(double exposure) {
|
||||
lastExposure = exposure;
|
||||
var failure = PicamJNI.setExposure((int) Math.round(exposure));
|
||||
if (failure) logger.warn("Couldn't set Pi camera exposure");
|
||||
if (failure) logger.warn("Couldn't set Pi Camera exposure");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBrightness(int brightness) {
|
||||
lastBrightness = brightness;
|
||||
var failure = PicamJNI.setBrightness(brightness);
|
||||
if (failure) logger.warn("Couldn't set Pi camera brightness");
|
||||
if (failure) logger.warn("Couldn't set Pi Camera brightness");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGain(int gain) {
|
||||
lastGain = gain;
|
||||
var failure = PicamJNI.setGain(gain);
|
||||
if (failure) logger.warn("Couldn't set Pi camera gain");
|
||||
if (failure) logger.warn("Couldn't set Pi Camera gain");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRedGain(int red) {
|
||||
lastAwbGains = Pair.of(red, lastAwbGains.getSecond());
|
||||
setAwbGain(lastAwbGains.getFirst(), lastAwbGains.getSecond());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlueGain(int blue) {
|
||||
lastAwbGains = Pair.of(lastAwbGains.getFirst(), blue);
|
||||
setAwbGain(lastAwbGains.getFirst(), lastAwbGains.getSecond());
|
||||
}
|
||||
|
||||
public void setAwbGain(int red, int blue) {
|
||||
var failure = PicamJNI.setAwbGain(red, blue);
|
||||
if (failure) logger.warn("Couldn't set Pi Camera AWB gains");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -164,17 +184,18 @@ public class ZeroCopyPicamSource extends VisionSource {
|
||||
var failure = PicamJNI.destroyCamera();
|
||||
if (failure)
|
||||
throw new RuntimeException(
|
||||
"Couldn't destroy a zero copy Pi camera while switching video modes");
|
||||
"Couldn't destroy a zero copy Pi Camera while switching video modes");
|
||||
failure = PicamJNI.createCamera(mode.width, mode.height, mode.fpsActual);
|
||||
if (failure)
|
||||
throw new RuntimeException(
|
||||
"Couldn't create a zero copy Pi camera while switching video modes");
|
||||
"Couldn't create a zero copy Pi Camera while switching video modes");
|
||||
|
||||
// We don't store last settings on the native side, and when you change video mode these get
|
||||
// reset on MMAL's end
|
||||
setExposure(lastExposure);
|
||||
setBrightness(lastBrightness);
|
||||
setGain(lastGain);
|
||||
setAwbGain(lastAwbGains.getFirst(), lastAwbGains.getSecond());
|
||||
|
||||
currentVideoMode = mode;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.vision.frame;
|
||||
|
||||
import edu.wpi.first.math.geometry.Rotation2d;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.vision.frame;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.vision.frame;
|
||||
|
||||
public enum FrameDivisor {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.vision.frame;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.vision.frame;
|
||||
|
||||
import edu.wpi.first.cscore.VideoMode;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.vision.frame.consumer;
|
||||
|
||||
import org.photonvision.vision.frame.Frame;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.vision.frame.consumer;
|
||||
|
||||
import edu.wpi.first.networktables.NetworkTable;
|
||||
|
||||
@@ -14,22 +14,95 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.photonvision.vision.frame.consumer;
|
||||
|
||||
import edu.wpi.first.cscore.CameraServerJNI;
|
||||
import edu.wpi.first.cscore.CvSource;
|
||||
import edu.wpi.first.cscore.MjpegServer;
|
||||
import edu.wpi.first.cscore.VideoEvent;
|
||||
import edu.wpi.first.cscore.VideoListener;
|
||||
import edu.wpi.first.cscore.VideoMode;
|
||||
import edu.wpi.first.cscore.*;
|
||||
import edu.wpi.first.networktables.NetworkTable;
|
||||
import edu.wpi.first.networktables.NetworkTableInstance;
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
import org.opencv.core.Size;
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Rect;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.photonvision.common.util.ColorHelper;
|
||||
import org.photonvision.vision.frame.Frame;
|
||||
import org.photonvision.vision.frame.FrameDivisor;
|
||||
|
||||
public class MJPGFrameConsumer {
|
||||
public static final Mat EMPTY_MAT = new Mat(60, 15 * 7, CvType.CV_8UC3);
|
||||
private static final double EMPTY_FRAMERATE = 2;
|
||||
private long lastEmptyTime;
|
||||
|
||||
static {
|
||||
EMPTY_MAT.setTo(ColorHelper.colorToScalar(Color.BLACK));
|
||||
var col = 0;
|
||||
Imgproc.rectangle(
|
||||
EMPTY_MAT,
|
||||
new Rect(col, 0, 15, EMPTY_MAT.height()),
|
||||
ColorHelper.colorToScalar(new Color(0xa2a2a2)),
|
||||
-1);
|
||||
col += 15;
|
||||
Imgproc.rectangle(
|
||||
EMPTY_MAT,
|
||||
new Rect(col, 0, 15, EMPTY_MAT.height()),
|
||||
ColorHelper.colorToScalar(new Color(0xa2a300)),
|
||||
-1);
|
||||
col += 15;
|
||||
Imgproc.rectangle(
|
||||
EMPTY_MAT,
|
||||
new Rect(col, 0, 15, EMPTY_MAT.height()),
|
||||
ColorHelper.colorToScalar(new Color(0x00a3a2)),
|
||||
-1);
|
||||
col += 15;
|
||||
Imgproc.rectangle(
|
||||
EMPTY_MAT,
|
||||
new Rect(col, 0, 15, EMPTY_MAT.height()),
|
||||
ColorHelper.colorToScalar(new Color(0x00a200)),
|
||||
-1);
|
||||
col += 15;
|
||||
Imgproc.rectangle(
|
||||
EMPTY_MAT,
|
||||
new Rect(col, 0, 15, EMPTY_MAT.height()),
|
||||
ColorHelper.colorToScalar(new Color(0x440045)),
|
||||
-1);
|
||||
col += 15;
|
||||
Imgproc.rectangle(
|
||||
EMPTY_MAT,
|
||||
new Rect(col, 0, 15, EMPTY_MAT.height()),
|
||||
ColorHelper.colorToScalar(new Color(0x0000a2)),
|
||||
-1);
|
||||
col += 15;
|
||||
Imgproc.rectangle(
|
||||
EMPTY_MAT,
|
||||
new Rect(col, 0, 15, EMPTY_MAT.height()),
|
||||
ColorHelper.colorToScalar(new Color(0)),
|
||||
-1);
|
||||
Imgproc.rectangle(
|
||||
EMPTY_MAT,
|
||||
new Rect(0, 50, EMPTY_MAT.width(), 10),
|
||||
ColorHelper.colorToScalar(new Color(0)),
|
||||
-1);
|
||||
Imgproc.rectangle(
|
||||
EMPTY_MAT, new Rect(15, 50, 30, 10), ColorHelper.colorToScalar(Color.WHITE), -1);
|
||||
|
||||
Imgproc.putText(
|
||||
EMPTY_MAT, "Stream", new Point(14, 20), 0, 0.6, ColorHelper.colorToScalar(Color.white), 2);
|
||||
Imgproc.putText(
|
||||
EMPTY_MAT,
|
||||
"Disabled",
|
||||
new Point(14, 45),
|
||||
0,
|
||||
0.6,
|
||||
ColorHelper.colorToScalar(Color.white),
|
||||
2);
|
||||
Imgproc.putText(
|
||||
EMPTY_MAT, "Stream", new Point(14, 20), 0, 0.6, ColorHelper.colorToScalar(Color.RED), 1);
|
||||
Imgproc.putText(
|
||||
EMPTY_MAT, "Disabled", new Point(14, 45), 0, 0.6, ColorHelper.colorToScalar(Color.RED), 1);
|
||||
}
|
||||
|
||||
private CvSource cvSource;
|
||||
private MjpegServer mjpegServer;
|
||||
|
||||
@@ -37,6 +110,7 @@ public class MJPGFrameConsumer {
|
||||
private VideoListener listener;
|
||||
|
||||
private final NetworkTable table;
|
||||
boolean isDisabled = false;
|
||||
|
||||
public MJPGFrameConsumer(String sourceName, int width, int height, int port) {
|
||||
this.cvSource = new CvSource(sourceName, VideoMode.PixelFormat.kMJPEG, width, height, 30);
|
||||
@@ -95,11 +169,23 @@ public class MJPGFrameConsumer {
|
||||
public void accept(Frame frame) {
|
||||
if (frame != null && !frame.image.getMat().empty()) {
|
||||
cvSource.putFrame(frame.image.getMat());
|
||||
|
||||
// Make sure our disabled framerate limiting doesn't get confused
|
||||
isDisabled = false;
|
||||
lastEmptyTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private Size getScaledSize(Size orig, FrameDivisor divisor) {
|
||||
return new Size(orig.width / divisor.value, orig.height / divisor.value);
|
||||
public void disabledTick() {
|
||||
if (!isDisabled) {
|
||||
cvSource.setVideoMode(VideoMode.PixelFormat.kMJPEG, EMPTY_MAT.width(), EMPTY_MAT.height(), 0);
|
||||
isDisabled = true;
|
||||
}
|
||||
|
||||
if (System.currentTimeMillis() - lastEmptyTime > 1000.0 / EMPTY_FRAMERATE) {
|
||||
cvSource.putFrame(EMPTY_MAT);
|
||||
lastEmptyTime = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
public int getCurrentStreamPort() {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user