Software architecture¶
The control software comes in three layers in this lab:
- AeroWare — legacy LabVIEW application. VFD path broken (see Operations → Start via AeroWare); DAQ path still works. Being retired.
WindTunnelControl.ps1— short-term PowerShell + Windows Forms GUI incode/wind_tunnel_control/. Does VFD control only, no DAQ. Used as a fallback and for direct hardware verification.- 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:
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.42wind_speed_MPH ≈ 0.0822 × drive_RPM − 13.14(fordrive_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.
Where to read next¶
- ADCL WinSoft — modules, threading model, footguns.
- WindTunnelControl.ps1 — Modbus client, start sequence, GUI layout.
- Building & deploying — how to ship updates to either tool.
- Testing — pytest smoke tests in
code/adcl_winsoft/tests/. - Extending the code — how to add a tab, a new register, or refresh calibration.