PolarFire® Core FPGAs and SoC FPGAs
Experience low power, high security, and reliable performance with PolarFire® Core & SoC FPGAs.
Experience low power, high security, and reliable performance with PolarFire® Core & SoC FPGAs.
Voice control has become an integral part of modern smart home automation. In this tutorial, we build a voice-controlled LED system using the ESP32-S3-BOX-3 development board, combining wake word detection, speech recognition, touch interface, and audio feedback to create an intelligent control system. The code will be based on the factory example provided by Espressif and we will do the needed modifications to make it apt for our project.
The ESP32-S3-BOX-3 is a powerful development platform from Espressif that integrates a 320×240 touchscreen display, dual microphones for voice input, stereo speakers, and WiFi/Bluetooth connectivity. This project demonstrates how to leverage these features using the ESP-IDF (Espressif IoT Development Framework) and ESP-SR (Speech Recognition) library.

For a detailed hands-on review and getting-started walkthrough of the ESP32-S3-BOX-3 board, check out our previous articles on the same
Getting Started with ESP32-S3-BOX-3 - CircuitDigest Review
Programming ESP32-S3-BOX-3 with Arduino IDE - RGB LED Control
| S.No | Component | Quantity |
| 1 | ESP32-S3-BOX-3 Development Board | 1 |
| 2 | RGB LED Module | 1 |
| 3 | Jumper Wires | As needed |
| 4 | USB-C Cable (for programming and power) | 1 |
The circuit connection is straightforward. We connect an external LED to GPIO 40 of the ESP32-S3-BOX-3 board through a current-limiting resistor. For the ease of demonstration, we have used the RGB LED module that came with the ESP32-S3-BOX-3. We will be using the DOCK accessory to connect the LED. Insert the ESP32S3-Box-3 into the dock. Connect the GND pin of the RGB Module to any of the ground points in the dock and any one of the anode pins to the G40 port in the dock. As already mentioned, if you are using a single external LED, connect the cathode of the LED to ground and the anode to the G40 through a current-limiting resistor. The image below shows the connection.

