In the docs it was mentioned that we can connect 4 Zed x cameras to a Zed box orin and stream at HD1200@30fps. But empirically we only measured 14-16 fps when streaming from four cameras (depth disabled). According to the docs we attach two zed x cameras per group and still 30fps@HD1200, so in total that is 4 cameras per box. As another test we only connected 2 cameras to the box. we are able to stream at 30fps @hd1200
Hi @narsimha
Welcome to the StereoLabs community
How did you measure this?
Are you using a custom software?
Have you tried to use the ZED Studio application?
Is the ZED Box running in MAXN power mode with the jetson_clocks script running?
I was using this custom script to check fps for each camera along with different combination of cameras. Device was set to max power mode (0), but I haven’t used any jetson_clocks scripts in background.
import time
import itertools
import pyzed.sl as sl
SERIALS = {0: 40966563, 1: 42533328, 2: 43221759, 3: 49402962}
RESOLUTIONS = [(“HD1200”, sl.RESOLUTION.HD1200), (“SVGA”, sl.RESOLUTION.SVGA)]
FPS_TARGETS = [30, 60]
DURATION_S = 6.0
COMBOS = (
[(i,) for i in range(4)] +
list(itertools.combinations(range(4), 2)) +
[(0, 1, 2, 3)]
)
results =
for res_label, res in RESOLUTIONS:
for fps in FPS_TARGETS:
for combo in COMBOS:
zeds =
ok = True
for idx in combo:
z = sl.Camera()
init = sl.InitParameters()
init.set_from_serial_number(SERIALS[idx])
init.depth_mode = sl.DEPTH_MODE.NONE
init.camera_resolution = res
init.camera_fps = fps
st = z.open(init)
if st != sl.ERROR_CODE.SUCCESS:
print(f"[{res_label}@{fps} cams={combo}] cam{idx} OPEN FAILED: {st}“, flush=True)
ok = False
for _, zz in zeds:
zz.close()
break
rec = sl.RecordingParameters(f”/tmp/matrixtest_cam{idx}.svo2", sl.SVO_COMPRESSION_MODE.H264)
rst = z.enable_recording(rec)
if rst != sl.ERROR_CODE.SUCCESS:
print(f"[{res_label}@{fps} cams={combo}] cam{idx} RECORDING FAILED: {rst}", flush=True)
ok = False
z.close()
for _, zz in zeds:
zz.close()
break
zeds.append((idx, z))
if not ok:
results.append((res_label, fps, combo, None))
continue
rt = sl.RuntimeParameters()
grabs = {idx: 0 for idx, _ in zeds}
t0 = time.time()
while time.time() - t0 < DURATION_S:
for idx, z in zeds:
if z.grab(rt) == sl.ERROR_CODE.SUCCESS:
grabs[idx] += 1
elapsed = time.time() - t0
for idx, z in zeds:
z.disable_recording()
z.close()
per_cam_fps = {idx: c / elapsed for idx, c in grabs.items()}
avg_fps = sum(per_cam_fps.values()) / len(per_cam_fps)
combo_str = ",".join(str(i) for i in combo)
fps_str = ",".join(f"{per_cam_fps[i]:.1f}" for i in combo)
print(f"[{res_label}@{fps}fps req] cams=({combo_str}) -> per-cam fps=[{fps_str}] avg={avg_fps:.1f}", flush=True)
results.append((res_label, fps, combo, per_cam_fps))
print(“\n=== SUMMARY ===”)
for res_label, fps, combo, per_cam_fps in results:
combo_str = “,”.join(str(i) for i in combo)
if per_cam_fps is None:
print(f"{res_label}@{fps}fps cams=({combo_str}): FAILED")
else:
avg = sum(per_cam_fps.values()) / len(per_cam_fps)
print(f"{res_label}@{fps}fps cams=({combo_str}): avg {avg:.1f} fps")
Is there any end-end guide that explains the setup of multiple cameras across different zed orin boxes and syncing them? If so that would be greatly appreciated.
Yes sure:
Hi also tried using the jetson_clocks but it still didnt make any improvement. I also updated the code to one thread per camera feed as in here, but still the results are identical to the original script I was using.
Hi Narsimha,
Thanks for sharing the script, that helps a lot. One detail stands out: every combination you tested also had H.264 SVO2 recording enabled on all four cameras, so what we have measured so far is the recording pipeline rather than the capture bandwidth the documentation refers to. Each ZED X records its full stereo pair, so four cameras at HD1200@30 is roughly the same encoder load as two cameras at HD1200@60, and we have a closely matching case where that load ran at the full rate with grab only and fell to 18-19 fps per camera as soon as H.264 recording was turned on.
Could you re-run the four camera test with the enable_recording call removed entirely, keeping depth_mode=NONE, and send the per camera fps? Please also confirm whether your one-thread-per-camera version still had recording enabled, and send the output of cat /usr/local/zed/version.txt, cat /proc/device-tree/model and dpkg -l | grep -i stereolabs so we know the exact Jetson module, SDK and GMSL driver versions.
One small note on the measurement itself: counting only grab() == sl.ERROR_CODE.SUCCESS discards frames that come back with a warning code but are still usable, so <= sl.ERROR_CODE.SUCCESS will give a more accurate count.
On synchronizing cameras across several ZED Boxes, the page above does cover it: hardware triggering is the path when cameras sit on the same Jetson or on chained capture cards, and PTP is the method when they are spread across different hosts on the network. To point you at the right one, do you need frame alignment at hardware trigger accuracy, or just aligned timestamps across boxes?
Regards
Tristan