The Reality of ESP32 ADCs on Acebott Boards
When building robotics projects or sensor networks using Acebott STEM kits and development boards, reading analog signals is a fundamental requirement. Whether you are measuring battery voltage, reading a potentiometer, or interfacing with analog distance sensors, understanding how to properly configure analog for Acebott ESP32 boards is critical. Acebott boards typically utilize the ESP32-WROOM-32E or 32D modules, which pack immense processing power and WiFi/Bluetooth capabilities. However, the ESP32's internal Analog-to-Digital Converter (ADC) is notoriously quirky compared to the straightforward ADCs found on standard Arduino Uno (ATmega328P) boards.
The ESP32 features a 12-bit Successive Approximation Register (SAR) ADC, meaning it outputs raw values from 0 to 4095. Unlike the 10-bit ADC on older AVRs (0-1023), the higher resolution is welcome, but it comes with a catch: severe non-linearity at the voltage extremes and hardware conflicts with the WiFi radio. In this comprehensive guide, we will bypass the common pitfalls and establish a robust framework for reading accurate analog data on your Acebott ESP32.
Mapping the Analog Pins on Your Acebott ESP32
The ESP32 silicon contains two separate ADC units: ADC1 and ADC2. When wiring sensors to your Acebott breakout board, choosing the correct ADC unit is the difference between a successful project and hours of frustrating debugging. Below is the mapping of usable analog pins typically exposed on Acebott ESP32 dev boards.
| ADC Unit | GPIO Pins | Input Only? | WiFi Safe? |
|---|---|---|---|
| ADC1 | GPIO 32, 33, 34, 35, 36 (VP), 39 (VN) | Yes (34, 35, 36, 39) | Yes |
| ADC2 | GPIO 0, 2, 4, 12, 13, 14, 15, 25, 26, 27 | No (Can be used as DAC/Output) | No |
The WiFi and ADC2 Hardware Conflict
This is the most critical piece of information for any IoT maker: ADC2 cannot be used while WiFi is active. The ESP32's WiFi stack requires ADC2 internally for RF calibration and signal monitoring. If your Acebott robot needs to transmit sensor telemetry over WiFi, you must exclusively use ADC1 pins (GPIO 32 through 39). Attempting to call analogRead() on an ADC2 pin while WiFi is connected will silently fail or return erratic garbage data.
Step-by-Step: Configuring Attenuation and Resolution
The ESP32 ADC natively operates around 1.1V. To read higher voltages (up to 3.3V), the microcontroller features an internal programmable attenuator. If you do not set the attenuation correctly, any voltage above 1.1V will saturate the ADC, returning a maximum raw value of 4095 regardless of the actual input.
| Attenuation Setting | Readable Voltage Range | Use Case |
|---|---|---|
ADC_0db |
100mV - 950mV | Low voltage precision sensors |
ADC_2_5db |
100mV - 1250mV | Standard op-amp outputs |
ADC_6db |
150mV - 1750mV | Intermediate analog signals |
ADC_11db |
150mV - 3100mV | Standard 3.3V logic & battery monitoring |
For 95% of Acebott robotics applications, you will want to use ADC_11db to capture the full 0V to 3.3V range. In the Arduino IDE, you configure this globally in your setup() function:
void setup() {
analogSetAttenuation(ADC_11db); // Sets 11dB attenuation for all ADC pins
analogReadResolution(12); // Ensures 12-bit resolution (0-4095)
}
Overcoming Non-Linearity: The Modern Calibration Approach
Historically, makers struggled with the ESP32's ADC non-linearity. The raw ADC curve flattens out near 0V and 3.1V, meaning a raw reading of 4000 might correspond to 3.1V, 3.2V, or 3.3V depending on the specific silicon die. Espressif solves this by burning a unique calibration curve into the eFuse of every ESP32 chip during manufacturing.
According to the Espressif ADC Calibration Documentation, leveraging this eFuse data is mandatory for precision applications. Fortunately, if you are using ESP32 Arduino Core v2.0.0 or newer, you no longer need to manually implement the esp_adc_cal C-structs. You can simply use the analogReadMilliVolts() function.
Implementing Calibrated Reads in Arduino IDE
The analogReadMilliVolts() function automatically applies the factory eFuse calibration data and returns a highly accurate voltage reading in millivolts, completely bypassing the non-linear raw ADC curve.
#define SENSOR_PIN 34 // ADC1 pin, safe for WiFi
void setup() {
Serial.begin(115200);
analogSetAttenuation(ADC_11db);
}
void loop() {
// Returns calibrated voltage in mV (e.g., 3150 for 3.15V)
int voltage_mV = analogReadMilliVolts(SENSOR_PIN);
float voltage_V = voltage_mV / 1000.0;
Serial.print("Calibrated Voltage: ");
Serial.println(voltage_V);
delay(500);
}
For deeper insights into ESP32 analog behaviors, Random Nerd Tutorials provides an excellent breakdown of how these Core v2.0+ functions handle the underlying ESP-IDF API calls automatically.
Real-World Application: Acebott Robot Battery Monitoring
A common requirement in Acebott mobile robots is monitoring the main battery pack. A 2S LiPo battery ranges from 6.4V (discharged) to 8.4V (fully charged). Since the ESP32 ADC pins will be permanently damaged by voltages exceeding 3.3V, you must use a hardware voltage divider before the signal reaches the Acebott board.
Designing the Voltage Divider
To safely step down 8.4V to a maximum of ~3.1V (leaving a small safety margin below the 3.3V absolute maximum), we use a resistor divider network. Using a 10kΩ (R1) and 4.7kΩ (R2) resistor pair yields the following formula:
Vout = Vin * (R2 / (R1 + R2))
Vout = 8.4V * (4700 / 14700) = 2.68V
This 2.68V maximum is well within the safe, linear region of the 11dB attenuation curve. Wire the junction of the two resistors to GPIO 35 (an ADC1 input-only pin).
Software Compensation for the Divider
To display the actual battery voltage in your Serial Monitor or IoT dashboard, you must multiply the calibrated millivolt reading by the inverse of the divider ratio:
const float DIVIDER_RATIO = 14700.0 / 4700.0; // Approx 3.127
void loop() {
int battery_mV = analogReadMilliVolts(35);
float actual_battery_V = (battery_mV * DIVIDER_RATIO) / 1000.0;
Serial.print("Battery Level: ");
Serial.print(actual_battery_V);
Serial.println(" V");
delay(1000);
}
Hardware Filtering for Noisy Motor Environments
Acebott robots utilize DC motors and servos that generate massive amounts of Electromagnetic Interference (EMI) and voltage ripple. The ESP32's high-impedance ADC inputs act like antennas, picking up this motor noise and causing your analog readings to fluctuate wildly.
Expert Hardware Tip: Always place a 100nF (0.1μF) ceramic capacitor physically close to the ESP32 pin, bridging the analog signal line and GND. This creates a low-pass RC filter (in combination with your voltage divider resistors) that smooths out high-frequency motor noise before the SAR ADC samples the voltage. Combining this hardware filtering with the software calibration techniques outlined above will yield rock-solid analog readings, allowing your Acebott ESP32 projects to perform reliably in the real world.