Here is the ESP32S3-Box-3 with the LED attached.
This project requires ESP-IDF v5.5.2. For full installation and configuration instructions, refer to the official Espressif Getting Started Guide:
ESP-IDF Getting Started Guide (Official)
Then make sure to get our project file from our repo using git clone or manually downloading and extracting it to your preferred location.
git clone https://github.com/Circuit-Digest/Voice-Activated-LED-Controller-with-Touch-Interface-Using-ESP32S3-Box-31. Set up the ESP-IDF environment: Once you have properly installed and set up the ESP-IDF following Espressif's guide, on Mac or Linux systems, open a terminal and run the following command to set up the ESP-IDF environment. Make sure not to close the terminal once done, and any upcoming idf command has to be executed through the same terminal or command prompt. If you ever close the terminal, or when opening the project later, run this command first to set up the environment. This has to be done in each new section.
. $HOME/esp/esp-idf/export.shOn Windows PCs, you can directly run the ESP-IDF command prompt shortcut in the Start menu, created by the ESP-IDF installer.
2. Navigate to the project directory. The path you provide must be to the root folder of your project directory.
cd /path_to_your_project_directory3. Configure the project: The menu config option is used to change or reconfigure the project parameters. It is completely optional since all required properties are already configured. But if you need, you can use the following command to access the menuconfig options.
idf.py menuconfig4. Build the project: You can use the following script to build the project. When it's executed, the IDF will copy any required managed components to the project folder and build the project. If any error occurs, other than related to code, it is highly recommended to do a full clean and then build.
idf.py build5. Flash and monitor: the following command is used to flash the code to the ESp32S3-Box-3 and monitor the serial log. Make sure to connect the board to the computer before running the command. If the board is not detected, even after connecting to the computer, Press and hold the boot button and then press the reset button. Later, release the boot button and try to upload the code. Once uploaded with this method, make sure to reset the board manually once the code is uploaded.
idf.py flash monitorFor your reference, this is the file structure of our project. The Main folder contains all the source code, while the components folder contains unmanaged component libraries, and the spiffs folder contains all the image or audio files.
Wake word detection uses ESP-SR WakeNet, a low-power neural network engine that runs continuously in the background. The Audio Front-End (AFE), preprocesses audio from the microphone array. Sample rate: 16 kHz, 16-bit signed, 2 channels (stereo). Then the WakeNet Engine does the CNN-based wake word detection. The Wakenet framework continuously monitors the audio stream with low power consumption. It supports up to 5 wake words simultaneously. The wake word detection flow is as given below.
Microphone -> I2S -> AFE -> WakeNet -> Wake Detection Event
Detection Events
The following key functions are used for the wakeword detection and are called from main/app/app_sr.c.
The project supports multiple pre-trained wake words. Configure them via idf.py menuconfig.
Navigation: idf.py menuconfig -> ESP Speech Recognition -> Load Multiple Wake Words
| Wake Word | Language | Config Key |
| Hi ESP | English | |
| Hi Lexin | Chinese | |
| Alexa | English | |
| Xiao Ai Tong Xue | Chinese | |
| Ni Hao Xiao Zhi | Chinese | |
Method 1 - Using menuconfig
1.Run idf.py menuconfig
2.Navigate to: ESP Speech Recognition -> Load Multiple Wake Words
3.Enable or disable desired wake words.
4.Save and rebuild: idf.py build flash
Method 2 - Modify Code
Wake word selection happens in app_sr.c:
// In app_sr_set_language() function (line ~235)
char *wn_name = esp_srmodel_filter(models, ESP_WN_PREFIX,
(SR_LANG_EN == g_sr_data->lang ? "hiesp" : "hilexin"));To switch the English wake word to "Alexa":
char *wn_name = esp_srmodel_filter(models, ESP_WN_PREFIX,
(SR_LANG_EN == g_sr_data->lang ? "alexa" : "hilexin"));Requirements: A custom wake word model trained with ESP-SR tools, in ESP-SR compatible format, with sufficient model partition space.
1. Train a custom wake word using ESP-SR training tools (see ESP-SR documentation).
2. Place the generated model file (.bin) in spiffs/ or the model partition.
3. Enable the custom word in menuconfig: For eg, ESP Speech Recognition -> CONFIG_SR_WN_WN9_CUSTOMWORD
4 .Update code in app_sr.c:
char *wn_name = esp_srmodel_filter(models, ESP_WN_PREFIX, "customword");5. Rebuild and flash: idf.py build flash
Speech recognition uses ESP-SR MultiNet, an offline command recognition engine that supports up to 200 commands without requiring cloud connectivity. Both English and Chinese are supported in the ESP-SR engine.
Wake Word Detected -> AFE Processing -> MultiNet -> Command ID -> Handler Action
Recognition States
Key Components
// Command definition array (app_sr.c)
static const sr_cmd_t g_default_cmd_info[] = {
{SR_CMD_LIGHT_ON, SR_LANG_EN, 0, "turn on light", "TkN nN LiT", {NULL}},
{SR_CMD_LIGHT_OFF, SR_LANG_EN, 0, "turn off light", "TkN eF LiT", {NULL}},
};
⇒ Step 1 - Add Command Enum (app_sr.h)
typedef enum {
SR_CMD_LIGHT_ON,
SR_CMD_LIGHT_OFF,
SR_CMD_MY_NEW_CMD, // Add your command enum
SR_CMD_MAX,
} sr_user_cmd_t;⇒ Step 2 - Add Command Definition (app_sr.c)
static const sr_cmd_t g_default_cmd_info[] = {
{SR_CMD_LIGHT_ON, SR_LANG_EN, 0, "turn on light", "TkN nN LiT", {NULL}},
{SR_CMD_LIGHT_OFF, SR_LANG_EN, 0, "turn off light", "TkN eF LiT", {NULL}},
{SR_CMD_MY_NEW_CMD, SR_LANG_EN, 2, "my new command", "mI nU kMnd", {NULL}}, // Add
};⇒ Step 3 - Add Handler Action (app_sr_handler.c)
case SR_CMD_MY_NEW_CMD: // Add your handler
ESP_LOGI(TAG, "My new command executed!");
// Your action here
break;⇒ Step 4 - Rebuild and Flash
idf.py build flash monitor// app_sr.h - enum
SR_CMD_FAN_ON,
SR_CMD_FAN_OFF,
SR_CMD_SET_BRIGHTNESS_HIGH,
SR_CMD_SET_BRIGHTNESS_LOW,
// app_sr.c - command definitions
{SR_CMD_FAN_ON, SR_LANG_EN, 2, "turn on fan", "TkN nN fN", {NULL}},
{SR_CMD_FAN_OFF, SR_LANG_EN, 3, "turn off fan", "TkN eF fN", {NULL}},
{SR_CMD_SET_BRIGHTNESS_HIGH, SR_LANG_EN, 4, "brightness high", "brItns hI", {NULL}},
{SR_CMD_SET_BRIGHTNESS_LOW, SR_LANG_EN, 5, "brightness low", "brItns lO", {NULL}},Dynamic Command Addition (Runtime)
sr_cmd_t new_cmd = {
.cmd = SR_CMD_MY_NEW_CMD,
.lang = SR_LANG_EN,
.id = 10,
.str = "my command",
.phoneme = "mI kMnd"
};
app_sr_add_cmd(&new_cmd);
app_sr_update_cmds(); // Update MultiNet command listAPI Functions (app_sr.h)
The project uses LVGL (Light and Versatile Graphics Library) for GUI rendering and touch input.
Initialisation (main.c)
bsp_display_cfg_t cfg = {
.lvgl_port_cfg = ESP_LVGL_PORT_INIT_CONFIG(),
.buffer_size = BSP_LCD_H_RES * CONFIG_BSP_LCD_DRAW_BUF_HEIGHT,
.double_buffer = 0,
.flags = { .buff_dma = true }
};
bsp_display_start_with_config(&cfg);
bsp_board_init();#include "lvgl.h"
#include "bsp/esp-bsp.h"
bsp_display_lock(0); // Lock for thread safety
lv_obj_t *scr = lv_scr_act(); // Get current screen
// Create a button
lv_obj_t *btn = lv_btn_create(scr);
lv_obj_set_size(btn, 100, 50);
lv_obj_align(btn, LV_ALIGN_CENTER, 0, 0);
// Add label
lv_obj_t *label = lv_label_create(btn);
lv_label_set_text(label, "Click Me");
// Add click callback
lv_obj_add_event_cb(btn, on_button_click, LV_EVENT_CLICKED, NULL);
bsp_display_unlock();static void on_touch_event(lv_event_t *e)
{
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t *obj = lv_event_get_target(e);
switch (code) {
case LV_EVENT_PRESSED:
lv_obj_set_style_bg_color(obj, lv_color_hex(0x0000FF), 0);
break;
case LV_EVENT_RELEASED:
lv_obj_set_style_bg_color(obj, lv_color_hex(0x00FF00), 0);
break;
case LV_EVENT_CLICKED:
light_ctrl_toggle(); // Perform action
break;
default: break;
}
}Supported Event Types
The project converts BMP from images stored in an array using the image_to_c tool by bitbank2, to LVGL-compatible RGB565 format at runtime using bmp_to_lv_img() in light_ui.c. If you wan you can also use the LVGL image converter tool to convert the images to c array. One other option is to store the image files in the file system and load them from there.
lv_img_set_src(img_obj, "/spiffs/image.bin");Here is an example code snippet showing how to create a new screen for the GUI. The LV object creation macro is used to create or define each screen.
// Screen 1: Main
lv_obj_t *main_screen = lv_obj_create(NULL);
// ... add widgets ...
// Screen 2: Settings
lv_obj_t *settings_screen = lv_obj_create(NULL);
// ... add widgets ...
// Navigate
void goto_settings(lv_event_t *e) { lv_scr_load(settings_screen); }
void goto_main(lv_event_t *e) { lv_scr_load(main_screen); }Warning: Each RGB565 pixel = 2 bytes. A 320×240 screen buffer = ~150 KB. Double buffering doubles that. Consider using PSRAM for large buffers.
For more details on how to use the LVGL library, please check out the official LVGL documentation.
Audio output uses the I2S interface with an ES8311 codec chip for digital-to-analog conversion. The I2S Driver handles audio data transfer. Sample rate: 16 kHz default for SR feedback, 16-bit, stereo (2 channels). The ES8311 codec with I2S input provides analog output to the speaker and volume and mute control.
Audio Playback Flow
WAV File -> Memory Buffer -> I2S Write -> Codec -> SpeakerKey Functions (app_sr_handler.c)
typedef enum {
AUDIO_WAKE, // Wake word detected tone
AUDIO_OK, // Command recognised tone
AUDIO_END, // Timeout / end tone
AUDIO_MAX,
} audio_segment_t;
// Load WAV from SPIFFS -> PSRAM
static esp_err_t load_wav_to_mem(audio_segment_t seg, const char *path)
{
FILE *fp = fopen(path, "rb");
if (!fp) return ESP_ERR_NOT_FOUND;
fseek(fp, 0, SEEK_END);
long sz = ftell(fp);
fseek(fp, 0, SEEK_SET);
s_audio[seg].buf = heap_caps_malloc(sz, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
s_audio[seg].len = (size_t)sz;
fread(s_audio[seg].buf, 1, sz, fp);
fclose(fp);
return ESP_OK;
}⇒ Step 1 - Add Audio Segment Enum
typedef enum {
AUDIO_WAKE,
AUDIO_OK,
AUDIO_END,
AUDIO_CUSTOM_1, // Add your segment
AUDIO_CUSTOM_2,
AUDIO_MAX,
} audio_segment_t;⇒ Step 2 - Add WAV File to SPIFFS
Place your WAV file in the spiffs/ directory. WAV requirements: uncompressed PCM, 16 kHz recommended, 16-bit, mono or stereo.
spiffs/
├── echo_en_wake.wav
├── echo_en_ok.wav
├── echo_en_end.wav
├── custom_sound_1.wav Add here
└── custom_sound_2.wav⇒ Step 3 - Load in Initialisation
ESP_RETURN_ON_ERROR(
load_wav_to_mem(AUDIO_CUSTOM_1, "/spiffs/custom_sound_1.wav"),
TAG, "load custom1 wav failed");⇒ Step 4 - Play When Needed
sr_echo_play(AUDIO_CUSTOM_1);⇒ Step 5 - Rebuild
idf.py build flashThe SPIFFS partition is automatically rebuilt with files from the spiffs/ directory.
| Parameter | Value |
| Sample Rates | 8, 16, 22.05, 44.1, 48 kHz |
| Bit Depth | 16-bit (recommended) |
| Channels | Mono or Stereo |
| Format | Uncompressed PCM WAV |
# Convert to 16 kHz, 16-bit, mono WAV
ffmpeg -i input.mp3 -ar 16000 -acodec pcm_s16le -ac 1 output.wav
# Convert to 16 kHz, 16-bit, stereo WAV
ffmpeg -i input.mp3 -ar 16000 -acodec pcm_s16le -ac 2 output.wavThe following BSP functions (bsp_board.h) control the audio codec:
| Function | Description |
| Set codec sample rate, bit depth, and channel mode |
| Set volume level (0-100) |
| Mute or unmute the audio codec |
| Write audio data buffer to I2S output |
| Stop the codec device |
| Resume the codec device |
Recommendations
Streaming Long Audio
void play_long_audio_stream(const char *wav_path)
{
FILE *fp = fopen(wav_path, "rb");
if (!fp) return;
fseek(fp, 44, SEEK_SET); // Skip WAV header
uint8_t chunk[4096];
size_t bytes_read;
while ((bytes_read = fread(chunk, 1, sizeof(chunk), fp)) > 0) {
size_t bytes_written = 0;
bsp_i2s_write((char *)chunk, bytes_read, &bytes_written, portMAX_DELAY);
}
fclose(fp);
}
1. Open the file: main/app/app_led.c
2. Find this line (around line 15):
#define SINGLE_LED_GPIO GPIO_NUM_403. Change it to a different pin (e.g. GPIO 38):
#define SINGLE_LED_GPIO GPIO_NUM_384. Save the file.
5. Rebuild and flash:
idf.py build flash monitor6. Test: Connect your LED to GPIO 38 instead of GPIO 40.
Once the hardware is connected and the software is set up, follow these steps to compile and upload the code.
⇒ Step 1 - Navigate to the Project Directory
cd /path/to/esp32-box3-voice-led-project⇒ Step 2 - Activate ESP-IDF Environment
. $HOME/esp/esp-idf/export.sh⇒ Step 3 - Configure (Optional)
idf.py menuconfig⇒ Step 4 - Build
idf.py buildThis compiles all source files and creates the firmware binary. The first build may take several minutes as dependencies are downloaded.
⇒ Step 5 - Flash and Monitor
idf.py flash monitor*Tip: Press Ctrl+] to exit the serial monitor.
After successfully flashing the firmware, the ESP32-S3-BOX-3 boots and displays the light control screen. Now we can control the LED with two different methods.
The first method is to use the voice commands. To use it:
1. Say the wake word: "Hi ESP" (speak clearly, about 1 metre from the device).
2. Wait for audio feedback - you'll hear a confirmation sound.
3. Speak the command: "Turn on light" or "Turn off light".
4. Observe: the LED changes state, the screen updates, and audio feedback plays.
5. Once the wake word is detected, you can continuously give commands without using the wake word. If you haven't provided any commands for a certain time(a few seconds), the ESP-SR engine will time out. To use it again, all you have to do is say the wake word again to trigger the wake word detection.
The second method is to use the touch screen. For that:
1. Touch the on-screen toggle button.
2. Observe: the LED toggles and the button image changes.
Here is the final result:
Find the project’s codebase and documentation here. Explore, fork, and contribute on GitHub.
Years ago, if you had opened the door to the hostel room of Venkat Rangan, you would have been greeted by music. One could say tinkering was something he always latched on to, because the door’s latch triggered the music from a system he built himself. "He's always been a tinkerer," recalled Vishal Srivastava, who studied alongside Venkat and now leads Marketing and Business Development at the company.
DTDS’s booth at electronica India 2025 highlighted a cost-effective approach to vehicle lighting systems. The company stated that its Light Control Module offers a competitive advantage, being 25% lighter on the pocket when compared to other market options. Chand Hanif, Senior FAE at the company, walked us through a live demo of the module at the booth. He explained, "We have put that complete setup as a PCB on outside also," giving visitors "more clarity on LED brightness and all."
With 18 years of experience, Bangalore and Chennai-based Sahara Group of Industries has been involved in numerous sectors, including healthcare, aviation, and automobile. Now the company has stepped into thin-film transistor (TFT) LCD display production, which was put on display at electronica India 2025.
At the Laser World of Photonics India 2025, Thorlabs, a photonics company, showcased optics, lasers, modulators, and detectors. Instruments like spectrometers and power meters were scattered across the booth. Stephan Hallwig, Head of Business Development and Marketing Communication EMEA, explained that the industry’s applications extend to semiconductor, medical, and telecommunication.
LiteWing is an open-source ESP32-S3 based drone that offers a flexible platform for experimentation and learning. By default, LiteWing operates using the modified Crazyflie firmware. LiteWing can also be configured using Betaflight, a powerful and widely adopted flight control software used in FPV and racing drones.
In this ESP32 Betaflight tutorial, we will go through the process of configuring the LiteWing drone Betaflight and turning it into a fully tunable drone. LiteWing drone Betaflight integration unlocks a rich set of features such as PID tuning, motor configuration, receiver setup, flight modes, and real-time diagnostics, making it an excellent choice for users who want deeper control over their drone’s behavior.
This ESP32 Betaflight configurator guide is for beginners as well as experienced developers who want to explore how open-source hardware like LiteWing can be integrated with standard flight software. By the end of this ESP32 Betaflight tutorial, you will have a properly configured LiteWing drone and a clear understanding of how ESP32 Betaflight firmware can be used to unlock its full potential. If you want to learn more about the LiteWing drone, its hardware, and other features, make sure to check out the official documentation and resources.
To follow this tutorial, you will need a LiteWing drone, an ExpressLRS (ELRS) receiver, and a compatible ELRS transmitter to control the drone. The receiver and transmitter should already be bound before connecting to the drone. A computer with Betaflight Configurator installed is also required for configuration and tuning. This ESP32 Betaflight configurator setup requires proper hardware connections.
Hardware Requirements:
» LiteWing ESP32-S3 drone with all components assembled
» ExpressLRS (ELRS) receiver for low-latency radio communication
» Compatible ELRS transmitter (pre-bound to receiver)
» USB data cable for computer connection
» LiPo battery suitable for LiteWing drone
Software Requirements:
» Betaflight Configurator v10.10.0 is installed on your computer
» Web browser (Chrome or Edge) for ESP flashing tool
» ESP32 Betaflight firmware binary file for ESP32-S3
Before configuring the LiteWing ESP32 drone Betaflight firmware must be programmed manually using the ESP flashing tool. LiteWing uses an ESP32-S3 based ESP-FC, so the correct binary file must be flashed before proceeding.
Downloading the ESP32 Betaflight Firmware
First, open the ESP-FC open-source GitHub repository using the link below. This firmware is developed and maintained by rtlopez, and his work is highly appreciated for contributing to the open-source community.
GitHub Repository: https://github.com/rtlopez/esp-fc
Once the repository page opens, navigate to the Releases section. The releases page contains precompiled firmware binaries for different ESP based flight controllers. From there, download the firmware .zip file specifically built for the ESP32-S3 microcontroller since LiteWing is based on the ESP32-S3 platform.

