3D visionTroubleshooting

Camera calibration file error? Check locale number parsing

Your calibration file downloads fine but the camera will not open? Find the locale setting that breaks decimal parsing and the LC_ALL fix that clears it.

LumaSpec Vision10 min read Share on LinkedIn

On this page 8 sections
  1. 01The symptom: the download succeeds, the file is rejected
  2. 02The 60-second check: read the locale the process really sees
  3. 03Why a comma kills the parse: the arithmetic
    1. Worked example: a valid row and a zeroed row
  4. 04The fix: set the locale where the SDK starts
  5. 05Still rejected: the remaining causes, ranked
  6. 06Prevention: pin the locale, keep one decimal convention
  7. 07The decision, case by case
  8. 08Questions

Your camera's SDK reaches the calibration service, downloads the file for your serial number and then declares it invalid — and the camera never opens. The file is almost always fine; the parse is not. On Linux the character that separates decimals is a locale setting, and a comma-decimal locale turns values like 0.999962 into plain zeros before the SDK's validation ever runs. This walkthrough gives you the 60-second check, the one-line fix for shells, containers and services, and the habits that keep the fault from returning after the next image update.

The symptom: the download succeeds, the file is rejected

The start-up log reads the same on every attempt. The SDK prints its version, finds the camera on USB, sees no calibration file for your serial number, downloads one, then fails with an invalid-calibration-file error. Some SDKs put the remedy inside that error — on Linux, export LC_ALL="C" and restart the application — which is the clearest hint you will ever get. The wrapper above then reports a camera-open failure and often appends a warning to check the USB cable. Ignore the cable advice at this stage: the fault happened while parsing calibration data, before any streaming started.

What misleads people is that the file on disk looks healthy. It has a plausible size, opens in a text editor, shows sensible numbers. The corruption happens in memory, during conversion from text to floating point, and it is silent: the parser logs nothing, returns the wrong value, and the validation that follows rejects the whole matrix.

The 60-second check: read the locale the process really sees

Run locale in the same shell, container and user account that start the SDK — not on your laptop, not in a fresh terminal. Three lines decide the case:

  • LC_ALL — the override. Empty is normal, not a fault.
  • LC_NUMERIC — the only category that governs decimal conversion.
  • LANG — the fallback used when the two above are unset.

Decision rule: if LC_NUMERIC or LC_ALL names a comma-decimal locale — de_DE.UTF-8, fr_FR.UTF-8, it_IT.UTF-8, es_ES.UTF-8, pt_BR.UTF-8, ru_RU.UTF-8 and most of Europe and Latin America — that is your cause. C and en_US.UTF-8 use periods and parse these files cleanly.

The definitive test takes one start: prepend LC_ALL=C to the usual start command. If the camera opens, the locale was the problem; if not, work down the remaining causes below.

Close two environment traps first. Hosts and containers keep separate environments, so a locale installed on the host does nothing inside the image, and the reverse. Services and autostart entries rarely inherit your interactive shell either — the classic signature is a camera that opens from a bare terminal but fails when the service starts it, because the two processes carry different LC_NUMERIC values.

Why a comma kills the parse: the arithmetic

C and C++ runtimes convert text to floating point with functions such as strtod, obeying the active LC_NUMERIC. Toolkits and middleware call setlocale at start-up and activate whatever the environment carries. In a comma locale the period is not a decimal character, so conversion stops there and the fraction is dropped without an error message. The same file becomes two different matrices:

Text in the file C / en_US.UTF-8 de_DE.UTF-8 (comma)
1403.85 1403.85 1403.0
0.007650 0.007650 0.0
0.999962 0.999962 0.0
-0.003560 -0.003560 0.0

Worked example: a valid row and a zeroed row

Take a plausible left-camera entry set from an example file: fx = 1403.85 px and a near-identity rotation row r = (0.999962, 0.007650, -0.003560).

Parsed correctly, the row norm is sqrt(0.999962² + 0.007650² + 0.003560²) = sqrt(0.9999240 + 0.0000585 + 0.0000127) = sqrt(0.9999952) ≈ 1.0000. A rotation row must have norm 1, so this file validates.

Parsed under the comma locale, every entry stops at the period: r = (0, 0, 0), norm = sqrt(0² + 0² + 0²) = 0. Zero is not 1, the matrix is not a rotation, and the SDK reports an invalid calibration file. The truncated focal would have slipped through: fx = 1403.0 instead of 1403.85 px moves a depth estimate at a 120 mm baseline and 42 px disparity from 1403.85 × 120 / 42 = 4011 mm to 1403 × 120 / 42 = 4009 mm — about 2 mm of error at 4 m. The zeros kill the file; the lost fraction barely moves the measurement.

Z = f × B / d sqrt(r1² + r2² + r3²) = 1

The failure also runs backwards. A tool that serialized numbers under a comma locale writes 0,999962 into an export, and a C-locale reader stops at the comma and reads 0. The file is valid text and invalid data — exactly what you see when parameters export cleanly from one program and refuse to import into another. The format side of that problem is covered in Import stereo calibration parameters across software formats.

