首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >蓝牙编程在树莓Pi 4使用蓝光和dbus。每件事情都很好,RPI需要超过90 is才能接收到8次浮标。

蓝牙编程在树莓Pi 4使用蓝光和dbus。每件事情都很好,RPI需要超过90 is才能接收到8次浮标。
EN

Stack Overflow用户
提问于 2022-02-07 19:30:33
回答 1查看 982关注 0票数 0

我正在进行一个项目,在这个项目中,Rpi将接收来自Arduino nano ble的8个浮标。Arduino是作为外围设备工作,并通过蓝牙发送8个浮标。Arduino代码如下所示。

代码语言:javascript
运行
复制
#include <Arduino_LSM9DS1.h>  // C:\Users\16312\Documents\Arduino\libraries\Arduino_LSM9DS1\src
#include <ArduinoBLE.h>
String localName = "testPeripheral";

#define BLE_UUID_SENSOR_DATA_SERVICE              "2BEEF31A-B10D-271C-C9EA-35D865C1F48A"
#define BLE_UUID_MULTI_SENSOR_DATA                "4664E7A1-5A13-BFFF-4636-7D0A4B16496C"

#define NUMBER_OF_SENSORS 8

union multi_sensor_data
{
  struct __attribute__( ( packed ) )
  {
    float values[NUMBER_OF_SENSORS];
  };
  uint8_t bytes[ NUMBER_OF_SENSORS * sizeof( float ) ];
};

union multi_sensor_data multiSensorData;

BLEService sensorDataService( BLE_UUID_SENSOR_DATA_SERVICE );
BLECharacteristic multiSensorDataCharacteristic( BLE_UUID_MULTI_SENSOR_DATA, BLERead | BLENotify, sizeof multiSensorData.bytes );

static long previousMillis = 0;
#define UPDATE_INTERVALL 50

float iter;
float dt;
void setup() {
  Serial.begin(9600);
  //while (!Serial);

  initBLE();

  if (!IMU.begin()) {
    Serial.println("Failed to initialize IMU!");
    while (1);
  }
  iter = 0;
}


void serial_print_xyz(float x, float y, float z) {
  int num_digits = 6;
  Serial.print(x, num_digits);  Serial.print('\t');
  Serial.print(y, num_digits);  Serial.print('\t');
  Serial.print(z, num_digits);  Serial.print('\t');
}

void serial_print_1(float val) {
  int num_digits = 6;
  Serial.print(val, num_digits);  Serial.print('\t');
}

void serial_print_1(int val) {
  Serial.print(val);  Serial.print('\t');
}

void serial_print_endln() {
  Serial.print("end");   Serial.println();
}



void loop() {
  //comment below line to remove serial print of master address

  dt = millis()-previousMillis;
  float acc_x, acc_y, acc_z;
  float mag_x, mag_y, mag_z;
  // Magnetic field seems to read at a slower rate than acceleration?
  if (IMU.accelerationAvailable() && IMU.magneticFieldAvailable()) {
    if ( millis() - previousMillis > UPDATE_INTERVALL )
    {
      previousMillis =  millis();
      // Read measurements
      IMU.readAcceleration(acc_x, acc_y, acc_z);
      IMU.readMagneticField(mag_x, mag_y, mag_z);
      iter++;
      // Export measurements
      checkCentralConnect();  //check if slave is connected to Master
      
      updateIMU(acc_x, acc_y, acc_z, mag_x, mag_y, mag_z);

      
      Serial.print("start\t");
      serial_print_1(iter);
      serial_print_1(dt);
      serial_print_xyz(acc_x, acc_y, acc_z);
      serial_print_xyz(mag_x, mag_y, mag_z);
      serial_print_endln();
    }
  }

}

void initBLE()
{
  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");
  }

  // set advertised local name and service UUID:
  BLE.setDeviceName( "Arduino Nano 33 BLE" );
  BLE.setLocalName( "Arduino Nano 33 BLE" );
  BLE.setAdvertisedService( sensorDataService );

  // BLE add characteristics
  sensorDataService.addCharacteristic( multiSensorDataCharacteristic );

  // add service
  BLE.addService( sensorDataService );

  // set the initial value for the characeristic:
  multiSensorDataCharacteristic.writeValue( multiSensorData.bytes, sizeof multiSensorData.bytes );

  // start advertising
  BLE.advertise();

  String address = BLE.address();
  Serial.print("Local mac address is: ");
  Serial.println(address);
  Serial.println("LocalName: Arduino Nano 33 BLE");
}

