# Door robot arm (The Descent) A white industrial robot arm on a rail, modelled from the user's seven reference pictures (`reference/`), rigged and fitted to the moon pool's two doors. The user's words (2026-10-16): > 3d model this in blender. Understand the picture references and rig it accordingly and mechanically. according to the > open and close animation fit it to the scene. for the moon pool doors "Moonpool_Door_Fore", "Moonpool_Door_Aft" are the > door. also consider the rail accordingly. do 2 version with and without the grab limbs shown in the red lined picture > so there will be 2 versions side by side so I can change when I want. dont miss details > this will be standalone project dont add on the ship yet **It is not in the ship.** The ship file (`models/M_Ship_v2_interior_season2.blend`) was never touched. The doors, rails, deck, pocket walls and lamps are a reference copy (`source/ship_context_2026-10-16.blend`) so the arm could be fitted. ## Open it and switch versions Open `DoorRobotArm.blend` (Blender 5.2). It opens in the scene **`DoorArm | Showroom`**: both versions standing side by side on a floor rail, at rest (the pose of the first reference picture): version A (with the grab limbs) at x -1.9, version B (the plate from the red sketch) at x +1.9. The scene **`DoorArm | Ship fit`** holds the arms in the pocket under the deck, one per door, following the doors' own animation (frames 1-120, 30 fps). Play the timeline there. **Switching:** in the Ship fit scene, select the empty **`DoorArm | CONTROLS`** (collection `DoorArm | controls`, a wire cube over the moon pool). In Object Properties > Custom Properties: - **`version`**: 0 = A, the gripper with the grab limbs; 1 = B, the neck and plate drawn in red on ref6. Both doors' arms and fixtures switch together. The other version is hidden in the viewport and in renders. It is not evaluated while hidden, so its objects keep old positions until you switch back. That is normal. - **`grip`**: version A's fingers, 0 open .. 1 closed on the knob on the door (default 1). Collections: `DoorArm | version A`, `DoorArm | version B` (arms, cables, fixtures), `DoorArm | rail kit` (both rail kits and energy chains), `DoorArm | solver (hidden)` (the solver empties), `00 CONTEXT | from the ship` (reference only), `90 STUDIO | lights (not part of the asset)` (lights so the dark pocket shows in Rendered view), `DoorArm | collision` (UCX hulls, in the showroom, eye off). ## Scale, axes, pivots - Metres, Z up, the ship's own coordinates. The arm is large: 2.8 m tall upright, 3.75 m reach. - Arm frame A (the rest pose): origin at the turntable face centre, +X forward to the tool, +Y the arm's left, +Z up. In the ship the arm hangs upside down. Its root empty `DoorArm__` sits at (0, -5.795, -4.182), turned 180 deg about X, under the rail. - Every moving part is its own object. Its origin is on its joint. At rest its rotation is 0 and its scale 1. Joints (A frame, metres): | joint | what | pivot | axis | |---|---|---|---| | J1 | turret yaw | (0, 0, 0) | Z | | J2 | shoulder | (-0.341, 0, 0.517) | Y | | J3 | elbow, driven by the hydraulic cylinder | (-1.210, 0, 1.826) | Y | | J4 | forearm roll | (-0.077, 0, 2.0614) | X | | J5 | wrist pitch | wrist centre (0.957, 0, 2.0614) | Y | | J6 | flange roll | wrist centre | X (tool axis) | The J3 cylinder turns on its trunnion at the knee (-0.8646, 0, 0.847). Its piston's rod eye sits on the knob pin (-1.6764, 0, 1.4564). The carriage pinion turns as the carriage runs on the rack. Every pivot is in `DoorRobotArm_layout.json`. ## The rig: how the arm follows the door Nothing is keyed. Every moving part is driven from the door's location (the door keeps its own animation) by 604 drivers. Each is a simple expression, so the user's Blender runs them with Python auto-run off. - A chain of solver empties computes a closed-form inverse kinematics (DESIGN.md section 5): 1. **IK1** puts the carriage on the rail and the wrist centre in the arm's frame. 2. **IK2** turns the turret. 3. **IK3 and IK4** solve the shoulder and the elbow (elbow up, as in ref1). 4. **IK5 and IK6** solve the spherical wrist (J4, J5, J6), the cylinder's angle and its length. - The end of the arm holds its door rigidly the whole time, position and angle: - Version A's four fingers grip a knob fixture bolted to the door. - Version B's plate is bolted to a pad that follows the door's curve. - Version B's wrist centre sits 0.326 m off the door face (A: 0.63 m), so B has its own pose. - The door fixtures follow their doors (location = door + offset; the doors never turn). - The two energy chains (44 links each) are driven from the carriage's position. ## The rail The door slides 6.14 m into its pocket. The usable rail is 6.49 m long (from the pocket's end wall to the rail's inner end; past it is the moon pool's opening). The user's rail is a plain box fixed under the deck, so the arm hangs from a carriage that wraps the rail's visible part from below. The asset adds a rail kit (the user's rail itself is unchanged): - **Running gear:** two steel running flanges on the rail's sides, four load wheels, four counter-rollers, four side guide rollers. - **Drive:** a rack under the rail and a pinion on the carriage. - **End stops:** rubber buffers at both ends of the travel. - **Energy chain:** in a tray beside the rail. The carriage runs 5.10 m at 0.831 of the door's speed (c = A + B * door_x), so it reaches each end exactly when the door does. The arm's joints take up the rest. ## Checks (all pass) Run by script; the reports are in `build/`. - **`rig_report.json`:** frames 1-120 step 1, both doors, both versions. - The end against the door: position error 0.056 mm (A), 0.055 mm (B); angle 0.014 deg. - 0 crossings between any two arm parts. 0 against the deck, rails, end walls, hull lining, basin channel, aperture rim, lamps, both doors, the rail kit, chains and fixtures. 0 for the cables and hoses. - Joints inside their limits. Piston always in its bore. - Carriage inside its travel. Strike pads 3.5 mm short of the buffers. The arm at least 0.24 m (A) / 0.32 m (B) from the end wall. - Version switch correct (A, B and back to A). 604 drivers, all simple and valid. - **`geo_report.json`:** 0 n-gons, 0 open edges (the floating markings apart), 0 non-manifold edges, 0 crossings at rest. - **`geo_sweep.json`:** each joint through its range on the door path plus 3 deg, others at rest; J1 the whole circle; the grip closed on the knob. 0 hits. - **`fbx_report.json`:** every FBX re-imported headless and compared: - bones, meshes, triangles, materials and UCX hulls; - bounds within 0.1 mm; - no scale on any node, and the default pose equals the bind pose; - animations run frames 1-120. ## Surfaces and textures Materials (few): - **Arm:** `M_DoorArm_PaintWhite` (satin white powder coat), `_Orange`, `_Gunmetal`, `_BlackMetal` (the carriage's stacked plates), `_Steel`, `_Rubber`, `_Glass`, `_Lamp` (a faint indicator). - **Rail kits, fixtures and chain:** `M_DoorArmKit_*`. - **Cables and hoses:** `M_DoorArm_Cable`. Wear is low: the ship is clean. What each material is made of is in `build/surf_report.json` and in the layout json. | texture | from | licence | |---|---|---| | `source_polyhaven/textures/blue_metal_plate/*` (2K: colour, normal, roughness, AO): the relief, roughness and scuffs under the paint and the dark metals (only its light and dark, not its blue) | polyhaven.com/a/blue_metal_plate, fetched with curl | CC0 | | `source_polyhaven/hdris/studio_small_09_2k.hdr`: the showroom's light in the renders only | polyhaven.com/a/studio_small_09 | CC0 | | `models/vessel-interior/textures/ModSci_Engineer/Textures/Base/*`: StainedSteel (bright steel), ScratchedMetal roughness (rubber), Glass_DirtRough (smudges), T_Scratch_Norm (fine scratches) | the user's own Modular SciFi pack (already in the Unreal project), read in place | the pack's licence | | `textures/T_DoorArm_Masks.png` (R occlusion, G edges, B crevices) and `textures/T_DoorArm_BevelNormal.png` (OpenGL; flip green for Unreal), 4096 | baked from the model (Cycles) | own work | UV layers on every arm mesh: - **UV0 `UVMap`:** one atlas shared by all 20 arm meshes of both versions, 357 px per metre. - **UV1 `UV_Tile`:** metres, for the tiling sets. The ship context's door materials had missing images already in the ship. In this file they have plain stand-in colours (reference only). ## FBX for Unreal (`fbx/`) Convention as the project's other models: forward -Y, up Z, the data turned -90 deg about Z. Import with **Convert Scene** and **Force Front X Axis**, so Unreal = (x, -y, z) x 100 of the Blender data. The skeletal files are in centimetres with no scale on any node. | file | what | |---|---| | `SK_DoorRobotArm_A.fbx`, `_A_LOD1.fbx`, `_A_LOD2.fbx` | version A: skeleton (root + 19 bones, one per moving part, at its pivot) and one skinned mesh. Every part rigid on its bone; the elbow cables and cylinder hoses blended between their two parts. 189,547 / 95,690 / 39,342 triangles | | `SK_DoorRobotArm_B.fbx`, `_B_LOD1.fbx`, `_B_LOD2.fbx` | version B (root + 11 bones): 164,119 / 82,976 / 34,268 triangles | | `A_DoorRobotArm___OpenClose.fbx` | the door animation for each version and door, frames 1-120, baked from the rig. Place the skeletal mesh at the root's position: Blender (0, -5.795, -4.182) turned 180 deg about X = Unreal (0, 579.5, -418.2) cm with a roll of 180 deg (not tried in Unreal yet); the carriage bone carries the travel along the rail | | `SM_DoorRobotArm_Links.fbx` | every part as a static mesh at its pivot with its `UCX_` hulls (41), for a Blueprint build | | `SM_DoorArm_RailKit_.fbx` | the rail kits, ship coordinates | | `SM_DoorArm_Fixture_.fbx` | the door fixtures (origin on the door's attach point; attach to the door actor), with UCX | | `SK_DoorArm_Chain_.fbx` + `A_DoorArm_Chain__OpenClose.fbx` | the energy chains, one bone per link, ship coordinates | **LODs:** LOD0 keeps every detail (the user asked for every detail). LOD1 (about 50 %) and LOD2 (about 20 %) drop the markings and the small parts first (screws, clips: below 3 cm and 6.5 cm across), then reduce. Import them in Unreal as LOD 1 and 2 of the skeletal mesh (LOD Settings > Import LOD). `previews/lods_A.png`, `previews/lods_B.png` show the three side by side. **Collision:** the skeletal meshes get a Physics Asset in Unreal. The static parts carry `UCX_` hulls. **Materials:** they exist in Blender only. Rebuild them in Unreal from the table in `build/surf_report.json` and the textures above. `DoorRobotArm_layout.json` has every number a consumer needs: bones, parents and pivots, joint axes and limits with the ranges the doors use, the roots, the carriage's travel and schedule, the doors' attach points and face normals, the inverse-kinematics constants, the version switch and the materials. ## Pictures - `previews/cycles/`, Cycles: - the showroom at the angles of ref1, ref2 and ref3 (both versions, A alone, B alone); - close-ups like ref4, ref5, ref6 (A and B) and ref7; - the ship fit at frames 1, 12, 30, 48 and 90 for both versions and both doors; - `cycles_ship__switch.png` sheets (A row over B row); - `cycles_compare_sheet.png`: each reference beside its Cycles view. - `previews/geo/`: Workbench views beside each reference. `geo_compare_sheet.png` puts every reference next to its view. - `previews/rig/`: quick renders of the rig in the pocket. `rig_switch_.png` shows the switch. ## Rebuild Everything is made by script, headless, one stage per call: "E:\Steam\steamapps\common\Blender\blender.exe" -b --factory-startup --python build/dra_build.py -- --stage 1. **`build`**: geometry + rig + surfaces. It backs the file up into `versions/` first. 2. **`bake`**: the atlas maps. 3. **`ucx`** 4. **`export`**, then **`verify_fbx`** 5. **`render`** 6. Checks, any time: `rig_check`, `geo_audit`, `geo_sweep`. `STATUS.md` holds the history and the numbers. ## Not done - **Not in the ship, by the user's word.** To append it later: - Append the collections `DoorArm | version A`, `DoorArm | version B`, `DoorArm | rail kit`, `DoorArm | solver (hidden)` and `DoorArm | controls` into the ship file. They are at the ship's own coordinates. - The drivers read `Moonpool_Door_Aft` and `Moonpool_Door_Fore` by name, so in the ship they bind to the real doors. - Check the doors and rails have not changed since 2026-10-16. If they did, rerun the design scripts and the rig check. - Remove the user's four placeholder `rail carriage` cubes there; the carriage replaces them. - **Nothing tried in Unreal yet:** the import, the root placement, the materials, the Physics Asset. - **Still differs from the references:** the turret, upper arm and wrist block are layered and rounded now, but still simpler than the sculpted reference model. The lower arm's dark core is one block, not as finely stepped as ref5. - **The wrist's margin at its deepest bend** (frames 9-15 and 100-112, version A) is 3 deg with J6 on the door path. Other animations should keep J6 near 45 deg when J5 bends past -72 deg.