UART Protocol Reference#
What you’ll do
UART 바이트 스트림에서
0xA5/0xB3/0xAF프레임을 안정적으로 파싱하고 송수신 규격을 맞춥니다.
Prerequisites
Little Endian
float32(IEEE-754) 인코딩/디코딩이 가능해야 합니다.
Next
값의 물리적 의미/부호/단위: Vehicle 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하드웨어 플로우 컨트롤 ONEndianness:
Little Endian(모든 다중 바이트 데이터)
1.1 프레이밍/동기화(권장)#
UART는 바이트 스트림이므로, 수신 측은 프레임 경계가 어긋날 수 있습니다. 아래와 같은 파싱 전략을 권장합니다.
스트림에서
0xA5,0xB3,0xAF를 헤더 후보로 스캔합니다.0xA5는 고정 길이(9B)이므로, 헤더 확인 후 8바이트를 추가로 읽습니다.0xB3응답은 고정 길이(5B)입니다.0xAF는RW,N_ID를 읽은 뒤 길이를 계산해 나머지를 읽습니다.Read 요청(
RW=0x00):L_total = 4 + N_IDWrite/응답(
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 Endianuint32: Unsigned 32-bit integer, Little Endian0xA5,0xB3의 payload는 항상float32입니다.0xAF(Utilities)의 Write(DATA 포함) 요청은 ID와 무관하게 DATA를float32로 해석합니다.0xAF의 Read 응답은 일반적으로float32를 돌려주며, AllState(0x06) 응답 일부 필드만uint32입니다. (아래 표 참고)
Header |
패킷 명칭 |
R/W |
길이 |
목적 |
|---|---|---|---|---|
|
Control |
Write |
9 Bytes |
실시간 제어 명령 (\(v\), \(\kappa\)) 전송 |
|
Vehicle Speed |
Read |
요청: 1 Byte / 응답: 5 Bytes |
차량 주행 속도 read |
|
Utilities |
Read/Write |
가변 길이 |
설정/진단/상태 조회 및 단독 테스트 |
2. PC Control Packet (0xA5)#
차량의 구동 및 조향을 직접 제어하는 패킷입니다.
전송 주기: 권장 \(300\,\mathrm{Hz}\) (최대 \(1\,\mathrm{kHz}\))
데이터 구조:
Byte 위치 |
필드명 |
Type |
단위 |
설명 |
|---|---|---|---|---|
0 |
Header |
|
- |
|
1 ~ 4 |
velocity_mps |
|
\(\mathrm{m/s}\) |
목표 속도 |
5 ~ 8 |
curvature_1pm |
|
\(\mathrm{m}^{-1}\) |
목표 곡률 |
참고
값의 물리적 의미(부호 규약 포함)는 Vehicle Control Model에 정리되어 있습니다.
2.1 전송 프레임 구조(PC → MCU)#
예시 : \(v = 1.23\,\mathrm{m/s}\), \(\kappa = 0.50\,\mathrm{m}^{-1}\)
1.23f(float32LE) =A4 70 9D 3F0.50f(float32LE) =00 00 00 3F
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를 전송합니다.
0xB3
Header
3.2 응답 프레임 구조(MCU → PC)#
프레임:
[0xB3][speed(4B, float32)]예시 데이터 (\(1.23\,\mathrm{m/s}\) 수신 시):
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 타입 |
단위 |
비고 |
|---|---|---|---|---|---|
|
AllState |
R |
(혼합) |
- |
모터 상태 9개 필드 스냅샷 |
|
Battery voltage |
R |
|
\(\mathrm{V}\) |
|
4.2.2 설정/진단/유틸리티 (Utilities)#
ID |
기능 |
R/W |
DATA 타입 |
단위 |
비고 |
|---|---|---|---|---|---|
|
Driver 초기화 |
W |
|
- |
값은 무시됨 |
|
Speed |
R/W |
|
\(\mathrm{eRPM}/\mathrm{rpm}\) |
|
|
Current |
R/W |
|
\(\mathrm{A}\) |
|
|
Servo pulse |
W |
|
\(\mu\mathrm{s}\) |
조향 오버라이드(테스트용). 해제: |
|
Encoder Calibration |
W |
|
- |
값은 무시됨 |
참고
0xAF의 응답 프레임은 항상 RW=0x01(데이터 포함) 형태로 반환됩니다.
4.3 전송 프레임 구조 (PC → MCU)#
패킷의 길이는 RW 필드와 N_ID 값에 따라 결정됩니다.
0 |
1 |
2 |
3 |
4…4+N_ID-1 |
4+N_ID … |
|---|---|---|---|---|---|
|
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바이트는 항상 포함됩니다.
Servo pulse 오버라이드
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 |
|---|---|---|---|---|
|
motor_id |
|
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 … |
|---|---|---|---|---|---|
|
motor_id |
|
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 … |
|---|---|---|---|---|---|
|
motor_id |
|
N_ID |
IDs (각 1Byte) |
DATA (각 ID마다 4Byte, Little Endian) |
4.4.1 예외 응답#
AllState(0x06)는 요청은 단일 ID로 보내지만, 9개 필드를 한 번에 보내는 구조입니다.
요청: N_ID=1, IDs=[0x06]
응답: N_ID=9
ID_List : 0x06을 9번 반복
Data_List: 9개 x 4바이트
[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}\) 가정):
0xAF 0x00 0x01 0x01 0x07 0xA4 0x70 0x45 0x41
Header MotorID RW N_ID ID [--- 12.34V (float) ---]
참고
응답에서 RW의 0x01은 데이터가 포함된 프레임의 flag입니다.
4.5.2 AllState (ID=0x06) 응답#
AllState는 요청 시 N_ID=1, ID 리스트는 0x06만 보냅니다.
하드웨어는 응답으로 9개 데이터 필드를 포함한 패킷을 반환합니다(응답 N_ID=9).
# |
응답데이터 |
Type |
설명 |
|---|---|---|---|
|
ID |
|
모터 CAN ID |
|
Position |
|
현재 각도(\(^\circ\)) |
|
Speed |
|
현재 회전 속도(\(\mathrm{rpm}\)) |
|
Current |
|
모터 전류(\(\mathrm{A}\)) |
|
Temperature |
|
모터/드라이버 온도(\(^\circ\mathrm{C}\)) |
|
Errorcode |
|
에러 플래그(하위 8비트 bitmask). |
|
Current bandwidth |
|
전류 제어 컷오프 주파수(\(\mathrm{Hz}\)) |
|
Velocity Kp |
|
속도 제어 Kp (드라이버 내부 단위) |
|
Velocity Ki |
|
속도 제어 Ki (드라이버 내부 단위) |
Errorcode 비트 정의#
Errorcode는 모터 드라이버가 상태 메시지에 포함해 보내는 1바이트 오류 플래그입니다. AllState에서는 uint32로 보이지만 실제 의미는 하위 8비트입니다.
여러 비트가 동시에 켜질 수 있습니다(OR).
Bit |
Mask |
의미 |
비고 |
|---|---|---|---|
0 |
|
CAN 오류 |
CAN 송수신/버스 상태 오류 |
1 |
|
SPI 오류 |
센서 SPI 통신 오류(초기화 실패 포함) |
2 |
|
Driver fault |
게이트 드라이버 fault(nFAULT 등) |
3 |
|
RCC 오류 |
클럭/시스템 초기화 관련 |
4 |
|
ADC 오류 |
- |
5 |
|
TIM 오류 |
- |
6 |
|
HRTIM 오류 |
- |
7 |
|
FMAC 오류 |
- |
주의
Errorcode != 0이면 해당 모터 드라이버는 보호 상태로 들어가 출력이 중지될 수 있습니다. 주행 명령을 0으로 내리고, 필요하면 드라이버 리셋(초기화) 또는 전원 재인가로 복구하세요.
AllState 요청:
0xAF 0x00 0x00 0x01 0x06(left),0xAF 0x01 0x00 0x01 0x06(right)응답 예시:
# |
Field |
Type |
Unit |
Value |
|---|---|---|---|---|
|
ID |
|
(ID 값) |
1 |
|
Position |
|
\(^\circ\) |
10.0 |
|
Speed |
|
\(\mathrm{rpm}\) |
1000.0 |
|
Current |
|
\(\mathrm{A}\) |
2.5 |
|
Temperature |
|
\(^\circ\mathrm{C}\) |
35.0 |
|
Errorcode |
|
bitmask (0이면 정상) |
0x00 |
|
Current bandwidth |
|
\(\mathrm{Hz}\) |
50.0 |
|
Velocity Kp |
|
- |
0.1 |
|
Velocity Ki |
|
- |
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로 분리해 사용합니다.