void checkCentralConnect()
{
  // listen for BLE centrals to connect:
  BLEDevice central = BLE.central();

  // if a central is connected to peripheral print mac address
  if (central) {
    //Serial.print("Connected to central: ");
    // print the central's MAC address:
    //Serial.print(central.address());
  }
}

void updateIMU(float accX, float accY, float accZ, float magX, float magY, float magZ)
{

  multiSensorData.values[0]  = accX;
  multiSensorData.values[1]  = accY;
  multiSensorData.values[2]  = accZ;

  multiSensorData.values[3]  = magX;
  multiSensorData.values[4]  = magY;
  multiSensorData.values[5]  = magZ;
  multiSensorData.values[6]  = dt;
  multiSensorData.values[7]  = iter;

  multiSensorDataCharacteristic.writeValue( multiSensorData.bytes, sizeof multiSensorData.bytes );
}

在这段代码中,您可以看到Arduino也在串行端口上发送数据,在这8个浮点数中,2个浮点数是一个循环的迭代和执行时间,所以通过检查Arduino的串行输出,我可以知道Arduino通过蓝牙发送数据所花费的时间。我所发现的是,Arduino的一个循环大约是50 ms,但在这50 ms中,IMU传感器在每个循环中需要48到49 ms(如果我删除用于从IMU获取值的代码,那么一个循环的执行时间仅为1ms )。Arduino只需1ms就可以通过蓝牙发送数据。但另一方面,RPI需要超过90ms才能接收到来自Arduino的这8款浮标。我在模块中使用BlueZ栈进行蓝牙通信,使用python与BlueZ通信。我附上了蓝牙扫描仪和数据读取器的下面代码。当类初始化时,它会扫描设备,如果找到Arduino,它将与它连接。初始化完成后,代码开始读取特征值。我正在使用while循环来连续读取值,但我无法理解为什么RPI只读取8个浮动值(检查python代码底部的主循环代码)就占用了90 is以上。我对python和Dbus编程非常陌生,请帮我弄清楚如何提高RPI中的蓝牙数据传输速度。如果有另一种方法,我正在使用错误或旧的方法,请提供一个链接到文档,通过它我可以理解什么是问题。

代码语言:javascript
运行
复制
#!/usr/bin/python3
from gi.repository import GLib
import bluetooth_utils
import bluetooth_constants
import dbus
import dbus.mainloop.glib
import sys
#import pydbus
import struct
from allDefData import defData

sys.path.insert(0, '.')

adapter_interface = None
mainloop = None
timer_id = None

devices = {}

