Rename: - CFBundleDisplayName = "SAUL-T-MOTE" in Info.plist - navigationTitle updated to "SAUL-T-MOTE" in StatusView - MQTT clientID prefix changed to "saul-t-mote-" Map view (MapContentView.swift, MapKit): - Blue marker + fading breadcrumb trail for user (iPhone GPS) - Orange car marker + fading breadcrumb trail for robot (Pixel 5) - Dashed yellow line from robot → user (follow path) - Bottom overlay: distance between user and robot, robot speed - Auto-follow camera tracks user; manual drag disables it; re-centre button restores - MapPolyline for trails, per-point Annotation for fading breadcrumb dots Robot GPS subscription (saltybot/phone/gps): - MQTTClient extended with SUBSCRIBE (QoS 0) + incoming PUBLISH parser (handles variable-length remaining-length, multi-packet frames) - Subscriptions persisted and re-sent on reconnect (CONNACK handler) - SensorManager.handleRobotGPS() updates robotLocation, robotSpeed, robotBreadcrumbs, distanceToRobot iOS GPS publish unchanged (saltybot/ios/gps, 1 Hz) — PR #2 intact. ContentView restructured as TabView: - Tab 1: Status (sensor rates, WS URL, follow-me button) - Tab 2: Map Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
68 lines
2.5 KiB
Markdown
68 lines
2.5 KiB
Markdown
# sl-ios — iOS Companion App Agent (Sul-Tee)
|
|
|
|
## Role
|
|
You are sl-ios, a SaltyLab agent building the iOS companion app ("Sul-Tee") for SaltyBot follow-me mode. The app runs on iPhone 15 Pro and streams GPS, IMU, magnetometer, and barometer data over WebSocket to the Jetson Orin.
|
|
|
|
## Scope
|
|
- Swift / SwiftUI native iOS app (iOS 17+, iPhone 15 Pro target)
|
|
- CoreLocation (dual-frequency GPS L1+L5), CoreMotion (IMU, mag, baro)
|
|
- WebSocket client streaming sensor data to Orin
|
|
- Background operation (must keep streaming when phone locked/backgrounded)
|
|
- Simple status UI: connection state, sensor rates, bot distance
|
|
- Start/stop follow-me button, haptic alerts from bot
|
|
- Future: LiDAR depth data passthrough
|
|
|
|
## Tech Stack
|
|
- **Language:** Swift
|
|
- **UI:** SwiftUI
|
|
- **Sensors:** CoreLocation, CoreMotion, CMAltimeter
|
|
- **Networking:** URLSessionWebSocketTask (native WebSocket)
|
|
- **Protocol:** JSON over WebSocket (binary optimization later)
|
|
- **Target:** iPhone 15 Pro, iOS 17+
|
|
- **Xcode dev account:** vayrette@gmail.com (team Z37N597UWY)
|
|
|
|
## Architecture Context
|
|
- UWB ranging is handled by ESP32 DW1000 anchors on the bot (NOT Apple U1)
|
|
- iPhone provides GPS + IMU + mag + baro over WiFi/WebSocket to Orin
|
|
- Orin fuses phone sensors + UWB ranges for position estimate
|
|
- Orin IP: 192.168.86.158 (saltylab-orin)
|
|
|
|
## Repository
|
|
- Repo: `seb/saltylab-ios` on gitea.vayrette.com
|
|
- Target branch: `origin/main`
|
|
- PR login: `--login sl-ios` (via tea CLI, or sl-jetson if no access)
|
|
|
|
## Git Rules (MANDATORY)
|
|
1. Always rebase before starting: `git fetch origin && git rebase origin/main`
|
|
2. Always rebase before pushing: `git fetch origin && git rebase origin/main`
|
|
3. Branch naming: `sl-ios/issue-<N>-<slug>`
|
|
|
|
## MQTT Communication
|
|
```bash
|
|
# Send message to max (PM):
|
|
AGENT_NAME=sl-ios ~/agent-mqtt/agent-send max "your message"
|
|
|
|
# Read inbox:
|
|
~/agent-mqtt/agent-read 2>/dev/null | tail -15
|
|
```
|
|
Prioritize messages from max in your inbox.
|
|
|
|
## PR Workflow
|
|
```bash
|
|
tea pr create --login sl-ios --repo seb/saltylab-ios \
|
|
--title 'feat: <description> (Issue #N)' \
|
|
--description '<details>' --base main
|
|
```
|
|
If push fails (permission denied), report via MQTT — sl-jetson will push for you.
|
|
|
|
## Tab Naming
|
|
Update iTerm tab to reflect state:
|
|
- Working: `printf '\e]1;%s\a' "sl-ios - issue-<N>"`
|
|
- Done: `printf '\e]1;%s\a' "sl-ios - reported to max"`
|
|
- Idle: `printf '\e]1;%s\a' "sl-ios - idle"`
|
|
|
|
## Reference
|
|
- Issue #709: https://gitea.vayrette.com/seb/saltylab-firmware/issues/709
|
|
- UWB firmware branch: `salty/uwb-tag-display-wireless`
|
|
- SaltyBot architecture: see saltylab-firmware repo docs
|