You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派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

问题原因分析

  1. 客户端读取逻辑错误:客户端使用char_read()同步读取特征值,但服务端是通过notify()主动推送数据。char_read()会等待服务端返回可读数据,若超时未获取到则抛出错误,进而触发连接断开。
  2. 未订阅通知:服务端主动推送通知,但客户端没有订阅该特征的通知通道,导致推送的数据无法被接收,同时客户端的char_read()一直等待不到数据,最终超时断开。
  3. 连接参数不兼容: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 15:02:09