To flash the firmware onto the LiteWing drone, open the Espressif ESP Tool (Web-based flasher) in a supported browser. Connect the LiteWing drone to your computer using a USB data cable, ensuring the drone is powered on and detected by your system. On the ESP Tool web page, click Select Port, choose the COM port corresponding to the LiteWing drone from the pop-up list and confirm the selection. Then click Connect to establish communication between the tool and the drone. Once connected successfully, the tool will be ready for firmware upload.

Upload the downloaded firmware file (firmware_0x00.bin) and set the flash address to 0x0000, verifying that both the correct file and address are selected. Click the Program button to begin flashing and wait until the process completes successfully, making sure not to disconnect the drone during programming. Once finished, the firmware will be successfully uploaded to the LiteWing drone, and you can now proceed to configure settings and tune the drone using Betaflight. Once the ESP32 Betaflight firmware upload completes successfully, your LiteWing drone is ready for configuration in Betaflight Configurator.
To configure and tune the LiteWing ESP32 Betaflight drone, you need the Betaflight Configurator installed on your computer. This software allows you to connect to the drone and adjust flight settings.
Downloading and Installing Betaflight Configurator
Visit the official GitHub release page for Betaflight Configurator Releases and download version 10.10.0 is recommended for easy setup. Choose the version compatible with your operating system: Windows, macOS, or Linux.

