Skip to main content
Version: 3.0 (next)

Beckhoff TwinCAT Beckhoff TwinCAT Integration Guide

Talk directly to Beckhoff TwinCAT 2 and TwinCAT 3 PLC runtimes using MaestroHub's TwinCAT connector, which speaks ADS (Automation Device Specification) — Beckhoff's native protocol — over AMS/TCP. This guide covers connection setup and AMS routing, the symbolic addressing model, authoring read/write/struct functions, the symbolic tag map, server-pushed device notifications, and how the matching nodes slot into the Pipeline Designer.

Overview​

The TwinCAT connector provides:

  • Symbolic read/write — address variables by their PLC symbol path (MAIN.fbMotor.Speed), not by raw memory offsets
  • Typed values — BOOL, integer types (BYTE/SINT/USINT/INT/UINT/DINT/UDINT/WORD/DWORD), REAL/LREAL floats, and STRING/WSTRING
  • Struct read/write — read a whole struct decoded field-by-field, or write selected members atomically with field-merge (autoFill)
  • Array access — read a 1-D scalar array variable as a list in a single round-trip
  • Full symbol browsing — upload and search the PLC's symbol table from the tag picker
  • Batched sum-up reads — read many symbols in one ADS request instead of one round-trip per tag
  • Server-pushed device notifications — the PLC pushes a new sample on-change or on a cycle, eliminating polling (used as a pipeline trigger)
  • Symbolic tag mapping — map friendly names to symbol paths
  • Automatic reconnection — transparent teardown-and-reconnect with a configurable retry budget
Supported runtimes

The connector targets the TwinCAT PLC runtime over AMS/TCP (port 48898):

  • TwinCAT 3 (TC3) — select TwinCAT Version TC3 (default AMS port 851)
  • TwinCAT 2 (TC2) — select TwinCAT Version TC2 (default AMS port 801)

Both versions share the same symbol and STRING handling. Plain ADS (securityMode: none) is supported today; Secure ADS (TLS/PSK on port 8016) arrives in a future release.

How ADS Connections Work​

ADS is not a simple host:port socket protocol — it routes messages between AMS devices, each identified by a 6-byte AmsNetId (written as six dotted octets, e.g. 192.168.1.10.1.1) and an AmsPort (the runtime task). The transport (AMS/TCP) runs on port 48898, but the actual addressing is by AmsNetId + AmsPort.

Two things must line up for a connection to succeed:

  1. The target — the PLC's Address (IP/host, used to open the AMS/TCP socket on port 48898), its Target AmsNetId, and the AMS Port of the runtime you want (851 for a TC3 PLC task, 801 for TC2).
  2. The route — the PLC must have a route that trusts this host's AmsNetId (Local AmsNetId). Without that route the PLC silently refuses the connection. This is the single most common setup problem.
The PLC must trust this host's AmsNetId — add the route first

ADS connections are gated by a route on the PLC side. Before the connection can work, add a route on the PLC that trusts this host's Local AmsNetId:

  • TwinCAT 3: TwinCAT XAE / System Manager → Routes, or edit StaticRoutes.xml
  • TwinCAT 2: TwinCAT System Manager → Route settings

Without the route, Test Connection fails — usually as a timeout or an AMS router error, not an obvious "access denied". The connector turns this failure into an actionable message telling you exactly which AmsNetId to add. Confirm a runtime is actually listening on the chosen AMS Port too.

Connection Configuration​

Creating a TwinCAT Connection​

Navigate to Connections → New Connection → Beckhoff TwinCAT and configure the form. The form is organized into six tabs: Connection, Advanced, Tag Map, Functions, Scaling, and Health. The Functions, Scaling, and Health tabs unlock after the connection is saved.

1. Profile Information​

FieldDefaultDescription
Profile Name—A descriptive name for this connection profile (required, max 100 characters). Must be unique across all connections.
Description—Optional description for this TwinCAT connection
Labels—Key-value pairs to categorize and organize the connection (max 10 labels)

Example Labels

  • environment: production — Deployment environment
  • line: line-1 — Production line
  • plc-version: TC3 — TwinCAT version
  • area: packaging — Plant area

2. ADS Connection Settings​

