ESP32-Based Wireless Communication Link Latency Test Results

English | 中文

By RichJ233

The tested solutions include:

Hardware

Device Purpose Notes
ESP32-S3 development board Wi-Fi UDP, ESP-NOW, native USB, and dual-S3 tests Taobao item 669443108979
ESP32-C3 development board Early S3↔C3 ESP-NOW tests Tmall item 730121383834
Paired wireless UART transparent-transmission modules 115200 8N1 UART transparent-transmission tests Taobao item 618869877874
Test 11 wireless UART transparent-transmission module 115200 8N1 UART transparent-transmission test Taobao item 563716927856
Windows PC Runs the Python test programs Host-side timing uses time.perf_counter_ns

Experiments

Name Timing scope
One-way host-visible latency From the PC writing data to one endpoint until the PC receives the complete data at the other endpoint
Radio RTT Wireless A→B→A round trip measured inside the MCU; excludes the PC, Python, and USB
Host RTT From Python sending a request until Python receives the matching response
Complete closed-loop latency Total time for state uplink, PC computation, and command downlink
Delivery rate Percentage of data eventually received successfully
Deadline hit rate Whether data arrives within the target period

1. ESP32-S3 UART ↔ Wi-Fi (UDP) ↔ PC

Test Path

Serial device/PC
→ UART
→ ESP32-S3
→ Wi-Fi UDP
→ PC

Configuration:

Results

Bidirectional transparent transmission worked reliably, with a latency of approximately 29 ms. The reverse UDP→ESP32-S3→UART path produced a similar result.

2. ESP32-S3 ↔ ESP32-C3 ESP-NOW One-Way Test

Test Method

The program alternated between the two directions:

S3 → C3
C3 → S3

Results

S3↔C3 ESP-NOW stop-and-wait RTT:

Metric Result
Valid 1000/1000
Median 4.374 ms
P95 10.910 ms
Maximum 25.573 ms

3. ESP32-S3 ↔ ESP32-C3 Bidirectional Communication Test

Test Path

→ C3 UART
→ ESP-NOW
→ S3 native USB
→ PC
→ S3 native USB
→ ESP-NOW
→ C3 UART

All later tests used fixed 32-byte binary frames containing a frame type, sequence number, and CRC16.

100 Hz Results

The target period was 10 ms, with 1000 measured samples.

Metric State uplink Command downlink Complete round trip
Valid 996/1000 961/1000 961/1000
Mean 8.989 ms 43.291 ms 51.985 ms
Median 5.937 ms 29.801 ms 38.834 ms
P90 22.034 ms 100.828 ms 108.076 ms
P95 25.079 ms 132.754 ms 137.270 ms
P99 33.683 ms 174.612 ms 179.279 ms
Maximum 57.814 ms 190.135 ms 200.578 ms
≤10 ms / planned 69.80% 22.30% 7.70%

Comparison of 50, 75, and 100 Hz Results

Target frequency Period Complete median Complete mean Complete P95 Deadline hit
50 Hz 20 ms 26.140 ms 32.040 ms 74.988 ms 39.30%
75 Hz 13.333 ms 148.256 ms 314.213 ms 1125.351 ms 2.30%
100 Hz 10 ms 38.834 ms 51.985 ms 137.270 ms 7.70%

The 75 Hz test produced many ESP_ERR_ESPNOW_NO_MEM, pending overwrite, and retry events. The results may be affected by the ESP-NOW queue and transmission state.

Active + Latest Test

When newer data arrives, the old waiting packet is replaced to prevent stale data from continuously accumulating.

One submitted active packet
+
One waiting latest packet

Results at 100 Hz with 2000 samples:

Metric State uplink Command downlink Complete round trip
Valid 1891/2000 1436/2000 1436/2000
Median 6.400 ms 5.414 ms 14.635 ms
Mean 9.839 ms 9.654 ms 17.722 ms
P95 26.359 ms 29.141 ms 43.264 ms
≤10 ms / planned 24.10%

The board-side submit count matched the peer-side radio receive count.

4. ESP32-S3 Native USB Local Loopback Latency Test

Test Path

→ PC
→ S3 native USB
→ Echo
→ S3 native USB
→ PC

Results

Metric Result
Valid 1000/1000
Mean 0.529 ms
Median 0.501 ms
P95 0.660 ms
P99 0.934 ms
Maximum 1.397 ms

5. Dual ESP32-S3 ESP-NOW RTT Test

Test Path

→ S3-A firmware
→ ESP-NOW PING
→ S3-B firmware
→ ESP-NOW PONG
→ S3-A firmware

Timing was measured on the boards using esp_timer_get_time and excludes Windows, Python, and USB.

Results

Metric Result
Valid 2000/2000
Minimum 2.973 ms
Median 3.602 ms
Mean 4.442 ms
P90 6.936 ms
P95 8.476 ms
P99 12.363 ms
Maximum 23.785 ms
≤10 ms / planned 97.30%

Board-side statistics:

6. Dual-S3 Host-Triggered RTT Test

Test Path

→ Python
→ USB
→ S3-A
→ ESP-NOW
→ S3-B
→ ESP-NOW
→ S3-A
→ USB
→ Python

Results

Metric Internal radio RTT Complete host RTT
Valid 1714/2000 1714/2000
Median 3.606 ms 4.774 ms
Mean 4.927 ms 6.029 ms
P95 11.925 ms 13.028 ms
P99 18.070 ms 19.223 ms
Maximum 41.194 ms 42.363 ms

7. Dual-S3 Single-USB Stop-and-Wait Test

Test Path

→ Python
→ USB A
→ S3-A
→ ESP-NOW
→ S3-B
→ ESP-NOW
→ S3-A
→ USB A
→ Python

