콘텐츠로 이동

XM10 Extension Module SDK v2.9.0

릴리즈 날짜: 2026-10-19 | 대상 보드: Rev 2.0 전용 (Rev 1.1 은 v2.8.1 그대로) | 새로 생긴 것: 구조체 로깅 · USB 메모리 저장

🛑 Rev 2.0 전용 릴리즈입니다. Rev 1.1 SDK 는 v2.8.1 에서 바뀐 것이 없습니다. Rev 1.1 보드를 쓰신다면 이미 받으신 Rev1.1.zip 을 계속 쓰시면 됩니다.

⚠️ 이번 릴리즈에서 새로 생긴 동작은 아직 실제 보드에서 확인하지 못했습니다. 아래 "아직 확인하지 못한 것" 을 먼저 읽어 주세요. (보드 확인 전)


한눈에 보기

  • 구조체 로깅이 생겼습니다 (Rev 2.0). 직접 만든 구조체를 등록해 두면, 보드가 필드 이름 · 단위 · 타입을 값과 함께 PC 로 보냅니다. xm_api_logging.h 와 새 예제 Ex.44 입니다. (보드 확인 전)
  • USB 메모리 저장을 새 API 로 다시 제공합니다 (Rev 2.0). v2.5.0 에서 뺐던 기능입니다. 구조체 하나를 정한 주기마다 USB 메모리에 기록합니다. xm_api_usb_msc.h(함수 14 개)와 새 예제 Ex.10 · Ex.34 입니다. (보드 확인 전)
  • USB-CDC 함수 몇 곳이 바뀌었습니다 (Rev 2.0). 채널 이름 JSON 은 1,007 바이트까지 받고 XM_SetUsbCustomMeta() 가 bool 을 돌려줍니다. 디버그 메시지는 1,021 바이트까지입니다. 시스템이 쓰는 모듈 ID 로는 보낼 수 없고, 인터럽트 안에서 부르면 false 입니다.
  • 헤더에서 선언 3 개가 빠졌습니다 (Rev 2.0). 시스템이 자동으로 쓰는 함수 · 타입이라 직접 쓸 필요가 없습니다. 쓰던 코드가 있다면 새 SDK 로 빌드할 때 오류가 나므로 그 줄을 지우세요. 이름은 아래 "헤더에서 빠진 선언 3 개" 에 있습니다.
  • 빌드 설정이 바뀌었습니다 (Rev 2.0). 선언 없는 함수를 부르면 경고가 아니라 오류로 빌드가 멈춥니다.
  • xm10 도구의 .xmlog 받은 시각이 UTC 로 바뀌었습니다. pc_time_us 는 이제 1970-01-01 UTC 부터의 µs 입니다.
  • 예제 수 — Rev 2.0 48 개 / Rev 1.1 40 개.
  • Rev 2.0 SDK 에 적힌 펌웨어 버전은 2.9.0 입니다.

구조체 로깅 (Rev 2.0)

지금까지는 XM_SendUsbDataWithId() 로 float 배열을 보내고 XM_SetUsbCustomMeta() 로 채널 이름만 따로 알려 줬습니다. 이번에는 구조체를 통째로 등록해 보낼 수 있습니다. 보드가 각 필드의 이름 · 단위 · 타입을 함께 PC 로 보내므로, PC 는 값을 정해진 타입으로 풉니다. (보드 확인 전) Rev 1.1(v2.8.1)에는 구조체 로깅이 없습니다.

#include "xm_api.h"
#include "xm_api_logging_raw.h"   // XM_LOG_* 매크로를 쓰는 .c 파일에는 꼭 넣습니다

typedef struct {
    float    hip_angle;
    int16_t  emg[8];
    uint32_t mode;
} MyLog_t;                                          // 24 B — 크기는 4 의 배수

XM_LOG_DECLARE(MyLog, MyLog_t);                     // 구조체에 짧은 이름(토큰) MyLog 를 붙입니다

XM_LOG_FIELDS(MyLog) = {                            // 보낼 필드: 이름 · 단위 · 배율
    XM_FIELD(MyLog, hip_angle, "hip_angle", "deg", 1.0f),
    XM_FIELD_ARRAY(MyLog, emg, "emg", "mV", 1.0f),
    XM_FIELD(MyLog, mode, "mode", "", 1.0f),
};

