# UART Protocol Reference

**What you’ll do**
- UART 바이트 스트림에서 `0xA5/0xB3/0xAF` 프레임을 안정적으로 파싱하고 송수신 규격을 맞춥니다.

**Prerequisites**
- Little Endian `float32`(IEEE-754) 인코딩/디코딩이 가능해야 합니다.

**Next**
- 값의 물리적 의미/부호/단위: {doc}`Vehicle Control Model </page/Introduction/control_model>`

KAIST 모빌리티 챌린지 플랫폼은 **PC와 하드웨어 간 UART 통신 프로토콜**을 이용합니다.

---

## 1. 통신 프로토콜 개요 

**UART 링크 설정**
* **Baud rate**: $9{,}600\sim2{,}250{,}000\,\mathrm{bps}$ (권장: $921{,}600\,\mathrm{bps}$)
* **Frame**: `8-N-1` (8 Data bits, No parity, 1 Stop bit)
* **Flow Control**: `RTS/CTS` 하드웨어 플로우 컨트롤 ON
* **Endianness**: `Little Endian` (모든 다중 바이트 데이터)

### 1.1 프레이밍/동기화(권장)

UART는 바이트 스트림이므로, 수신 측은 프레임 경계가 어긋날 수 있습니다. 아래와 같은 파싱 전략을 권장합니다.

- 스트림에서 `0xA5`, `0xB3`, `0xAF`를 **헤더 후보**로 스캔합니다.
- `0xA5`는 고정 길이(9B)이므로, 헤더 확인 후 8바이트를 추가로 읽습니다.
- `0xB3` 응답은 고정 길이(5B)입니다.
- `0xAF`는 `RW`, `N_ID`를 읽은 뒤 길이를 계산해 나머지를 읽습니다.
  - Read 요청(`RW=0x00`): `L_total = 4 + N_ID`
  - Write/응답(`RW=0x01`): `L_total = 4 + N_ID + 4N_ID = 4 + 5N_ID`
- 길이가 비정상(예: `N_ID`가 너무 큼)인 경우 해당 헤더는 폐기하고 다음 후보를 찾습니다.

### 1.2 데이터 타입 (Little Endian)

- `float32`: IEEE-754 32-bit float, Little Endian
- `uint32`: Unsigned 32-bit integer, Little Endian
- `0xA5`, `0xB3`의 payload는 **항상 `float32`** 입니다.
- `0xAF`(Utilities)의 **Write(DATA 포함) 요청은 ID와 무관하게 DATA를 `float32`로 해석**합니다.
- `0xAF`의 Read 응답은 일반적으로 `float32`를 돌려주며, **AllState(0x06) 응답 일부 필드만 `uint32`** 입니다. (아래 표 참고)


| Header | 패킷 명칭 | R/W | 길이 | 목적 |
| --- | --- | --- | --- | --- |
| ``0xA5`` | **Control** | Write | 9 Bytes | 실시간 제어 명령 ($v$, $\kappa$) 전송 |
| ``0xB3`` |**Vehicle Speed** | Read | 요청: 1 Byte / 응답: 5 Bytes | 차량 주행 속도 read |
| ``0xAF`` | **Utilities**| Read/Write | 가변 길이 | 설정/진단/상태 조회 및 단독 테스트 |
---

## 2. PC Control Packet (0xA5)

차량의 구동 및 조향을 직접 제어하는 패킷입니다.

* **전송 주기:** 권장 $300\,\mathrm{Hz}$ (최대 $1\,\mathrm{kHz}$)

* **데이터 구조:**

| Byte 위치 | 필드명 | Type | 단위 | 설명 |
| --- | --- | --- | --- | --- |
| 0 | Header | `uint8` | - | `0xA5` |
| 1 ~ 4 | velocity_mps | `float32` | $\mathrm{m/s}$ | 목표 속도 |
| 5 ~ 8 | curvature_1pm | `float32` | $\mathrm{m}^{-1}$ | 목표 곡률 |

--- 

```{admonition} 참고
:class: note

값의 물리적 의미(부호 규약 포함)는 {doc}`Vehicle Control Model </page/Introduction/control_model>`에 정리되어 있습니다.
```

### 2.1 전송 프레임 구조(PC → MCU)
* **예시** :  $v = 1.23\,\mathrm{m/s}$, $\kappa = 0.50\,\mathrm{m}^{-1}$
    * `1.23f` (`float32` LE) = `A4 70 9D 3F`
    * `0.50f` (`float32` LE) = `00 00 00 3F`
