SCS0009 桌面上位機(GUI 與 CLI)
本頁是 SCS0009 序列匯流排版的桌面控制教學。網頁控制見 SCS0009 網頁控制,硬體接線見 SCS0009 接線。
快速上手
- 安裝 Python 3.10+ 與相依套件:安裝。
- 連接匯流排驅動板,確認序列埠:環境需求。
- 執行 GUI:
amazing-hand-gui或python amazing_hand_gui.py。 - 按 標定 檢查左右手、角度和中位。
- 用逐指滑桿、預設姿態和序列做動作。
AmazingHand Python 控制工具(適用左手和右手)
用 Python 編寫的 GUI 與命令列工具,透過序列匯流排伺服馬達驅動板控制 8 個 Feetech SCS0009 伺服馬達,驅動 Pollen Robotics 的 AmazingHand 靈巧手。
左右手都支援。 啟動時選擇右手(伺服馬達 ID 1-8)或左手(伺服馬達 ID 11-18),--hand 可跳過提問。姿勢庫左右手共用,每隻手在 data/config.yaml 裡各自維護伺服馬達映射、安裝偏移和原始值目標。詳見左右手選擇。

專案結構
amazing_hand_gui.py – GUI 主程式
amazing_hand_cmd.py – 命令列工具
hand_logic.py – 共用業務邏輯(不依賴 UI)
pyproject.toml – 套件中繼資料、相依套件、pytest 設定
data/
config.yaml – 應用程式設定(序列埠、限位、原始值目標)
hand_config.yaml – 已儲存的手勢與序列
docs/
REQUIREMENTS.md – 需求與驗收標準
CONFIG_FORMAT.md – 設定檔格式說明
scs_servo_protocol.md – SCS0009 暫存器參考
CHANGES.md – 相對原版的改動說明與原因
user_manual.md – 已遷移到中央教學的跳轉頁
tests/
test_hand_logic.py – hand_logic 單元測試(155 項)
test_gui_utils.py – GUI 工具函式單元測試(51 項)
test_cmd.py – CLI 單元測試(42 項)
test_integration.py – 整合測試(14 項)
test_system.py – 子程序系統測試(22 項)
test_system_hardware.py – 硬體測試(33 項,需 --hardware)
test_cmd_hardware.py – CLI 硬體測試(21 項,需 --hardware)環境需求
- Python 3.10 或更高版本(GUI 需要包含 Tkinter)
- 為 8 個伺服馬達提供獨立的 5V 外接電源
- 已安裝好驅動的 USB 序列匯流排適配器
安裝
建議用 pip 安裝(讀取 pyproject.toml):
pip install -e .或直接安裝相依套件:
pip install -r requirements.txt開發與測試環境:
pip install -r requirements-dev.txt標定
伺服馬達的角度體系、手勢預設和中位都取決於具體的機械手。這些參數全部集中在 data/config.yaml。
左右手選擇
兩隻手用的伺服馬達和機械結構都不同,所以介面彈出之前先選:
AmazingHand — which hand?
1 = right hand (servo IDs 1-8)
2 = left hand (servo IDs 11-18)
Enter 1 or 2 [1]:
LEFT hand — servo IDs 11-18
Ring (11, 12) Middle (13, 14) Pointer (15, 16) Thumb (17, 18)
middle position raw: [571, 451, 571, 451, 571, 451, 571, 451]跳過提問:
python amazing_hand_gui.py --hand left
python amazing_hand_cmd.py --pose victory --hand left不加 --hand 時用 data/config.yaml 裡的 hand: 值。
為什麼一隻手不只是換組 ID。 除了伺服馬達編號(右手 1-8、左手 11-18,且左手的手指編號是鏡像的 —— 無名指在前),左手還有兩處機械差異,程式都會自動處理:
| 右手 | 左手 | |
|---|---|---|
| 伺服馬達 ID | 1-8 | 11-18 |
| 手指 → ID | 食指 1,2 / 中指 3,4 / 無名指 5,6 / 拇指 7,8 | 無名指 11,12 / 中指 13,14 / 食指 15,16 / 拇指 17,18 |
| 廠商 MiddlePos | [451, 571, …] | [571, 451, …] |
| 安裝偏移 | 0° | −35.16°(hands.left.angle_offset) |
| 同指雙伺服馬達 | (a, b) | (b, a)(hands.left.mirror_pose) |
上述後兩項漏掉任何一個手勢都會走形:安裝偏移會讓每根手指偏 35°,少了同指互換則張開方向整個反過來(V 字手勢兩指併攏、該併攏的三指反而張開)。
data/hand_config.yaml 是左右手共用的,儲存的永遠是右手序;左手在讀取時轉換、儲存時換回。
標定一隻新手。 以 hands.left 裡的值為範本,然後按這個順序核驗:
- 按 Middle position,看 Current (0-1023) 那行是否讀到預期的原始值
- 按 Open All / Close All —— 行程應該到機械限位且不堵轉
- 試一個張開手勢(victory 張成 V 字、greeting 三指併攏)
哪一項不對,該調哪個參數:
| 現象 | 改哪裡 |
|---|---|
| Middle position 讀數不對 | hands.<名稱>.raw_positions.middle |
| 張開方向反了 | hands.<名稱>.mirror_pose |
| 行程不夠或過頭 | hands.<名稱>.raw_positions.open / close |
角度體系
GUI 和 CLI 都使用角度值,由 rustypot 驅動換算成伺服馬達內部的原始值:
raw = 1024 × angle / 300° + 511 (0.29297°/step,原始值範圍 0–1023)| 角度 | 含義 |
|---|---|
| −35° | 完全張開(伸直) |
| 0° | 中位,手指自然微屈 |
| +75° | 完全握緊(拳) |
每根手指的兩個伺服馬達並排、軸心共線:同向旋轉產生側擺,反向旋轉產生屈伸。偶數 ID 伺服馬達相對奇數 ID 取反,所以同一個開合值就會讓兩個伺服馬達朝相反方向運動;這一點由程式自動處理,你不需要手動換算。
限位
limits:
servo_min: -75 # 任何伺服馬達指令的絕對行程上下限
servo_max: 75
base_min: -75 # 開合滑桿範圍
base_max: 75
side_min: -35 # 左右滑桿範圍
side_max: 35side_min/side_max 控制左右張開。由於程式做了歸一化(u = |side_offset| / |side_min|),只改這個範圍不會改變實際張開幅度,只是把滑桿刻度壓縮了。要真正改變手指張開的角度,必須同時修改 auto_extremes。
原始值目標
三個全域位置按鈕把伺服馬達驅動到精確的原始值,不經過角度模型:
raw_positions: # 下標 0 -> 伺服馬達 ID 1 …… 下標 7 -> 伺服馬達 ID 8
open: [260, 760, 260, 760, 260, 760, 260, 760]
close: [760, 260, 760, 260, 760, 260, 760, 260]
middle: [451, 571, 451, 571, 451, 571, 451, 571]- open / close —— 機械行程兩端。用廠商的 Feetech 調校工具單獨驅動伺服馬達測出來。
- middle —— 標定後的機械中位(即廠商 Arduino 演示程式裡的 MiddlePos)。注意它不是 open 和 close 的中點,而是偏離 raw 511 約 ±60 raw(±17.6°)。
這些是每隻手各自的標定值。廠商原話是 "replace values by your calibration results"。
如何校驗: Servo Feedback 面板有一行 Current (0-1023),即時顯示原始位置。按下 Middle position 按鈕後,這一行應該讀到 451, 571, 451, 571, …。
控制項範圍速查
| 控制項 | 範圍 |
|---|---|
| 開合滑桿(縱向) | −75 … +75 |
| 左右滑桿(橫向) | −35 … +35 |
| 速度 | 1(慢) … 6(快) |
速度值會由驅動當作 rad/s 傳給伺服馬達,所以 1–6 大致對應 57–344 °/s。帶載後實際速度約為該值的 70% —— 排序列延時時要把這一點算進去。
執行 GUI (amazing_hand_gui.py)

