3D visionTroubleshooting

Jetson stereo camera devicetree: set sync_sensor_index on sensor 1

Isaac ROS Argus stereo fails when nvargus sees two separate camera modules. Set sync_sensor_index = <1> on the second sensor in your Jetson devicetree.

LumaSpec Vision10 min read Share on LinkedIn

On this page 8 sections
  1. 01Why does the Isaac ROS Argus stereo launch fail when argus_camera works on both sensors?
  2. 02Why isn't GPIO frame sync enough to make nvargus see a stereo camera?
  3. 03How much does sync skew cost a stereo depth rig?
  4. 04Which devicetree properties make nvargus register one stereo module?
  5. 05How do you verify the stereo module with argus_syncstereo before launching ROS?
  6. 06Why does the stereo launch still fail after adding sync_sensor_index?
  7. 07When should you stop editing the devicetree and buy a supported stereo camera?
  8. 08Questions

You built a stereo camera for Jetson: two synchronized sensors, two working video nodes, and argus_camera opens each one cleanly. Then the Isaac ROS Argus stereo launch fails, and the monocular launch on the same rig works. That split is the whole clue, and it is a devicetree problem, not a trigger problem. The path below runs from symptom to fix: why nvargus must register the pair as one stereo camera module, which properties do that, how argus_syncstereo proves the result, what to re-check when the property is present and the launch still fails, and the numbers that decide whether the custom rig stays worth the work.

Why does the Isaac ROS Argus stereo launch fail when argus_camera works on both sensors?

The stereo node asks nvargus for one camera module that contains two sensors, and your devicetree still registers two independent single-sensor modules. argus_camera proves each sensor streams; it proves nothing about module grouping, which is the only thing the stereo launch checks.

The symptom set is consistent. Both sensors enumerate as /dev/video0 and /dev/video1. argus_camera -d 0 and argus_camera -d 1 each stream a clean image. The monocular Isaac ROS Argus launch runs and even saves a left image. Only the stereo launch aborts. If that is your exact pattern, the launch file is not the fault — it is asking for a camera that Argus has not registered.

nvargus builds its world from the devicetree at daemon start. It groups sensor nodes into camera modules, and the module is the unit a stereo producer opens. Your driver work and your trigger work live below that layer and stay invisible to it. The stereo launch wants one module holding two sensors; when the devicetree still defines two single-sensor modules, there is nothing for it to open, and the run fails before a single frame moves.

Why isn't GPIO frame sync enough to make nvargus see a stereo camera?

GPIO frame sync makes the two sensors expose at the same instant, but nvargus never measures a trigger wire. It reads the devicetree, and without sync_sensor_index = <1> on the second sensor it registers the pair as two unrelated modules.

A stereo rig has two layers that fail independently. The electrical layer is your trigger: one generator pulses both sensors so the exposures start together. The registration layer is the devicetree: nvargus reads it once, at daemon start, and decides which devices belong to one camera module. A trigger wire feeds the first layer and says nothing to the second, which is why a rig can be physically synchronized and still enumerate as two unrelated cameras.

Syncing two CSI cameras on Jetson for stereo SLAM walks the electrical layer in detail. This article is about the layer above it — and the fix there costs two properties, not an oscilloscope session.

How much does sync skew cost a stereo depth rig?

Skew between the two exposures converts straight into motion parallax: a rig on a 250 mm/s line with 0.2 mm per pixel on target loses about 42 pixels if the second sensor fires one 33.3 ms frame late, and only 0.06 pixels if the skew is 50 µs.

Worked example — illustrative inputs, so rescale to your own line: a camera pair mounted over a belt moving at 250 mm/s, with 0.2 mm of scene per pixel on the target, running at 30 fps. The frame period is 1/30 s = 33.3 ms.

Case 1, no working sync, second sensor one frame late: motion between the two exposures is 250 mm/s × 33.3 ms = 8.3 mm. On the target that is 8.3 / 0.2 = 41.6, about 42 px. The frames share no overlapping content, and stereo matching returns noise instead of depth.

Case 2, trigger-tight 50 µs skew: motion is 250 mm/s × 50 µs = 12.5 µm, which is 12.5 / 200 µm per pixel = 0.06 px. The pair reads as simultaneous.