```text
0xA5    0xA4 0x70 0x9D 0x3F     0x00 0x00 0x00 0x3F
Header  [--float32 speed--]    [-float32 curvature-]
```
### 2.2 응답 프레임 구조
* **응답없음**

### 2.3 적용/안전
- `0xA5`는 ACK가 없고, 보드는 **마지막으로 수신한 $(v,\kappa)$를 계속 적용**합니다.
- 제어 루프가 멈추거나 통신이 끊겨도 차량이 계속 움직일 수 있으므로, 호스트(PC)에서 **데드맨 타이머(예: 수백 $\mathrm{ms}$)** 를 두고 타임아웃 시 $(0,0)$을 보내 정지시키는 방식을 권장합니다.
- 속도 $v$는 내부에서 제한/평활화될 수 있습니다. 급격한 명령 변화는 그대로 즉시 반영되지 않을 수 있습니다.
## 3. Vehicle Speed Packet (0xB3)

### 3.1 요청 프레임 구조(PC → MCU)

단일 Byte `0xB3`를 전송합니다.
```text
0xB3 
Header 
```
### 3.2 응답 프레임 구조(MCU → PC)

* **프레임:** `[0xB3][speed(4B, float32)]`
* **예시 데이터 ($1.23\,\mathrm{m/s}$ 수신 시):**
```text
0xB3   0xA4 0x70 0x9D 0x3F
Header [-- float32 speed--]
```


### 3.3 값의 의미

`speed`는 차량 중심 속도 ($\mathrm{m/s}$)입니다.

---

## 4. Diagnostic & Device-Specific Utilities (0xAF)

`0xAF` 패킷은, 하드웨어의 세부 파라미터에 접근하거나 개별 장치를 조정하기 위해 사용됩니다.  
주로 초기 설정(Setup), 상태 진단(Diagnostics), 단독 테스트 시나리오에서 사용합니다.

실시간 조향/구동 제어는 기본적으로 `0xA5`($v$, $\kappa$)를 사용합니다.

### 4.1 활용 시나리오

- 시스템 기동 전 점검: 배터리 전압 확인, 엔코더 캘리브레이션
- 운용 중 모니터링: 온도/에러 코드/전류 등 이상 징후 확인
- 단독 테스트: 모터 속도/전류 직접 입력, 조향 서보 오버라이드

### 4.2 ID 목록

#### 4.2.1 상태 모니터링 (Monitoring)

| ID | 기능 | R/W | DATA 타입 | 단위 | 비고 |
|---:|---|---|---|---|---|
| `0x06` | AllState | R | (혼합) | - | 모터 상태 9개 필드 스냅샷 |
| `0x07` | Battery voltage | R | `float32` | $\mathrm{V}$ | `motor_id`는 무시됨(권장 0) |

#### 4.2.2 설정/진단/유틸리티 (Utilities)

| ID | 기능 | R/W | DATA 타입 | 단위 | 비고 |
|---:|---|---|---|---|---|
| `0x00` | Driver 초기화 | W | `float32` | - | 값은 무시됨 |
| `0x03` | Speed | R/W | `float32` | $\mathrm{eRPM}/\mathrm{rpm}$ | `write`: eRPM, `read`: rpm |
| `0x04` | Current | R/W | `float32` | $\mathrm{A}$ | `write`: A, `read`: A |
| `0x05` | Servo pulse | W | `float32` | $\mu\mathrm{s}$ | 조향 오버라이드(테스트용). 해제: `0.0` 전송 (Read 미지원) |
| `0x1E` | Encoder Calibration | W | `float32` | - | 값은 무시됨 |

```{admonition} 참고
:class: note

`0xAF`의 응답 프레임은 항상 `RW=0x01`(데이터 포함) 형태로 반환됩니다.
```


### 4.3 전송 프레임 구조 (PC → MCU)
패킷의 길이는 `RW` 필드와 `N_ID` 값에 따라 결정됩니다.

|0|1|2|3|4...4+N_ID-1|4+N_ID ...|
|---|---|---|---|---|---|
|`0xAF`|**motor_id**|**RW**|**N_ID**|**IDs** (각 1Byte)|**DATA** 각 ID마다 4Byte|

- RW=`0x01`인 경우, `DATA`는 `IDs`에 나열된 순서대로 4바이트씩 이어붙입니다.
- 응답 프레임도 `IDs` 순서와 `DATA` 순서가 1:1로 대응됩니다. (단, AllState는 예외)

