致伸上位機開發文件
v1.0.0
React 19
TypeScript 5.6
更新日期:2026-03-14
1. 專案概述
專案名稱
JinXiang ATOM (季享科技 ATOM 版)
App ID
com.jinher.atomrobotcontrol
支援平台
Web, Electron, Android, iOS, Orange Pi
功能特色
- 多模式任務系統:配送、領位、回收、生日、巡航、導覽、語音互動
- 跨平台統一架構:5 個平台共用相同前端程式碼
- MQTT 雲端控制:透過 AWS IoT 實現遠端監控與操控
- ATOM 自動發現:掃描網段自動尋找並連接機器人
- 故障轉移機制:主要 ATOM 無回應時自動切換備用
- 即時地圖視圖:支援建圖模式與即時位置追蹤
- 語音 AI 互動:整合 Google Gemini API
- 多角色系統:熊、女孩、戰士、自訂角色
2. 系統架構
整體架構圖
┌─────────────────────────────────────────────────────────────┐
│ 使用者介面 (React + Vite + Tailwind) │
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │配送 │ │領位 │ │回收 │ │生日 │ │巡航 │ │導覽 │ │語音 │ │
│ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ AmrContext (WebSocket Client) │ │
│ │ 統一通訊層 ws://localhost:8980 │ │
│ └────────────────────────────────────────────────────────┘ │
└─────────────────────────────┬───────────────────────────────┘
│ WebSocket (Port 8980)
┌─────────────────────────────┴───────────────────────────────┐
│ WebSocket Proxy (Node.js / Java) │
│ ┌─────────────┐ ┌────────────┐ ┌────────────────────┐ │
│ │ HTTP Client │ │Webhook Srv │ │AWS IoT MQTT Client │ │
│ │ → ATOM API │ │Port 8086 │ │雲端遠端控制 │ │
│ └──────┬──────┘ └──────┬─────┘ └──────────┬─────────┘ │
└─────────┬─────────────┬────────────────┬─────────────┘
│ HTTP │ Webhook │ MQTT
┌─────────┴─────────────┴─────┐ ┌───┴─────────────┐
│ ATOM Action Server │ │ AWS IoT Core │
│ (192.168.168.168:8080) │ │ 雲端訊息中心 │
└─────────────────────────────────┘ └───────────────────┘
通訊流程
- 前端 → Proxy:前端透過 WebSocket 連接到 Proxy (Port 8980)
- Proxy → ATOM:Proxy 將 WebSocket 訊息轉換為 HTTP 請求發送到 ATOM
- ATOM → Proxy:ATOM 的狀態回報透過 Webhook (Port 8086) 推送回 Proxy
- Proxy → 前端:Proxy 將狀態更新透過 WebSocket 推送到前端
- 雲端控制:AWS IoT MQTT 提供遠端命令與狀態同步
跨平台 Proxy 實現
| 平台 | Proxy 實現 | 說明 |
| Web | websocket-proxy/server.js | 獨立啟動 |
| Electron | electron/main.cjs (內嵌) | 自動啟動 |
| Android | AmrPlugin.java (Java) | 內建 WebSocket Server |
| Orange Pi | Node.js (systemd 服務) | 系統服務自動啟動 |
3. 目錄結構
/opt/JinXiang-ATOM/
├── App.tsx # 應用入口與路由 (541 行)
├── index.tsx # React 掛載點
├── types.ts # TypeScript 類型定義 (217 行)
├── constants.ts # 多語言翻譯常數 (49KB)
├── SettingsStorage.ts # 儲存封裝
├── *Context.tsx # 9 個 Context 狀態管理器
│
├── components/ # 18 個 UI 元件
├── src/plugins/ # 平台插件 (AmrPlugin, TtsPlugin)
├── websocket-proxy/ # WebSocket Proxy (5309 行)
├── electron/ # Electron 桌面應用
├── android/ # Android 應用 (Java)
├── deploy/ # Orange Pi 部署
├── docs/ # API 文件與規範
└── public/ # 靜態資源
4. 技術棧
前端
| 技術 | 版本 | 用途 |
| React | 19.0.0 | UI 框架 |
| TypeScript | 5.6.2 | 型別安全 |
| Vite | 6.0.1 | 建構工具 |
| Tailwind CSS | 4.0.0 | CSS 框架 |
| Lucide React | 0.555.0 | 圖示庫 |
| Axios | 1.7.7 | HTTP 客戶端 |
跨平台
| 技術 | 版本 | 用途 |
| Electron | 33.2.0 | Windows 桌面 |
| Capacitor | 6.2.0 | Android / iOS |
後端 (Proxy)
| 技術 | 版本 | 用途 |
| ws | 8.18.0 | WebSocket 伺服器 |
| Express | 4.18.2 | HTTP 伺服器 |
| AWS IoT SDK v2 | 1.24.0 | MQTT 雲端連線 |
| Sharp | 0.34.5 | 圖片處理 |
5. 通訊架構
WebSocket 協議
// 前端 → Proxy:發送命令
{
"type": "command",
"action": "moveTo",
"data": { "waypoint": "A01" }
}
// Proxy → 前端:狀態更新
{
"type": "status",
"data": {
"batteryLevel": 85,
"moveState": "moving",
"location": { "x": 1.5, "y": 2.3, "orientation": 90 }
}
}
HTTP API 轉發對照
| WebSocket 命令 | HTTP API 端點 |
moveTo("A01") | POST /service/control/commands |
emergencyStop() | POST /service/system/emergency/stop |
checkAlive() | GET /service/system/check_alive |
Webhook 回報端點
| 端點 | 內容 |
POST /monitor | 電量、路由狀態、啟動進度 |
POST /pose | 即時位置 (x, y, orientation) |
POST /map | 即時地圖 (建圖模式) |
6. Context 狀態管理系統
6.1 AmrContext - AMR 通訊核心
檔案:AmrContext.tsx (3233 行, 121KB) - 系統最核心的 Context
主要方法
// 導航控制
moveTo(waypoint: string) // 導航至指定站點
stopMove() // 停止移動
pauseMove() // 暫停移動
resumeMove() // 恢復移動
goCharge() // 前往充電站
// 緊急控制
emergencyStop() // 緊急停止
releaseEmergency() // 解除緊急停止
// SLAM 與地圖
setSlamMode(mode, mapName) // 設定 SLAM 模式
getMapList() // 取得地圖列表
getWaypoints() // 取得站點列表
// 手動控制
manualControl(direction, speed) // 手動控制移動
// 原始命令
sendCommand(cmd) // 發送原始 JSON 命令
主要狀態 (AmrStatus)
proxyConnected: boolean // Proxy 連線狀態
amrConnected: boolean // ATOM 連線狀態
batteryLevel: number // 電量 (0-100)
charging: boolean // 充電中
moveState: string // 移動狀態 (idle/moving/paused)
slamMode: string // SLAM 模式
currentMap: string // 目前地圖
waypoints: string[] // 站點列表
location: { x, y, orientation } // 即時位置
6.2 其他 Context
| Context | 檔案 | 功能 |
| LanguageContext | LanguageContext.tsx | 多語言切換 (zh/tw/en/ja),提供 t(key) |
| ConfigContext | ConfigContext.tsx | 模式啟用、托盤配置、密碼、API 端點 |
| ModeSettingsContext | ModeSettingsContext.tsx | 各模式詳細設定 |
| SpeechContext | SpeechContext.tsx | TTS 語音合成 |
| VoiceAIContext | VoiceAIContext.tsx | Google Gemini API 語音互動 |
| CloudContext | CloudContext.tsx | 雲端設備激活 |
| LogContext | LogContext.tsx | 任務日誌記錄 |
| CharacterContext | CharacterContext.tsx | 角色選擇 |
7. UI 元件
核心視圖
| 元件 | 功能 |
| TaskView | 任務執行視圖(配送/領位/回收/生日/巡航) |
| SettingsView | 設定主視圖 |
| VoiceView | 語音互動界面 |
| GuideModeView | 導覽模式 |
| MappingModeView | 建圖模式 |
| MappingControlPage | 手機建圖遙控 |
| ActivationView | 雲端激活 |
設定面板
| 元件 | 功能 |
| ModeSettingsPanel | 模式設定 |
| MapSettingsPanel | 地圖設定 |
| MapViewPanel | 即時地圖視圖 |
| SecuritySettingsPanel | 安全性設定 |
通用 UI
| 元件 | 功能 |
| MainAvatar | 待機畫面大頭像 |
| MiniAvatar | 任務中小型頭像 |
| BearFace | 熊臉角色動畫 |
| StatusBar | 狀態列(電量/連線/時間) |
| DebugConsole | 除錯控制台 |
8. 應用模式
8.1 模式列表
| 模式 | 代碼 | 說明 |
| 待機 | IDLE | 大頭像畫面,點擊進入主選單 |
| 主選單 | HOME | 8 宮格模式選擇 |
| 配送 | DELIVERY | 送餐/物品配送 |
| 領位 | LEADING | 帶位引導 |
| 回收 | COLLECTION | 餐具/物品回收 |
| 生日 | BIRTHDAY | 生日慶祝(播放音樂) |
| 巡航 | CRUISE | 自動巡航路線 |
| 導覽 | GUIDE | 多媒體導覽 |
| 語音 | VOICE_INTERACTION | AI 語音對話 |
| 設定 | SETTINGS | 系統設定 |
8.2 模式設定介面
配送模式 (DeliveryModeSettings)
{
enabledDestinations: string[] // 啟用的目的地站點
returnPoint: string // 返回點
waitTimeSeconds: number // 到達後等待時間
autoReturn: boolean // 自動返回
confirmBeforeReturn: boolean // 返回前確認
}
巡航模式 (CruiseModeSettings)
{
patrolPoints: string[] // 巡航路線點(按順序)
intervalSeconds: number // 每站停留時間
loopEnabled: boolean // 循環巡航
returnWhenDone: boolean // 完成後返回起點
}
生日模式 (BirthdayModeSettings)
{
enabledDestinations: string[] // 啟用的目的地
celebrationDuration: number // 慶祝時長(秒)
musicEnabled: boolean // 播放音樂
musicFile: string // 音樂檔案
musicVolume: number // 音量 (0-100)
musicPlayOnStart: boolean // 開始任務即播放
}
9. ATOM API 參考
系統端點
GET /service/system/check_alive # 健康檢查
GET /service/control/get/robot_mode # 取得機器人模式
GET /service/control/get/map_list # 取得地圖列表
GET /service/control/get/waypoint_list # 取得站點列表
控制命令
POST /service/control/commands
{
"delivery_command": {
"deliver_to_location": ["A01"] // 導航至站點
}
}
POST /service/control/commands
{
"webhook_url": "http://host:8086/" // 設定 Webhook
}
POST /service/control/commands
{
"slam_command": {
"mode": "navigation", // navigation / mapping / idle
"map_name": "map_name"
}
}
緊急控制
POST /service/system/emergency/stop # 緊急停止
POST /service/system/emergency/resume # 解除緊急
完整 API 文件請參考 docs/ATOM_API_v1.0.3.md
10. MQTT 雲端協議
10.1 Topic 結構
jr2/
├── fleet/discovery # 設備發現
├── server/online # Server 重啟通知
└── robot/{deviceId}/
├── command # 控制命令 (APP → Robot)
├── response # 命令回應 (Robot → APP)
├── status # 完整狀態 (每 30 秒)
├── location # 位置更新 (每 5 秒)
├── online # 上線/離線
├── alert # 警報通知
└── control/
├── request / release # 請求/釋放控制權
├── heartbeat # 心跳
├── status # 控制權狀態
└── takeover # 強制接管
10.2 控制權管理
| 項目 | 數值 |
| 有效期 | 5 分鐘 |
| 心跳間隔 | 30 秒 |
| 心跳超時 | 60 秒後自動釋放 |
| 優先級 1 | 一般用戶 |
| 優先級 2 | 管理員(可強制接管) |
| 優先級 3 | 緊急 |
座標單位 (ROS 標準)
| 項目 | 單位 | 說明 |
| 位置 X, Y | 米 (m) | 機器人實際位置 |
| 角度 Orientation | 度 (°) | 0°=東,逆時針為正 |
| 地圖 MapW, MapH | 像素 (px) | 地圖圖片大小 |
| 解析度 MapResolution | m/pixel | 每像素對應公尺 |
完整協議:docs/MQTT_PROTOCOL_UNIFIED.md
第三方接入:docs/MQTT_THIRD_PARTY_SPEC.md
11. WebSocket Proxy
檔案:websocket-proxy/server.js (5309 行, 160KB)
| 功能 | 說明 |
| WebSocket Server | Port 8980,接收前端命令 |
| HTTP Client | 轉發命令至 ATOM API |
| Webhook Server | Port 8086,接收 ATOM 狀態推送 |
| AWS IoT MQTT | 雲端遠端控制 |
| ATOM 自動發現 | 掃描網段尋找 ATOM |
| 故障轉移 | 主 ATOM 無回應自動切換備用 |
| 健康檢查 | 定期 polling /service/system/check_alive |
配置檔案
// atom-config.json
{
"atomUrl": "http://192.168.168.168:8080",
"knownAtoms": [
{ "url": "http://192.168.168.168:8080", "successCount": 300 },
{ "url": "http://192.168.55.148:8080", "successCount": 237 }
]
}
// site-config.json
{
"siteId": "site_001",
"siteName": "場域名稱",
"robotName": "機器人名稱"
}
輔助模組
| 檔案 | 功能 |
control-manager.js | MQTT 控制權管理器 |
socket-server.js | Socket 伺服器封裝 |
mqtt-test-client.js | MQTT 測試工具 |
Android 版本內嵌 Java WebSocket Server,實現與 Node.js Proxy 相同的協議。
| 檔案 | 大小 | 功能 |
AmrPlugin.java | 71KB | Capacitor 插件入口 |
AmrWebSocketServer.java | 11KB | 內嵌 WebSocket Server |
AtomHttpClient.java | 22KB | HTTP 客戶端 |
AtomWebhookServer.java | 21KB | Webhook 接收 |
MqttManager.java | 90KB | AWS IoT MQTT |
RoboClawManager.java | 18KB | RoboClaw 馬達控制 |
Android 設定:最低 SDK 25 (Android 7.1)、編譯 SDK 34、橫向顯示、允許 HTTP 明文
檔案:electron/main.cjs (24KB) - 內嵌 WebSocket Proxy,自動管理生命週期
- 支援 NSIS 安裝程式和 Portable 版本
- 構建:
npm run electron:build
deploy/
├── scripts/setup.sh # 環境設定 (Node.js, Nginx)
├── scripts/deploy.sh # 部署腳本
├── scripts/kiosk.sh # Kiosk 全螢幕模式
├── systemd/*.service # 系統服務
├── nginx/atom.conf # 反向代理
└── autostart/*.desktop # 開機自動啟動
13. 儲存系統
檔案:SettingsStorage.ts
- 瀏覽器:localStorage
- Electron:檔案系統 (electronAPI)
localStorage 鍵值 (jixiang_ 前綴)
| 鍵名 | 內容 |
jixiang_language | 語言設定 |
jixiang_character | 角色選擇 |
jixiang_enabled_modes | 啟用的模式 |
jixiang_tray_config | 托盤配置 |
jixiang_api_config | API 端點設定 |
jixiang_speech_config | 語音配置 |
jixiang_mode_settings | 模式設定 |
自動儲存機制
- 啟動時載入:
initializeSettings()
- 每 30 秒自動儲存:
startAutoSave(30000)
- 關閉前儲存:
beforeunload 事件
14. TypeScript 類型定義
// 核心類型 (types.ts)
enum AppMode {
IDLE, HOME, DELIVERY, LEADING, COLLECTION,
CRUISE, BIRTHDAY, SETTINGS, VOICE_INTERACTION, GUIDE
}
enum RobotStatus { IDLE, MOVING, PAUSED, BLOCKED, EMERGENCY }
enum TrayConfigType { TR_1x1, TR_1x2, TR_1x3 }
enum GuideContentType { TEXT, IMAGE, VIDEO }
type Language = 'zh' | 'en' | 'ja'
type Character = 'bear' | 'girl' | 'warrior' | 'custom'
type SpeechEventType = 'onStart' | 'onArrival' | 'onFinish'
type ActivationStatus = 'active' | 'inactive' | 'pending'
interface TaskLogInfo {
mode: AppMode
startPoint: string; endPoint: string
startTime: Date; endTime: Date
durationMs: number; distanceM: number
status: 'completed' | 'cancelled' | 'failed'
}
interface ApiConfig {
elevatorIp: string; elevatorPort: string
cmsApiUrl: string; cmsApiKey: string; cmsSiteId: string
}
interface ProxyConfig {
host: string; port: number; autoConnect: boolean
}
15. 開發指南
環境準備
npm install
cd websocket-proxy && npm install
開發模式
# 方法 1:兩個終端
npm run dev # Vite 開發伺服器 (Port 3000)
npm run proxy # WebSocket Proxy (Port 8980)
# 方法 2:Proxy 熱重載
cd websocket-proxy && npm run dev
# 方法 3:Electron 開發
npm run electron:dev
構建命令
npm run build # TypeScript + Vite 打包
npm run lint # ESLint 檢查
npm run preview # 預覽構建結果
平台構建
npm run electron:build # Windows 安裝程式
npm run android:build # Debug APK
npm run android:build:release # Release APK
npm run ios:build # iOS
npm run deploy:pack # Orange Pi 部署包
build-all.bat # 一鍵全平台構建
路由結構
| 路由 | 元件 | 說明 |
#/ | App.tsx | 主應用(IDLE → HOME → 各模式) |
#/mapping-control | MappingControlPage | 手機建圖遙控 |
16. 部署指南
Web 部署
npm run build
# 將 dist/ 目錄部署到 Web Server
# 同時啟動 Proxy: cd websocket-proxy && node server.js
Electron (Windows)
npm run electron:build
# 輸出 NSIS 安裝程式到 release/
Android
npm run android:build
# 輸出 APK: android/app/build/outputs/apk/debug/
Orange Pi Zero3
npm run deploy:pack
# 在 Orange Pi 上執行:
./deploy/scripts/setup.sh # 環境設定
./deploy/scripts/deploy.sh # 部署應用
sudo systemctl start atom-proxy
sudo systemctl start atom-web
17. 配置參考
Port 配置
| 服務 | Port | 說明 |
| Vite 開發伺服器 | 3000 | 前端開發 |
| WebSocket Proxy | 8980 | 前端通訊 |
| Webhook Server | 8086 | ATOM 狀態回報 |
| ATOM Action Server | 8080 | ATOM HTTP API |
環境變數
# .env.local
VITE_GEMINI_API_KEY=your_api_key # Google Gemini API
VITE_AMR_WS_URL=ws://localhost:8980 # WebSocket Proxy
VITE_WEBHOOK_PORT=8086 # Webhook Port
# Proxy 環境變數
MQTT_ENABLED=true # 啟用 MQTT
ATOM_URL=http://192.168.168.168:8080 # ATOM 地址
關鍵檔案大小
| 檔案 | 行數 | 大小 |
AmrContext.tsx | 3,233 | 121KB |
server.js | 5,309 | 160KB |
MqttManager.java | - | 90KB |
AmrPlugin.java | - | 71KB |
constants.ts | - | 49KB |
electron/main.cjs | - | 24KB |
文件產生日期:2026-03-14 | 專案版本:v1.0.0 | 季享科技 JinHer Technology