void Control_Setup(void)
{
    if (!XM_LOG_REGISTER(MyLog, 0xF0, 1000)) {          // 모듈 ID 0xF0, 1000 Hz
        XM_SetLedEffect(XM_LED_1, XM_LED_BLINK, 200);   // 등록 실패는 LED 로 알립니다
    }
}

void Control_Loop(void)
{
    MyLog_t s = { 0 };
    (void)XM_LOG_SEND(MyLog, &s);                       // 등록한 주기보다 일찍 부르면 보내지 않고 false
}

쓰는 방법

  • 네 매크로(XM_LOG_DECLARE · XM_LOG_FIELDS · XM_LOG_REGISTER · XM_LOG_SEND)는 같은 .c 파일 안에서 씁니다. C 파일 전용입니다.
  • XM_LOG_REGISTER() 는 Control_Setup() 에서, XM_LOG_SEND() 는 Control_Loop() 에서 부릅니다. 둘 다 bool 을 돌려줍니다.
  • XM_LOG_SEND() 를 매 루프 불러도 등록한 주기로만 나갑니다. 주기가 되기 전에는 보내지 않고 false 입니다.
  • 구조체 크기는 4 의 배수이고 1,008 바이트 이하입니다. 구조체는 4 개까지 등록하고, 모듈 ID 는 0xF0 ~ 0xFE 에서 구조체마다 하나씩 고릅니다.
  • 필드는 구조체 하나에 1 ~ 90 개입니다. 필드 이름은 15 자, 단위는 7 자까지이고, 영문 · 숫자 · 기호(ASCII)만 쓸 수 있습니다.
  • 필드 타입은 멤버의 C 타입에서 자동으로 정해집니다. 배열 멤버는 XM_FIELD_ARRAY 로 적습니다.
  • 잘못 쓰면(지원하지 않는 멤버 타입, 4 의 배수가 아닌 크기 등) 컴파일러가 그 줄을 가리킵니다.
  • 보내지 못한 이유를 찾을 때는 XM_Log_GetStats() 로 카운터를 읽습니다.

알아 둘 점

  • 등록한 모듈 ID 는 그 구조체 전용입니다. 같은 ID 로 XM_SendUsbDataWithId() 를 부르면 false 입니다.
  • 구조체를 등록하면 XM_SendUsbDataWithId() · XM_SendUsbDebugMessage() 로 보내는 양에 한도가 생깁니다. 짧은 시간에 너무 많이 보내거나 한 번에 너무 크게 보내면 false 입니다. 큰 데이터는 구조체 로깅으로 보내세요.
  • XM_USB_SetHostProfile() 은 Control_Setup() 에서 첫 XM_LOG_REGISTER() 보다 먼저 부릅니다. 구조체를 하나라도 등록한 뒤에는 이 호출이 무시됩니다.
  • 구조체를 등록한 뒤에는 XM_SetUsbCustomMeta() 도 Control_Setup() 안에서만 부를 수 있습니다. 그 밖에서 부르면 false 입니다.
  • 일반 시리얼 터미널용 프로파일(XM_USB_HOST_TERMINAL)에서도 구조체 데이터는 그대로 나가 터미널 화면에 깨진 글자로 섞여 보일 수 있습니다. 텍스트만 볼 때는 구조체를 등록하지 마세요.
  • Control_Setup() 에서는 USB 가 아직 준비되지 않아 PC 로 보낸 메시지가 보통 나가지 않습니다. 등록에 실패했는지는 LED 로 알리세요.
  • 구조체를 등록하면 제어 루프가 1 ms 를 넘겨 늦어져도 Total Data(0x20)는 1 ms 마다 최대 한 번만 나가고, 그 구간에서는 xm_loop_count 값이 이어지지 않고 건너뜁니다. 보드가 보내는 간격과 PC 에 도착하는 시각은 1 ms 간격으로 고르지 않을 수 있습니다. (설계 목표, 보드 확인 전)