class bleScan():

    def __init__(self, defD):
        # dbus initialisation steps
        self.defD = defD
        self.adapter_path = bluetooth_constants.BLUEZ_NAMESPACE + bluetooth_constants.ADAPTER_NAME
        self.ArdunoBleD = lambda: None
        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
        self.bus = dbus.SystemBus()
        self.get_through_list_connected_devices()

        print(hasattr(self.ArdunoBleD, 'Name'))
        while(not hasattr(self.ArdunoBleD, 'Name')):
            print("Scanning")
            self.discover_devices(self.bus, 2000)
            if hasattr(self.ArdunoBleD, 'Name') and defD.ArdBleName in self.ArdunoBleD.Name:

                print("Scanning Stoped")
                break
            else:
                print("Not found Rescanning")
        char_proxy = self.bus.get_object(bluetooth_constants.BLUEZ_SERVICE_NAME, '/org/bluez/hci0/dev_1B_4E_C8_D6_CC_06/service000a/char000b')
        self.char_interface = dbus.Interface(char_proxy, bluetooth_constants.GATT_CHARACTERISTIC_INTERFACE)


    def Som(self, interfaces, path):

        if bluetooth_constants.GATT_SERVICE_INTERFACE in interfaces:
            properties = interfaces[bluetooth_constants.GATT_SERVICE_INTERFACE]
            print("-------------------------------------------------------------- ------------------")
            print("SVC path :", path)
            if 'UUID' in properties:
                uuid = properties['UUID']
            if uuid == bluetooth_constants.TEMPERATURE_SVC_UUID:
                found_ts = True
                ts_path = path
            print("SVC UUID : ", bluetooth_utils.dbus_to_python(uuid))
            print("SVC name : ", bluetooth_utils.get_name_from_uuid(uuid))
            return
        if bluetooth_constants.GATT_CHARACTERISTIC_INTERFACE in interfaces:
            properties = interfaces[bluetooth_constants.GATT_CHARACTERISTIC_INTERFACE]
            print(" CHR path :", path)
            if 'UUID' in properties:
                uuid = properties['UUID']
            if uuid == bluetooth_constants.TEMPERATURE_CHR_UUID:
                found_tc = True
            tc_path = path
            print(" CHR UUID : ", bluetooth_utils.dbus_to_python(uuid))
            print(" CHR name : ", bluetooth_utils.get_name_from_uuid(uuid))
            flags = ""
            for flag in properties['Flags']:
                flags = flags + flag + ","
            print(" CHR flags : ", flags)
            return
        if bluetooth_constants.GATT_DESCRIPTOR_INTERFACE in interfaces:
            properties =interfaces[bluetooth_constants.GATT_DESCRIPTOR_INTERFACE]
            print(" DSC path :", path)
            if 'UUID' in properties:
                uuid = properties['UUID']
            print(" DSC UUID : ", bluetooth_utils.dbus_to_python(uuid))
            print(" DSC name : ", bluetooth_utils.get_name_from_uuid(uuid))
            return

    def get_through_list_connected_devices(self):
        bus = self.bus
        proxy = bus.get_object(bluetooth_constants.BLUEZ_SERVICE_NAME, '/')
        interface = dbus.Interface(proxy, bluetooth_constants.DBUS_OM_IFACE)
        mngd_objs = interface.GetManagedObjects()
        for path, interfaces in mngd_objs.items():
            print(path)

            for ainterface in interfaces:
                print(ainterface)
                if ainterface == bluetooth_constants.DEVICE_INTERFACE:
                    device_properties = interfaces[bluetooth_constants.DEVICE_INTERFACE]
                    #if path not in devices:
                    devices[path] = device_properties
                    dev = devices[path]
                    try:
                        adr_name_Conn_inDev = ('Address' and 'Name' and 'Connected' in dev)
                        arduinoName_isCorrect = self.defD.ArdBleName in bluetooth_utils.dbus_to_python(dev['Name'])
                        isConnected = bluetooth_utils.dbus_to_python(device_properties['Connected'])

                    except:
                        adr_name_Conn_inDev = False
                        arduinoName_isCorrect = False
                        isConnected = False

                    if adr_name_Conn_inDev and arduinoName_isCorrect and isConnected:
                        self.ArdunoBleD.Name = bluetooth_utils.dbus_to_python(dev['Name'])
                        self.ArdunoBleD.Address = bluetooth_utils.dbus_to_python(dev['Address'])
                        #self.ArdunoBleD.RSSI = bluetooth_utils.dbus_to_python(dev['RSSI'])
                        self.ArdunoBleD.Path = path
                        self.Som(interfaces , path)
                        print("Found: Arduino Nano Ble in Connected Dev")
                    elif adr_name_Conn_inDev and arduinoName_isCorrect and not isConnected:
                        print("Not found in connected Devices")
                        print("Connecting...")
                        self.connect(path)
                        if self.isConnected(path):
                            self.ArdunoBleD.Name = bluetooth_utils.dbus_to_python(dev['Name'])
                            self.ArdunoBleD.Address = bluetooth_utils.dbus_to_python(dev['Address'])
                            # self.ArdunoBleD.RSSI = bluetooth_utils.dbus_to_python(dev['RSSI'])
                            self.ArdunoBleD.Path = path
                            self.Som(interfaces, path)



                    # if 'Address' in dev:
                    #     print("EXI bdaddr: ", bluetooth_utils.dbus_to_python(device_properties['Address']))
                    # if 'Name' in device_properties:
                    #     print("Name: ", bluetooth_utils.dbus_to_python(device_properties['Name']))
                    # if 'Connected' in device_properties:
                    #     print("Con: ", bluetooth_utils.dbus_to_python(device_properties['Connected']))





    def isConnected(self, device_path):
        bus = self.bus
        proxy = bus.get_object(bluetooth_constants.BLUEZ_SERVICE_NAME, device_path)
        interface = dbus.Interface(proxy, 'org.freedesktop.DBus.Properties')
        print("----------------")
        return interface.Get(bluetooth_constants.DEVICE_INTERFACE, 'Connected')


    def connect(self, device_path):
        bus = self.bus

        device_proxy = bus.get_object(bluetooth_constants.BLUEZ_SERVICE_NAME, device_path)
        device_interface = dbus.Interface(device_proxy, bluetooth_constants.DEVICE_INTERFACE)
        #p_interface = dbus.Interface(device_proxy, bluetooth_constants.DEVICE_INTERFACE)
        try:
            device_interface.Connect()
        except Exception as e:
            print("Failed to connect")
            print(e.get_dbus_name())
            print(e.get_dbus_message())
            if ("UnknownObject" in e.get_dbus_name()):
                print("Try scanning first to resolve this problem")
                return bluetooth_constants.RESULT_EXCEPTION
        else:
            print("Connected OK")
            return bluetooth_constants.RESULT_OK

    def interfaces_added(self, path, interfaces):
        # interfaces is an array of dictionary entries
        if not bluetooth_constants.DEVICE_INTERFACE in interfaces:
            return

        device_properties = interfaces[bluetooth_constants.DEVICE_INTERFACE]
        print(path)
        if path not in devices:
            print("NEW path :", path)
            devices[path] = device_properties
            dev = devices[path]

            if ('Address' and 'Name' and 'RSSI' in dev) and self.defD.ArdBleName in bluetooth_utils.dbus_to_python(
                    dev['Name']):

                self.connect(path)
                if self.isConnected(path):
                    self.ArdunoBleD.Name = bluetooth_utils.dbus_to_python(dev['Name'])
                    self.ArdunoBleD.Address = bluetooth_utils.dbus_to_python(dev['Address'])
                    self.ArdunoBleD.RSSI = bluetooth_utils.dbus_to_python(dev['RSSI'])
                    self.ArdunoBleD.Path = path
                    self.Som(interfaces, path)
                # self.ArdunoBleD.Name = bluetooth_utils.dbus_to_python(dev['Name'])
                # self.ArdunoBleD.Address = bluetooth_utils.dbus_to_python(dev['Address'])
                # self.ArdunoBleD.RSSI = bluetooth_utils.dbus_to_python(dev['RSSI'])
                # self.ArdunoBleD.Path = path
                print("Found: Arduino Nano Ble")

                self.discovery_timeout()
        print("------------------------------")

    def interfaces_removed(self, path, interfaces):

        # interfaces is an array of dictionary strings in this signal
        if not bluetooth_constants.DEVICE_INTERFACE in interfaces:
            return
        if path in devices:
            dev = devices[path]
        if 'Address' in dev:
            print("DEL bdaddr: ",
              bluetooth_utils.dbus_to_python(dev['Address']))
        else:
            print("DEL path : ", path)
        print("Rem",path)
        del devices[path]

    def discovery_timeout(self):
        global adapter_interface

        global mainloop
        global timer_id
        GLib.source_remove(timer_id)
        mainloop.quit()
        adapter_interface.StopDiscovery()
        bus = dbus.SystemBus()
        bus.remove_signal_receiver(self.interfaces_added, "InterfacesAdded")
        bus.remove_signal_receiver(self.interfaces_removed, "InterfacesRemoved")
        return True

    def read_temperature(self):


        char_interface = self.char_interface
        try:
            self.value = char_interface.ReadValue({})
        except Exception as e:
            print("Failed to read temperature")
            print(e.get_dbus_name())
            print(e.get_dbus_message())
            return bluetooth_constants.RESULT_EXCEPTION
        # else:
        #     self.temperature = bluetooth_utils.dbus_to_python(self.value[0])
        #     #print("Temperature=" + str(self.temperature ) + "C")
        #     return bluetooth_constants.RESULT_OK


    def discover_devices(self, bus, timeout):
        global adapter_interface
        global mainloop
        global timer_id


        # acquire an adapter proxy object and its Adapter1 interface so we can
        # call its methods
        adapter_object = bus.get_object(bluetooth_constants.BLUEZ_SERVICE_NAME, self.adapter_path)
        adapter_interface = dbus.Interface(adapter_object, bluetooth_constants.ADAPTER_INTERFACE)
        # register signal handler functions so we can asynchronously report
        # discovered devices
        # InterfacesAdded signal is emitted by BlueZ when an advertising packet
        # from a device it doesn't
        # already know about is received
        bus.add_signal_receiver(self.interfaces_added, dbus_interface=bluetooth_constants.DBUS_OM_IFACE,
                                signal_name="InterfacesAdded")
        bus.add_signal_receiver(self.interfaces_removed,
                                dbus_interface=bluetooth_constants.DBUS_OM_IFACE,
                                signal_name="InterfacesRemoved")

        mainloop = GLib.MainLoop()
        timer_id = GLib.timeout_add(timeout, self.discovery_timeout)
        adapter_interface.StartDiscovery(byte_arrays=True)
        mainloop.run()
