# Property of PMA Electrical Solutions, LLC. # # AutomationDirect IronHorse ACG series AC drive, BUILT-IN RS-485 Modbus RTU # (control terminals S+/S-, or pins 1/8 of the I/O board RJ-45). # # Source: IH ACG Series AC Drive User Manual, 1st Ed., Rev A - 07/08/2026 # (cdn.automationdirect.com/static/manuals/acgdrives/acgdrives.pdf). # Comm wiring / node limits ............ ch.5 pp. 5-4 to 5-6 # CM group comm parameters ............. ch.5 pp. 5-7 to 5-8 # Command + frequency source ........... ch.5 p. 5-8 # Command-loss behaviour (Pr.12/13) .... ch.5 p. 5-9 # Modbus-RTU function codes + example .. ch.5 pp. 5-12 to 5-14 # Compatible common area (0h0000-001B).. ch.5 pp. 5-14 to 5-16 # Monitoring area (0h0300-0h034C) ...... ch.5 pp. 5-17 to 5-21 # Control area (0h0380-0h0395) ......... ch.5 pp. 5-22 to 5-23 # Parameter address tables ............. ch.5 pp. 5-26 onward # Pr.12 default (0: None) .............. ch.4 Pr group summary (0h1B0C) # # Claims ONLY the IronHorse ACG. The ACN and ACM are separate manuals with # separate register sets — the ACN has no compatible common area at all, and # the ACM's control word uses different bits. Do not cross-apply. # # --------------------------------------------------------------------------- # ADDRESSING — the manual's hex "Comm. Address" is NOT the wire address. # # 0-based protocol address = (manual hex Comm. Address) - 1 # # Proved twice inside this manual, not inferred: # * p. 5-14 worked example writes bA.70/bA.71 (Comm. Address 0x1246/0x1247) # with Starting Address 0x1245, labelled "Starting Address -1 (0x1246-1)". # * p. 5-26 states "Hex Address 0000 is unavailable with Modbus RTU", which # is only true if the wire address is hex-1 (0h0000 would be -1). # The manual's "ModbusRTU Decimal" column is the 1-based 4xxxx reference: # wire = ModbusRTU Decimal - 40001 (e.g. 44678 -> 0x1245, matching above). # The "ModbusTCP Decimal" column applies ONLY to the ACG-ET2 Ethernet option # card, where wire = hex. RTU and TCP wire addresses differ by one on this # drive. Every address below is already converted; do not subtract again. # # FALSIFY IN ONE READ on the first bench unit: read 0x0310 (0h0311, output # frequency) and 0x0311. Under this profile 0x0310 tracks the display in # 0.01 Hz. If instead 0x0311 tracks it, the whole map is off by one and every # address here must be raised by 1. # # vfd-core reads HOLDING REGISTERS (FC03) only. The ACG also answers FC04 on # the same addresses (p. 5-12), but nothing here requires it. # --------------------------------------------------------------------------- # # Drive-side setup, or the drive ACKs writes and ignores them: # CM.1 station ID (1-250), CM.2 = 0 Modbus-RTU, CM.3 baud (3 = 9600), # CM.4 = 0 (8N1), CM.5 response delay ms; # drv = 3 (Int485) -> command source is the built-in RS-485 port # Frq = 6 (Int485) -> frequency source is the built-in RS-485 port # # Values written to the common areas are NOT retained across a power cycle # unless 0h03E0 (wire 0x03DF) "Save parameters" is written 1 first (p. 5-24). # The frequency written to 0h0380 is never saved, by design (p. 5-23). name = "AutomationDirect IronHorse ACG" vendor = "AutomationDirect" device_type = "vfd" verified = false probe_register = 0x02FF # 0h0300 Drive model, reads 0x0010 on an ACG [connection] summary = "The ACG built-in RS-485 bus is available at screw terminals or an I/O-board RJ45; the optional ACG-ET2 board provides Modbus TCP." warnings = ["The screw terminals and base-drive RJ45 are the same RS-485 channel."] [[connection.methods]] id = "control_terminals_rs485" title = "Built-in RS-485 terminals" transport = "serial" hardware = "built_in" port = "Control terminals S+ and S-" connector = "Two control-terminal positions" adapter = "Isolated USB-to-RS-485 adapter, 2-wire half-duplex" cable = "18 AWG shielded twisted-pair RS-485 cable" parts = ["Isolated two-wire RS-485 adapter", "18 AWG shielded twisted-pair RS-485 cable"] steps = ["Lock out line and control power, wait the vendor-specified discharge time, and verify the DC bus is de-energized before opening a cover or landing conductors.", "Land the positive and negative data conductors exactly as shown; connect the cable shield or signal common only where the method identifies it.", "Route the communications cable away from motor and mains conductors. Terminate the two physical ends of a long multidrop trunk only.", "Restore control power with the motor area clear, configure the drive from its keypad, then verify identity and read-only monitor data before enabling remote control."] setup = ["Set CM.1=node, CM.2=0 Modbus RTU, CM.3=3 for 9600, CM.4=0 for 8N1, drv=3, and Frq=6."] warnings = ["RS-485 A/B naming is not consistent between manufacturers. Follow the + and - signal mapping in this guide, not the letter printed on an unfamiliar adapter.", "Do not use protective earth as the data return unless the vendor drawing explicitly calls for it."] source = "AutomationDirect IronHorse ACG User Manual, 1st Ed. Rev A, chapter 5 pp. 5-4 to 5-9 (S+/S-, RJ45 pins 1/8, cable and setup), Appendix B pp. B-2 to B-30 (ACG-ET2 Modbus TCP)" [[connection.methods.wiring]] adapter = "Adapter D+ / +" device = "S+" signal = "RS-485 data positive" required = true [[connection.methods.wiring]] adapter = "Adapter D- / -" device = "S-" signal = "RS-485 data negative" required = true [[connection.methods]] id = "rj45_rs485" title = "Built-in I/O-board RJ45 RS-485" transport = "serial" hardware = "built_in" port = "RJ45 on ACG I/O board" connector = "RJ45 wired as RS-485, not Ethernet" adapter = "Isolated USB-to-RS-485 adapter, 2-wire half-duplex" cable = "CAT5/CAT5e/CAT6 shielded cable using the pin-1/pin-8 pair" parts = ["Isolated two-wire RS-485 adapter", "CAT5/CAT5e/CAT6 shielded cable using the pin-1/pin-8 pair", "Field-terminated modular plug or documented breakout adapter"] steps = ["Lock out line and control power, wait the vendor-specified discharge time, and verify the DC bus is de-energized before opening a cover or landing conductors.", "Land the positive and negative data conductors exactly as shown; connect the cable shield or signal common only where the method identifies it.", "Route the communications cable away from motor and mains conductors. Terminate the two physical ends of a long multidrop trunk only.", "Restore control power with the motor area clear, configure the drive from its keypad, then verify identity and read-only monitor data before enabling remote control."] setup = ["Set CM.1=node, CM.2=0 Modbus RTU, CM.3=3 for 9600, CM.4=0 for 8N1, drv=3, and Frq=6."] warnings = ["A modular communications jack is not automatically Ethernet. Never connect it to a LAN switch unless this guide explicitly identifies a Modbus TCP method.", "RS-485 A/B naming is not consistent between manufacturers. Follow the + and - mapping shown here.", "The built-in RJ45 is shared with software/keypad/option-card use and is not a LAN port."] source = "AutomationDirect IronHorse ACG User Manual, 1st Ed. Rev A, chapter 5 pp. 5-4 to 5-9 (S+/S-, RJ45 pins 1/8, cable and setup), Appendix B pp. B-2 to B-30 (ACG-ET2 Modbus TCP)" [[connection.methods.wiring]] adapter = "Adapter D+ / +" device = "RJ45 pin 1 (S+)" signal = "RS-485 data positive" required = true [[connection.methods.wiring]] adapter = "Adapter D- / -" device = "RJ45 pin 8 (S-)" signal = "RS-485 data negative" required = true [[connection.methods]] id = "acg_et2_modbus_tcp" title = "ACG-ET2 Modbus TCP option" transport = "tcp" hardware = "option" port = "RJ45 Ethernet network port on ACG-ET2" connector = "RJ45 Ethernet" adapter = "Computer Ethernet interface or Ethernet switch" cable = "Category 5 or better Ethernet patch cable" parts = ["ACG-ET2 communications option", "Included internal RJ45 lead", "Ethernet patch cable"] steps = ["Lock out and isolate the equipment before fitting an option module or opening the enclosure.", "Install and fully seat the specified communications module according to its installation instructions.", "Connect the computer or switch with the specified Ethernet cable; keep it separated from motor and mains wiring.", "Restore control power, assign an IP address on the same subnet, discover the device, and verify read-only data before enabling network control."] setup = ["Install ACG-ET2 with power removed, connect its included internal lead to the drive, configure CM.10-CM.21 IP settings and the protocol/lost-command parameters."] warnings = ["An Ethernet link does not make remote motor control safe. Verify the drive-side communication-loss action and the independent hardwired stop circuit before commanding run.", "Do not confuse the ACG-ET2 external Ethernet port with the base-drive RS-485 RJ45.", "Install or remove the board only after the DC bus has fully discharged."] source = "AutomationDirect IronHorse ACG User Manual, 1st Ed. Rev A, chapter 5 pp. 5-4 to 5-9 (S+/S-, RJ45 pins 1/8, cable and setup), Appendix B pp. B-2 to B-30 (ACG-ET2 Modbus TCP)" [serial] baudrate = 9600 # CM.3 default 3 parity = "N" # CM.4 default 0 = D8/PN/S1 stopbits = 1 [monitor] # 0h0305. NIBBLE-coded, not flags: B0-B3 0=stopped 1=fwd 2=rev 3=DC braking; # B4-B7 1=speed search 2=accel 3=constant 4=decel 5=decel-to-stop 6=H/W OCS # 7=S/W OCS 8=dwell; B12-B15 0=normal 4=warning 8=fault. No bit names here # because a nibble read as flags is a lie. drive_state = { address = 0x0304 } # 0h000E, compatible common area (p. 5-15). Genuine flags. status_word = { address = 0x000D, bits = { 0 = "STOPPED", 1 = "RUNNING_FWD", 2 = "RUNNING_REV", 3 = "FAULT_TRIP", 4 = "ACCELERATING", 5 = "DECELERATING", 6 = "SPEED_REACHED", 7 = "DC_BRAKING", 8 = "STOPPING", 9 = "JOG_MODE", 10 = "BRAKE_RELEASE", 11 = "FWD_CMD", 12 = "REV_CMD", 13 = "CMD_SOURCE_IS_COMMS", 14 = "FREQ_SOURCE_IS_COMMS" } } output_frequency = { address = 0x0310, scale = 0.01, unit = "Hz" } # 0h0311 motor_current = { address = 0x030F, scale = 0.1, unit = "A" } # 0h0310 output_rpm = { address = 0x0311, unit = "rpm" } # 0h0312 motor_speed_feedback = { address = 0x0312, signed = true, unit = "rpm" } # 0h0313, directional output_voltage = { address = 0x0313, unit = "V" } # 0h0314 dc_voltage = { address = 0x0314, unit = "V" } # 0h0315 output_power = { address = 0x0315, scale = 0.1, unit = "kW" } # 0h0316 output_torque = { address = 0x0316, scale = 0.1, unit = "%" } # 0h0317 heatsink_temperature = { address = 0x032C, unit = "degC" } # 0h032D # 0h0331/0h0332/0h0333/0h0334/0h0335 — [faults] can only carry one register, # so the other four trip words are exposed here. latch_trip_2 = { address = 0x0330, bits = { 3 = "FAN_TRIP", 6 = "PRE_PID_FAIL", 7 = "BAD_CONTACT_IO_BOARD", 8 = "EXTERNAL_BRAKE_TRIP", 9 = "NO_MOTOR_TRIP", 10 = "BAD_OPTION_CARD", 14 = "PRE_OVER_HEAT_TRIP" } } level_trip = { address = 0x0331, bits = { 0 = "BX", 1 = "LOW_VOLTAGE_TRIP", 2 = "LOST_COMMAND", 3 = "KEYPAD_LOST_COMMAND" } } hw_diagnosis_trip = { address = 0x0332, bits = { 0 = "ADC_ERROR", 1 = "EEPROM_ERROR", 2 = "WATCHDOG_1_ERROR", 3 = "WATCHDOG_2_ERROR", 5 = "QUEUE_FULL" } } warnings = { address = 0x0333, bits = { 0 = "OVERLOAD", 1 = "UNDERLOAD", 2 = "DRIVE_OVERLOAD", 3 = "LOST_COMMAND", 4 = "FAN_RUNNING", 5 = "DB", 6 = "ENCODER_INSTALL", 7 = "ENCODER_DISCONNECT", 8 = "KEYPAD_LOST", 9 = "AUTO_TUNING_FAILED" } } latch_trip_3 = { address = 0x0334, bits = { 0 = "OVER_TORQUE_1", 1 = "UNDER_TORQUE_1", 2 = "OVER_TORQUE_2", 3 = "UNDER_TORQUE_2" } } # Control area, p. 5-22. 0h0382 bits: B0 0=stop/1=run, B1 0=reverse/1=forward, # B2 0->1 trip initialization, B3 0->1 free-run stop. The manual's own example # gives forward = 0003h and reverse = 0001h, so direction is a COMMAND BIT # here, not the sign of the reference — run_rev is real and is included. # Reset (B2) needs a 0->1 edge, hence the two-step sequence; 0x0004 carries # B0 = 0, so the reset value is a STOP, never a run. [control] command_register = 0x0381 # 0h0382 Operation command speed_register = 0x037F # 0h0380 Frequency command speed_scale = 0.01 # 0.01 Hz per count — fieldbus scale, p. 5-22 speed_unit = "Hz" max_ref = 400.0 # dr.20 Maximum frequency range is 40.00-400.00 Hz step_delay = 0.05 stop = [0x0000] run_fwd = [0x0003] run_rev = [0x0001] reset = [0x0004, 0x0000] # Pr.12 Lost Cmd Mode / Pr.13 Lost Cmd Time (p. 5-9). AT FACTORY DEFAULT THIS # DRIVE DOES NOT STOP ON COMM LOSS: Pr.12 = 0 "None" means "the speed command # immediately becomes the operation frequency without any protection # function" — the motor keeps running at the last commanded speed and only a # Lost Command WARNING is raised. Set Pr.12 = 1 (Free-Run) or 2 (Dec) on any # bus where silence must stop the motor. Pr.13 defaults to 1.0 s (range # 0.1-120 s); if Pr.13 is shortened below 1 s, shorten interval_ms with it. [control.watchdog] interval_ms = 500 fault = "Lost Command Trip (Pr.12 Lost Cmd Mode, Pr.13 Lost Cmd Time)" # No [running_check]. This drive publishes no single "running" bit: 0h000E # splits it across B1 (forward) and B2 (reverse), and 0h0305's B0-B3 is a # nibble. Asserting B1 alone would report STOPPED while the motor runs in # reverse, which would let a parameter restore through on a turning motor — # the exact interlock main.rs relies on. Unknown blocks; a wrong bit does not. # On a site that never reverses, and only there, add: # [running_check] # register = 0x000D # bit = 1 # 0h0330 Latch type trip information - 1 (p. 5-20). A BITFIELD: several trips # can be live at once, so there is no code to look up. The remaining trip # words are in [monitor] above. NOT SOURCED: this manual publishes no # register-mapped trip HISTORY — Pr group trip records are keypad/LCD only — # so [faults] carries no history registers rather than guessed ones. [faults] register = 0x032F bitfield = true bits = { 0 = "OVERLOAD_TRIP", 1 = "UNDERLOAD_TRIP", 2 = "DRIVE_OVERLOAD_TRIP", 3 = "E_THERMAL_TRIP", 4 = "GROUND_FAULT_TRIP", 5 = "OUTPUT_OPEN_PHASE_TRIP", 6 = "INPUT_OPEN_PHASE_TRIP", 9 = "NTC_TRIP", 10 = "OVERCURRENT_TRIP", 11 = "OVERVOLTAGE_TRIP", 12 = "EXTERNAL_TRIP", 13 = "ARM_SHORT", 14 = "OVER_HEAT_TRIP", 15 = "FUSE_OPEN_TRIP" } # 0h0301 Drive capacity. A coded value (0x3200 = 0.75 kW, 0x4160 = 22 kW, # p. 5-17), not a scaled number — useful as an identity to compare before a # restore, which is all [rating] is for. [rating] register = 0x0300 label = "drive capacity code (0h0301)" # No [parameters]. The manual publishes a complete per-parameter address table # (pp. 5-26 onward), but the CM group (0h1700) sits inside it: a restore that # sweeps a whole group rewrites the station ID and baud rate and drops the bus # mid-restore. Transcribe the wanted groups deliberately, excluding CM, before # enabling clone/restore on this drive.