FieldDefaultDescription
Address—Target PLC IP or hostname (required). The AMS/TCP router port 48898 is used to open the socket.
Target AmsNetId—6-byte AMS Net ID of the PLC, written as six dotted octets (required). Often the IP with .1.1 appended, e.g. 192.168.1.10.1.1.
AMS Port851The runtime port: 851 = TC3 PLC task 1, 801 = TC2 PLC, 852/853 = further TC3 tasks (1–65535).
Local AmsNetId—This host's AMS Net ID (six dotted octets). Must be added as a trusted route on the PLC or the connection fails. Leave blank to let the runtime use a default.
TwinCAT VersionTC3TC2 or TC3. Selecting a version sets the standard AMS Port for you (801 for TC2, 851 for TC3) only when the port is still at the other version's default — it never clobbers a port you typed for a non-standard task.
Choosing the AMS Port

The TwinCAT Version field is a convenience that picks the standard runtime port. Override the AMS Port directly when you need a non-default PLC task:

  • 851 — TC3 PLC task 1 (the default)
  • 852, 853, … — further TC3 PLC tasks
  • 801 — TC2 PLC runtime

If reads fail immediately after connecting, an AMS Port pointed at the wrong task (or no task) is a common cause.

3. Advanced — Local Port, Timing & Retries​

The Advanced tab tunes the local ADS port, transport timing, and the retry policy.

FieldDefaultDescription
Local AMS Port0Local ADS port (0–65535). 0 = auto-assign.
Request Timeout (ms)5000Per-request transport timeout (0–60,000 ms)
Retries2Number of retries on a transport-level failure (0–10)
Retry Delay (ms)500Delay between retry attempts (0–60,000 ms)
Retry and reconnect behavior

On a transport error (socket closed, dial failure, timeout) the connector tears down the session and reconnects on the next attempt, within the configured Retries budget separated by Retry Delay. An ADS device code (the PLC answered with an error — e.g. "symbol not found") is not retried; it is surfaced immediately as a failed result, because retrying a bad request would only repeat the same error.

4. Tag Map​

The Tag Map tab attaches an optional symbolic alias list — see Symbolic Tag Map below. It is entirely optional; every operation can always reference a raw PLC symbol path.

Testing the Connection​

Click Test Connection at the bottom of the form. The probe opens the AMS/TCP socket and issues an ADS Read State round-trip as its health check, then reports a latency in milliseconds. A non-zero ADS code still counts as success — the PLC answered, so the wire is alive — only a transport failure (no socket, no route, no runtime) fails the probe.

If the probe fails because of a missing route or a timeout, the connector returns a specific message telling you to add a route on the PLC trusting this host's Local AmsNetId and to confirm a runtime is listening on the chosen AMS Port. Use this before saving to catch a wrong address, AmsNetId, AMS Port, or a missing route early.

Symbolic Addressing​

TwinCAT variables are addressed by their symbol path — the fully-qualified name from your PLC program — not by a memory address. Examples:

Symbol PathWhat it refers to
MAIN.fbMotor.SpeedThe Speed member of the fbMotor function-block instance in program MAIN
GVL.bEStopThe bEStop variable in a Global Variable List
MAIN.stStatusA whole struct variable
MAIN.aTemperaturesAn array variable

Internally each symbol is resolved to a handle and read/written by handle. Handles are valid for the lifetime of one session and are re-resolved automatically after a reconnect or a PLC program download — you never manage them yourself.

Symbol Browser​

The function form includes a Symbol Browser in the right sidebar to help you discover symbol paths without leaving MaestroHub:

  • Click Browse to upload the PLC's symbol table (via the internal twincat.list.symbols operation). A real PLC can expose tens of thousands of symbols, so the list is virtualized for responsiveness.
  • The search box filters the list by a case-insensitive substring of the symbol path.
  • Each row shows the symbol's type and size; click a row to drop the symbol path straight into the form field (or add it as a data point on a block read).
  • The refresh button re-uploads the table — useful after a PLC program download changes the symbols.

Supported Data Types​

Each value is interpreted as a data type on top of the raw ADS byte access. All scalars are little-endian. When you leave Data Type blank, the connector uses the type recorded in the uploaded symbol table; set it explicitly to override.