PC 에서 보기

  • SDK 에 들어 있는 xm10 도구가 모듈 ID 마다 탭을 하나씩 열고(탭 제목은 모듈 ID 와 구조체 이름), 필드 이름으로 그래프와 CSV 열 이름을 만들고, 보드가 보낸 타입으로 값을 풉니다. (보드 확인 전)
  • PhAI Studio 는 아직 개발 중이라, 직접 정의한 데이터 구조체(커스텀 구조체)는 우선 xm10 도구로 보고 저장하세요.
  • 구조체 로깅을 쓰지 않는 기존 방식(XM_SetUsbCustomMeta() + XM_SendUsbDataWithId())은 그대로 쓸 수 있습니다. 이때 보드는 지금까지처럼 채널 이름만 보내고, PC 는 값을 float32 로 가정합니다.

예제 Ex.44 — CDC Struct Logging (Rev 2.0)

구조체 두 개(SensorLog · StatusLog)를 등록해 버튼 · 확장 ADC · 합성 파형 값을 이름 · 단위와 함께 보냅니다. USE_H10 을 1 로 바꾸면 H10 의 고관절 값을 읽어 1 kHz 로 보내는 형태가 됩니다(읽기만 하고 토크는 내보내지 않습니다). 등록에 실패하면 LED 3 이 빠르게 깜빡입니다. 아직 보드에서 확인되지 않은 예제입니다. (보드 확인 전) Ex.44 CDC Struct Logging 보기


USB 메모리에 저장하기 (Rev 2.0)

v2.5.0 에서 뺐던 USB 메모리 저장을 새 API 로 다시 제공합니다. 구조체 하나를 등록해 두면, 저장하는 동안 정한 주기(정하지 않으면 1000 Hz)마다 그 구조체를 USB 메모리에 기록합니다. 기록 함수를 따로 부르지 않습니다. (보드 확인 전) v2.5.0 에서 뺀 이유는 저장 중에 표본이 조용히 빠질 수 있어서였습니다. 이번에는 빠진 표본 수와 가장 긴 공백을 XM_GetUsbLogStats() · summary.txt · 디코더 결과에서 볼 수 있습니다. (보드 확인 전) Rev 1.1(v2.8.1)에는 USB 메모리 저장이 없습니다.

// Control_Setup()
XM_SetUsbLogSource(&s_log, sizeof(s_log));   // s_log 는 전역 또는 static 구조체
XM_SetUsbLogSampleRateHz(100);               // 생략하면 1000 Hz

// Control_Loop() — XM_IsUsbLogReady() 와 XM_IsUsbLogSessionIdle() 이 모두 true 일 때
XM_StartUsbDataLog("", "loop_count(uint32_t), hip_L(float), hip_R(float), contact(uint8_t), _pad(3bytes)");
  1. Control_Setup() 에서 구조체를 등록하고 주기를 정합니다.
  2. Control_Loop() 에서 구조체의 값을 채웁니다. 저장은 Control_Loop() 가 끝난 뒤 시스템이 합니다.
  3. XM_IsUsbLogReady() 와 XM_IsUsbLogSessionIdle() 이 모두 true 일 때 XM_StartUsbDataLog() 로 시작합니다. false 가 돌아오면 XM_GetUsbLogLastStartError() 로 이유를 봅니다.
  4. XM_StopUsbDataLog() 로 멈추고 XM_IsUsbLogSessionIdle() 이 true 가 될 때까지 기다립니다. true 가 되면 파일이 모두 닫힌 것이므로 USB 메모리를 뽑아도 됩니다. (보드 확인 전)
