Compare commits

...

21 Commits

Author SHA1 Message Date
Matt
72717cecf0 Disable Roborio finder (#450)
Rio finder has been linked to weird crashes after Autonomous
2022-03-31 22:55:51 -04:00
Matt
971ff3ac40 Calculate aspect ratio using rotated rect (#447) 2022-03-31 22:51:14 -04:00
Banks T
b80e436f02 Force fs sync on all .json writes (#451) 2022-03-31 22:46:12 -04:00
Matt
be1a053cbe Fix PhotoVersion template typo (#446) 2022-03-16 21:39:02 -07:00
Matt
f4555dc545 Fix offset point bug (#445)
Fixes bug where offset point can be wrong
2022-03-16 21:38:47 -07:00
Matt
54fdd1db51 Add test mode from path (#440)
adds --path to --test-mode
2022-03-16 21:33:20 -07:00
Matt
1805785cc6 Rio discovery slowdown (#444)
* Only send rio IPs on settings button click

* Wpiformat
2022-03-14 20:44:14 -07:00
Matt
e62f6419b5 Move config saving to its own thread (#438)
* Move config saving to its own thread

RIO discovery can block

* Add sleep
2022-03-01 00:11:30 -05:00
Declan
fa7824c616 Fix 960x720 weirdness (#439)
* Update 960x720 FOV modifier to track video mode change

* Update native code to version that includes 960x720 fix
2022-02-28 07:42:26 -05:00
Matt
9090aa6bcc Add version verification disable switch in photonlib (#437) 2022-02-28 07:37:52 -05:00
Declan
5655ca6890 Separate AWB gain slider (#410)
Makes gain adjust digital gain, adds sliders for red/blue on picam

Co-authored-by: Chris Gerth <chrisgerth010592@gmail.com>
2022-02-28 00:45:29 -05:00
Matt
50fdfd8bce Add outlier rejection (#432)
Uses standard deviations from mean x/y location to reject outliers
2022-02-28 00:44:22 -05:00
Declan
3120a6439b Handle average hue inverted (#431)
Co-authored-by: Chris Gerth <chrisgerth010592@gmail.com>
2022-02-27 00:09:44 -05:00
Jason Daming
ab3e8c8db7 Add version string to NT in sim (#424) 2022-02-22 20:01:01 -05:00
Banks T
5144819ce2 Invertable hue (#428)
* Add UI-side changes for invertable hue slider

* Add hue inverted range

* Add new slider backgrounds to threshold tab

* Run spotless

* Updated libpicam.so to artifact built from commit c458bab87740 in that repo on gerth2's pi.

* undo the java-side hack since isVCSMSupported is fixed

* Hook up hue inversion frontend to backend and UI tweaks

* Remove unused .flipped class

* Fix hueInverted name in Vue.js store

Co-authored-by: Declan Freeman-Gleason <declanfreemangleason@gmail.com>
Co-authored-by: Matt <matthew.morley.ca@gmail.com>
Co-authored-by: Chris Gerth <chrisgerth010592@gmail.com>
2022-02-21 22:41:51 -05:00
Matt
d779fe23f0 Add disabled stream warning (#409) 2022-01-24 12:39:04 -05:00
Matt
b2a3f34433 Fix version verification with non-default networktable (#407)
Adds version verification to c++ too
2022-01-24 12:38:45 -05:00
drew-struensee
b09a6d6a2d Added Support for 3D tracking of the 2022 Cargo Balls (#408)
* added cargo ball 2022

* added cargoball2022. tested on pi.. it works

* spotlessapply

* made list more consistant
2022-01-20 22:36:54 -05:00
Tyler Veness
9893cf1f7e Update photonlib and photonlib example license headers to MIT (#395) 2022-01-20 22:35:28 -05:00
Matt
fc91daf397 Enable GPU acecel on any Pi Zeros, not just zero W (#405) 2022-01-20 21:59:29 -05:00
Matt
a3e205cb6f Limit circle accuracy to [1,100] (#406) 2022-01-20 21:57:41 -05:00
278 changed files with 2407 additions and 916 deletions

1
.gitignore vendored
View File

@@ -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

View File

@@ -25,7 +25,3 @@ includeOtherLibs {
^units/
^wpi/
}
licenseUpdateExclude {
\.java$
}

View File

@@ -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/>.
*/

View File

@@ -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")
}

View File

@@ -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"
/>

View File

@@ -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,

View File

@@ -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,

View File

@@ -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;

View File

@@ -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>

View File

@@ -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

View File

@@ -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: {

View File

@@ -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: ""

View File

@@ -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>

View File

@@ -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>

View File

@@ -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)
}

View 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;
public enum ProgramStatus {

View 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.configuration;
import com.fasterxml.jackson.annotation.JsonCreator;

View 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.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();
}
}

View 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.configuration;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

View 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.configuration;
public class HardwareSettings {

View 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.configuration;
import com.fasterxml.jackson.annotation.JsonCreator;

View 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.configuration;
import java.util.Collection;

View 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.dataflow;
import java.util.function.Consumer;

View 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.dataflow;
import java.util.ArrayList;

View 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.dataflow;
import java.util.concurrent.BlockingQueue;

View 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.dataflow;
import java.util.ArrayList;

View 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.dataflow;
import java.util.List;

View 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.dataflow.events;
import org.photonvision.common.dataflow.DataChangeDestination;

View 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.dataflow.events;
import org.photonvision.common.dataflow.DataChangeDestination;

View 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.dataflow.events;
import io.javalin.websocket.WsContext;

View 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.dataflow.events;
import io.javalin.websocket.WsContext;

View 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.dataflow.networktables;
import edu.wpi.first.networktables.EntryListenerFlags;

View 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.dataflow.networktables;
import edu.wpi.first.networktables.EntryNotification;

View File

@@ -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() {

View 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.dataflow.websocket;
import java.util.ArrayList;

View 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.hardware.GPIO;
import org.photonvision.common.configuration.HardwareConfig;

View 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.hardware.GPIO;
import java.util.Arrays;

View 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.hardware.GPIO.pi;
@SuppressWarnings("SpellCheckingInspection")

View 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.hardware.GPIO.pi;
import java.util.HashMap;

View 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.hardware.GPIO.pi;
import static org.photonvision.common.hardware.GPIO.pi.PigpioException.*;

View 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.hardware.GPIO.pi;
public class PigpioPulse {

View 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.hardware.GPIO.pi;
import static org.photonvision.common.hardware.GPIO.pi.PigpioException.*;

View 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.hardware.GPIO.pi;
import java.io.DataInputStream;

View 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.hardware;
import edu.wpi.first.networktables.NetworkTableEntry;

View File

@@ -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"),

View 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.hardware;
import edu.wpi.first.util.RuntimeDetector;

View 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.hardware;
import java.util.List;

View 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.hardware;
import edu.wpi.first.networktables.EntryNotification;

View 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.hardware.metrics;
public class CPUMetrics extends MetricsBase {

View 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.hardware.metrics;
public class DiskMetrics extends MetricsBase {

View 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.hardware.metrics;
public class GPUMetrics extends MetricsBase {

View 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.hardware.metrics;
import java.io.PrintWriter;

View 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.hardware.metrics;
import java.util.HashMap;

View 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.hardware.metrics;
public class RAMMetrics extends MetricsBase {

View 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.logging;
public enum LogGroup {

View 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.logging;
public enum LogLevel {

View 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.logging;
import java.io.*;

View 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.networking;
import java.net.InterfaceAddress;

View 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.networking;
import org.photonvision.common.configuration.ConfigManager;

View 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.networking;
public enum NetworkMode {

View File

@@ -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) {
}
}
}

View 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.scripting;
public enum ScriptCommandType {

View 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.scripting;
import com.fasterxml.jackson.annotation.JsonCreator;

View 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.scripting;
import java.io.IOException;

View 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.scripting;
public enum ScriptEventType {

View 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.scripting;
import java.io.IOException;

View 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;
import java.awt.*;

View 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;
public class MemoryManager {

View 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;
public class ReflectionUtils {

View 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;
import java.util.HashMap;

View 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;
import java.io.*;

View 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;
import com.fasterxml.jackson.databind.ObjectMapper;

View 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;
import java.util.concurrent.*;

View 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 java.io.File;

View 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(

View 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 java.io.File;

View 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> {

View 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.math;
import java.util.ArrayList;

View File

@@ -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());
}
}

View 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.numbers;
import org.opencv.core.Point;

View 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.numbers;
public class IntegerCouple extends NumberCouple<Integer> {

View 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.numbers;
import com.fasterxml.jackson.annotation.JsonIgnore;

View 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.numbers;
import java.math.BigDecimal;

View 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.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);

View 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.vision.calibration;
import com.fasterxml.jackson.annotation.JsonCreator;

View 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.vision.calibration;
import com.fasterxml.jackson.annotation.JsonIgnore;

View 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.vision.camera;
public enum CameraQuirk {

View 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.vision.camera;
public enum CameraType {

View 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.vision.camera;
import edu.wpi.first.cscore.VideoMode;

View 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.vision.camera;
import java.util.HashMap;

View 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.vision.camera;
import edu.wpi.first.cameraserver.CameraServer;

View File

@@ -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;
}

View 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.vision.frame;
import edu.wpi.first.math.geometry.Rotation2d;

View 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.vision.frame;
import java.util.function.Consumer;

View 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.vision.frame;
public enum FrameDivisor {

View 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.vision.frame;
import java.util.function.Supplier;

View 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.vision.frame;
import edu.wpi.first.cscore.VideoMode;

View 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.vision.frame.consumer;
import org.photonvision.vision.frame.Frame;

View 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.vision.frame.consumer;
import edu.wpi.first.networktables.NetworkTable;

View File

@@ -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