`motor_id`는 요청 종류에 따라 의미가 달라집니다.
- 모터/드라이버 제어(예: Speed/Current/AllState 등): `motor_id` = 모터 id (0: left, 1: right)
- Servo pulse(`0x05`): `motor_id` = 서보 id (0: left, 1: right)
- Battery voltage(`0x07`): `motor_id`는 무시되지만, 프레임 형식상 1바이트는 항상 포함됩니다.

```{admonition} Servo pulse 오버라이드
:class: warning

Servo pulse(`0x05`)는 조향 출력을 직접 지정하는 override입니다. 값이 설정되어 있으면 $(v,\kappa)$ 기반 조향 대신 해당 pulse가 적용되며, 곡률 기반 조향으로 돌아가려면 `0.0`을 전송해 해제합니다. (출력은 $900\sim2100\,\mu\mathrm{s}$로 클램프)
```

#### 4.3.1 Read 요청
- RW=`0x00` (Read): Payload 없음

|0|1|2|3|4...4+N_ID-1|
|---|---|---|---|---|
|`0xAF`|**motor_id**|`0x00`|**N_ID**|**IDs** (각 1Byte)|

**길이:** $L_{total}=4+N_{ID}$

#### 4.3.2 Write 전송
- RW=`0x01` (Write)

|0|1|2|3|4...4+N_ID-1|4+N_ID ...|
|---|---|---|---|---|---|
|`0xAF`|**motor_id**|`0x01`|**N_ID**|**IDs** (각 1Byte)|**DATA** (RW=0x01일 때만, 각 ID마다 4Byte)|

**길이:** $L_{total}=4+N_{ID}+4N_{ID}=4+5N_{ID}$

### 4.4 응답 프레임 구조 (MCU → PC)
| 0      | 1            | 2                  | 3        | 4...4+N_ID-1      | 4+N_ID ...                             |
| --- | --- | --- | --- | --- | --- |
| `0xAF` | **motor_id** | `0x01` (응답/데이터 포함) | **N_ID** | **IDs** (각 1Byte) | **DATA** (각 ID마다 4Byte, Little Endian) |

#### 4.4.1 예외 응답
AllState(`0x06`)는 요청은 단일 ID로 보내지만, 9개 필드를 한 번에 보내는 구조입니다.
```text
요청: N_ID=1, IDs=[0x06]
응답: N_ID=9
ID_List : 0x06을 9번 반복 
Data_List: 9개 x 4바이트
```
```text
[0xAF][motor_id][0x01][0x09]
[0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06]
[data0(4B) ... data8(4B)]
```


### 4.5 활용 예시
#### 4.5.1 배터리 전압 읽기 (ID 0x07)
* **요청:** `0xAF 0x00 0x00 0x01 0x07` (Header, MotorID(권장 0), Read, N_ID=1, ID=7)
* **응답 ($12.34\,\mathrm{V}$ 가정):**
```text
0xAF   0x00   0x01   0x01   0x07  0xA4 0x70 0x45 0x41 
Header MotorID  RW    N_ID   ID  [--- 12.34V (float) ---]
```
```{admonition} 참고
:class: note

응답에서 RW의 `0x01`은 데이터가 포함된 프레임의 flag입니다.
```

#### 4.5.2 AllState (ID=0x06) 응답
AllState는 요청 시 `N_ID=1`, ID 리스트는 `0x06`만 보냅니다.  
하드웨어는 응답으로 **9개 데이터 필드**를 포함한 패킷을 반환합니다(응답 `N_ID=9`).

|#| 응답데이터| Type|설명 |
| --- | --- | --- |--- |
|`1`| **ID** | `uint32`| 모터 CAN ID | 
|`2`| **Position** |`float32`| 현재 각도($^\circ$) | 
|`3`| **Speed**|`float32` | 현재 회전 속도($\mathrm{rpm}$) | 
|`4`| **Current** | `float32` | 모터 전류($\mathrm{A}$) | 
|`5`| **Temperature** |`float32`| 모터/드라이버 온도($^\circ\mathrm{C}$) | 
|`6`| **Errorcode**  |`uint32`| 에러 플래그(하위 8비트 bitmask). `0x00`이면 정상 |
|`7`| **Current bandwidth** |`float32` | 전류 제어 컷오프 주파수($\mathrm{Hz}$) | 
|`8`| **Velocity Kp** | `float32` | 속도 제어 Kp (드라이버 내부 단위) | 
|`9`| **Velocity Ki** | `float32`| 속도 제어 Ki (드라이버 내부 단위) | 