종류 함수 부르는 곳
설정 XM_SetUsbLogSource() · XM_SetUsbLogSampleRateHz() · XM_SetUsbLogAutoTimestamp() · XM_SetUsbLogRollingSize() Control_Setup() · Control_Loop()
시작 · 정지 · 마커 · 통계 XM_StartUsbDataLog() · XM_StopUsbDataLog() · XM_InsertUsbLogMarker() · XM_GetUsbLogStats() Control_Setup() · Control_Loop()
상태 XM_IsUsbLogReady() · XM_IsUsbLogSessionIdle() · XM_IsUsbLogRecording() · XM_GetUsbLogLastStartError() · XM_GetUsbDiskFreeMB() · XM_GetUsbDiskTotalMB() 어디서나
  • 설정 · 시작 · 정지 · 마커 · 통계 함수를 다른 태스크나 인터럽트에서 부르면 아무것도 하지 않고 false 를 돌려줍니다.
  • 메타 줄(XM_StartUsbDataLog() 의 두 번째 인자)에는 구조체의 필드를 선언 순서대로 이름(타입) 으로 적고 쉼표로 잇습니다. 디코더가 이 줄로 데이터를 풉니다.
  • 비워 둔 바이트는 _pad(3bytes) 처럼 _ 로 시작하는 이름으로 적습니다. 필드 크기의 합이 등록한 구조체 크기와 다르면 시작하지 않습니다(XM_USB_LOG_START_METADATA_MISMATCH).
  • USB 메모리는 FAT32 로 포맷합니다. exFAT 과 NTFS 는 인식하지 않습니다.
  • 저장 주기는 1000 의 약수 중에서 고르고, 정하지 않으면 1000 Hz 입니다. 주기에 비해 구조체가 크면 시작하지 않습니다(XM_USB_LOG_START_TOO_BIG_FOR_RATE).
  • 1000 Hz 로 저장하면 표본이 일부 빠질 수 있습니다. 빠진 수와 가장 긴 공백은 XM_GetUsbLogStats() 와 디코더 결과에 나옵니다.
  • /LOGS/<세션 이름>/ 폴더에 metadata.txt · data_000_part_000.bin … · summary.txt 가 만들어집니다. 이름을 비우면 시계(RTC)로 YYMMDD_HHMMSS 를 만듭니다.
  • 파일은 정한 크기(기본 10 MB)마다 새 파트로 나뉩니다. (보드 확인 전)
  • 저장하는 동안에는 USB 메모리를 뽑지 마세요.

USB-C 포트는 하나입니다

  • XM10 의 USB-C 포트는 하나입니다. USB 메모리를 꽂아 두는 동안에는 PhAI Studio · xm10 도구 · USB 로 하는 펌웨어 업로드를 쓸 수 없습니다.
  • 이 동안에는 PC 와의 USB 통신이 끊겨 있어서 XM_IsUsbStreamConnected() 는 false 이고, PC 로 보내는 함수(XM_SendUsbDataWithId() 등)는 false 를 돌려줍니다.
  • 저장이 끝나면 USB 메모리를 뽑고 PC 를 연결하세요. (보드 확인 전)

예제 Ex.10 · Ex.34 (Rev 2.0)

예제 하는 일
Ex.10 USB Memory Log 버튼 1 로 저장을 시작 · 정지합니다. 루프 카운터 · 합성 사인파 · 합성 톱니파 · 버튼 상태 · H10 연결 여부를 구조체 하나(16 B)에 담아 100 Hz 로 저장합니다. 버튼 2 는 표시(마커)를 넣습니다. USB 메모리를 뽑고 PC 를 연결해 시리얼 터미널을 연 뒤 버튼 3 을 누르면 마지막 통계를 보냅니다 (보드 확인 전)
Ex.34 USB Memory Gait Log H10 보행 데이터를 구조체 하나(96 B)에 담아 1 kHz 로 저장합니다. 버튼 1 로 시작 · 정지하고, 버튼 2 · 3 은 마커를 넣습니다

두 예제 모두 아직 보드에서 확인하지 못했습니다. (보드 확인 전)

⚠️ Ex.34 안전: 기본 설정(USE_H10_ASSIST 0)은 기록만 하고 토크나 제어 명령을 보내지 않습니다. USE_H10_ASSIST 를 1 로 바꾸면 H10 의 기존 보조 알고리즘이 켜져 착용자에게 보조 토크가 걸립니다. 착용자와 주변의 안전을 확인한 뒤에만 켜세요.

빌드하기 전에 _SetupBodyData() 의 신체 정보(체중 · 키 · 다리 길이)를 착용자의 값으로 고치세요. 예시 값 그대로면 무릎 · 허벅지 각도가 부정확합니다.