pixels of error = speed × skew / pixel scale one frame late: (250 mm/s × 0.0333 s) / 0.2 mm/px ≈ 42 px 50 µs skew: (250 mm/s × 0.00005 s) / 0.2 mm/px ≈ 0.06 px
Skew between exposures Scene motion at 250 mm/s Error at 0.2 mm/px
50 µs, trigger-tight 12.5 µm 0.06 px
1 ms, software-timed 250 µm 1.25 px
33.3 ms, one frame late 8.3 mm ≈42 px

Speed and skew multiply the error; pixel scale divides it. Watch the middle row: a software-timed pair that starts exposures 1 ms apart already gives up 1.25 px, enough to soften depth edges on anything moving. Skew has a brightness face too — two sensors on separate auto exposure can register correctly and still disagree on gray level, which setting auto exposure per stereo camera in a depth rig addresses.

Which devicetree properties make nvargus register one stereo module?

Both sensor nodes must sit inside a single camera module node, and the second sensor carries sync_sensor_index = <1>; the sync_sensor property itself must stay uncommented. With that grouping nvargus reports Total Module Count is 1 instead of 2.

Copy the layout of the reference AR0234 stereo module instead of inventing one: the module file tegra234-camera-p3762-a00.dtsi under t234-common-modules shows a single camera module node that contains both sensor nodes, with sync_sensor_index = <1> on the second sensor. Apply it in this order:

  1. Move both sensor nodes into one camera module node and remove the two standalone module entries, so exactly one module remains.
  2. Add sync_sensor_index = <1> to the second sensor's node; leave the first sensor without it.
  3. Make sure the sync_sensor property for the module is present and not commented out.
  4. Rebuild the DTB, install it and reboot the carrier board.
  5. Read the sensor nodes under /proc/device-tree and confirm the property and the grouping actually booted.

How do you verify the stereo module with argus_syncstereo before launching ROS?

Run argus_syncstereo and read the module count: a healthy rig prints Total Module Count is 1, a getSensorPlacement line for each sensor, and one session that adds camera device 0 and 1 and creates two streams. Count 2 means the grouping never reached the running system.

argus_syncstereo is the Argus sample that opens a stereo module directly, so it isolates registration from your ROS configuration. On a healthy rig the opening lines are:

getSensorPlacement for sensor 0 is SENSOR_PLACEMENT_BOTTOM_RIGHT
getSensorPlacement for sensor 1 is SENSOR_PLACEMENT_TOP_RIGHT
Total Module Count is 1

Between the count and the sessions, a line names your stereo camera module and reports with the following 2 sensors connected: 0 1. Then come Session[0] : add camera device 0, Session[0] : add camera device 1, PRODUCER: Creating stream[0]. and PRODUCER: Creating stream[1]. — one session owning both devices is the signature you want.

Passing argus_syncstereo proves registration only. Prove simultaneity separately: verify hardware sync between two cameras actually works gives tests that catch a trigger that fires but does not lock. Then retry the launches in order — monocular first, stereo second. If the sample passes with Count 1 and the stereo launch still fails, the fault sits in the ROS layer, and the launch and nvargus-daemon logs will name the client or stream setup that broke.

Why does the stereo launch still fail after adding sync_sensor_index?

Mostly it is a stale boot: the property landed in the source but an older devicetree is still running, or the sync_sensor block stayed commented out and the count stayed at 2. Work down this list: running tree, module grouping, property location, placement order, then the link side.

Each item below has a test that takes minutes; the first three cause most repeat failures.

  1. Stale DTB. Test: read the second sensor's node under /proc/device-tree. If sync_sensor_index is not there, the source change never booted — rebuild, reinstall, reboot, re-check.
  2. Property in the wrong node. Test: open the module source and follow the parent chain from the property. It must sit in the sensor node inside the camera module, not in a bus or driver node beside it.
  3. sync_sensor commented out. Test: search the module file for sync_sensor. The property must be active, because a commented-out sync_sensor registers a module without its stereo role.
  4. Leftover module entries. Test: argus_syncstereo prints Total Module Count is 2. Disable the standalone module nodes so only the grouped one compiles.
  5. Placement mismatch. Test: the getSensorPlacement values disagree with your mechanics, or left and right arrive swapped. Correct the placement values in the module.
  6. Link-layer failure. Test: does each sensor still stream alone? When a single sensor now drops frames, shows green or the capture interface times out, the fault is serializer, cabling or capture, not registration — resolving Jetson Orin NX GMSL camera VI timeouts and green screens covers that layer, and how to isolate a blank frame from one sensor on a multi-camera rig gives the isolation drill.