Data TypeBytesValue ShapeExample
BOOL1booleantrue / false
BYTE1unsigned 8-bit (0–255)200
SINT1signed 8-bit (−128 to 127)-5
USINT1unsigned 8-bit (0–255)200
INT2signed 16-bit (−32,768 to 32,767)-100
UINT2unsigned 16-bit (0–65,535)1234
WORD2unsigned 16-bit0x04D2 → 1234
DINT4signed 32-bit-70000
UDINT4unsigned 32-bit70000
DWORD4unsigned 32-bit70000
REAL4IEEE 754 single-precision float3.14
LREAL8IEEE 754 double-precision float3.141592653589793
STRINGcapacitytext, null-terminated, fixed capacityHello
WSTRINGcapacitytext (UTF-16LE), null-terminated, fixed capacityHello
STRING capacity comes from the symbol — not guessed

For STRING and WSTRING, the capacity is taken from the symbol's own byte size in the PLC symbol table (e.g. a STRING(80) is 81 bytes including the null terminator). Reads decode up to the first null; writes are truncated to fit and zero-padded to the full capacity so the whole PLC variable is overwritten. You don't set a length manually — the symbol table is authoritative.

Auto-detected wide types

When you leave Data Type blank, the connector also decodes the wider IEC types it finds in the symbol table — LINT/ULINT (signed/unsigned 64-bit), LWORD (unsigned 64-bit), and TIME (a DWORD of milliseconds). The explicit Data Type dropdown lists the common set above; for these wider types, leave the override blank and let the symbol table drive decoding.

Arrays​

A plain Read Symbol on a 1-D array of a scalar type (e.g. ARRAY [0..9] OF REAL) reads the whole array in one round-trip and returns its elements as a list. Multi-dimensional arrays, arrays of arrays, and arrays of structs are not decoded — they return a clear "not supported — read elements individually" error rather than wrong data. To read one element, address it directly (e.g. MAIN.aTemperatures[3]).

Symbolic Tag Map​

The tag map lets functions reference a friendly name (e.g. MotorSpeed) instead of a raw symbol path (MAIN.fbMotor.Speed). It is optional — operations can always use raw symbol paths.

Open the connection → Tag Map tab. Each tag maps a name to a symbol path and an optional data type:

FieldRequiredDescription
NameYesFriendly tag name. Must be unique within the connection — duplicates are rejected.
SymbolYesThe PLC symbol path the tag resolves to (e.g. MAIN.fbMotor.Speed)
Data TypeNoOptional override; leave as Auto to use the type from the symbol table

Add a tag by filling the Name / Symbol / Data Type row and clicking the + button. Existing tags are listed below with a remove action.

Tags resolve everywhere a symbol is accepted

Anywhere a function asks for a Symbol / Tag, you can type either a raw symbol path (MAIN.fbMotor.Speed) or a tag name (MotorSpeed). The connector resolves the tag to its underlying symbol path and data type at execution time. Re-pointing a tag to a different symbol is a one-line change in the tag map rather than an edit to every function.

Function Builder​

Creating TwinCAT Functions​

After the connection is saved:

  1. Open the connection and navigate to the Functions tab
  2. Click New Function to open the function type selection dialog
  3. Choose a function type (grouped into Read, Write, and Trigger)
  4. Fill the Basic fields (name, description, labels) and the Configuration fields (operation-specific parameters), using the Symbol Browser to pick paths
  5. Use the Test Function button to validate the function against the live PLC before saving (except for Device Notification, which is validated by enabling its pipeline)
TwinCAT function type selection dialog

Pick a TwinCAT function type: Read Symbol, Read Block, Read Struct, Write Symbol, Write Struct, or Device Notification

Read Symbol (twincat.read.symbol)​

Purpose: Read a single typed value from one TwinCAT variable identified by its symbol path. If the symbol is a 1-D scalar array, its elements are returned as a list (see Arrays).

Configuration Fields​

FieldTypeRequiredDefaultDescription
Symbol / TagStringYes—PLC symbol path (MAIN.fbMotor.Speed) or a tag-map alias. Supports ((paramName)) templates.
Data TypeSelectNo(from symbol table)Override how to decode the value. Leave blank to use the type recorded in the symbol table.

Use Cases: Process-variable monitoring, reading a setpoint, checking an E-stop or status flag, reading an array of values.

Example Output