import time
if __name__ == '__main__':

    defD = defData()
    Dev = bleScan(defD)

    while(True):
        if hasattr(Dev.ArdunoBleD, 'Name') and Dev.isConnected(Dev.ArdunoBleD.Path):
            time1 = time.time()
            Dev.read_temperature()
            print("hmm", Dev.value)
            s = struct.unpack('8f', bytearray(Dev.value))
            print(s)
            dt2 = time.time() - time1
            print(dt2)
        else:
            print("Er")

Arduino的产量为贝娄。

代码语言:javascript
运行
复制
start   309.000000  52.000000   0.033325    0.993530    -0.032715   0.329590    -1.257324   -1.013184   end
start   310.000000  50.000000   0.033569    0.993408    -0.034668   0.305176    -1.354980   -2.331543   end

起始和结束之间的8个数字是Arduino通过蓝牙发送的8个浮点数,第一个浮点数是迭代的,第二个是ms中一个循环的执行时间。

Python代码的输出如下所示。

代码语言:javascript
运行
复制
hmm dbus.Array([dbus.Byte(0), dbus.Byte(0), dbus.Byte(234), dbus.Byte(60), dbus.Byte(0), dbus.Byte(56), dbus.Byte(126), dbus.Byte(63), dbus.Byte(0), dbus.Byte(128), dbus.Byte(101), dbus.Byte(189), dbus.Byte(0), dbus.Byte(128), dbus.Byte(59), dbus.Byte(62), dbus.Byte(0), dbus.Byte(32), dbus.Byte(25), dbus.Byte(191), dbus.Byte(0), dbus.Byte(224), dbus.Byte(43), dbus.Byte(191), dbus.Byte(0), dbus.Byte(0), dbus.Byte(72), dbus.Byte(66), dbus.Byte(0), dbus.Byte(104), dbus.Byte(178), dbus.Byte(69)], signature=dbus.Signature('y'))
(0.028564453125, 0.9930419921875, -0.0560302734375, 0.18310546875, -0.59814453125, -0.67138671875, 50.0, 5709.0)
0.09242081642150879
----------------


