드라이버가 숫자 하나만 반환하면 무엇이 사라지는가
센서 읽기 함수가120을 돌려줬다. 이것이 rpm인지 rad/s인지, signed인지, 어느 축/시각의 값인지 모르면 제어기에 바로 넣을 수 없다. 오류 때0을 반환하면 실제 정지 측정값과 통신 실패도 구별할 수 없다. 과거 정상값을 다시 보내며 수신 시각을 덮으면 오래된 관측이 새 값처럼 보인다.
드라이버 계약은 입력의 표현/조건, 출력의 의미/유효성, 실패 시 처리를 정하는 약속이다. M04.01의 실행 대상/메모리, .03의 샘플 출처, .04의 바이트/응답, .05의 접수/만료를 한 경계로 연결한다. 일반적인 코딩 문법보다 이 약속을 먼저 확인해야 AI 호스트와 MCU가 같은 숫자를 같은 뜻으로 해석한다.
이 단위는 자체 가상 회전 센서와 속도 설정값의 종이 분석이다. 실제 제품/표준의 driver API나 검증된 모터 명령이 아니다. 정상/오류 표와 검사 결과는 제공 입력이며 실제 장치·보정/통신·제어 안정성을 시험한 것이 아니다.
바이트 표현과 물리량을 따로 정의한다
가상 센서의 schema는S1, firmware는F2, 보정 식별자는C3다. payload는 signed16 two's-complement·big-endian으로 표현한 정수 rpm이다. 제공 측정 범위는-3000~3000rpm이며 양 끝을 포함한다. 이는 이 예제 입력 규칙이지 모든16bit 센서의 측정 범위가 아니다.
정수 rpm을 표준 출력의rad/s로 바꾸는 관계는 한 회전=2πrad, 한 분=60s에서 나온다. 따라서 ω=raw×2π/60rad/s다. 원시값과 원시 단위도 추적할 수 있게 남긴다. 변환한 숫자만 보존하면 나중에 부호/scale/보정 오류를 구분하기 어렵다.
| 제공 바이트 | 해석과 변환 |
|---|---|
| 0x00/0x78 | 0x0078=120rpm → 4π≈12.5663706rad/s |
| 0xFF/0x88 | signed16 -120rpm → -4π≈-12.5663706rad/s |
| 0x02/0x58 | 600rpm → 20π≈62.8318531rad/s |
0xFF88을 unsigned로 읽으면65416이다. signed16의 음수 영역에서는65536을 빼므로-120이 된다. 이것은 숫자 표기/폭의 계약 설명이며 C/C++ 문법이나 포인터 연산 입문이 아니다. byte 안의 bit 순서와 두 byte의 endian도 M04.04처럼 분리한다.
출력 축은 sensor_shaft 프레임의 +z에 대한 오른손 방향 회전이라고 준다. ROS REP103의 SI·rad/우수좌표계와 연결하되 프레임 이름만 base_link로 바꿔 장착 변환을 끝냈다고 하지 않는다. 다른 축/방향·기구비/보정이 있으면 변환 관계와 버전이 별도로 필요하다.
표현 범위·측정 범위·명령 범위는 다르다
signed16 표현 범위는-32768~32767이다. 그 안의4000은 표현 가능하지만 가상 센서의 측정 계약±3000rpm 밖이므로 E_RANGE다. 반대로600rpm은 측정 계약 안이며 환산값62.8318531rad/s도 표현 오류가 아니다.
이제 별도 속도 명령의 허용 범위를-20~20rad/s로 정한다. 같은62.8318531rad/s를 명령으로 제출하면 이 명령 범위를 초과하므로 거부한다. 측정이 명령 한도보다 크다고 관측 자체를0으로 만들면 과속 정보를 잃는다. 감독 계층의 고장/제한 판단과 유효한 관측 보존을 구분한다.
형식 범위 안의 명령도 실제 장비의 허용 전압/전류·토크/속도·기구 한계와 현재 상태/권한을 보장하지 않는다. 모든 범위를 하나의 max 숫자로 합치지 말고 값의 목적과 적용 계층을 적는다.
현재 결과와 과거 정상값을 다른 경로로 돌려준다
현재 측정 결과는 OK 또는 ERROR다. OK에는 현재 값/단위/프레임·원본 표본ID/시각/clock·버전이 있다. ERROR에는 해당 오류 코드와 요청/시도 기록을 두며 현재 정상 측정값 필드는 없다. 실패 원인을 추측해0이나 이전값으로 현재 값을 채우지 않는다.
last_good은 표시/진단을 위한 별도 과거 기록이다. 이 예제에서는 마지막 OK의 값/표본ID/원본 시각을 보존하고 오류 때 덮지 않는다. 현재 ERROR와 last_good을 함께 보이더라도 현재 제어 입력이 OK가 되는 것은 아니다. 보간/추정값을 쓰려면 추정 출처·불확실성·시간/허용 정책을 별도 정의해야 한다.
| 예제 오류 코드 | 현재 측정에 대한 의미 |
|---|---|
| E_TIMEOUT | 완료 프레임을 기다리던 기한 만료. 현재 값 없음 |
| E_CRC | 제공 프레임 검사 실패. payload를 정상 측정으로 사용하지 않음 |
| E_SCHEMA | 지원하지 않는 schema/firmware/보정 조합·단위 형식 |
| E_RANGE | 제공 측정/명령 범위 위반 또는 비유한 명령 수치 |
| E_FRAME | 축/프레임이 다르고 검증할 변환 관계가 없음 |
| E_STALE | 같은 clock에서 계산한 표본 나이가 허용 한도 초과 |
| E_CLOCK | clock 관계/epoch 불명 또는 미래 표본 등 시간 계약 위반 |
코드 이름/우선순위는 자체 예제다. 실제 장치가 모든 원인을 구분할 수 있다고 주장하지 않는다. 예제는 수신 길이/CRC → 지원 버전/단위 → 원시 수치 → 축/프레임 → 시각/신선도 순으로 확인하고 첫 실패를 대표 오류로 남긴다. 원래 상태/동시 결함을 알 수 있다면 원본 진단 근거도 보존한다. 오류 코드를 바꿔 통신 성공률을 높였다고 보고하지 않는다.
원본 시각·clock과 신선도를 함께 검사한다
현재 장치 clock은mcuB7, 단위ms, now=1000ms라고 준다. 허용 표본 나이는0~30ms로 양 끝을 포함한다. 원본 표본 시각과 now가 같은 clock/epoch일 때만 age=now-sample을 계산한다. 수신 시각은 별도이며 원본 시각을 대신하지 않는다.
| 제공 기록 | 이 예제의 판정 |
|---|---|
| S1/F2/C3, raw120, mcuB7의980ms | age20ms, 나머지 검사도 충족하면 OK |
| 같은 조건,969ms | age31ms → E_STALE |
| 같은 조건,1030ms | 미래30ms → E_CLOCK |
| host 시각9000ms만 있음 | mcuB7과 관계 미제공 → E_CLOCK |
| schemaS2 또는 미지원F3/C4 | 지원 조합 불일치 → E_SCHEMA |
| 수신 timeout, last_good=raw120/980ms | 현재 E_TIMEOUT. 과거 기록을 새 측정으로 바꾸지 않음 |
정확히970ms면 age30ms로 시간 조건 안이다. 그렇다고 나머지 CRC/단위/버전·상태까지 통과했다고 덧붙이지 않는다. 시각 조건은 여러 검사 중 하나다. 이 예제의30ms는 요구로 정한 한도이며 모든 제어기에 충분한 물리 신선도 보장이 아니다.
호스트의 수신 시각으로 stamp를 덮으면969ms 표본도 '지금 도착한 새 값'처럼 보인다. M04.05처럼 서로 다른 clock의 숫자는 바로 차감하지 않는다. clock 변환을 쓴다면 관계/오차·재부팅/역행/단절 조건을 남긴다.
명령은 검사한 뒤 표현하고, 범위 위반을 숨기지 않는다
가상 명령 입력은 유한한rad/s이며 범위±20, 기준 축은sensor_shaft의+z다. NaN/무한·단위 미제공/불일치·다른 frame/미지원 버전은 정상 명령으로 접수하지 않는다. 이 예제에서 비유한 수치는 E_RANGE, 단위/버전 불일치는 E_SCHEMA, 변환 근거 없는 다른 frame은 E_FRAME으로 구분한다. 검증 순서를 지켜야 비정상 수치가 양자화나 비교를 통과하지 않는다.
전송 표현은 signed16 정수 한 단위가0.01rad/s라고 준다. 입력을0.01로 나눈 뒤 가장 가까운 정수로 반올림하고 정확한 절반이면0에서 먼 쪽을 고른다. 표현 전 원래 입력 범위를 먼저 검사하고, 표현 결과의 폭/범위도 확인한다. byte 배치는 이 예제에서big-endian이며 실제 프레임/CRC 구현은 제공하지 않는다.
센서120rpm의 환산값12.5663706rad/s를 유효한 새 명령으로 제출했다고 하자.1256.63706을 반올림해1257, 복원하면12.57rad/s다. 양자화 차이는약+0.0036294rad/s로0.005rad/s 이내다. 이것은 표현 오차이며 측정 정확도/추종 오차를 뜻하지 않는다. 끝값20은2000, -20은-2000으로 표현되고 두 끝 모두 허용한다.
입력62.8318531rad/s는 범위 밖이므로 자동으로20으로 clamp하지 않는다. 이 계약에서는 E_RANGE 거부이며 새 명령을 접수하지 않는다. 다른 설계가 제한 정책을 쓰면 요청값/실제 제한값·이유/정책을 명시해야 한다. 값이 바뀐 사실을 숨기며 '그대로 적용 성공'이라고 기록하지 않는다.
명령의 값/표현 검사를 통과해도 M04.05의 상태·epoch/seq·현재 권한/만료 검사는 남는다. 새 접수 거부가 기존 ACTIVE 명령을 즉시 취소한다는 정책도 여기서 추가하지 않는다. 기존 명령의 상태/lease는 그 계약대로 판단하고, 논리 접수와 실제 출력/물리 상태는 별도다.
ROS 메시지의 특례를 다른 계약에 복사하지 않는다
ROS2 Jazzy Imu 원본은 각속도rad/s·가속도m/s²를 사용한다. 모든0의 공분산은 미상이고, 해당 공분산 첫 원소-1은 그 추정량이 미제공임을 나타낸다. 숫자가 있다는 이유로 정확한0오차/유효한 추정이라고 해석하지 않는다.
Range 원본의 고정거리형에는±Inf로 검출/범위 밖을 나타내는 규칙이 있다. 현재 가상 회전속도 계약의 '유한 값만 허용'을 모든 ROS 메시지에 일괄 적용하면 이런 의미를 잃는다. 실제 메시지 종류/버전·sentinel과 단위를 먼저 확인한다. 이 단위에서 ROS 패키지를 설치하거나 토픽을 실행하지 않는다.
센서에서 호스트/제어기로 넘길 계약을 완성한다
입력에는 대상/주소·프레임/길이/바이트·비트/부호/scale·버전/보정이, 출력에는 raw와표준 값/단위·frame/축·원본/수신 시각과clock·표본ID/현재 상태·오류가 필요하다. 명령에는 요청ID/epoch/seq·원래/표현 값·단위/범위·만료·접수/거부가 붙는다. 각 필드의 주체와 의미를 정하면 '성공' 하나로 서로 다른 계층을 합치지 않게 된다.
기존 4.4 센서 시간 정합과 연결해 과거값/추정값을 원본 최신 관측으로 바꾸지 않는다. W07 기본 완료는 제공 계약의 계산/유효성·실패/미확인을 설명한 상태다. 학습 순서의 바로 다음은 이미 집필된 M07.04 주파수 응답·근궤적이며, 단위/시간·지연이 제어 해석에 미치는 영향을 연결한다. 이어지는 M26.01 요구사항·HSI에서 이 경계를 제어/보드·소프트웨어 요구와 연결한다. 실제 driver 실행·측정 정확도·안전 기능을 검증한 것은 아니다.