介面分為四塊:
- 左欄:四根手指的逐指控制面板,含開合/側擺滑桿、Auto/Raw 模式、速度、Open/Close/Center。
- 中欄:全域控制按鈕(Open All / Close All / Center All / Middle position)和姿態管理。
- 右欄:遙測曲線與 Servo Feedback 回饋表(位置、負載、溫度、電壓)。
- 底部:執行日誌與狀態列,顯示連線狀態、動作進度和錯誤資訊。
pip 安裝後可直接呼叫:
amazing-hand-gui
amazing-hand-gui --port /dev/ttyUSB0或直接執行:
python amazing_hand_gui.py
python amazing_hand_gui.py --port /dev/ttyUSB0埠下拉框會列出本機實際存在的序列埠(優先使用 pyserial,沒有則讀 Windows 登錄檔),所以編號靠後的適配器也能顯示出來。下拉框可以直接手輸埠號。設定裡的預設埠沒插時,GUI 會自動從第一個真實埠啟動;想固定埠就明確傳 --port。
功能

逐指滑桿控制開合與左右,支援 Auto(開合 + 左右)和 Raw(直接控制兩個伺服馬達角度)兩種模式
Auto 模式的兩個滑桿是控制軸,程式自動做差動合成;Raw 模式才是直接給兩個伺服馬達角度。每根手指的兩個伺服馬達並排、軸心共線:同向旋轉產生側擺,反向旋轉產生屈伸。
逐指 Open / Close / Center 快捷按鈕
逐指速度選擇(1–6),另有全域速度同步下拉框
鍵盤快速鍵,便於精確微調
全域位置按鈕:Open All、Close All、Center All、Middle position
基於 data/hand_config.yaml 的手勢與序列管理
可直接在介面上刪除已儲存的手勢(🗑 Delete 按鈕)
即時伺服馬達遙測曲線(位置、負載、溫度、電壓)
Servo Feedback 表格,含即時原始位置(0–1023),可用於標定校驗
鍵盤操作
- 1-4:選擇手指(Ring 無名指、Middle 中指、Pointer 食指、Thumb 拇指)
- 方向鍵:移動選中的手指
- 上/下:握緊 / 張開
- 左/右:左右移動
- 修飾鍵:
- 無:每次 1°(精調)
- Shift:每次 5°(常規)
- Ctrl:每次 10°(快速)
- 快捷動作:
- Q:選中的手指完全握緊
- E:選中的手指完全張開
- C:左右位置回正
全域按鈕
| 按鈕 | 開合 | 左右 |
|---|---|---|
| ✋ Open All | 所有手指到原始值 open | 回正 |
| ✊ Close All | 所有手指到原始值 close | 回正 |
| ⊙ Center All | 保持不變 | 回正 |
| ⊙ Middle position | 所有手指到原始值 middle | 回正 |
Global Speed 下拉框(1–6)會立刻把選定速度套用到所有手指控制項,並同步各指的滑桿顯示。
三個原始值按鈕(Open All、Close All、Middle position)繞過了角度模型,因此執行後滑桿顯示的是最接近的可表示值,而不是精確值。之後再碰滑桿,手會偏離原始目標最多約 0.3° —— 這是為了精確命中標定位置的刻意取捨。
已知問題:Center All 不會跳過處於 Raw 模式的手指,會覆蓋你手動設定的原始角度。單指的 ⊙ Center 按鈕則不會。
執行 CLI (amazing_hand_cmd.py)
獨立的命令列工具,無需啟動 GUI 即可套用手勢和播放序列。它讀取與 GUI 相同的 data/hand_config.yaml,並逐字發送儲存的姿勢值 —— 與 GUI 發出的完全一致。
Linux:序列埠權限
USB 序列埠適配器通常表現為 /dev/ttyACM0(Waveshare / CDC-ACM)或 /dev/ttyUSB0(FTDI / CH340)。
查找方式:
ls /dev/ttyACM* /dev/ttyUSB* 2>/dev/null
# 或者
dmesg | grep -E 'ttyACM|ttyUSB' | tail -5如果報 Permission denied,把目前使用者加入 dialout 群組後重新登入:
sudo usermod -aG dialout $USERpip 安裝後
amazing-hand-cmd --list
amazing-hand-cmd --pose open
amazing-hand-cmd --sequence demo --loop
amazing-hand-cmd --pose open --speed 6
# 需要時覆蓋序列埠:
amazing-hand-cmd --pose open --port /dev/ttyUSB0直接執行
python amazing_hand_cmd.py --list
python amazing_hand_cmd.py --pose open
python amazing_hand_cmd.py --pose close --speed 6
python amazing_hand_cmd.py --sequence demo
python amazing_hand_cmd.py --sequence wave --loop
python amazing_hand_cmd.py --port /dev/ttyUSB0 --pose open
python amazing_hand_cmd.py --list --config /path/to/hand_config.yaml參數
| 參數 | 預設值 | 說明 |
|---|---|---|
| --pose NAME | – | 套用指定名稱的手勢 |
| --sequence NAME | – | 播放指定名稱的序列 |
| --list | – | 列出所有手勢與序列 |
| --loop | 關 | 循環播放序列,直到 Ctrl+C |
| --speed N | 3 | 伺服馬達速度 1(慢)… 6(快) |
| --port PORT | Linux /dev/ttyACM0 Windows COM9 | 序列埠的埠號 |
| --baudrate N | 1000000 | 鮑率 |
| --config PATH | data/hand_config.yaml | 指定其他設定檔 |
| --hand | config.yaml 的 hand | 指定使用哪隻手(右手 1-8,左手 11-18) |
腳本結束時(包括 Ctrl+C)會自動關閉所有伺服馬達的力矩。
CLI 沒有對應 data/config.yaml 的 --config 參數,該檔案始終從專案目錄載入。
設定檔
data/config.yaml
| 段落 | 用途 |
|---|---|
| serial | 各平台預設序列埠、鮑率、可選鮑率列表 |
| servos | 每根手指對應的伺服馬達 ID |
| limits | 伺服馬達與兩個滑桿的角度範圍 |
| speeds | 1–6 速度刻度的預設值/最小/最大值 |
| auto_extremes | 左右滑桿到極限時的伺服馬達位置 |
| raw_positions | 全域位置按鈕的精確原始值目標 |
| paths | 手勢/序列檔案的位置 |
伺服馬達與手指的對應關係
| 手指 | 伺服馬達 ID | 姿勢陣列下標 |
|---|---|---|
| Pointer 食指 | 1, 2 | 4, 5 |
| Middle 中指 | 3, 4 | 2, 3 |
| Ring 無名指 | 5, 6 | 0, 1 |
| Thumb 拇指 | 7, 8 | 6, 7 |
姿勢陣列的順序是 無名指、中指、食指、拇指,不是按伺服馬達 ID 排列。 手動編輯 hand_config.yaml 時這是最容易搞錯的一點。
amazing_hand_cmd.py 頂部的註解寫著 "index 0→servo1 … 7→servo8",那個註解是錯的,上表才是程式的真實行為。
手勢與序列

