This controller enables the construction of a relatively inexpensive Magnetic Loop Antenna for HF bands, such as this one.
- ESP32 processor
- Control options:
- Web interface
- LCD Display + Pushbuttons / Rotary Encoder
- Memory management:
- Up to 50 memory slots, automatically sorted by frequency
- Auto-save after successful tuning (stale memories replaced, duplicates removed)
- Automatic memory selection by frequency
- Automation features (requires wfview):
- Automatic antenna tuning with adaptive hill-climb algorithm
- Automatic motor positioning for non-memorised frequencies (interpolation)
- Automatic memory selection when changing frequency on the radio
- Dynamic configuration:
- Set endstop and motor position via the web interface
- Configure WiFi and wfview settings without modifying source code
- REST API v1 for external integration and scripting
The project is inspired by Jose's (EA7HVO) controller, from which I borrowed the overall concept, enclosure, hardware UI, and numerous other insights.
Jose's project is excellent and well-proven. If remote operation is not a priority for you, I highly recommend checking out his work.
All components match EA7HVO's project, except:
-
The control board is a Wemos D1 R32, which has the same form factor as an Arduino Uno but is powered by an ESP32 processor.
-
The Protoneer CNC Shield 3.0 is the same board used in EA7HVO's project, however in this one you must remove the only resistor on the board (R1) in order to make it work. You can either cut the resistor using scissors (it is through hole) or you can desolder it.
-
Wires are connected in a different order:
Pin Name ESP32 GPIO Protoneer CNC 3.0 Board Pin SCL_PIN 26 ZSTEP SDA_PIN 17 XSTEP BUTTON1_PIN 13 ENDSTOP X- BUTTON2_PIN 5 ENDSTOP Y- BUTTON3_PIN 23 ENDSTOP Z- BUTTON4_PIN 14 ZDIR BUTTON5_PIN 18 SPINDIR ENCODER_PIN1 16 XDIR ENCODER_PIN2 19 SPINENABLE -
Unlike Jose's boards, all connections to the CNC shield can be made using pin headers without the need to solder anything (the only soldered wires are below the Wemos board, used for 12V power supply).
Apart from these modifications, everything else is the same. This ensures a well-documented build process while adding remote operation capabilities and improved memory management.
Software has been rewritten from scratch. Rotation is now handled by the AccelStepper library which allows faster speeds and controlled acceleration/deceleration of the stepper. The biggest additions are the web interface, the improved memory management, the automation features, and the REST API.
The entire project can be emulated online using Wokwi. However, note that the free Wokwi version does not support the web interface, nor the automation features.
Below is a screenshot of the web interface:
When powered on, the controller will start in Access Point mode. Connect to the K1FM Loop Controller Wi-Fi network and navigate to 192.168.4.1 in your browser to access the control interface. From there, you can operate the antenna directly. Additionally, you can configure the controller to connect to your home Wi-Fi and set up the wfview server parameters, enabling the automation features.
Once the Wi-Fi parameters are configured, the controller will automatically connect to your home Wi-Fi network on subsequent power-ups, bypassing Access Point mode.
You must set your capacitor's endstop using the LCD menu or the web interface before using the controller. This is critical — accidentally rotating the shaft past either endstop could irreversibly damage a vacuum capacitor.
Automation features require wfview running on a computer connected to your radio. Configure the wfview server URL in the web interface (e.g. http://radio.local:8081/api/v1/radio) and enable Radio Control in the LCD menu or via the API.
When Radio Control is enabled the controller:
- Polls the radio's current frequency every 300 ms
- Moves the motor to the matching memory position when the frequency matches a saved memory (if Automatic Memory Selection is also enabled)
- Interpolates a motor position from bracketing memories for frequencies not in memory (with a 50 kHz hysteresis to avoid chasing VFO changes while scanning)
The auto-tune function (Tune button or POST /api/v1/tune) uses a three-phase adaptive hill-climb:
-
Pre-position — jump to the nearest saved memory within ±50 kHz as a starting hint. If none exists, linearly interpolate from the closest memories above and below within ±1 MHz. Magnetic loop positions drift daily with weather, so this is a hint only.
-
Coarse phase (50-step probes) — explore both directions and follow the improving one until the minimum is bracketed.
-
Medium phase (10-step probes) — refine from the best coarse position.
-
Fine phase (1-step probes) — lock in to the exact minimum.
On success (SWR ≤ 1.2), the result is saved: the nearest memory within 50 kHz is replaced (stale memories are expected due to daily drift), or a new memory is created. Any other memory sharing the same motor position is removed as redundant. Failed tunes are never saved.
The controller exposes a REST API at /api/v1/. All endpoints return JSON.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/status |
Current position, frequency, SWR, flags |
| GET | /api/v1/memories |
All saved memories |
| POST | /api/v1/memories |
Add or update a single memory |
| PUT | /api/v1/memories |
Bulk replace all memories |
| GET | /api/v1/memories/{index} |
Single memory by index |
| PUT | /api/v1/memories/{index} |
Update memory by index |
| DELETE | /api/v1/memories/{index} |
Delete memory by index |
| POST | /api/v1/memories/{index}/select |
Move motor to memory position |
| GET | /api/v1/settings |
Export settings |
| PUT | /api/v1/settings |
Update settings |
| POST | /api/v1/step/{dir}/{n} |
Step motor ±n steps (dir: up or down) |
| POST | /api/v1/tune |
Run auto-tune sequence |
| POST | /api/v1/swr |
Measure SWR without tuning |
Automatic memory selectionDONEAutomatic antenna tuningDONEDynamic endstop configurationDONEOTA configuration management (WiFi / wfview)DONEREST APIDONEAdaptive tuning algorithm with memory interpolationDONE- Generalize capacitance calculation to support other capacitors
This project is provided as is, without any express or implied warranties. The author assumes no responsibility for any damage, malfunctions, or regulatory violations resulting from the use of this controller. Use at your own risk.
This project is licensed under the MIT License. You are free to use, modify, and distribute it, provided that the original license and attribution remain intact.