The fix: set the locale where the SDK starts

  1. Confirm the cause with the inline test: LC_ALL=C before the usual start command.
  2. Make it stick in the shell you start from: export LC_ALL="C", then launch the SDK again.
  3. Pin the variable at the layer that actually starts the camera, or the fault returns at the next reboot: Environment=LC_ALL=C in the service unit, ENV LC_ALL=C in the container image definition, or -e LC_ALL=C passed at run time.
  4. Start through the vendor's launch file instead of the bare node. The launch file loads the robot description, the transform tree and the environment the driver expects; a bare-node start skips those steps and fails in ways that imitate calibration faults.
  5. Delete the cached per-serial .conf the error message named, so the next start downloads a fresh copy under the corrected locale. Restart.
  6. Verify: the log now prints camera model, serial number and firmware versions where the invalid-file error used to sit. Run locale once more in the same process environment if in doubt.

If the locale you want is not generated on the machine at all — locale -a lists what exists — install the distribution's locales package, run locale-gen for the locale you need and set it with update-locale. Generating a locale changes nothing by itself; what matters is the value LC_NUMERIC carries in the SDK's process.

Still rejected: the remaining causes, ranked

Ordered by how often each turns out to be the culprit:

  1. Corrupt or partial download. Test: read the first bytes. A calibration file starts with keys and digits; a proxy or captive-portal answer starts with an HTML tag. Re-download once — a second failure means the network path is rewriting the response, not a camera fault.
  2. Another unit's file. Test: compare the serial in the file name with the serial the SDK prints at start-up. Every camera is calibrated individually, so a sibling unit's file is invalid by design.
  1. A hand-edited or mixed-convention file. Test: reload a pristine download over your edits. When you move parameters between programs, compare the parsed numeric values rather than the text, as in How to compare camera calibration parameters across workflows.
  2. The calibration really is gone. Recalibrate with the vendor's tool and judge the result by the RMS reprojection error — vendor guidance treats about 1.0 px as the threshold for redoing a stereo calibration. If capture is the struggle, Fixing the checkerboard grid pitch covers the most common capture error, and Camera extrinsic calibration accuracy beyond reprojection error explains how to read the result.
  3. It never was the file. A camera that enumerates and then times out points at the transport: start with what to check when a USB3 camera falls back to a slower link on an embedded board, then a walkthrough for resolving USB3 camera driver conflicts between applications. If the camera opens but the node still hangs, Depth camera stuck at startup: check topic publishing first continues the diagnosis, and Vision application startup error: diagnose missing DLLs covers Windows machines that fail on missing libraries.

Prevention: pin the locale, keep one decimal convention

  • Pin the variable where it survives updates: the image definition or the service unit, never only your interactive shell. One line — ENV LC_ALL=C or Environment=LC_ALL=C — outlives every rebuild.
  • Keep one decimal convention for every text file exchanged in the plant: the period. Configure export tools to invariant or English formatting so a comma never enters a number.
  • Validate after load in your own code: require each rotation row to have norm 1, the matrix determinant to be +1, and fx to be positive. Three assertions catch a mangled file before it becomes a silent pose error.
  • Archive one known-good file per serial number, as described in Save camera calibration parameters for reliable reuse, so a damaged cache means a re-download rather than a recalibration.
  • Windows adds the same trap through the regional format: libraries that convert with the system culture read commas as decimals on comma regions. Run the acquisition process under an invariant culture and the same files load unchanged.

The decision, case by case

  • Invalid-calibration-file error in the log → run locale where the SDK runs. Comma in LC_NUMERIC or LC_ALL → LC_ALL="C" (or LC_NUMERIC="C"), delete the cached file, restart. One line, fixed.
  • Locale already period-based → check download integrity, then the serial match.
  • File loads but poses or depth are wrong → the file was edited or borrowed. Recalibrate and hold the result near or below about 1.0 px RMS.
  • Camera never enumerates at all → transport and drivers, not the file; start with the USB checks above.

If the camera itself turns out to be the weak link, compare replacements in the 3D sensors and area scan cameras categories. Free expert support comes with every order — the contact page starts it. The 3D topic page collects more start-up and integration fixes like this one.

Questions

Does LC_ALL="C" change anything else in my application?

It only affects processes started with that variable: messages come out in plain ASCII English and numbers use periods. Desktop language, dates, currency and every other program are untouched. If you want localized text elsewhere, set only LC_NUMERIC="C" — that category alone controls the decimal character used to parse and print numbers, and it is the minimal change that fixes the file.

Why did the same camera work yesterday and fail today?

Something in the environment changed, not the camera. A new container image, a language pack, a locale regeneration or an edited shell profile can set LC_NUMERIC to a comma-decimal value. Run locale in the environment that fails and in one that works, and compare the two outputs line by line. Also check whether the SDK updated, because a new parser meets the same file with new rules.

How do I read the locale of a service or node that is already running?

Find the process ID and read the environ file for it under /proc; each line is one VARIABLE=value entry. Container and service processes do not inherit your interactive shell's variables, so locale in your terminal can show a healthy period locale while the failing process runs under a comma locale. Test in the process's own environment, every time.

Can I just edit the commas into periods by hand?

You can for one test, but do not run production on an edited file. The SDK re-downloads over the cached copy at the next start, wiping the edit, and a hand-edited calibration carries no way to catch a mistyped digit. Fix the locale so every future download parses, and keep a pristine copy of the original file for reference.

The camera opens now, but depth looks slightly off. Is the calibration damaged?

Probably not. Once the locale fix lets the file parse, the values are exact; no half-parsed state is kept. Look for mechanical causes first: the camera was knocked, mounting shifted, focus or temperature changed, or the part sits near the depth range limit. If doubt remains, recalibrate and judge by the RMS reprojection error — a well-captured stereo calibration lands near or below about 1.0 px.