Learn how to read and display network and node status diagnostics from an EtherCAT network. The application creates a MotionController object, checks for errors, and displays overall network status along with per-node AL Status, status codes, and CoE emergency messages, including each node's service-channel request counts.
""" EtherCAT network status diagnostic utility for real-time monitoring.
This utility displays the overall network status from the MotionController and
the individual status of each network node. It provides visibility into:
Network Status (MotionController level):
- ActiveNodeCount: Number of nodes actively responding on the network
- AlStatus: Logical OR of AL Status registers from all nodes (0x0130)
- MissedCyclicFrameCount: Cumulative count of missed cyclic EtherCAT frames
- CyclicFramePeriodUs: Most recent cyclic frame period in microseconds
- SynchronizationErrorNs: Distributed Clock synchronization error in nanoseconds
Node Status (per RapidCodeNetworkNode):
- AlStatus: EtherCAT AL Status register (0x0130) value for this specific node
- AlStatusCode: EtherCAT AL Status Code register value (error details)
- CoeEmergencyMessage: CANopen over EtherCAT emergency message (if any)
- CoeEmergencyMessageNetworkCounter: Network counter when emergency was received
- SdoReadCount / SdoWriteCount: Service channel requests (CoE SDO transfers and also
register access, index below 0x1000) the network firmware serviced for this node,
cumulative since the network started
- SdoReadFailCount / SdoWriteFailCount: How many of those requests failed (an SDO abort
or other error status, or no answer within the firmware's one second wait). Register
writes are fire and forget, so they never count as failures
- AkdAsciiCount / AkdAsciiFailCount: Kollmorgen AKD ASCII commands serviced for this
node, and how many of them failed (shown only where the node accepts them, see
RapidCodeNetworkNode.IsAKDASCIICommandSupported)
AL Status Register (0x0130) Decoding:
Bits 0-3 indicate Device State Machine state:
- 1 = Init (initialization)
- 2 = PreOp (pre-operational, mailbox communication only)
- 3 = Bootstrap (firmware update mode)
- 4 = SafeOp (safe-operational, inputs active, outputs safe)
- 8 = Operational (full operation, inputs and outputs active)
Bit 4 is the Error Flag - when set, check AlStatusCode for details.
When to Use This Diagnostic Tool:
- Verify all nodes are in OPERATIONAL state after network startup
- Check for nodes reporting errors (Bit 4 set in AlStatus)
- Monitor missed cyclic frame counts for network quality issues
- Check DC synchronization error for timing accuracy
- Diagnose CoE emergency messages from drives or devices
Practical Examples of Output to Diagnose Network Issues:
Example 1: A cable or power failure.
- Active Node Count: 2 (7 discovered)
Example 2: A node fell out of Operational state. Look up 1A in the manual.
- 0 | Mitsubishi MR-J5-TM | 0x14 (SAFEOP+ERR) | 0x001A | 0x000000000000 | 0
"""
from _imports import RapidCode, helpers
MAX_STATE_WIDTH = max(len(s) for s in helpers.AL_STATUS_STATES.values()) + len(helpers.AL_STATUS_ERROR_SUFFIX)
AL_STATUS_COL_WIDTH = 7 + MAX_STATE_WIDTH
def display_network_status(controller: RapidCode.MotionController):
"""Display the overall network status and per-node status."""
network_status = controller.NetworkStatusGet()
nodes = []
max_name_len = 10
for i in range(controller.NetworkNodeCountGet()):
node = controller.NetworkNodeGet(i)
helpers.check_errors(node)
if node.Exists():
nodes.append(node)
max_name_len = max(max_name_len, len(node.NameGet()))
width = 80
print("\n" + "=" * width)
print("NETWORK STATUS")
print("=" * width)
network_state = helpers.get_enum_name("RSINetworkState_RSINetworkState", controller.NetworkStateGet())
al_status_str = f"0x{network_status.AlStatus:02X} ({helpers.decode_al_status_ored(network_status.AlStatus)})"
sync_sign = "+" if network_status.SynchronizationErrorNs >= 0 else ""
print(f" Network State: {network_state}")
print(f" Active Node Count: {network_status.ActiveNodeCount} ({controller.NetworkNodeCountGet()} discovered)")
print(f" AL Status: {al_status_str}")
print(f" Missed Cyclic Frames: {network_status.MissedCyclicFrameCount}")
print(f" Cyclic Frame Period: {network_status.CyclicFramePeriodUs} us")
print(f" Synchronization Error: {sync_sign}{network_status.SynchronizationErrorNs} ns")
print("\n" + "=" * width)
print("NODE STATUS (with each node's service channel request counts)")
print("=" * width)
header = f"{'Node':>4} | {'Name':<{max_name_len}} | {'AL Status':^{AL_STATUS_COL_WIDTH}} | {'AL Code':^8} | {'CoE Emergency':^16} | {'Counter':>8}"
print(header)
print("-" * len(header))
for node in nodes:
node_index = node.NumberGet()
node_name = node.NameGet()[:max_name_len]
status = node.StatusGet()
al_status_str = f"0x{status.AlStatus:02X} ({helpers.decode_al_status(status.AlStatus):^{MAX_STATE_WIDTH}})"
al_code_str = f"0x{status.AlStatusCode:04X}"
coe_emergency_str = f"0x{status.CoeEmergencyMessage:012X}"
counter_str = f"{status.CoeEmergencyMessageNetworkCounter:8d}"
print(f"{node_index:>4} | {node_name:<{max_name_len}} | {al_status_str:^{AL_STATUS_COL_WIDTH}} | {al_code_str:^8} | {coe_emergency_str:^16} | {counter_str}")
service_channel = (f" service channel: SDO r/w {status.SdoReadCount}/{status.SdoWriteCount} "
f"(fail {status.SdoReadFailCount}/{status.SdoWriteFailCount})")
if node.IsAKDASCIICommandSupported():
service_channel += f", AKD ASCII {status.AkdAsciiCount} (fail {status.AkdAsciiFailCount})"
print(service_channel)
print("=" * width)
print("Network Status Diagnostic")
print("-" * 40)
creation_params: RapidCode.CreationParameters = helpers.get_creation_parameters()
motion_controller: RapidCode.MotionController = RapidCode.MotionController.Create(creation_params)
print(f"MotionController creation error count: {motion_controller.ErrorLogCountGet()}")
helpers.check_errors(motion_controller)
print(f"RapidCode Version: {motion_controller.VersionGet()}")
print(f"Serial Number: {motion_controller.SerialNumberGet()}")
display_network_status(motion_controller)
motion_controller.Delete()