The viewer shows the range; your code has to ask for it. Write an exposure a 3D camera does not accept and one of two things happens: the SDK throws an out-of-range error during set-up, or the device clamps the value quietly and scans come back dark or motion-smeared. Both cost bench time. The fix is a short parameter-tree query before you stream: read the exposure node's minimum, maximum and unit, compare them with the value your lighting budget needs, then write and read back. This guide covers the query on laser profilers, structured-light and ToF cameras, the scan-cycle arithmetic that caps exposure, and the decision for each out-of-range case.
What the range query gives you
The range lives in the device's parameter tree — the same store the vendor's viewer reads when it draws its exposure slider. Query it through the SDK and the returned numbers should match that display for the same scan mode; a mismatch means the session sits in a different exposure mode or region than the screen you compared with. The GenICam Standard Features Naming Convention names the feature ExposureTime and defines it as a float in microseconds. Minimum and maximum are properties of the node itself, read them the way you read the value, and some SDKs also carry a boundary parameter of their own — one names it ExposureTimeMax — holding the upper limit the device enforces.
The range is per model and per mode, which is why the query exists at all: limits move when the ROI, the exposure region or the scan recipe changes, so a constant pasted from another camera's session is a latent defect. The same ask-the-device habit as validating a UVC camera gain range applies here: query, do not assume.
The query runs the same way on every 3D camera class: laser profilers, projected structured-light cameras and ToF sensors all hold their capture settings in an SDK parameter tree, so one helper in your capture library covers the lot.
- Type
- Laser profiler
- Type
- Laser profiler
- Type
- Stereo / structured light
- Type
- Depth / ToF camera
Find the exposure nodes before you write
ExposureTime alone is not the whole story. The GenICam pattern applies a manual value only when ExposureMode is Timed and ExposureAuto is Off; in an automatic mode the camera picks its own exposure inside its own limits, and your planned number is decoration. Devices that expose several exposure windows add ExposureTimeSelector, which chooses the window a write applies to — select it first or the value lands where the part is not.
Exposure time is not a mandatory GenICam feature. Some 3D cameras place it under a scan-profile or exposure-mode setting instead, and a few fix it per scan mode. If the node is missing, enumerate the feature list — the capability query walkthrough shows the walk — and search the names for exposure-related entries; when a node should exist but the tree reports it absent, the node-not-existing diagnostics cover the usual causes.
Check the unit while you are there. The SFNC convention is microseconds; some vendor parameters state limits in seconds instead, and a few expose the unit as its own field. A value correct in µs is a thousand times too large in ms, so read the unit once and scale in exactly one place in your capture library.
A 3D laser profile sensor such as the MV-DP4180-03P takes the same query-and-clamp before any scan recipe is frozen.
- Type
- Laser profiler
Query, check, set: the procedure
- Open the device in manual-exposure intent and set the exposure mode before streaming, following the manual-exposure-before-streaming initialization order.
- Locate the node by name — ExposureTime in the SFNC naming — and call ExposureTimeSelector first if the device exposes several windows.
- Read the limits. The node names below are the standard ones; the accessor calls stand in for your SDK's parameter-tree API:
params = device.parameter_tree # open session, before streaming
exp = params.node("ExposureTime") # SFNC feature name, float, microseconds
lo = exp.minimum # smallest accepted exposure, us
hi = exp.maximum # largest accepted exposure, us
print(lo, hi) # illustrative return: 30.0 100000.0
- Clamp in your own code and write; the GenICam exposure write in Python walkthrough covers the write itself:
target = 2000.0 # us, from the lighting budget
exp.value = min(max(target, lo), hi) # clamp against the queried limits
print(exp.value) # read back: proves what the device took
- Confirm the mode guards: ExposureMode Timed and ExposureAuto Off, or the write never reaches the sensor.
- Compare sent and read-back values and log both; a mismatch is the device clamping. A refused write is usually access state rather than range — the node-not-writable check sorts those causes.
- Verify on the first frames: the darkest part you ship centered in the histogram, the achieved scan rate on target. Inside a capture loop, keep sets and gets to the safe parameter set-and-get pattern.
Budget the exposure against the scan cycle
A range check is necessary but not sufficient. On any scanned 3D rig the exposure also has to fit the cycle: exposure, readout and transfer together must finish before the next profile falls due. The scan rate follows from the geometry — on an encoder-timed profiler, the pitch is the travel per profile:
The 0.8 reserves readout and transfer; measure your own reserve on the bench and substitute it.
Worked example. A dark rubber seal runs under a laser profiler on a belt at 200 mm/s, and inspection needs a profile every 0.5 mm of travel. The scan rate is 200 ÷ 0.5 = 400 Hz, so the cycle is 1 ÷ 400 s = 2.5 ms = 2,500 µs. Reserving 20% for readout and transfer gives a budget of 0.8 × 2,500 µs = 2,000 µs. Say the range query returns 30 µs to 100,000 µs with 1 µs step: 2,000 µs sits inside, the write passes, and the scan holds 400 Hz.
Now the part that decides. The seal is dark and needs 3,000 µs to reach target brightness. The range would accept it — 3,000 µs sits far inside 100,000 µs — but the cycle cannot: 3,000 µs exceeds the 2,500 µs period, so 400 Hz is unreachable and the belt outruns the sensor. Three fixes, with numbers: coarsen the pitch to 1.0 mm, halving the required rate to 200 Hz and doubling the period to 5,000 µs, which leaves a 4,000 µs budget that fits; slow the belt to 100 mm/s at the original pitch, which lands on the same 200 Hz; or hold 400 Hz and put more light on the part. The range query said the write would pass; the cycle arithmetic says the scan would fail.
Sensor-side sampling is rarely the binding limit. The MV-HLVS-16K100-L60 line-scan 2.5D inspection system specifies a 120 kHz sampling rate and a 600 mm emitting area length. At the example's scan rate, that sampling ceiling sits roughly 300 times above demand — on a conveyor the exposure budget, not the sampling rate, runs out first.
- Type
- 2.5D inspection
When the value you want sits outside the range
Four cases cover every out-of-range outcome, and each has a decision. None of them is "write it anyway".
| Query result | What it means | Decision |
|---|---|---|
| Target below the minimum — 8 µs wanted against a 30 µs floor | Overexposed even at the floor | Set the minimum and remove light: turn the light controller output down or close the aperture until the histogram centers |
| Target above the maximum and above the cycle period | The capture cannot complete in the cycle | Add light, coarsen the pitch or slow the belt — doubling the pitch halves the required rate and doubles the budget |
| Target above the maximum, inside the cycle period | Only the device ceiling blocks you | Add light, or average consecutive profiles — signal sums like a longer exposure while noise grows as the square root of the count — if processing tolerates the latency |
| Read-back differs from the value sent | The device clamped | Log both values and clamp writes in code against the limits queried at open |
Traps specific to 3D cameras
Automatic exposure re-decides every scan, so an encoder-timed rig returns inconsistent depth pass to pass. Lock Timed and Off once the value is proven on the bench; that is the whole point of planning the number instead of letting the camera drift.
Raising exposure can push the achievable rate below the belt. If the measured rate lands short of target after a write, work the low frame rate on software trigger checklist before blaming exposure alone — stream mode and data streams cause most of those shortfalls.
Gain is the wrong first knob. It amplifies what the sensor already captured, noise included, while exposure inside the budget collects more signal. Tune gain only after exposure and light are maxed within the cycle; the depth-camera gain and exposure trade-off walks the near-range case.
Checks before you deploy
- Range, unit and read-back logged at open — when dark scans surface later, the limits the rig ran under are in the record.
- Measured scan rate on target after the write — an accepted value is not a completed cycle.
- Exposure at or below 0.8 × the measured cycle period — recompute whenever pitch or belt speed changes.
- Histogram of the darkest shipped part centered in-range, with margin for a darker lot from the supplier.
- Clamp in code uses the queried minimum and maximum, never constants copied from a datasheet or another camera's session.
More capture-side reading sits on the 3D camera topic page.
Where to go next
Choose the sensor class first, then run this query on the bench before the wiring goes into the cell. The 3D sensors category covers profiler, structured-light and ToF families; the area scan cameras page lists conventional 2D sensors with the same GenICam-style trees; the camera finder filters both at once; and the camera step of the configurator pairs the sensor with the rest of the rig. If a scan-rate budget will not close, send the numbers through the contact page and the applications team will check the arithmetic with you.
Questions
What units does the exposure range come back in?
The GenICam SFNC defines ExposureTime as a float in microseconds, and most 3D camera stacks follow it. Some vendor parameters instead state their limits in seconds, and a few expose the unit as its own field. Read the unit together with the minimum and maximum: writing 2 into a milliseconds node sets 2,000 µs — a thousand times the 2 µs you meant, which on a 2,500 µs cycle consumes 80% of it by itself.
Why does an exposure write succeed while the scan rate still drops?
The range check passed but the cycle did not: exposure, readout and transfer together must fit inside 1 ÷ f_scan. Read the achieved rate after the write, not just the accepted value. If the target was 400 Hz and the measured rate settles at 300 Hz, cut exposure until the rate holds, or double the pitch from 0.5 mm to 1.0 mm, which halves the required rate to 200 Hz and doubles the period to 5,000 µs.
How often should the exposure range be re-queried?
Treat the range as mode-scoped: query at open, again after every exposure-mode, ROI or selector change, and whenever a recipe loads on the device. A value that passed in a single-exposure recipe can be out of budget in a two-window one, where each window must fit roughly half the period. The range printed in a datasheet belongs to a different device session — the parameter tree is the only authority.
What if the tree has no ExposureTime node?
Exposure time is not a mandatory GenICam feature, so some 3D cameras place it under a scan-profile or exposure-mode setting, or fix it per scan mode. Enumerate the feature list and search the names for exposure-related entries, then check the model's parameter documentation for the name it uses. If a node exists but refuses writes, check the session's access state first — a second client holding the device produces the same symptom.