After installing and opening the ESP32 Betaflight configurator.
Before connecting the LiteWing ESP32 drone to Betaflight, you should adjust some settings in the Options tab as shown in the reference image. Make sure to enable “Show All Serial Devices” this ensures that the software can detect the drone even if it doesn’t appear by default.
These changes help the Betaflight Configurator communicate properly with the drone.

Once the settings are updated, manually select the COM port in the software and click the Connect button to establish communication between the software and the drone.
When you first connect the LiteWing ESP32 drone to Betaflight, you may notice that the real-time updates and the 3D model in the setup tab do not respond correctly when the drone is moved. This happens because the default pin assignments in Betaflight do not match the LiteWing hardware. To fix this, you can update the pin assignments using the CLI tab in Betaflight Configurator. By entering the correct commands, you can map the pins according to LiteWing’s configuration, ensuring that all motors and sensors respond accurately during real-time updates.

ESP32 Betaflight CLI Pin Configuration Commands
Navigate to the CLI tab in Betaflight Configurator and enter the following commands. These commands configure all necessary GPIO pins for the LiteWing ESP32 drone:
set pin_input_rx -1
set pin_output_0 6
set pin_output_1 5
set pin_output_2 3
set pin_output_3 4
set pin_buzzer 8
set pin_serial_0_tx 43
set pin_serial_0_rx 44
set pin_serial_1_tx 17
set pin_serial_1_rx 18
set pin_serial_2_tx -1
set pin_serial_2_rx -1
set pin_i2c_scl 10
set pin_i2c_sda 11
set pin_input_adc_0 2
set pin_input_adc_1 -1
set pin_spi_0_sck 12
set pin_spi_0_mosi 35
set pin_spi_0_miso 37
set pin_spi_cs_0 -1
set pin_spi_cs_1 7
set pin_spi_cs_2 -1
set pin_buzzer_invert -1After pasting the commands, simply press Enter, then type save and press Enter again to save the changes. And then type reboot and press Enter again to apply the changes. This will update the pin configuration automatically, making the setup quick and easy without manually changing each assignment.
After the CLI commands are executed, simply disconnect and reconnect the LiteWing drone. This will allow the ESP32 drone to connect with Betaflight Configurator and to display real-time updates, reflecting the drone’s movements accurately.
The following pin configuration changes are implemented to match the LiteWing hardware setup.
| Pin Type | GPIO Assignment | Function |
|---|---|---|
| Motor Output 1 | GPIO 6 | Front-right motor PWM control |
| Motor Output 2 | GPIO 5 | Rear-right motor PWM control |
| Motor Output 3 | GPIO 3 | Rear-left motor PWM control |
| Motor Output 4 | GPIO 4 | Front-left motor PWM control |
| UART1 TX/RX | GPIO 17/18 | ExpressLRS receiver communication |
| I2C SCL/SDA | GPIO 10/11 | IMU sensor communication (MPU6050) |
| ADC Input | GPIO 2 | Battery voltage monitoring |
After configuring the GPIO pins in your ESP32 Betaflight configurator, you may notice that the 3D model moves when the LiteWing drone is tilted or rotated, but the movements don't exactly match the actual drone orientation. The 3D model in Betaflight moves when the drone is tilted or rotated, but you may notice that its movements do not exactly match the actual drone. This happens because the IMU (Inertial Measurement Unit) on the LiteWing is placed in a different orientation. To correct this, go to the Configuration tab in Betaflight, scroll to Board and Sensor Alignment, and change the First Gyro setting from Default to CW 270°. This aligns the 3D model accurately with the real movements of the drone.

