mickryley
feat: realsense cam hq
c9e1299
|
Raw History Blame Contribute Delete
40.6 kB

RealSense D400 series β€” the numbers this pod graph is built from

Every value in realsense_d400.hpodgraph comes from one of the four sources below. Nothing here is estimated from a photograph or inferred from a rendering. Where a number is not published, it says so and states exactly what was assumed instead.

Tag Source
DS RealSense Product Family D400 Series Datasheet, doc 337029-017, rev 021 (Oct 2025) and the Mar 2026 revision (which adds D436).
URDF realsense2_description xacro macros, IntelRealSense/realsense-ros, branch ros2-development β€” the vendor's own published frame tree.
D421 RealSense Depth Module D421 Datasheet v1.2.
D555 / D457 D555 PoE Datasheet v1.1, RealSense D457 Datasheet Dec 2025.
ASSUMED Not published by any of the above. The assumption is stated inline and the graph exposes the value as an editable parameter.

1. Frames and axes

Vendor frame (URDF)

The vendor publishes two datums per camera:

  • bottom_screw_frame β€” the centre of the 1/4-20 UNC tripod hole on the bottom face. This is the physical mounting datum.
  • camera_link β€” the depth origin, which the datasheet defines (Β§4.8.1) as "the X-Y center of the left imager", at the Z plane where depth reads zero.

URDF body axes are ROS: +X forward (out of the lens), +Y left, +Z up. Optical frames add rpy = (-Ο€/2, 0, -Ο€/2), giving the usual optical convention (+Z forward, +X right, +Y down).

Graph authoring frame

The graph is authored Z-up, converted once by a single SpaceTransform z_up β†’ y_up immediately before AssetOutput (pod is Y-up native; LuckyEngine is Y-up).

Authoring axes, Z-up:

Axis Meaning
+X the camera's right (so the right IR imager is at +X)
+Y the direction the camera looks (optical axis, out of the lens)
+Z up

SpaceTransform z_up β†’ y_up is a βˆ’90Β° rotation about X, i.e. (x, y, z) β†’ (x, z, βˆ’y). Applied to the axes above:

Authored (Z-up) After transform (engine, Y-up)
camera right +X +X β€” engine right
camera up +Z +Y β€” engine up
camera look +Y βˆ’Z β€” the direction a LuckyEngine camera looks

That last row is the load-bearing one. SceneCamera builds its projection with glm::perspectiveFov (Hazel/src/Hazel/Renderer/Camera.h), which is right-handed looking down βˆ’Z with +Y up. So an optical frame authored this way needs no rotation at all β€” a CameraComponent sitting on it with an identity local rotation points out of the lens.

Do not "fix" the optical frames by adding a 180Β° yaw. If a camera looks backwards, the SpaceTransform has been changed or removed β€” fix that instead.

Conversion used to derive the tables below

