Skip to content

Commit

Permalink
Merge branch 'master' into 2023-12-28_pi-image-modifier
Browse files Browse the repository at this point in the history
  • Loading branch information
srimanachanta committed Jan 1, 2024
2 parents 1a6a017 + a9f1e50 commit ed7a3ae
Show file tree
Hide file tree
Showing 46 changed files with 1,716 additions and 69 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ plugins {
id "edu.wpi.first.wpilib.repositories.WPILibRepositoriesPlugin" version "2020.2"
id "edu.wpi.first.GradleRIO" version "2024.1.1-beta-4"
id 'edu.wpi.first.WpilibTools' version '1.3.0'
id 'com.google.protobuf' version '0.9.4' apply false
}

allprojects {
Expand Down
88 changes: 63 additions & 25 deletions photon-client/src/components/settings/NetworkingCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import PvInput from "@/components/common/pv-input.vue";
import PvRadio from "@/components/common/pv-radio.vue";
import PvSwitch from "@/components/common/pv-switch.vue";
import PvSelect from "@/components/common/pv-select.vue";
import { NetworkConnectionType } from "@/types/SettingTypes";
import { NetworkConnectionType, type NetworkSettings } from "@/types/SettingTypes";
import { useStateStore } from "@/stores/StateStore";
const settingsValid = ref(true);
// Copy object to remove reference to store
const tempSettingsStruct = ref<NetworkSettings>(Object.assign({}, useSettingsStore().network));
const isValidNetworkTablesIP = (v: string | undefined): boolean => {
// Check if it is a valid team number between 1-9999
const teamNumberRegex = /^[1-9][0-9]{0,3}$/;
Expand Down Expand Up @@ -38,9 +40,31 @@ const isValidHostname = (v: string | undefined) => {
return hostnameRegex.test(v);
};
const settingsHaveChanged = (): boolean => {
const a = useSettingsStore().network;
const b = tempSettingsStruct.value;
return (
a.ntServerAddress !== b.ntServerAddress ||
a.connectionType !== b.connectionType ||
a.staticIp !== b.staticIp ||
a.hostname !== b.hostname ||
a.runNTServer !== b.runNTServer ||
a.shouldManage !== b.shouldManage ||
a.shouldPublishProto !== b.shouldPublishProto ||
a.canManage !== b.canManage ||
a.networkManagerIface !== b.networkManagerIface ||
a.setStaticCommand !== b.setStaticCommand ||
a.setDHCPcommand !== b.setDHCPcommand
);
};
const saveGeneralSettings = () => {
const changingStaticIp = useSettingsStore().network.connectionType === NetworkConnectionType.Static;
// Update with new values
Object.assign(useSettingsStore().network, tempSettingsStruct.value);
useSettingsStore()
.saveGeneralSettings()
.then((response) => {
Expand Down Expand Up @@ -80,7 +104,7 @@ const saveGeneralSettings = () => {
const currentNetworkInterfaceIndex = computed<number>({
get: () => useSettingsStore().networkInterfaceNames.indexOf(useSettingsStore().network.networkManagerIface || ""),
set: (v) => (useSettingsStore().network.networkManagerIface = useSettingsStore().networkInterfaceNames[v])
set: (v) => (tempSettingsStruct.value.networkManagerIface = useSettingsStore().networkInterfaceNames[v])
});
</script>

Expand All @@ -90,22 +114,19 @@ const currentNetworkInterfaceIndex = computed<number>({
<div class="ml-5">
<v-form ref="form" v-model="settingsValid">
<pv-input
v-model="useSettingsStore().network.ntServerAddress"
v-model="tempSettingsStruct.ntServerAddress"
label="Team Number/NetworkTables Server Address"
tooltip="Enter the Team Number or the IP address of the NetworkTables Server"
:label-cols="4"
:disabled="useSettingsStore().network.runNTServer"
:disabled="tempSettingsStruct.runNTServer"
:rules="[
(v) =>
isValidNetworkTablesIP(v) ||
'The NetworkTables Server Address must be a valid Team Number, IP address, or Hostname'
]"
/>
<v-banner
v-show="
!isValidNetworkTablesIP(useSettingsStore().network.ntServerAddress) &&
!useSettingsStore().network.runNTServer
"
v-show="!isValidNetworkTablesIP(tempSettingsStruct.ntServerAddress) && !tempSettingsStruct.runNTServer"
rounded
color="red"
text-color="white"
Expand All @@ -115,33 +136,33 @@ const currentNetworkInterfaceIndex = computed<number>({
The NetworkTables Server Address is not set or is invalid. NetworkTables is unable to connect.
</v-banner>
<pv-radio
v-model="useSettingsStore().network.connectionType"
v-model="tempSettingsStruct.connectionType"
label="IP Assignment Mode"
tooltip="DHCP will make the radio (router) automatically assign an IP address; this may result in an IP address that changes across reboots. Static IP assignment means that you pick the IP address and it won't change."
:input-cols="12 - 4"
:list="['DHCP', 'Static']"
:disabled="!(useSettingsStore().network.shouldManage && useSettingsStore().network.canManage)"
:disabled="!(tempSettingsStruct.shouldManage && tempSettingsStruct.canManage)"
/>
<pv-input
v-if="useSettingsStore().network.connectionType === NetworkConnectionType.Static"
v-model="useSettingsStore().network.staticIp"
v-if="tempSettingsStruct.connectionType === NetworkConnectionType.Static"
v-model="tempSettingsStruct.staticIp"
:input-cols="12 - 4"
label="Static IP"
:rules="[(v) => isValidIPv4(v) || 'Invalid IPv4 address']"
:disabled="!(useSettingsStore().network.shouldManage && useSettingsStore().network.canManage)"
:disabled="!(tempSettingsStruct.shouldManage && tempSettingsStruct.canManage)"
/>
<pv-input
v-model="useSettingsStore().network.hostname"
v-model="tempSettingsStruct.hostname"
label="Hostname"
:input-cols="12 - 4"
:rules="[(v) => isValidHostname(v) || 'Invalid hostname']"
:disabled="!(useSettingsStore().network.shouldManage && useSettingsStore().network.canManage)"
:disabled="!(tempSettingsStruct.shouldManage && tempSettingsStruct.canManage)"
/>
<v-divider class="pb-3" />
<span style="font-weight: 700">Advanced Networking</span>
<pv-switch
v-model="useSettingsStore().network.shouldManage"
:disabled="!useSettingsStore().network.canManage"
v-model="tempSettingsStruct.shouldManage"
:disabled="!tempSettingsStruct.canManage"
label="Manage Device Networking"
tooltip="If enabled, Photon will manage device hostname and network settings."
:label-cols="4"
Expand All @@ -150,16 +171,16 @@ const currentNetworkInterfaceIndex = computed<number>({
<pv-select
v-model="currentNetworkInterfaceIndex"
label="NetworkManager interface"
:disabled="!(useSettingsStore().network.shouldManage && useSettingsStore().network.canManage)"
:disabled="!(tempSettingsStruct.shouldManage && tempSettingsStruct.canManage)"
:select-cols="12 - 4"
tooltip="Name of the interface PhotonVision should manage the IP address of"
:items="useSettingsStore().networkInterfaceNames"
/>
<v-banner
v-show="
!useSettingsStore().networkInterfaceNames.length &&
useSettingsStore().network.shouldManage &&
useSettingsStore().network.canManage
tempSettingsStruct.shouldManage &&
tempSettingsStruct.canManage
"
rounded
color="red"
Expand All @@ -169,27 +190,44 @@ const currentNetworkInterfaceIndex = computed<number>({
Photon cannot detect any wired connections! Please send program logs to the developers for help.
</v-banner>
<pv-switch
v-model="useSettingsStore().network.runNTServer"
v-model="tempSettingsStruct.runNTServer"
label="Run NetworkTables Server (Debugging Only)"
tooltip="If enabled, this device will create a NT server. This is useful for home debugging, but should be disabled on-robot."
class="mt-3 mb-3"
class="mt-3 mb-2"
:label-cols="4"
/>
<v-banner
v-show="useSettingsStore().network.runNTServer"
v-show="tempSettingsStruct.runNTServer"
rounded
color="red"
text-color="white"
icon="mdi-information-outline"
>
This mode is intended for debugging; it should be off for proper usage. PhotonLib will NOT work!
</v-banner>
<pv-switch
v-model="tempSettingsStruct.shouldPublishProto"
label="Also Publish Protobuf"
tooltip="If enabled, Photon will publish all pipeline results in both the Packet and Protobuf formats. This is useful for visualizing pipeline results from NT viewers such as glass and logging software such as AdvantageScope. Note: photon-lib will ignore this value and is not recommended on the field for performance."
class="mt-3 mb-2"
:label-cols="4"
/>
<v-banner
v-show="tempSettingsStruct.shouldPublishProto"
rounded
color="red"
class="mb-3"
text-color="white"
icon="mdi-information-outline"
>
This mode is intended for debugging; it should be off for field use. You may notice a performance hit by using
this mode.
</v-banner>
</v-form>
<v-btn
color="accent"
:class="useSettingsStore().network.runNTServer ? 'mt-3' : ''"
style="color: black; width: 100%"
:disabled="!settingsValid && !useSettingsStore().network.runNTServer"
:disabled="!settingsValid || !settingsHaveChanged()"
@click="saveGeneralSettings"
>
Save
Expand Down
2 changes: 2 additions & 0 deletions photon-client/src/stores/settings/GeneralSettingsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export const useSettingsStore = defineStore("settings", {
staticIp: "",
hostname: "photonvision",
runNTServer: false,
shouldPublishProto: false,
networkInterfaceNames: [
{
connName: "Example Wired Connection",
Expand Down Expand Up @@ -112,6 +113,7 @@ export const useSettingsStore = defineStore("settings", {
setDHCPcommand: this.network.setDHCPcommand || "",
setStaticCommand: this.network.setStaticCommand || "",
shouldManage: this.network.shouldManage,
shouldPublishProto: this.network.shouldPublishProto,
staticIp: this.network.staticIp
};
return axios.post("/settings/general", payload);
Expand Down
1 change: 1 addition & 0 deletions photon-client/src/types/SettingTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export interface NetworkSettings {
hostname: string;
runNTServer: boolean;
shouldManage: boolean;
shouldPublishProto: boolean;
canManage: boolean;
networkManagerIface?: string;
setStaticCommand?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public class NetworkConfig {
public String hostname = "photonvision";
public boolean runNTServer = false;
public boolean shouldManage;
public boolean shouldPublishProto = false;

@JsonIgnore public static final String NM_IFACE_STRING = "${interface}";
@JsonIgnore public static final String NM_IP_STRING = "${ipaddr}";
Expand Down Expand Up @@ -72,6 +73,7 @@ public NetworkConfig(
@JsonProperty("hostname") String hostname,
@JsonProperty("runNTServer") boolean runNTServer,
@JsonProperty("shouldManage") boolean shouldManage,
@JsonProperty("shouldPublishProto") boolean shouldPublishProto,
@JsonProperty("networkManagerIface") String networkManagerIface,
@JsonProperty("setStaticCommand") String setStaticCommand,
@JsonProperty("setDHCPcommand") String setDHCPcommand) {
Expand All @@ -80,6 +82,7 @@ public NetworkConfig(
this.staticIp = staticIp;
this.hostname = hostname;
this.runNTServer = runNTServer;
this.shouldPublishProto = shouldPublishProto;
this.networkManagerIface = networkManagerIface;
this.setStaticCommand = setStaticCommand;
this.setDHCPcommand = setDHCPcommand;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.photonvision.common.configuration.ConfigManager;
import org.photonvision.common.dataflow.CVPipelineResultConsumer;
import org.photonvision.common.logging.LogGroup;
import org.photonvision.common.logging.Logger;
Expand Down Expand Up @@ -135,6 +136,9 @@ public void accept(CVPipelineResult result) {
result.multiTagResult);

ts.resultPublisher.accept(simplified, simplified.getPacketSize());
if (ConfigManager.getInstance().getConfig().getNetworkConfig().shouldPublishProto) {
ts.protoResultPublisher.set(simplified);
}

ts.pipelineIndexPublisher.set(pipelineIndexSupplier.get());
ts.driverModePublisher.set(driverModeSupplier.getAsBoolean());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,15 @@
import java.util.List;
import org.apache.commons.lang3.tuple.Pair;
import org.photonvision.common.util.math.MathUtils;
import org.photonvision.raspi.LibCameraJNI;
import org.photonvision.vision.camera.CameraQuirk;
import org.photonvision.vision.frame.Frame;
import org.photonvision.vision.frame.FrameThresholdType;
import org.photonvision.vision.pipe.impl.CalculateFPSPipe;
import org.photonvision.vision.pipe.impl.Draw2dCrosshairPipe;
import org.photonvision.vision.pipe.impl.ResizeImagePipe;
import org.photonvision.vision.pipe.impl.RotateImagePipe;
import org.photonvision.vision.pipeline.result.DriverModePipelineResult;

public class DriverModePipeline
extends CVPipeline<DriverModePipelineResult, DriverModePipelineSettings> {
private final RotateImagePipe rotateImagePipe = new RotateImagePipe();
private final Draw2dCrosshairPipe draw2dCrosshairPipe = new Draw2dCrosshairPipe();
private final CalculateFPSPipe calculateFPSPipe = new CalculateFPSPipe();
private final ResizeImagePipe resizeImagePipe = new ResizeImagePipe();
Expand All @@ -51,10 +47,6 @@ public DriverModePipeline(DriverModePipelineSettings settings) {

@Override
protected void setPipeParamsImpl() {
RotateImagePipe.RotateImageParams rotateImageParams =
new RotateImagePipe.RotateImageParams(settings.inputImageRotationMode);
rotateImagePipe.setParams(rotateImageParams);

Draw2dCrosshairPipe.Draw2dCrosshairParams draw2dCrosshairParams =
new Draw2dCrosshairPipe.Draw2dCrosshairParams(
frameStaticProperties, settings.streamingFrameDivisor, settings.inputImageRotationMode);
Expand All @@ -72,19 +64,13 @@ protected void setPipeParamsImpl() {
@Override
public DriverModePipelineResult process(Frame frame, DriverModePipelineSettings settings) {
long totalNanos = 0;
boolean accelerated = LibCameraJNI.isSupported() && cameraQuirks.hasQuirk(CameraQuirk.PiCam);

// apply pipes
var inputMat = frame.colorImage.getMat();

boolean emptyIn = inputMat.empty();

if (!emptyIn) {
if (!accelerated) {
var rotateImageResult = rotateImagePipe.run(inputMat);
totalNanos += rotateImageResult.nanosElapsed;
}

totalNanos += resizeImagePipe.run(inputMat).nanosElapsed;

var draw2dCrosshairResult = draw2dCrosshairPipe.run(Pair.of(inputMat, List.of()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ private void update() {
// (pipeline-dependent). I kinda hate how much leak this has...
// TODO would a callback object be a better fit?
var wantedProcessType = pipeline.getThresholdType();

frameSupplier.requestFrameThresholdType(wantedProcessType);
var settings = pipeline.getSettings();
if (settings instanceof AdvancedPipelineSettings) {
Expand Down
29 changes: 29 additions & 0 deletions photon-lib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,35 @@ task writeCurrentVersion {
}

build.mustRunAfter writeCurrentVersion
cppHeadersZip.dependsOn writeCurrentVersion

// Building photon-lib requires photon-targeting to generate its proto files. This technically shouldn't be required but is needed for it to build.
model {
components {
all {
it.sources.each {
it.exportedHeaders {
srcDirs "src/main/native/include"
srcDirs "src/generate/native/include"
}
}
it.binaries.all {
it.tasks.withType(CppCompile) {
it.dependsOn ":photon-targeting:generateProto"
}
}
}
}
testSuites {
all {
it.binaries.all {
it.tasks.withType(CppCompile) {
it.dependsOn ":photon-targeting:generateProto"
}
}
}
}
}

def vendorJson = artifacts.add('archives', file("$photonlibFileOutput"))

Expand Down
Loading

0 comments on commit ed7a3ae

Please sign in to comment.