Arduino
본 예제는 Arduino Nano 개발 보드, Windows PC 1대, 점퍼 와이어 여러 개, IMU 자세 센서, USB-TTL 변환 모듈을 사용합니다.
1. 장치 연결



2. 핵심 코드 해설
구체적인 코드는 자료의 소스 코드를 참조하세요.
C++
//링 버퍼의 데이터를 파싱하여 완전한 프레임 추출 및 캐시 갱신
//Process RX ring buffer, parse frames and update internal cache
void IMU_UART_Process(void)
{
enum {
RX_STATE_EXPECT_HEAD1 = 0,
RX_STATE_EXPECT_HEAD2,
RX_STATE_EXPECT_LENGTH,
RX_STATE_EXPECT_FUNCTION,
RX_STATE_COLLECT_DATA
};
static uint8_t rx_state = RX_STATE_EXPECT_HEAD1;
static uint8_t frame_length = 0;
static uint8_t frame_function = 0;
static uint8_t frame_buffer[64]; /* 数据区 + 校验 / data section + checksum */
static uint16_t frame_index = 0;
uint8_t current_byte = 0;
//링 버퍼의 모든 데이터 처리
while (_rxbuf_pop(¤t_byte) == 0) {
switch (rx_state) {
case RX_STATE_EXPECT_HEAD1:
//프레임 헤더 1 탐색
if (current_byte == FRAME_HEAD1) {
rx_state = RX_STATE_EXPECT_HEAD2;
}
//아니면 현재 상태 유지
break;
case RX_STATE_EXPECT_HEAD2:
//프레임 헤더 2 탐색
if (current_byte == FRAME_HEAD2) {
rx_state = RX_STATE_EXPECT_LENGTH;
} else {
//프레임 헤더 불일치, 처음부터 다시 탐색
rx_state = RX_STATE_EXPECT_HEAD1;
}
break;
case RX_STATE_EXPECT_LENGTH:
//프레임 길이 저장
frame_length = current_byte;
rx_state = RX_STATE_EXPECT_FUNCTION;
break;
case RX_STATE_EXPECT_FUNCTION:
//기능 코드 저장
frame_function = current_byte;
frame_index = 0;
rx_state = RX_STATE_COLLECT_DATA;
break;
case RX_STATE_COLLECT_DATA: {
//데이터 길이 계산(프레임 길이 - 헤더 2바이트 - 길이 1바이트 - 기능 코드 1바이트)
uint16_t data_length = (frame_length >= 4) ? (uint16_t)(frame_length - 4) : 0;
//데이터 길이 유효성 확인
if (data_length == 0 || data_length > sizeof(frame_buffer)) {
rx_state = RX_STATE_EXPECT_HEAD1;
break;
}
//현재 바이트 저장
frame_buffer[frame_index++] = current_byte;
//모든 데이터 수집 완료 여부 확인
if (frame_index >= data_length) {
//체크섬 계산
uint8_t calculated_checksum = (uint8_t)(FRAME_HEAD1 + FRAME_HEAD2 + frame_length + frame_function);
for (uint16_t i = 0; i < data_length - 1; ++i) {
calculated_checksum += frame_buffer[i];
}
//체크섬 검증
uint8_t received_checksum = frame_buffer[data_length - 1];
if (calculated_checksum == received_checksum) {
//검증 통과, 데이터 파싱
_parse_frame_data(frame_function, frame_buffer);
}
//상태 초기화, 다음 프레임 수신 대기
rx_state = RX_STATE_EXPECT_HEAD1;
}
} break;
default:
//알 수 없는 상태, 초기화
rx_state = RX_STATE_EXPECT_HEAD1;
break;
}
}
}
/* ---------- 解析数据帧 / Parse one complete frame ---------- */
static void _parse_frame_data(uint8_t frame_function, const uint8_t *frame_data)
{
switch (frame_function) {
case IMU_FUNC_RAW_ACCEL: {
//상수 스케일 계수 정의
const float ACCEL_RATIO = 16.0f / 32767.0f;
const float DEG2RAD = 3.14159265358979323846f / 180.0f;
const float GYRO_RATIO = (2000.0f / 32767.0f) * DEG2RAD;
const float MAG_RATIO = 800.0f / 32767.0f;
//가속도 데이터 파싱
s_ax = to_int16(&frame_data[0]) * ACCEL_RATIO;
s_ay = to_int16(&frame_data[2]) * ACCEL_RATIO;
s_az = to_int16(&frame_data[4]) * ACCEL_RATIO;
//자이로 데이터 파싱
s_gx = to_int16(&frame_data[6]) * GYRO_RATIO;
s_gy = to_int16(&frame_data[8]) * GYRO_RATIO;
s_gz = to_int16(&frame_data[10]) * GYRO_RATIO;
//자력계 데이터 파싱
s_mx = to_int16(&frame_data[12]) * MAG_RATIO;
s_my = to_int16(&frame_data[14]) * MAG_RATIO;
s_mz = to_int16(&frame_data[16]) * MAG_RATIO;
break;
}
case IMU_FUNC_EULER:
s_roll = to_float(&frame_data[0]);
s_pitch = to_float(&frame_data[4]);
s_yaw = to_float(&frame_data[8]);
break;
case IMU_FUNC_QUAT:
s_q0 = to_float(&frame_data[0]);
s_q1 = to_float(&frame_data[4]);
s_q2 = to_float(&frame_data[8]);
s_q3 = to_float(&frame_data[12]);
break;
case IMU_FUNC_BARO:
s_height = to_float(&frame_data[0]);
s_temperature = to_float(&frame_data[4]);
s_pressure = to_float(&frame_data[8]);
s_pressure_contrast = to_float(&frame_data[12]);
break;
case IMU_FUNC_VERSION:
s_version_high = frame_data[0];
s_version_mid = frame_data[1];
s_version_low = frame_data[2];
break;
case IMU_FUNC_RETURN_STATE:
s_last_rx_function = frame_data[0];
s_last_rx_state = (int16_t)frame_data[1];
break;
default:
//알 수 없는 프레임 유형, 오류 처리 추가 가능
break;
}
}IMU_UART_Process(): 캐시된 데이터를 읽고, 통신 프로토콜에 맞는 데이터를 _parse_frame_data로 파싱합니다.
_parse_frame_data(): 데이터 프레임을 파싱합니다.
3. imu 데이터 읽기
프로그램이 Arduino에 다운로드된 후 시리얼 어시스턴트를 열면(설정 파라미터는 아래 그림 참조) IMU 모듈의 데이터가 계속 출력되는 것을 볼 수 있습니다. IMU 모듈의 자세를 바꾸면 데이터가 변화합니다.

주의: 위는 10축 IMU 데이터 읽기입니다. 6축은 자기력계(Magnetometer)와 기압계(Barometer) 데이터가 없고, 9축은 기압계(Barometer) 데이터가 없습니다.