저장한 로그를 푸는 PC 프로그램

USB 메모리의 /LOGS/<세션 이름>/ 폴더를 PC 로 옮겨 XM10 Log Decoder 로 풉니다. 빠진 표본이 있으면 그 위치와 길이를 알려 줍니다.

  • Windows 용 설치형 프로그램이고, 파이썬은 필요 없습니다.
  • 릴리즈 페이지의 첨부 파일에서 XM10 Log Decoder 2.2.1 을 받습니다.

USB-CDC 함수에서 바뀐 것 (Rev 2.0)

채널 이름 — XM_SetUsbCustomMeta()

  • JSON 은 1,007 바이트까지 받습니다(XM_USB_CUSTOM_META_MAX_LEN). 전에는 512 바이트를 넘으면 아무 알림 없이 보내지 않았습니다.
  • 반환값이 void 에서 bool 로 바뀌었습니다. 등록되면 true 입니다. NULL 이거나 너무 길면 false 이고, 이전에 등록한 이름이 그대로 남습니다.
  • 반환값을 쓰지 않는 코드는 그대로 빌드됩니다. NULL 을 넘겨 이름을 지우던 코드는 이제 지울 수 없습니다(false).
  • XM_USB_HOST_TERMINAL 프로파일이 아니면 PC 프로그램이 COM 포트를 열 때마다 채널 이름을 다시 보냅니다. 이름이 안 보일 때 USB 케이블을 다시 꽂지 않아도 됩니다. (보드 확인 전)
  • v2.8.1 에서 안내한 제한(창에서 Disconnect 뒤 Connect 만 다시 눌러 받은 .xmlog 에는 채널 이름이 없음)도 Rev 2.0 에서는 없어지도록 했습니다. (보드 확인 전)
  • 할 일: 이름 목록이 길다면 반환값을 확인하세요. false 면 단위를 이름 안에 적어(예: "IMU0 Roll [deg]") JSON 을 줄이세요.
  • Rev 1.1 은 v2.8.1 과 같습니다. 반환값이 없고, JSON 은 512 바이트까지이고, 이름은 USB 를 연결할 때 한 번 보냅니다. 이름이 안 보이면 케이블을 다시 꽂으세요.

디버그 메시지 — XM_SendUsbDebugMessage()

  • 문자열 뒤에 0x00 한 바이트를 붙여 보냅니다. 함께 보내는 데이터 패킷이 깨지지 않게 하려는 것입니다. XM_USB_HOST_TERMINAL 프로파일에서도 똑같이 붙습니다. (보드 확인 전)
  • 한 번에 1,021 바이트까지 보냅니다(XM_USB_DEBUG_MESSAGE_MAX_LEN). 넘거나 NULL 이면 false 이고 아무것도 보내지 않습니다. 길이는 바이트 기준이라 한글은 글자 수보다 바이트가 많습니다.
  • 빈 문자열("")은 0x00 한 바이트만 보내고 true 입니다. 전에는 false 였습니다.
  • 전에는 스트림을 받는 중에 텍스트를 보내면 메시지 하나마다 데이터 패킷 하나가 손실됐습니다. Rev 2.0 에서는 이 손실이 없도록 바꿨습니다. (보드 확인 전)
  • 할 일: 1,021 바이트를 넘는 메시지는 나눠서 보내세요. 구조체 로깅을 쓰면 더 짧은 한도가 적용됩니다.
  • Rev 1.1 은 v2.8.1 과 같습니다. 종료 바이트(0x00)를 붙이지 않고 1,021 바이트 한도도 없으며, 스트림을 받는 중에 보내면 메시지마다 데이터 패킷 하나가 손실됩니다.

시스템이 쓰는 모듈 ID — XM_SendUsbDataWithId()

  • 0x20 · 0xB2 · 0xED · 0xEE · 0xEF · 0xFF 로 보내면 false 입니다.
  • XM_SetUsbStreamModuleId() 는 이 값들을 무시하고 이전 ID 를 그대로 씁니다.
  • 할 일: 내 데이터는 0xF0 ~ 0xFE 를 쓰세요. SDK 예제는 0xF0 ~ 0xF3 만 씁니다.
  • Rev 1.1 은 v2.8.1 과 같습니다. 모든 ID 를 받습니다.

