sniffer measurements of Bluetooth broadcast and observe #2822
Replies: 8 comments 5 replies
|
Hi Bert, There was one other observation that I wanted to add. Hopefully you can open the BLERadio firmware driver and get some improvement towards a reliable Rx/Tx handshake operation. {wishlist} While you are there, can you expose the packet count since last 'observe' or 'broadcast' as radio.count.in(channel) and radio.count.out() |
Does a Pybricks hub send data slower when it is not connected to a PC? (round 2, two firmware versions)Why this testA LEGO hub can send small updates over Bluetooth while also listening for updates from other hubs at the same time.
The goal is more reliable numbers, and to see if both versions behave the same way. Results
Column meaning, in plain words:
One malformed (unreadable) packet was seen once, in the "never pause, does not read while waiting, not connected" test on the stable firmware. It did not happen in any other test. Although in previous tests it was sparingly seen. Connected runs:Not-connected (no-PC) runs only:Conclusion
|
|
Here is another firmware to try. 😄 If it works right, we should be getting 20 updates per second or so (unless movehub is the broadcaster). |
Does PR#500 fix the "hub sends data slower when not connected to a PC" problem?Why this testEarlier tests showed that a LEGO hub sending and listening for Bluetooth updates at the same time gets much slower when it is not connected to a PC, sometimes almost completely stopping. David looked into it and found a cause A fix PR 500 was made. This post repeats the same tests as before, and one much longer on a hub running that fix, to check whether it actually solves the problem. ResultsAll three firmware versions, side by side, same tests and programs as before:
Column meaning:
No malformed (unreadable) packets were seen in any of the 13 tests on this firmware, including the long one below. The earlier firmware versions had 1 such packet in the tests. All tests lasted at least 5 minutes. On the earlier firmware versions, two "not connected" tests stopped sending data after only a few seconds even though the test kept running for the full 5 minutes; on PR#500 firmware, the same two tests ran the full 5 minutes with data the whole time. The long testOne extra test ran for about 32 minutes: sending method "pause between updates", reading while waiting, 50ms startup wait, not connected to a PC (the same settings as one of the rows above), just left running much longer to check whether the speed holds up over time. Cut into 5-minute chunks, the speed per chunk was: 5.93, 5.68, 5.76, 6.05, 5.84, 5.73, then 2.46 for the last partial chunk. The gap between one group of repeated updates and the next never went above 1 second anywhere in the whole 32 minutes. On the earlier firmware, a similar long test fluctuated between almost nothing and near-normal speed within the same run, with gaps up to a minute long. This one did not do that: it stayed steady the whole time. Speed at a glanceSame numbers as the "Speed" column, as bars, so the difference is easier to see. Each chart uses its own scale (PC-connected speeds are much higher than not-connected ones, so putting them on the same scale would make the not-connected bars too small to read). Conclusion
|
|
Dear All,
As soon as Heartbeat starts, it polls the CityHub, which broadcasts responses for each valid received group of packets. The sniffer sees all the 12-Byte packets from Channel 102 (0x66) and 119 (0x77) For the Hub BLE Radio, timers are Stopwatch-based, to minimise the load on the BLE chip and not running in the main loop. 'observe' occurs every 100ms and 'broadcast' STOP occurs 500ms after Transmit begins. This actually provides non-blocking and allows receive of other 'speed' commands from the remote control. The main reason to stop the broadcast is the need to share the response channel with other hubs. |
Pybricks BLE sniffer results - PR#500#2 (319f5ffc7)Generated from Results
Malformed (undecodable) packets seen: 0 while connected, 0 while not connected. Speed at a glanceTests indicated with PR#500#2 is githash 319f5ffc7 PC connected: Not connected: |
To see if the pause makes "room"
All adverticements with LEGO manufactor id. |
|
OK, I think I understand well enough what is going on now. And I think we should do some more tuning, but it will need a modified experiment. Bert has just been looking at advertisements, but we need to balance time for all of the different things. Apparently, we had all of the hubs set to observe all of the time when observing is enabled (and not a connection in the city/technic hub case). So this is why the advertisement rate was so low. For most of the hubs, we have the advertisement rate to 25ms which means that it tries to advertise every 25 to 35ms (there is a random 0-10ms added on always to prevent aliasing issues - that's just how BLE works and can't be adjusted). In the two commits of the pull request I made, the observe is set to a 50% duty cycle so that it can observe half the time and broadcast half the time. The first attempt, the observe window (and therefore broadcast window) was 20ms, which was smaller that the advertisement interval, so even when not observing, the advertisement might not have been within that window and got dropped. The second attempt has a 35ms window, so an advertisement pretty much always happens. That is why we saw the ~12.5/s rate (disconnected) - it is a bit less than 1/2 of the ~28/s baseline that was measured. For the connected case, on city/technic hubs, there is actually separate set of interval/window parameters that I didn't change yet. They are set to observe all of the time too, but apparently the connection trumps the observing and the advertisement apparently piggy-backs on the connection. So this is why we never saw a change in connected numbers with the pull request changes. However, the fact that it is advertising at ~22/s compared to the ~28/s baseline means that it is advertising almost all of the time and never observing. So this explains why observing doesn't work well while connected on these hubs. We should be able to tweak things though to make more time for observing. We can reduce the time slot used by the connection. This will make stdio slower but observing would work better while connected. For the experiment, we probably need to make a special firmware that logs the timestamp of every advertisement received from another hub that is broadcasting. And also use a sniffer to see when it is advertising. And we would need to do all of the combinations. Hub A = received advertisements recorded by firmware
Maybe we could use sensors to coordinate between hubs to go through the observing/broadcasting combinations, then we would only have to run two tests, the connected and disconnected. |
Uh oh!
There was an error while loading. Please reload this page.
Rationale
Discussion item 2818 made me measure broadcasts on a CityHub.
This is the result.
Setup
Receiver:
Raspberry Pi Pico 2 W, MicroPython, passive scan via the built-in
bluetoothmodule.ble_sniffer.py
Hub:
City Hub, Pybricks v4.1.0b2
Hub-side test program:
CityHub program broadcast_transmit_demo.py
radio.broadcast(value)on a timer, noobserve_channelsset at all.BLERadioobject per phase: TX-only for 200ms, then RX-only for 800ms.BLERadiofor the whole run, bothbroadcast_channelandobserve_channelsset up front. TX paused withbroadcast(None), resumed withbroadcast(value).broadcast(new_value)called back-to-back.Added two more variables to modes 1-3:
POLL_OBSERVE(actively callradio.observe(channel)on a timer during listening periods, instead of just leavingobserve_channelsconfigured and unread).SETTLE_MS(a short pause after constructing/reconfiguring aBLERadio, before using it).Results
Baseline, broadcast only, no observe channel defined.
No meaningful difference. This is the reference point everything below is measured against.
Modes 1-3 with
POLL_OBSERVEandSETTLE_MSvaried.What the raw log looks like
This is mode 3, poll observe on, settle 50ms, standalone. The value changes once a second; each row is one received packet:
This is not a slow rate, it is a very fluctuating one.
Interpretation
The problem only shows up once
observe_channelsis used and alsobroadcast_channel, dual-role is the trigger.It's the worst performer connected (3.79 pkt/s vs ~19-23 pkt/s for modes 1 and 3) and the only one that simply stops standalone rather than degrading.
broadcast(None)followed bybroadcast(value)on the same radio object doesn't reliably restart transmission, mode 1's full object recreation and mode 3's "never stop" approach, both avoid this because neither exercises that specific resume path.radio.observe()measurably helps standalone, but doesn't fix it.Modes 1 and 3 standalone go from ~0.95-1.03 pkt/s (observe configured but never read) to ~3-4 pkt/s (observe actively polled), a real, repeatable improvement, but still a lot below the ~28 pkt/s baseline or the ~19-23 pkt/s connected dual-role rate.
SETTLE_MSmade no consistent difference in either direction across every mode it was tested on. This is not a factor here.Caveats
Bottom line
Dual-role (broadcast + observe together) is slow and reproducible:
Mode 2's pause/resume pattern has its own, separate bug?
If it is helpful, I could do similar measurements on another firmwarelevel.
All reactions