Skip to content

Commit 2ccd60e

Browse files
authored
Merge pull request #1121 from luxonis/fix/stress-test
stress-test: Add a flag to slowly ramp up dot and flood lights
2 parents e901dc5 + 8417eb6 commit 2ccd60e

1 file changed

Lines changed: 93 additions & 12 deletions

File tree

utilities/stress_test.py

Lines changed: 93 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ def create_yolo(pipeline: dai.Pipeline, camera: dai.node.ColorCamera) -> Tuple[s
119119
yoloDet.input.setBlocking(False)
120120
camera.preview.link(yoloDet.input)
121121
xoutColor = pipeline.createXLinkOut()
122-
passthrough_q_name = f"preview_{camera.getBoardSocket()}"
122+
# Match the rest of this script's naming: "preview_<SOCKET_NAME>"
123+
passthrough_q_name = "preview_" + camera.getBoardSocket().name
123124
xoutColor.setStreamName(passthrough_q_name)
124125
yoloDet.passthrough.link(xoutColor.input)
125126
xout_yolo = pipeline.createXLinkOut()
@@ -150,6 +151,24 @@ def stress_test(mxid: str = ""):
150151
parser = argparse.ArgumentParser()
151152
parser.add_argument("-ne", "--n-edge-detectors", default=0, type=int, help="Number of edge detectors to create.")
152153
parser.add_argument("--no-nnet", action="store_true", default=False, help="Don't create a neural network.")
154+
parser.add_argument(
155+
"--no-stereo",
156+
action="store_true",
157+
default=False,
158+
help="Don't create stereo depth (even if a stereo pair is present).",
159+
)
160+
parser.add_argument(
161+
"--slow-rampup",
162+
action="store_true",
163+
default=False,
164+
help="Ramp IR dot/flood brightness after the pipeline starts (helps avoid device crashes).",
165+
)
166+
parser.add_argument(
167+
"--rampup-seconds",
168+
type=float,
169+
default=5.0,
170+
help="Duration (seconds) for --slow-rampup. Recommended: 5.",
171+
)
153172

154173
# May have some unknown args
155174
args, _ = parser.parse_known_args()
@@ -159,24 +178,76 @@ def stress_test(mxid: str = ""):
159178
exp_time = 20000
160179

161180
import time
181+
162182
success, device_info = dai.Device.getDeviceByMxId(mxid)
163183
cam_args = [] # Device info or no args at all
164184
if success:
165185
cam_args.append(device_info)
166186
with dai.Device(*cam_args) as device:
167-
print("Setting default dot intensity to", dot_intensity)
168-
device.setIrLaserDotProjectorIntensity(dot_intensity)
169-
print("Setting default flood intensity to", flood_intensity)
170-
device.setIrFloodLightIntensity(flood_intensity)
187+
if args.slow_rampup:
188+
# Put IR to a known safe baseline before starting the pipeline.
189+
# The actual configured targets are applied after the pipeline is running.
190+
try:
191+
device.setIrLaserDotProjectorIntensity(0.0)
192+
device.setIrFloodLightIntensity(0.0)
193+
except Exception as e:
194+
print("Warning: Failed to set IR intensity baseline:", repr(e))
195+
else:
196+
print("Setting default dot intensity to", dot_intensity)
197+
device.setIrLaserDotProjectorIntensity(dot_intensity)
198+
print("Setting default flood intensity to", flood_intensity)
199+
device.setIrFloodLightIntensity(flood_intensity)
200+
171201
pipeline, outputs, pipeline_context = build_pipeline(device, args)
172202
device.startPipeline(pipeline)
203+
204+
ramp_start_t: Optional[float] = None
205+
ramp_last_set_t: float = 0.0
206+
ramp_last_dot: Optional[float] = None
207+
ramp_last_flood: Optional[float] = None
208+
209+
if args.slow_rampup:
210+
print(
211+
f"Slow rampup enabled: ramping dot={dot_intensity:.2f}, flood={flood_intensity:.2f} over {args.rampup_seconds:.1f}s (non-blocking)"
212+
)
213+
ramp_start_t = time.time()
214+
173215
start_time = time.time()
174216
queues = [device.getOutputQueue(name, size, False)
175217
for name, size in outputs if name != "sys_log"]
176218
camera_control_q = device.getInputQueue("cam_control")
177219
sys_info_q = device.getOutputQueue("sys_log", 1, False)
178220
usb_speed = device.getUsbSpeed()
179221
while True:
222+
# Ramp IR on-the-fly while we keep draining queues.
223+
if ramp_start_t is not None:
224+
now = time.time()
225+
dur = float(args.rampup_seconds)
226+
# Rate-limit device setter calls; these are RPCs and can be chatty.
227+
if dur <= 0:
228+
frac = 1.0
229+
else:
230+
frac = clamp((now - ramp_start_t) / dur, 0.0, 1.0)
231+
232+
# Update at most ~20Hz, or on final completion.
233+
if (now - ramp_last_set_t) >= 0.05 or frac >= 1.0:
234+
dot = dot_intensity * frac
235+
flood = flood_intensity * frac
236+
try:
237+
if ramp_last_dot is None or abs(dot - ramp_last_dot) >= 1e-3:
238+
device.setIrLaserDotProjectorIntensity(dot)
239+
ramp_last_dot = dot
240+
if ramp_last_flood is None or abs(flood - ramp_last_flood) >= 1e-3:
241+
device.setIrFloodLightIntensity(flood)
242+
ramp_last_flood = flood
243+
except Exception as e:
244+
print("Warning: IR rampup failed:", repr(e))
245+
ramp_start_t = None
246+
ramp_last_set_t = now
247+
248+
if frac >= 1.0:
249+
ramp_start_t = None
250+
180251
for queue in queues:
181252
packet = queue.tryGet()
182253
# print("QUEUE", queue.getName(), "PACKET", packet)
@@ -431,7 +502,7 @@ def build_pipeline(device: dai.Device, args) -> Tuple[dai.Pipeline, List[Tuple[s
431502
edge_detector.outputImage.link(edge_detector_xlink.input)
432503
xlink_outs.append((stream_name, 5))
433504

434-
if left and right:
505+
if left and right and not args.no_stereo:
435506
if left.getResolutionWidth() > 1280:
436507
print("Left camera width is greater than 1280, setting ISP scale to 2/3")
437508
left.setIspScale(2, 3)
@@ -442,18 +513,19 @@ def build_pipeline(device: dai.Device, args) -> Tuple[dai.Pipeline, List[Tuple[s
442513
output = "out" if hasattr(left, "out") else "video"
443514
getattr(left, output).link(stereo.left)
444515
getattr(right, output).link(stereo.right)
445-
stereo.setDefaultProfilePreset(
446-
dai.node.StereoDepth.PresetMode.HIGH_DENSITY)
447-
stereo.setOutputSize(left.getResolutionWidth(),
448-
left.getResolutionHeight())
516+
stereo.setDefaultProfilePreset(dai.node.StereoDepth.PresetMode.HIGH_DENSITY)
517+
stereo.setOutputSize(left.getResolutionWidth(), left.getResolutionHeight())
449518
stereo.setLeftRightCheck(True)
450519
stereo.setSubpixel(True)
451520
stereo.setDepthAlign(align_socket)
452521
else:
453-
print("Device doesn't have a stereo pair, skipping stereo depth creation...")
522+
if args.no_stereo and left and right:
523+
print("--no-stereo set, skipping stereo depth creation...")
524+
else:
525+
print("Device doesn't have a stereo pair, skipping stereo depth creation...")
454526
if color_cam is not None:
455527
if not args.no_nnet:
456-
if left is not None and right is not None: # Create spatial detection net
528+
if left is not None and right is not None and not args.no_stereo: # Create spatial detection net
457529
print("Creating spatial detection network...")
458530
yolo = pipeline.createYoloSpatialDetectionNetwork()
459531
blob_path = get_or_download_yolo_blob()
@@ -472,6 +544,15 @@ def build_pipeline(device: dai.Device, args) -> Tuple[dai.Pipeline, List[Tuple[s
472544
color_cam.preview.link(yolo.input)
473545
stereo.depth.link(yolo.inputDepth)
474546

547+
# Always export the color preview stream, even when the color cam is used by the spatial NN
548+
# (otherwise CAM_C looks "missing" since only depth+yolo are published).
549+
passthrough_q_name = "preview_" + color_cam.getBoardSocket().name
550+
xout_color = pipeline.createXLinkOut()
551+
xout_color.setStreamName(passthrough_q_name)
552+
yolo.passthrough.link(xout_color.input)
553+
xlink_outs.append((passthrough_q_name, 4))
554+
context.q_name_yolo_passthrough = passthrough_q_name
555+
475556
xout_depth = pipeline.createXLinkOut()
476557
depth_q_name = "stereo depth"
477558
xout_depth.setStreamName(depth_q_name)

0 commit comments

Comments
 (0)