To monitor the battery voltage in the software, make the necessary changes as shown in the reference image below, select Onboard ADC as the voltage meter source and then set the minimum and maximum cell voltage values, and adjust the warning cell voltage according to your requirements.

In the voltage meter settings, set the scale to 10, the divider value to 1, and the multiplier value to 2, as these values are calculated based on the voltage divider used in the LiteWing.
| Parameter | Value | Purpose |
|---|---|---|
| Voltage Scale | 10 | ADC reading multiplier for voltage calculation |
| Voltage Divider | 1 | Hardware divider ratio (pre-calculated in scale) |
| Voltage Multiplier | 2 | Correction factor for LiteWing's voltage divider circuit |
After entering these values, click Save and Reboot to apply the battery monitoring configuration to your ESP32 Betaflight firmware.
LiteWing ESP32 drone uses brushed DC motors, so the motor protocol must be configured accordingly in Betaflight. In the Configuration tab of Betaflight Configurator, set the Motor Protocol to Brushed. Then set the Motor PWM Frequency to 8000 Hz. Keep the remaining motor and ESC-related parameters set as shown in the reference image, as these values are configured for the LiteWing hardware.

After making these changes, click Save and Reboot to apply the settings. Once completed, the motors will respond correctly and smoothly during operation.
In this setup, we are going to control the LiteWing drone using a radio transmitter and receiver. For this setup, we are using an ExpressLRS (ELRS) receiver due to its low-latency radio communication. ELRS is widely used due to its long range, fast response, and open-source support.

