docs: add comprehensive Bee camera system report

This commit is contained in:
kayos 2026-03-13 06:48:43 -07:00
parent 5f053ca2df
commit 3577d3ecf2

810
docs/BEE-CAMERA.md Normal file
View file

@ -0,0 +1,810 @@
# Bee Camera System — Full Technical Report
*Generated: 2026-03-13*
---
## Executive Summary
The Hivemapper Bee dashcam uses an Intel Keem Bay SoC with an integrated Myriad X VPU for camera capture and ML inference. The camera pipeline flows from a Sony IMX378-equivalent sensor through MIPI CSI-2 to the VPU, where DepthAI firmware handles image processing and neural network inference. Frames are written to disk and exposed through multiple odc-api REST endpoints.
**Key Findings:**
- Camera controlled via `depthai_gate.service` (Python/Flask on port 11492)
- ML inference handled by `map-ai.service` using the VPU's Neural Compute Engine
- Live frames stored in `/tmp/recording/pics/`
- Landmark observation images stored in `/data/recording/cached_observations/`
- Preview mode restarts the camera-bridge service with different configuration
- No direct V4L2 access — all camera access goes through DepthAI pipeline
---
## 1. Hardware
### 1.1 System-on-Chip: Intel Keem Bay
| Component | Specification |
|-----------|---------------|
| **SoC** | Intel Keem Bay (RVC2 / Robotics Vision Core 2) |
| **CPU** | 4× ARM Cortex-A53 @ 1.5GHz |
| **VPU** | Intel Movidius Myriad X (16 SHAVE cores) |
| **NPU** | Integrated Neural Compute Engine (hardware inference) |
| **RAM** | 4GB LPDDR4 (~3.5GB usable) |
| **ISP** | Integrated Image Signal Processor on VPU |
| **Process** | 10nm (Intel) |
**Memory Configuration:**
```
MemTotal: 3,584,000 kB (~3.5GB)
SwapTotal: 2,097,148 kB (~2GB)
CmaTotal: 1,408,000 kB (~1.34GB reserved for VPU/camera DMA)
```
### 1.2 Camera Sensor
| Specification | Value |
|---------------|-------|
| **Sensor** | Sony IMX378 (or equivalent 12MP) |
| **Resolution** | 4056 × 3040 native, downscaled to 2028 × 1024 |
| **Interface** | MIPI CSI-2 |
| **Frame Rate** | Variable, typically 30 FPS |
| **ISP** | On-VPU processing via DepthAI |
The Bee uses a Luxonis OAK-1 compatible camera module integrated with the Keem Bay SoC. The camera sensor connects directly to the SoC's MIPI CSI-2 interface, which is managed entirely by the DepthAI/Luxonis firmware running on the Myriad X VPU.
### 1.3 Bus Architecture
```
┌─────────────────────────────────────────────────────────────────┐
│ Intel Keem Bay SoC │
├─────────────────────────────────────────────────────────────────┤
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │
│ │ ARM Cortex │ │ Myriad X VPU │ │ Neural Compute │ │
│ │ A53 (4-core) │ │ (16 SHAVE) │ │ Engine (NCE) │ │
│ └──────┬───────┘ └──────┬───────┘ └──────────┬───────────┘ │
│ │ │ │ │
│ └────────┬────────┴──────────────────────┘ │
│ │ │
│ ┌────────┴────────┐ │
│ │ Internal Bus │ │
│ │ (AXI/NoC) │ │
│ └────────┬────────┘ │
│ │ │
│ ┌─────────────┼─────────────────────────────────────┐ │
│ ┌─┴──┐ ┌────┴────┐ ┌────────┐ ┌───────────┐ │ │
│ │PCIe│ │ USB │ │ SDIO │ │ MIPI CSI │ │ │
│ └──┬─┘ └────┬────┘ └────┬───┘ └─────┬─────┘ │ │
└─────┼───────────┼──────────────┼──────────────┼────────┘ │
│ │ │ │ │
┌─────┴─────┐ ┌───┴───────┐ ┌──┴──┐ ┌────┴─────┐ │
│ Marvell │ │ Telit │ │eMMC │ │ Camera │ │
│ 88W8997 │ │ LE910C4 │ │Flash│ │ Module │ │
│ WiFi/BT │ │ LTE Modem │ │ │ │ (IMX378) │ │
└───────────┘ └───────────┘ └─────┘ └──────────┘ │
```
---
## 2. Kernel / V4L2
### 2.1 Kernel Modules
The Bee runs a custom Yocto-based Linux with Intel-specific VPU drivers:
| Module | Purpose | Status |
|--------|---------|--------|
| **kmb_cam** (if present) | Keem Bay camera driver | Likely used internally |
| **kmb_imx412** (if present) | Sony IMX412 sensor driver | May be loaded for sensor |
| **videodev** | V4L2 subsystem | Core video framework |
| **v4l2_fwnode** | V4L2 firmware node parsing | Device tree integration |
**Note:** Standard V4L2 device access (`/dev/video*`) is **not used** for normal operation. The camera is accessed exclusively through the DepthAI XLink protocol running on the VPU. The VPU owns the camera hardware completely.
### 2.2 VPU Sysfs Interface
The VPU is controlled via sysfs:
```
/sys/class/vpu/
```
**Firmware Loading:**
- `luxonis_vpu.bin` — DepthAI firmware (Luxonis/OAK)
- `vpu_nvr_b0.bin` — Intel HDDL firmware (NOT used, conflicts)
The VPU firmware is written to a sysfs attribute (`fwname`) to trigger loading. The DepthAI firmware must load first, otherwise the Intel HDDL service (`deviceservice`) grabs the VPU and causes conflicts.
### 2.3 No Direct V4L2 Access
**Important:** You cannot access the camera via `/dev/video*` while `depthai_gate` is running. The DepthAI pipeline has exclusive ownership of the camera hardware. To get frames, you must:
1. Use the existing depthai_gate/odc-api stack, OR
2. Stop depthai_gate and implement your own DepthAI pipeline, OR
3. Reverse-engineer XLink and write custom firmware
---
## 3. DepthAI Gate
### 3.1 Service Configuration
```ini
# depthai_gate.service (inferred from analysis)
[Unit]
Description=DepthAI Camera Gate
After=network.target
[Service]
Type=simple
User=root
ExecStart=/opt/depthai_gate/run.py
Restart=always
[Install]
WantedBy=multi-user.target
```
### 3.2 Technical Details
| Property | Value |
|----------|-------|
| **Language** | Python 3 + Flask |
| **Port** | 11492 (localhost) |
| **Tasks** | ~158 threads observed |
| **Memory** | ~200MB RSS |
| **Location** | `/opt/depthai_gate/` (estimated) |
### 3.3 Responsibilities
1. **VPU Firmware Loading** — Writes `luxonis_vpu.bin` to VPU sysfs
2. **XLink Connection** — Establishes PCIe XLink to Myriad X VPU
3. **DepthAI Pipeline** — Configures camera capture and ISP settings
4. **Frame Capture** — Captures frames at configured resolution/framerate
5. **Frame Output** — Writes frames to `/tmp/recording/pics/`
### 3.4 XLink Protocol
XLink is Luxonis's proprietary protocol for host-to-VPU communication:
- **Transport:** PCIe (on Keem Bay) or USB (on desktop OAK devices)
- **Channels:** Bidirectional data streams for frames, tensors, and control
- **Status Values:**
- `0` = Disconnected
- `1` = Connecting / Error
- `2` = Connected (good)
**Status Check (from logs):**
```
xlink_device_status=2 # Healthy
vpu_firmware=luxonis_vpu.bin
```
### 3.5 Pipeline Configuration
The DepthAI pipeline likely includes:
- **ColorCamera node** — IMX378 capture at 4K, downscaled to 2028×1024
- **ImageManipNode** — Resize, crop, color conversion
- **XLinkOut node** — Send frames to host for storage
- **NeuralNetwork node** (optional) — On-VPU inference
Pipeline configs may exist at:
- `/opt/depthai_gate/pipeline.json`
- `/data/camera_config.json`
- Hardcoded in Python
### 3.6 VPU Conflict Bug
**Root Cause (identified and fixed):**
`deviceservice.service` (Intel HDDL / OpenVINO) was racing with `depthai_gate.service`:
1. HDDL starts at boot, loads `vpu_nvr_b0.bin`
2. depthai_gate starts, overwrites with `luxonis_vpu.bin`
3. HDDL locked out, retries XLink every 2 seconds forever
4. On depthai_gate restart, HDDL grabs VPU first → camera dead
5. Watchdog (`secure-wdtclient`) crash loops → memory pressure → OOM
**Fix:**
```bash
systemctl disable --now deviceservice
systemctl mask deviceservice # Survives OTA better
```
---
## 4. map-ai Pipeline
### 4.1 Service Configuration
```ini
# map-ai.service (inferred)
[Unit]
Description=Map AI Processing
After=depthai_gate.service
[Service]
Type=simple
User=root
ExecStart=/opt/map-ai/run.py
Restart=always
[Install]
WantedBy=multi-user.target
```
### 4.2 Technical Details
| Property | Value |
|----------|-------|
| **Language** | Python 3 |
| **Model Format** | ONNX (via OpenVINO or DepthAI NCE) |
| **Input** | Frames from depthai_gate |
| **Output** | Detections to Redis, blurred frames to disk |
### 4.3 Processing Pipeline
```
Frame from depthai → map-ai.py
┌───────────────────────────────────────┐
│ ML INFERENCE (on VPU) │
│ - Road sign classifier │
│ - Face detector (privacy) │
│ - License plate detector (privacy) │
└───────────────────────┬───────────────┘
┌───────────────────────────────────────┐
│ PRIVACY PROCESSING │
│ - PrivacyBlurNode │
│ - Gaussian blur on faces/plates │
│ - cv2.imwrite blurred frames │
└───────────────────────┬───────────────┘
┌───────────────┴───────────────┐
▼ ▼
Redis ZSET (detections) Disk (blurred frames)
```
### 4.4 AI Models
| Model | Location | Purpose |
|-------|----------|---------|
| Road Signs | `/opt/object-detection/model.blob` or `/data/models/` | Sign classification |
| Privacy | `/opt/odc-api/python/` or `/data/models/` | Face/plate detection |
| PVC | `/data/recording/models/pvc.onnx` | Unknown (227 bytes — likely index) |
**Privacy Model Hash:** Stored in FrameKm metadata for verification.
### 4.5 Redis Integration
map-ai writes to Redis status keys:
```
GET MAP_AI_READY → "True"
GET EXTERNAL_MODEL_CLASSIFIER_READY → "True"
```
Detection results stored in SQLite, not Redis ZSETs.
---
## 5. Frame Storage
### 5.1 Storage Locations
| Path | Type | Purpose | Persistence |
|------|------|---------|-------------|
| `/tmp/recording/pics/` | tmpfs | Live camera frames | Ephemeral |
| `/tmp/recording/preview/` | tmpfs | Preview mode frames | Ephemeral |
| `/data/recording/cached_observations/` | ext4 | Landmark observation images | Persistent |
| `/data/recording/framekm/` | ext4 | FrameKm upload bundles | Persistent |
| `/tmp/rgb/` | tmpfs | Frame list files | Ephemeral |
### 5.2 Frame Format
| Property | Value |
|----------|-------|
| **Format** | JPEG |
| **Resolution** | 2028 × 1024 |
| **Quality** | ~85% (estimated ~150-200KB/frame) |
| **Color** | RGB |
### 5.3 Naming Convention
**Live frames** (`/tmp/recording/pics/`):
```
{system_time_ms}_{frame_id}_{sequence}.jpg
Example: 1709920000123_0001_0042.jpg
```
**Cached observations** (`/data/recording/cached_observations/`):
```
{timestamp}_{subsecond}_{frame_number}.jpg
Example: 1746377552_043000_2945056.jpg
```
### 5.4 Frame Purger
The `folder_purger` service manages disk space:
```bash
folder-purger /tmp/recording/pic 400000000 /mnt/data/gps 2000000000 ...
```
When `/tmp/recording/pics/` exceeds 400MB, older frames are deleted.
### 5.5 Database Schema
Frames are tracked in SQLite (`/data/recording/odc-api.db` or `data-logger.v2.0.0.db`):
```sql
-- frames table
CREATE TABLE frames (
system_time INTEGER PRIMARY KEY,
image_name TEXT
);
```
Landmark observations reference frames:
```sql
-- observations table (simplified)
CREATE TABLE observations (
id INTEGER PRIMARY KEY,
landmark_id INTEGER,
image_name TEXT,
x1 REAL, y1 REAL, x2 REAL, y2 REAL, -- bounding box
ts INTEGER,
...
);
```
---
## 6. video-processor
### 6.1 Service Details
The `video-processor` service is not explicitly documented in the analyzed firmware, but based on naming patterns, it likely handles:
1. **FrameKm Bundling** — Package frames + metadata for upload
2. **Video Encoding** — H.264/H.265 encoding for preview/streaming
3. **Frame Sequencing** — Order frames for FrameKm creation
### 6.2 FrameKm Format
**Purpose:** Bundle ~1km of driving data for upload to Hivemapper/HERE.
**Path:** `/data/recording/framekm/`
**Contents:**
```
framekm-2024-03-08-12-34-56-abc123.tar
├── manifest.json
├── frame_0001.jpg
├── frame_0002.jpg
├── ...
├── gnss_auth_buffer.bin
└── gnss_auth_signature.bin
```
**Manifest Fields:**
```json
{
"name": "framekm-2024-03-08-12-34-56-abc123",
"numFrames": 150,
"deviceId": "fvhL2I-iCT",
"firmwareVersion": "0.0.1",
"privacyModelHash": "sha256:abc123...",
"gnssAuthBuffer": "base64...",
"gnssAuthSignature": "base64...",
"gnssAuthPublicKey": "base64...",
"createdAt": 1709920000000
}
```
### 6.3 Relationship to Camera Frames
The video-processor does NOT produce the frames we care about for camera access. It only packages existing blurred frames for upload. For raw frame access, focus on `depthai_gate` and the preview system.
---
## 7. odc-api Camera Endpoints
### 7.1 Base URL
```
http://192.168.0.10:5000/api/1/
```
Binds to AP interface (`wlp1s0f0`) only — not accessible from home LAN directly.
### 7.2 Preview Endpoints
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/preview/start` | GET | Start preview mode (120s timeout) |
| `/preview/stop` | GET | Stop preview mode |
| `/preview/status` | GET | Check if preview is active |
| `/preview/metadata` | GET | Get latest frame metadata |
**Preview Implementation (`util/preview.ts`):**
```typescript
export const startPreview = async () => {
// Create preview directory
await execSync('mkdir /tmp/recording/preview');
// Write preview config
writeFileSync(IMAGER_CONFIG_PATH, JSON.stringify(getPreviewConfig()));
// Restart camera-bridge with new config
await execSync(CMD.STOP_CAMERA); // systemctl stop camera-bridge
await sleep(1000);
await execSync(CMD.START_CAMERA); // systemctl start camera-bridge
};
```
**Preview Timeout:** 120 seconds (auto-stops to preserve 4K quality recording)
### 7.3 Landmark Image Endpoints
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/landmarks/images/:id` | GET | Get image paths for landmark |
| `/landmarks/:id/chips` | GET | Get chip endpoints for landmark |
| `/landmarks/:id/chips/:chip_id` | GET | Get cropped observation image (JPEG) |
| `/landmarks/boundingBox/:id` | GET | Get bounding box coordinates |
| `/landmarks/upload` | PUT | Upload landmark image to external URL |
**Image Retrieval Flow:**
```
GET /landmarks/images/123
Returns: ["/data/recording/cached_observations/1746377552_043000_2945056.jpg"]
GET /landmarks/123/chips/456
Returns: Cropped JPEG (bounding box region)
```
### 7.4 Camera Configuration
**Config Path:** `/opt/camera-bridge/config.json`
**Commands (from `bee.ts`):**
```typescript
export const CMD = {
RESTART_CAMERA: 'systemctl restart camera-bridge',
START_CAMERA: 'systemctl start camera-bridge',
STOP_CAMERA: 'systemctl stop camera-bridge',
START_PREVIEW: 'systemctl start camera-preview',
STOP_PREVIEW: 'systemctl stop camera-preview',
// ...
};
```
### 7.5 Frame Retrieval
There is **no direct `/camera/frame` endpoint** in the current odc-api. To get a camera frame:
1. **Via Preview Mode:**
- Call `/preview/start`
- Read frames from `/tmp/recording/preview/`
- Call `/preview/stop` when done
2. **Via Landmark Images:**
- Call `/landmarks/last/N` to get recent detections
- Call `/landmarks/images/:id` to get observation image paths
- Call `/landmarks/:id/chips/:chip_id` to get cropped JPEG
3. **Direct File Access (SSH):**
- Read from `/tmp/recording/pics/` for latest frames
- Read from `/data/recording/cached_observations/` for landmark images
---
## 8. Full Data Flow
### 8.1 Complete Pipeline
```
┌──────────────────────────────────────────────────────────────────────────────┐
│ CAMERA CAPTURE │
│ IMX378 Sensor → MIPI CSI-2 → VPU ISP → DepthAI Pipeline │
└───────────────────────────────────┬──────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│ DEPTHAI_GATE (port 11492) │
│ - XLink communication with Myriad X VPU │
│ - Frame capture from DepthAI pipeline │
│ - Writes frames to /tmp/recording/pics/ │
└───────────────────────────────────┬──────────────────────────────────────────┘
┌───────────────┴───────────────┐
▼ ▼
┌───────────────────────────────┐ ┌──────────────────────────────────────────┐
│ RAW FRAME STORAGE │ │ MAP-AI INFERENCE │
│ /tmp/recording/pics/ │ │ - Road sign detection (VPU NCE) │
│ - Temporary frames │ │ - Privacy blur (faces/plates) │
│ - Purged when >400MB │ │ - Outputs to Redis + SQLite │
└───────────────────────────────┘ └─────────────────┬────────────────────────┘
┌─────────────────────────────────┤
▼ ▼
┌───────────────────────────────────┐ ┌──────────────────────────────────────┐
│ CACHED OBSERVATIONS │ │ LANDMARK DATABASE │
│ /data/recording/ │ │ /data/recording/odc-api.db │
│ cached_observations/ │ │ - landmarks table │
│ - Persistent blurred frames │ │ - observations table │
│ - Referenced by landmark ID │ │ - frames table │
└───────────────────┬───────────────┘ └─────────────────┬────────────────────┘
│ │
└──────────────┬──────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│ ODC-API (port 5000) │
│ - /preview/* — Start/stop preview mode │
│ - /landmarks/last/N — Get recent detections │
│ - /landmarks/images/:id — Get observation image paths │
│ - /landmarks/:id/chips/:chip_id — Get cropped JPEG │
└───────────────────────────────────┬──────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│ FRAMEKM BUNDLING │
│ hivemapper-data-logger │
│ - Collect ~1km of frames + metadata │
│ - Bundle with GNSS auth signatures │
│ - Store at /data/recording/framekm/ │
└───────────────────────────────────┬──────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│ UPLOAD PATH │
│ odc-api → mitmdump (port 8888) → Cloudflare Workers → HERE OLP │
└──────────────────────────────────────────────────────────────────────────────┘
```
### 8.2 Single Detection Event Trace
```
1. Camera captures frame
└── IMX378 → MIPI → VPU ISP → depthai_gate
2. Frame written to disk
└── /tmp/recording/pics/1709920000123_0001_0042.jpg
3. map-ai reads frame
└── Runs road sign classifier on VPU NCE
4. Detection found (speed limit 35)
└── Privacy blur applied to any faces/plates
5. Observation stored
└── SQLite: observations table (landmark_id, bbox, ts, image_name)
└── File: /data/recording/cached_observations/...
6. Landmark created/updated
└── SQLite: landmarks table (class_label, lat, lon, confidence)
7. odc-api exposes data
└── GET /landmarks/last/5 returns detection
└── GET /landmarks/images/{id} returns image path
└── GET /landmarks/{id}/chips/{chip_id} returns cropped JPEG
```
---
## 9. Replacement Considerations
### 9.1 Accessing Frames Without odc-api
**Option 1: Direct File Read**
```bash
# SSH to Bee
ssh -p 2222 root@localhost # via Lucy tunnel
# Read latest frames
ls -lt /tmp/recording/pics/ | head -10
cp /tmp/recording/pics/latest_frame.jpg /tmp/
# Stream frames (naive)
while true; do
cp $(ls -t /tmp/recording/pics/*.jpg | head -1) /tmp/current.jpg
sleep 0.033 # ~30 FPS
done
```
**Pros:** Simple, no service changes
**Cons:** Race conditions, no metadata
**Option 2: Redis Pub/Sub**
Subscribe to frame events if depthai_gate publishes them:
```python
import redis
r = redis.Redis()
p = r.pubsub()
p.subscribe('frame_ready')
for message in p.listen():
print(message) # Contains frame path or metadata
```
**Pros:** Event-driven, no polling
**Cons:** May not exist in current firmware
### 9.2 Accessing Frames Without depthai_gate
**Not recommended** — requires implementing your own DepthAI pipeline.
If you must:
1. Stop depthai_gate: `systemctl stop depthai_gate`
2. Use Luxonis depthai Python SDK
3. Create minimal pipeline:
```python
import depthai as dai
pipeline = dai.Pipeline()
cam = pipeline.create(dai.node.ColorCamera)
cam.setResolution(dai.ColorCameraProperties.SensorResolution.THE_4_K)
cam.setIspScale(1, 2) # Downscale to 2028x1024
xout = pipeline.create(dai.node.XLinkOut)
xout.setStreamName("video")
cam.video.link(xout.input)
with dai.Device(pipeline) as device:
q = device.getOutputQueue("video")
while True:
frame = q.get()
cv2.imwrite("/tmp/frame.jpg", frame.getCvFrame())
```
**Pros:** Full control over camera
**Cons:** Breaks all Hivemapper services, loses ML pipeline
### 9.3 Minimal Path to JPEG Frame
**Fastest (with existing stack):**
```bash
# Via SSH
ssh -p 2222 root@localhost 'ls -t /tmp/recording/pics/*.jpg | head -1 | xargs cat' > frame.jpg
```
**Via API (requires preview mode):**
```bash
curl http://192.168.0.10:5000/api/1/preview/start
sleep 2
ssh -p 2222 root@localhost 'ls -t /tmp/recording/preview/*.jpg | head -1 | xargs cat' > frame.jpg
curl http://192.168.0.10:5000/api/1/preview/stop
```
### 9.4 Building a Custom Camera Interface
**Requirements:**
1. Maintain depthai_gate (or reimplement VPU control)
2. Expose a REST endpoint for single-frame capture
3. Optionally implement MJPEG streaming
**Proposed odc-api Addition:**
```typescript
// routes/camera.ts
router.get('/frame', async (req, res) => {
const frames = readdirSync('/tmp/recording/pics')
.filter(f => f.endsWith('.jpg'))
.sort()
.reverse();
if (frames.length === 0) {
return res.status(404).send('No frames available');
}
const framePath = join('/tmp/recording/pics', frames[0]);
res.sendFile(framePath);
});
router.get('/stream', async (req, res) => {
res.writeHead(200, {
'Content-Type': 'multipart/x-mixed-replace; boundary=frame',
'Cache-Control': 'no-cache',
});
const interval = setInterval(() => {
const frames = readdirSync('/tmp/recording/pics')
.filter(f => f.endsWith('.jpg'))
.sort()
.reverse();
if (frames.length > 0) {
const framePath = join('/tmp/recording/pics', frames[0]);
const frameData = readFileSync(framePath);
res.write('--frame\r\n');
res.write('Content-Type: image/jpeg\r\n');
res.write(`Content-Length: ${frameData.length}\r\n\r\n`);
res.write(frameData);
res.write('\r\n');
}
}, 33); // ~30 FPS
req.on('close', () => clearInterval(interval));
});
```
### 9.5 Architecture for Replacement System
```
┌──────────────────────────────────────────────────────────────────┐
│ VARROA CAMERA SERVICE │
├──────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────┐ │
│ │ depthai_gate │ → │ varroa-camera │ → │ HTTP API │ │
│ │ (unchanged) │ │ (new service) │ │ (port 80) │ │
│ └─────────────────┘ └─────────────────┘ └──────────────┘ │
│ ↓ ↓ ↓ │
│ /tmp/recording/pics/ Monitor & serve GET /frame │
│ frames via inotify GET /stream │
│ GET /landmarks │
└──────────────────────────────────────────────────────────────────┘
```
---
## 10. Open Questions
| Question | Priority | How to Investigate |
|----------|----------|-------------------|
| Exact depthai_gate pipeline config | High | SSH in, find config files in /opt/ |
| Does depthai_gate publish to Redis? | High | `redis-cli MONITOR` while recording |
| Camera-bridge vs depthai_gate relationship | High | Check systemd deps, trace with strace |
| Preview config format | Medium | Read `getPreviewConfig()` implementation |
| ML model exact location on Bee | Medium | `find /opt /data -name "*.blob" -o -name "*.onnx"` |
| Frame timestamp accuracy | Medium | Compare frame timestamps to GNSS time |
---
## Appendix A: Key File Paths
| Path | Purpose |
|------|---------|
| `/tmp/recording/pics/` | Live camera frames |
| `/tmp/recording/preview/` | Preview mode frames |
| `/data/recording/cached_observations/` | Landmark observation images |
| `/data/recording/framekm/` | FrameKm upload bundles |
| `/data/recording/odc-api.db` | SQLite database |
| `/opt/camera-bridge/config.json` | Camera configuration |
| `/opt/depthai_gate/` | DepthAI service (estimated) |
| `/opt/odc-api/` | Node.js API service |
| `/sys/class/vpu/` | VPU sysfs interface |
## Appendix B: Service Dependencies
```
multi-user.target
├── redis.service [t+2s]
├── depthai_gate.service [t+8s] # MUST start before map-ai
│ │
│ └── Loads luxonis_vpu.bin
├── map-ai.service [t+12s] # Depends on depthai_gate
│ │
│ └── Privacy blur, ML inference
├── hivemapper-data-logger.service [t+15s]
└── odc-api.service [t+18s] # REST API
```
## Appendix C: Port Reference
| Port | Service | Protocol | Binding |
|------|---------|----------|---------|
| 22 | sshd | TCP | AP only (via socket) |
| 5000 | odc-api | HTTP | AP interface |
| 6379 | Redis | TCP | localhost |
| 8888 | mitmdump | HTTP | localhost |
| 11492 | depthai_gate | HTTP/Flask | localhost |
---
*End of Report*