For two CSI cameras, lane count and format mismatches break one sensor at a time and masquerade as stereo faults; two single-lane CSI cameras for stereo: what to verify is the checklist for that case. If the sample passes while the launch fails, remember Argus serves one client at a time — close the vendor tool before launching, and the capture-time article shows another way a competing client skews what you measure.

When should you stop editing the devicetree and buy a supported stereo camera?

Give the devicetree work one focused day: the fix itself is two properties, so if a clean rebuild still prints Total Module Count is 2, the remaining effort is driver-and-link debugging, and a supported stereo camera becomes the faster path to a deployed depth stack.

A custom rig stays right when the machine fixes the baseline, the form factor or the trigger scheme and the drivers are stable — you are one property from done. A supported depth camera becomes right when the SLAM stack has a deadline: an integrated 3D sensor brings its own SDK and depth pipeline, so module registration never enters your schedule. Match the SDK's output to your stack before you order, and filter the types in the camera finder.

A middle path exists when the machine does not force CSI or GMSL: Isaac ROS nodes consume standard image topics, so two GigE or USB3 area scan cameras with their own drivers skip nvargus entirely. Price the bandwidth first: one 2.3 MP mono stream at 60 fps is 2,304,000 px × 8 bit × 60 = 1.11 Gbit/s, more than a single GigE link carries, so plan two links or USB3 per camera.

If you stay on CSI or GMSL, prefer sensors with built-in platform support: IMX219 and IMX477 on Jetson: built-in driver support and stereo sync explains what already-supported sensors take off your plate. Keep the module devicetree in version control beside the carrier board's files, and rerun argus_syncstereo after every platform software update — registration regressions arrive with updates, not with your code. When the fallback path includes a laser-based profiler, treat the laser class labels and interlocks on the housing as part of the mount and never bypass them to save setup time.

Want a second opinion on the build-versus-buy call? Send the sensor pair, the carrier board and your frame-rate target through the contact page, and we will lay out both paths with concrete parts. More depth-rig fault-finding lives on the 3D topic page.

Questions

Does sync_sensor_index go on both sensors or only on the second one?

Only the second sensor carries sync_sensor_index = <1>. In the reference AR0234 stereo module the first sensor has no matching value and stays at index 0, so the property is not mirrored across both nodes. Place it in the second sensor's node inside the single camera module, then rebuild and recheck with argus_syncstereo.

Do you still need the GPIO trigger once the module grouping works?

Yes, because the two layers stay independent. Registration tells nvargus which devices form one stereo camera; the trigger decides whether the two exposures really happen at the same instant. Drop the trigger and the launch will still pass while anything moving produces smeared or mismatched pairs, so keep both and re-check the trigger after any sensor swap.

Which sensor becomes the left image of the stereo pair?

The placement values in your module decide it, and argus_syncstereo shows what nvargus read: the reference AR0234 rig prints SENSOR_PLACEMENT_BOTTOM_RIGHT for sensor 0 and SENSOR_PLACEMENT_TOP_RIGHT for sensor 1. If left and right come out swapped in your pipeline, correct the placement properties in the module first and only then touch the launch file.

Does the one-module rule apply to CSI rigs as well as GMSL ones?

Yes. Grouping two sensors into one module is an Argus registration rule, and it does not care how frames reach the SoC — CSI lanes or a GMSL link through a serializer both end in the same module model. The link layer adds its own failures, such as GMSL VI timeouts, but the module-count requirement is identical.

Is sync_sensor_index a driver change or a devicetree-only change?

Devicetree-only. nvargus reads the property when it enumerates camera modules, and your sensor driver keeps its probe, its video nodes and its streaming behavior untouched. That is why a rig can pass argus_camera on both devices while the stereo launch fails: the driver work is done and only module registration is missing.