matlab SimulinkのBLE functionを作ってみた　備忘録

　Simulinkには、BLEのブロックがありません。BLEのセントラルを作ります。
###センサのデータを送るペリフェラル
　Arduino Nano 33 BLE senseボードには、 9軸IMUのLSM9DS1が搭載されています。このボードで、ペリフェラルを作ります。

<img width="400" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/ad451eb6-70b7-4f39-320d-7c9c8529e64f.png">


　キャラクタUUIDはAcceleration、Gyroscope、Magneticの三つです。次のように、それぞれx、y、zは、カンマで区切ってテキストで送ります。
　　 ``0.12,34.56,7.89``

```C

#include <Arduino_LSM9DS1.h>
#include <ArduinoBLE.h>

// LSM9DS1

// BLE Service
#define Nano33BLESense_Service7_UUID   "F000AE00-0451-4000-B000-000000000000"
BLEService Nano33BLESense_Service7(Nano33BLESense_Service7_UUID);

// BLE  Characteristic
#define LSM9DS1_Acceleration_Characteristic_UUID    "F000AE01-0451-4000-B000-000000000000"
#define LSM9DS1_Gyroscope_Characteristic_UUID    "F000AE02-0451-4000-B000-000000000000"
#define LSM9DS1_Magnetic_Characteristic_UUID    "F000AE03-0451-4000-B000-000000000000"
BLEStringCharacteristic    LSM9DS1_Acceleration(LSM9DS1_Acceleration_Characteristic_UUID, BLERead | BLENotify, 37);
BLEStringCharacteristic    LSM9DS1_Gyroscope(LSM9DS1_Gyroscope_Characteristic_UUID, BLERead | BLENotify, 37);
BLEStringCharacteristic    LSM9DS1_Magnetic(LSM9DS1_Magnetic_Characteristic_UUID, BLERead | BLENotify, 37);


// BLE  Descriptor
#define LSM9DS1_Acceleration_Descriptor_UUID    "2901"
#define LSM9DS1_Gyroscope_Descriptor_UUID       "2901"
#define LSM9DS1_Magnetic_Descriptor_UUID        "2901"
BLEDescriptor   LSM9DS1_Acceleration_Descriptor(LSM9DS1_Acceleration_Descriptor_UUID, "Hz  Acceleration in G's  X  Y  Z");
BLEDescriptor   LSM9DS1_Gyroscope_Descriptor(LSM9DS1_Gyroscope_Descriptor_UUID, "Hz  Gyroscope in degrees/second  X  Y  Z");
BLEDescriptor   LSM9DS1_Magnetic_Descriptor(LSM9DS1_Magnetic_Descriptor_UUID, "uT  Magnetic Field in uT X  Y  Z");

#define localNAME  "LSM9DS1"
#define DeviceNAME "LSM9DS1_BLE"

float previousMillis = 0;  // last time value was checked, in ms

void setup() {
  Serial.begin(9600);
  while (!Serial);
  Serial.println("\nStarted\n");

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

  Serial.print("Accelerometer sample rate = ");
  Serial.print(IMU.accelerationSampleRate());
  Serial.println("Hz  Acceleration in G's X\tY\tZ");

  Serial.print("Gyroscope sample rate = ");
  Serial.print(IMU.gyroscopeSampleRate());
  Serial.println("Hz  Gyroscope in degrees/second X\tY\tZ");

  Serial.print("Magnetic field sample rate = ");
  Serial.print(IMU.magneticFieldSampleRate());
  Serial.println("uT  Magnetic Field in uT X\tY\tZ");

  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");
    while (1);
  }

  BLE.setLocalName(localNAME);
  BLE.setDeviceName(DeviceNAME);

  //// set the service
  BLE.setAdvertisedService(Nano33BLESense_Service7);

  // add characteristic
  Nano33BLESense_Service7.addCharacteristic(LSM9DS1_Acceleration);
  Nano33BLESense_Service7.addCharacteristic(LSM9DS1_Gyroscope);
  Nano33BLESense_Service7.addCharacteristic(LSM9DS1_Magnetic);
  
  // add descriptor
  LSM9DS1_Acceleration.addDescriptor(LSM9DS1_Acceleration_Descriptor);
  LSM9DS1_Gyroscope.addDescriptor(LSM9DS1_Gyroscope_Descriptor);
  LSM9DS1_Magnetic.addDescriptor(LSM9DS1_Magnetic_Descriptor);
    
  // add service
  BLE.addService(Nano33BLESense_Service7);
  
  // start advertising
  BLE.advertise();
  Serial.println("\nBluetooth device active, waiting for connections...");
}

void loop() {
  // wait for a BLE central
  BLEDevice central = BLE.central();

  // if a central is connected to the peripheral:
  if (central) {
    delay(100);
    Serial.print("\n Connected to central: ");
    // print the central's BT address:
    Serial.println(central.address());

    // check data every 200ms
    // while the central is connected:
    while (central.connected()) {
      long currentMillis = millis();
      // if 200ms have passed, check value:
      if (currentMillis - previousMillis >= 200) {
        previousMillis = currentMillis;
        updateValue();
        delay(1000);
      }
    }
    // when the central disconnects
    Serial.print("Disconnected from central: ");
    Serial.println(central.address());
    goto brout;
  }
  brout: ;
}

void updateValue() {
  float xa, ya, za, xg, yg, zg, xm, ym, zm;
  Serial.println("");
  if (IMU.accelerationAvailable()) {
    IMU.readAcceleration(xa, ya, za);
    
    Serial.println("acceleration "+String(xa)+'\t'+String(ya)+'\t'+String(za));
  }
  if (IMU.gyroscopeAvailable()) {
    IMU.readGyroscope(xg, yg, zg);
    Serial.println("gyroscope    "+String(xg)+'\t'+String(yg)+'\t'+String(zg));
    }
  if (IMU.magneticFieldAvailable()) {
    IMU.readMagneticField(xm, ym, zm);
    Serial.println("magneticField "+String(xm)+'\t'+String(ym)+'\t'+String(zm));
  }
  // update  characteristic
  LSM9DS1_Acceleration.writeValue(String(xa)+","+String(ya)+","+String(za));
  LSM9DS1_Gyroscope.writeValue(String(xg)+","+String(yg)+","+String(zg));
  LSM9DS1_Magnetic.writeValue(String(xm)+","+String(ym)+","+String(zm));
}
```


