# `translate.py` `dancer0.ino` 教學 --- ## 1 流程 1. **先用 `editor.py`** 編排好顏色幀、舞者 LED 光效,結果都存在 `data/` 資料夾。 2. **執行 `translate.py`** 後,程式會: 1. 讀取 `data/setting.json` + `data/data.json` …後把舞者 LED 布局、顏色表、幀資料抓進記憶體。 2. 逐一生成 `dancer0.ino‥dancerN.ino`,全放到 `esp32_ino/` 資料夾。 3. **用 Arduino IDE / PlatformIO** 將相對應的 `.ino` 燒進那位舞者的 ESP32 板子。 4. 上台時 **`editor.py` → UDP 廣播幀號** …後 ESP32 收到就立即呼叫 `playh()`,同步更新燈條顏色。 --- ## 2 `translate.py` 逐段解析 | 區塊 | 行數 | 作用 | 重點說明 | | ------------------------------- | ----------------------------- | --------------------------------------------------------- | ------------------------------- | | **載入 JSON** | `import json …` 之後 (行 1–14) | `load_json()` 幫我讀設定檔,保持 `utf‑8` 編碼 | 只要設定檔格式對,這邊基本不會出錯。 | | **全域常數** | 行 17–26 | `output_dir`、`WIFI_SSID`、`WIFI_PASSWORD` | Wi‑Fi 連線密碼直接硬寫這裡。 | | **工具函式** | 行 28–44 | `array_to_string()` 把 Python list 轉成 Arduino 用的 `{1,2,3}` | 這一招省去手動組字串的痛苦。 | | **`generate_content(dancerN)`** | 行 46–108 | **靈魂函式**:讀取第 `dancerN` 位舞者的 LED 排列 & 幀資料,拼出 `.ino` 原始碼 | | | **檔案輸出** | `create_ino_file()` (行 30–42) | 把字串寫進 `dancer{i}.ino` | 有 `try/except`,失敗會印 Error 不會當掉。 | | **`main()` loop** | 行 110–115 | for‑loop 產生全部舞者 `.ino` | 執行一次就全部搞定。 | ### 2‑1 動態產 C 陣列 ```python LED_stripe[i] = array_to_string(stripe) NUM_LEDS[i] = len(stripe) ... framedata = f"int data[{a}][{b}] = {c};" ``` * 我先把每條燈帶對應到人體部位的 **LED 索引** 攤平成 `{0,1,2,…}`。 * 接著把多維 `frames[nowdancer]` 轉 `{顏色 index}` 矩陣,給 ESP32 直接查表。 ### 2‑2 拼接 `Settingcode` `Settingcode` 內含: * `#define NUM_LEDSx` 讓 FastLED 知道每條燈長度。 * `DATA_PINx` 設燈帶接腳;我固定用 GPIO 17,16,32,33,25,26,14,27。 * `COLOR_COUNT`、`char colors[][20]` 存顏色 hex。 * `int LEDPARTx[]` → 每一條燈帶對應到「人體部位 index」陣列。 * 以上都在 `translate.py` 用 f‑string 串好再寫檔。 --- ## 3 `dancerX.ino` 架構(其他舞者同理) > 以下行數以 `translate.py` 內 template 為準,因為 `.ino` 直接由它輸出。 ### 3‑1 巨集 & 全域變數 ```cpp #define NUM_LEDS1 60 //左手臂 #define DATA_PIN1 17 ... char colors[][20] = {"#000000","#ff0000",…}; CRGB LED1[NUM_LEDS1]; CRGB* LEDstrings[] = {LED1,…}; ``` * **`LEDstrings`** 是二維指標陣列,`FastLED.addLeds<WS2812…>` 一次註冊八條燈帶。 * `lednums[]`、`pins[]` 也同步生成,方便迴圈掃描。 ### 3‑2 `setup()` – 初始化 ```cpp void setup(){ Serial.begin(115200); for(y=0;y<COLOR_COUNT;y++) colorArray[y]=hexToColor(colors[y]); FastLED.addLeds<WS2812, DATA_PIN1, GRB>(LEDstrings[0], NUM_LEDS1); ... // 其餘七條 WiFi.begin(ssid, password); while(WiFi.status()!=WL_CONNECTED){ delay(1000); } udp.begin(localUdpPort); } ``` * **`hexToColor()`** 把 `#RRGGBB` 字串轉 CRGB。 * FastLED + WS2812 設定一次就好。 * Wi‑Fi 連平台自己架,可用手機開熱點測試。 ### 3‑3 `loop()` – 收 UDP → 播放幀 ```cpp int packetSize = udp.parsePacket(); if(packetSize){ udp.read(incomingPacket,4); int frameN = (incomingPacket[0]<<24)|...; playh(frameN); } ``` * 我只收 4 bytes big‑endian 整數=「第幾幀」。 * 收到後立即呼叫 `playh()`,無條件同步,不等校正。 ### 3‑4 `playh(int frameN)` – 真正點燈 ```cpp for(int ledstring=0; ledstring<USEDPIN_NUM; ledstring++){ CRGB* strip = LEDstrings[ledstring]; int* map = leds[ledstring]; for(int led=0; led<lednums[ledstring]; led++){ strip[led] = colorArray[ data[frameN][ map[led] ] ]; } } FastLED.show(); ``` * **兩層 for‑loop**:外圈掃八條燈帶,內圈掃單顆 LED。 * `map[led]` 取得這顆 LED 對應的人體部位 index,再去 `data[frameN][part]` 找顏色。 * `FastLED.show()` 一次送完,延遲 < 2 ms,足夠舞台同步。 --- ## 4 常見雷區 & 我的踩坑經驗 | 問題 | 現象 | 解法 | |------|------|-----| | **LED 條長度不符** | 部分燈不亮、跟光效對不起來| 檢查 `setting.json` 裡每條陣列長度,跟實體 LED 顆數對齊。| | **Wi‑Fi 連不上** | ESP32 不停印 `Connecting to WiFi.` | SSID/密碼改對、確認 2.4 GHz;或改用手機熱點測。| | **UDP 丟包** | 少數幀錯位 | 可在 `editor.py` 端每 16 ms 重送上一次幀,容錯更高(實測可行)。| --- ## 5 動手練習 1. **改光效**:打開 `data/data.json` 把 `"#ff0000"` 換 `"#00ffff"`…後重跑 `translate.py`、重新燒錄,LED 效果應馬上變。 2. **變更 LED 排列**:在 `setting.json` 的 `"LED"` 陣列改順序,再生成 `.ino`,可測試右手臂/左手臂對調。 editor.py` `broadcast_port` 也改,觀察是否仍能同步。 ---