Skip to content

Software architecture

The control software comes in three layers in this lab:

  1. AeroWare — legacy LabVIEW application. VFD path broken (see Operations → Start via AeroWare); DAQ path still works. Being retired.
  2. WindTunnelControl.ps1 — short-term PowerShell + Windows Forms GUI in code/wind_tunnel_control/. Does VFD control only, no DAQ. Used as a fallback and for direct hardware verification.
  3. ADCL WinSoft — long-term Python + PySide6 application in code/adcl_winsoft/. Does VFD control and DAQ in one process. Packaged as a single-file .exe. This is the supported tool going forward.

When to use which tool

Tool Use when
ADCL WinSoft The default. Any run that needs data, calibration, or a UI with feedback.
WindTunnelControl.ps1 ADCL WinSoft is unavailable; you need to test the Modbus path itself; you need to spin the motor without committing to a recording session.
AeroWare Only its DAQ side, only while validating ADCL WinSoft against it. Never its VFD side.

The two new tools share the same Modbus protocol behaviour (start sequence, calibration constants, drive parameters required). They differ in language, threading model, polish, and feature scope. Both target the same RETA-01 at 192.168.50.10:502.

Shared concepts

Modbus profile

Both tools use the ABB Drives profile with the quick-access registers:

Address Name Notes
0 Control Word 0x0476 (prep / ramp-stop), 0x047F (run), 0x0000 (off / E-Stop)
1 REF1 Speed reference, scaled REF1 = drive_RPM × 22.42
3 Status Word RDY, RUN, REM, FAULT bits
4 ACT1 Speed actual
5 ACT2 Current actual

Both tools read parameter values through the formula address = group × 100 + index − 1.

Start sequence

Both tools issue the same sequence from idle:

write REF1 = setpoint × 22.42
wait 0.2 s
write CW = 0x0476
wait 0.5 s
write CW = 0x047F

For mid-run changes both tools write only REF1. This is the most important behavioural rule in either codebase.

Calibration constants

Both tools share the empirical constants from WT_MS_2:

  • REF1 = drive_RPM × 22.42
  • wind_speed_MPH ≈ 0.0822 × drive_RPM − 13.14 (for drive_RPM > 300, where the static-ring transducer escapes noise)

See Reference → Calibration constants.

Differences worth knowing

Aspect ADCL WinSoft WindTunnelControl.ps1
Language Python 3.12 + PySide6 (Qt6) PowerShell 5.1 + Windows Forms
Modbus socket One persistent socket per VfdClient, lock-guarded One fresh socket per call
Polling rate 250 ms (4 Hz) reads; commands enqueued async 4 Hz polling loop
DAQ Yes — NI-DAQmx via nidaqmx, simulated fallback No
Calibration Yes — per-channel + matrix No
Data recording Yes — CSV in AeroWare-compatible format No
Admin gate Yes — Argon2id password, hidden tabs No
Packaging Single-file .exe via PyInstaller Run script directly
Source code/adcl_winsoft/ code/wind_tunnel_control/

Why persistent vs fresh sockets

The RETA-01 is happy with one connection at a time. Opening a fresh TCP socket per Modbus call works — that is what WindTunnelControl.ps1 does, at 4 Hz that is ~8 sockets per second and the adapter does not complain — but at higher rates the TCP handshake overhead becomes a problem. ADCL WinSoft polls at the same 4 Hz but its DAQ side adds load, and its command worker can fire writes in bursts; the persistent-socket design is what makes that stable.

This is the architectural lesson out of WT_MS_2's AeroWare diagnosis: AeroWare appears to have opened a fresh socket per Modbus call, which combined with its incorrect target IP produced a ~9 s TCP retransmit storm before failure. The persistent-socket plus correct IP design avoids both classes of bug.