　つながったときのシリアルモニタの様子です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/41e52036-6e9b-d368-4f6b-569183459929.png)

###セントラル
　Arduino Nano 33 BLE senseボードとの接続は、事前に調べたアドレスで行っています。
　% initialize outputに記述したの三つの出力変数の初期化は、正しくない記述のような気がします。
　このファンクションに入力はないです。出力は三つです。
　persistentは永続変数の定義で、空の行列 ([]) に初期化されます。
　coder.extrinsicで定義された命令は、本体のコードを生成せず、代わりに MATLABエンジンを使用して呼び出しを実行します。
　Accelerationは、gの単位で送られてきたのをm/s^2に換算しています。


```matlab
function [Acceleration, Gyroscope, MagneticField] = fcn()
      % automatically initialized to []
      persistent b;    
      persistent g11; 
      persistent g12; 
      persistent g13; 
      % extrinsic declarations
      coder.extrinsic('ble');
      coder.extrinsic('characteristic');
      coder.extrinsic('read');
      coder.extrinsic('subscribe');
      coder.extrinsic('split');

      if(isempty(b))
          Nano33BLE_address="88A2EDC9F60C";
          b = ble(Nano33BLE_address);
          ServiceUUID    = "F000AE00-0451-4000-B000-000000000000";
          LSM9DS1_Acceleration_Characteristic_UUID  =  "F000AE01-0451-4000-B000-000000000000";
          LSM9DS1_Gyroscope_Characteristic_UUID     =  "F000AE02-0451-4000-B000-000000000000";
          LSM9DS1_MagneticField_Characteristic_UUID =  "F000AE03-0451-4000-B000-000000000000";

          g11 = characteristic(b, ServiceUUID, LSM9DS1_Acceleration_Characteristic_UUID);
          subscribe(g11);  % Notify
          g12 = characteristic(b, ServiceUUID, LSM9DS1_Gyroscope_Characteristic_UUID);
          subscribe(g12);
          g13 = characteristic(b, ServiceUUID, LSM9DS1_MagneticField_Characteristic_UUID);
          subscribe(g13);
      end

      % initialize output
      Acceleration=[0 0 0];
      Gyroscope=[0 0 0];
      MagneticField=[0 0 0];

      accelerationXYZ = char(read(g11));
      dataA = split(accelerationXYZ, ",");
      aX = dataA(1);
      aY = dataA(2);
      aZ = dataA(3);
      Acceleration = [str2double(aX)*9.8 str2double(aY)*9.8 str2double(aZ)*9.8];

      gyroscopeXYZ = char(read(g12));
      dataG = split(gyroscopeXYZ, ",");
      gX = dataG(1);
      gY = dataG(2);
      gZ = dataG(3);
      Gyroscope = [str2double(gX), str2double(gY), str2double(gZ)];

      magneticFieldXYZ = char(read(g13));
      dataM = split(magneticFieldXYZ, ",");
      mX = dataM(1);
      mY = dataM(2);
      mZ = dataM(3);
      MagneticField = [str2double(mX), str2double(mY), str2double(mZ)];
end
```

　実行している様子です。
![2021-11-22 (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/2d74cbda-ea19-1b7a-8e22-e765fc160fbf.png)

###環境
Arduino IDEは1.8.16
matlabはR2021b update1
Simulinkはバージョン10.4
Windows10 21H2