1 (edited by JosephDuchesne 2020-09-26 05:16:35)

Topic: ESP32 BLE Update Rate is much slower than wifi

I'm using an ESP32 based RemoteXY to control a robot, and I need to use Bluetooth Low Energy as a protocol, but the default data update frequency over BLE on Android RemoteXY is very slow.

To test, I set up a tiny RemoteXY instance of just a joystick, and manually wiggled the joystick while the arduino printed the milliseconds between different values.

Measured values Android RemoteXY -> ESP32 via WiFi hotspot: 52ms/update (~20Hz)
Measured values Android RemoteXY -> ESP32 via BLE: 180ms/update (~5.5Hz)

The WiFi experiment demonstrates that both the ESP32 and the Android app are capable of at least 20Hz data rate, however the BLE communication mode isn't configured to support that data rate.

Bluetooth Low Energy is very preferable to wifi hotspot, since it doesn't take my phone off wif (very annoying), and should have longer range and reliability.

I also tried to profile classic bluetooth, but it crashed repeatedly.

Since the Arduino library is open source, I went through the BLE RemoteXY code in case the delay is in that esp32core_ble. As far as I can tell it is not.


Android Bluetooth Low Energy has 3 connection priorities:

High: 11.25 -15 ms
Balanced: 30-50ms
Low: 100-125ms

This can be set with:
https://developer.android.com/reference … ority(int)

Running Android Debugger, I logged the connection event, filtering for "Bluetooth" when running RemoteXY:

2020-09-25 16:26:35.870 4636-7798/? D/BluetoothGatt: connect() - device: 8C:AA:B5:8C:49:EE, auto: false
2020-09-25 16:26:35.870 4636-7798/? D/BluetoothGatt: registerApp()
2020-09-25 16:26:35.870 4636-7798/? D/BluetoothGatt: registerApp() - UUID=53474f53-223f-4802-8c1a-2727b5f1fbc3
2020-09-25 16:26:35.872 4636-4662/? D/BluetoothGatt: onClientRegistered() - status=0 clientIf=7
2020-09-25 16:26:36.279 1523-1691/? W/BluetoothEventManager: AclStateChangedHandler: activeDevice is null
2020-09-25 16:26:36.281 4636-4767/? D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=7 device=8C:AA:B5:8C:49:EE
2020-09-25 16:26:36.281 4636-4767/? D/BluetoothGatt: discoverServices() - device: 8C:AA:B5:8C:49:EE
2020-09-25 16:26:36.282 2123-2123/? I/TrustAgent: TAG: TrustAgent.Tracker. [BluetoothConnectionTracker] Bluetooth connect broadast for BDBV8-1 8C:AA:B5:8C:49:EE [CONTEXT service_id=84 ]
2020-09-25 16:26:36.286 4636-4767/? D/BluetoothGatt: onSearchComplete() = Device=8C:AA:B5:8C:49:EE Status=0
2020-09-25 16:26:36.286 4636-4767/? D/BluetoothGatt: setCharacteristicNotification() - uuid: 0000ffe1-0000-1000-8000-00805f9b34fb enable: true
2020-09-25 16:26:40.405 3144-3144/? D/BluetoothAdapter: stopLeScan()
2020-09-25 16:26:40.415 3144-3144/? D/BluetoothAdapter: isLeEnabled(): ON

It seems that RemoteXY isn't even setting the connection priority.

Here's debug logging turned on:

With lots of controls:

[   27.078] <- 55 06 00 C0 F1 B9 // update var request
[   27.079] -> 55 08 00 C0 22 00 F5 43 // update var reply
[   27.168] <- 55 0A 00 80 EF 17 00 00 AA 06
[   27.169] -> 55 06 00 80 F0 49
// 180 ms since last update

[   27.258] <- 55 06 00 C0 F1 B9  // update var request
[   27.259] -> 55 08 00 C0 86 00 8F 83   // update var reply
[   27.348] <- 55 0A 00 80 00 00 00 00 2E D6   // joystick & others update
[   27.349] -> 55 06 00 80 F0 49  // ack
// 180 ms since last update

With one joystick, no vars:

[   11.431] <- 55 06 00 C0 F1 B9   // noop
[   11.432] -> 55 06 00 C0 F1 B9   // noop reply
[   11.521] <- 55 08 00 80 F1 64 A8 4C   // joystick update
[   11.522] -> 55 06 00 80 F0 49  // ack
// 180 ms since last update

[   11.611] <- 55 06 00 C0 F1 B9   // noop
[   11.612] -> 55 06 00 C0 F1 B9   // noop
[   11.701] <- 55 08 00 80 DD CF F5 33  // joystick update
[   11.702] -> 55 06 00 80 F0 49   // ack
// 180 ms since last update

Each packet is being received every 90ms, and replied to nearly instantly, and becuase the first packet is always sent, even when there are no variables to be updated (I suppose because the device could push input values up in a reply), the maximum data rate is 180ms/update (5.55Hz).

This is really sub-optimal for controlling even simple things like LEDs (tapping an LED button is missed most of the time, wheras it works most of the time on WiFi).

Using the nRF Connect android BLE debugger, I was able to replay these packets at a much higher datarate (as fast as 5ms/packet, although that overran a buffer on the ESP32).

Is it possible to address the connection priority issue, and make the existing 90ms/packet rate either lower (25ms/packet seems to be roughly where the wifi one is), or ideally to make this configurable?

Otherwise I really like this app! It's so close to exactly what I'm looking for.

The other major area for improvement would be to allow for a protocol that updates in as few as one call->response, rather than requiring two round trips per update, but that's probably not necessary to get things working fast enough for most purposes.

Edit: Since I'm roadblocked on this, I poked at the binary apk myself to see if my theory is correct.

Adding requestConnectionPriority(1) after the code logs ""BLE device connected" increases the frequency from 5.5Hz to 11Hz.

I also reduced all the sleep statement durations (Thread.sleep(20) -> Thread.sleep(2) in the Device class, and cut the delayIsInterrupted min sleep from 10ms to 1ms in RXYSocket. Those changes increased the frequency from 11Hz to 16.6Hz. I'd still like it to go faster, but I paid my $10 for RemoteXYPro so I wouldn't have to do all the hard work myself smile

Any chance this issue could be looked into?

2 (edited by hrgraf 2020-10-27 13:34:32)

Re: ESP32 BLE Update Rate is much slower than wifi

Hi,

I have not used RemoteXY with WiFi, but with ESP32 BLE and Android, I can confirm the low update frequency of 5Hz, e.g. on Joystick updates.

This is a major drawback for me too, and I would expect/require GUI updates at 50Hz.
(I am still evaluating RemoteXY free)

Thank you.

P.S.:Since there is no update/reaction on the issue, I have found/created myself an alternative:
Instead of a smartphone app, I am using directly a Wii remote and (optionally) its connected Nunchuk as input controllers for my ESP32 project. Over Bluetooth, I get accelerometer data, analog joystick values and 13 buttons, easily at 100Hz update rate.
(See: https://github.com/hrgraf/ESP32Wiimote)