인터럽트 안에서 부르면

  • XM_SendUsbData() · XM_SendUsbDataWithId() · XM_SendUsbDebugMessage() 를 인터럽트 안에서 부르면 아무것도 보내지 않고 false 입니다.
  • 할 일: Control_Loop() 안에서 부르세요. 직접 만든 백그라운드 태스크(XM_Task_*)에서도 부르지 마세요. 보내는 데이터가 깨질 수 있습니다.
  • Rev 1.1 은 v2.8.1 과 같습니다.

헤더에서 빠진 선언 3 개

  • 빠진 것: XM_USB_ProcessPeriodic() · XM_GetUsbLogStatus() · XmLogStatus_e(XM_LOG_STATUS_*). 시스템이 자동으로 쓰는 함수 · 타입이라 직접 쓸 필요가 없습니다.
  • 쓰던 코드가 있다면 그 줄을 지우세요. 함수는 아래 "빌드 설정" 의 새 설정에서 implicit declaration of function 오류가 납니다. 타입 XmLogStatus_e 는 어느 설정에서나 unknown type name 오류가 납니다.
  • USB 메모리 저장 상태가 필요하면 XM_IsUsbLogRecording() · XM_IsUsbLogSessionIdle() 을 쓰세요.
  • Rev 1.1 은 v2.8.1 과 같습니다. 세 선언이 그대로 있습니다.

빌드 설정 — 선언 없는 함수 호출은 오류 (Rev 2.0)

Rev 2.0 SDK 의 빌드 설정(STM32CubeIDE 의 Debug · Release 와 CMake)에 -Werror=implicit-function-declaration 이 들어갔습니다.

  • 헤더에 선언되지 않은 함수를 부르면 이제 경고가 아니라 빌드 오류입니다. 전에는 경고만 나오고 빌드됐고, 이때 함수는 반환값을 int 로 가정하고 불렸습니다.
  • 화면에는 error: implicit declaration of function '함수 이름' 으로 나옵니다.
  • 이렇게 고치세요.
    1. 그 함수를 선언한 헤더를 #include 합니다. SDK 함수라면 보통 #include "xm_api.h" 하나면 됩니다. 직접 만든 함수라면 부르기 전에 원형(prototype)을 선언합니다.
    2. 함수 이름이 맞는지 확인합니다. 오타이거나 SDK 에서 빠진 이름일 수 있습니다.
    3. 위에서 설명한 빠진 선언 3 개를 쓰고 있다면 그 줄을 지웁니다.
  • 새로 받은 Rev2.0.zip 에 들어 있는 설정입니다. 이전 ZIP 으로 만든 프로젝트의 설정은 바뀌지 않습니다.
  • Rev 1.1 SDK 는 그대로입니다.

PC 데이터 도구 — .xmlog 받은 시각

xm10 도구가 .xmlog 에 적는 PC 가 받은 시각(pc_time_us)이 바뀌었습니다.

v2.8.0 · v2.8.1 v2.9.0
.xmlog 의 pc_time_us 수신을 시작한 뒤 흐른 µs 1970-01-01 UTC 부터의 µs
실시간 CSV 의 pc_time_s 수신을 시작한 뒤 흐른 초 그대로
  • 저장을 시작할 때 PC 시계로 기준을 한 번 잡고, 그 뒤는 PC 의 단조 시계로 더합니다. 그래서 저장하는 동안 PC 시계가 조정돼도 값이 튀거나 뒤로 가지 않습니다. 대신 오래 저장하면 PC 시계와 조금씩 벌어질 수 있습니다.
  • .xmlog 에서 뽑은 CSV 의 pc_time_us 도 UTC 값입니다. 날짜 · 시각까지 필요하면 이 값을 쓰세요.
  • 예전 도구(v2.8.0 · v2.8.1)가 만든 .xmlog 는 예전 값(수신을 시작한 뒤 흐른 µs)을 그대로 가지고 있습니다. 두 값을 섞어 비교하지 마세요.
  • .xmlog 형식을 칸마다 정리한 문서가 새로 생겼습니다. 형식에 맞지 않는 레코드를 만나면 읽기를 멈추는 규칙도 들어 있습니다 — pc-data-tool/spec/xmlog.md
  • 이 변경은 Rev2.0.zip 의 pc-data-tool/ 폴더에 들어 있습니다.
  • Rev1.1.zip 은 v2.8.1 과 같은 파일이라 이전 도구가 들어 있습니다. 새 도구가 필요하면 Rev2.0.zip 이나 GitHub 레포의 pc-data-tool/ 폴더에서 받으세요. 이 폴더는 보드 리비전과 무관하게 같은 파일입니다.

