CANopen-Treiber
Überblick
CANopen — Application Layer nach EN 50325-4 / CiA 301 auf dem CAN-Bus (verbreitet bei Motorantrieben, Encodern und IO-Modulen). Native Neuimplementierung 2026-07 — die frühere Delegation an Apache PLC4j canopen wurde entfernt (PLC4X CANopen unterstützt nur den lokalen SocketCAN-Transport und lässt sich nicht über TCP transportieren; auf Edge-Systemen ohne physischen CAN-Bus schlug connect deshalb fehl). Verwendet wird nun eine eigene SDO-Expedited-Upload-Implementierung in plantpulse-plc-protocol (CanopenSdoClient) plus Transport-Abstraktion (CanTransport) — dasselbe native Muster wie bei AB-ETH / BACnet.
| Punkt | Wert |
|---|---|
opc_type | CANOPEN |
| Implementierungsklasse | plantpulse.driver.protocol.canopen.CANOpenDriver |
| Bibliothek | eigene native Implementierung (canopen aus plantpulse-plc-protocol — SDO Expedited Upload) |
| Vererbung | BaseProtocolDriver (nicht PLC4j) |
getProtocol() | "canopen:tcp" (alte PLC4X-Schema-Notation beibehalten — Kompatibilität für Logs/Diagnose) |
| Standardport | 20200 (CAN-over-TCP-Gateway) |
| Status | stabil (SDO-Expedited-Polling) |
| read | OK (SDO Expedited Upload, Werte ≤ 4 Byte) |
| write | ❌ (nur lesend — SDO Download nicht implementiert) |
| Sicherheit | keine |
Der Standardtransport (tcp) kommuniziert mit CANopen-Knoten jenseits eines CAN-↔-TCP-Gateways. CAN-Frames werden mit einem eigenen Binär-Framing von canId(4B BE) + dlc(1B) + data[dlc] über TCP übertragen (kein Handshake, keine Busnamen-Aushandlung — identisches Framing wie im Simulator). transport=socketcan (lokales can0) ist derzeit ein Stub (erfordert native AF_CAN-Bindung/JNI), daher schlägt connect fehl — der Zweig für physische CAN-Schnittstellen folgt später.
Klassenstruktur
BaseProtocolDriver
└── CANOpenDriver — connect() 에서 CanTransport(tcp/socketcan) + CanopenSdoClient 생성
Bei fehlgeschlagenem read (Abort/Timeout/Socket) wird der Socket invalidiert (connected=false + close), damit der Edge einen Neuaufbau der Verbindung auslöst.
Zusammenfassung des Wire-Formats (Eigenimplementierung — SDO Expedited Upload)
- Anfrage: COB-ID
0x600+nodeId, data[0x40, index LE(2B), subindex, 0×4]. - Antwort: COB-ID
0x580+nodeId, command0x43(4B) /0x47(3B) /0x4B(2B) /0x4F(1B) — Wert little-endian.0x80= Abort (Code u32 LE) → Kommunikationsausnahme. - Segmented / Block Transfer nicht unterstützt (Werte > 4B, z. B. lange Strings) — für das Polling skalarer Tags genügt Expedited.
OPC-Registrierungsoptionen
| Feld | Bedeutung | Standard |
|---|---|---|
opc_agent_ip | IP des CAN-TCP-Gateways | 192.168.1.20 |
opc_agent_port | TCP-Port des Gateways | 20200 |
options.read-timeout | SDO-Antwort-Timeout (ms) | 3000 |
options.transport | tcp / socketcan (Stub) | tcp |
options.can-interface | Schnittstellenname im socketcan-Modus | can0 |
Die Option node-id aus alten Formularen/Dokumenten entfällt — die Node-ID ist jetzt das erste Feld der Tag-Adresse (siehe unten). Auch die Optionen request-timeout/heartbeat werden von der nativen Implementierung nicht akzeptiert (Timeout über read-timeout).
Format von Tag plc_address (neuer Vertrag)
<nodeId>:<index>:<subindex>[:<TYPE>]
| Feld | Bedeutung | Notation |
|---|---|---|
nodeId | CANopen-Node-ID (1..127) | dezimal |
index | Objektverzeichnis-Index (0..0xFFFF) | hexadezimal mit Präfix 0x (0x6041) oder dezimal |
subindex | Subindex (0..255) | hexadezimal mit Präfix 0x oder dezimal |
TYPE (optional) | Typ für die LE-Byte-Interpretation | bei Auslassung Ableitung aus data_type → andernfalls UINT16 |
| Notation | Bedeutung |
|---|---|
1:0x6041:0:UINT16 | Knoten 1, DS402 Statusword |
3:0x2000:0:REAL | Knoten 3, float32 im herstellerspezifischen Bereich |
1:0x6064:0:INT32 | Position actual value (32 Bit signed) |
5:8192:1 | Knoten 5, Index dezimal 8192 (= 0x2000), TYPE weggelassen → UINT16 |
TYPE-Token (inkl. Aliasen)
| Token (Alias) | Größe | Interpretation |
|---|---|---|
BOOL (BOOLEAN) | 1 | ungleich 0 bedeutet true |
UINT8 (U8, USINT, BYTE) / INT8 (I8, SINT) | 1 | u8 / i8 |
UINT16 (U16, UINT, WORD) / INT16 (I16, INT) | 2 | u16 / i16 (Standard 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 (abschließende NUL entfernt) |
Bei weggelassenem TYPE Ableitung aus data_type: Boolean→BOOL, Integer→INT16, Long→INT32, Float→REAL, Double→REAL (Näherung auf 4B), String→STRING.
Unterstützt / nicht unterstützt
- read: SDO Expedited Upload (≤ 4 Byte) — OK.
- write: nicht unterstützt —
isWriteSupported() = falseundwrite()liefern immerfalse. (SDO Download folgt.) - Segmented / Block SDO, PDO-Mapping, NMT-/Heartbeat-Überwachung, SYNC, EMCY, LSS: nicht unterstützt.
- Direktes SocketCAN / USB-CAN: Stub (CAN-over-TCP-Gateway vorausgesetzt).
curl-Registrierungsbeispiel
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"}
]
}'
Hinweise
- Standards CiA 301 (Application Layer) / CiA 402 (Drives).
- Code: Paket
canopeninplantpulse-edge-driver/src/plantpulse/driver/protocol/canopen/CANOpenDriver.java+plantpulse-plc-protocol. - Betrieb: Das Gateway-Framing ist ein eigenes Binärformat (
canId+dlc+data) — es unterscheidet sich vom Textprotokoll socketcand. Es wird empfohlen, die Adressen anhand der EDS-Datei des Geräts zu verifizieren.