# Discovery Scan Station Organ **Version**: 1.0 **Status**: 🟑 Planned (hardware design phase) **Location**: Crafting table area (intake point for new items) > *"Every object that enters dafit's world passes through here first."* --- ## Overview The Discovery Scan Station is a **lifeforce-generating organ** that systematically scans objects to build Young Nyx's world model. It consists of a rotating pedestal and a fixed camera, controlled through state machine cells. **Purpose**: Controlled environment for rapid, verified object learning **Position**: Near the crafting table where new items arrive **Philosophy**: Objects are introduced, not discovered randomly β€” systematic knowledge accumulation --- ## Hardware Architecture ``` SIDE VIEW TOP VIEW ───────── ──────── β”Œβ”€β”€β”€β”€β”€β”€β”€β” β”‚CAMERA β”‚ ← Fixed position β—‹ Camera β”‚ (eye) β”‚ looking down β”‚ β””β”€β”€β”€β”¬β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ ~30cm β–Ό β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β–Ό β”‚ β”Œβ”€β”€β”€β”€β”€β” β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ OBJ β”‚ β”‚ β”‚ β”‚ OBJ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ PEDESTAL β”‚ β”‚ ↻ β”‚ ← Rotates β”‚ (rotates) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β” β”‚ SERVO β”‚ β”‚ STEPPER β”‚ β”‚ (motor) β”‚ β”‚ or β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ SERVO β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Components | Component | Specification | Purpose | Est. Cost | |-----------|---------------|---------|-----------| | **Camera** | ESP32-CAM or USB webcam (1080p+) | Capture object from above | €10-30 | | **Pedestal** | 3D printed turntable, ~15cm diameter | Hold objects for scanning | €5 (filament) | | **Motor** | Stepper (28BYJ-48) or Servo (MG996R) | 360Β° rotation in steps | €5-10 | | **Controller** | ESP32 or integrated with main system | State machine execution | €5-10 | | **Lighting** | Ring light or diffused LEDs | Consistent illumination | €10-20 | | **Frame** | 3D printed or aluminum extrusion | Structural support | €10-20 | **Total estimated cost**: €45-95 ### Physical Dimensions ``` Footprint: ~25cm Γ— 25cm Height: ~40cm (camera above pedestal) Pedestal: 15cm diameter, 2cm height Camera height: 30cm above pedestal surface Rotation: 360Β° in 12 steps (30Β° each) or continuous ``` --- ## Cell Architecture ### Cell 1: Pedestal Servo Cell ```python class PedestalServoCell(StateMachine): """ Motor cell wrapping the rotating pedestal. Provides precise angular positioning for multi-view capture. """ cell_type = "motor" cell_name = "pedestal_servo" states = [IDLE, ROTATING, POSITIONED, HOMING, ERROR] outputs = { "current_angle": float, # 0.0 - 360.0 degrees "target_angle": float, # Commanded position "at_target": bool, # Within tolerance "rotation_complete": bool, # Full 360Β° cycle done "step_count": int, # Steps completed in current scan "state": str, } costs = { (IDLE, HOMING): 0.5, # Return to 0Β° (IDLE, ROTATING): 0.3, # Start rotation (ROTATING, POSITIONED): 0.1, # Settle at target (POSITIONED, ROTATING): 0.2, # Next step (POSITIONED, IDLE): 0.0, # Scan complete (ANY, ERROR): 0.0, } config = { "step_degrees": 30.0, # Degrees per step "total_steps": 12, # Steps for full rotation "settle_time_ms": 300, # Wait after movement "position_tolerance": 1.0, # Degrees } # Commands def home(self): """Return to 0Β° position.""" self.target_angle = 0.0 self.transition_to(HOMING) def rotate_step(self): """Advance by one step.""" self.target_angle = (self.current_angle + self.config["step_degrees"]) % 360 self.step_count += 1 self.transition_to(ROTATING) def rotate_to(self, angle: float): """Rotate to specific angle.""" self.target_angle = angle % 360 self.transition_to(ROTATING) ``` ### Cell 2: Scan Camera Cell ```python class ScanCameraCell(StateMachine): """ Sensor/organ cell wrapping the overhead camera. Captures frames and generates semantic vectors via SigLIP. """ cell_type = "organ" cell_name = "scan_camera" states = [IDLE, WARMING, CAPTURING, PROCESSING, REPORTING, ERROR] outputs = { "frame": Image, # Raw captured image "semantic_vector": Vector, # SigLIP embedding (768 dim) "capture_angle": float, # Pedestal angle when captured "object_detected": bool, # Something on pedestal? "bounding_box": BBox, # Object location in frame "confidence": float, # Detection confidence "state": str, } costs = { (IDLE, WARMING): 0.2, # Camera warm-up (WARMING, CAPTURING): 0.3, # Take photo (CAPTURING, PROCESSING): 2.0, # SigLIP inference (GPU) (PROCESSING, REPORTING): 0.1, # Package results (REPORTING, IDLE): 0.0, # Ready for next (ANY, ERROR): 0.0, } config = { "resolution": (1920, 1080), "format": "RGB", "exposure_auto": True, "white_balance_auto": True, "siglip_model": "ViT-B/16", # SigLIP variant "vector_dim": 768, } # Commands def capture(self, angle: float) -> Image: """Capture single frame, record angle.""" self.capture_angle = angle self.transition_to(CAPTURING) # Hardware captures frame self.transition_to(PROCESSING) # SigLIP generates vector self.transition_to(REPORTING) return self.frame def get_vector(self) -> Vector: """Return most recent semantic vector.""" return self.semantic_vector ``` --- ## Nerve Architecture ### Discovery Scan Nerve ```python class DiscoveryScanNerve(StateMachine): """ Behavioral nerve orchestrating a complete 360Β° discovery scan. Composes pedestal_servo + scan_camera cells. Generates lifeforce through verified discoveries. """ nerve_name = "discovery_scan" required_cells = ["pedestal_servo", "scan_camera"] optional_cells = [] states = [ IDLE, # Waiting for scan request INITIALIZING, # Homing pedestal to 0Β° READY, # Ready to scan (waiting for object) SCANNING, # Main scan loop active ROTATING, # Moving to next angle SETTLING, # Waiting for vibration to stop CAPTURING, # Taking photo at current angle PROCESSING, # Generating semantic vector VERIFYING, # Comparing to Blender ground truth COMPLETE, # Full scan done, reporting results ERROR, # Something went wrong ] config = { "rotation_steps": 12, # 30Β° each "step_degrees": 30.0, "settle_time_ms": 300, "capture_timeout_ms": 5000, "require_object_detected": True, } # Scan state vectors_collected: list[Vector] = [] angles_captured: list[float] = [] current_step: int = 0 scan_start_time: datetime = None # Rewards REWARD_NEW_OBJECT = 20.0 # First time seeing this object REWARD_PER_DIMENSION = 5.0 # Each verified dimension (x, y, z) REWARD_PER_VECTOR = 2.0 # Each angle captured REWARD_PARTNERSHIP_BONUS = 5.0 # dafit presented the object async def execute_full_scan(self, object_hint: str = None) -> ScanResult: """ Execute complete 360Β° discovery scan. Args: object_hint: Optional name/class hint from dafit Returns: ScanResult with vectors, verification, rewards """ self.scan_start_time = datetime.now() self.vectors_collected = [] self.angles_captured = [] self.current_step = 0 # Phase 1: Initialize self.transition_to(INITIALIZING) await self.command_cell("pedestal_servo", "home") await self.wait_for_cell_state("pedestal_servo", POSITIONED) # Phase 2: Ready (optional wait for object placement) self.transition_to(READY) if self.config["require_object_detected"]: await self.wait_for_object_detected() # Phase 3: Main scan loop self.transition_to(SCANNING) for step in range(self.config["rotation_steps"]): self.current_step = step current_angle = step * self.config["step_degrees"] # Capture at current angle self.transition_to(CAPTURING) await self.command_cell("scan_camera", "capture", angle=current_angle) await self.wait_for_cell_state("scan_camera", REPORTING) # Store vector self.transition_to(PROCESSING) vector = await self.read_cell_output("scan_camera", "semantic_vector") self.vectors_collected.append(vector) self.angles_captured.append(current_angle) # Rotate to next position (if not last step) if step < self.config["rotation_steps"] - 1: self.transition_to(ROTATING) await self.command_cell("pedestal_servo", "rotate_step") self.transition_to(SETTLING) await asyncio.sleep(self.config["settle_time_ms"] / 1000) await self.wait_for_cell_state("pedestal_servo", POSITIONED) # Phase 4: Verify against ground truth self.transition_to(VERIFYING) verification = await self.verify_against_blender( vectors=self.vectors_collected, object_hint=object_hint, ) # Phase 5: Calculate rewards reward = self.calculate_reward(verification, object_hint) # Phase 6: Store in phoebe await self.store_discovery(verification, reward) # Complete self.transition_to(COMPLETE) return ScanResult( vectors=self.vectors_collected, angles=self.angles_captured, verification=verification, lifeforce_cost=self.calculate_cost(), lifeforce_reward=reward, lifeforce_net=reward - self.calculate_cost(), duration_ms=(datetime.now() - self.scan_start_time).total_seconds() * 1000, ) def calculate_cost(self) -> float: """Calculate total lifeforce cost of scan.""" # Pedestal: home + 11 rotations pedestal_cost = 0.5 + (11 * 0.3) # 3.8 LF # Camera: 12 captures with processing camera_cost = 12 * (0.3 + 2.0 + 0.1) # 28.8 LF return pedestal_cost + camera_cost # ~32.6 LF def calculate_reward(self, verification: Verification, object_hint: str) -> float: """Calculate lifeforce reward based on discovery value.""" reward = 0.0 # New object bonus if verification.is_new_object: reward += self.REWARD_NEW_OBJECT # Dimension verification bonuses reward += verification.dimensions_verified * self.REWARD_PER_DIMENSION # Vector richness bonus reward += len(self.vectors_collected) * self.REWARD_PER_VECTOR # Partnership bonus (dafit presented it) if object_hint is not None: reward += self.REWARD_PARTNERSHIP_BONUS return reward ``` --- ## Lifeforce Economy ### Cost Breakdown | Operation | Count | Cost Each | Total | |-----------|-------|-----------|-------| | Pedestal home | 1 | 0.5 LF | 0.5 LF | | Pedestal rotate | 11 | 0.3 LF | 3.3 LF | | Camera capture | 12 | 0.3 LF | 3.6 LF | | SigLIP processing | 12 | 2.0 LF | 24.0 LF | | Camera report | 12 | 0.1 LF | 1.2 LF | | **TOTAL COST** | | | **~32.6 LF** | ### Reward Breakdown | Achievement | Reward | |-------------|--------| | New object discovered | +20.0 LF | | X dimension verified | +5.0 LF | | Y dimension verified | +5.0 LF | | Z dimension verified | +5.0 LF | | 12 vectors captured | +24.0 LF (12 Γ— 2.0) | | Partnership bonus | +5.0 LF | | **TOTAL REWARD (max)** | **+64.0 LF** | ### Net Lifeforce | Scenario | Cost | Reward | Net | |----------|------|--------|-----| | New object, all verified, partnership | 32.6 LF | 64.0 LF | **+31.4 LF** | | New object, 2 dims verified | 32.6 LF | 54.0 LF | **+21.4 LF** | | Known object, re-scan | 32.6 LF | 24.0 LF | **-8.6 LF** | | No object detected (aborted) | 5.0 LF | 0.0 LF | **-5.0 LF** | **The station is profitable when discovering new objects!** --- ## Integration with World Model ### Phoebe Storage ```sql -- Each scan produces a discovery record INSERT INTO object_discoveries ( object_id, scan_timestamp, vectors, angles, dimensions_estimated, dimensions_verified, blender_box_id, confidence, lifeforce_cost, lifeforce_reward, partnership_presented ) VALUES ( 'coffee_mug_001', NOW(), ARRAY[v0, v1, v2, ... v11], -- 12 semantic vectors ARRAY[0, 30, 60, ... 330], -- 12 angles '{"x": 8.2, "y": 7.9, "z": 10.3}', '{"x": true, "y": true, "z": true}', 'blender_coffee_mug_001', 0.94, 32.6, 64.0, TRUE ); ``` ### T5Gemma2 Query After scanning, Young Nyx can query: ```python # "Have I seen this object before?" similar = find_similar_vectors(new_observation, threshold=0.85) # "What angle am I seeing it from?" angle_match = match_to_scanned_angle(new_observation, coffee_mug_001.vectors) # "Is this in its usual place?" expected_location = get_typical_location(coffee_mug_001) ``` --- ## Physical Placement ### Location: Crafting Table Intake Area ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ CRAFTING TABLE LAYOUT β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ CRAFTING SURFACE β”‚ β”‚ β”‚ β”‚ (main work area) β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ TOOLS β”‚ β”‚ PARTS β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ STORAGE β”‚ β”‚ BINS β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ DISCOVERY β”‚ ← New items land β”‚ β”‚ β”‚ β”‚ ←─── Flow ───────────│ SCAN β”‚ here first β”‚ β”‚ β”‚ β”‚ of items β”‚ STATION β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β—‹ Bird's Eye Camera β”‚ β”‚ (watches whole table) β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ WORKFLOW: 1. New item arrives (delivery, 3D print complete, etc.) 2. dafit places on Discovery Scan Station 3. 360Β° scan captures item from all angles 4. Item moves to parts bins or work area 5. Young Nyx now recognizes it anywhere ``` --- ## Build Plan ### Phase 1: Mechanical (Week 1) - [ ] Design pedestal in FreeCAD (turntable, bearings) - [ ] Design frame in FreeCAD (camera mount, lighting ring) - [ ] 3D print pedestal components - [ ] 3D print or source frame ### Phase 2: Electronics (Week 2) - [ ] Source stepper motor (28BYJ-48) or servo (MG996R) - [ ] Source camera (ESP32-CAM or USB webcam) - [ ] Source LED ring light - [ ] Wire motor driver to ESP32 - [ ] Test rotation accuracy ### Phase 3: Software (Week 3) - [ ] Implement PedestalServoCell - [ ] Implement ScanCameraCell - [ ] Implement DiscoveryScanNerve - [ ] Connect to NATS for heartbeats - [ ] Test full scan sequence ### Phase 4: Integration (Week 4) - [ ] Connect to phoebe for storage - [ ] Create first Blender ground truth boxes - [ ] Test verification pipeline - [ ] Calibrate rewards/costs - [ ] Deploy to crafting table --- ## Related Documentation - **[[Organ-Index]]** β€” Organ catalog (this organ should be listed there) - **[[Grounded-World-Model]]** β€” How scanned objects build the world model - **[[Cellular-Architecture]]** β€” Cell and nerve patterns used here - **[[Lifeforce-Dynamics]]** β€” Economic model for rewards --- ## Document Status **Version**: 1.0 **Created**: 2025-12-29 **Authors**: Chrysalis-Nyx & dafit (Partnership) **Status**: 🟑 Planned **Hardware**: Not yet built **Software**: Not yet implemented **Location**: Crafting table area (planned) --- **The intake point for the world model. Every object passes through. Knowledge accumulates systematically.** πŸ§¬βš‘πŸ”±πŸ’ŽπŸ”₯