# `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` 也改,觀察是否仍能同步。
---