CANopen 드라이버
개요
CANopen — CAN 버스 위의 EN 50325-4 / CiA 301 표준 application layer (모터드라이브 / 인코더 / IO 모듈에서 보편). 2026-07 네이티브 재작성 — 옛 Apache PLC4j canopen 위임은 제거되었습니다(PLC4X CANopen 은 로컬 SocketCAN transport 만 지원해 TCP 로 나를 수 없어, 물리 CAN 버스가 없는 엣지에서 connect 가 죽었음). 지금은 plantpulse-plc-protocol 의 자체 SDO expedited upload 구현(CanopenSdoClient) + transport 추상화(CanTransport)를 사용 — AB-ETH / BACnet 와 동일한 네이티브 패턴.
| 항목 | 값 |
|---|---|
opc_type | CANOPEN |
| 구현 클래스 | plantpulse.driver.protocol.canopen.CANOpenDriver |
| 라이브러리 | 자체 네이티브 (plantpulse-plc-protocol 의 canopen — SDO expedited upload) |
| 상속 | BaseProtocolDriver (PLC4j 아님) |
getProtocol() | "canopen:tcp" (옛 PLC4X scheme 표기 유지 — 로그/진단 호환) |
| 기본 포트 | 20200 (CAN-over-TCP 게이트웨이) |
| 상태 | 안정 (SDO expedited 폴링) |
| read | OK (SDO expedited upload, 값 ≤4바이트) |
| write | ❌ (읽기 전용 — SDO download 미구현) |
| 보안 | 없음 |
기본 transport(tcp)는 CAN ↔ TCP 게이트웨이 너머의 CANopen 노드와 통신합니다. CAN 프레임을 canId(4B BE) + dlc(1B) + data[dlc] 자체 바이너리 프레이밍으로 TCP 에 실어 나릅니다(핸드셰이크/버스명 협상 없음 — 시뮬레이터와 동일 프레이밍). transport=socketcan(로컬 can0)은 현재 스텁(AF_CAN 네이티브 바인딩/JNI 필요)이라 connect 가 실패합니다 — 물리 CAN 인터페이스 트랙은 후속.
클래스 구조
BaseProtocolDriver
└── CANOpenDriver — connect() 에서 CanTransport(tcp/socketcan) + CanopenSdoClient 생성
read 실패(Abort/타임아웃/소켓)는 소켓을 무효화(connected=false + close)해 엣지가 재연결하도록 유도합니다.
wire 포맷 요약 (자체 구현 — SDO expedited upload)
- 요청: COB-ID
0x600+nodeId, data[0x40, index LE(2B), subindex, 0×4]. - 응답: COB-ID
0x580+nodeId, command0x43(4B)/0x47(3B)/0x4B(2B)/0x4F(1B) — 값 little-endian.0x80= Abort(코드 u32 LE) → 통신 예외. - segmented / block transfer 미지원(값 >4B, 예: 긴 문자열) — 스칼라 태그 폴링엔 expedited 로 충분.
OPC 등록 옵션
| 필드 | 의미 | 기본 |
|---|---|---|
opc_agent_ip | CAN-TCP 게이트웨이 IP | 192.168.1.20 |
opc_agent_port | 게이트웨이 TCP 포트 | 20200 |
options.read-timeout | SDO 응답 타임아웃 (ms) | 3000 |
options.transport | tcp / socketcan(스텁) | tcp |
options.can-interface | socketcan 모드 인터페이스명 | can0 |
옛 폼/문서의 node-id 옵션은 폐기 — 노드 ID 는 이제 태그 주소의 1번째 필드입니다(아래). request-timeout/heartbeat 옵션도 네이티브가 받지 않습니다(타임아웃은 read-timeout).
태그 plc_address 형식 (신규 계약)
<nodeId>:<index>:<subindex>[:<TYPE>]
| 필드 | 의미 | 표기 |
|---|---|---|
nodeId | CANopen 노드 id (1..127) | 10진 |
index | 오브젝트 딕셔너리 index (0..0xFFFF) | 0x 접두 16진(0x6041) 또는 10진 |
subindex | 서브 index (0..255) | 0x 접두 16진 또는 10진 |
TYPE (선택) | LE 바이트 해석 타입 | 생략 시 data_type 유추 → 그것도 없으면 UINT16 |
| 표기 | 의미 |
|---|---|
1:0x6041:0:UINT16 | 노드 1, DS402 Statusword |
3:0x2000:0:REAL | 노드 3, 제조사 영역 float32 |
1:0x6064:0:INT32 | Position actual value (32-bit signed) |
5:8192:1 | 노드 5, index 10진 8192(=0x2000), TYPE 생략 → UINT16 |
TYPE 토큰 (별칭 포용)
| 토큰(별칭) | 크기 | 해석 |
|---|---|---|
BOOL(BOOLEAN) | 1 | 0 아니면 true |
UINT8(U8,USINT,BYTE) / INT8(I8,SINT) | 1 | u8 / i8 |
UINT16(U16,UINT,WORD) / INT16(I16,INT) | 2 | u16 / i16 (기본 UINT16) |
UINT32(U32,UDINT,DWORD) / INT32(I32,DINT) | 4 | u32 / i32 |
REAL(FLOAT,F32,REAL32) | 4 | IEEE-754 float (LE) |
STRING(STR,VISIBLE_STRING) | ≤4 | ASCII (trailing NUL 제거) |
TYPE 생략 시 data_type 유추: Boolean→BOOL, Integer→INT16, Long→INT32, Float→REAL, Double→REAL(4B 근사), String→STRING.
support / 미지원
- read: SDO expedited upload (≤4바이트) — OK.
- write: 미지원 —
isWriteSupported() = false,write()는 항상false. (SDO download 는 후속.) - segmented / block SDO, PDO 매핑, NMT / Heartbeat 모니터링, SYNC, EMCY, LSS: 미지원.
- 직접 SocketCAN / USB-CAN: 스텁 (CAN-over-TCP 게이트웨이 전제).
curl 등록 예시
curl -X POST http://<edge-host>/api/v1/opc \
-H "Content-Type: application/json" \
-d '{
"opc_id": "OPC_CANOPEN_DRIVE1",
"opc_type": "CANOPEN",
"opc_name": "Servo Drive 1",
"opc_agent_ip": "192.168.1.20",
"opc_agent_port": "20200",
"site_id": "SITE_00001",
"auto_collect": true,
"timecycle": 1000,
"options": { "read-timeout": "3000" },
"tag_list": [
{"tag_id":"OPC_CANOPEN_DRIVE1_T01","tag_name":"Statusword","plc_address":"1:0x6041:0:UINT16","data_type":"Integer"},
{"tag_id":"OPC_CANOPEN_DRIVE1_T02","tag_name":"ActualPos","plc_address":"1:0x6064:0:INT32","data_type":"Long"}
]
}'
참고
- CiA 301 (Application Layer) / CiA 402 (Drives) 표준.
- 코드:
plantpulse-edge-driver/src/plantpulse/driver/protocol/canopen/CANOpenDriver.java+plantpulse-plc-protocol의canopen패키지. - 운영: 게이트웨이 프레이밍은 자체 바이너리(
canId+dlc+data) — socketcand 텍스트 프로토콜과 다름. 좌표는 device EDS 파일 기준으로 검증 권장.