APIs, concepts, guides, and more
NetworkNode: Error Counts

Learn how to read and display RX error diagnostic counters from all network nodes in an EtherCAT network. The application creates a MotionController object, checks for errors, and if the network is operational, it reads RX error counters from each node and displays them in a formatted table.


Warning
This is a sample program to assist in the integration of the RMP motion controller with your application. It may not contain all of the logic and safety features that your application requires. We recommend that you wire an external hardware emergency stop (e-stop) button for safety when using our code sample apps. Doing so will help ensure the safety of you and those around you and will prevent potential injury or damage.

The sample apps assume that the system (network, axes, I/O) are configured prior to running the code featured in the sample app. See the Configuration page for more information.


In this page:


📜 NetworkNode Errors

""" EtherCAT RX error counter diagnostic utility for real-time network quality monitoring.
This utility reads the mandatory EtherCAT RX Error Counters from all network nodes following
the EtherCAT Technology Group diagnostic specifications. It monitors communication quality by
tracking both Frame Errors (CRC failures at data link layer) and Physical Layer Errors
(invalid symbols at hardware level) for each slave port.
RX Error Counter Types (Per ETG.1600)
- Frame Error Counters (0x0300, 0x0302, 0x0304, 0x0306): Increment when CRC check fails on
incoming frames, indicating corrupted data that will be discarded. Each slave port checks
frames arriving from outside and increments this counter when corruption is detected.
- Physical Layer Error Counters (0x0301, 0x0303, 0x0305, 0x0307): Track invalid symbols
detected at the physical layer, can occur both within and outside frames. When occurring
within frames, usually indicates Frame Errors as well.
When to Use This Diagnostic Tool
- Lost Frame Counter increments at master - investigate with this tool
- Working Counter (WKC) errors detected - deeper hardware diagnosis needed
- Cable qualification - validate new installations meet industrial Ethernet standards
- EMC troubleshooting - sporadic errors indicate electromagnetic interference
- Preventive maintenance - periodic monitoring for degrading connections
Interpreting Error Counter Values
- All zeros: Ideal state, network operating perfectly
- Sporadic increments (days/weeks apart): Normal due to BER 10^-12 (one bit error per trillion bits transmitted).
Industrial Ethernet standard.
- Burst errors (seconds/minutes): Actual problem requiring investigation
- Systematic increment: Hardware failure (damaged cable, connector oxidation, device fault)
- Unbalanced counters: Many Physical Layer but no Frame Errors or vice versa may indicate internal device
issue - consider replacing the device
Diagnostic Procedure (ETG Standard)
1. Follow frame path through network topology
2. Find FIRST port reporting Frame Error ≠ 0 in path sequence
3. Problem location is between this port and previous device
4. Check: cable routing near power lines, connector quality, shielding, grounding
Per ETG specifications, errors immediately after power-on/off are expected and should
be ignored. Only errors during steady-state operation indicate actual problems.
See also: ServiceChannelRead() can read ESC registers (< 0x1000) and SDOs (>= 0x1000)
"""
from typing import Dict
from _imports import RapidCode, helpers
# CONSTANTS (from https://www.ethercat.org/download/documents/EtherCAT_Diagnosis_For_Users.pdf pages 19-25)
PORT_0_FRAME_ERROR_COUNTER_REG = 0x300
PORT_0_RX_ERROR_COUNTER_REG = 0x301
PORT_1_FRAME_ERROR_COUNTER_REG = 0x302
PORT_1_RX_ERROR_COUNTER_REG = 0x303
PORT_2_FRAME_ERROR_COUNTER_REG = 0x304
PORT_2_RX_ERROR_COUNTER_REG = 0x305
PORT_3_FRAME_ERROR_COUNTER_REG = 0x306
PORT_3_RX_ERROR_COUNTER_REG = 0x307
ERROR_COUNT_SUBINDEX = 0
ERROR_COUNT_BYTES = 1
# METHODS
def read_node_rx_error_counters(node) -> Dict[str, int]:
"""Read all RX error counters from a network node."""
error_counts = {}
try:
# PORT 0
error_counts['Port0_FrameErrors'] = node.ServiceChannelRead(PORT_0_FRAME_ERROR_COUNTER_REG, ERROR_COUNT_SUBINDEX, ERROR_COUNT_BYTES)
error_counts['Port0_RxErrors'] = node.ServiceChannelRead(PORT_0_RX_ERROR_COUNTER_REG, ERROR_COUNT_SUBINDEX, ERROR_COUNT_BYTES)
# PORT 1
error_counts['Port1_FrameErrors'] = node.ServiceChannelRead(PORT_1_FRAME_ERROR_COUNTER_REG, ERROR_COUNT_SUBINDEX, ERROR_COUNT_BYTES)
error_counts['Port1_RxErrors'] = node.ServiceChannelRead(PORT_1_RX_ERROR_COUNTER_REG, ERROR_COUNT_SUBINDEX, ERROR_COUNT_BYTES)
# PORT 2
error_counts['Port2_FrameErrors'] = node.ServiceChannelRead(PORT_2_FRAME_ERROR_COUNTER_REG, ERROR_COUNT_SUBINDEX, ERROR_COUNT_BYTES)
error_counts['Port2_RxErrors'] = node.ServiceChannelRead(PORT_2_RX_ERROR_COUNTER_REG, ERROR_COUNT_SUBINDEX, ERROR_COUNT_BYTES)
# PORT 3
error_counts['Port3_FrameErrors'] = node.ServiceChannelRead(PORT_3_FRAME_ERROR_COUNTER_REG, ERROR_COUNT_SUBINDEX, ERROR_COUNT_BYTES)
error_counts['Port3_RxErrors'] = node.ServiceChannelRead(PORT_3_RX_ERROR_COUNTER_REG, ERROR_COUNT_SUBINDEX, ERROR_COUNT_BYTES)
except Exception as ex:
print(f"Error reading node {node.NumberGet()}: {ex}")
# Return zeros if there's an error
for port in range(4):
error_counts[f'Port{port}_FrameErrors'] = 0
error_counts[f'Port{port}_RxErrors'] = 0
return error_counts
def display_network_error_diagnostics(controller: RapidCode.MotionController):
"""Display RX error diagnostic counters for all nodes in the network."""
# Collect all nodes first to determine max name length
nodes = []
max_node_name_length = 10 # minimum width
for i in range(controller.NetworkNodeCountGet()):
io = controller.IOGet(i)
helpers.check_errors(io)
if io.NetworkNode.Exists():
nodes.append(io.NetworkNode)
max_node_name_length = max(max_node_name_length, len(io.NetworkNode.NameGet()))
# Print header first to measure actual line length
header_line = f"{'Node':^4} | {'Name':^{max_node_name_length}} | {'Port 0':^12} | {'Port 1':^12} | {'Port 2':^12} | {'Port 3':^12}"
subheader_line = f"{'':^4} | {'':^{max_node_name_length}} | {'Frame RX':^12} | {'Frame RX':^12} | {'Frame RX':^12} | {'Frame RX':^12}"
# Use actual header length for separator lines
total_width = len(header_line)
print("\n" + "="*total_width)
print("ETHERCAT RX ERROR COUNTERS")
print(f"Network: {controller.NetworkNodeCountGet()} Nodes")
print("="*total_width)
# Print header
print(header_line)
print(subheader_line)
print("-"*total_width)
# Print error counts for each node
for node in nodes:
node_index = node.NumberGet()
node_name = node.NameGet()[:max_node_name_length] # Truncate if needed
# Read error counters
error_counts = read_node_rx_error_counters(node)
# Format each port's errors - properly spaced (5+2+5 = 12 chars total)
ports = []
for port_num in range(4):
frame_errors = error_counts[f'Port{port_num}_FrameErrors']
rx_errors = error_counts[f'Port{port_num}_RxErrors']
ports.append(f"{frame_errors:5d} {rx_errors:5d}")
print(f"{node_index:^4} | {node_name:<{max_node_name_length}} | {ports[0]:^12} | {ports[1]:^12} | {ports[2]:^12} | {ports[3]:^12}")
print("="*total_width)
# MAIN
print("⬤ NetworkNode Errors")
print("EtherCAT RX Error Counter Diagnostics")
print("-"*40)
# create motion controller
creation_params: RapidCode.CreationParameters = helpers.get_creation_parameters()
motion_controller: RapidCode.MotionController = RapidCode.MotionController.Create(creation_params)
# check for errors
print(f"MotionController creation error count: {motion_controller.ErrorLogCountGet()}")
helpers.check_errors(motion_controller)
# print version info
print(f"RapidCode Version: {motion_controller.VersionGet()}")
print(f"Serial Number: {motion_controller.SerialNumberGet()}")
# check if network is operational
if motion_controller.NetworkStateGet() == RapidCode.RSINetworkState_RSINetworkStateOPERATIONAL:
display_network_error_diagnostics(motion_controller)
else:
print("\nNetwork is not in OPERATIONAL state. Current state:", motion_controller.NetworkStateGet())
print("Cannot read node error counts.")
# clean up
motion_controller.Delete()