Connect the ELRS receiver to the LiteWing according to the UART wiring. Power the receiver using 3.3V and GND. Connect the receiver’s TX pin to the drone’s RX (GPIO18), and the receiver’s RX pin to the drone’s TX (GPIO17). Ensure all power, ground, and signal connections are properly made before proceeding.
Ideal for use within LiteWing Ctrl ESP32 Drone, ExpressLRS Receivers offer the following advantages:
∗ Ultra-low latency - Instantaneous feedback to commands and immediate changes to airframe attitude, with receipt of command inputs occurring at ultra-low latencies (as little as 5ms).
∗ Long distances - An excellent range of operation — several kilometres, assuming optimal use of antennas.
∗ Open Source Protocol - Firmware is open source; support from a community of users.
∗ CRSF Protocol - Fully compliant with the Betaflight CRSF Receiver Mode.
| ELRS Receiver Pin | LiteWing GPIO Pin | Connection Purpose |
|---|---|---|
| VCC (3.3V) | 3.3V Power | Receiver power supply |
| GND | GND | Common ground connection |
| TX | GPIO 18 (RX) | Receiver transmits data to drone |
| RX | GPIO 17 (TX) | Receiver receives data from drone |
Next, open Betaflight Configurator and go to the Ports tab. Enable Serial RX on the UART 2, where the ELRS receiver is connected, and save the settings.

Then go to the Receiver tab, set the Receiver Mode to Serial-based receiver, and select CRSF as the protocol. Save and reboot the drone. After this, power on the transmitter if everything is configured correctly, and you will see real-time channel movements in the Receiver tab when you move the transmitter sticks.
Flight modes define how the LiteWing drone behaves during flight. In this setup, we will configure ARM, ANGLE, and BLACKBOX modes using Betaflight.

Open the Modes tab in Betaflight Configurator. Assign a switch on your transmitter to the ARM mode to enable and disable the motors safely. Next, assign another switch or position to ANGLE mode, which provides self-levelling and is ideal for stable and beginner-friendly flight. Enable BLACKBOX mode to record flight data for tuning and troubleshooting.

After assigning the switches, make sure the activation ranges are set correctly and click Save. These modes will allow you to arm the drone and switch between stable and aggressive flight behavior as needed.
The default PID values in ESP32 Betaflight firmware are not suitable for the LiteWing drone and can result in unstable flight performance. Since LiteWing is a lightweight drone using brushed DC motors, custom PID values are required to achieve stable and smooth flight.
In the PID Tuning tab of Betaflight Configurator, replace the default values with the recommended LiteWing PID values provided in the reference configuration. These values have been tested and optimized specifically for LiteWing and help eliminate oscillations while improving control and responsiveness.

After entering the PID values, click Save and perform a short test flight. If required, minor adjustments can be made later, but the provided values should give a stable and reliable flying experience right away.
The LiteWing drone requires custom PID tuning because:
∗ Low weight construction: The reduced weight necessitates changes to PID (proportional, integral and derivative) settings for the model.
∗ Brushed motor technology (coreless): Torque curves with different speed exponentials compared to the brushless motor.
∗ Small propellers: Lower inertia creates a need for different stabilization procedures than those required by larger props.
∗ Compact design: The shorter arm lengths between motors affect the rotational characteristics of the various components.
Blackbox is a logging feature in Betaflight that records flight data such as gyro values, motor outputs, PID behavior, and receiver inputs. This data is useful for analyzing flight performance and troubleshooting issues like vibrations, oscillations, or unstable behavior.