所有手勢和序列都儲存在 data/hand_config.yaml。檔案不存在時 GUI 會自動建立。
儲存手勢
- 用滑桿或鍵盤把手擺到目標姿勢
- 在 "Name:" 輸入框填入名稱
- 點擊 Pose Management 區域的 "➕ Add New"
速度只影響滑桿的移動快慢;儲存的手勢只記錄 8 個伺服馬達位置。
載入 / 刪除手勢
- 從下拉框選擇後點擊 ✓ Apply 讓手移動到該姿勢
- 點擊 Apply 右側的 🗑 Delete,確認後永久刪除
序列管理
- 在 Sequence Player 中點擊 "🔧 Manage" 開啟序列管理器
- Saved Sequences(左欄)
- 檢視、執行、編輯或刪除已有序列
- 雙擊或點擊 "▶ Execute" 執行一次
- Sequence Builder(右欄)
- 雙擊 "Available Poses" 中的手勢即可加入為一步
- 可為每一步單獨設定 8 個伺服馬達的速度和延時;步驟以 "pose:s1,s2,...,s8|delay" 形式儲存
- 用 ↑/↓ 調整順序,或用 "⏱ Delay" 按鈕插入獨立暫停
- 填好名稱後點擊 "💾 Save Sequence" 儲存;點 "▶ Execute" 可先試跑不儲存
- 回到主視窗,需要連續播放時勾選 Sequence Player 裡的 Loop