{
"symbol": "MAIN.fbMotor.Speed",
"dataType": "LREAL",
"value": 72.5
}

Read Block (Multi) (twincat.read.block)​

Purpose: The efficient multi-read path. Reads multiple named symbols in a single ADS sum-up request instead of one round-trip per tag — the right primitive for dashboards and scans. Each datapoint resolves its own handle and data type; a single bad symbol fails only its own entry, not the whole batch.

Configuration Fields​

FieldTypeRequiredDescription
Data PointsArrayYesOne or more symbols to read in a single coalesced operation

Each data point

FieldTypeRequiredDescription
nameStringYesOutput key for this point in the result map
symbolStringYesPLC symbol path or tag-map alias
dataTypeSelectNoOptional override; blank = use the symbol table type

Use Cases: Dashboard snapshots, periodic historian logging, reading a block of process values from one program in one efficient call.

Example — Data Points

namesymboldataType
speedMAIN.fbMotor.SpeedLREAL
runningMAIN.fbMotor.bRunningBOOL
countMAIN.nPartCountDINT
estopGVL.bEStopBOOL

Example Output

{
"values": {
"speed": 72.5,
"running": true,
"count": 100000,
"estop": false
}
}

If any point fails to resolve or decode, the result also includes an errors map keyed by the failing point's name; the points that succeeded are still returned under values:

{
"values": { "speed": 72.5, "count": 100000 },
"errors": { "estop": "symbol not found" }
}

Read Struct (twincat.read.struct)​

Purpose: Read a whole struct variable and decode every scalar member by its offset and type from the uploaded symbol table. Returns a nested object keyed by member name — the right path for the struct-heavy programs typical of TwinCAT 3. The struct's byte blob is read in one round-trip, then sliced member-by-member; nested structs become nested objects.

Configuration Fields​

FieldTypeRequiredDescription
Struct SymbolStringYesPLC symbol path of a struct variable (MAIN.stStatus) or a tag-map alias. Supports ((paramName)) templates.

Use Cases: Reading a machine-status struct, a recipe struct, or any composite type as a single nested object.

Example Output

{
"symbol": "MAIN.stStatus",
"dataType": "ST_Status",
"value": {
"running": true,
"speed": 72.5,
"mode": 2,
"fault": { "code": 0, "active": false }
}
}
Read Symbol vs. Read Struct

A plain Read Symbol on a struct returns an error directing you to Read Struct (a struct has no single scalar value). Use Read Struct for any composite type; use Read Symbol for scalars and 1-D scalar arrays.

Write Symbol (twincat.write.symbol)​

Purpose: Write a single typed value to one writable TwinCAT variable, resolved by symbol path. The value is encoded according to the symbol's data type (or an explicit override). Writing to a read-only variable is rejected by the PLC with a clear ADS code, surfaced as a failed result.

Configuration Fields​

FieldTypeRequiredDefaultDescription
Symbol / TagStringYes—Writable PLC symbol path (MAIN.fSetpoint) or a tag-map alias. Supports ((paramName)) templates.
ValueTextYes—Value to write, parsed according to the data type. Supports ((paramName)) templates — see Using Parameters.
Data TypeSelectNo(from symbol table)Override how to encode the value. Leave blank to use the symbol table type.

Value parsing by type

Data TypeAccepted ValueNotes
BOOLtrue, false, 1, 0, on, off, yes, noCase-insensitive
BYTE / USINT / UINT / WORD / UDINT / DWORD1234Unsigned; rejects negatives
SINT / INT / DINT-100Signed
REAL / LREAL3.14IEEE 754 float
STRING / WSTRINGHelloEncoded to the symbol's capacity, null-terminated

Use Cases: Setpoint updates, recipe download, setting a command/start flag, mode changes.

Example Output

{
"symbol": "MAIN.fSetpoint",
"dataType": "LREAL",
"value": "42.5"
}
Safety First

Always implement validation and safety checks before writing to industrial equipment. A setpoint or command flag can move a motor, valve, or actuator immediately. Gate writes behind a Condition node that bounds the value, or behind an explicit operator action. A plain Write Symbol on a struct is rejected — use Write Struct.

Write Struct (twincat.write.struct)​

