内容
# ESP32 电机控制 — WiFi + MCP 远程电机控制

ESP32 自身に HTTP 服务器を 띄우고, 폰/PC/AI 어디서든 WiFi 로 모터를 제어한다.
AI(Claude 등)는 표준 MCP 프로토콜로, 사람은 브라우저나 curl 로 제어합니다. 어느 방법을 쓰든 결국 ESP32 한 대에 붙는 것이라 별도 서버를 운영할 필요가 없습니다.
```
Claude (MCP tools) ─→ esp32-motor-mcp (Rust stdio MCP) ─→ HTTP ─→ ESP32 웹서버 ─→ 연속회전 서보
폰 브라우저 / curl ──────────────────────────────────────→ ↗
```
- 펌웨어: Arduino 코드 (ESP32-S3 와 일반 ESP32 둘 다 지원). 별도 라이브러리 설치가 필요 없습니다 — ESP32 보드 패키지만 설치하면 바로 컴파일됩니다.
- MCP 서버: Rust 로 작성. 무거운 프레임워크 없이 JSON 처리 라이브러리(serde_json) 하나만 사용해 가볍게 만들었습니다.
- 범용 시퀀스 언어: "왼쪽 2바퀴 돌고 1초 쉬고 오른쪽 1바퀴" = `L2,W1,R1`
## 1. 준비 부품
| 부품 | 주문 검색어 (쿠팡/디바이스마트/엘레파츠) | 참고 |
|---|---|---|
| ESP32 개발보드 (검정, USB-C 2개) | **ESP32-S3-DevKitC-1** 또는 "ESP32-S3 개발보드 N16R8" | USB-C 1개짜리 일반 "ESP32 DevKit V1"(WROOM-32)도 동일 동작 |
| 파란색 소형 모터 (360도 회전) | **FS90R 연속회전 서보** 또는 "SG90 360도 연속회전 서보" | 일반 SG90(180도)은 바퀴 회전 불가 — 반드시 "360도/연속회전(continuous rotation)" 표기 확인 |
| 연결선 | 점퍼케이블 암-수 (F-M) 3개 | 서보 케이블 3핀 |
일반 SG90 = 각도 제어용(0~180도). "2바퀴 돌려" 같은 회전 명령을 쓰려면 연속회전형이어야 함.
정밀한 바퀴 수가 중요해지면 스텝모터(28BYJ-48 + ULN2003 드라이버)로 업그레이드 권장.
## 2. 배선
| 서보 선 | ESP32 핀 |
|---|---|
| 주황/노랑 (신호) | GPIO 4 |
| 빨강 (VCC) | 5V (VIN) |
| 갈색/검정 (GND) | GND |
USB 5V 전원으로 서보 1개는 충분. 여러 개 달면 외부 5V 전원 분리.
## 3. 펌웨어 업로드 (Arduino IDE)
1. Arduino IDE 설치 → 환경설정 → 추가 보드 매니저 URL:
`https://espressif.github.io/arduino-esp32/package_esp32_index.json`
2. 보드 매니저에서 "esp32 by Espressif" 설치
3. 보드 선택: **ESP32S3 Dev Module** (일반 ESP32면 "ESP32 Dev Module")
4. 업로드 → 시리얼 모니터(115200)에 접속 SSID 와 IP 출력됨. 이후 USB 분리 가능(전원만 연결)
WiFi 연결 순서 (자동):
1. **등록해 둔 공유기** — 공유기 이름과 비밀번호는 보드 내부 저장공간(NVS)에 한 번만 저장해 두면 됩니다. 소스코드에는 비밀번호를 쓰지 않습니다 (아래 등록 방법 참고)
2. 등록된 공유기가 없거나 연결에 실패하면, 주변의 공개(암호 없는) WiFi 를 검색해서 신호가 센 순서로 최대 5곳까지 자동으로 연결을 시도합니다
3. 그것도 실패하면 보드가 스스로 임시 WiFi(`ESP32-MOTOR` / 비밀번호 `motor1234`)를 만듭니다 → 폰으로 여기에 접속한 뒤 브라우저에서 `http://192.168.4.1` 을 열면 됩니다
공유기 등록 방법 (한 번만 하면 재부팅해도 유지됩니다):
- 방법 A (시리얼): 시리얼 모니터(115200)에 `WIFI <공유기이름> <비밀번호>` 입력 → 저장 후 자동 재부팅
- 방법 B (웹): 위 3번의 임시 WiFi 상태에서 `http://192.168.4.1` 접속 → "WiFi 공유기 등록" 폼 입력
- 방법 C (API): `curl "http://<IP>/api/wifi?ssid=<ssid>&pass=<pw>"`
주의: 공개 AP 는 암호화가 없는 망이다. 이 장치는 모터 명령만 주고받으므로 실용상 문제 없지만, 상시 운용은 본인 공유기 등록을 권장.
## 4. 사용법
### 폰/PC 브라우저
`http://<ESP32_IP>/` — 버튼 UI (왼쪽/오른쪽 N바퀴, 연속회전, 정지, 시퀀스)
### API (curl / Claude / 자동화)
```bash
# 예: "왼쪽으로 2바퀴 돌고 1초 쉬고 우측으로 1바퀴"
curl "http://<IP>/api/seq?seq=L2,W1,R1"
curl "http://<IP>/api/turn?dir=left&turns=2" # 왼쪽 2바퀴
curl "http://<IP>/api/turn?dir=right&turns=1&speed=50" # 50% 속도
curl "http://<IP>/api/seq?seq=S-100" # 왼쪽 무한 회전
curl "http://<IP>/api/stop" # 정지
curl "http://<IP>/api/status" # 상태 JSON
```
시퀀스 문법 (범용 — 조합으로 어떤 응용 명령이든 표현):
| 토큰 | 의미 |
|---|---|
| `L<바퀴>` / `R<바퀴>` | 왼쪽/오른쪽 n바퀴. 소수 가능 (`L0.25` = 왼쪽 90도) |
| `W<초>` | 대기 |
| `S<±속도%>` | 연속회전 (음수=왼쪽), `/api/stop` 까지 |
| `S<±속도%>X<초>` | 시간지정 회전 (`S-50X3` = 왼쪽 50% 로 3초) |
| `@<속도%>` | 해당 스텝 속도 (`L2@50` = 왼쪽 2바퀴를 절반 속도로) |
| `&repeat=N` | 시퀀스 전체 N회 반복 |
응용 명령 변환 예:
| 자연어 명령 | API 호출 |
|---|---|
| 왼쪽 2바퀴 돌고 1초 쉬고 오른쪽 1바퀴 | `seq=L2,W1,R1` |
| 좌우로 반바퀴씩 3번 왔다갔다 | `seq=L0.5,R0.5&repeat=3` |
| 오른쪽으로 천천히 90도 | `seq=R0.25@20` |
| 왼쪽으로 5초간 돌다가 멈추고 오른쪽 3바퀴 | `seq=S-100X5,W0.5,R3` |
| 시계방향으로 계속 돌려 | `seq=S100` |
### 보정 (바퀴 수 정확도)
연속회전 서보는 시간 기반 근사라 개체별 실측 보정 필요:
```bash
curl "http://<IP>/api/cal_run?dir=left" # 정확히 10초 회전 — 바퀴 수를 눈으로 센다
curl "http://<IP>/api/cal?spr_left=0.625" # 10초에 16바퀴였으면 10/16=0.625
# 정지 상태에서 미세하게 돌면: curl "http://<IP>/api/cal?stop_us=1480" (1500 근처로 조절)
```
보정값은 보드 내부 저장공간에 저장되므로 한 번만 해두면 재부팅해도 유지됩니다.
## 5. MCP 远程控制 (AI 自然语言控制标准路径)
`mcp-server/` 폴더가 MCP 서버입니다. AI 가 이 서버를 통해 ESP32 的 기능을 표준 도구(tool)처럼 쓸 수 있게 해줍니다.
Claude Code 에 user 스코프로 등록 완료 (`claude mcp list` → esp32-motor Connected).
| MCP tool | 기능 |
|---|---|
| `motor_status` | 状态查询 (旋转中/队列/修正值/IP/信号强度) |
| `motor_turn` | 方向+轮数+速度 旋转 |
| `motor_seq` | 通用序列执行 (L/R/W/S 语法 + repeat) |
| `motor_stop` | 立即停止 |
| `motor_calibrate` | 修正值设置 (板内永久存储) |
| `motor_cal_run` | 10秒旋转修正助手 |
使用: Claude 会话中 "电机左转 2 圈,停顿 1 秒,右转 1 圈" → `motor_seq(seq="L2,W1,R1")` 自动调用.
ESP32 地址设置 (둘 중 하나):
- 默认: `~/.claude.json` 的 esp32-motor 项中 `ESP32_MOTOR_URL` 值 (初始值为临时 WiFi 模式地址 http://192.168.4.1 — 请将板子连接到路由器后更换为实际 IP)
- 调用별: 각 tool 的 `host` 인자로 재정의
재빌드: `cd mcp-server && cargo build --release`
MCP 를 안 쓰는 환경(폰 브라우저, curl, 다른 자동화 도구)에서는 4번 항목의 API 를 그대로 쓰면 됩니다. 어느 쪽이든 같은 ESP32 서버 하나에 연결되는 것이라 따로 관리할 것이 없습니다.
## 6. 常见问题 (完全初学者 Q&A)
### 开始前
**Q. 电子学完全不懂可以吗?**
是的。不需要焊接。只需将 3 根线插入引脚,程序通过 USB 加载即可。按照本文档的顺序即可完成。
**Q. 零件价格多少?**
主板 + 电机 + 电缆合计大约 2~3 万元(价格可能会有变动)。计算机可以使用 Windows/Mac 任意一种。
**Q. 我已经购买了普通的 SG90 伺服电机,可以使用吗?**
普通 SG90 只能进行角度控制(0~180 度),无法执行“旋转 2 圈”之类的命令。请选择带有“360 度/连续旋转”标识的 FS90R 系列。外观几乎相同,请务必确认商品名称。
### 主板连接和驱动
**Q. 我将主板插入 USB,但计算机无法识别。**
1. 最常见的是电缆问题 — “充电专用”电缆无法传输数据,请更换电缆。
2. 可能是驱动程序未安装。在设备管理器(Windows)中,如果看到“未知设备”,请为相应的主板芯片安装驱动程序:CP210x 来自 Silicon Labs,CH340 来自 WCH,均可免费下载。
3. 请直接插入计算机主机的 USB 接口,而不是使用 USB 扩展坞。
**Q. ESP32-S3 主板上有两个 USB-C 接口,应该插入哪一个?**
请插入标有“COM”/“UART”的接口。初始加载和串口监视器使用此接口比较稳定(另一个是“USB”接口,用于高级用途)。
### 固件加载
**Q. 加载时,端口(COM)未出现在列表中。**
主板必须被识别才会出现端口。请解决驱动问题。在 Arduino IDE 中,选择工具 → 端口菜单,COM 号是您插入的主板的端口。
**Q. 加载过程中出现“Failed to connect”错误。**
在加载开始时 **按住主板的 BOOT 按钮**,当出现“Connecting...”时松开手。通常这样就可以解决问题。如果仍然无法连接,请更换电缆或端口。
**Q. 我应该选择哪块主板?**
ESP32-S3 主板选择“ESP32S3 Dev Module”,普通 ESP32 主板(芯片上标记为 WROOM-32)选择“ESP32 Dev Module”。本项目代码支持两者。
**Q. 串口监视器中出现乱码。**
请将串口监视器右下角的波特率(baud rate)设置为 **115200**。
### 布线(线连接)
**Q. 伺服电机的 3 根线应该插入哪里?**
| 伺服线颜色 | 主板引脚 | 含义 |
|---|---|---|
| 橙色(或黄色) | GPIO 4 引脚 | 信号 |
| 红色 | 5V(或 VIN) | 电源 |
| 棕色(或黑色) | GND | 接地 |
引脚名称在主板上用小字印刷。只需将杜邦线插入对应的引脚即可。
**Q. 如果布线错误,会损坏吗?**
如果信号线插入其他 GPIO,引脚可能会没问题(但可能无法正常工作)。但 **请勿将红色(5V)和棕色(GND)线互换**,否则伺服电机可能会损坏。
### WiFi 连接
**Q. 无法连接到家里的 WiFi。**
ESP32 **仅支持 2.4GHz**。如果路由器的名称为“OOO_5G”之类,则它是 5GHz 网络,无法连接。请使用同一路由器的 2.4GHz 网络名称进行注册。
**Q. WiFi 密码应该在哪里输入?**
请勿在代码中输入(否则,密码将被暴露)。有两种方法:
- 在串口监视器中输入 `WIFI 路由器名称 密码`,然后按 Enter → 自动保存并重启。
- 在手机 WiFi 列表中连接 `ESP32-MOTOR`(密码为 motor1234)→ 在浏览器中访问 `192.168.4.1` → “WiFi 路由器注册”表单输入。
**Q. 我输入的密码错误。**
使用相同的方法重新输入即可覆盖原有密码。
**Q. `ESP32-MOTOR` WiFi 出现在我的手机上,这是什么?**
当主板无法连接到路由器时,它会创建一个临时的 WiFi 热点(正常运行)。连接后,您可以访问 `192.168.4.1` 进行电机控制和路由器注册。
**Q. 如何找到主板的 IP 地址?**
在串口监视器中,它会以 `STA connected: ... http://192.168.x.x/` 形式输出。如果您已经拔掉了 USB,请在路由器的“已连接设备”页面上查找以 esp32 开头的设备。
**Q. 我可以拔掉 USB 吗?**
可以。WiFi 连接后,USB 只提供电源。您也可以将主板插入手机充电器或移动电源,它们将正常工作。
### 电机运行
**Q. 电机完全不工作。**
1. 检查 3 根线是否按照表格插入(特别是信号线 = GPIO 4)。
2. 在浏览器中访问 `http://<主板IP>/` → 点击“左转 1 圈”按钮测试。
3. 如果仍然无法工作,请打开串口监视器查看错误信息。
**Q. 即使我停止了电机,它仍然会稍微转动。**
这是连续旋转伺服电机的个体差异(不是故障)。您可以调整停止脉冲:
`curl "http://<主板IP>/api/cal?stop_us=1480"` — 尝试 1480、1520 等接近 1500 的值,直到电机完全停止。
**Q. 我命令“旋转 2 圈”,但它旋转的圈数略多/少于 2 圈。**
连续旋转伺服电机基于时间,初始时会有误差。进行一次校准后,精度会大大提高:
1. `curl "http://<主板IP>/api/cal_run?dir=left"` → 准确旋转 10 秒。手动计数圈数。
2. 计算 10 ÷ 圈数 并注册:例如,如果是 16 圈,则 `curl "http://<主板IP>/api/cal?spr_left=0.625"`
3. 对右侧也执行一次(`dir=right`,`spr_right=`)。
**Q. 电机有嗡嗡声或无力。**
这是 USB 接口供电不足的迹象。请插入墙上充电器(5V 1A 或更高)。如果您计划连接多个伺服电机,请为伺服电机单独使用 5V 适配器。
### AI / MCP 控制
**Q. 什么是 MCP?是否必要?**
MCP 是 AI(Claude 等)与外部工具交互的标准方式。它不是必需的 — 您可以使用手机浏览器按钮或 curl 命令完成所有操作。MCP 提供了“语音控制”的标准化附加路径。
**Q. 如何向 AI 下达命令?**
注册 MCP 后,您可以用平常的语言告诉 Claude:“电机左转 2 圈,停顿 1 秒,右转 1 圈”。AI 会自动将其转换为 `L2,W1,R1` 序列。
**Q. 我可以在家外控制它吗?**
默认配置仅在同一 WiFi(在家中)内有效。外部控制需要路由器端口转发或 VPN(Tailscale 等),这是一个更高级的话题 — 请勿在没有安全设置的情况下开放端口。
**Q. 它似乎坏了。如果我想从头开始怎么办?**
通过 USB 重新上传固件将重置程序。如果要擦除存储的 WiFi/校准值,请在 Arduino IDE 中启用工具 → “Erase All Flash Before Sketch Upload”,然后上传。