UART Protocol Reference#

What you’ll do

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

Prerequisites

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

Next

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)입니다.

  • 0xAFRW, 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}\)

목표 곡률


참고

값의 물리적 의미(부호 규약 포함)는 Vehicle 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

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 타입

단위

비고

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

-

값은 무시됨

참고

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인 경우, DATAIDs에 나열된 순서대로 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

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개 필드를 한 번에 보내는 구조입니다.

요청: 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

설명

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 오류

-

주의

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로 분리해 사용합니다.