예제 개수

Rev 2.0 48 개 / Rev 1.1 40 개.

  • 새 예제 3 개 — 모두 🛑 Rev 2.0 전용입니다. Ex.10 USB Memory Log · Ex.34 USB Memory Gait Log · Ex.44 CDC Struct Logging
  • Ex.10 · Ex.34 는 v2.4.1 까지 있던 USB 메모리 예제(v2.5.0 에서 삭제)와 이름도 내용도 다른 새 예제입니다.
  • Rev 1.1 SDK 는 40 개 그대로입니다. Rev 2.0 에만 있는 예제는 Ex.10 · 34 · 36 · 40 · 41 · 42 · 43 · 44 로 모두 8 개입니다.

아직 확인하지 못한 것 — 꼭 읽어 주세요

이번 릴리즈에서 새로 생긴 동작은 빌드와 PC 쪽 시험으로만 확인했고, 실제 보드에서는 아직 확인하지 못했습니다. 써 보시다가 이상한 점이 있으면 알려 주세요.

  • USB 메모리 저장 전체 — 저장 · 정지 · 뽑기와 Ex.10 · Ex.34 입니다. 저장을 멈춘 뒤 XM_IsUsbLogSessionIdle() 이 true 가 되면 뽑아도 된다는 것도 포함합니다. (보드 확인 전)
  • USB 메모리를 뽑고 PC 를 다시 연결하는 동작 — USB-C 포트가 하나라서, 메모리를 뽑은 뒤 PC 연결(PhAI Studio · xm10 도구 · USB 로 하는 펌웨어 업로드)이 다시 되는지 시험하기 전입니다. (보드 확인 전)
  • USB 메모리 종류와 빠지는 표본 — 여러 종류의 USB 메모리를 비교하지 않았습니다. 1000 Hz 로 저장할 때 빠지는 표본 수는 메모리마다 다를 수 있고, 이 버전으로 측정한 숫자는 아직 없습니다. 저장이 Control_Loop() 주기에 주는 영향도 측정하지 않았습니다. (보드 확인 전)
  • 디코더의 허용 공백 — 1000 Hz · 100 Hz 가 아닌 저장 주기에서 디코더가 판정에 쓰는 허용 공백은 실제 보드 로그로 확인하지 않은 계산값입니다. (보드 확인 전)
  • 구조체 로깅 전체 — 구조체를 등록하고, 필드 정보를 보내고, 등록한 주기로 데이터를 보내고, xm10 도구가 탭 제목과 열 이름을 만들고 값을 타입대로 풀어 보여 주기까지의 과정과 Ex.44 입니다. 실제 보드에서 받은 데이터로는 확인하지 못했습니다. (보드 확인 전)
  • 구조체 로깅의 설계 목표 — PC 프로그램이 잠시(기본 50 ms, XM_Log_SetMinStallMs() 로 바꿀 수 있습니다) 멈춰도 보드가 데이터를 빠뜨리지 않고 담아 두는 것, 그리고 Total Data 를 1 ms 마다 최대 한 번만 보내는 것은 설계 목표입니다. 50 ms 는 아직 보드에서 재 보지 않은 초기값이라 보장이 아니라 목표입니다. (설계 목표)
  • 채널 이름 · 필드 정보를 다시 보내는 동작 — PC 프로그램이 COM 포트를 열 때마다 채널 이름(구조체 로깅을 쓰면 필드 정보도)을 다시 보내는 것과, 포트를 연 뒤 몇 초 안에 도착하는 것은 설계 목표입니다. (설계 목표, 보드 확인 전)
  • 디버그 메시지 끝의 0x00 — 메시지를 보내는 중에도 데이터 패킷이 빠지지 않는지 확인하지 못했습니다. (보드 확인 전)
  • 새 기능을 쓰지 않는 코드 — 구조체 로깅과 USB 메모리 저장을 쓰지 않는 코드에서 PC 로 나가는 데이터가 v2.8.1 과 같은지(위에서 바뀐 곳은 제외)를 보드에서 다시 확인하지 못했습니다. (보드 확인 전)
  • 버전 번호 — 보드에 올린 펌웨어가 2.9.0 으로 보고되는지는 확인하지 못했습니다. (보드 확인 전)
  • XM10 Log Decoder 설치 — 설치 파일을 파이썬이 없는 Windows PC 에 설치해 실행해 보지 않았습니다.

