Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
use nix
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,6 @@ node_modules
dist
components.d.ts
photon-server/src/main/resources/web/index.html

# Direnv
.direnv
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true,
"python.testing.cwd": "photon-lib/py"
"python.testing.cwd": "photon-lib/py",
"java.configuration.updateBuildConfiguration": "interactive"
}
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ ext {
libcameraDriverVersion = "v2025.0.4"
rknnVersion = "dev-v2025.0.0-5-g666c0c6"
rubikVersion = "dev-v2025.1.0-8-g067a316"
baslerVersion = "local"
frcYear = "2025"
mrcalVersion = "v2025.0.0";

Expand Down
4 changes: 4 additions & 0 deletions photon-client/src/components/common/pv-camera-info-card.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ const cameraInfoFor: any = (camera: PVCameraInfo) => {
if (camera.PVFileCameraInfo) {
return camera.PVFileCameraInfo;
}
if (camera.PVBaslerCameraInfo) {
return camera.PVBaslerCameraInfo;
}
return {};
};
</script>
Expand All @@ -39,6 +42,7 @@ const cameraInfoFor: any = (camera: PVCameraInfo) => {
<td v-if="camera.PVUsbCameraInfo" class="mb-3">USB Camera</td>
<td v-else-if="camera.PVCSICameraInfo" class="mb-3">CSI Camera</td>
<td v-else-if="camera.PVFileCameraInfo" class="mb-3">File Camera</td>
<td v-else-if="camera.PVBaslerCameraInfo" class="mb-3">Basler Camera</td>
<td v-else>Unidentified Camera Type</td>
</tr>
<tr v-if="cameraInfoFor(camera).baseName !== undefined && cameraInfoFor(camera).baseName !== null">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ const cameraInfoFor = (camera: PVCameraInfo): any => {
if (camera.PVFileCameraInfo) {
return camera.PVFileCameraInfo;
}
if (camera.PVBaslerCameraInfo) {
return camera.PVBaslerCameraInfo;
}
return {};
};
</script>
Expand Down Expand Up @@ -78,10 +81,12 @@ const cameraInfoFor = (camera: PVCameraInfo): any => {
<td v-if="saved.PVUsbCameraInfo" class="mb-3">USB Camera</td>
<td v-else-if="saved.PVCSICameraInfo" class="mb-3">CSI Camera</td>
<td v-else-if="saved.PVFileCameraInfo" class="mb-3">File Camera</td>
<td v-else-if="saved.PVBaslerCameraInfo" class="mb-3">Basler Camera</td>
<td v-else>Unidentified Camera Type</td>
<td v-if="current.PVUsbCameraInfo" class="mb-3">USB Camera</td>
<td v-else-if="current.PVCSICameraInfo" class="mb-3">CSI Camera</td>
<td v-else-if="current.PVFileCameraInfo" class="mb-3">File Camera</td>
<td v-else-if="current.PVBaslerCameraInfo" class="mb-3">Basler Camera</td>
<td v-else>Unidentified Camera Type</td>
</tr>
<tr
Expand Down
31 changes: 23 additions & 8 deletions photon-client/src/components/dashboard/tabs/InputTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import PvSelect from "@/components/common/pv-select.vue";
import { computed } from "vue";
import { useSettingsStore } from "@/stores/settings/GeneralSettingsStore";
import { useStateStore } from "@/stores/StateStore";
import { getResolutionString } from "@/lib/PhotonUtils";
import { getBinningString, getResolutionString } from "@/lib/PhotonUtils";
import { useDisplay } from "vuetify";

// Due to something with libcamera or something else IDK much about, the 90° rotations need to be disabled if the libcamera drivers are being used.
Expand All @@ -31,9 +31,9 @@ const getFilteredStreamDivisors = (): number[] => {
const getNumberOfSkippedDivisors = () => streamDivisors.length - getFilteredStreamDivisors().length;

const cameraResolutions = computed(() =>
useCameraSettingsStore().currentCameraSettings.validVideoFormats.map(
(f) => `${getResolutionString(f.resolution)} at ${f.fps} FPS, ${f.pixelFormat}`
)
useCameraSettingsStore().currentCameraSettings.validVideoFormats.map((f) => {
return `${getResolutionString(f.resolution)} at ${f.fps} FPS, ${f.pixelFormat}${getBinningString(f.binning)}`;
})
);
const handleResolutionChange = (value: number) => {
useCameraSettingsStore().changeCurrentPipelineSetting({ cameraVideoModeIndex: value }, false);
Expand Down Expand Up @@ -116,24 +116,38 @@ const interactiveCols = computed(() =>
/>
<pv-slider
v-if="useCameraSettingsStore().currentPipelineSettings.cameraRedGain !== -1"
:disabled="
useCameraSettingsStore().currentPipelineSettings.cameraWhiteBalanceTemp === -1 &&
useCameraSettingsStore().currentCameraSettings.pipelineSettings.cameraAutoWhiteBalance
"
v-model="useCameraSettingsStore().currentPipelineSettings.cameraRedGain"
label="Red AWB Gain"
:label="
useCameraSettingsStore().currentPipelineSettings.cameraWhiteBalanceTemp !== -1 ? 'Red AWB Gain' : 'Red Gain'
"
:min="0"
:max="100"
:slider-cols="interactiveCols"
tooltip="Controls red automatic white balance gain, which affects how the camera captures colors in different conditions"
tooltip="Controls red white balance gain, which affects how the camera captures colors in different conditions"
@update:modelValue="
(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraRedGain: args }, false)
"
/>
<pv-slider
v-if="useCameraSettingsStore().currentPipelineSettings.cameraBlueGain !== -1"
:disabled="(() => {
const temp = useCameraSettingsStore().currentPipelineSettings.cameraWhiteBalanceTemp;
const autoWB = useCameraSettingsStore().currentCameraSettings.pipelineSettings.cameraAutoWhiteBalance;
console.log('Blue Gain - temp:', temp, 'autoWB:', autoWB, 'disabled:', temp === -1 && autoWB);
return temp === -1 && autoWB;
})()"
v-model="useCameraSettingsStore().currentPipelineSettings.cameraBlueGain"
label="Blue AWB Gain"
:label="
useCameraSettingsStore().currentPipelineSettings.cameraWhiteBalanceTemp !== -1 ? 'Blue AWB Gain' : 'Blue Gain'
"
:min="0"
:max="100"
:slider-cols="interactiveCols"
tooltip="Controls blue automatic white balance gain, which affects how the camera captures colors in different conditions"
tooltip="Controls blue white balance gain, which affects how the camera captures colors in different conditions"
@update:modelValue="
(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraBlueGain: args }, false)
"
Expand All @@ -148,6 +162,7 @@ const interactiveCols = computed(() =>
"
/>
<pv-slider
v-if="useCameraSettingsStore().currentPipelineSettings.cameraWhiteBalanceTemp !== -1"
v-model="useCameraSettingsStore().currentPipelineSettings.cameraWhiteBalanceTemp"
:disabled="useCameraSettingsStore().currentPipelineSettings.cameraAutoWhiteBalance"
label="White Balance Temperature"
Expand Down
5 changes: 4 additions & 1 deletion photon-client/src/lib/PhotonUtils.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import type { Resolution } from "@/types/SettingTypes";
import type { BinningConfig, Resolution } from "@/types/SettingTypes";

export const resolutionsAreEqual = (a: Resolution, b: Resolution) => {
return a.height === b.height && a.width === b.width;
};

export const getResolutionString = (resolution: Resolution): string => `${resolution.width}x${resolution.height}`;

export const getBinningString = (binning?: BinningConfig): string =>
binning != null && binning.mode !== "NONE" ? ` ${binning.mode} ${binning.horz}x${binning.vert}` : "";

export const parseJsonFile = async <T extends Record<string, any>>(file: File): Promise<T> => {
return new Promise((resolve, reject) => {
const fileReader = new FileReader();
Expand Down
13 changes: 12 additions & 1 deletion photon-client/src/stores/settings/CameraSettingsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
actions: {
updateCameraSettingsFromWebsocket(data: WebsocketCameraSettingsUpdate[]) {
const configuredCameras = data.reduce<{ [key: string]: UiCameraConfiguration }>((acc, d) => {
console.log("Bmode: " + d.videoFormatList[0].binningMode);
acc[d.uniqueName] = {
cameraPath: d.cameraPath,
nickname: d.nickname,
Expand Down Expand Up @@ -128,7 +129,16 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
horizontalFOV: v.horizontalFOV,
verticalFOV: v.verticalFOV,
standardDeviation: v.standardDeviation,
mean: v.mean
mean: v.mean,
...(v.binningMode !== undefined &&
v.binningHorz !== undefined &&
v.binningVert !== undefined && {
binning: {
mode: v.binningMode,
horz: v.binningHorz,
vert: v.binningVert
}
})
})),
completeCalibrations: d.calibrations,
isCSICamera: d.isCSICamera,
Expand All @@ -145,6 +155,7 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
hasConnected: d.hasConnected,
mismatch: d.mismatch
};

return acc;
}, {});
this.cameras =
Expand Down
28 changes: 24 additions & 4 deletions photon-client/src/types/SettingTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export interface PVCameraInfoBase {
Huge hack. In Jackson, this is set based on the underlying type -- this
then maps to one of the 3 subclasses here below. Not sure how to best deal with this.
*/
cameraTypename: "PVUsbCameraInfo" | "PVCSICameraInfo" | "PVFileCameraInfo";
cameraTypename: "PVUsbCameraInfo" | "PVCSICameraInfo" | "PVFileCameraInfo" | "PVBaslerCameraInfo";
}

export interface PVUsbCameraInfo {
Expand Down Expand Up @@ -103,11 +103,19 @@ export interface PVFileCameraInfo {
uniquePath: string;
}

export interface PVBaslerCameraInfo {
serial: string;
model: string;

uniquePath: string;
}

// This camera info will only ever hold one of its members - the others should be undefined.
export class PVCameraInfo {
PVUsbCameraInfo: PVUsbCameraInfo | undefined;
PVCSICameraInfo: PVCSICameraInfo | undefined;
PVFileCameraInfo: PVFileCameraInfo | undefined;
PVBaslerCameraInfo: PVBaslerCameraInfo | undefined;
}

export interface VsmState {
Expand Down Expand Up @@ -139,10 +147,17 @@ export interface Resolution {
height: number;
}

export interface BinningConfig {
mode: String;
horz: number;
vert: number;
}

export interface VideoFormat {
resolution: Resolution;
fps: number;
pixelFormat: string;
binning?: BinningConfig;
index?: number;
diagonalFOV?: number;
horizontalFOV?: number;
Expand Down Expand Up @@ -220,7 +235,9 @@ export enum ValidQuirks {
PiCam = "PiCam",
StickyFPS = "StickyFPS",
LifeCamControls = "LifeCamControls",
PsEyeControls = "PsEyeControls"
PsEyeControls = "PsEyeControls",
BaslerDaA1280Controls = "BaslerDaA1280Controls",
ManualWB = "ManualWB"
}

export interface QuirkyCamera {
Expand Down Expand Up @@ -371,7 +388,9 @@ export const PlaceholderCameraSettings: UiCameraConfiguration = {
StickyFPS: false,
InnoOV9281Controls: false,
LifeCamControls: false,
PsEyeControls: false
PsEyeControls: false,
BaslerDaA1280Controls: false,
ManualWB: false
}
},
isCSICamera: false,
Expand All @@ -386,7 +405,8 @@ export const PlaceholderCameraSettings: UiCameraConfiguration = {
uniquePath: "/dev/foobar2"
},
PVCSICameraInfo: undefined,
PVUsbCameraInfo: undefined
PVUsbCameraInfo: undefined,
PVBaslerCameraInfo: undefined
},
isConnected: true,
hasConnected: true,
Expand Down
3 changes: 3 additions & 0 deletions photon-client/src/types/WebsocketDataTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ export type WebsocketVideoFormat = Record<
verticalFOV?: number;
standardDeviation?: number;
mean?: number;
binningMode?: String;
binningHorz?: number;
binningVert?: number;
}
>;

Expand Down
13 changes: 10 additions & 3 deletions photon-client/src/views/CameraMatchingView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useStateStore } from "@/stores/StateStore";
import {
PlaceholderCameraSettings,
PVCameraInfo,
type PVBaslerCameraInfo,
type PVCSICameraInfo,
type PVFileCameraInfo,
type PVUsbCameraInfo,
Expand Down Expand Up @@ -221,7 +222,7 @@ const yesDeleteMySettingsText = ref("");
/**
* Get the connection-type-specific camera info from the given PVCameraInfo object.
*/
const cameraInfoFor = (camera: PVCameraInfo | null): PVUsbCameraInfo | PVCSICameraInfo | PVFileCameraInfo | any => {
const cameraInfoFor = (camera: PVCameraInfo | null): PVUsbCameraInfo | PVCSICameraInfo | PVFileCameraInfo | PVBaslerCameraInfo | any => {
if (!camera) return null;
if (camera.PVUsbCameraInfo) {
return camera.PVUsbCameraInfo;
Expand All @@ -232,6 +233,9 @@ const cameraInfoFor = (camera: PVCameraInfo | null): PVUsbCameraInfo | PVCSICame
if (camera.PVFileCameraInfo) {
return camera.PVFileCameraInfo;
}
if (camera.PVBaslerCameraInfo) {
return camera.PVBaslerCameraInfo;
}
return {};
};

Expand All @@ -243,7 +247,8 @@ const getMatchedDevice = (info: PVCameraInfo | undefined): PVCameraInfo => {
return {
PVFileCameraInfo: undefined,
PVCSICameraInfo: undefined,
PVUsbCameraInfo: undefined
PVUsbCameraInfo: undefined,
PVBaslerCameraInfo: undefined,
};
}
return (
Expand All @@ -252,7 +257,8 @@ const getMatchedDevice = (info: PVCameraInfo | undefined): PVCameraInfo => {
) || {
PVFileCameraInfo: undefined,
PVCSICameraInfo: undefined,
PVUsbCameraInfo: undefined
PVUsbCameraInfo: undefined,
PVBaslerCameraInfo: undefined,
}
);
};
Expand Down Expand Up @@ -477,6 +483,7 @@ const getMatchedDevice = (info: PVCameraInfo | undefined): PVCameraInfo => {
<span v-if="camera.PVUsbCameraInfo">USB Camera:</span>
<span v-else-if="camera.PVCSICameraInfo">CSI Camera:</span>
<span v-else-if="camera.PVFileCameraInfo">File Camera:</span>
<span v-else-if="camera.PVBaslerCameraInfo">Basler Camera:</span>
<span v-else>Unknown Camera:</span>
&nbsp;<span>{{ cameraInfoFor(camera)?.name ?? cameraInfoFor(camera)?.baseName }}</span>
</v-card-title>
Expand Down
3 changes: 3 additions & 0 deletions photon-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ dependencies {
implementation("org.photonvision:photon-libcamera-gl-driver-jni:$libcameraDriverVersion:linuxarm64") {
transitive = false
}
implementation("org.teamdeadbolts:basler_jni-linuxx64:$baslerVersion") {
transitive = false
}
implementation "org.photonvision:photon-libcamera-gl-driver-java:$libcameraDriverVersion"

implementation "org.photonvision:photon-mrcal-java:$mrcalVersion"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.photonvision.jni;

import java.io.IOException;
import java.util.List;
import org.photonvision.common.util.TestUtils;

public class BaslerCameraJNI extends PhotonJNICommon {
private boolean isLoaded;
private static BaslerCameraJNI instance = null;

private BaslerCameraJNI() {
isLoaded = false;
}

public static BaslerCameraJNI getInstance() {
if (instance == null) instance = new BaslerCameraJNI();

return instance;
}

public static synchronized void forceLoad() throws IOException {
TestUtils.loadLibraries();

forceLoad(getInstance(), BaslerCameraJNI.class, List.of("baslerjni"));
}

@Override
public boolean isLoaded() {
return isLoaded;
}

@Override
public void setLoaded(boolean state) {
isLoaded = state;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,10 @@ public enum CameraQuirk {
ArduOV9782,
/** Camera has odd exposure range, and supports gain control */
See3Cam_24CUG,

/** Quirks to tell the difference between basler cameras */
BaslerDaA1280Controls,

/** Other Basler Quirks */
ManualWB,
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@
public enum CameraType {
UsbCamera,
ZeroCopyPicam,
BaslerCamera,
FileCamera // special case for File-based vision sources
}
Loading
Loading