步驟格式
pose_name:speed1,speed2,...,speed8|delay- speed1..speed8 —— 按姿勢順序排列的 8 個伺服馬達速度(1–6)
- delay —— 距離下一步的等待時間,如 0.6s。可省略;省略時 GUI 會退回到固定的自動等待
- 獨立暫停寫作 SLEEP:1.0s(沒有逗號分隔的速度列表)
延時的選取。 驅動本身能讀到達伺服馬達是否停止,但序列播放用的是固定延時。大致按 行程角度 / (速度 × 57.3 × 0.7) 秒來估算,並留出餘量 —— 在帶載的手上,超過約 130° 的動作在速度 3 下需要 1.0 秒以上。
YAML 格式範例
poses:
open:
positions: [-35, -35, -35, -35, -35, -35, -35, -35]
close:
positions: [75, 75, 75, 75, 75, 75, 75, 75]
ring_close: # 無名指握緊,其餘張開
positions: [75, 75, -35, -35, -35, -35, -35, -35]
sequences:
demo:
steps:
- "open:3,3,3,3,3,3,3,3|2.0s"
- "close:6,6,6,6,6,6,6,6|2.0s"
- "ok:3,3,3,3,3,3,3,3|1.0s"
- "victory:3,3,3,3,3,3,3,3|1.0s"
- "greeting:3,3,3,3,3,3,3,3|1.5s"
- "close:6,6,6,6,6,6,6,6|2.0s"
wave:
steps:
- "open:6,6,6,6,6,6,6,6|0.8s"
- "wave_r:5,5,5,5,5,5,5,5|0.6s"
- "wave_l:5,5,5,5,5,5,5,5|0.6s"
- "open:5,5,5,5,5,5,5,5|0.8s"
finger_roll:
steps:
- "open:6,6,6,6,6,6,6,6|0.5s"
- "ring_close:5,5,5,5,5,5,5,5|0.6s"
- "open:5,5,5,5,5,5,5,5|0.5s"
- "middle_close:5,5,5,5,5,5,5,5|0.6s"
- "open:5,5,5,5,5,5,5,5|0.5s"循環播放由執行時控制(GUI 的核取方塊),不再寫入 YAML。
測試
專案包含 284 項單元/整合/系統測試,以及 54 項硬體測試。
執行全部測試(無需硬體)
pytest執行 GUI + CLI 硬體測試(需要連接伺服馬達)
pytest tests/test_system_hardware.py --hardware --port /dev/ttyACM0
pytest tests/test_cmd_hardware.py --hardware --port /dev/ttyACM0
# 或兩個一起:
pytest tests/test_system_hardware.py tests/test_cmd_hardware.py --hardwaretest_system_hardware.py 驗證連線、手勢套用、遙測讀取、單指張合/揮手、速度控制、序列執行與運動偵測。
test_cmd_hardware.py 端到端驗證 CLI 層:姿勢位置、速度參數、序列步驟、wait_for_motion、--list 輸出,以及結束時關閉力矩。
完整的驗收標準見 驗收需求與測試。
注意:非硬體測試斷言的是 hand_logic.py 裡的兜底預設值,那套預設值仍是原版的 −40…110 尺度。執行時 data/config.yaml 會覆蓋它們,所以無論你怎麼標定,測試都能通過 —— 但也意味著測試並不會校驗你目前的標定參數。
伺服馬達 ID 設定
用 Feetech 官方軟體配合序列匯流排驅動設定伺服馬達 ID 的教學: https://www.robot-maker.com/forum/tutorials/article/168-brancher-et-controler-le-servomoteur-feetech-sts3032-360/
Feetech 軟體下載: https://github.com/Robot-Maker-SAS/FeetechServo
遙測與回饋
- 指標選擇:位置、負載、速度、溫度、電壓、運動旗標。
- 圖表模式:Multi-Servo(多伺服馬達曲線)與 Scope(單通道示波器)。
- 縮放/平移:Y Zoom / Pan、Time Zoom / Pan。
- 回饋表:Goal、Position、Speed、Load、Voltage、Temperature、Status、Moving。


序列編輯器
- 在 Sequence Player 中點擊 Manage。
- 用 Available Poses 新增步驟,調整逐指速度、步驟延時或插入休眠。
- 用 ↑/↓ 調整順序,輸入名稱儲存;也可先 Execute 試運行。
- 回到主視窗選擇序列並 Play;啟用 Loop 連續播放。
序列定義位於 data/hand_config.yaml 的 sequences 鍵下。
疑難排解
| 現象 | 建議 |
|---|---|
| 未列出序列埠 | 重新插拔 USB 適配器、安裝驅動或重新啟動 GUI。 |
| Connect 按鈕變灰 | 已連線,先點 Disconnect。 |
| 調整視窗卡頓 | 關閉不必要視窗;resize 已做防抖/限流。 |
| 序列未驅動所有手指 | 檢查每步速度,確保每個姿態包含全部 8 個伺服馬達值。 |
| 阻塞指示持續 | 檢查機械卡阻;目標與實際位置差異大且無運動會觸發阻塞。 |
相關開發文件
致謝
原始專案:Betatester777 硬體與參考韌體:Pollen Robotics