##### Errorcode 비트 정의

`Errorcode`는 모터 드라이버가 상태 메시지에 포함해 보내는 **1바이트 오류 플래그**입니다. AllState에서는 `uint32`로 보이지만 실제 의미는 **하위 8비트**입니다.  
여러 비트가 동시에 켜질 수 있습니다(OR).

| Bit | Mask | 의미 | 비고 |
|---:|---:|---|---|
| 0 | `0x01` | CAN 오류 | CAN 송수신/버스 상태 오류 |
| 1 | `0x02` | SPI 오류 | 센서 SPI 통신 오류(초기화 실패 포함) |
| 2 | `0x04` | Driver fault | 게이트 드라이버 fault(nFAULT 등) |
| 3 | `0x08` | RCC 오류 | 클럭/시스템 초기화 관련 |
| 4 | `0x10` | ADC 오류 | - |
| 5 | `0x20` | TIM 오류 | - |
| 6 | `0x40` | HRTIM 오류 | - |
| 7 | `0x80` | FMAC 오류 | - |

```{admonition} 주의
:class: warning

`Errorcode != 0`이면 해당 모터 드라이버는 보호 상태로 들어가 출력이 중지될 수 있습니다. 주행 명령을 0으로 내리고, 필요하면 드라이버 리셋(초기화) 또는 전원 재인가로 복구하세요.
```

* **AllState 요청:** `0xAF 0x00 0x00 0x01 0x06` (left), `0xAF 0x01 0x00 0x01 0x06` (right)

* **응답 예시:**

| # | Field       | Type      | Unit      |   Value |
| --- | --- | --- | --- | --- |
|  `0` | **ID**        | `uint32`  | (ID 값)  |      1 |
|  `1` | **Position**  | `float32` | $^\circ$     |   10.0 |
|  `2` | **Speed**     | `float32` | $\mathrm{rpm}$     | 1000.0 |
|  `3` | **Current**   | `float32` | $\mathrm{A}$       |    2.5 |
|  `4` | **Temperature**      | `float32` | $^\circ\mathrm{C}$      |   35.0 |
|  `5` | **Errorcode**     | `uint32`  | bitmask (0이면 정상) |   0x00 |
|  `6` | **Current bandwidth** | `float32` | $\mathrm{Hz}$   |   50.0 |
|  `7` | **Velocity Kp**  | `float32` | -   |    0.1 |
|  `8` | **Velocity Ki**   | `float32` | -   |   0.01 |

```
0xAF 0x01 0x01 0x09 
0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06
0x01 0x00 0x00 0x00
0x00 0x00 0x20 0x41
0x00 0x00 0x7A 0x44
0x00 0x00 0x20 0x40
0x00 0x00 0x0C 0x42
0x00 0x00 0x00 0x00
0x00 0x00 0x48 0x42
0xCD 0xCC 0xCC 0x3D
0x0A 0xD7 0x23 0x3C
```
```
0xAF 0x01 0x01 0x09  -> [Header][Motor ID][RW][N_ID 9개] 
0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 0x06 [기능 ID 9개]
0x01 0x00 0x00 0x00 [id]
0x00 0x00 0x20 0x41 [position]
0x00 0x00 0x7A 0x44 [speed]
0x00 0x00 0x20 0x40 [current]
0x00 0x00 0x0C 0x42 [temperature]
0x00 0x00 0x00 0x00 [error code] 
0x00 0x00 0x48 0x42 [current bandwidth]
0xCD 0xCC 0xCC 0x3D [velocity kp]
0x0A 0xD7 0x23 0x3C [velocity ki]
```

#### 4.5.3 Servo pulse 오버라이드 (ID 0x05)

조향 서보를 단독으로 점검하거나 특정 펄스폭을 직접 넣어 확인할 때 사용합니다.

- 테스트 시작: `[0xAF][servo_id][0x01][0x01][0x05][float32 pulse_us]`
- 테스트 종료: 동일 프레임으로 `pulse_us = 0.0`을 보내면 $(v, \kappa)$ 기반 조향으로 복귀합니다.

`pulse_us`는 $900\sim2100\,\mu\mathrm{s}$ 범위로 제한됩니다.

권장: 운용 중 주행 입력은 `0xA5`로, 점검/설정은 `0xAF`로 분리해 사용합니다.