S3-B's USB connection was not included in the timed path.

Only one transaction was allowed in flight at a time. The test recorded the complete host RTT, internal ESP-NOW RTT, and host+USB overhead.

Results

Metric Run 1 Run 2
Valid / planned 2436/3000 2470/3000
Complete median 4.515 ms 4.342 ms
Complete mean 5.866 ms 5.697 ms
Complete P95 13.070 ms 12.728 ms
Complete P99 18.406 ms 16.814 ms
Complete maximum 30.694 ms 43.885 ms
Radio median 3.743 ms 3.541 ms
Radio mean 5.099 ms 4.941 ms
Host+USB median 0.709 ms 0.712 ms
Host+USB P95 1.018 ms 1.041 ms

The board-side statistics for both tests recorded 3100 complete wireless round trips:

8. Dual-S3 Asynchronous Bidirectional Communication Test

Test Method

Results

Metric State uplink Command downlink Complete round trip
Valid / planned 2996/3000 2482/3000 2482/3000
Minimum 1.948 ms 1.955 ms 4.047 ms
Median 3.671 ms 3.426 ms 11.894 ms
Mean 8.346 ms 8.838 ms 14.328 ms
P90 21.906 ms 25.891 ms 29.685 ms
P95 22.700 ms 32.874 ms 36.668 ms
P99 28.675 ms 42.358 ms 47.351 ms
Maximum 51.027 ms 62.686 ms 64.884 ms
≤10 ms / planned 63.77% 58.47% 38.70%

9. nRF24-Like Wireless UART Transparent Module: 12-Byte Sequential Round Trip

Serial Configuration and Frame Format

A5 5A | uint32 sequence | PING | CRC16-CCITT

Test Path and Timing

The same PC was connected to two USB serial ports:

t0: PC writes to serial A
→ Module A
→ Wireless link
→ Module B
t1: PC receives the complete frame from serial B

t2: PC writes the validated frame back to serial B
→ Module B
→ Wireless link
→ Module A
t3: PC receives the returned frame from serial A

Calculations:

Results

Metric A→B PC forwarding B→A Full RTT
Mean 8.465 ms 0.014 ms 8.585 ms 17.063 ms
Median 8.326 ms 0.010 ms 8.581 ms 16.920 ms
P90 8.933 ms 0.021 ms 8.651 ms 17.524 ms
P95 8.988 ms 0.028 ms 8.722 ms 17.589 ms
P99 9.260 ms 0.058 ms 9.034 ms 18.054 ms
Minimum 7.910 ms 0.005 ms 7.980 ms 16.494 ms
Maximum 27.299 ms 0.814 ms 11.332 ms 35.873 ms
Std 0.510 ms 0.025 ms 0.127 ms 0.529 ms

Sample statistics:

For 12-byte data at 115200 8N1, the theoretical total transmission time across four UART legs is approximately 4.167 ms.

10. nRF24-Like Wireless UART Transparent Module: Simultaneous Bidirectional Transmission

Test Method

Two Python workers used threading.Barrier to start as close to simultaneously as possible:

Serial A sends frame A while serial B sends frame B
Both endpoints wait for data from the opposite side

Each frame was 12 bytes and contained a header, source, sequence number, payload, and CRC.

Results

Many communication failures occurred. No stable latency statistics or accurate failure rate were produced.

This result alone does not prove that the product is half-duplex by specification. It may also be caused by simultaneous-transmission collisions, contention, or a radio that cannot transmit and receive at the same time. However, the link is not suitable for designs that rely on simultaneous bidirectional transmission.

11. nRF24-Like Wireless UART Transparent Module: 10-Byte Python Echo RTT

Configuration

Frame format:

AA 55 | uint32 sequence | uint16 data | CRC16-MODBUS

Test Path

Python main thread
→ COM9
→ Module A
→ Wireless link
→ Module B
→ COM10
→ Python echo thread writes the same data back to COM10
→ Module B
→ Wireless link
→ Module A
→ COM9
→ Python main thread

Results

Metric Result
Warm-up valid 49/50
Formal valid 1000/1000
Mean 21.013 ms
Median 21.578 ms
P90 22.024 ms
P95 22.124 ms
P99 22.391 ms
Minimum 19.121 ms
Maximum 24.892 ms
Std 0.998 ms

The actual test frequency was approximately 24.2 Hz.

Results Comparison

Solution Measurement scope Main result Samples / valid rate
Wi-Fi UART↔UDP Bidirectional transparent transmission Connected successfully, approximately 29 ms
S3↔C3 ESP-NOW One-way host-visible Typically about 3–7 ms, with TIMEOUT events
S3+C3 100 Hz communication State→PC→command return Mean 51.985 ms, P95 137.270 ms, ≤10 ms 7.70% 961/1000
Dual-S3 ESP-NOW Board-side radio RTT Mean 4.442 ms, median 3.602 ms, P99 12.363 ms 2000/2000
Dual-S3 single-USB run PC→A→B→A→PC Mean 5.697 ms, median 4.342 ms, P99 16.814 ms 2470/3000
Dual-S3 asynchronous communication State→PC→command return Median 11.894 ms, P99 47.351 ms, ≤10 ms 38.70% 2482/3000
Transparent modules, sequential round trip A→B→PC forwarding→A Mean 17.063 ms, P99 18.054 ms 2973/3000
Transparent modules, simultaneous bidirectional Both endpoints transmit simultaneously Many failures, no stable statistics
Test 11 transparent module echo COM9→COM10 Python echo→COM9 Mean 21.013 ms, P99 22.391 ms 1000/1000