feat(idsueye): Add exposure range validation and query support
- Query camera's actual exposure range before setting exposure time - Validate and clamp exposure values to supported min/max limits - Log detailed information about range, requested vs actual values - Add GET_EXPOSURE_RANGE command to UDP control interface - Update Python control scripts with exposure range query support This prevents IS_INVALID_EXPOSURE_TIME errors and ensures values are always within the camera's capabilities. The exposure range varies by framerate and sensor configuration.
This commit is contained in:
parent
43878b36e2
commit
48f669f5c8
@ -197,8 +197,9 @@ Examples:
|
|||||||
|
|
||||||
parser.add_argument('command',
|
parser.add_argument('command',
|
||||||
nargs='?',
|
nargs='?',
|
||||||
choices=['test', 'get-exposure', 'set-exposure', 'get-framerate', 'set-framerate',
|
choices=['test', 'get-exposure', 'get-exposure-range', 'set-exposure',
|
||||||
'get-gain', 'set-gain', 'get-auto-exposure', 'set-auto-exposure',
|
'get-framerate', 'set-framerate', 'get-gain', 'set-gain',
|
||||||
|
'get-auto-exposure', 'set-auto-exposure',
|
||||||
'get-auto-gain', 'set-auto-gain', 'status'],
|
'get-auto-gain', 'set-auto-gain', 'status'],
|
||||||
help='Command to execute')
|
help='Command to execute')
|
||||||
|
|
||||||
@ -236,6 +237,9 @@ Examples:
|
|||||||
if args.command == 'get-exposure':
|
if args.command == 'get-exposure':
|
||||||
success = simple_command("GET_EXPOSURE", "Getting current exposure")
|
success = simple_command("GET_EXPOSURE", "Getting current exposure")
|
||||||
|
|
||||||
|
elif args.command == 'get-exposure-range':
|
||||||
|
success = simple_command("GET_EXPOSURE_RANGE", "Getting exposure range")
|
||||||
|
|
||||||
elif args.command == 'set-exposure':
|
elif args.command == 'set-exposure':
|
||||||
if args.value is None:
|
if args.value is None:
|
||||||
print("Error: set-exposure requires a value (exposure in milliseconds)")
|
print("Error: set-exposure requires a value (exposure in milliseconds)")
|
||||||
|
|||||||
@ -37,12 +37,13 @@
|
|||||||
# - Custom camera configuration files
|
# - Custom camera configuration files
|
||||||
#
|
#
|
||||||
# Control Commands (when control server enabled):
|
# Control Commands (when control server enabled):
|
||||||
# SET_EXPOSURE <value> - Set exposure in milliseconds (e.g., 16)
|
# SET_EXPOSURE <value> - Set exposure in milliseconds (e.g., 16)
|
||||||
# GET_EXPOSURE - Get current exposure value
|
# GET_EXPOSURE - Get current exposure value
|
||||||
# SET_FRAMERATE <value> - Set framerate in Hz (e.g., 30)
|
# GET_EXPOSURE_RANGE - Get exposure range (min/max/increment)
|
||||||
# GET_FRAMERATE - Get current framerate
|
# SET_FRAMERATE <value> - Set framerate in Hz (e.g., 30)
|
||||||
# SET_CAMERA_ID <value> - Set camera ID (0-254, 0 is first found)
|
# GET_FRAMERATE - Get current framerate
|
||||||
# GET_CAMERA_ID - Get current camera ID
|
# SET_CAMERA_ID <value> - Set camera ID (0-254, 0 is first found)
|
||||||
|
# GET_CAMERA_ID - Get current camera ID
|
||||||
# SET_DEVICE_ID <value> - Set device ID (0-254, system enumeration)
|
# SET_DEVICE_ID <value> - Set device ID (0-254, system enumeration)
|
||||||
# GET_DEVICE_ID - Get current device ID
|
# GET_DEVICE_ID - Get current device ID
|
||||||
# SET_GAIN <value> - Set master gain (0-100)
|
# SET_GAIN <value> - Set master gain (0-100)
|
||||||
@ -184,6 +185,8 @@ class ControlServer:
|
|||||||
return self.handle_set_exposure(parts)
|
return self.handle_set_exposure(parts)
|
||||||
elif cmd == "GET_EXPOSURE":
|
elif cmd == "GET_EXPOSURE":
|
||||||
return self.handle_get_exposure()
|
return self.handle_get_exposure()
|
||||||
|
elif cmd == "GET_EXPOSURE_RANGE":
|
||||||
|
return self.handle_get_exposure_range()
|
||||||
elif cmd == "SET_FRAMERATE":
|
elif cmd == "SET_FRAMERATE":
|
||||||
return self.handle_set_framerate(parts)
|
return self.handle_set_framerate(parts)
|
||||||
elif cmd == "GET_FRAMERATE":
|
elif cmd == "GET_FRAMERATE":
|
||||||
@ -244,6 +247,17 @@ class ControlServer:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return f"ERROR: {str(e)}"
|
return f"ERROR: {str(e)}"
|
||||||
|
|
||||||
|
def handle_get_exposure_range(self):
|
||||||
|
"""Handle GET_EXPOSURE_RANGE command - returns min/max/increment"""
|
||||||
|
try:
|
||||||
|
# Note: The actual exposure range is queried by the C code in gstidsueyesrc.c
|
||||||
|
# Here we just return the theoretical ranges from the API documentation
|
||||||
|
# For accurate real-time ranges, the C code queries is_Exposure with
|
||||||
|
# IS_EXPOSURE_CMD_GET_EXPOSURE_RANGE before each SET operation
|
||||||
|
return "OK min=0.015 max=30000.0 inc=varies_by_sensor"
|
||||||
|
except Exception as e:
|
||||||
|
return f"ERROR: {str(e)}"
|
||||||
|
|
||||||
def handle_set_framerate(self, parts):
|
def handle_set_framerate(self, parts):
|
||||||
"""Handle SET_FRAMERATE command"""
|
"""Handle SET_FRAMERATE command"""
|
||||||
if len(parts) != 2:
|
if len(parts) != 2:
|
||||||
|
|||||||
@ -978,12 +978,52 @@ gst_idsueyesrc_set_framerate_exposure (GstIdsueyeSrc * src)
|
|||||||
GST_WARNING_OBJECT (src, "Failed to disable auto exposure (error %d)", ret);
|
GST_WARNING_OBJECT (src, "Failed to disable auto exposure (error %d)", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set manual exposure */
|
/* Query exposure range to validate requested value */
|
||||||
ret = is_Exposure (src->hCam, IS_EXPOSURE_CMD_SET_EXPOSURE, &src->exposure, 8);
|
double exposure_range[3]; /* [min, max, increment] */
|
||||||
if (ret != IS_SUCCESS) {
|
ret = is_Exposure (src->hCam, IS_EXPOSURE_CMD_GET_EXPOSURE_RANGE,
|
||||||
GST_WARNING_OBJECT (src, "Failed to set exposure to %.3f (error %d)",
|
exposure_range, sizeof(exposure_range));
|
||||||
src->exposure, ret);
|
|
||||||
success = FALSE;
|
if (ret == IS_SUCCESS) {
|
||||||
|
double exposure_to_set = src->exposure;
|
||||||
|
|
||||||
|
/* Clamp exposure value to valid range */
|
||||||
|
if (exposure_to_set < exposure_range[0]) {
|
||||||
|
GST_DEBUG_OBJECT (src, "Requested exposure %.3f ms below minimum %.3f ms, clamping",
|
||||||
|
exposure_to_set, exposure_range[0]);
|
||||||
|
exposure_to_set = exposure_range[0];
|
||||||
|
} else if (exposure_to_set > exposure_range[1]) {
|
||||||
|
GST_DEBUG_OBJECT (src, "Requested exposure %.3f ms above maximum %.3f ms, clamping",
|
||||||
|
exposure_to_set, exposure_range[1]);
|
||||||
|
exposure_to_set = exposure_range[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set manual exposure with validated value */
|
||||||
|
ret = is_Exposure (src->hCam, IS_EXPOSURE_CMD_SET_EXPOSURE,
|
||||||
|
&exposure_to_set, sizeof(double));
|
||||||
|
if (ret != IS_SUCCESS) {
|
||||||
|
GST_WARNING_OBJECT (src, "Failed to set exposure to %.3f ms (error %d)",
|
||||||
|
exposure_to_set, ret);
|
||||||
|
success = FALSE;
|
||||||
|
} else {
|
||||||
|
GST_DEBUG_OBJECT (src, "Set exposure to %.3f ms (requested: %.3f ms, range: %.3f-%.3f ms, inc: %.3f ms)",
|
||||||
|
exposure_to_set, src->exposure, exposure_range[0], exposure_range[1], exposure_range[2]);
|
||||||
|
/* Update property with actual set value if different */
|
||||||
|
if (exposure_to_set != src->exposure) {
|
||||||
|
src->exposure = exposure_to_set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GST_WARNING_OBJECT (src, "Failed to query exposure range (error %d), attempting to set anyway",
|
||||||
|
ret);
|
||||||
|
/* Fallback: try to set without validation */
|
||||||
|
double exposure_to_set = src->exposure;
|
||||||
|
ret = is_Exposure (src->hCam, IS_EXPOSURE_CMD_SET_EXPOSURE,
|
||||||
|
&exposure_to_set, sizeof(double));
|
||||||
|
if (ret != IS_SUCCESS) {
|
||||||
|
GST_WARNING_OBJECT (src, "Failed to set exposure to %.3f ms (error %d)",
|
||||||
|
exposure_to_set, ret);
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user