6.3 KiB
Beckhoff TwinCAT (ADS) Driver
Getting-started guide for the Beckhoff TwinCAT driver. This is the short path —
for the full per-field spec read docs/v2/driver-specs.md §6,
for hands-on CLI testing read Driver.TwinCAT.Cli.md,
and for the test-harness map read TwinCAT-Test-Fixture.md.
What it talks to
Beckhoff PLC runtimes — TwinCAT 2 and TwinCAT 3 — over the Beckhoff ADS
protocol carried by AMS routing. The driver runs in-process in the OtOpcUa
server's .NET 10 AnyCPU host. It compiles and runs without a local AMS router,
but every wire call returns BadCommunicationError until a router is reachable
(the router translates an AMS Net ID to an IP route).
Addressing is symbol-based: tags are referenced by their TwinCAT symbolic
name (e.g. MAIN.bStart, GVL.Counter, Motor1.Status.Running) rather than by
raw memory offset. One driver instance fans out to N targets, each identified by
an AMS Net ID + port.
Project split
| Project | Target | Role |
|---|---|---|
src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/ |
net10.0 | In-process driver — hosts the ADS client, symbol-path parser, and per-device probe loops |
src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Contracts/ |
net10.0 | Config records + the TwinCATDataType enum bound from DriverConfig JSON |
Minimum deployment
"Drivers": {
"twincat-cell-1": {
"Type": "TwinCAT",
"Config": {
"Devices": [ { "HostAddress": "ads://5.23.91.23.1.1:851", "DeviceName": "Cell1" } ],
"Tags": [
{ "Name": "Start", "DeviceHostAddress": "ads://5.23.91.23.1.1:851",
"SymbolPath": "MAIN.bStart", "DataType": "Bool", "Writable": true },
{ "Name": "Count", "DeviceHostAddress": "ads://5.23.91.23.1.1:851",
"SymbolPath": "GVL.Counter", "DataType": "Int32", "Writable": false }
]
}
}
}
AMS address form
HostAddress is an ads://{netId}:{port} URI parsed by
src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATAmsAddress.cs. The Net ID
is six dot-separated octets (NOT an IP — a Beckhoff-specific identifier the
router maps to a route); the port is the AMS service port (851 = TC3 PLC runtime
1, 852 = runtime 2, 801 / 811 / 821 = TC2 PLC runtimes). Port defaults to 851
when omitted (ads://5.23.91.23.1.1).
Symbol path form
Symbol paths are parsed by
src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATSymbolPath.cs, which
mirrors IEC 61131-3 structured-text identifiers: global-variable-list
(GVL.Counter), program variable (MAIN.bStart), struct member access
(Motor1.Status.Running), array subscripts (Data[5], Matrix[1,2]), and
bit-access (Flags.0).
Tag discovery
DiscoverAsync always emits the pre-declared Tags as the authoritative config
path, under TwinCAT/{device}/. When EnableControllerBrowse is set, the
driver also walks each device's symbol table and surfaces controller-resident
globals / program locals under a Discovered/ sub-folder; any symbol-loader
error falls back to pre-declared-only so a flaky symbol download never blocks
discovery.
Capability surface
TwinCATDriver : IDriver, IReadable, IWritable, ITagDiscovery, ISubscribable, IHostConnectivityProbe, IPerCallHostResolver, IRediscoverable
(src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT/TwinCATDriver.cs).
| Capability | Path | Notes |
|---|---|---|
IReadable |
ReadAsync → ADS ReadValueAsync |
Per-device client, lazily connected and serialized per device |
IWritable |
WriteAsync → ADS WriteValueAsync |
Read-only tags return BadNotWritable |
ITagDiscovery |
DiscoverAsync |
Pre-declared tags + opt-in controller symbol browse |
ISubscribable |
native ADS notifications (default), poll fallback | UseNativeNotifications=true registers device notifications so the PLC pushes changes; false uses the shared PollGroupEngine |
IHostConnectivityProbe |
per-device probe loop | One HostConnectivityStatus per configured device; Running/Stopped transitions raise OnHostStatusChanged |
IPerCallHostResolver |
ResolveHost lookup in the tag map |
Routes each call to the device of the referenced tag; returns an empty-string sentinel when unresolved |
IRediscoverable |
symbol-version-changed callback | A PLC re-download fires OnRediscoveryNeeded so the address space is rebuilt |
Rediscovery on PLC re-download
IRediscoverable is the distinguishing capability. When the ADS client detects
DeviceSymbolVersionInvalid (1809 / 0x0711) — the documented TwinCAT
symbol-version-changed signal, raised when a PLC program is re-downloaded —
every symbol and notification handle is invalidated. The driver raises
OnRediscoveryNeeded with a TwinCAT scope hint so Core rebuilds the address
space rather than treating it as a transient connection error.
Native notifications
By default the driver registers native ADS device notifications: the PLC pushes
value changes on its own cycle, which is strictly better for latency and CPU
than polling. NotificationMaxDelayMs lets TwinCAT coalesce notifications up to
a batching delay for high-churn signals. Set UseNativeNotifications=false for
deployments where the AMS router has notification limits you can't raise — then
the driver falls through to the shared poll engine.
Single-connection-per-device
Each device's ADS client is lazily connected and serialized by a per-device
connect gate, so a concurrent read / write / probe can't race a client
create-or-dispose. Probe-initiated connects use the probe timeout; reads and
writes use the driver-wide Timeout.
Testing
- Unit tests —
tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.TwinCAT.Tests/cover the AMS / symbol-path parsers, the status mapper, and the driver lifecycle via a fake ADS client factory. - Integration fixture — see TwinCAT-Test-Fixture.md for the harness map.
- CLI — Driver.TwinCAT.Cli.md documents the standalone read/write/browse/probe CLI for manual checks.
Further reading
docs/v2/driver-specs.md §6— full per-field spec and DriverConfig JSON shape- Driver.TwinCAT.Cli.md — standalone TwinCAT driver CLI
- TwinCAT-Test-Fixture.md — test-harness map