STMicroelectronics / BlueSTSDK_Android

Bluetooth low energy Sensors Technology Software Development Kit (Android version)
https://www.st.com/en/embedded-software/bluest-sdk.html
BSD 3-Clause "New" or "Revised" License
92 stars 46 forks source link

High frequency streaming #14

Closed rbrondi closed 6 years ago

rbrondi commented 6 years ago

Hi all,

I've started using the library to interact with a BlueCoin and a SensorTile boards. So far I successfully connect to the board, receive battery information and stream gyro and accelerometer data from both boards at the same time.

I've recorded accelerations and angular velocities for some seconds and the data rate varies between 20hz and 45hz. Is there a way to set the desired frequencies for both the sensors using the BlueSTSDK library? Which is the maximum throughput for the two boards? How can I maximize the data throughput?

For the project I'm working on, it is crucial to receive data from 3 up to 5 IMUs simultaneously at about 50hz. I've read in other posts that on Android a way to maximize the throughput of the BLE is to set the max connection interval to 11,5ms (or 7,5ms depending on the OS version). Is there a way to set this parameter using the BlueSTSDK library?

Thanks Raffaello

GiovanniVisentiniST commented 6 years ago

Hi Raffaello,

I'm sorry but for both the question the answer is no. From the library point of view you just enable the notification, the update frequency is decided by the firmware. To change the connection interval, in theory you can request a connection interval from android using this method: requestConnectionPriority but I didn't use it because I can not control what means "high priority". We change the connection interval from the firmware using the function: aci_l2cap_connection_parameter_update_request. We use it in the FP-SNS-ALLMEMS1 when we transmit the audio data from the sensor tile/bluecoin. If I remember well we set it to 11.5 because not all device (and ios) where supporting lower configuration.

Note that the accelerometer and gyroscope data are transmitted together with the magnetometer data. If you don't need the magnetometer and you need an high frequency I will consider to remove the magnetometer data (changing the characteristics uuid and format) so save bandwidth.

Best Regards Giovanni

rbrondi commented 6 years ago

Hi Vincenzo, thanks for your reply.

I tried to edit the ALLMEMS firmware in order to change the max connection interval parameter. I've downloaded the sample code, compiled it and flashed the board. Everything works fine. Then I tryed to change the BLE max connection interval. If I'm not wrong, you change it using the aci_l2cap_connection_parameter_update_request function inside sensor_service.c@1452. I tryed to call the function with the same parameters just outside the if statement (if(TargetBoardFeatures.AudioBVIsInitalized){).

The function is called when I connect to the board returning a BLE_STATUS_SUCCESS status (I switched on a led upon success). But when I try to interact with the board with the application I receive an error.

D/BluetoothGatt: onClientConnParamsChanged() - Device=C0:83:28:31:57:XX interval=12 status=0
W/BluetoothGatt: onCharacteristicRead() - Device=C0:85:4A:37:54:XX handle=26 Status=133
E/com.st.BlueSTSDK.Node: Error reading the characteristics: android.bluetooth.BluetoothGattCharacteristic@48e4462
                         Error connecting to the node:null
D/BluetoothGatt: close()
D/BluetoothGatt: unregisterApp() - mClientIf=7
W/STConnection: onStateChange: new state Dead
D/BluetoothGatt: onClientConnectionState() - status=8 clientIf=7 device=C0:85:4A:37:54:XX
W/BluetoothGatt: Unhandled exception in callback
                 java.lang.NullPointerException: Attempt to invoke virtual method 'void android.bluetooth.BluetoothGattCallback.onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)' on a null object reference
                     at android.bluetooth.BluetoothGatt$1.onClientConnectionState(BluetoothGatt.java:228)
                     at android.bluetooth.IBluetoothGattCallback$Stub.onTransact(IBluetoothGattCallback.java:70)
                     at android.os.Binder.execTransact(Binder.java:573)

I don't know if this is the place where asking for this kind of support. If not, can you please tell me where I can ask? Thanks a lot. Raffaello

GiovanniVisentiniST commented 6 years ago

It is strange that the node is null.. Can you post the line from the connection to the error? It is happening in your application or in the example application? Could you try also the example application?

In the meantime I will check with the Fw people if your change is correct.

Best Regards Giovanni

rbrondi commented 6 years ago

Good morning Vincenzo. Yesterday I wrongly assumed that the if statement where the library sets the intervals was not executed by default. Today I verified instead that the code is alway called. So probably the issue was related to a double call to aci_l2cap_connection_parameter_update_request.

I removed the call to aci_l2cap_connection_parameter_update_request function I inserted yesterday and I tried to change the original values (sensor_service.c@1452):

ret = aci_l2cap_connection_parameter_update_request(handle,
                                                  8 /* interval_min*/,
                                                  17 /* interval_max */,
                                                  0   /* slave_latency */,
                                                  400 /*timeout_multiplier*/);

Setting interval_max to a lower(11) or greater(110) value did not change the data rate on the tablet.

I then tried to remove the magnetometer values from the BLE package editing the function AccGyroMag_Update in sensor_service.c:

tBleStatus AccGyroMag_Update(SensorAxes_t *Acc,SensorAxes_t *Gyro,SensorAxes_t *Mag)
{  
  tBleStatus ret;
  int32_t AXIS_X;
  int32_t AXIS_Y;
  int32_t AXIS_Z;

  const size_t buff_dim = 2+3*2*2;

//  uint8_t buff[2+3*3*2];
  uint8_t buff[buff_dim];

  STORE_LE_16(buff   ,(HAL_GetTick()>>3));

  STORE_LE_16(buff+2 ,Acc->AXIS_X);
  STORE_LE_16(buff+4 ,Acc->AXIS_Y);
  STORE_LE_16(buff+6 ,Acc->AXIS_Z);

  Gyro->AXIS_X/=100;
  Gyro->AXIS_Y/=100;
  Gyro->AXIS_Z/=100;

  STORE_LE_16(buff+8 ,Gyro->AXIS_X);
  STORE_LE_16(buff+10,Gyro->AXIS_Y);
  STORE_LE_16(buff+12,Gyro->AXIS_Z);

  /* Apply Magneto calibration */
  /*AXIS_X = Mag->AXIS_X - MAG_Offset.AXIS_X;
  AXIS_Y = Mag->AXIS_Y - MAG_Offset.AXIS_Y;
  AXIS_Z = Mag->AXIS_Z - MAG_Offset.AXIS_Z;

  STORE_LE_16(buff+14,AXIS_X);
  STORE_LE_16(buff+16,AXIS_Y);
  STORE_LE_16(buff+18,AXIS_Z);
*/
//  ret = ACI_GATT_UPDATE_CHAR_VALUE(HWServW2STHandle, AccGyroMagCharHandle, 0, 2+3*3*2, buff);
  ret = ACI_GATT_UPDATE_CHAR_VALUE(HWServW2STHandle, AccGyroMagCharHandle, 0, buff_dim, buff);

  if (ret != BLE_STATUS_SUCCESS){
    if(W2ST_CHECK_CONNECTION(W2ST_CONNECT_STD_ERR)){
      BytesToWrite =sprintf((char *)BufferToWrite, "Error Updating Acc/Gyro/Mag Char\r\n");
      Stderr_Update(BufferToWrite,BytesToWrite);
    } else {
      ALLMEMS1_PRINTF("Error Updating Acc/Gyro/Mag Char\r\n");
    }
    return BLE_STATUS_ERROR;
  }
  return BLE_STATUS_SUCCESS;    
}

The result was the same (frequencies are still lower than 50Hz). My final attempt was to disable all the unneeded sensors in the Init_MEM1_Sensors function, but still no luck.

Could you please help me in trying to increase the sensor data rate?

Thanks, Raffaello

GiovanniVisentiniST commented 6 years ago

Hi Raffaelo,

First of all my name is Giovanni, not Vincenzo :)