After enabling Blackbox in Betaflight, fly the LiteWing drone to record flight data. Once the flight is complete, connect the drone to Betaflight Configurator, go to the Blackbox tab, and download the log files. Open these logs in the Betaflight Blackbox Explorer to analyze gyro data, PID behavior, and vibrations, which help in improving stability and tuning performance.
After completing all the steps in this guide, your LiteWing drone configured with Betaflight is fully ready for flight. You can now safely test it, fine-tune settings if needed, and explore more advanced Betaflight features as you gain experience.
⇥ 1. How to calibrate the IMU?
To calibrate the IMU (Inertial Measurement Unit) in Betaflight, place the LiteWing drone on a flat and stable surface. Open Betaflight Configurator and connect the drone. Go to the Setup tab and click the Calibrate Accelerometer button. Keep the drone completely still during the calibration process. Once finished, the IMU will be calibrated, ensuring accurate orientation and stable flight behavior.
⇥ 2. Why is my LiteWing not connecting to Betaflight Configurator?
After flashing or making configuration changes, disconnect and reconnect the drone, and ensure that no other applications (such as Arduino IDE, serial monitor, or ESP tools) are using the same COM port.
⇥ 3. Do I need to calibrate the accelerometer every time?
No, you do not need to calibrate the accelerometer every time you power on the LiteWing drone. Accelerometer calibration is usually required only once during the initial setup or after making major changes.
⇥ 4. How do I enable FPV (Acro) mode on the LiteWing drone?
Assign a switch for ARM and do not enable ANGLE mode.
When the angle mode is off, the LiteWing drone flies in FPV (Acro) mode.
Beginner-friendly LiteWing drone projects that explore different ways to program, control, and experiment with ESP32 based drones, focusing on practical learning and real-world applications.
DIY Gesture Control Drone using Python with LiteWing and ESP32
Build a gesture-controlled drone using ESP32 and LiteWing. This project explains how to track hand movements with MPU6050 and control the drone via Bluetooth and Python using UDP communication.
How to Use Height Hold Mode in LiteWing ESP32 Drone?
Learn how to add height hold to the LiteWing ESP32 drone using the VL53L1X ToF sensor. This tutorial explains sensor setup, PID control, and app integration for smooth indoor flights.
How to Program the LiteWing Drone using Python with Crazyflie Cflib Python SDK
Learn how to control the LiteWing drone using the Crazyflie cflib Python SDK. This guide covers installation, basic commands, and writing Python code to spin the drone's motors via Wi-Fi.
The Joule Thief Circuit is a simple and clever electronic design that can power an LED using a nearly dead battery. The project demonstrates how basic components like a transistor, a toroidal coil, and a resistor can work together to boost a low input voltage to a usable output voltage. By building this circuit, we can explore how a nearly dead battery's energy can be used efficiently without wasting the energy in it. A Joule Thief circuit is a simple voltage booster that uses a toroidal coil, an NPN transistor, and a resistor to extract power from nearly dead batteries. It is a great project for understanding how inductive switching, voltage boosting, and energy-efficient design can be in a practical way.
For a deeper understanding of boost converter concepts, including switching operation, design principles, and efficiency considerations, refer to Switching Boost Regulator: Design Basics and Efficiency. This resource provides clear explanations of how switching regulators work and how voltage boosting is achieved efficiently in practical circuits.
A Joule Thief circuit is a small, energy-efficient boost converter designed to extract usable power from very low-voltage sources such as “dead” or nearly drained batteries. It uses a transistor, a resistor, and a toroidal coil with two windings to step up the low input voltage and generate high-voltage pulses. These pulses are strong enough to power devices like LEDs, even when the battery voltage is too low to operate them directly.
The joule thief circuit working mechanism relies on rapid switching, turning the transistor ON and OFF many times per second, which stores and releases energy in the coil. This simple circuit is widely used to demonstrate energy harvesting, inductive switching, and efficient power utilisation, making it popular in hobby electronics, education, and low-power lighting applications. This joule thief circuit with toroid operates through self-sustained oscillation, rapidly switching the transistor between conduction and cutoff states thousands of times per second.
The Joule Thief circuit has a minimal set of electronic components that are easy to obtain and assemble. Below the detailed table explaining each component and its purpose in the circuit.
| Components | Quantity | Description | Function in Circuit |
| NPN Transistor (eg.2N2222,2N3904) | 1 | A small-signal transistor | Acts as a switch, controlling current flow through the coil and enabling voltage boosting |
| 1 kΩ Resistor | 1 | Limits current to the transistor base | Prevents excessive base current and ensures stable oscillation |
| Toroidal Coil | 1 | Small ferrite core with two windings | Stores and releases magnetic energy; provides feedback to the transistor for oscillation |
| LED | 1 | Light Emitting Diode | Converts boosted voltage pulses into visible light |
| Battery (AA or AAA, 1.5V) | 1 | Low-voltage power source | Provides input voltage, even if weak or partially discharged |
| Breadboard | 1 | prototyping board | Allows easy assembly and testing of the circuit without soldering |
| Connecting Wires | As needed | copper or jumper wires | Connects components to form the complete circuit |
The image below displays all joule thief circuit components required for construction. It includes a toroidal inductor for energy storage, an NPN transistor for high-speed switching, a 1 kΩ resistor to control base current, an LED as the load, an AA battery as the low-voltage source, and a breadboard for easy prototyping and testing of the circuit. If you want to learn more about what an NPN transistor is and how it works, check out the article “NPN Transistors.”
The joule thief circuit diagram shows how the transistor, resistor, LED, and the two windings on the toroid are connected. It clearly illustrates how the Joule Thief boosts a low battery voltage to power the LED.

This Joule thief schematic clearly illustrates a simple Joule Thief circuit, showing how a low-voltage battery can be boosted to light an LED. In this setup, the core component is a Joule Thief circuit with a toroid, where the toroidal core carries two windings: the primary winding (1 & 2) for current flow and the feedback winding(3 & 4) for rapid switching. This layout helps you understand how the coil windings and the transistor work together to step up the voltage efficiently from even a nearly drained battery. This joule thief circuit diagram demonstrates the critical relationship between components.
This wiring diagram shows the practical implementation of the joule thief circuit with toroid, with clearly distinguished coil connections. The primary winding, which carries the main current from the battery, is shown using the red wire, while the feedback (switching) winding, which provides base drive to the transistor, is indicated using the yellow wire. The correct interaction between these two windings enables rapid transistor switching and voltage boosting to power the LED from a low-voltage battery.
Understanding the joule thief circuit working requires examining the electromagnetic interactions between the toroidal coil windings and the transistor switching behaviour. The Joule Thief uses a Toroidal coil with two windings :
1. Primary Coil - carries the main current from the battery
2. Feedback (switching) Coil - controls the transistor switching
Both coils work together to create a self-oscillating boost converter
When the battery is connected, a small current starts to flow through the primary coil and then to the transistor’s base through the resistor. This turns the transistor slightly ON, allowing current to flow through it. The magnetic field starts building in the primary coil due to the flow of current around the toroid.
As the magnetic field builds around the primary coil, it induces a voltage in the feedback(switching) coil. This process occurs due to the mutual inductance. The induced voltage is passed into the transistor, increasing the base current.
As a result, the transistor turns more ON, allowing more current to flow through the primary coil.
This is called the positive feedback, and it forces the transistor to full conduction.
As current continues to flow through the primary winding, the magnetic field in the toroidal core keeps increasing until the ferrite core can no longer store additional magnetic flux. This condition is known as Magnetic Saturation.
Once the core reaches saturation, the induced voltage in the feedback coil starts to drop sharply, causing the base drive of the transistor to disappear. As a result, the transistor switches OFF abruptly.
When the transistor switches OFF, the current flowing through the primary coil cuts off suddenly.
But the inductors resist the sudden change in the current flow, so the magnetic field collapses rapidly, which is stored in the primary coil.
This collapse creates a high voltage spike across the primary coil. This spike is much higher than the original battery voltage and is enough to light up an LED.
Once the transistor switches OFF, the current flow through the primary winding stops and the magnetic field in the toroid collapses to ZERO. After this, a small amount of current starts again to flow across the coil and into the transistor’s base through the resistor. This initiates the next switching cycle.
This repeated action causes the primary and feedback windings to continuously force the transistor to turn ON and OFF at high frequency. The frequency is between the hundreds and thousands of times per second, which produces rapid voltage pulses that keep the LED illuminated.
Here is the Simulation of the simple Joule thief circuit. It demonstrates how a low-voltage battery is able to power an LED through the rapid switching and voltage boosting. At the beginning, the current starts to flow through the primary winding, causing the transistor to switch ON. The feedback wing then reinforces the base drive, which results in rapid oscillation. The following simulation demonstrates the joule thief circuit working principles in real-time.

