PWM 서보 프로토콜, 명령과 캘리브레이션
이 페이지는 PWM 펌웨어의 시리얼 프로토콜, 명령, 캘리브레이션과 파라미터 미세 조정을 다룹니다. 배선은 PWM 배선, 플래싱은 PWM 빠른 시작, 데스크톱/웹 제어는 PWM 데스크톱 제어 프로그램 / PWM 웹 제어를 참고하세요.
아래 명령은 저장소의
AmazingHand-PWM/디렉터리에서 실행합니다. 펌웨어 소스:firmware/AmazingHand_Serial/.
1. 명령과 제스처 개요
앞 11개 줄은 제스처 명령이고, 나머지는 직접 구동, 방향 선택, 반복, 정지, 링크 테스트 명령입니다.
| 제스처/명령 | 명령 | 설명 |
|---|---|---|
| 주먹 | 0x01 | 가위바위보: 모든 손가락 주먹 |
| 가위 | 0x02 | 가위바위보: 검지+중지를 펴서 V자 |
| 보 | 0x03 | 가위바위보: 모든 손가락 펼침 |
| 엄지 척 | 0x04 | 엄지를 세우고 나머지는 주먹 |
| 놀림1 | 0x05 | 검지 흔들기("아니야 아니야") |
| 놀림2 | 0x06 | 약지 펴서 흔들기(새끼손가락 대체) |
| 펼치기 | 0x07 | 모든 손가락 펼침 |
| 주먹 쥐기 | 0x08 | 모든 손가락 닫기 |
| OK | 0x09 | OK 제스처 |
| 집기 | 0x0A | 집기(pinch) 제스처 |
| 가리키기 | 0x0C | 검지를 펴서 "가리키기" 동작 |
| 직접 구동 | 0xF0 | 서보 8채널 각도 직접 제어 |
| 왼손/오른손 설정 | 0xF1 | 왼손/오른손 모드 전환 |
| 반복 | 0xFE | 마지막 제스처 반복 실행 |
| 정지 | 0xFF | 현재 제스처 즉시 종료 |
| NOP | 0x00 | 링크 테스트 |
참고: 명령 0x0B는 폐기되었습니다(기존 "엄지 아래로"가 "엄지 척" 동작과 중복되어 제거됨).
2. 펌웨어 캘리브레이션(선택, 첫 사용 시 권장)
서보 중심 위치와 펄스 폭은 실제 기구에 맞춰 캘리브레이션해야 하며, 펌웨어 소스에서 직접 수정할 수 있습니다:
components/hand_servo/hand_servo.c상단의middle_pos[8]와min_pw/mid_pw/max_pw[8]를 편집합니다.
캘리브레이션 후에는 다시 컴파일해 플래싱해야 합니다.
3. 시리얼 통신 프로토콜
3.1 물리 계층
| 파라미터 | 값 |
|---|---|
| 인터페이스 | USB Serial (UART0) |
| 보드레이트 | 115200 |
| 데이터 비트 | 8 |
| 패리티 | 없음 (None) |
| 정지 비트 | 1 |
| 흐름 제어 | 없음 |
3.2 프레임 형식
호스트 → ESP32(명령 프레임)
┌────────┬────────┬──────────┬────────────────┬──────────┐
│ 0xAA │ CMD_ID │ DATA_LEN │ DATA[0 .. N-1] │ CHECKSUM │
│ 1 Byte │ 1 Byte │ 1 Byte │ N Bytes │ 1 Byte │
└────────┴────────┴──────────┴────────────────┴──────────┘
프레임 헤더 명령 ID 데이터 길이 데이터 페이로드 체크섬- 프레임 헤더: 고정
0xAA, 한 프레임의 시작을 표시 - CMD_ID: 명령 번호(명령 참고 참고)
- DATA_LEN: 데이터 페이로드의 바이트 수(0-8, 8을 초과하는 프레임은 무효)
- DATA: 데이터 페이로드, 길이는 DATA_LEN으로 결정
- CHECKSUM:
CMD_ID ^ DATA_LEN ^ DATA[0] ^ ... ^ DATA[N-1](XOR 체크섬)
DATA_LEN = 0이면 CHECKSUM = CMD_ID입니다.
ESP32 → 호스트(응답 프레임)
┌────────┬────────┬────────┬──────────┐
│ 0xBB │ CMD_ID │ STATUS │ CHECKSUM │
│ 1 Byte │ 1 Byte │ 1 Byte │ 1 Byte │
└────────┴────────┴────────┴──────────┘
프레임 헤더 명령 ID 상태 코드 체크섬- 프레임 헤더: 고정
0xBB - CMD_ID: 원래 명령 번호
- STATUS: 상태 코드(아래 표 참고)
- CHECKSUM:
CMD_ID ^ STATUS
상태 코드
| STATUS | 의미 | 설명 |
|---|---|---|
| 0x00 | OK | 명령이 수락되어 실행 시작 |
| 0x01 | 잘못된 명령 | CMD_ID가 명령 표에 없음 |
| 0x02 | 파라미터 오류 | 데이터 길이 또는 내용이 올바르지 않음 |
| 0x03 | 사용 중 | 제스처 실행 중, 새 명령을 임시로 받지 않음 |
| 0x10 | 완료 | 제스처 실행 완료 |
3.3 통신 타이밍
호스트 ESP32
│ │
│──── [AA 01 00 01] ────────→│ "주먹" 명령 전송
│ │
│←─── [BB 01 00 01] ─────────│ ACK: 명령 수락됨
│ │
│ (제스처 실행 중)
│ │
│←─── [BB 01 10 11] ─────────│ 완료: 제스처 실행 완료
│ │
│──── [AA 02 00 02] ────────→│ "가위" 명령 전송
│ │
│←─── [BB 02 00 02] ─────────│ ACK
│ │3.4 제스처 정지 & 프레임 타임아웃
[AA FF 00 FF]를 보내면 언제든 실행 중인 제스처를 중단할 수 있습니다- ESP32는 200ms 안에 한 프레임을 다 받지 못하면 자동으로 버립니다(바이트 유실로 인한 영구 탈조 방지)
- 체크섬이 맞지 않는 프레임은 조용히 버려지므로, 호스트 PC는 타임아웃 재전송을 구현해야 합니다
3.5 왼손/오른손 모드
기본은 오른손 모드입니다. [AA F1 01 02 F2]를 보내 왼손으로, [AA F1 01 01 F1]을 보내 오른손으로 전환합니다. 왼손/오른손은 엄지의 운동 방향에 영향을 줍니다(주먹/가위/엄지 척/OK/집기 등 엄지가 포함된 제스처).
4. 명령 참고
4.1 제스처 명령(0x01–0x0A, 0x0C)
이 명령들은 데이터 페이로드가 필요 없으며(DATA_LEN=0), ESP32가 받으면 즉시 해당 제스처를 실행합니다.
| 명령 | HEX 프레임 | 응답 | 설명 |
|---|---|---|---|
| 주먹 | AA 01 00 01 | BB 01 00 01 → BB 01 10 11 | 모든 손가락 주먹 |
| 가위 | AA 02 00 02 | BB 02 00 02 → BB 02 10 12 | 검지+중지 펼침 |
| 보 | AA 03 00 03 | BB 03 00 03 → BB 03 10 13 | 모든 손가락 펼침 |
| 엄지 척 | AA 04 00 04 | BB 04 00 04 → BB 04 10 14 | 엄지 세움 |
| 놀림1 | AA 05 00 05 | BB 05 00 05 → BB 05 10 15 | 검지 흔들기(약 2.5s) |
| 놀림2 | AA 06 00 06 | BB 06 00 06 → BB 06 10 16 | 약지 흔들기(약 2.5s) |
| 펼치기 | AA 07 00 07 | BB 07 00 07 → BB 07 10 17 | 모든 손가락 펼침 |
| 주먹 쥐기 | AA 08 00 08 | BB 08 00 08 → BB 08 10 18 | 모든 손가락 닫기 |
| OK | AA 09 00 09 | BB 09 00 09 → BB 09 10 19 | OK 제스처 |
| 집기 | AA 0A 00 0A | BB 0A 00 0A → BB 0A 10 1A | 집기(pinch) 제스처 |
| 가리키기 | AA 0C 00 0C | BB 0C 00 0C → BB 0C 10 1C | 검지를 펴서 "가리키기" 동작 |
4.2 직접 구동 명령(0xF0)
서보 8채널 각도를 직접 제어하며, 8바이트 데이터가 각각 서보 1-8에 대응하고 각 바이트 값 범위는 0-180입니다.
예시: 모든 서보 중간 위치(90°)
전송: AA F0 08 5A 5A 5A 5A 5A 5A 5A 5A F8
│ │ │ └── 0x5A 8개(90°) ──┘ │
│ │ │ └── CHECKSUM
│ │ └── DATA_LEN = 8
│ └── CMD_DIRECT_DRIVE
└── 프레임 헤더체크섬 = F0 ^ 08 ^ 5A ^ 5A ^ 5A ^ 5A ^ 5A ^ 5A ^ 5A ^ 5A = F8
0x5A 8개를 둘씩 XOR하면 0x00이 되고, 최종적으로
0xF0 ^ 0x08 ^ 0x00 = 0xF8입니다
예시: 검지 펼침(서보1=170°, 서보2=10°), 나머지 중간(90°)
전송: AA F0 08 AA 0A 5A 5A 5A 5A 5A 5A 58
└─170° └─10°4.3 왼손/오른손 설정(0xF1)
1바이트 데이터: 0x01 = 오른손, 0x02 = 왼손.
오른손 설정: AA F1 01 01 F1
왼손 설정: AA F1 01 02 F24.4 제어 명령
| 명령 | HEX 프레임 | 설명 |
|---|---|---|
| NOP | AA 00 00 00 | 링크 테스트, 즉시 BB 00 00 00 반환 |
| 반복 | AA FE 00 FE | 마지막 제스처 반복 실행 |
| 정지 | AA FF 00 FF | 현재 제스처 즉시 종료 |
4.5 응답 치트시트
잘못된 명령을 받았을 때(존재하지 않는 명령 0xFC 예):
전송: AA FC 00 FC
응답: BB FC 01 FD (STATUS=0x01 잘못된 명령)체크섬 검증:
FC ^ 00 = FC, 응답FC ^ 01 = FD
5. 제스처 파라미터 미세 조정
5.1 파라미터 위치
각 제스처의 각도 오프셋은 #define 매크로로 정의되므로, 로직 코드를 수정할 필요 없이 값만 조정합니다.
- ESP-IDF 버전:
components/hand_gestures/hand_gestures.c상단 "제스처 파라미터(사용자 조정 가능)" 영역
5.2 파라미터 의미
// 예: 주먹 제스처
#define ROCK_IDX_OFF1 70 // 검지 관절 1 오프셋
#define ROCK_IDX_OFF2 -70 // 검지 관절 2 오프셋- 양수 = 굽혀서 쥠, 음수 = 펴서 엶
- 손가락마다 오프셋 2개,
middle_pos(기본 90°) 기준 - 차동 구조: 두 서보가 나란히, 축 중심이 일직선; 같은 방향 회전은 좌우 벌림, 반대 방향 회전은 굴곡/신전; 두 오프셋 각도의 합은 벌림, 차는 굴곡/신전에 대응
5.3 조정 절차
- 해당 제스처의
#define매크로를 찾습니다 - 값을 수정합니다(크게 → 폭 증가; 작게 → 폭 감소)
- 다시 컴파일해 플래싱하고 호스트 PC로 테스트합니다
- 동작이 자연스러워질 때까지 반복 미세 조정합니다
6. 자주 묻는 질문
Q1: 호스트 PC가 시리얼 포트에 연결되지 않음?
- ESP32가 Type-C로 PC에 연결되었는지 확인
- 장치 관리자의 COM 포트 번호가 GUI 선택과 일치하는지 확인
- 보드레이트 115200 확인
- 시리얼 포트를 점유한 다른 소프트웨어 종료
Q2: 명령을 보내도 반응이 없음?
- 먼저
AA 00 00 00(NOP)을 보내고BB 00 00 00이 수신되어야 함 - 펌웨어가 플래싱되었고 대상 칩이 ESP32-S3인지 확인
- 배선 확인(GND 공통 접지 여부)
Q3: 제스처 동작 폭이 잘못되었거나 방향이 반대?
제스처 파라미터 미세 조정(5절)으로 해당 매크로를 조정합니다.
Q4: 왼손/오른손 모드가 어떤 제스처에 영향을 주나요?
주먹/가위/엄지 척/OK/집기 등 엄지가 포함된 제스처에서 왼손/오른손을 전환하면 엄지 미러 방향이 바뀝니다.
Q5: 손가락이 걸려 펴지지 않나요?
모든 수축 계열 제스처는 실행 전에 자동으로 "먼저 손 전체를 편 뒤 오므리므로" 이전 제스처에 손가락이 막히지 않습니다. 그래도 걸리면 기계 조립을 점검하거나 수축 폭을 줄이세요.