Then:

Best Regards Giovanni

rbrondi commented 6 years ago

Hi Giovanni,

I really apologize for the mistake. I absolutely don't know why I called you Vincezo..so embarassing :S

Thanks again for your inputs. I've successfully increased the data rate by changing the value of the variable DEFAULT_uhCCR4_Val

Now I'm trying to understand how to interpret the data I'm receiving on the mobile device. Looking at the datasheet of the sensor LSM6DSM and the source code of the firmware, looks like that the sensors are streaming accelerations using mG and angular velocities using mdps measurement units. Is it right?

In my application I need to work with accelerations expressed in g and angular velocities expressed in dps. So I thought to just multiply each sample component by 0.001. When I looked at FeatureGyroscope source code(line 130) I've seen that each component is multiplied by 0.1 while no conversion is applied to acceleration data in FeatureAcceleration (line 142). Is my assumption wrong? Why did you multiply angular velocity components by 0.1?

As regard as the null value for the node name I think the problem is related to the fact that I'm manually creating a Node instance for each sensor I've to connect. The application I'm developing needs to directly connect to the sensors without making a previous scan. Looking at the BlueSTSDK code I've seen that to obtain an instance of a Node you need to interact with the Manager class which mantains a list of discovered node. Since the list is empty in my case, to create a new Node I used the same code of the test suit :

private Node createNode(BluetoothDevice device) {
        //taken from ST test suit. Create a generic ble node using a default advertisement array
        byte[] advertisement = new byte[]{0x07, (byte) 0xFF, (byte) 0x01, (byte) 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF};

        try {
            return  new Node(device, 10, advertisement);
        } catch (InvalidBleAdvertiseFormat invalidBleAdvertiseFormat) {
            //should never happen
            throw new RuntimeException(invalidBleAdvertiseFormat);
        }
    }

Is this wrong? Is there a better way to achive the result?

Thanks a lot Raffaello

GiovanniVisentiniST commented 6 years ago

Hi Raffaello,

to know the units you can see the FEATURE_UNIT constant in the feature class. for the Accelorometer when you use the getAccX() method, you have the data in mg. for the Gyroscope when you use the getGyroX() method you have the data in dps. I'm dividing by 10 because we send also 1 decimal position.

if you create the node by hand you can add it to the manager with the addNode method.

Giovanni