Purpose: Write multiple members of a TwinCAT struct in one atomic write, encoding each member by its offset and type. With autoFill on (the default) the current struct is read first and only the provided members are changed, so unspecified fields are preserved rather than zeroed.

Configuration Fields​

FieldTypeRequiredDefaultDescription
Struct SymbolStringYes—PLC symbol path of a struct variable (MAIN.stConfig) or a tag-map alias. Supports ((paramName)) templates.
FieldsObjectYes—A JSON object of { memberName: value } to write. Members not listed are preserved when autoFill is on. Supports ((paramName)) templates.
Auto-fill (read-merge-write)BooleanNotrueWhen on, the current struct is read and the provided fields are merged so unspecified members are preserved. When off, all unspecified members are written as zero.

The Fields editor is a JSON object — for example:

{
"setpoint": 42.5,
"enabled": true,
"mode": 2
}

Use Cases: Updating a few fields of a config or recipe struct without disturbing the rest, downloading a complete struct.

Example Output

{
"symbol": "MAIN.stConfig",
"written": ["setpoint", "enabled", "mode"],
"autoFill": true
}
Auto-fill off zeroes everything you didn't list

With autoFill = false, every member you do not include in Fields is written as zero — the whole struct is overwritten. Leave autoFill on (the default) unless you intend to reset the entire struct. Nested-struct and array members cannot be written as a single field; write their individual scalar members instead.

Device Notification (twincat.notify)​

Purpose: Subscribe to a TwinCAT variable using ADS device notifications. The PLC pushes a new sample whenever the value changes (on-change) or on a fixed cycle (cyclic) — no polling. Each push carries a server timestamp. This function type is a pipeline trigger: see Pipeline Integration and the TwinCAT Trigger node.

Configuration Fields​

FieldTypeRequiredDefaultDescription
Symbol / TagStringYes—PLC symbol path to monitor (MAIN.bAlarm) or a tag-map alias
Data TypeSelectNo(from symbol table)Override how to decode each sample
ModeSelectNoonChangeonChange = push only when the value changes; cyclic = push every cycle time
Cycle Time (ms)NumberNo1000Sampling cycle for cyclic mode, and the server's change-check interval for onChange (0–3,600,000 ms). 0 = server default.
Max Delay (ms)NumberNo0Maximum time the server batches samples before pushing (0–3,600,000 ms). 0 = no batching (push immediately).

Use Cases: Trigger a pipeline whenever an alarm flag changes; receive a temperature every 500 ms (cyclic); event-driven telemetry without polling.

onChange is enforced by the PLC — no connector-side dedup

In onChange mode the PLC itself only pushes when the value actually changes (checked every Cycle Time). There is no extra deduplication in MaestroHub — every delivered sample is a real change with its own server timestamp. This mirrors the OPC UA subscription model, not the always-fire CANopen TPDO model.

Using Parameters​

The Value field on Write Symbol (and the symbol/fields fields) supports parameter placeholders using ((parameterName)) syntax. Parameters are detected automatically as you type and surface in the Function Parameters block. Use parameters to make a single function reusable across multiple pipeline contexts.

ConfigurationDescriptionExample
TypeValidate the expected value typenumber, boolean, string
RequiredForce critical inputsRequired / Optional
Default ValueProvide safe fallbacks for unattended runs0, false, 100.0
DescriptionDocument the parameter's purpose"Target temperature setpoint in °C"

Example

  • Function type: Write Symbol
  • Symbol: MAIN.fSetpoint
  • Data Type: LREAL
  • Value: ((targetTemp))

At pipeline execution the runtime substitutes ((targetTemp)) with the value bound on the node and writes it to MAIN.fSetpoint.

Testing Functions​

Read Symbol, Read Block, Read Struct, Write Symbol, and Write Struct functions can be tested before saving using the Test Function button:

  1. Click Test Function on the function form
  2. The dialog shows an execution overview with the resolved configuration
  3. If the function references ((paramName)) templates, you are prompted for values
  4. Click Execute Test to run the function against the live PLC
  5. The result — decoded value(s), any ADS device error, and execution timing — renders in the dialog

You do not need to save the function to test it. Device Notification functions are not tested this way — they are validated by enabling the pipeline that uses them.

Pipeline Integration​

