드라이브 모델 파일
내 서보 드라이브 붙이기 에서 쓰는 YAML 파일(schema: cia402_drive/v1)의 키 레퍼런스입니다. plem drive check 와 plem drive run 의 오류 문장이 schema §4.1 처럼 가리키는 번호는 이 페이지의 같은 번호 절입니다. plem drive run 의 동작, ROS 인터페이스, Python plem.drive 는 드라이브 버스 API 에 있습니다.
전체 모양
schema: cia402_drive/v1 # 이 문자열만 받습니다
model: { name: my_drive } # 파일 판본은 주석으로 적습니다 (제품은 읽지 않습니다)
bus: { name: my_drive, cycle_time_ns: 1000000, sync_mode: sm } # 버스는 /my_drive 로 뜹니다
fault_reset: { policy: none, pulse_ms: 0 }
# cia402_profile: [...] # 표준과 다른 드라이브만
slaves: # 드라이브 슬레이브, 1개 이상
- ring_position: 0
vendor_id: 0x00c0ffee
product_code: 0x00001001
pdo_mapping: scanned
startup_sdo: []
axes: # 이 슬레이브의 축, 1개 이상
- name: j0
channel: 1
mode: cst # cst | csp | csv — 축마다
mode_display: post_enable
factors:
gear_ratio: 100.0
encoder_resolution: 65536
torque: { unit: scaled_current, counts_per_amp: 50.0, torque_constant: 0.12 }
velocity: { velocity_factor: 1.0 }
flip: false
zero_offset_count: 0
error_code_pdo: null # scanned 매핑은 적어야 합니다 (§4.2)
limits:
position: { min_rad: -3.05, max_rad: 3.05 }
velocity_rad_s: 2.6
torque_nm: { min: -400.0, max: 400.0 } # cst 축만 — csp·csv 축은 적지 않습니다
# acceleration_rad_s2: 5.0 # csp·csv 축은 필수 — cst 축은 적지 않습니다
# approval: 없으면 미승인 — 승인 기록은 벤치가 이 파일 안에 씁니다 (§6)
위 값은 모양을 보이기 위한 것이지 어떤 드라이브의 값도 아닙니다. 축은 파일에 적은 순서가 곧 관절 순서이고(슬레이브를 오가며 섞을 수 없습니다), 버스 하나에 축은 8개까지입니다.
§1 필수 키와 생략
키는 아래에 적은 곳 말고는 전부 필수입니다. 빠진 키는 거부되고, 직접 정해야 하는 값을 기본값이 대신하지 않습니다. 빼는 것이 뜻을 갖는 곳은 아래뿐입니다.
cia402_profile— 빼면 CiA 402 표준 전이표를 씁니다(아래).- 스위치로 끈 기능의 하위 블록 —
bus.sync_mode: sm이면 슬레이브의dc를,fault_reset.policy: none이면pacing을 적지 않습니다(적으면 거부). 같은 이유로cst가 아닌 축에는limits.torque_nm을,cst축에는limits.acceleration_rad_s2를 적지 않습니다(아래). - 슬레이브의
stored_sdo— 빼면 드라이브의 저장값을 읽지 않습니다(아래). dc블록의write_cycle_time— 빼면 0x1C32:02 를 쓰지 않습니다(아래).approval— 빼면 미승인입니다(아래).factors.position, 그리고 위치·속도의unit— 값이rotary_motor_encoder하나뿐이라 빼도 같습니다(아래).error_code_pdo— 슬레이브 매핑이standard이거나, 선언한 매핑이 그 축 채널의 Error code(0x603F)를 담으면 빼도 그 항목을 씁니다. 그 밖의 매핑에서는 적어야 합니다(아래).
bus.name 은 로더만 보면 빼도 읽히지만, plem drive check 와 run 이 없으면 거부하므로 드라이브 버스에서는 필수입니다(아래).
값이 없다는 것은 정해진 표기로 적습니다: null(error_code_pdo, approval.record), [](startup_sdo, 매핑이 없는 SM 의 pdos). 스키마에 없는 키도 거부됩니다 — 오탈자가 생략으로 읽히지 않게 하기 위해서입니다.
지원하지 않는 선언은 받지 않습니다. mode 는 cst·csp·csv 만, factors 의 단위(unit)는 아래 표의 값만 받습니다.
§2 YAML 형식
로더는 YAML 의 좁은 부분집합만 읽습니다. 거부되면 구문 오류는 줄·열 번호를, 파일 형식 오류는 키 경로(slaves[1].axes[0].channel)를 알려 줍니다. 값 검사의 거부는 축 번호 아래의 파일 키(axes[i].limits.position·axes[i].name·axes[i].factors.gear_ratio·slaves[s].startup_sdo[w]·bus.cycle_time_ns)로 말하고, 그 i 가 파일의 어느 축인지는 로더의 INFO 대응 줄(axes[i] = slaves[s].axes[k] (이름))에 있습니다 — plem drive check 에서는 stderr 로, plem drive run 에서는 기동 로그로 나옵니다.
| 항목 | 규칙 |
|---|---|
| 문서 | 한 파일에 문서 하나. 맨 앞 --- 하나는 허용 |
| 금지 문법 | anchor·alias(&·*), 모든 명시 태그(!!int 포함), 블록 스칼라(|·>), merge key(<<). 중첩은 16단까지 |
| 키 | 문자열 키만. 같은 키 두 번은 거부 |
| bool | true·false 만(따옴표 없이). yes·on 은 거부 |
| null | null 만. ~·빈 값은 거부 |
| 정수 | 10진(앞자리 0 금지) 또는 0x 16진. +·_·1536.0·따옴표 거부. 음수는 부호 있는 칸(zero_offset_count, dc.sync0_shift_ns)에만 |
| 실수 | -1.5, 2e-3 같은 유한값. .5·1.·+1.0·.inf·nan 거부. 정수 표기(121)는 받습니다 |
| 문자열 | 숫자·bool·null 처럼 읽히는 값(12, true, 0x1f)은 따옴표로 감쌉니다. 제어 문자는 거부 |
| 인코딩·크기 | UTF-8, 1 MiB 까지 |
model
model.name — 1–31바이트(UTF-8 바이트 기준), 공백만으로는 안 됩니다.
bus
| 키 | 값 |
|---|---|
name | 버스 이름. plem drive run 은 버스를 /<name> 네임스페이스에서 띄우고, Python 은 Bus("<name>") 로 붙습니다. 영문, 숫자, _ 만 쓰고 숫자로 시작하지 않으며 64바이트 이하입니다. 어긋나면 거부합니다. plem drive check 와 run 은 이 키가 없는 파일을 거부합니다(로더 자체는 이 키가 없는 파일도 읽습니다). 승인 digest 에 들어가지 않으므로 이름을 바꿔도 승인이 유지됩니다 |
cycle_time_ns | 제어 주기(ns) — EtherCAT Cycle time(0x1C32:02)과 같은 단위. 200000–1000000, 1000 의 배수(µs 단위)만 받습니다 — 아니면 거부하고 반올림하지 않습니다 |
sync_mode | sm = PLEM 이 DC 를 켜지 않습니다(동기 방식은 드라이브 설정을 따릅니다 — A6B 두 축 예제(a6b_pair/drive.yaml)의 드라이브는 이때 Free Run 으로 돌았습니다: OP 에서 0x1C32:01·0x0981 이 0), dc_sync0 = 슬레이브 DC(AssignActivate·SYNC0 주기)를 켭니다. 값 이름은 ETG Sync mode(0x1C32:01)에서 빌렸습니다. 다른 값은 거부. dc_sync0 이면 모든 슬레이브가 dc 블록을 적습니다 |
dc 블록(sync_mode: dc_sync0 일 때만):
| 키 | 값 |
|---|---|
assign_activate | 0 이 아닌 값 — 드라이브 ESI 의 AssignActivate |
sync0_cycle_ns | 0 이 아닌 값, 버스 주기(ns)의 정수배 |
sync0_shift_ns | 부호 있는 정수(ns). 마스터가 SYNC0 을 주기 시작에서 이만큼 늦춥니다 — 아래 SYNC0 shift |
write_cycle_time | 선택. true 만 받습니다(빼면 쓰지 않음 — false 는 거부). PLEM 이 기동 때(PREOP) 0x1C32:02 = sync0_cycle_ns 를 슬레이브마다 한 번 씁니다(0x1C32:01 과 0x1C33 은 쓰지 않음). 드라이브의 ESI 나 매뉴얼이 0x1C32:02 를 rw 로 적고 마스터가 설정한다고 할 때만 적습니다(A6B. MR-J4-TM 은 :02 가 rw 이지만 매뉴얼이 :01 이 DC 레지스터를 따른다고 하지 않아(기본 Free Run) 미확인이고, PLEM 은 :01 을 쓰지 않습니다). :02 가 읽기 전용이거나 없는 드라이브(Yaskawa Σ-7S, Inovance SV660N, LS L7NH, Beckhoff AX8000, Omron 1S, Kollmorgen AKD)에는 적지 않습니다 — 적으면 기동 때 쓰기가 거부될 것으로 보이고(읽기 전용 객체에 대한 CoE abort), 그러면 슬레이브가 PREOP 에 남고(커널 로그에 0x1C32:02 SDO abort) 브레이크 해제가 거부됩니다. 켜면 config digest 가 바뀝니다(재승인) |
DC 의 기준 클록은 서보 슬레이브 중 링 위치가 가장 낮은 것입니다(파일의 슬레이브 순서와 무관). PLEM 은 드라이브의 0x1C32 를 읽지 않습니다. 드라이브가 돌 수 없는 주기는 드라이브가 거부합니다 — 기동 중(PREOP→SAFEOP)에, 또는 운전 중 동기 오류로 슬레이브가 OP 밖으로 떨어지는 형태로(A6B 문서의 동작과 참조 모델이며 모든 드라이브의 보장은 아닙니다). OP 가 아닌 슬레이브의 축은 브레이크 해제가 거부되고 rt_events 에 SLAVE_NOT_OPERATIONAL(98 — AL 상태: 0 오프라인(또는 조회 실패)·1 INIT·2 PREOP·4 SAFEOP·8 OP 이나 재구성 대기, 링 위치)이 남습니다. plem drive run 은 모든 슬레이브가 OP 에 든 뒤에야 버스를 띄우므로, 이 이벤트는 대개 그 뒤 슬레이브가 OP 를 벗어났다는 뜻입니다(8 은 재구성 대기). 커널 로그(sudo dmesg | grep -i ethercat)에서 AL status code 나 거부된 startup SDO(startup_sdo, 또는 dc.write_cycle_time 의 0x1C32:02)를 찾으세요.
dc_sync0 의 실기 근거는 A6B 두 대뿐입니다 — 0x1C32:02 를 손으로(CLI, RAM) 쓴 구성에 이어, PLEM 이 write_cycle_time 으로 쓰는 구성(지금 A6B 두 축 예제 a6b_pair/drive.yaml)에서도 OP 에 들어 enable 뒤 새 드라이브 fault 없이 추종했고, 두 감속기 출력축을 조(jaw)로 묶은 결합 구동도 했습니다(조가 하중을 실었는지는 재지 않았습니다). 다른 드라이브는 그 드라이브에서 돌려 보기 전에는 지원을 주장하지 않습니다.
SYNC0 shift
sync0_shift_ns 는 마스터 쪽 SYNC0 shift 입니다. PLEM 은 RT 루프가 깨어날 때 DC 기준 시각을 정하고 그 뒤에 그 주기의 프레임을 보내며, SYNC0 은 그 기준 시각에서 sync0_shift_ns 만큼 뒤에 울립니다. 드라이브 자신의 Shift time(0x1C32:03)과는 다른 값입니다(A6B 는 0x1C32:03 을 지원하지 않습니다).
SYNC0 은 그 주기의 프레임이 드라이브에 닿은 뒤에, 여유를 두고 울려야 합니다. 값은 아래 범위에서 고릅니다.
- 하한: 호스트가 깨어나 프레임을 보내기까지의 최악 시간 + 드라이브까지의 전송 시간 + 여유보다 크게
- 상한: 제어 주기 − 드라이브 자체 처리 시간(드라이브 매뉴얼)보다 작게
주기에 대한 비율로 생각합니다. 너무 작으면 보내는 목표는 고른데 토크가 가끔 튀거나 추종 오차가 갑자기 뜁니다.
A6B 두 대, 1 ms 주기에서 잰 값: 프레임은 깨어난 뒤 약 12 µs(p99 15 µs, 최대 55 µs)에 나갔습니다. sync0_shift_ns: 0 에서는 SYNC0 이 프레임보다 먼저 울려 드라이브가 가끔 한 주기의 목표를 건너뛰거나 되풀이했고, 20 µs 에서도 그랬습니다. 300 µs 에서는 10 번 돌려 한 번도 없었습니다. A6B 두 축 예제(a6b_pair/drive.yaml)의 300000 은 이 측정값이라 주기가 약 300 µs 이하면 맞지 않습니다. 다른 주기, 다른 드라이브, 드라이브 쪽 입력 shift(0x1C33), 한 번을 넘는 결합 운전은 아직 돌려 보지 않았습니다.
fault_reset
버스 전체에 한 번 정합니다.
policy | pacing |
|---|---|
none | 적지 않습니다 |
bounded_auto_reset | { interval_ms, max_attempts } 필수 — interval_ms > 0, max_attempts 1–10000 |
max_attempts 는 횟수 상한일 뿐, 그 횟수까지 안전하다는 보장이 아닙니다. interval_ms 는 제어 주기의 횟수로 셀 수 있어야 하며, 이 판정은 기동 때 합니다.
pulse_ms(필수, 0–1000) — fault reset 한 번에 controlword bit 7 을 켜 두는 최소 시간(ms)입니다. policy 와 무관하게 모든 reset(reset_error 요청·자동 reset)에 씁니다. 제어 주기로 올림한 프레임 수(최소 1)가 되므로 0 은 한 제어 주기입니다. 드라이브 매뉴얼이 유지 시간을 요구하면 그 값을 적습니다. 축이 fault 를 벗어나면 남은 시간과 무관하게 그 프레임에서 bit 7 을 내립니다. PLEM 이 보장하는 것은 보내는 controlword 의 모양뿐입니다 — 드라이브가 reset 됐는지는 status 로 확인합니다.
cia402_profile
빼면 코어 내장 전이표를 모든 축이 씁니다. 그 표는 CiA 402 표준 전이의 부분집합(12행)이고 표준 밖 행은 없습니다. 표준과 다르게 전이하는 드라이브만 최상위에 행 목록을 적습니다(파일에 하나, 모든 축에 적용). 예를 들어 전원 투입 뒤 not_ready_to_switch_on 에서 Shutdown 명령을 받아 ready_to_switch_on 으로 가는 드라이브는 내장 표 앞에 그 행을 더한 13행 표를 적습니다.
cia402_profile:
- { from: switch_on_disabled, to: ready_to_switch_on, control_word: 0x0006 }
- { from: ready_to_switch_on, to: switched_on, control_word: 0x0007 }
# …
상태 이름: not_ready_to_switch_on · switch_on_disabled · ready_to_switch_on · switched_on · operation_enabled · quick_stop_active · fault_reaction_active · fault. 16행까지이고, 빈 목록과 null 은 거부됩니다(내장 표를 쓰려면 키를 뺍니다). 로더는 표의 모양(중복·필수 전이·명령과 목적지의 일치)을 검사하지만 드라이브가 실제로 그렇게 전이하는지는 보장하지 않습니다. 내장 표도 전이 전부를 실기로 확인한 것은 아닙니다.
§4.1 slaves — 슬레이브와 PDO 매핑
슬레이브 하나 = 물리 드라이브 하나입니다.
| 키 | 값 |
|---|---|
ring_position | 링 위치(ethercat slaves 의 번호). 순서대로일 필요는 없고, 같은 값 두 번은 거부. 똑같은 드라이브 여러 대는 목록으로 한 항목에 적습니다(아래) |
vendor_id·product_code | ethercat slaves -v 의 값. 0 은 거부. 링 위치의 드라이브와 다르면 선언값과 실제값을 함께 보여 주며 기동을 멈춥니다(「the configuration declares vendor 0x… product 0x…, but the slave at that ring position is …」) — ethercat slaves -v 에서 다시 옮기거나 ring_position 을 고칩니다 |
pdo_mapping | standard, scanned 또는 매핑 선언(아래) |
dc | bus 참고 |
startup_sdo | 아래. 없으면 [] |
stored_sdo | (선택) 아래. 없으면 키를 뺍니다([] 는 거부) |
axes | 이 슬레이브의 축. 빈 목록은 거부 |
pdo_mapping: scanned — 버스가 기동 때 드라이브의 현재 매핑을 읽어 필수 항목이 다 있는지 검사하고 그대로 씁니다. 드라이브에 쓰지 않습니다. 빠진 항목이 있으면 활성화 전에 슬레이브·리비전·항목 이름을 붙여 거부합니다. 따옴표를 친 "scanned"·null·빈 목록은 거부됩니다. 기동 로그의 INFO 줄에 매핑 요약과 sha256:… 값이 남고, PLEM_LOG_LEVEL=debug 로 기동하면 매핑 전문이 남습니다 — 그 전문을 pdo_mapping: 아래에 들여쓰기만 맞춰 붙이면 같은 매핑의 선언이 됩니다.
pdo_mapping: standard — PLEM 이 읽고 쓰는 CiA 402 객체만으로 매핑을 만들어 PREOP 에서 드라이브에 씁니다. 축마다 채널 순서로 RxPDO 0x1600 + 채널 − 1(SM 2, watchdog 켬)에 Controlword(0x6040)·Modes of operation(0x6060)·모드의 목표(cst 0x6071 · csp 0x607A · csv 0x60FF)를, TxPDO 0x1A00 + 채널 − 1(SM 3)에 Statusword(0x6041)·Modes of operation display(0x6061)·위치·속도·토크 실제값(0x6064·0x606C·0x6077)·Error code(0x603F)를 그 축 채널 주소로 담습니다. 켜질 때 매핑에 필요한 항목이 없고 매핑 변경을 받는 드라이브에 씁니다. 그 밖의 객체(터치 프로브·디지털 입력)가 필요하거나 한 슬레이브에 축이 4개를 넘으면 매핑을 선언합니다. 채널별 PDO 번호(0x1600 + 채널 − 1)는 CiA 402 규칙이 아니라 PLEM 이 고른 것입니다. 드라이브가 이 PDO 번호나 항목을 받지 않으면 PREOP→SAFEOP 에서 거부되므로, 매뉴얼이 허용하는 매핑을 선언하거나 scanned 를 씁니다. 실기에서는 아직 돌려 보지 않았습니다.
같은 드라이브 여러 대 — 드라이브·모터·감속기·설정이 같으면 ring_position: [0, 1] 처럼 링 위치를 목록으로 적어 한 항목으로 씁니다. 축의 name·flip·zero_offset_count 만 드라이브마다 다르므로 링 위치 수만큼 목록으로 적습니다(name: [axis0, axis1]). 나머지 키는 모두에 똑같이 적용되고, 하나라도 다른 드라이브는 따로 적습니다. 로더가 목록을 펼치므로 digest·승인 기록은 한 대씩 적은 파일과 같습니다. 메시지의 slaves[k]·axes[i] 는 펼친 뒤의 순서입니다.
매핑 선언 — 코어가 PREOP 에서 이 매핑을 드라이브에 씁니다. 특정 PDO 가 필요한 드라이브에 씁니다.
pdo_mapping:
sync_managers:
- { sm: 0, direction: output, watchdog: false, pdos: [] } # 메일박스 SM 은 pdos: []
- { sm: 1, direction: input, watchdog: false, pdos: [] }
- sm: 2
direction: output # output = 마스터→드라이브(Rx), input = 드라이브→마스터(Tx)
watchdog: true
pdos:
- index: 0x1600
entries:
- { index: 0x6040, subindex: 0, bits: 16 }
- { index: 0x0000, subindex: 0, bits: 8 } # index 0 = 빈칸(폭만큼 자리를 차지)
- { index: 0x6071, subindex: 0, bits: 16 }
- sm: 3
direction: input
watchdog: false
pdos: [ ... ]
- SM 은 4개까지, SM 당 PDO 4개까지, PDO 당 항목 16개까지입니다. 빈
sync_managers와 빈entries는 거부됩니다. - 항목의
index는 절대 주소입니다 — 두 번째 채널의 statusword 는0x6841로 적습니다. - 출력 SM 에
watchdog: true가 하나도 없으면 거부됩니다. watchdog 시간은 드라이브 기본값(ESI)이고 PLEM 이 정하지 않습니다. PLEM 이 죽었을 때 이 watchdog 이 드라이브를 멈춘다는 것은 전제이지 측정한 것이 아닙니다.scanned슬레이브는 SM 을 쓰지 않으므로 드라이브 자체 설정 그대로이고, 이 검사도 하지 않습니다. - 필수 PDO 역할(statusword 등 공통 역할과 그 축 모드의 목표 —
cst0x6071 ·csp0x607A ·csv0x60FF)이 다 있는지, 주소가 겹치지 않는지는 버스가 기동 때 판정하고,plem drive check도 같은 판정을 드라이브 없이 돌려 거부합니다.scanned슬레이브의 매핑만 기동 때 드라이브에서 읽어 판정합니다.
axes — 축
축 하나 = CiA 402 축 하나 = 호스트가 보는 관절 하나입니다.
| 키 | 값 |
|---|---|
name | [a-z_][a-z0-9_]*, 31바이트 이하, 파일 안에서 중복 금지. joint_states 의 이름이 됩니다 |
channel | 드라이브 안의 몇 번째 CiA 402 축인가(1–8). 채널 n 의 객체 주소는 채널 1 보다 (n − 1) × 0x800 큽니다 — 프로필 영역 0x6000–0x9FFF 를 0x800 블록 8개로 나누는 CiA 402 논리 장치 방식입니다 |
mode | cst(토크) · csp(위치) · csv(속도) — 아래 |
mode_display | pre_enable 또는 post_enable — 아래 |
factors | 단위 환산 — 아래 표 |
flip | true 면 PLEM 과 드라이브 사이에서 부호를 뒤집습니다 — PLEM 쪽 부호 반전이며, 드라이브의 0x607E(Polarity)는 쓰지 않습니다 |
zero_offset_count | 관절 0 rad 에 해당하는 드라이브 위치 카운트(부호 있는 32비트) — 드라이브가 보고하는 카운트 그대로이고 flip 을 먼저 적용하지 않습니다. 드라이브의 Home offset(0x607C)·Position offset(0x60B0)과는 별개이고, PLEM 은 이 객체들을 쓰지 않습니다 |
error_code_pdo | null(드라이브가 ErrorCode 를 매핑하지 않음) 또는 { index, subindex, bits }. 빼면 Error code(0x603F) — standard 매핑, 또는 그 축 채널의 0x603F 를 담은 선언 매핑일 때만. scanned 매핑(기동 때에야 읽음)이나 0x603F 가 없는 선언 매핑은 적어야 합니다 |
limits | 안전 한계 — 아래 |
ramp | 은퇴한 키 — 적으면 거부됩니다(아래) |
error_code_pdo.index 는 채널 1 의 주소(0x603F)로 적습니다. 채널 2 축이라도 0x683F 로 적지 않습니다 — 코어가 채널만큼 더합니다. index: 0 은 거부됩니다(선언하지 않으려면 null). 이와 달리 pdo_mapping 과 startup_sdo 의 주소는 절대 주소입니다.
mode_display — 드라이브가 0x6061(표시 모드)을 언제 0x6060(요청 모드)에 맞추는지입니다. 기본값이 없습니다.
pre_enable— enable 전에 맞춥니다.post_enable— 처음 enable 할 때까지 0x6061 이 0 입니다.
CiA 402 가 정하지 않는 드라이브 특성이라 자기 드라이브에서 잽니다. 첫 해제 전 휴지 상태의 0x6061 과, 처음 Operation Enabled 가 됐을 때의 0x6061 을 봅니다.
factors 의 키도 전부 필수입니다(위치·속도의 unit 은 값이 하나뿐이라 빼도 됩니다). 로더가 검사하는 것은 단위 이름과 수가 양수인지뿐이라 값이 틀려도 파일은 통과합니다. 기어비와 엔코더 분해능은 축마다 한 번 적고, 토크·위치·속도 환산이 모두 그 값을 씁니다. factors 는 PLEM 쪽 환산이며 드라이브의 Factor group 객체(0x608F–0x60A9)는 쓰지 않습니다. PLEM 안에서 토크는 늘 Nm 이고, 드라이브의 숫자로는 통신 경계에서 한 번만 바꿉니다 — 그 숫자의 뜻을 드라이브마다 torque.unit 으로 적습니다.
| 키 | 뜻 |
|---|---|
torque.unit | 드라이브가 토크(0x6071·0x6077)를 세는 단위이고, 단위마다 적는 키가 다릅니다(다른 단위의 키를 적으면 거부됩니다). scaled_current — 드라이브 고유의 전류 카운트(CiA 402 밖). 카운트 = τ × counts_per_amp ÷ (torque_constant × gear_ratio). rated_per_mille — CiA 402 표준 단위로, 한 카운트가 모터 정격 토크(0x6076)의 1/1000 입니다. 카운트 = τ × 1000 ÷ (motor_rated_torque_nm × gear_ratio) |
torque.counts_per_amp | (scaled_current) 암페어당 전류 카운트(드라이브 매뉴얼) |
torque.torque_constant | (scaled_current) 모터 토크 상수 Nm/A(모터 명판) |
torque.motor_rated_torque_nm | (rated_per_mille) 모터 정격 토크 Nm(모터축). 드라이브의 0x6076 은 mNm 으로 읽히므로 1000 으로 나눠 적습니다(0x6076 이 1270 이면 1.27). 값이 틀리면 모든 토크 명령과 측정 토크가 그 비율만큼 어긋납니다 — 파일 값이 크면 명령이 약해지고, 작으면 명령이 세져 드라이브의 토크 명령 범위 끝까지 갈 수 있습니다. 벤치가 0x6076 을 한 번 읽어 이 값과 1 %(최소 1 mNm) 넘게 다르면 경고하고 그 경고를 승인 기록의 벤치 증거(conditions.notes)에도 남깁니다 — 벤치를 멈추지는 않습니다. 드라이브에 그 객체가 없거나, 값이 0·0xFFFFFFFF 이거나, 읽기에 실패하면 대조하지 않습니다 |
gear_ratio | 출력축 한 바퀴당 모터 회전 수(감속비). 축마다 한 번. 감속기가 없으면 1.0 — 그러면 출력축이 곧 모터축입니다. 이 값으로 축 값(limits·명령·joint_states)은 출력축의 rad·rad/s·Nm 이 됩니다. 드라이브 값(startup_sdo·stored_sdo·zero_offset_count·dc)은 드라이브 매뉴얼의 원시 값 그대로이고 감속비를 타지 않습니다(위치 단위는 모터 카운트). 감속기를 바꾸면 이 값과 축 값을 함께 고칩니다 |
position.unit·velocity.unit | rotary_motor_encoder 만(빼도 같습니다 — position 블록째로). 위치 카운트 = rad × encoder_resolution × gear_ratio ÷ 2π |
encoder_resolution | 모터 한 바퀴당 엔코더 카운트(정수). 축마다 한 번 |
velocity.velocity_factor | 속도 카운트 하나에 해당하는 위치 카운트 수(1.0 = 위치와 같은 단위). 드라이브 매뉴얼의 0x606C 단위에서 얻습니다. 틀리면 속도 한계와 joint_states 속도가 조용히 어긋납니다 |
mode — 운전 모드와 명령
mode 는 그 축의 0x6060 값입니다 — cst 10 · csp 8 · csv 9. 축마다 정하고 한 버스에 섞어도 되며, 기동부터 매 주기 보내고 실행 중에는 바꾸지 않습니다. 명령은 축 모드의 단위입니다 — cst Nm · csp rad · csv rad/s(csp 는 궤적 컨트롤러가, csv·cst 는 스트림 컨트롤러가 씁니다 — 내 서보 드라이브 붙이기). 위치·속도는 zero_offset_count 기준 관절 좌표이고 flip 은 PLEM 이 드라이브와의 경계에서 한 번 적용합니다. 버스는 모드를 info 의 modes_of_operation 으로, plem drive check 는 JSON 의 axes[i].mode 로 알립니다.
명령은 브레이크가 풀려 모든 축이 Operation Enabled(드라이브가 명령을 실행하는 운전 허용 상태)이고 보호정지가 없으며, 모든 축의 명령이 검사를 통과한 주기에만 드라이브로 나갑니다. 그 밖의 주기에는 전 축이 중립입니다 — cst 0 Nm, csp 그 주기의 실측 위치, csv 0 rad/s. 검사는 값을 자르지 않습니다 — 넘으면 그 주기에 보호정지를 걸고(그 주기에 csp 축은 직전 주기의 목표를 그대로 두고, 나머지 축은 중립), 다음 주기부터 전 축을 중립으로 쓰며 브레이크 강제 체결을 시작합니다(실제로 물리는 시각은 드라이브마다 다릅니다). 검사는 드라이브 카운트로 바꿨다 되돌린 값으로 하므로 한계 바로 근처의 값은 반올림으로 갈릴 수 있고, 카운트로 표현할 수 없는 값(int32 밖, 끝 멈춤이 없는 축은 ±2⁴⁸ 카운트 밖)도 보호정지입니다.
cst 축이 없는 버스의 해제. 해제는 명령 스트림을 먼저 요구하지 않습니다. 해제 전에 쓴 명령은 적용하지 않고, 해제 뒤 첫 명령이 올 때까지 csp 축은 해제 때의 위치를 지키고(처지는 실측을 따라가지 않습니다) csv 축은 0 rad/s 를 명령합니다 — 이 목표도 아래 검사를 받습니다. 첫 csp 명령은 그 지킨 위치에서 한 주기 이동량으로 판정합니다. 계획 속도를 함께 쓴 csp 명령(plem drive run 의 궤적 컨트롤러)은 그 속도 × 샘플 나이만큼 앞으로 밀어 적용합니다 — 컨트롤러 매니저가 버스 루프와 다른 시계로 돌아도 늦게 읽은 샘플이 이 검사에 걸리지 않게 하기 위해서입니다. 명령 끊김 감시(50 ms)는 해제 뒤 첫 명령에서 시작하고, 모션이 꺼져 있거나 요청 정지가 도는 동안은 쉽니다. cst 축이 하나라도 있는 버스는 종전대로 해제 전에 명령이 흘러야 합니다(없으면 해제 거부). 실기로는 A6B 위치 축 두 개와 그 csv 사본으로 한 세션 돌렸습니다(실기 근거).
| 모드 | 검사 |
|---|---|
cst | 검사 대신 limits.torque_nm 으로 자릅니다(종전대로) |
csp | 드라이브 카운트로 바꿨다 되돌린 목표가 limits.position 안이고, 직전 주기에 적용한 목표(해제·복구 뒤 첫 적용이면 그 주기 실측)에서 limits.velocity_rad_s × 주기 이내 |
csv | 드라이브 카운트로 바꿨다 되돌린 속도의 크기가 limits.velocity_rad_s 이하 |
실측 위치가 관절 좌표로 표현되지 않는 축은 위치 한계를 넘은 것처럼 다룹니다(limits). 한계 때문에 걸린 보호정지의 원인은 rt_events 의 LIMIT_STOP 사건으로 나옵니다(내 서보 드라이브 붙이기). csp 는 A6B 두 대에서, csv 는 짧은 저속 런 한 번만 실기로 돌렸습니다. 움직이는 csv 축의 보호정지와 정지 때 브레이크 시각은 실기로 확인하지 않았습니다.
ramp — 은퇴
예전에 csp 축에 적던 ramp 블록(명령을 도착 위치로 받아 버스 루프 안에서 사다리꼴로 보간)은 은퇴했습니다. 축에 ramp 키가 있으면 로더가 거부하고 블록을 지우라고 알려 줍니다 — 이동은 클라이언트(plem drive run 의 궤적 컨트롤러, Python plem.drive 의 Bus.move_to)가 계획하고, 정지는 limits.acceleration_rad_s2 로 감속합니다. ramp 가 없는 파일의 digest 는 은퇴 전과 같습니다. plem drive check 의 axes[i].velocity_cap_rad_s(속도 한계에서 제어 주기당 위치 카운트 하나 — 끝 멈춤 없는 축은 둘 — 를 뺀 값)는 그대로 있고, plem drive run 의 궤적 계획은 이 속도를 넘지 않습니다.
limits — 안전 한계
기본값이 없고, 값이 맞는지는 선언하시는 분의 책임입니다. 로더는 모양만 봅니다. 이 한계는 PLEM 소프트웨어 쪽의 검사와 자르기입니다 — PLEM 은 드라이브 자체의 한계 객체 — 위치 0x607D(Software position limit), 속도 0x607F·0x6080, 토크 0x6072(Max torque) — 를 쓰지 않습니다.
| 키 | 단위 | 거부 조건 | 넘으면 |
|---|---|---|---|
position: { min_rad, max_rad } 또는 null | 출력축 rad, zero_offset_count 기준 | 유한하지 않음, min ≥ max. null 인데 zero_offset_count 가 0 이 아님 | 보호정지 + 브레이크 강제 체결. 실기(A6B)에서는 범위 밖 위치 명령(LIMIT_STOP 사유 4 — 명령은 적용되지 않음)과 기동 때 이미 밖에 있던 축(사유 1)을 봤고, 움직이던 축의 실측 위치가 넘는 경우는 미확인 |
velocity_rad_s | 출력축 rad/s | 유한하지 않음, 0 이하 | 보호정지 + 브레이크 강제 체결. 실기(A6B)에서 실측 속도 초과(사유 2)와 csv 속도 명령 초과(사유 6 — 명령은 적용되지 않음)를 봤습니다 |
acceleration_rad_s2 | 출력축 rad/s² — csp·csv 축만(필수) | csp·csv 축에서 빠짐·0 이하, cst 축에 적음 | 한계가 아니라 요청 정지의 감속입니다. 축이 실제로 낼 수 있고 드라이브의 0x6085(Quick stop deceleration)를 넘지 않는 값을 적습니다. config digest 에 들어가므로, 이 키가 생기기 전의 csp·csv 승인 파일은 키를 더하고 다시 벤치합니다 |
torque_nm: { min, max } | 출력축 Nm — cst 축만 | cst 축에서 빠짐·유한하지 않음·min < 0 < max 가 아님, csp·csv 축에 적음 | cst 축의 명령을 그 범위로 자릅니다. csp·csv 축은 토크 명령을 보내지 않으므로 적지 않습니다 — 그 축의 토크는 드라이브 안의 루프가 내고 드라이브의 0x6072 가 묶습니다 |
위치 한계 밖에서 멈춘 축은 해제되지 않습니다.
위치 한계는 절대값 엔코더를 전제합니다. PLEM 에는 홈잉이 없어, zero_offset_count 와 위치 한계는 드라이브가 전원을 넣을 때마다 같은 위치를 보고할 때만 축의 자리를 가리킵니다. 증분 엔코더는 켤 때마다 카운트가 새로 시작해 한계가 아무것도 지키지 못하는데, 엔코더 종류를 적을 키가 없어 로더도 벤치도 거부하지 못합니다 — 그런 드라이브는 쓰지 마세요(전원 결합 브레이크와 같은 종류의 전제입니다). 끝 멈춤이 없는 축(아래)은 지킬 위치 한계가 없습니다.
끝 멈춤이 없는 축(출력축이 한 방향으로 계속 도는 축)은 위치 한계를 null 로 적고, zero_offset_count 를 0 으로 둡니다. 토크·위치·속도 모드 어느 것이든 됩니다.
zero_offset_count: 0
limits: { position: null, velocity_rad_s: 20.0 } # cst 축이면 torque_nm 도 적습니다
- 속도 한계는 그대로 필요합니다 — 끌 수 없고, 넘으면 보호정지입니다.
- 위치 값은 드라이브의 32비트 카운트가 끝을 넘어도 끊기지 않고 이어집니다(
joint_states·위치 명령 모두). PLEM 이 드라이브가 보낸 위치를 프레임마다 따라가며 넘어간 바퀴를 셉니다. 속도·토크 값은 영향이 없습니다. - PLEM 을 다시 시작하면 드라이브 값부터 셉니다. 저장해 두는 원점이 없어, 재시작 직후 위치는 드라이브가 보고하는 값 그대로입니다(예: 23비트 엔코더·
gear_ratio1 이면 약 ±1608 rad 안). 위치 축은 매번 그때의 위치를 기준으로 명령하십시오. - 한 방향으로 아주 오래 돌면 멈춥니다. PLEM 시작 뒤 한 방향 순이동이 2⁴⁸ 카운트(23비트 엔코더면 모터 약 3,350만 회전 — 모터 400 rad/s 로 약 6일, 20 rad/s 로 약 122일)를 넘으면 보호정지하고(
LIMIT_STOP사유 3), PLEM 을 다시 시작할 때까지 reset 이 거부됩니다. 다시 시작하면 이어서 돌 수 있습니다. 위치 명령도 그 범위 밖이면 보호정지입니다(사유 7). - 통신이 끊긴 사이의 이동은 짧아야 합니다. 프레임을 받지 못하는 동안은 위치를 따라가지 못합니다. 그 사이 모터가 2³¹ 카운트(23비트 엔코더면 256 회전, 6000 rpm 에서 2.56초) 이상 움직이면 보고되는 위치가 2³² 카운트 단위로 어긋납니다 — PLEM 은 이를 감지하지 않습니다(명령은 드라이브 좌표와 맞게 유지됩니다).
- 좌표를 바꾸는 정비는 정지 상태에서 하고, 끝나면 PLEM 을 다시 시작하십시오. 원점 복귀, 다회전 클리어, 드라이브 설정 도구의 조작, 전자 기어·극성 변경처럼 드라이브가 위치를 다시 만드는 일은 PLEM 이 구분하지 못하고 움직임으로 셉니다.
- 드라이브 쪽 조건(PLEM 이 검사하지 않습니다): 드라이브의 위치 값이 32비트 전 범위로 돌아야 하고(드라이브 측 위치 범위 0x607B 를 좁히거나 드라이브 고유의 연속 회전 절대 모드를 쓰지 않음), 위치 목표 0x607A 가 넘어가는 것을 연속 이동으로 받아야 하며, 드라이브의 소프트웨어 위치 한계(0x607D)가 꺼져 있어야 합니다. 또 다음 기동도 견뎌야 합니다: 다회전 절대 엔코더 드라이브는 전원 투입 등 초기화 때 엔코더에서 위치를 다시 만드는데, 한 방향으로 32비트 범위(23비트 엔코더·전자 기어 1:1 이면 모터 약 ±256 회전)보다 멀리 간 뒤에는 카운터 넘침 알람으로 기동하지 않는 드라이브가 있습니다. 운전 모드(
csp·csv·cst)와 상관없습니다 — 엔코더는 늘 바퀴를 셉니다. 그런 드라이브는 엔코더를 증분 모드로 쓰거나, 32비트 전 범위 wrap 을 유지하면서 넘침만 무시하는 설정을 켜고(A6B: Pr6.98 bit 3 = 1, 기능 확장판 3 이후 — 전자 기어에 따라 전원을 다시 넣은 뒤 위치가 끄기 전과 다를 수 있음, 매뉴얼 p.255-256), 둘 다 없으면 위치 한계를 둬 그 범위 안에서 오가게 하십시오. PLEM 은 정지 때, 그 런에서 센 위치(기동 때 드라이브 값에서 시작)가 범위 밖에서 끝난 축마다 로그에 한 번 경고합니다 — 앞선 런의 넘김, 드라이브 자체 오프셋, 1:1 이 아닌 드라이브 측 전자 기어는 보지 못하므로, 경고가 없다고 다음 기동이 보장되지는 않습니다. Panasonic MINAS A6B 는 매뉴얼(SX-DSV03242 R10.1 p.261, p.100-101)이 이 동작을 적고 있고, 그 밖의 드라이브는 그 매뉴얼로 확인하십시오. PLEM 은 0x607D 를 쓰지 않으니, 기대값을stored_sdo에 적어 두면 기동할 때 읽어 다르면 경고합니다. A6B 의 예(벤더마다 다릅니다):
stored_sdo: # A6B: 소프트웨어 위치 한계 끔 (607Dh-01h >= 607Dh-02h)
- { index: 0x607D, subindex: 1, size: 4, value: 0 }
- { index: 0x607D, subindex: 2, size: 4, value: 0 }
- 실기: A6B 두 대에서 두 축이 ±480 rad(모터축)를 최대 375 rad/s 로 오가며 32비트 카운트 경계를 여섯 번씩 넘었고, 위치·명령이 끊기지 않았고
LIMIT_STOP은 없었습니다. 출력축으로 한 방향 840 rad(감속비 21, 모터 약 2,900 회전)를 돈 런도 끊김 없이 끝났지만, Pr6.98 bit 3 = 0(공장값)인 그 드라이브들은 다음 기동에서 Err29.1(0x603F = 0xFF1D)로 기동하지 않았습니다. 2⁴⁸ 카운트 보호정지와 통신이 끊긴 사이의 이동은 실기로 확인하지 않았습니다. - 영점을 두는 축(유한한 한계)은 위치가 32비트 관절 카운트로 표현되지 않는 동안(아주 큰
zero_offset_count에서 카운트가 끝에 닿은 경우) 보호정지가 걸리고 reset 이 거부됩니다 — 그 동안의 위치는 움직여도 한 값이라 한계를 판정할 수 없기 때문입니다.csp·csv축의 명령도 이 두 한계로 검사합니다(mode).
startup_sdo
기동 때 드라이브에 차례로 쓰는 SDO 목록입니다. 슬레이브마다 16개까지, 적은 순서와 반복을 그대로 지킵니다(합치거나 정렬하지 않습니다).
startup_sdo:
- { index: 0x6098, subindex: 0, size: 1, value: 35 }
size는 바이트로 1·2·4.value는 그 폭의 부호 없는 값(0 ≤ value < 2^(8 × size)). 음수는 받지 않습니다.index는 절대 주소입니다.- PLEM 이 쓰거나 파일의 다른 키가 정하는 객체는 거부됩니다 — PDO 배정·매핑(0x1C10–0x1C2F, 0x1600–0x17FF, 0x1A00–0x1BFF), 동기 객체(0x1C32·0x1C33 — 동기는
sync_mode·dc로만 정하고, PLEM 이 쓰는 것은dc.write_cycle_time의 0x1C32:02 뿐입니다), 그리고 축마다(채널 주소로 옮겨서) PLEM 이 쓰는 controlword 0x6040·모드 0x6060·목표값 0x6071·0x607A·0x60FF,limits·zero_offset_count와 겨루는 한계 0x607D·0x6072·0x6080·homing offset 0x607C. 한계와 homing offset 은 PLEM 이 드라이브에 쓰지 않습니다 — 파일 안에 출처가 둘 생기지 않게 거부할 뿐입니다. - 그 밖의 객체는 받아들이며, 무엇을 하는지는 선언하시는 분의 책임입니다. 미승인 파일도 기동 때 쓰고, 쓴 것을 로그에 전부 남깁니다. 드라이브가 쓰기를 거부했을 때 PLEM 이 그 원인을 startup SDO 로 짚어 주지는 않습니다.
- 쓴 값은 PLEM 이 끝나도 드라이브에 남습니다(드라이브 RAM — 전원을 다시 넣을 때까지). 다른 파일로 바꿔 띄우면 앞 파일이 쓴 객체를 그대로 물려받습니다 — 실기(A6B)에서 앞선 시험 파일이 낮춰 둔 토크 한계·위치 편차 한계가 남아 다음 파일의 평범한 이동이 위치 편차 알람(Err24.0)으로 멈췄습니다. 쓰는 객체가 적은 파일로 바꿀 때는 드라이브 전원을 다시 넣습니다.
stored_sdo
드라이브에 저장돼 있어야 할 값의 목록입니다(선택). 버스가 기동할 때 값마다 한 번 읽어, 다르면 경고 한 줄을 남깁니다. PLEM 은 이 값을 쓰지도 저장하지도 않고, 다르거나 읽지 못해도 기동을 막지 않습니다. 원소 모양은 startup_sdo 와 같습니다.
stored_sdo:
- { index: 0x3401, subindex: 0, size: 4, value: 0 }
- { index: 0x3015, subindex: 0, size: 2, value: 2 }
size·value규칙은startup_sdo와 같고, 음수는 그 폭의 2의 보수(hex)로 적습니다. 슬레이브마다 16개까지. 필요 없으면 키를 뺍니다([]는 거부).- 거부되는 것은 형식 오류뿐입니다 — 한 슬레이브에 같은 주소 두 번, 같은 슬레이브의
startup_sdo가 쓰는 주소(쓴 값은 다음 전원 재투입까지 드라이브 RAM 에 남아 읽어도 뜻이 없습니다 —startup_sdo로 옮긴 객체는 여기서 뺍니다). - 드라이브의 출력 PDO 에 매핑된 객체(마스터가 매 주기 보냅니다)와 PDO 매핑·배정 객체(0x1600–0x17FF, 0x1A00–0x1BFF, 0x1C10–0x1C2F)는 읽지 않고 그렇다고 경고합니다. 0x1C32·0x1C33 에는 드라이브가 운전 중 채우는 칸이 있으니 저장 설정 칸만 적습니다.
- 경고에는 두 갈래가 적힙니다. 파일이 맞으면(드라이브 매뉴얼이 그 객체를 쓰고 저장할 수 있다고 할 때) PLEM 을 멈추고 드라이브 전원을 한 번 껐다 켠 뒤 그 값을 내려 쓰고, 드라이브가 CiA 301 저장(0x1010:01)을 지원하면 저장합니다(드라이브 매뉴얼 참조). 전원을 켤 때 적용되는 객체면 다시 껐다 켭니다. 저장은 보통 드라이브가 그 순간 가진 저장 가능한 값 전부를 저장하므로, 먼저 껐다 켜야 지난 기동의
startup_sdo쓰기가 함께 저장되지 않습니다. 드라이브가 맞으면(예: 이 기계에서 튜닝) 파일의stored_sdo를 고칩니다. - 일치해도 값이 저장됐거나 적용됐다는 뜻은 아닙니다 — 지금 값만 읽습니다(내려 쓰고 저장하지 않은 값은 다음 전원 재투입까지 일치로 나옵니다).
- 읽기는 기동을 기다리게 할 수 있습니다. PLEM 은 자체 타임아웃을 두지 않고, 전송이 시작된 뒤에는 EtherCAT 마스터의 CoE 처리만이 대기를 묶으므로(슬레이브 mailbox 가 비어 있는 동안의 단계별 응답 타임아웃) 다른 mailbox 응답을 계속 보내는 드라이브는 기동을 붙잡을 수 있습니다. SDO abort 없이 읽기가 실패하면(무응답·CoE 가 없는 슬레이브·mailbox 오류) 그 슬레이브의 나머지를 읽지 않습니다.
- 직전 정지 직후(수 초 안)에 다시 기동하면 읽기가 실패할 수 있습니다. EtherCAT 마스터(IgH 1.6.13)가 드라이브가 PREOP 에 든 지 3초 이후 같은 mailbox 로 SDO 사전을 한 번 읽는데(걸리는 시간은 드라이브에 따라 다릅니다), 그와 겹치면 경고에
ret=-5(mailbox 오류)가 찍힙니다. 이 실패로 기동이 거부되지는 않고, 비교가 필요하면 버스가 잠시 쉰 뒤 다시 기동합니다(유지보수자의 A6B 벤치: 3초 뒤 기동은 걸렸고 25초 뒤는 걸리지 않았습니다). - 승인과 무관합니다. 승인된 파일의
stored_sdo를 고쳐도 승인은 유지되고, 승인은 이 목록을 보증하지 않습니다 — 벤치 때 드라이브가 이 값을 가졌다는 것도 보여 주지 않습니다. plem drive check는 버스를 읽지 못하므로 형식만 검사합니다.
§4.10 요청 정지
cst 축이 없는 버스에서 해제 중일 때 protective_stop 과 런의 끝(plem drive run 터미널의 Ctrl-C)은 축을 먼저 감속하는 정지입니다. cst 축이 있는 버스나 해제되지 않은 버스에서는 곧바로 disable 하고(종전대로), 한계 위반·명령 끊김·통신 상실은 어느 버스에서나 곧바로 섭니다(드라이브의 0x605C·0x6084). 로봇 팔 계층은 이 정지를 쓰지 않습니다.
- 감속. 각
csp·csv명령이 지금 속도(마지막으로 적용한 명령의 속도)에서 매 주기limits.acceleration_rad_s2× 주기씩 줄어 0 에서 멈춥니다 — 0 을 지나 되돌아가지 않습니다. 그동안 호스트 명령은 적용하지 않으며, 정지 목표도 mode 의 검사를 받습니다. - 끝. 명령이 모두 0 이고 모든 축의 실측 속도가
limits.velocity_rad_s의 1 % 안이면 모션을 끄고 브레이크를 물립니다. 보호정지는 걸리지 않아 reset 없이 다시 열 수 있습니다. - 확인되지 않으면 Quick stop. 계획한 감속 시간 + 0.5 s 안에 끝나지 않으면 Operation enabled 인 모든 드라이브에 Quick stop 을 명령하고
rt_events에HALT_TIMEOUT(0x4F, 값 = 요청 뒤 초)을 남깁니다. 드라이브는 자기 0x6085 로 감속해 0x605A 가 정한 상태(2 = Switch on disabled)로 가고, 그때 보호정지가 걸려 다음 해제 전에reset_error가 필요합니다. 모든 축이 브레이크 체결 상태를 읽거나 2 s 가 더 지나면 끝나고, 그때도 Quick stop active 인 축에는 Disable voltage 를 보냅니다 — 드라이브의 0x6085 가 2 s 안에 축을 세우지 못하면 움직이는 축의 전원이 끊깁니다. 0x6085·0x605A 는 PLEM 이 쓰지 않으니startup_sdo로 줍니다. Quick stop 명령을 보낼 수 있도록csp·csv축의 전이표(cia402_profile을 적었다면)에는 operation_enabled → quick_stop_active 행(0x0002)이 있어야 하고, 없으면 파일이 거부됩니다(내장 표에는 있습니다). - 도는 동안. 해제(
release_brake)는 거부되고, 명령 끊김 감시는 쉽니다. 서비스는 곧바로 응답하므로 끝은status의 브레이크로 봅니다.
1 % 대역, 0.5 s, 2 s 는 설계값입니다. 이 정지는 A6B 위치 축 두 개로 한 세션 실기로 돌렸지만, Quick stop 대비 단계까지 간 적은 없습니다(실기 근거). 벤치의 stop-decel 항목이 그 평균 감속을 잽니다(§6.1). 드라이브가 운전 중의 Quick stop 명령에 어떻게 반응하는지와 0x605A 값의 뜻은 드라이브마다 다릅니다.
§6 approval — 승인 기록
선택 키입니다. 처음에는 적지 않습니다 — 없으면 미승인입니다. 다음 모양으로 적어도 같습니다.
approval:
status: unapproved
record: null
미승인 파일은 터미널에서 plem drive run 이 벤치를 제안하고 승인되면 이어서 띄우며, 터미널이 없으면 거부합니다. 드라이브 곁에 사람이 있는 실행이면 --unapproved 로 띄웁니다(내 서보 드라이브 붙이기). approved 기록은 벤치가 끝에 이 파일 안에 씁니다 — 파일의 approval 블록을 제자리에서 바꾸거나(없으면 끝에 붙임) 나머지 바이트는 그대로 두고, 같은 디렉터리의 임시 파일 + rename 으로 한 번에 바꿉니다(권한 유지, 심링크면 대상 파일에). 벤치 증거(claims·conditions·items)를 통째로 담으므로 보관할 파일은 이 파일 하나입니다. 블록을 제자리에서 찾을 수 없는 파일(따옴표 친 키 등)은 plem drive check 의 approve_blocker 가 미리 알려 주고 벤치가 시작 전에 거부합니다. 손으로 쓰거나 고치지 않습니다(stored_sdo 는 예외 — 승인 밖입니다, 위) — 로더가 잡는 편집은 아래 세 가지 대조에 걸리는 것뿐이고, 증거의 조건·항목 설명 같은 나머지 편집은 잡지 못합니다. 예전 낱말 unverified·verified 는 거부됩니다.
approved 파일은 로더가 다음을 모두 확인해야 적재됩니다. 하나라도 어긋나면 적재가 실패하고(미승인으로 내려가지 않습니다), plem drive check 가 이유를 전부 JSON 의 reasons 로 보여 줍니다.
- 기록의 digest 가 지금 파일의 설정·전이표와 같습니다 — 값을 하나라도 고치면 승인이 무효가 됩니다(주석·들여쓰기·키 순서와
stored_sdo는 상관없습니다). - 슬레이브마다 드라이브 식별값이 하나씩 있습니다.
- 기록 안의 벤치 증거가 주장하는 값이 위 1–2 와 기록의
implementation_revision과 같고, 지금 소프트웨어의 필수 항목이 전부PASS입니다. 이 대조는 한쪽만 고친 실수(예:check가 찍은 새 digest 를 기록 머리에만 붙여 넣기)를 잡을 뿐, 벤치가 실제로 돌았다는 증명은 아닙니다 — 두 사본을 함께 고치거나 증거의 조건·항목을 고친 것은 잡지 못합니다.
승인은 소프트웨어 업데이트 뒤에도 유지됩니다. implementation_revision 은 벤치를 돌린 소프트웨어 버전의 기록이고, 지금 버전과 비교하지 않습니다. 승인이 풀리는 경우는 다음과 같습니다.
- 파일의 값을 고쳤을 때.
cia402_profile을 뺀 파일은 업데이트로 코어 내장 전이표가 바뀔 때도 풀립니다. - 드라이브를 바꿔 기록한 식별값이나 스캔한 매핑이 달라졌을 때(아래 기동 대조).
- 기록 안의 벤치 증거가 기록 머리와 어긋나게 바뀌었을 때 — 되돌리면 다시 열립니다.
- 업데이트가 필수 항목을 더하거나 기준을 올렸을 때 — 그 업데이트는 CHANGELOG 에 「드라이브 재벤치 필요」로 알립니다(§6.1).
다시 벤치할 때는 같은 파일로 합니다 — 승인이 풀린 파일(기록이 더는 성립하지 않는 파일)도 벤치가 열어 기록을 바꿉니다. 실효 승인이 있는 파일은 벤치가 거부합니다.
기동 때는 버스가 드라이브의 실물 값 — SII 시리얼, SII revision number, 0x1009(하드웨어 버전), 0x100A(소프트웨어 버전), scanned 슬레이브는 스캔한 매핑의 digest — 을 기록과 대조하고, 다르거나 못 읽으면 활성화 전에 거부합니다. 매핑 digest 가 다를 때 메시지는 두 값을 보여 주고 원인을 하나로 좁히지 않습니다(드라이브·펌웨어 교체, 기록 오기 등). 명판을 확인하고 다시 벤치하세요.
승인의 범위. 기동 때 대조하는 것은 기록에 적은 칸뿐이고, null 칸은 대조하지 않습니다. 시리얼이 0 이거나 없는 드라이브가 하나라도 있으면 승인은 개체가 아니라 모델에 묶여 다른 개체에서도 열립니다(plem drive check 의 identity_scope: model) — 비운 칸만큼 넓어집니다. 버전 칸을 적었으면 같은 하드웨어·소프트웨어 버전의 드라이브에서 열리고, 비우면 그 대조가 빠집니다. 단 시리얼이 0 이고 revision number·두 버전이 null 이며 매핑 digest 도 없으면(선언 매핑) 대조할 값이 하나도 없어 기록이 거부됩니다(§6.1). scanned 슬레이브는 매핑 digest 도 같아야 하므로 매핑이 다른 리비전은 리비전마다 승인합니다. 판정은 기록끼리의 일치이지 측정이 참이라는 증명이 아닙니다.
§6.1 bench 파일과 필수 항목
벤치가 잰 값을 승인 판정에 넘기는 파일입니다. 형식은 §2 의 YAML 부분집합과 같습니다. 벤치(미승인 파일에 plem drive run 이 제안)가 이 파일을 임시 디렉터리에 만들어 C++ 판정 도구에 넘기고 지웁니다(내 서보 드라이브 붙이기). schema 줄 뒤의 내용은 모델 파일의 approval.record.bench 로 통째로 옮겨지므로, 승인 뒤에는 이 파일이 필요 없습니다. 기록을 담은 모델 파일이 파일 크기 한도(1 MiB)를 넘게 되면 기록을 거부합니다.
schema: cia402_bench/v1
claims:
config_digest: "sha256:…" # plem drive check 출력에서
profile_digest: "sha256:…" # 같음
implementation_revision: "…" # 같음
slaves:
- { slave: 0, serial: 0, revision_number: 0x00000002, hardware_version: "…", software_version: "…", pdo_mapping_digest: "sha256:…" }
conditions: { host: "…", master: "…", date: "YYYY-MM-DD", measured_by: "…", notes: "" }
items:
- { id: assembly-match, result: PASS, evidence: "…" }
# …
claims.slaves— 파일의slaves[]순서마다 하나.serial·revision_number(SII 의 revision number —ethercat slaves -v의 Revision number)는 정수 또는null, 두 버전은 31바이트까지의 문자열 또는null. 전부 비울 수는 없습니다(시리얼 0 은 빈 값으로 세고, revision number 는 0 도 읽은 값입니다).pdo_mapping_digest는scanned슬레이브면 벤치 기동한 버스가info(plem_drive_msgs/DriveInfo)로 낸 값을 그대로 옮겨 적고(기동 로그 INFO 줄using the scanned PDO mapping — … sha256:…의 값과 같습니다), 매핑을 선언한 슬레이브면null입니다.items—result는PASS·FAIL·NA. 같은id두 번은 거부됩니다.
필수 항목 — 버스의 축 모드로 정해집니다:
| id | 확인하는 것 | 필수인 버스 |
|---|---|---|
assembly-match | 버스가 조립한 값, joint_states 의 축, 스캔한 매핑 digest 가 파일과 같다 | 전부 |
idle-non-oe | 기동 전 모든 축이 Operation Enabled 가 아니다 | 전부 |
start-rtso | 기동 뒤 모든 축이 브레이크가 체결된 휴지 상태(Switch on disabled 또는 Ready to Switch On), 대기 중인 브레이크 동작 없음, 보호정지 없음, 모든 축이 위치 한계 안. 버스는 첫 해제 전에 상태 전이를 명령하지 않고(controlword 0x0000), 이 상태는 그 아래에서 드라이브가 스스로 머무는 휴지 상태입니다(표준 드라이브는 Switch on disabled, 일부 계열은 Ready to Switch On). 예외가 하나 있습니다 — 기동 전 읽기에서 Fault 인 축(벤치 시작 전에 이미 래치된 fault)에는 기동 뒤 판정 전에 벤치가 reset_error 를 한 번 보내고, 증거에 그렇게 적습니다. 드라이브가 Shutdown 명령을 받아들이는지를 일반적으로 보이지는 않습니다 — Switch on disabled 에서 시작하는 드라이브라면 첫 해제(release-oe)가 Shutdown 도 거치지만, 벤치는 0x0006 을 보냈는지 기록하지 않습니다. id 는 v1 이름을 그대로 씁니다 — 기준이 느슨해졌을 뿐 엄격해지지 않았습니다 | 전부 |
release-oe | 해제하면 모든 축이 Operation Enabled(두 번째 해제는 무동작), 서 있는 동안의 표류 | 전부 |
stale-engage | 스트림을 끊으면 명령이 오래되어 보호정지와 브레이크 강제 체결 | csv·cst 축이 있는 버스 |
stop-decel | 움직이는 축의 범주 1 정지 — 각 csp·csv 축이 여유 쪽으로 최대 0.5 rad 를 속도 상한의 0.3 배 이하로 움직이는 순항 중에 protective_stop: HALT_TIMEOUT 없음, 모든 축 정지·체결, 축마다 평균 감속(요청 때 속도 ÷ 정지까지 시간. rt_raw 의 매 주기로 재고, 기록 중 주기가 빠지면 실패) ≤ 1.1 × limits.acceleration_rad_s2 | csp·csv 축이 있는 버스 |
disable-engage | 서 있는 축에 protective_stop 이면 disable, 체결, 대기 0, 보호정지 0 | 전부 |
stop-quiesce | 해제 중 컨트롤러 매니저에 SIGINT — 종료 코드 0, 하드웨어 플러그인 출력에 브레이크 미확인 줄(brakes were NOT confirmed engaged on stop) 없음, 사슬 프로세스 잔존 없음, 마스터 Idle, 정지 뒤 SDO 로 Operation Enabled 아님 | 전부 |
해제는 래치라 위치 축은 해제 때의 위치, 속도 축은 0 rad/s 를 지키고, 속도·토크 축이 있는 버스는 스트림 축에 0(토크 0 Nm, 속도 0 rad/s)을 흘립니다. 합격 기준은 모드와 무관하게 같습니다. stop-decel 은 지금 벤치의 유일한 모션입니다. 지금 벤치와 stop-decel 은 A6B 위치 축 두 개로 한 세션 실기로 돌려 승인까지 받았고, 스트림 축이 있는 버스의 벤치(stale-engage)는 아직 실기로 돌리지 않았습니다(실기 근거). 벤치가 확인하고 경고하는 것은 벤치 세부에 있습니다.
필수인 버스에서 항목이 하나라도 없거나 PASS 가 아니면 승인되지 않습니다. 필수가 아닌 항목은 NA 이거나 없어도 됩니다(csp 축만의 버스에서 stale-engage 는 NA — 궤적 컨트롤러가 매 주기 쓰고, 멈춘 컨트롤러 매니저의 stale 정지는 벤치가 재지 않습니다). cst 축만 있는 버스의 기존 승인은 그대로 유효하고, csp·csv 축이 있는 버스의 기존 승인은 stop-decel 이 없어 다시 벤치해야 합니다. FAIL 은 어떤 항목이든 거부됩니다 — 드라이브가 제공하지 않는 선택 항목은 NA 로 적거나 뺍니다. 지금 소프트웨어의 필수 항목 목록은 plem drive check JSON 의 required_bench_items 키가 보여 줍니다.
업데이트가 어떤 항목의 합격 기준을 올리면 그 항목의 id 가 새 이름으로 바뀝니다(예: stale-engage → stale-engage-2). 옛 벤치 증거에는 새 id 가 없으므로 승인이 풀리고, 그 업데이트의 CHANGELOG 에 「드라이브 재벤치 필요」가 적힙니다.
한 브레이크를 여러 축이 공유하는 드라이브는 이 승인 절차의 대상이 아닙니다. 승인 판정은 공유 여부를 검사하지 못합니다.