树莓派Pico W与Zero 2W BLE连接后立即断开且超时问题求助
问题排查:Raspberry Pi Pico W与Zero 2W BLE连接后立即断开并抛出NotificationTimeout错误
尝试通过Bluetooth Low Energy(BLE)连接Raspberry Pi Pico W(服务端)与Raspberry Pi Zero 2W(客户端)实现数据传输,但二者建立连接后立即断开。运行代码后,Zero 2W显示已成功连接Pico W,但会抛出pygatt.exceptions.NotificationTimeout: None错误,需排查问题原因。
服务端(Raspberry Pi Pico W)代码
import sys import aioble import bluetooth import machine import uasyncio as asyncio from micropython import const def uid(): """ Return the unique id of the device as a string """ return "{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}".format( *machine.unique_id()) MANUFACTURER_ID = const(0x02A29) MODEL_NUMBER_ID = const(0x2A24) SERIAL_NUMBER_ID = const(0x2A25) HARDWARE_REVISION_ID = const(0x2A26) BLE_VERSION_ID = const(0x2A28) led = machine.Pin("LED", machine.Pin.OUT) _DEVICE_INFO_UUID = bluetooth.UUID(0x180A) # Device Information _GENERIC = bluetooth.UUID(0x1848) _BUTTON_UUID = bluetooth.UUID(0x2A6E) _BLE_APPEARANCE_GENERIC_REMOTE_CONTROL = const(384) ADV_INTERVAL_MS = 250_000 device_info = aioble.Service(_DEVICE_INFO_UUID) connection = None # Create Characteristic for device info aioble.Characteristic(device_info, bluetooth.UUID(MANUFACTURER_ID), read=True, initial="KevsRobots.com") aioble.Characteristic(device_info, bluetooth.UUID(MODEL_NUMBER_ID), read=True, initial="1.0") aioble.Characteristic(device_info, bluetooth.UUID(SERIAL_NUMBER_ID), read=True, initial=uid()) aioble.Characteristic(device_info, bluetooth.UUID(HARDWARE_REVISION_ID), read=True, initial=sys.version) aioble.Characteristic(device_info, bluetooth.UUID(BLE_VERSION_ID), read=True, initial="1.0") remote_service = aioble.Service(_GENERIC) button_characteristic = aioble.Characteristic(remote_service, _BUTTON_UUID, read=True, notify=True) print("Registering services") aioble.register_services(remote_service, device_info) connected = False async def remote_task(): """ Task to handle remote control """ while True: if not connected: print("Not Connected") await asyncio.sleep_ms(1000) continue button_characteristic.write(b"data") button_characteristic.notify(connection, b"data") await asyncio.sleep_ms(10) async def peripheral_task(): """ Task to handle peripheral """ global connected, connection while True: connected = False connection = await aioble.advertise(ADV_INTERVAL_MS, name="KevsRobots", appearance=_BLE_APPEARANCE_GENERIC_REMOTE_CONTROL, services=[_GENERIC]) print("Connection from", connection.device) connected = True print("connected") await connection.disconnected() print("disconnected") async def main(): tasks = [ asyncio.create_task(peripheral_task()), asyncio.create_task(remote_task()) ] await asyncio.gather(*tasks) asyncio.run(main())
客户端(Raspberry Pi Zero 2W)代码
import pygatt CHARACTERISTIC = "00002a6e-0000-1000-8000-00805f9b34fb" def connect_to_ble_device(device_address): print('start') adapter = pygatt.GATTToolBackend() adapter.start() try: print("Connecting to BLE device with address: {}".format(device_address)) device = adapter.connect(device_address) while True: value = device.char_read(CHARACTERISTIC, timeout=10) print('value is', value) finally: adapter.stop() if __name__ == "__main__": connect_to_ble_device('28:CD:C1:0C:39:65') # Pico MAC Address
问题原因分析
- 客户端读取逻辑错误:客户端使用
char_read()同步读取特征值,但服务端是通过notify()主动推送数据。char_read()会等待服务端返回可读数据,若超时未获取到则抛出错误,进而触发连接断开。 - 未订阅通知:服务端主动推送通知,但客户端没有订阅该特征的通知通道,导致推送的数据无法被接收,同时客户端的
char_read()一直等待不到数据,最终超时断开。 - 连接参数不兼容:pygatt默认连接参数与Pico W的aioble配置不匹配,可能导致连接稳定性差,容易触发断开逻辑。
解决方法
客户端代码修改:改用订阅通知模式
将同步读取改为订阅通知,接收服务端主动推送的数据:
import pygatt CHARACTERISTIC = "00002a6e-0000-1000-8000-00805f9b34fb" def handle_data(handle, value): print('收到数据:', value) def connect_to_ble_device(device_address): print('启动连接') adapter = pygatt.GATTToolBackend() adapter.start() try: print(f"连接BLE设备: {device_address}") # 配置连接参数,开启自动重连 device = adapter.connect(device_address, timeout=10, auto_reconnect=True) # 订阅特征通知,绑定回调函数 device.subscribe(CHARACTERISTIC, callback=handle_data) # 保持连接运行 while True: pass except pygatt.exceptions.BLEError as e: print(f"连接错误: {e}") finally: adapter.stop() if __name__ == "__main__": connect_to_ble_device('28:CD:C1:0C:39:65') # Pico MAC地址
服务端代码优化:添加订阅检查
确保仅在客户端订阅通知时才发送数据,避免无效操作:
async def remote_task(): """ 处理远程控制任务 """ while True: if not connected: print("未连接") await asyncio.sleep_ms(1000) continue # 检查是否有客户端订阅了当前特征的通知 if button_characteristic.subscribed(): button_characteristic.write(b"data") button_characteristic.notify(connection, b"data") await asyncio.sleep_ms(10)
额外建议
- 验证Pico W的蓝牙MAC地址准确性,避免连接错误设备。
- 在Zero 2W上用
hciconfig命令检查蓝牙适配器状态,确保其正常工作。 - 调整服务端广播间隔
ADV_INTERVAL_MS为100_000(100ms),提升连接稳定性。
内容的提问来源于stack exchange,提问作者yuval kalan
相关产品推荐
相关产品推荐