Use the TwinCAT functions you configure here as nodes inside the Pipeline Designer. Reads, writes, and struct operations are exposed as matching connector nodes, and Device Notification functions drive the TwinCAT trigger node:

  • TwinCAT Read Symbol (connected.twincat.read.symbol) — executes a twincat.read.symbol function
  • TwinCAT Read Block (connected.twincat.read.block) — executes a twincat.read.block sum-up function
  • TwinCAT Read Struct (connected.twincat.read.struct) — executes a twincat.read.struct function
  • TwinCAT Write Symbol (connected.twincat.write.symbol) — executes a twincat.write.symbol function
  • TwinCAT Write Struct (connected.twincat.write.struct) — executes a twincat.write.struct function
  • TwinCAT Trigger (trigger.twincat) — starts a pipeline on each ADS device notification from a twincat.notify function

For node-level details (full parameter reference, input/output schema, execution settings), see the Beckhoff TwinCAT Nodes and TwinCAT Trigger pages.

For orchestration strategies that mix TwinCAT with other data sources, see the Connector Nodes page.

Common Use Cases​

Process Monitoring to a Historian or UNS​

Author a Read Block function covering your line's key symbols (speeds, counts, levels, status flags), drive it from a Schedule trigger, and route the decoded map to a historian, MQTT topic, or the Unified Namespace. The sum-up read keeps the round-trip count to one even for dozens of symbols.

Event-Driven Alarms and Telemetry​

Author a Device Notification function on an alarm flag (onChange) or a process value (cyclic), then use the TwinCAT Trigger node to start a pipeline on each push — no polling interval, latency bounded by the PLC's check cycle.

Setpoint and Recipe Download​

Receive setpoints from an upstream MES or operator UI, then issue parameterized Write Symbol functions (Value: ((setpoint))), or a Write Struct to update several recipe fields atomically. Validate every value with a Condition node before the write reaches the PLC.

Symbolic Tag Standardization​

Build a tag map once (or browse the symbol table to discover paths), then author every function against friendly names. Re-pointing a tag to a different symbol is a one-line change in the tag map rather than an edit to every function.

Troubleshooting​

Connection Issues​

SymptomPossible CauseSolution
Test Connection fails with a route / timeout messageThe PLC has no route trusting this host's AmsNetIdAdd a route on the PLC (TwinCAT System Manager → Routes, or StaticRoutes.xml) for this host's Local AmsNetId, then retest.
Test Connection times out immediatelyWrong Address, nothing listening on AMS/TCP port 48898, or a firewallConfirm the PLC IP/host, that port 48898 is reachable from the connector host, and that the TwinCAT system is running.
Connects, but every read fails right awayWrong AMS Port — pointed at a task with no runtimeUse 851 for a TC3 PLC task (or 852/853 for further tasks), 801 for TC2. Confirm the runtime is in Run mode.
symbol not found style errorThe symbol path is wrong, or the program was downloaded and the cached table is staleUse the Symbol Browser (click Refresh after a program download) to confirm the exact path. Symbol paths are case-insensitive but must otherwise match.

Read / Write Issues​

SymptomPossible CauseSolution
symbol … has compound type … — use read.structTried to Read Symbol on a structUse Read Struct for composite types.
A struct read/write rejects a member as "compound"A member is itself a nested struct or arrayRead or write the member's individual scalar fields instead of the whole nested member.
Write rejected with an ADS device codeThe target variable is read-only, or the value is out of range/wrong typeConfirm the variable is writable and the value parses for its data type.
multi-dimensional arrays are not supported / arrays of … not supportedRead Symbol on a multi-dim array or array of structsAddress individual elements (e.g. MAIN.aData[3]) or read scalar members individually.
A STRING reads back truncatedThe written string exceeded the symbol's capacityThe capacity is the PLC STRING(N) size; shorten the value or enlarge the PLC variable.
Notifications stop / "dropping notification samples" warningThe downstream consumer can't keep up with the sample rateIncrease Cycle Time, reduce the number of subscribed symbols, or buffer downstream with an Aggregator node.
Test before wiring

Use the Test Function button on the connection page to validate every read/write/struct function against the live PLC before wiring it into a pipeline. It is the fastest way to catch a wrong symbol path, wrong data type, or a read-only target. Use the Symbol Browser to confirm exact paths and types.