APIs, concepts, guides, and more
Network: Status

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.

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:


📜 Network Status

""" 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
# AL Status decoding (bits 0-3 state, bit 4 error flag) lives in _helpers: helpers.decode_al_status
# for one node, helpers.decode_al_status_ored for the network-wide OR of every node's register.
# Calculate formatting widths from actual data
MAX_STATE_WIDTH = max(len(s) for s in helpers.AL_STATUS_STATES.values()) + len(helpers.AL_STATUS_ERROR_SUFFIX) # e.g., "SAFEOP" + "+ERR" = 10
AL_STATUS_COL_WIDTH = 7 + MAX_STATE_WIDTH # "0xXX (" + state + ")" = 7 + state width
def display_network_status(controller: RapidCode.MotionController):
"""Display the overall network status and per-node status."""
# Get network status from MotionController
network_status = controller.NetworkStatusGet()
# Collect nodes and determine max name length for formatting
nodes = []
max_name_len = 10 # minimum width
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()))
# Print network status header
width = 80
print("\n" + "=" * width)
print("NETWORK STATUS")
print("=" * width)
# Decode and display network-level status
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 per-node status
print("\n" + "=" * width)
print("NODE STATUS (with each node's service channel request counts)")
print("=" * width)
# Header row
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))
# Print each node's status
for node in nodes:
node_index = node.NumberGet()
node_name = node.NameGet()[:max_name_len]
# Get node status
status = node.StatusGet()
# Format fields
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}")
# The table row is already at full width, so the service channel counters get a second
# line. They are cumulative since the network started, so they show which node the firmware
# has done the most service channel work for. The "SDO" counts also include register
# access (index below 0x1000), which shares the same service channel thread.
service_channel = (f" service channel: SDO r/w {status.SdoReadCount}/{status.SdoWriteCount} "
f"(fail {status.SdoReadFailCount}/{status.SdoWriteFailCount})")
# Only the nodes that accept AKDASCIICommand get the ASCII counts: elsewhere they stay 0.
if node.IsAKDASCIICommandSupported():
service_channel += f", AKD ASCII {status.AkdAsciiCount} (fail {status.AkdAsciiFailCount})"
print(service_channel)
print("=" * width)
# MAIN
print("Network Status Diagnostic")
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()}")
# Display network and node status
display_network_status(motion_controller)
# Clean up
motion_controller.Delete()