As seen in the simulation of the Joule Thief schematic, once the magnetic core reaches saturation, the transistor switches OFF, and the stored magnetic energy collapses, which results in a high-voltage spike across the primary winding. This voltage spike is sufficient to forward-bias the LED, allowing it to glow even though the battery voltage is very low.
The continuous ON & OFF switching cycle is clearly visible in the simulation, and it proves the self-oscillating nature of the Joule Thief Circuit and its ability to efficiently boost voltage from weak power sources.
This practical demonstration showcases a real-world joule thief circuit working behaviour. The LED does not glow when connected directly to the low-voltage battery, but it lights up when connected through the Joule Thief circuit. This happens due to rapid switching and voltage boosting using the toroidal coil. The demonstration confirms the circuit’s ability to utilise energy from weak batteries.

In the above video, the LED is directly connected to the battery, but it does not glow. This happens because the battery voltage is too low to overcome the LED’s forward voltage requirement. Although the battery still contains some energy, it is insufficient to drive current through the LED directly. This observation highlights the limitation of low-voltage sources and sets the foundation for using the Joule Thief circuit, which boosts the voltage and enables the LED to glow even from a weak battery.

When the LED is connected through the Joule Thief circuit with toroid, it starts glowing even with the same low-voltage battery. This is because the circuit boosts the battery’s voltage by rapidly switching the transistor and storing energy in the toroidal coil. The collapsing magnetic field generates high voltage pulses that are sufficient to forward bias the LED. This result clearly demonstrates the effectiveness of the Joule Thief circuit in extracting and utilising the remaining energy from weak batteries.
∗ Supercharged Joule Thief circuit: The supercharged Joule Thief has a higher efficiency (greater than 80%) than other types of Joule Thief circuits that range from 40-60% efficiency.
∗ Buck-Boost Converters: Used for more powerful applications with a negative voltage output from an input voltage.
∗ Voltage multiplier: Converts lower-voltage AC electricity into DC electricity of a higher voltage.
∗ Split-pi Topology: DC-DC converters that have bidirectional capabilities due to the use of MOSFETs and are suited for regenerative braking systems.
| Advantages | Disadvantages |
| Can operate from very low input voltages | Can operate from very low input voltages |
| Utilizes energy from weak or “dead” batteries | Output voltage is unregulated |
| Simple circuit with very few components | Not suitable for high-current loads |
| Low cost and easy to build | Efficiency drops at higher loads |
| Self-oscillating (no external controller needed) | Generates electrical noise due to switching |
| Ideal for learning voltage boosting concepts | Cannot be used for battery charging |
| Compact and portable design | Performance depends on coil winding quality |
⇥ 1. What is the minimum battery voltage needed?
The circuit can often run from as low as 0.8V, depending on components.
⇥ 2. Why is it called a “Joule Thief”?
Because it “steals” the remaining energy (joules) from weak or “dead” batteries and makes them usable again.
⇥ 3. Why is a toroidal core used?
The toroid helps create strong magnetic coupling between the two windings, making the switching process efficient.
⇥ 4. Can I use any NPN transistor?
Most general-purpose NPN transistors (like 2N3904, BC547, or 2N2222) will work.
⇥ 5. How does the circuit boost voltage?
It uses a transistor and a two-winding coil to store energy in a magnetic field and release it as high-voltage pulses when the transistor switches OFF.
⇥ 6. Why does the circuit oscillate automatically?
Because the feedback winding sends a signal that rapidly turns the transistor ON and OFF, creating a self-sustaining oscillation cycle.
⇥ 7. Can the Joule Thief charge batteries?
Not directly. It boosts voltage but does not regulate current, so it's not suitable for battery charging without modifications.
⇥ 8. What is the typical operating frequency range of a Joule Thief circuit?
Joule Thief circuits normally operate at oscillation frequencies between 50 and 500 kHz, which are mainly influenced by various factors such as the type of core used for the toroid, the number of turns in the winding, the properties of the transistor, and the load applied.
This tutorial was created by the CircuitDigest engineering team. Our experts focus on creating practical, hands-on tutorials to help makers and engineers learn Raspberry Pi projects, Arduino projects, Electronic Circuit projects and more.
I hope you liked this article and learned something new from building the Joule Thief circuit. If you have any doubts, you can ask in the comments below or use our CircuitDigest forum for a detailed discussion.
A simple collection of beginner-friendly electronics circuits and concepts, covering LED control, 555 timer applications, boost converters, and basic transistor operation.
Single Cell Boost Converter Circuit using Coin Cell – 5V Output
In this project, we build a low-cost 5V booster circuit that provides a constant regulated output voltage of 5V from a CR2032 coin cell.
A Simple DC-DC Boost Converter using 555 Timer IC
In this project, we build a simple boost converter circuit using a 555 timer IC. A boost converter is a non-isolated type of switch-mode power supply that is used to step up the voltage.
Simple Flashing LED using 555 Timer IC
This tutorial will show you how to make an LED glow and fade on a certain interval. So here is the step by step guide to make this flashing LED circuit.
This tutorial shows how to design a high-power LED driver circuit using the LM317 IC. It covers current limiting basics, resistor calculations, power ratings, and practical breadboard testing for reliable LED operation.
Murata’s booth at electronica India 2025 showcased under the theme “Beyond Discrete - Sensing the Future.” With their Application Engineering Specialist, Kousik Barathwaj, we discussed the company’s MMWave radar solution that’s designed to enhance automotive safety.
Your email is safe with us, we don’t spam.
Be a part of our ever growing community.