APIs, concepts, guides, and more
network-status.py
Note
See Network: Status 📜 for a detailed explanation of this sample code.
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.
1""" EtherCAT network status diagnostic utility for real-time monitoring.
2
3 This utility displays the overall network status from the MotionController and
4 the individual status of each network node. It provides visibility into:
5
6 Network Status (MotionController level):
7 - ActiveNodeCount: Number of nodes actively responding on the network
8 - AlStatus: Logical OR of AL Status registers from all nodes (0x0130)
9 - MissedCyclicFrameCount: Cumulative count of missed cyclic EtherCAT frames
10 - CyclicFramePeriodUs: Most recent cyclic frame period in microseconds
11 - SynchronizationErrorNs: Distributed Clock synchronization error in nanoseconds
12
13 Node Status (per RapidCodeNetworkNode):
14 - AlStatus: EtherCAT AL Status register (0x0130) value for this specific node
15 - AlStatusCode: EtherCAT AL Status Code register value (error details)
16 - CoeEmergencyMessage: CANopen over EtherCAT emergency message (if any)
17 - CoeEmergencyMessageNetworkCounter: Network counter when emergency was received
18 - SdoReadCount / SdoWriteCount: Service channel requests (CoE SDO transfers and also
19 register access, index below 0x1000) the network firmware serviced for this node,
20 cumulative since the network started
21 - SdoReadFailCount / SdoWriteFailCount: How many of those requests failed (an SDO abort
22 or other error status, or no answer within the firmware's one second wait). Register
23 writes are fire and forget, so they never count as failures
24 - AkdAsciiCount / AkdAsciiFailCount: Kollmorgen AKD ASCII commands serviced for this
25 node, and how many of them failed (shown only where the node accepts them, see
26 RapidCodeNetworkNode.IsAKDASCIICommandSupported)
27
28 AL Status Register (0x0130) Decoding:
29 Bits 0-3 indicate Device State Machine state:
30 - 1 = Init (initialization)
31 - 2 = PreOp (pre-operational, mailbox communication only)
32 - 3 = Bootstrap (firmware update mode)
33 - 4 = SafeOp (safe-operational, inputs active, outputs safe)
34 - 8 = Operational (full operation, inputs and outputs active)
35 Bit 4 is the Error Flag - when set, check AlStatusCode for details.
36
37 When to Use This Diagnostic Tool:
38 - Verify all nodes are in OPERATIONAL state after network startup
39 - Check for nodes reporting errors (Bit 4 set in AlStatus)
40 - Monitor missed cyclic frame counts for network quality issues
41 - Check DC synchronization error for timing accuracy
42 - Diagnose CoE emergency messages from drives or devices
43
44 Practical Examples of Output to Diagnose Network Issues:
45 Example 1: A cable or power failure.
46 - Active Node Count: 2 (7 discovered)
47 Example 2: A node fell out of Operational state. Look up 1A in the manual.
48 - 0 | Mitsubishi MR-J5-TM | 0x14 (SAFEOP+ERR) | 0x001A | 0x000000000000 | 0
49"""
50
51from _imports import RapidCode, helpers
52
53
54# AL Status decoding (bits 0-3 state, bit 4 error flag) lives in _helpers: helpers.decode_al_status
55# for one node, helpers.decode_al_status_ored for the network-wide OR of every node's register.
56
57# Calculate formatting widths from actual data
58MAX_STATE_WIDTH = max(len(s) for s in helpers.AL_STATUS_STATES.values()) + len(helpers.AL_STATUS_ERROR_SUFFIX) # e.g., "SAFEOP" + "+ERR" = 10
59AL_STATUS_COL_WIDTH = 7 + MAX_STATE_WIDTH # "0xXX (" + state + ")" = 7 + state width
60
61
62def display_network_status(controller: RapidCode.MotionController):
63 """Display the overall network status and per-node status."""
64
65 # Get network status from MotionController
66 network_status = controller.NetworkStatusGet()
67
68 # Collect nodes and determine max name length for formatting
69 nodes = []
70 max_name_len = 10 # minimum width
71 for i in range(controller.NetworkNodeCountGet()):
72 node = controller.NetworkNodeGet(i)
73 helpers.check_errors(node)
74 if node.Exists():
75 nodes.append(node)
76 max_name_len = max(max_name_len, len(node.NameGet()))
77
78 # Print network status header
79 width = 80
80 print("\n" + "=" * width)
81 print("NETWORK STATUS")
82 print("=" * width)
83
84 # Decode and display network-level status
85 network_state = helpers.get_enum_name("RSINetworkState_RSINetworkState", controller.NetworkStateGet())
86 al_status_str = f"0x{network_status.AlStatus:02X} ({helpers.decode_al_status_ored(network_status.AlStatus)})"
87 sync_sign = "+" if network_status.SynchronizationErrorNs >= 0 else ""
88
89 print(f" Network State: {network_state}")
90 print(f" Active Node Count: {network_status.ActiveNodeCount} ({controller.NetworkNodeCountGet()} discovered)")
91 print(f" AL Status: {al_status_str}")
92 print(f" Missed Cyclic Frames: {network_status.MissedCyclicFrameCount}")
93 print(f" Cyclic Frame Period: {network_status.CyclicFramePeriodUs} us")
94 print(f" Synchronization Error: {sync_sign}{network_status.SynchronizationErrorNs} ns")
95
96 # Print per-node status
97 print("\n" + "=" * width)
98 print("NODE STATUS (with each node's service channel request counts)")
99 print("=" * width)
100
101 # Header row
102 header = f"{'Node':>4} | {'Name':<{max_name_len}} | {'AL Status':^{AL_STATUS_COL_WIDTH}} | {'AL Code':^8} | {'CoE Emergency':^16} | {'Counter':>8}"
103 print(header)
104 print("-" * len(header))
105
106 # Print each node's status
107 for node in nodes:
108 node_index = node.NumberGet()
109 node_name = node.NameGet()[:max_name_len]
110
111 # Get node status
112 status = node.StatusGet()
113
114 # Format fields
115 al_status_str = f"0x{status.AlStatus:02X} ({helpers.decode_al_status(status.AlStatus):^{MAX_STATE_WIDTH}})"
116 al_code_str = f"0x{status.AlStatusCode:04X}"
117 coe_emergency_str = f"0x{status.CoeEmergencyMessage:012X}"
118 counter_str = f"{status.CoeEmergencyMessageNetworkCounter:8d}"
119
120 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}")
121
122 # The table row is already at full width, so the service channel counters get a second
123 # line. They are cumulative since the network started, so they show which node the firmware
124 # has done the most service channel work for. The "SDO" counts also include register
125 # access (index below 0x1000), which shares the same service channel thread.
126 service_channel = (f" service channel: SDO r/w {status.SdoReadCount}/{status.SdoWriteCount} "
127 f"(fail {status.SdoReadFailCount}/{status.SdoWriteFailCount})")
128 # Only the nodes that accept AKDASCIICommand get the ASCII counts: elsewhere they stay 0.
129 if node.IsAKDASCIICommandSupported():
130 service_channel += f", AKD ASCII {status.AkdAsciiCount} (fail {status.AkdAsciiFailCount})"
131 print(service_channel)
132
133 print("=" * width)
134
135
136# MAIN
137print("Network Status Diagnostic")
138print("-" * 40)
139
140# Create motion controller
141creation_params: RapidCode.CreationParameters = helpers.get_creation_parameters()
142motion_controller: RapidCode.MotionController = RapidCode.MotionController.Create(creation_params)
143
144# Check for errors
145print(f"MotionController creation error count: {motion_controller.ErrorLogCountGet()}")
146helpers.check_errors(motion_controller)
147
148# Print version info
149print(f"RapidCode Version: {motion_controller.VersionGet()}")
150print(f"Serial Number: {motion_controller.SerialNumberGet()}")
151
152# Display network and node status
153display_network_status(motion_controller)
154
155# Clean up
156motion_controller.Delete()