호환성

항목 내용
기존 펌웨어 코드 (Rev 2.0) 대부분 재빌드만 하면 됩니다. 다음은 고쳐야 합니다 — 헤더에서 빠진 선언 3 개를 쓰는 코드 · 선언 없는 함수를 부르는 코드(이제 오류) · 시스템이 쓰는 모듈 ID(0x20 등)로 보내는 코드 · 송신 함수(XM_SendUsbData() · XM_SendUsbDataWithId() · XM_SendUsbDebugMessage())를 인터럽트 안에서 부르는 코드 · 1,021 바이트를 넘는 디버그 메시지를 보내는 코드 · XM_SetUsbCustomMeta() 에 NULL 을 넘겨 이름을 지우던 코드
새 헤더 xm_api.h 가 xm_api_logging.h 와 xm_api_usb_msc.h 를 함께 가져옵니다. XM_LOG_ · XM_FIELD · XM_Log_ · XM_USB_LOG_ 로 시작하는 이름을 직접 만들어 쓰셨다면 겹칠 수 있습니다. xm_api_logging_raw.h 는 xm_api.h 가 가져오지 않으니, XM_LOG_* 매크로를 쓰는 .c 파일에서 직접 include 하세요
Rev 1.1 v2.8.1 그대로 — SDK · 헤더 · 예제 40 개 · USB-CDC 함수의 동작이 모두 같습니다. 새 헤더가 없어서 구조체 로깅 · USB 메모리 저장 코드는 Rev 1.1 에서 컴파일되지 않습니다
PC 데이터 도구 .xmlog 의 받은 시각(pc_time_us)이 바뀌었습니다. 필요한 Python 패키지는 그대로입니다 (pyserial pyqt5 pyqtgraph numpy)
부트로더 v1.1.0 그대로입니다. 이미 설치된 부트로더는 바꾸지 않아도 됩니다

다운로드

파일 대상
Rev2.0.zip Rev 2.0 보드용 SDK (예제 48 개, pc-data-tool/ 포함)
Rev1.1.zip Rev 1.1 보드용 SDK — v2.8.1 과 같은 파일입니다 (변경 없음, 예제 40 개)
XM10LogDecoder_Setup_v2.2.1_dbb8525.exe (.zip · SHA256SUMS.txt) XM10 Log Decoder 2.2.1 — USB 메모리에 저장한 로그를 푸는 PC 프로그램 (Windows)
AGR_Bootloader.bin XM10 부트로더 v1.1.0 — v2.8.1 과 같은 파일 (아직 보드로 확인하지 않음)
SUIT_H10_Binary_20260820.zip KIT H10 펌웨어 — v2.6.0 과 동일본
SUIT_ContentsFiles_20260820.zip H10 컨텐츠 파일 — v2.6.0 과 동일본

이번 변경은 Rev 2.0 에만 해당합니다. Rev 1.1 을 쓰신다면 이미 받으신 Rev1.1.zip(v2.8.1)을 계속 쓰시면 됩니다.

압축을 풀 때 짧은 경로(예: C:\xm10\)에 푸세요. 경로가 깊으면 윈도우의 경로 길이 제한 때문에 빌드가 실패할 수 있는데, 이건 코드 문제가 아니라 경로 길이 문제입니다.


관련 문서