URDF ROS (x, y, z) β†’ authored Z-up (x', y', z'):

x' = -y      (ROS +Y is left; authored +X is right)
y' =  x      (ROS +X is forward; authored +Y is the look direction)
z' =  z

2. Optical module properties

Module Baseline Depth FOV HD 16:9 Depth FOV VGA 4:3 IR projector FOV Source
D401 18 mm H 84 / V 58 / D 92 β€” none (passive) DS 3-49
D415 55 mm H 65 / V 40 / D 72 H 50 / V 40 / D 61 H 67 / V 41 / D 75 DS 3-49
D430 50 mm H 87 / V 58 / D 95 H 75 / V 62 / D 89 H 90 / V 63 / D 99 DS 3-49
D450 95 mm H 87 / V 58 / D 95 H 75 / V 62 / D 89 H 90 / V 63 / D 99 DS 3-49
D421 50 mm H 75 / V 50 (Β±3) β€” yes D421 v1.2

FOV tolerance is Β±3Β° lens-to-lens (DS 3-49 note 3). Depth FOV is quoted at 2 m (20 cm for the D401).

3. Colour sensor properties

Sensor Used by Colour FOV Shutter Native
OV2740 D415, D435, D435i, D435f, D435if H 69 / V 42 / D 77 rolling 1920Γ—1080
OV9782 D436, D455, D455f, D456, D457, D555 H 90 / V 65 / D 98 global 1280Γ—800
(left imager via ISP) D405 H 84 / V 58 / D 92 global β€”

D405 has no separate colour sensor: its colour stream is the left imager through the ISP (DS table 4-4, "Color Stream from Left RGB via ISP"), which is why its colour and depth origins are the same point.

4. Per-model geometry

All offsets are authored Z-up millimetres from the 1/4-20 tripod-hole centre unless the datum column says otherwise. leftIR.x is negative because the left imager is to the camera's left.

Model Housing WΓ—DΓ—H (mm) Datum leftIR x rightIR x RGB x optical y (fwd) optical z IMU
D405 42 Γ— 23 Γ— 42 1/4-20 βˆ’9.0 +9.0 βˆ’9.0 (same as leftIR) 10.85 21.0 β€”
D415 99 Γ— 20 Γ— 23 1/4-20 βˆ’20.0 +35.0 βˆ’35.0 8.67 11.5 β€”
D421 95 Γ— 10.5 Γ— 32 module back-face centre βˆ’25.0 +25.0 β€” 10.5 16.0 β€”
D435 90 Γ— 25 Γ— 25 1/4-20 βˆ’17.5 +32.5 βˆ’32.5 10.60 12.5 β€”
D435i 90 Γ— 25 Γ— 25 1/4-20 βˆ’17.5 +32.5 βˆ’32.5 10.60 12.5 yes
D435f 90 Γ— 25.8 Γ— 25 1/4-20 βˆ’17.5 +32.5 βˆ’32.5 10.60 12.5 β€”
D435if 90 Γ— 25.8 Γ— 25 1/4-20 βˆ’17.5 +32.5 βˆ’32.5 10.60 12.5 yes
D436 90 Γ— 25 Γ— 25 1/4-20 βˆ’17.5 +32.5 βˆ’32.5 10.60 12.5 yes
D455 124 Γ— 26 Γ— 29 1/4-20 βˆ’47.5 +47.5 +11.5 11.15 14.5 yes
D455f 124 Γ— 26.8 Γ— 29 1/4-20 βˆ’47.5 +47.5 +11.5 11.15 14.5 yes
D456 124 Γ— 26 Γ— 29 1/4-20 βˆ’47.5 +47.5 +11.5 11.15 14.5 yes
D457 124 Γ— 36 Γ— 29 1/4-20 βˆ’47.5 +47.5 +11.5 11.15 (ASSUMED) 14.5 yes
D555 167 Γ— 48 Γ— 42 body centre (ASSUMED) βˆ’47.5 +47.5 +11.5 11.15 (ASSUMED) 21.0 yes

How each column was obtained

leftIR.x β€” DS tables 4-20/4-21/4-22 give "From centerline of 1/4-20 to left imager": D415 20 mm, D43x 17.5 mm, D45x 47.5 Β±0.1 mm, D405 9 mm. D457's own datasheet table 4-11 repeats 47.5 mm. Sign from URDF (*_cam_depth_py, ROS +Y = left) β†’ authored βˆ’x.

rightIR.x β€” leftIR.x + baseline. URDF *_cam_depth_to_infra2_offset is βˆ’baseline in ROS Y for every model, i.e. exactly one baseline to the camera's right.

RGB.x β€” URDF *_cam_depth_to_color_offset, in ROS +Y (left), negated:

Model URDF value (ROS +Y) Authored Ξ”x from leftIR
D405 0.0 0
D415 +0.015 βˆ’15 mm
D435 family +0.015 βˆ’15 mm
D455 family βˆ’0.059 +59 mm

Note the sign flip on the D45x line: on a D435 the colour lens is outboard of the left imager, on a D455 it is inboard, 11.5 mm to the right of the tripod hole. Getting this backwards puts the colour camera 118 mm out of place on a D455.

Consistency check (this is why the table can be trusted): on every model the outermost two optics land symmetrically about the tripod hole β€” D415 Β±35, D435 Β±32.5, D455 Β±47.5, D405 Β±9.

optical y (how far forward of the screw the depth origin sits) β€” (screw β†’ front face) βˆ’ (front glass thickness) βˆ’ |Z'|, where Z' is the datasheet "depth start point" (DS table 4-16/4-17) and the first two terms are URDF *_cam_mount_from_center_offset and *_glass_to_front:

Model screw→front glass Z' = optical y
D405 14.65 0.1 βˆ’3.7 10.85
D415 9.87 0.1 βˆ’1.1 8.67
D43x 14.9 0.1 βˆ’4.2 10.60
D45x 15.8 0.1 βˆ’4.55 11.15

The f variants (D435f/D435if/D455f) publish a 0.5 mm larger |Z'| (βˆ’4.7, βˆ’5.05) because the NIR filter moves the cover glass 0.5 mm forward, not because the imager moves. Their depth origin is therefore identical to the unfiltered sibling; only the housing gets 0.8 mm deeper. The graph models it that way.

The D415 is the one place the vendor URDF and the datasheet disagree: the xacro defines d415_cam_mount_from_center_offset = 0.00987 and then passes 0 for the link joint's X. The datasheet's Z' of βˆ’1.1 mm says the depth origin is not on the screw plane, so the graph uses the derived 8.67 mm. The discrepancy is 8.67 mm along the optical axis.

optical z β€” housing height / 2 for every model (URDF *_cam_depth_pz); the optical axis is on the housing's horizontal midline.

IMU offsets β€” URDF, relative to the depth origin, ROS (x, y, z):

Model URDF Authored Ξ” from leftIR (x, y, z)
D435i / D435if (βˆ’0.01174, βˆ’0.00552, +0.0051) (+5.52, βˆ’11.74, +5.10) mm
D455 family (βˆ’0.01602, βˆ’0.03022, +0.0074) (+30.22, βˆ’16.02, +7.40) mm

D436 has a 6DoF IMU (BMI085, DS table 3-56) but no published offset; the graph uses the D435i figures and marks them ASSUMED. D457 and D555 likewise reuse the D455 figures.

The four assumptions, stated plainly

  1. D436 colour offset. RESOLVED. The Mar 2026 revision carries a D436 mechanical drawing (figure 10-11) whose front view dimensions every aperture directly, and unusually gives as-built rather than nominal figures: baseline 49.95, projector 29.00, colour 15.05, and 17.45 from the 1/4-20 centreline to the left imager. The assumed 15 mm colour offset was right to within 0.05 mm. The graph keeps the nominal 15 / 50 / 17.5 for consistency with the rest of the D43x family; the difference is 50 Β΅m.
  2. D457 forward offset. Same D450 optics and cover-glass stack as the D455 (its datasheet repeats both the 47.5 mm and the βˆ’4.55 mm figures), but it does not publish where the 1/4-20 hole sits in its 36 mm-deep housing. The graph assumes the front face is where the D455's is (15.8 mm ahead of the screw) and puts the extra 10 mm on the back, where the GMSL connector is.
  3. D555 datum and layout. Its datasheet states it is "composed of the long range global shutter D450 optical module with IMU" and gives baseline 95 mm, so the intra-module layout is the D455's. It publishes no mounting datum at all. The graph references the D555 to the housing centre and centres the stereo pair on it.
  4. D421 datum. The D421 datasheet gives "left centre hole to left imager centre = 18.5 mm" but no drawing locating that hole in the 95 mm width. The graph follows the vendor URDF, which centres the stereo pair on the module and references it to the back-face centre.

5. Streaming modes β€” reference only

LuckyEngine cannot set these. They are shown in the graph's parameter panel so the recorder can be matched to them by hand. See README in the pod graph header.

Depth (Z16)

Models Resolution Frame rates (fps)
D415, D43x, D436 1280Γ—720 6, 15, 30
848Γ—480, 640Γ—480, 640Γ—360, 480Γ—270, 424Γ—240 6, 15, 30, 60, 90
D45x, D457 1280Γ—720 5, 15, 30
848Γ—480, 640Γ—480, 640Γ—360, 480Γ—270, 424Γ—240 5, 15, 30, 60, 90
D405 1280Γ—720 5, 15, 30
848Γ—480, 640Γ—360, 480Γ—270, 424Γ—240 5, 15, 30, 60, 90
D421 1280Γ—720 6, 15, 30
848Γ—480, 640Γ—480, 640Γ—360, 480Γ—270 6, 15, 30, 60, 90
D555 1280Γ—720 5, 15, 30
896Γ—504, 640Γ—360, 448Γ—252 5, 15, 30, 60

Colour (YUY2)

Models Resolution Frame rates (fps)
D415, D435, D435i, D435f, D435if 1920Γ—1080, 1280Γ—720 6, 15, 30
960Γ—540, 848Γ—480, 640Γ—480, 640Γ—360, 424Γ—240 6, 15, 30, 60
320Γ—240, 320Γ—180 6, 30, 60
D436 1280Γ—720 6, 15, 30
848Γ—480, 640Γ—480, 640Γ—360, 480Γ—270 6, 15, 30, 60
424Γ—240 6, 30, 60
D45x, D457 1280Γ—800 5, 15, 30
848Γ—480, 640Γ—480 5, 15, 30, 60
640Γ—360, 480Γ—270, 424Γ—240 5, 15, 30, 60, 90
D405 1280Γ—720 5, 15, 30
848Γ—480, 640Γ—360, 480Γ—270, 424Γ—240 5, 15, 30, 60, 90
D555 1280Γ—720 5, 15, 30
896Γ—504, 640Γ—360, 448Γ—252 5, 15, 30, 60

Source: DS tables 4-2 … 4-5 (Mar 2026 rev), D421 v1.2, D555 v1.1. The D436 and D555 product pages advertise "up to 1280Γ—800" colour; the datasheet streaming tables cap the USB colour stream at 1280Γ—720 and list 1280Γ—800 as the calibration format only. The tables above follow the datasheet.

Minimum-Z (mm) β€” DS table 4-11

Resolution D415 D43x/D436 D45x/D457 D405
1280Γ—720 450 280 520 100
848Γ—480 310 195 350 70
640Γ—480 310 175 320 β€”
640Γ—360 240 150 260 55
480Γ—270 180 120 200 45
424Γ—240 160 105 180 40

D421: ~200 mm at VGA (D421 v1.2). D555: ~260 mm at VGA, ~520 mm at max resolution, ideal range 0.6–6 m (D555 v1.1).

Depth quality β€” DS table 4-14

Z-accuracy Β±2 % for every model; fill rate β‰₯99 % (β‰₯99.5 % D405); RMS spatial noise ≀2 % (≀1 % D405); temporal noise ≀1 % (≀0.5 % D405). Quoted within 80 % of the depth FOV, at ≀2 m (D415, D43x), ≀4 m (D45x), ≀0.5 m (D405).

These are what the graph seeds DepthSensorParams from β€” see Β§6.

6. Mapping onto LuckyEngine's depth sensor model

Hazel::Data::DepthSensorModel::ActiveStereo is described in Hazel/src/Hazel/Data/DataTypes.h:265 as "RealSense-style active-IR stereo: zΒ² disparity noise, specular dropout, occlusion shadows" β€” it is the right model for every camera in this pack except the D405, which is passive (DS table 4-14 note 4: "KPIs for D405, a passive camera, are measured using a textured target"). ActiveStereo is still the closest available model for the D405; the difference is that its noise should not be assumed to improve with projector power.

DepthSensorParams fields and the value this pack recommends:

Field Meaning Value
Baseline virtual stereo baseline, drives zΒ² noise and occlusion width the model's real baseline (table Β§4)
MinRange near blind zone Min-Z at the resolution you are recording (table above)
MaxRange beyond this the sensor returns nothing D405 0.5 m, D415 3 m, D43x 3 m, D45x/D457/D555 6 m
SubpixelSigma disparity 1-sigma noise, px 0.08 default; the datasheet quotes error as a % of Z, not in disparity px, so this is left at the engine default
DetectFloor angular return fraction below which a pixel drops out 0.03 default

MaxRange uses each model's stated ideal range, not an absolute maximum: D405 "0.7 m" max ideal (DS quality spec measured ≀0.5 m), D415/D43x ≀3 m, D45x ≀6 m, D457 "0.6 m to 6 m", D555 "60 cm to 6 m".

DepthScale (metres per uint16 code) should be picked as MaxRange / 65535 rounded up β€” the Settings panel tooltip says the same thing. For a 6 m D455 that is 0.0001 m/code; for a 0.5 m D405, 0.00001 m/code. The engine default of 0.001 wastes 99 % of the 16-bit range on a close-in camera.


7. The IR projector

The projector is not a stream, so it has no librealsense extrinsic and it appears in no URDF. It is dimensioned on the datasheet mechanical drawings, whose front views carry an aperture chain measured from the left imager:

Model Projector offset from the left imager Source
D405 none β€” passive DS 3-49, "IR Projector: N/A"
D415 28 mm DS figure 10-8
D435 / D435i / D435f / D435if 29 mm DS figure 10-9
D436 29.00 mm DS figure 10-11 (as-built)
D455 / D455f / D456 37.5 mm DS figure 10-12
D457 37.5 mm (ASSUMED) same D450 optical module as the D455
D555 37.5 mm (ASSUMED) same D450 optical module (D555 v1.1 says so outright)
D421 29 mm (ASSUMED) not published; a wide 50 mm-baseline module, so the D43x value

Reading those chains also re-derives the numbers in Β§4 from a source independent of the URDF, and they agree: the D435 sheet gives (17.5) to the left imager, (15) to the colour imager and (50) to the right imager; the D415 sheet gives (20), (15) and (55); the D455 sheet gives (47.5), (59) and (95), plus IMU callouts of (30.22), (βˆ’7.4) and Z (βˆ’16.02) that match the URDF's d455_imu_p* exactly.

The direction is the same on every sheet: all dimensions run from the left imager, and the projector sits between the two IR imagers β€” so its offset is positive in the authored frame (toward the camera's right), unlike the colour imager, which is negative on everything except the D45x.

Why the graph emits it as a frame rather than only as an aperture. The projector is a second viewpoint. A surface the stereo pair can both see but the projector cannot reach gets no pattern, so an active stereo camera drops out in the projector's shadow as well as in the stereo occlusion that DepthSensorParams::Baseline already models. Those are different shadows with different geometry, and only the projector frame carries the second one.

8. Manufacturer 3D models β€” what exists

Checked so a proxy can be swapped for the real shape. There is no manufacturer FBX, OBJ or glTF for any of these parts.

Official CAD, from https://dev.realsenseai.com/docs/cad-files/:

Download Contents Format
D400 Depth Cameras D405, D415, D435, D435f, D435i, D455, D455f, D456, D457 SolidWorks .SLDPRT
D555 Camera D555_SOLID_SOC.STEP (37.6 MB) STEP β€” open, directly convertible
D400 Depth Modules D401, D415, D430, D450 SolidWorks .SLDPRT

No D436 and no D421 in the CAD set. .SLDPRT is proprietary and needs SolidWorks or a commercial converter; the D555 STEP is the only one usable without one.

Vendor mesh assets, from realsense2_description/meshes in IntelRealSense/realsense-ros (open, already tessellated, Apache-2.0):

File Size
d405.stl 195 kB
d415.stl 21.3 MB
d421.stl 20 kB
d435.dae, d436.dae 15.8 MB each
d455.stl 2.6 MB
d585.stl 7.0 MB

These are the practical swap-in candidates. Two things to know before swapping:

  1. They are outer shells with no optics. d455.stl and d405.stl were placed into this graph's frame and rendered front-on: a rounded housing, a flat recessed front window, and no lens apertures or projector window at all. Swapping one in gives a more accurate silhouette and fewer visual cues than the proxy in this pack, which at least shows which opening is which.
  2. They independently confirm Β§4. Placed through the URDF's own visual transform, d455.stl measures 124 Γ— 26 Γ— 29 mm and d405.stl 42 Γ— 23 Γ— 42 mm; both straddle the tripod datum in X, put the optical axis on the housing's vertical midline, and put the front face 4.65 mm / 3.80 mm ahead of the depth origin β€” which is exactly front_y βˆ’ opt_y in Β§4 for each.

9. The model name engraved into the top face

The proxy cuts the selected model's name into the top of the housing so a scene full of cameras can be read without selecting each one. It is a real boolean cutout of the text -- a round-bottomed groove one stroke radius deep -- and getting there took two fixes in pod rather than anything in this graph.

Why it did not work at first

pod's text comes from StringToCurves, whose glyph table is a 36-character stroke font: open polylines, not closed outlines. CurveToMesh gives those thickness by sweeping a round profile, so a glyph is a set of tubes, and the tubes pass through each other wherever two strokes meet. pod's MeshBoolean is Manifold, and Manifold's boolean arranges operand A against operand B; it never arranges one operand's shells against each other. Those crossings survived into the result as interior faces, and a Difference with the text came back with a lid of degenerate slivers where the groove should have been.

Blender's exact solver does not have this problem because it arranges every face against every other before classifying by winding number, which is why a text cutout "just works" there. Manifold exposes the same capability as Decompose() (split shells by connectivity) plus BatchBoolean(Add) (arrange them against each other); it just has to be asked.

The two pod fixes

  1. MeshBoolean resolves each operand against itself first (pod/src/Nodes/Boolean.cpp, ResolveSelfOverlap). Decompose, batch-union, then the real boolean. A single-shell operand -- nearly every operand there is -- is handed straight back, so the common path pays one Decompose and no boolean. MeshBooleanList folds through the same code, so it gets it too. Regression tests assert the volume removed by a self-overlapping tool, which is the number a leftover lid gets wrong.

  2. StringToCurves splits closed-loop glyphs (pod/src/Nodes/Curves.cpp). 0, 6, 8, O and their like are one stroke that ends where it began. Swept, that tube's first ring is perpendicular to the outgoing segment and its last to the incoming one, at the same centre, so its two end caps cross inside a single shell -- the one case fix 1 cannot reach, and 0 left exactly one sliver at every stroke radius tried. A loop is now emitted as two open strokes overlapping by one segment: each cap lands inside the other tube and the crossing is between two shells, which fix 1 resolves. A stroke renderer draws the same ink.

Both were found by measurement, not reasoning: cut each glyph into a box alone and count downward-facing triangles in the cut plane. Before: D 0 3 4 6 8 9 F all bad. After fix 1: only 0 6 8 9. After fix 2: only 6 9, which are open hooks whose spine turns faster than a 0.45 mm tube can follow -- a genuine sweep limit, and no model name uses either. Subdividing, resampling or filleting the curve makes that worse (shorter segments beside the same turn), so it is left alone.

How the right name is selected

pod cannot switch a string on an index (IndexSwitch has Geometry, Float, Bool and Material variants and no string one; a Menu knob carries an Identifier no expression can reach). So all thirteen cutters are built at the same spot and the geometry is switched: two chained IndexSwitch nodes (ten slots each) forward one into the Difference. The second index is max(0, model - 9), a Float expression feeding an Int pin, which rounds (pod/src/Evaluator.cpp:234). The twelve unselected chains still evaluate and are dropped; the whole graph is ~11 ms.

Sizing and orientation

Cap height is min(label_cap, body_d * 0.34); the clamp is what lets the 7.5 mm default fit the 10.5 mm-deep D421. label_cut is the profile radius: half the stroke width and exactly the groove depth, because the tubes are centred on the top face and the inside half is what the boolean removes.

Text is built reading along +X (the camera's own right), so unrotated it reads from behind the unit. label_rot defaults to a yaw of pi so it reads from in front, where you stand to check what a camera is pointing at. The yaw is safe only because the group aligns the text Middle in Y as well as Center in X, putting the origin at the centre of the cap box.

Checks

tools/check_marking.py measures the cut on all thirteen models: nothing above the top face, a groove exactly one stroke radius deep, zero downward- facing triangles in the top plane (the lid a failed cut leaves), and a groove no wider than one name. tools/verify_marking_selection.py proves the switch chain by overriding the names with N-stroke markers and recovering N from the groove width. Both isolate the groove geometrically, since it is cut into the housing and has no material of its own.

pod's glyph table is uppercase only, so D435i is spelled D435I.

10. Mounting hardware and threads

Everything here is read off the vendor mechanical drawings, not inferred. Sources are the D400 series datasheet 337029-017 (October 2024) figures 10-8 through 10-14, the D457 datasheet 337029-011 (August 2025), the D421 datasheet v1.2 and the D555 datasheet v1.1. Positions are authored Z-up millimetres from the same datum as section 4 - the 1/4-20 tripod centre, except on the D421 and D555.

The two mounting systems, and which face each is on

Every camera in this pack (not the D421 module) carries two independent mounting provisions, and they are on different faces:

  1. A 1/4-20 UNC tripod hole on the BOTTOM face. This is the pack's datum and was already modelled; what is new here is its thread depth.
  2. Two threaded holes on the BACK face, straddling the tripod centreline. This is the load-bearing one for a bracket - the D457 datasheet calls the back "the Rear Mounting Surface" and specifies a flatness tolerance for it (Table 3-20, 0.1 mm), and Β§3.8.2.2 of 337029-017 recommends bracket mounting through these screws rather than the tripod.

The back, not the bottom. Worth stating because the D435's drawing alone cannot prove it: that camera is 25 mm high and 25 mm deep, so its back and bottom views are the same size. The D415 (20 deep, 23 high) and the D455 (26 deep, 29 high) are not square in section, and on both the screw view measures the HEIGHT - 23 and 29 - so the screws are on the back. The D435 is the same drawing convention and the same logo placement, so it follows.

Per model

Model Back-face screws Pitch (mm) x from datum Max insert Tripod 1/4-20
D405 2 x M-unread 20.00 +/- 10.00 not readable yes, 5.0 mm
D415 2 x M3 45.00 +/- 22.50 3 mm yes, depth not published
D421 2 x M3 through + 4 x d3.10 corner 87.00 x 24.00 +/- 43.50 through none
D435 2 x M3 45.00 +/- 22.50 3 mm yes, depth not published
D435i 2 x M3 45.00 +/- 22.50 3 mm yes, depth not published
D435f 2 x M3 45.00 +/- 22.50 3 mm yes, depth not published
D435if 2 x M3 45.00 +/- 22.50 3 mm yes, depth not published
D436 2 x M3 (INHERITED) 45.00 +/- 22.50 3 mm yes, depth not published
D455 2 x M4 95.00 +/- 47.50 4 mm yes, 9.0 mm
D455f 2 x M4 95.00 +/- 47.50 4 mm yes, 9.0 mm
D456 2 x M4 95.00 +/- 47.50 4 mm yes, 9.0 mm
D457 2 x M4 (pitch INHERITED) 95.00 +/- 47.50 4 mm yes, depth not published
D555 2 x M4 125.40 +/- 0.20 +/- 62.70 6 mm not shown on its datasheet

Recommended torque: 0.4 Nm for the M3 pairs (figures 10-8, 10-9); the D457's M4 inserts withstand <= 3.0 Nm (M4 zinc-plated class 8.8 SHCS); the D421's module screws should not exceed 5 kgf*cm.

Height on the back face

Measured from the drawings rather than assumed: the screw pair sits on the back face's horizontal centreline on the D415, D435 and D455, i.e. at the housing's mid-height. On the D405's 42 x 42 back face the pair is centred both ways.

That the pair straddles the tripod axis was measured, not assumed

The D435's figure 10-9 does not dimension the screws against the 1/4-20 - it only gives the 45 mm pitch. Taking the drawing's own pixels at 900 dpi, the midpoint of the screw pair lands at 756.0 and the midpoint of the body outline at 756.75, i.e. they coincide to 0.07 mm at that scale. The optics are already known to be symmetric about the tripod centreline (section 4 dimensions them from it), so the body centre IS the tripod axis, and the screws straddle it. This also explains why the D415 and the D435 share a 45 mm pitch despite different widths and different baselines: the pattern is referenced to the common datum so one bracket fits both.

USB cable retention

Not a mounting provision for a bracket, but it is on the same faces and will be in the way of one. The D455 carries 2 x M2 beside its USB-C on the BOTTOM, with the connector centre 37.01 mm from the 1/4-20 toward the camera's RIGHT. The D405 carries 2 x M2x0.4 18.00 mm apart beside its screw-locked USB 3 Micro-B (not a USB-C) on its left side. Both are now modelled -- as cable-lock holes in the Detailed housing -- see section 12.

The D421 is a bare module and mounts differently

It has no tripod hole. Its datasheet gives 2 x M3 threaded-through holes on the horizontal centreline and 4 non-threaded d3.10 corner holes on an 87.00 x 24.00 pattern, to be bolted to a flat heat sink.

This resolves one of the pack's assumed datums. Section 4 previously carried the D421's datum as "back-face centre (ASSUMED)". The datasheet states the real reference: "the Depth module D421 origin reference from the left centre hole to the left imager centre is 18.5 mm". The left centre hole is the left M3 at x = -43.5, so the left imager is at -43.5 + 18.5 = -25.0 - which is exactly the value the pack already carried. The number was right; it is no longer an assumption.

What is still not published

Carried as gaps rather than invented:

  • The D405's back-face thread size. Its figure 10-13 calls out "2X M?x?.? MAXIMUM INSERT ?mm", but the datasheet's embedded drawing raster is only 1020 x 1320 px for the whole sheet and that annotation does not survive at any magnification. The 20.00 mm pitch and the hole positions are legible; the thread is not. Modelled as M3, the smaller of the two sizes used elsewhere in the family, so a bracket designed against it will not foul an M4 boss.
  • Tripod thread depth on the D415, D435 family, D436 and D457. Only the D405 (5.0 mm) and the D455 (9.0 mm) state it. Modelled at 5.0 mm, the shallower published figure, for the same reason.
  • The D436's screw pattern. The D436 is not in 337029-017 and its own datasheet has no mechanical drawing. It shares the D435's 90 x 25 x 25 housing and every optical offset, so the D435's pattern is inherited.
  • The D457's screw pitch. Its datasheet states 2 x M4 on the rear mounting surface and the torque limit, but its mechanical-drawing page renders blank. It shares the D455's 124 x 29 back face, so the D455's 95 mm is inherited.
  • Whether the D555 has a 1/4-20 at all. Its datasheet shows only the 2 x M4 at 125.40. A FRAMOS product listing claims one 1/4-20 and two M3, which contradicts the vendor drawing on the thread size; the drawing is preferred and the tripod is left out rather than guessed at.

11. Sources

12. Quality: the Detailed housing and the real ports

The graph carries a quality switch (Camera group, Proxy / Detailed, default Proxy). Everything it adds is generated by tools/gen_detail.py and appended AFTER every existing parameter, because pod lowers parameters to nodes in document order and a scene's per-instance override binds a knob by that node id. Checked by dumping the lowered graph before and after: all 129 existing parameter nodes keep their ids, model is still 905, quality is 1144.

Both qualities keep every body, frame and the collision box exactly where they were. Only the render mesh changes.

Proxy (quality 0)

The housing above, unchanged, plus an opening cut 2 mm into it for every connector the model has, at the connector's real position and orientation, with a bright steel plate at its floor (mat_port_hint) so a dark opening in a dark housing still reads. The covered sync-port slot is indicated the same way on the top face.

Detailed (quality 1)

The housing is a rounded rectangle in front view -- a STADIUM (radius = half the height) on every model except the D405's rounded square and the D421 module's box -- clipped by two elliptic cylinders: one along X that domes the top and rounds the bottom-front edge, one along Z that pulls the ends in toward the front and back. The numbers are fitted to the vendor meshes of section 8 (silhouette extents binned along each axis, each fit checked at three or more depths):

Model Front outline Dome (along X) Ends (along Z) Source
D405 rounded square, r 6 mm (17.37 at 0.5 mm from the end, 19.61 at 2.5) none: flat none d405.stl
D415 stadium, r 11.5 top 11.5 -> 9.63 at the front: semi-axis 26.8, crown 15.4 behind the front 49.5 -> 47.61: semi-axis 53.4 d415.stl
D435 family, D436 stadium, r 12.5 12.5 -> 10.05: 31.1 @ 19.5 (predicts 11.76 at 8.7 back, measured 11.64) 45 -> 42.54: 58.3 d435.dae
D455, D455f, D456 stadium, r 14.5 14.5 at 12 back -> 12.34 front, 11.94 back: 22 @ 12 62 -> 59.84 / 59.32: 45 d455.stl
D457 stadium, r 14.5 30 @ 15 60 ASSUMED: no mesh; D457 datasheet fig 3-7 shows the D455's domed silver body, deeper
D555 stadium, r 21 60 @ 24 110 ASSUMED: no mesh; its datasheet cover photograph
D421 box, 1 mm corners none none bare module

Every mesh measures the bottom FLAT at the back and rounded only at the front. The flat part starts at the dome's crown: the meshes put its start a little further forward, but starting it there leaves a kink of up to 8 degrees and a 0.8 mm step where the dome's underside meets it.

The front is black gloss glass in a 1.0-1.5 mm aluminium frame, following the housing's front outline, with a ring and a lens disc on it at every aperture of section 4 (the same has_rgb_lens / has_projector rules as the proxy).

The housing is bead-blasted silver aluminium (mat_alu) on the D4xx, and mat_dark_body on the D555 -- dark grey in its datasheet photograph -- and on the bare D421 module.

The ports are pod's own connector graphs (assets/connectors in the pod repo, copied into groups/: usb_c_receptacle, usb3_micro_b_receptacle, rj45_jack, fakra_jack), each set into a pocket cut to its outline:

Model Connector Where Source
D405 USB 3 Micro-B, 2 x M2x0.4 cable-lock holes 18.00 apart LEFT side face, long axis vertical, at mid-height, 6.82 forward of the rear face DS fig 10-13; the vendor mesh has the 12 mm slot exactly there, on its +x face, which the URDF's rpy (pi/2, 0, pi/2) makes the camera's left
D415, D435 family, D436 USB-C, vertical on the floor of an OPEN POCKET in the back face at the camera's RIGHT end, x from +36 to the end, 8 mm deep; socket centred at x = +40 a mid-height section of d415.stl (open end cap, socket at mesh x = -40); the rear views of DS fig 10-8 and 10-9 draw that end cap. D43x pocket depth ASSUMED from the D415 (the d435.dae is too fragmentary to section there)
D455, D455f, D456 USB-C, 2 x M2 cable-lock holes BOTTOM face, 4.06 from the rear edge, 37.01 from the 1/4-20 toward the camera's RIGHT, long axis along X DS fig 10-11 bottom view. It sits below the front view (third-angle projection), so it shares that view's orientation, and the front view puts the left imager at page-right. The lock holes measure 15.4 apart on the drawing; the USB-IF dual-lock pitch 15.00 is used
D457 USB-C as the D455 (its y is the D455's, ASSUMED); FAKRA on the rear, camera-LEFT end, 5 mm below the optical axis, x = -52 (ASSUMED) D457 datasheet fig 3-7: the blue FAKRA leaves the back at the end opposite the bottom USB-C
D555 RJ45 at the camera's RIGHT end of the bottom, USB-C at its LEFT end, tripod between; +/-48 mm, mid-depth (ASSUMED) BOTTOM face D555 datasheet v1.1 cover photograph; the lens order (camera-right imager, RGB, projector, left imager) fixes which end is which
D415, D43x, D436, D45x, D457 JST SH sync header, under a covered slot TOP face, centred in X: D415 18.3 x 3.6 at 16.2 behind the front; D43x 17.6 x 3.6 at 20.7; D45x and D457 22.4 x 4.4 at 22 the top views of DS fig 10-8, 10-9, 10-11, and D457 fig 7-12 "External Sensor Sync Connector". Drawn as the slot and its cover plate with a screw, because the header itself is under the cover
D421 none modelled the module's board connectors are not in the connector library

section 10's correction: the pod connector README first placed the D455's USB-C toward the camera's LEFT. The drawing says right, as above; the README is corrected.

Shading. The render mesh is smoothed by angle: 30 degrees on the Proxy, as it always was, and 12 on the Detailed housing (shade_angle). The detailed shell's dome and corners are faceted at 2.25 and 5.6 degrees, so they stay smooth; where the dome crosses the stadium ends the crease angle runs from 0 to 90 degrees, and at 30 every face under it was averaged across the flat faces' long boolean triangles. Measured on the exported normals: faces bent more than 8 degrees from their own plane, 8.0% of the D435i housing's area at 30 degrees, 0.7% at 12. (pod's midui editor viewport does not read these per-corner normals -- it averages every face at a vertex -- so it shows smears on BOTH qualities that neither the export nor LuckyEngine has.)

The D457's engraved name moved. Its 36 mm top carries the sync slot 22 mm back, and a centred name cut straight through it; label_y now keeps a tripod-datum model deeper than 27 mm (only ever the D457) 13.5 mm behind the front. check_marking.py and verify_marking_selection.py measure the groove only within the name's own band, so the slot is not read as part of it; both pass on all 13.

Checks

tools/verify_models.py (all 13 bodies on their table values), tools/check_mounts.py (every screw and tripod hole cut to its published depth), tools/check_marking.py, tools/verify_marking_selection.py and tools/check_coplanar.py all pass on the default (Proxy) graph. Every model bakes at both qualities in about 0.3 s; the Detailed housing's extents equal the published housing dimensions exactly (the ports sit inside them).

Still open

  • The D405's back-face screws: at 600 dpi the October 2025 drawing reads "2X M3x0.5, MAXIMUM INSERT 4.0mm". Section 10 carries the thread as unreadable and the graph models 3 mm; not changed here.
  • The D436's two stacked cable-lock screws: position and pitch not dimensioned; not modelled.
  • The D555's port positions and the D457's FAKRA position are photograph-level estimates, stated as ASSUMED above.

13. Graph layout and recording settings (pack 1.1)

The camera graph is arranged into labeled frames for the proxy housing, engraving, mounting holes, detailed housing and optics, each connector family, assembly, optical and mounting frames, the collision box, and output. Connector helper graphs have separate frames for their shells, inserts, contacts, locking features, and assembly. Smaller shape helpers have a single workflow frame.

This layout changes no camera dimensions, optical transforms, materials, quality defaults, render roles, or collision behavior. The top-level authored ID ceiling remains 904: model stays on node 905 and quality stays on node 1144. Existing scene overrides therefore keep their bindings. The thirteen generated model-name strings have native editor positions beside their engraving nodes. Folded numeric and parameter nodes remain hidden by the editor's default display settings.

Resolution and FPS are configured per camera in Settings > Data > Camera Bindings. For one recorded image per data step, use the same frequency for every recorded camera, the Capture runner, and the data recorder. These graph parameters describe the camera body and optical frames; they do not configure recording. Enable Invisible to Cameras in the Pod component to exclude its generated housing from captures while retaining it in the editor viewport.