hmm dbus.Array([dbus.Byte(0), dbus.Byte(0), dbus.Byte(231), dbus.Byte(60), dbus.Byte(0), dbus.Byte(144), dbus.Byte(126), dbus.Byte(63), dbus.Byte(0), dbus.Byte(128), dbus.Byte(99), dbus.Byte(189), dbus.Byte(0), dbus.Byte(0), dbus.Byte(97), dbus.Byte(190), dbus.Byte(0), dbus.Byte(128), dbus.Byte(9), dbus.Byte(191), dbus.Byte(0), dbus.Byte(160), dbus.Byte(215), dbus.Byte(191), dbus.Byte(0), dbus.Byte(0), dbus.Byte(68), dbus.Byte(66), dbus.Byte(0), dbus.Byte(120), dbus.Byte(178), dbus.Byte(69)], signature=dbus.Signature('y'))
(0.0281982421875, 0.994384765625, -0.0555419921875, -0.2197265625, -0.537109375, -1.6845703125, 49.0, 5711.0)
0.092437744140625
----------------
EN

回答 1

Stack Overflow用户

发布于 2022-02-07 20:42:39

要加快速度,请在RPi端使用指示或通知。这是GATT客户订阅GATT服务器提供的数据的一种方式。通知是未确认的消息或更新,而指示是确认的消息或更新。由于您将非常频繁地进行更新,因此使用通知似乎是明智的。这将在MainLoop中完成,而不是在While循环中完成。这在BlueZ GATT API https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/gatt-api.txt#n181中有介绍。

这应该足以让你得到你想要的提速。如果您还需要更多,那么就会有AcquireNotify。

BlueZ D总线在执行通知时会通过不同的OS层,这会减慢数据更新的速度。为了克服这一问题,在以后的版本中,BlueZ引入了AcquireNotify,它打开一个套接字来绕过一些层来加快速度。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71024303

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档