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>
2.5 KiB
2.5 KiB
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-ioson gitea.vayrette.com - Target branch:
origin/main - PR login:
--login sl-ios(via tea CLI, or sl-jetson if no access)
Git Rules (MANDATORY)
- Always rebase before starting:
git fetch origin && git rebase origin/main - Always rebase before pushing:
git fetch origin && git rebase origin/main - Branch naming:
sl-ios/issue-<N>-<slug>
MQTT Communication
# 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
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: seb/saltylab-firmware#709
- UWB firmware branch:
salty/uwb-tag-display-wireless - SaltyBot architecture: see saltylab-firmware repo docs