「RedBear」タグアーカイブ

hackster.io への投稿方法

hacksterは自作ハードウェア作品の紹介記事やデバイスやツールの使用方法を投稿できるコミュニケーションサイトです。

[bc url =”https://www.hackster.io/”]

FacebookやTwitter等のSNSアカウントでもアカウント登録可能です。
様々な電子作品やツールの応用の記事が世界中から投稿されていて非常に勉強になりますし、後ほど詳細記載しますが投稿したりイイねされたりするとポイントが貰えてギフト券に交換できたりします。

現在(2018/11/15)、reputation pointsによる景品交換制度はなくなってしまいました。残念。。。

あと拡散力が半端ないので電子作品の発表の場にお悩みの方は是非おすすめのサイトです。英語がネックですが。。。

我々にはGoogle翻訳がついている!

投稿方法

サイト上部やプロフィールページの”+ New project”をクリックで新規記事の投稿できます。

  1. The basics

    こちらで記事題名と概要を記載し、サムネイル画像アップロードします。

  2. The team

    複数名での作品の場合はここでメンバー情報を記載します。

  3. Things

    ここでは使用部品の型番や購入先のURLの記載や使用ソフトウェア、ツールを記載します。

  4. The story

    こちらに本文を記載します。画像や動画、コードを交えて記載できます。動画はvineでも投稿できます。

  5. Attachments

    ここではソースコード、回路図、ブロック図、CADデータが追加できます。ここで追加したデータは閲覧者が直接DLできます。

  6. Publication settings

    記事の中身がそろったらいよいよ投稿です。ここでは記事のタイプの選択、難易度、カテゴリー、公開範囲など指定して投稿を終了します。

以前は運営の記事チェックと修正指摘があれば直して ようやく公開だったのですが今はノーチェックで公開されます。

reputation points

hacksterに投稿する最大のメリットはポイントが有ることです。ポイント取得方法は以下のとおりです。

  • 記事投稿・公開で1つにつき50pt
  • 投稿記事にイイね(respect)1つ付くごとに5pt
  • 投稿記事のビュー数が1000以下では100ビューごとに5pt、10000ビューで50pt
  • hacksterサイトにサインアップごとに1pt

 

ポイントは景品に交換できます。
[bc url = “https://www.hackster.io/store”]
魅力的な商品があるのですが残念ながらハードウェアへの交換はUS在住者のみ。

しかしAdafruitやSparkFunの$10ギフト券は非常に魅力です! 200ptで交換できます。この手のサイトは国内で手に入らないモノを購入する際に利用するのですが送料がバカ高い。。。最低でも$20でトラッキングできる方法だと$60くらい。。ですのでこのギフトは非常に有益だと思います。4つ作品投稿するだけで$10ゲットですから。

ちなみに私の現状のポイントは以下の通り。ギフト$60分に達しました!わーい!送料うくー!送料!送料!送料。。。。

コンテスト

hacksterは定期的に指定のプラットフォームやツールを使用したコンテストが開催されています。景品や賞金が豪華なものが多いのでマッチするものがあれば是非参加してみたいと思っています。

[bc url=”https://www.hackster.io/contests”]

圧倒的な拡散力

投稿するとhackster登録者の興味に応じてメールで通知されたり、公式Twitterで拡散されていきます。

Makerに馴染みの深いソフトウェアやハードウェアメーカとの連携も非常に強く、hacksterに投稿の際に使用プラットフォームにArduinoを指定すると自動的にArduinoの公式Project Hubにも投稿されます。

[bc url =”https://create.arduino.cc/projecthub”]

場合によってはArduino公式Twitterで紹介されたりもします。

 

Adafruitの製品を使用して投稿するとAdafruit公式ブログに掲載される場合もあります。

https://blog.adafruit.com/2016/06/08/this-crazy-police-hat-will-make-you-laugh-wearablewednesday/#comments

 

また最近Make:との連携もスタートしました。
[bc url =”http://makezine.jp/blog/2016/10/share-your-project.html”]

[bc url =”https://community.makezine.com/share”]

こちらは自動連携ではないのですがhacksterで公開されてる場合は簡単に投稿できます。

hackster.ioのアカウントでログインできます。”+ New project”をクリックで投稿画面に入ります。
Import from your Hackster.io profileで投稿済みのプロジェクトを選択し、カテゴリー指定するだけで投稿終了です。

 

ちなみに私のhacksterプロフィールページは以下です。
[bc url = “https://www.hackster.io/H0meMadeGarbage”]

日本でもこういったサイトができるといいなぁ 🙄 

ワウペダルと加速度センサでBLE制御ラジコン!

以前スマホでコントロールするラジコンを作ったのですが。。。

Blynk で BLE 制御ラジコン!

やっぱり物理コントローラで動かしてみたくなりハンドルに加速度センサ、アクセルに大昔に買ったワウペダルを使ってコントローラつくりました♪コントローラと車の通信にはBLEを使用しました。
 
ワウペダルはウルフルズのガッツだぜをコピーしたくて買ったんだったなぁ。。もう20年前か。。。。

構成

部品

  •  Redbearlab BLE Nano
     
  • Redbear Duo
     
  • 6DOF MPU-6050
    [amazonjs asin=”B081RHK82T” locale=”JP” title=”KKHMF 2個 MPU-6050 6DOF GY-521 MPU6050 3軸ジャイロスコープ + 加速度センサーモジュール Arduino用”]
     
  • Motor Driver DRV8835
    [amazonjs asin=”B014GZ9JTC” locale=”JP” title=”HiLetgo 3pcs DRV8833デュアルモータードライバー”]
     
  • JIM DUNLOP wah pedal CRYBABY
    [amazonjs asin=”B00SKJGWCI” locale=”JP” title=”JIM DUNLOP ワウペダル CBM95 CRYBABY”]

車体

BLEとWiFiを搭載したマイコンRedBear Duoを使用しコントローラ情報を受信(BLE Central)し、モータを制御します。今回はWiFi使用しないのでBLE Nanoでも良かったのですがNanoはPWM出力できないのでPWM出力端子のあるDuoを贅沢に使用!

コントローラ

BLE搭載マイコンBLE Nanoを使用して車体と通信(BLE Peripheral)しています。

ハンドル(現状タッパのフタ。。。ww)の傾きを6軸モーションセンサMPU6050のy軸(水平方向)の加速度で検出しBLE Nanoに送信。

アクセルとしてワウペダルを使用しました。

ワウペダル内の可変抵抗に配線引っ張ってBLE Nanoに接続してペダルの踏み込みを検知します。中ホコリだらけだった。。。

 

BLE NanoとDuoの詳細は以下にも記載しております。

BLE Nano – Redbear Duo間通信でモータ制御 -球体POV製作への道 その4-

動作

ワウペダルを踏み込むと加速します!

 
ハンドルを切ると曲がります!

 

Arduino IDE用コード

Redbear Duo (Central)
以下をベースに生成
 
#if defined(ARDUINO) 
SYSTEM_MODE(SEMI_AUTOMATIC); 
#endif

/* 
 * BLE scan parameters:
 *     - BLE_SCAN_TYPE     
 *           0x00: Passive scanning, no scan request packets shall be sent.(default)
 *           0x01: Active scanning, scan request packets may be sent.
 *           0x02 - 0xFF: Reserved for future use.
 *     - BLE_SCAN_INTERVAL: This is defined as the time interval from when the Controller started its last LE scan until it begins the subsequent LE scan.
 *           Range: 0x0004 to 0x4000
 *           Default: 0x0010 (10 ms)
 *           Time = N * 0.625 msec
 *           Time Range: 2.5 msec to 10.24 seconds
 *     - BLE_SCAN_WINDOW: The duration of the LE scan. The scan window shall be less than or equal to the scan interval.
 *           Range: 0x0004 to 0x4000
 *           Default: 0x0010 (10 ms)
 *           Time = N * 0.625 msec
 *           Time Range: 2.5 msec to 10240 msec
 */
#define BLE_SCAN_TYPE        0x00   // Passive scanning
#define BLE_SCAN_INTERVAL    0x0060 // 60 ms
#define BLE_SCAN_WINDOW      0x0030 // 30 ms

int mpuVol;
uint8_t wpVol = 0; //Wah pedal値

int L = D8;
int R = D9;

/******************************************************
 *                      Type Define
 ******************************************************/
typedef struct {
  uint16_t  connected_handle;
  uint8_t   addr_type;
  bd_addr_t addr;
  struct {
    gatt_client_service_t service;
    struct {
      gatt_client_characteristic_t chars;
      gatt_client_characteristic_descriptor_t descriptor[2]; // User_descriptor and client charactersitc configuration descriptor.
    } chars[2];  
  } service; // Service contains two characteristics and each characteristic contains two descriptors.
} Device_t;

/******************************************************
 *               Variable Definitions
 ******************************************************/
// Connect handle.
static uint16_t connected_id = 0xFFFF;

Device_t device;
uint8_t  chars_index = 0;
uint8_t  desc_index = 0;

// The service uuid to be discovered.
static uint8_t service1_uuid[16] = { 0x71,0x3d,0x00,0x00,0x50,0x3e,0x4c,0x75,0xba,0x94,0x31,0x48,0xf1,0x8d,0x94,0x1e };

static uint8_t gatt_notify_flag = 0;

/******************************************************
 *               Function Definitions
 ******************************************************/
 /**
 * @brief Find the data given the type in advertising data.
 *
 * @param[in]  type          The type of field data.
 * @param[in]  advdata_len   Length of advertising data.
 * @param[in]  *p_advdata    The pointer of advertising data.
 * @param[out] *len          The length of found data.
 * @param[out] *p_field_data The pointer of buffer to store field data.
 *
 * @retval 0 Find the data
 *         1 Not find.
 */
uint32_t ble_advdata_decode(uint8_t type, uint8_t advdata_len, uint8_t *p_advdata, uint8_t *len, uint8_t *p_field_data) {
  uint8_t index = 0;
  uint8_t field_length, field_type;

  while (index < advdata_len) {
    field_length = p_advdata[index];
    field_type = p_advdata[index + 1];
    if (field_type == type) {
      memcpy(p_field_data, &p_advdata[index + 2], (field_length - 1));
      *len = field_length - 1;
      return 0;
    }
    index += field_length + 1;
  }
  return 1;
}

/**
 * @brief Callback for scanning device.
 *
 * @param[in]  *report
 *
 * @retval None
 */
void reportCallback(advertisementReport_t *report) {
  uint8_t index;

  Serial.println("reportCallback: ");
  Serial.print("The advEventType: ");
  Serial.println(report->advEventType, HEX);
  Serial.print("The peerAddrType: ");
  Serial.println(report->peerAddrType, HEX);
  Serial.print("The peerAddr: ");
  for (index = 0; index < 6; index++) {
    Serial.print(report->peerAddr[index], HEX);
    Serial.print(" ");
  }
  Serial.println(" ");

  Serial.print("The rssi: ");
  Serial.println(report->rssi, DEC);

  Serial.print("The ADV data: ");
  for (index = 0; index < report->advDataLen; index++) {
    Serial.print(report->advData[index], HEX);
    Serial.print(" ");
  }
  Serial.println(" ");
  Serial.println(" ");

  uint8_t len;
  uint8_t adv_name[31];
  // Find short local name.
  if (0x00 == ble_advdata_decode(0x08, report->advDataLen, report->advData, &len, adv_name)) {
    Serial.print("  The length of Short Local Name : ");
    Serial.println(len, HEX);
    Serial.print("  The Short Local Name is        : ");
    Serial.println((const char *)adv_name);
    if (0x00 == memcmp(adv_name, "TXRX", min(4, len))) {
      ble.stopScanning();
      device.addr_type = report->peerAddrType;
      memcpy(device.addr, report->peerAddr, 6);

      //ble.connect(report->peerAddr, report->peerAddrType);
      //ble.connect(report->peerAddr, BD_ADDR_TYPE_LE_PUBLIC);
      ble.connect(report->peerAddr, BD_ADDR_TYPE_LE_RANDOM);
    }
  }
}

/**
 * @brief Connect handle.
 *
 * @param[in]  status   BLE_STATUS_CONNECTION_ERROR or BLE_STATUS_OK.
 * @param[in]  handle   Connect handle.
 *
 * @retval None
 */
void deviceConnectedCallback(BLEStatus_t status, uint16_t handle) {
  RGB.color(0, 60, 25); //BLE接続時にLED水色
  switch (status) {
    case BLE_STATUS_OK:
      Serial.println("Device connected!");
      // Connect to remote device, start to discover service.
      connected_id = handle;
      device.connected_handle = handle;
      // Start to discover service, will report result on discoveredServiceCallback.
      ble.discoverPrimaryServices(handle);
      break;
    default: break;
  }
}

/**
 * @brief Disconnect handle.
 *
 * @param[in]  handle   Connect handle.
 *
 * @retval None
 */
void deviceDisconnectedCallback(uint16_t handle){
  RGB.color(100, 0, 0); //BLE非接続時にLED赤色
  analogWrite(L, LOW);
  analogWrite(R, LOW);
  Serial.print("Disconnected handle:");
  Serial.println(handle,HEX);
  if (connected_id == handle) {
    Serial.println("Restart scanning.");
    // Disconnect from remote device, restart to scanning.
    connected_id = 0xFFFF;
    ble.startScanning();
  }
}

/**
 * @brief Callback for handling result of discovering service.
 *
 * @param[in]  status      BLE_STATUS_OK/BLE_STATUS_DONE
 * @param[in]  con_handle  
 * @param[in]  *service    Discoverable service.
 *
 * @retval None
 */
static void discoveredServiceCallback(BLEStatus_t status, uint16_t con_handle, gatt_client_service_t *service) {
  uint8_t index;
  if (status == BLE_STATUS_OK) {   // Found a service.
    Serial.println(" ");
    Serial.print("Service start handle: ");
    Serial.println(service->start_group_handle, HEX);
    Serial.print("Service end handle: ");
    Serial.println(service->end_group_handle, HEX);
    Serial.print("Service uuid16: ");
    Serial.println(service->uuid16, HEX);
    Serial.print("The uuid128 : ");
    for (index = 0; index < 16; index++) {
      Serial.print(service->uuid128[index], HEX);
      Serial.print(" ");
    }
    Serial.println(" ");
    if (0x00 == memcmp(service->uuid128, service1_uuid, 16)) {
      Serial.println("Target uuid128");
      device.service.service = *service;
    }
  }
  else if (status == BLE_STATUS_DONE) {
    Serial.println("Discovered service done");
    // All sevice have been found, start to discover characteristics.
    // Result will be reported on discoveredCharsCallback.
    ble.discoverCharacteristics(device.connected_handle, &device.service.service);
  }
}

/**
 * @brief Callback for handling result of discovering characteristic.
 *
 * @param[in]  status           BLE_STATUS_OK/BLE_STATUS_DONE
 * @param[in]  con_handle  
 * @param[in]  *characteristic  Discoverable characteristic.
 *
 * @retval None
 */
static void discoveredCharsCallback(BLEStatus_t status, uint16_t con_handle, gatt_client_characteristic_t *characteristic) {
  uint8_t index;
  if (status == BLE_STATUS_OK) {   // Found a characteristic.
    Serial.println(" ");
    Serial.print("characteristic start handle: ");
    Serial.println(characteristic->start_handle, HEX);
    Serial.print("characteristic value handle: ");
    Serial.println(characteristic->value_handle, HEX);
    Serial.print("characteristic end_handle: ");
    Serial.println(characteristic->end_handle, HEX);
    Serial.print("characteristic properties: ");
    Serial.println(characteristic->properties, HEX);
    Serial.print("characteristic uuid16: ");
    Serial.println(characteristic->uuid16, HEX);
    Serial.print("characteristic uuid128 : ");
    for (index = 0; index < 16; index++) {
      Serial.print(characteristic->uuid128[index], HEX);
      Serial.print(" ");
    }
    Serial.println(" ");
    if (chars_index < 2) { 
      device.service.chars[chars_index].chars= *characteristic;
      chars_index++;
    }
  }
  else if (status == BLE_STATUS_DONE) {
    Serial.println("Discovered characteristic done");
    chars_index = 0;
    // All characteristics have been found, start to discover descriptors.
    // Result will be reported on discoveredCharsDescriptorsCallback.
    ble.discoverCharacteristicDescriptors(device.connected_handle, &device.service.chars[chars_index].chars);
  }
}

/**
 * @brief Callback for handling result of discovering descriptor.
 *
 * @param[in]  status         BLE_STATUS_OK/BLE_STATUS_DONE
 * @param[in]  con_handle  
 * @param[in]  *descriptor    Discoverable descriptor.
 *
 * @retval None
 */
static void discoveredCharsDescriptorsCallback(BLEStatus_t status, uint16_t con_handle, gatt_client_characteristic_descriptor_t *descriptor) {
  uint8_t index;
  if (status == BLE_STATUS_OK) {   // Found a descriptor.
    Serial.println(" ");
    Serial.print("descriptor handle: ");
    Serial.println(descriptor->handle, HEX);
    Serial.print("descriptor uuid16: ");
    Serial.println(descriptor->uuid16, HEX);
    Serial.print("descriptor uuid128 : ");
    for (index = 0; index < 16; index++) {
      Serial.print(descriptor->uuid128[index], HEX);
      Serial.print(" ");
    }
    Serial.println(" ");
    if (desc_index < 2) {
      device.service.chars[chars_index].descriptor[desc_index++] = *descriptor;
    }
  }
  else if (status == BLE_STATUS_DONE) {
    // finish.
    Serial.println("Discovered descriptor done");
    chars_index++;
    if (chars_index < 2) {
      desc_index=0;
      ble.discoverCharacteristicDescriptors(device.connected_handle, &device.service.chars[chars_index].chars);
    }
    else {   // Read value of characteristic, 
      // Result will be reported on gattReadCallback.
      ble.readValue(device.connected_handle,&device.service.chars[1].chars);
    }
  }
}

/**
 * @brief Callback for handling result of reading.
 *
 * @param[in]  status         BLE_STATUS_OK/BLE_STATUS_DONE/BLE_STATUS_OTHER_ERROR
 * @param[in]  con_handle  
 * @param[in]  value_handle   
 * @param[in]  *value
 * @param[in]  length
 *
 * @retval None
 */
void gattReadCallback(BLEStatus_t status, uint16_t con_handle, uint16_t value_handle, uint8_t *value, uint16_t length) {
  uint8_t index;
    
  if (status == BLE_STATUS_OK) {
    //受信処理
    mpuVol = value[0] - 127; //MPU6050 Acc-y値
    wpVol = value[1]; //Wah pedal値
    Serial.print(mpuVol); Serial.print("\t");
    Serial.println(wpVol);
  }
  else if (status == BLE_STATUS_DONE) {
    //送信(ダミー)
    uint8_t data[]= {0};
    // Result will be reported on gattWrittenCallback.
    // If use ble.writeValueWithoutResponse, will no response.
    ble.writeValue(device.connected_handle, device.service.chars[0].chars.value_handle, sizeof(data), data);
  }
}

/**
 * @brief Callback for handling result of writting.
 *
 * @param[in]  status         BLE_STATUS_DONE/BLE_STATUS_OTHER_ERROR
 * @param[in]  con_handle  
 *
 * @retval None
 */
void gattWrittenCallback(BLEStatus_t status, uint16_t con_handle) {
  if (status == BLE_STATUS_DONE) {
    //受信
    ble.readValue(device.connected_handle,&device.service.chars[1].chars);    
  }
}

/**
 * @brief Callback for handling result of reading descriptor.
 *
 * @param[in]  status         BLE_STATUS_DONE/BLE_STATUS_OTHER_ERROR
 * @param[in]  con_handle  
 * @param[in]  value_handle   
 * @param[in]  *value
 * @param[in]  length
 *
 * @retval None
 */
void gattReadDescriptorCallback(BLEStatus_t status, uint16_t con_handle, uint16_t value_handle, uint8_t *value, uint16_t length) {
  uint8_t index;
  if(status == BLE_STATUS_OK) {
    Serial.println(" ");
    Serial.println("Read descriptor ok");
    Serial.print("conn handle: ");
    Serial.println(con_handle, HEX);
    Serial.print("value handle: ");
    Serial.println(value_handle, HEX);
    Serial.print("The value : ");
    for (index = 0; index < length; index++) {
      Serial.print(value[index], HEX);
      Serial.print(" ");
    }
    Serial.println(" ");
  }
  else if (status == BLE_STATUS_DONE) {
    // Enable notify.
    ble.writeClientCharsConfigDescritpor(device.connected_handle, &device.service.chars[0].chars, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
  }
}

/**
 * @brief Callback for handling result of writting client characteristic configuration.
 *
 * @param[in]  status         BLE_STATUS_DONE/BLE_STATUS_OTHER_ERROR
 * @param[in]  con_handle
 *
 * @retval None
 */
void gattWriteCCCDCallback(BLEStatus_t status, uint16_t con_handle) {
  if (status == BLE_STATUS_DONE) {
    Serial.println("gattWriteCCCDCallback done");
    if (gatt_notify_flag == 0) { 
      gatt_notify_flag = 1;
      ble.writeClientCharsConfigDescritpor(device.connected_handle, &device.service.chars[1].chars, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
    }
    else if (gatt_notify_flag == 1) {
      gatt_notify_flag = 2;
    }
  }
}

/**
 * @brief Callback for handling notify event from remote device.
 *
 * @param[in]  status         BLE_STATUS_OK
 * @param[in]  con_handle  
 * @param[in]  value_handle   
 * @param[in]  *value
 * @param[in]  length 
 *
 * @retval None
 */
void gattNotifyUpdateCallback(BLEStatus_t status, uint16_t con_handle, uint16_t value_handle, uint8_t *value, uint16_t length) {
  uint8_t index;
  Serial.println(" ");
  Serial.println("Notify Update value ");
  Serial.print("conn handle: ");
  Serial.println(con_handle, HEX);
  Serial.print("value handle: ");
  Serial.println(value_handle, HEX);
  Serial.print("The value : ");
  for (index = 0; index < length; index++) {
    Serial.print(value[index], HEX);
    Serial.print(" ");
  }
  Serial.println(" ");
}

/**
 * @brief Setup.
 */
void setup() {
  Serial.begin(115200);
  delay(5000);
  RGB.control(true);
  RGB.color(100, 0, 0);

  pinMode(L, OUTPUT); 
  pinMode(R, OUTPUT); 

    
  // Open debugger, must befor init().
  //ble.debugLogger(true);
  //ble.debugError(true);
  //ble.enablePacketLogger();
    
  Serial.println("BLE central demo!");
  // Initialize ble_stack.
  ble.init();
    
  // Register callback functions.
  ble.onConnectedCallback(deviceConnectedCallback);
  ble.onDisconnectedCallback(deviceDisconnectedCallback);
  ble.onScanReportCallback(reportCallback);

  ble.onServiceDiscoveredCallback(discoveredServiceCallback);
  ble.onCharacteristicDiscoveredCallback(discoveredCharsCallback);
  ble.onDescriptorDiscoveredCallback(discoveredCharsDescriptorsCallback);
  ble.onGattCharacteristicReadCallback(gattReadCallback);
  ble.onGattCharacteristicWrittenCallback(gattWrittenCallback);
  ble.onGattDescriptorReadCallback(gattReadDescriptorCallback);

  ble.onGattWriteClientCharacteristicConfigCallback(gattWriteCCCDCallback);
  ble.onGattNotifyUpdateCallback(gattNotifyUpdateCallback);

  // Set scan parameters.
  ble.setScanParams(BLE_SCAN_TYPE, BLE_SCAN_INTERVAL, BLE_SCAN_WINDOW);
  
  // Start scanning.
  ble.startScanning();
  Serial.println("Start scanning ");
}

/**
 * @brief Loop.
 */
void loop() {
  if(wpVol > 45){
    if(mpuVol > 0){
      analogWrite(L, wpVol - map(abs(mpuVol), 0, 127, 0, wpVol));
      analogWrite(R, wpVol + map(abs(mpuVol), 0, 127, 0, wpVol));
    }else{
      analogWrite(L, wpVol + map(abs(mpuVol), 0, 127, 0, wpVol));
      analogWrite(R, wpVol - map(abs(mpuVol), 0, 127, 0, wpVol));
    }
  }else {
    analogWrite(L, LOW);
    analogWrite(R, LOW);
  }
}
BLE Nano (Peripheral)
以下をベースに生成
 
6軸モーションセンサMPU6050のArduino用ライブラリは以下にあります(MPU6050とI2Cdevを使用)。
 https://github.com/jrowberg/i2cdevlib/tree/master/Arduino
 
BLE NanoでMPU6050を使用する場合にはArduino IDEボードマネージャのRedBearLab nRF51822 Boardsのパッケージバージョン1.0.5を使用してください。1.0.6以上では何かしらに変更あったらしくエラー出まくります。。。
 
さらにI2Cdev.hに ”#define BUFFER_LENGTH 32″ を追加で問題なく使用できるようになります。
 
#include <BLE_API.h>
#include <Wire.h>
#include "I2Cdev.h"
#include "MPU6050.h"


BLE ble;
Timeout timeout;                
MPU6050 mpu;

#define TXRX_BUF_LEN 20

static uint8_t tx_buf[TXRX_BUF_LEN];

// The Nordic UART Service
static const uint8_t service1_uuid[]                = {0x71, 0x3D, 0, 0, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t service1_tx_uuid[]             = {0x71, 0x3D, 0, 3, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t service1_rx_uuid[]             = {0x71, 0x3D, 0, 2, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t uart_base_uuid_rev[]           = {0x1E, 0x94, 0x8D, 0xF1, 0x48, 0x31, 0x94, 0xBA, 0x75, 0x4C, 0x3E, 0x50, 0, 0, 0x3D, 0x71};

uint8_t tx_value[TXRX_BUF_LEN] = {0,};
uint8_t rx_value[TXRX_BUF_LEN] = {0,};

GattCharacteristic  characteristic1(service1_tx_uuid, tx_value, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE );

GattCharacteristic  characteristic2(service1_rx_uuid, rx_value, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);

GattCharacteristic *uartChars[] = {&characteristic1, &characteristic2};

GattService         uartService(service1_uuid, uartChars, sizeof(uartChars) / sizeof(GattCharacteristic *));

MPU6050 accelgyro;

int16_t ax, ay, az;
int16_t gx, gy, gz;

        
static void disconnectionCallBack(Gap::Handle_t handle, Gap::DisconnectionReason_t reason) {
    ble.startAdvertising();
}

void writtenHandle(const GattWriteCallbackParams *Handler) {
  uint8_t buf[TXRX_BUF_LEN];
  uint16_t bytesRead, index;

  if (Handler->handle == characteristic1.getValueAttribute().getHandle()) {
    ble.readCharacteristicValue(characteristic1.getValueAttribute().getHandle(), buf, &bytesRead);
    for(byte index=0; index<bytesRead; index++) {
      Serial.write(buf[index]);
    }
  }
}

void setup() {
  // join I2C bus (I2Cdev library doesn't do this automatically)
  #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    Wire.begin();
  #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
    Fastwire::setup(400, true);
  #endif
  
  Serial.begin(250000);

  // initialize device
  Serial.println("Initializing I2C devices...");
  accelgyro.initialize();

  // verify connection
  Serial.println("Testing device connections...");
  Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");

  
  mpu.setXAccelOffset(-1020);
  mpu.setYAccelOffset(-1030);
  mpu.setZAccelOffset(1470);
  mpu.setXGyroOffset(80);
  mpu.setYGyroOffset(-45);
  mpu.setZGyroOffset(30);
  

  //BLE設定
  ble.init();
  ble.onDisconnection(disconnectionCallBack);
  ble.onDataWritten(writtenHandle);
      
  // setup adv_data and srp_data
  ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
  ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
                                     (const uint8_t *)"TXRX", sizeof("TXRX") - 1);
  ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
                                     (const uint8_t *)uart_base_uuid_rev, sizeof(uart_base_uuid_rev));
                
  // set adv_type
  ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);    
  // add service
  ble.addService(uartService);
  // set device name
  ble.setDeviceName((const uint8_t *)"Simple Chat");
  // set tx power,valid values are -40, -20, -16, -12, -8, -4, 0, 4
  ble.setTxPower(4);
  // set adv_interval, 100ms in multiples of 0.625ms.
  ble.setAdvertisingInterval(160);
  // set adv_timeout, in seconds
  ble.setAdvertisingTimeout(0);
  // start advertising
  ble.startAdvertising();

  Serial.println("Advertising Start!"); 
}

void loop() {
  // read raw accel/gyro measurements from device
  accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

  /*
  Serial.print("a/g:\t");
  Serial.print(ax); Serial.print("\t");
  Serial.print(ay); Serial.print("\t");
  Serial.print(az); Serial.print("\t");
  Serial.print(gx); Serial.print("\t");
  Serial.print(gy); Serial.print("\t");
  Serial.println(gz);
  */
  
        
  //BLEデータ送信
  tx_buf[0] = map(ay, -18000, 18000, 0, 255); //MPU6050
  tx_buf[1] = map(analogRead(A5), 960, 0, 0, 255); //Wah Pedal値
  Serial.print(tx_buf[0]); Serial.print("\t");
  Serial.println(tx_buf[1]);
  ble.updateCharacteristicValue(characteristic2.getValueAttribute().getHandle(), tx_buf, 2);
}

 

これでヘッドマウントデスプレイでFPVできたら面白いだろうなぁ

BLE Car Controlled by Motion Sensor and Wah Pedal

I made a BLE car controlled by motion sensor and wah pedal.

Configuration

Parts

  •  Redbearlab BLE Nano
    [amazonjs asin=”B01G5EZTVE” locale=”JP” title=”RedBear DUO – Wi-Fi + BLE IoT Board”]

     

  • Redbear Duo
    [amazonjs asin=”B01G5EZTVE” locale=”JP” title=”RedBear DUO – Wi-Fi + BLE IoT Board”]
     
  • 6DOF MPU-6050
    [amazonjs asin=”B07FMLWWR9″ locale=”JP” title=”Pinbotronix Arduino GY-521 MPU-6050加速度センサーモジュール3軸ジャイロスコープ加速度計スタンドチルト”]
     
  • Motor Driver DRV8835
    [amazonjs asin=”B00R7EKBQA” locale=”JP” title=”デュアルモータードライバDRV8835″]
     
  • JIM DUNLOP wah pedal CRYBABY
    [amazonjs asin=”B005GJCG7A” locale=”JP” title=”JIM DUNLOP ワウペダル CRYBABY GCB95″]

Car Body

I used the RedBear Duo (BLE Central) to receive the controller (handle and accelerator) information and control the motor.

Controller

And I used the BLE Nano (BLE Peripheral) to communicate with the car.

The 6-axis motion sensor MPU6050 detects the inclination of the handle (y-axis acceleration).

I used the wah pedal as an accelerator.

I wired the variable resistor in the wah pedal to the BLE Nano, so the BLE Nano can detect the depression of the pedal.

Operation

Accelerate by pressing down the wah pedal!

 
Steer the car when you turn the handle!

 

Code for Arduino IDE

Redbear Duo (Central)

Generated based on the following
 
#if defined(ARDUINO) 
SYSTEM_MODE(SEMI_AUTOMATIC); 
#endif

/* 
 * BLE scan parameters:
 *     - BLE_SCAN_TYPE     
 *           0x00: Passive scanning, no scan request packets shall be sent.(default)
 *           0x01: Active scanning, scan request packets may be sent.
 *           0x02 - 0xFF: Reserved for future use.
 *     - BLE_SCAN_INTERVAL: This is defined as the time interval from when the Controller started its last LE scan until it begins the subsequent LE scan.
 *           Range: 0x0004 to 0x4000
 *           Default: 0x0010 (10 ms)
 *           Time = N * 0.625 msec
 *           Time Range: 2.5 msec to 10.24 seconds
 *     - BLE_SCAN_WINDOW: The duration of the LE scan. The scan window shall be less than or equal to the scan interval.
 *           Range: 0x0004 to 0x4000
 *           Default: 0x0010 (10 ms)
 *           Time = N * 0.625 msec
 *           Time Range: 2.5 msec to 10240 msec
 */
#define BLE_SCAN_TYPE        0x00   // Passive scanning
#define BLE_SCAN_INTERVAL    0x0060 // 60 ms
#define BLE_SCAN_WINDOW      0x0030 // 30 ms

int mpuVol;
uint8_t wpVol = 0; //Wah pedal値

int L = D8;
int R = D9;

/******************************************************
 *                      Type Define
 ******************************************************/
typedef struct {
  uint16_t  connected_handle;
  uint8_t   addr_type;
  bd_addr_t addr;
  struct {
    gatt_client_service_t service;
    struct {
      gatt_client_characteristic_t chars;
      gatt_client_characteristic_descriptor_t descriptor[2]; // User_descriptor and client charactersitc configuration descriptor.
    } chars[2];  
  } service; // Service contains two characteristics and each characteristic contains two descriptors.
} Device_t;

/******************************************************
 *               Variable Definitions
 ******************************************************/
// Connect handle.
static uint16_t connected_id = 0xFFFF;

Device_t device;
uint8_t  chars_index = 0;
uint8_t  desc_index = 0;

// The service uuid to be discovered.
static uint8_t service1_uuid[16] = { 0x71,0x3d,0x00,0x00,0x50,0x3e,0x4c,0x75,0xba,0x94,0x31,0x48,0xf1,0x8d,0x94,0x1e };

static uint8_t gatt_notify_flag = 0;

/******************************************************
 *               Function Definitions
 ******************************************************/
 /**
 * @brief Find the data given the type in advertising data.
 *
 * @param[in]  type          The type of field data.
 * @param[in]  advdata_len   Length of advertising data.
 * @param[in]  *p_advdata    The pointer of advertising data.
 * @param[out] *len          The length of found data.
 * @param[out] *p_field_data The pointer of buffer to store field data.
 *
 * @retval 0 Find the data
 *         1 Not find.
 */
uint32_t ble_advdata_decode(uint8_t type, uint8_t advdata_len, uint8_t *p_advdata, uint8_t *len, uint8_t *p_field_data) {
  uint8_t index = 0;
  uint8_t field_length, field_type;

  while (index < advdata_len) {
    field_length = p_advdata[index];
    field_type = p_advdata[index + 1];
    if (field_type == type) {
      memcpy(p_field_data, &p_advdata[index + 2], (field_length - 1));
      *len = field_length - 1;
      return 0;
    }
    index += field_length + 1;
  }
  return 1;
}

/**
 * @brief Callback for scanning device.
 *
 * @param[in]  *report
 *
 * @retval None
 */
void reportCallback(advertisementReport_t *report) {
  uint8_t index;

  Serial.println("reportCallback: ");
  Serial.print("The advEventType: ");
  Serial.println(report->advEventType, HEX);
  Serial.print("The peerAddrType: ");
  Serial.println(report->peerAddrType, HEX);
  Serial.print("The peerAddr: ");
  for (index = 0; index < 6; index++) {
    Serial.print(report->peerAddr[index], HEX);
    Serial.print(" ");
  }
  Serial.println(" ");

  Serial.print("The rssi: ");
  Serial.println(report->rssi, DEC);

  Serial.print("The ADV data: ");
  for (index = 0; index < report->advDataLen; index++) {
    Serial.print(report->advData[index], HEX);
    Serial.print(" ");
  }
  Serial.println(" ");
  Serial.println(" ");

  uint8_t len;
  uint8_t adv_name[31];
  // Find short local name.
  if (0x00 == ble_advdata_decode(0x08, report->advDataLen, report->advData, &len, adv_name)) {
    Serial.print("  The length of Short Local Name : ");
    Serial.println(len, HEX);
    Serial.print("  The Short Local Name is        : ");
    Serial.println((const char *)adv_name);
    if (0x00 == memcmp(adv_name, "TXRX", min(4, len))) {
      ble.stopScanning();
      device.addr_type = report->peerAddrType;
      memcpy(device.addr, report->peerAddr, 6);

      //ble.connect(report->peerAddr, report->peerAddrType);
      //ble.connect(report->peerAddr, BD_ADDR_TYPE_LE_PUBLIC);
      ble.connect(report->peerAddr, BD_ADDR_TYPE_LE_RANDOM);
    }
  }
}

/**
 * @brief Connect handle.
 *
 * @param[in]  status   BLE_STATUS_CONNECTION_ERROR or BLE_STATUS_OK.
 * @param[in]  handle   Connect handle.
 *
 * @retval None
 */
void deviceConnectedCallback(BLEStatus_t status, uint16_t handle) {
  RGB.color(0, 60, 25);
  switch (status) {
    case BLE_STATUS_OK:
      Serial.println("Device connected!");
      // Connect to remote device, start to discover service.
      connected_id = handle;
      device.connected_handle = handle;
      // Start to discover service, will report result on discoveredServiceCallback.
      ble.discoverPrimaryServices(handle);
      break;
    default: break;
  }
}

/**
 * @brief Disconnect handle.
 *
 * @param[in]  handle   Connect handle.
 *
 * @retval None
 */
void deviceDisconnectedCallback(uint16_t handle){
  RGB.color(100, 0, 0); //BLE非接続時にLED赤色
  analogWrite(L, LOW);
  analogWrite(R, LOW);
  Serial.print("Disconnected handle:");
  Serial.println(handle,HEX);
  if (connected_id == handle) {
    Serial.println("Restart scanning.");
    // Disconnect from remote device, restart to scanning.
    connected_id = 0xFFFF;
    ble.startScanning();
  }
}

/**
 * @brief Callback for handling result of discovering service.
 *
 * @param[in]  status      BLE_STATUS_OK/BLE_STATUS_DONE
 * @param[in]  con_handle  
 * @param[in]  *service    Discoverable service.
 *
 * @retval None
 */
static void discoveredServiceCallback(BLEStatus_t status, uint16_t con_handle, gatt_client_service_t *service) {
  uint8_t index;
  if (status == BLE_STATUS_OK) {   // Found a service.
    Serial.println(" ");
    Serial.print("Service start handle: ");
    Serial.println(service->start_group_handle, HEX);
    Serial.print("Service end handle: ");
    Serial.println(service->end_group_handle, HEX);
    Serial.print("Service uuid16: ");
    Serial.println(service->uuid16, HEX);
    Serial.print("The uuid128 : ");
    for (index = 0; index < 16; index++) {
      Serial.print(service->uuid128[index], HEX);
      Serial.print(" ");
    }
    Serial.println(" ");
    if (0x00 == memcmp(service->uuid128, service1_uuid, 16)) {
      Serial.println("Target uuid128");
      device.service.service = *service;
    }
  }
  else if (status == BLE_STATUS_DONE) {
    Serial.println("Discovered service done");
    // All sevice have been found, start to discover characteristics.
    // Result will be reported on discoveredCharsCallback.
    ble.discoverCharacteristics(device.connected_handle, &device.service.service);
  }
}

/**
 * @brief Callback for handling result of discovering characteristic.
 *
 * @param[in]  status           BLE_STATUS_OK/BLE_STATUS_DONE
 * @param[in]  con_handle  
 * @param[in]  *characteristic  Discoverable characteristic.
 *
 * @retval None
 */
static void discoveredCharsCallback(BLEStatus_t status, uint16_t con_handle, gatt_client_characteristic_t *characteristic) {
  uint8_t index;
  if (status == BLE_STATUS_OK) {   // Found a characteristic.
    Serial.println(" ");
    Serial.print("characteristic start handle: ");
    Serial.println(characteristic->start_handle, HEX);
    Serial.print("characteristic value handle: ");
    Serial.println(characteristic->value_handle, HEX);
    Serial.print("characteristic end_handle: ");
    Serial.println(characteristic->end_handle, HEX);
    Serial.print("characteristic properties: ");
    Serial.println(characteristic->properties, HEX);
    Serial.print("characteristic uuid16: ");
    Serial.println(characteristic->uuid16, HEX);
    Serial.print("characteristic uuid128 : ");
    for (index = 0; index < 16; index++) {
      Serial.print(characteristic->uuid128[index], HEX);
      Serial.print(" ");
    }
    Serial.println(" ");
    if (chars_index < 2) { 
      device.service.chars[chars_index].chars= *characteristic;
      chars_index++;
    }
  }
  else if (status == BLE_STATUS_DONE) {
    Serial.println("Discovered characteristic done");
    chars_index = 0;
    // All characteristics have been found, start to discover descriptors.
    // Result will be reported on discoveredCharsDescriptorsCallback.
    ble.discoverCharacteristicDescriptors(device.connected_handle, &device.service.chars[chars_index].chars);
  }
}

/**
 * @brief Callback for handling result of discovering descriptor.
 *
 * @param[in]  status         BLE_STATUS_OK/BLE_STATUS_DONE
 * @param[in]  con_handle  
 * @param[in]  *descriptor    Discoverable descriptor.
 *
 * @retval None
 */
static void discoveredCharsDescriptorsCallback(BLEStatus_t status, uint16_t con_handle, gatt_client_characteristic_descriptor_t *descriptor) {
  uint8_t index;
  if (status == BLE_STATUS_OK) {   // Found a descriptor.
    Serial.println(" ");
    Serial.print("descriptor handle: ");
    Serial.println(descriptor->handle, HEX);
    Serial.print("descriptor uuid16: ");
    Serial.println(descriptor->uuid16, HEX);
    Serial.print("descriptor uuid128 : ");
    for (index = 0; index < 16; index++) {
      Serial.print(descriptor->uuid128[index], HEX);
      Serial.print(" ");
    }
    Serial.println(" ");
    if (desc_index < 2) {
      device.service.chars[chars_index].descriptor[desc_index++] = *descriptor;
    }
  }
  else if (status == BLE_STATUS_DONE) {
    // finish.
    Serial.println("Discovered descriptor done");
    chars_index++;
    if (chars_index < 2) {
      desc_index=0;
      ble.discoverCharacteristicDescriptors(device.connected_handle, &device.service.chars[chars_index].chars);
    }
    else {   // Read value of characteristic, 
      // Result will be reported on gattReadCallback.
      ble.readValue(device.connected_handle,&device.service.chars[1].chars);
    }
  }
}

/**
 * @brief Callback for handling result of reading.
 *
 * @param[in]  status         BLE_STATUS_OK/BLE_STATUS_DONE/BLE_STATUS_OTHER_ERROR
 * @param[in]  con_handle  
 * @param[in]  value_handle   
 * @param[in]  *value
 * @param[in]  length
 *
 * @retval None
 */
void gattReadCallback(BLEStatus_t status, uint16_t con_handle, uint16_t value_handle, uint8_t *value, uint16_t length) {
  uint8_t index;
    
  if (status == BLE_STATUS_OK) {
    //Rx Data
    mpuVol = value[0] - 127; //MPU6050 Acc-y
    wpVol = value[1]; //Wah pedal
    Serial.print(mpuVol); Serial.print("\t");
    Serial.println(wpVol);
  }
  else if (status == BLE_STATUS_DONE) {
    uint8_t data[]= {0};
    // Result will be reported on gattWrittenCallback.
    // If use ble.writeValueWithoutResponse, will no response.
    ble.writeValue(device.connected_handle, device.service.chars[0].chars.value_handle, sizeof(data), data);
  }
}

/**
 * @brief Callback for handling result of writting.
 *
 * @param[in]  status         BLE_STATUS_DONE/BLE_STATUS_OTHER_ERROR
 * @param[in]  con_handle  
 *
 * @retval None
 */
void gattWrittenCallback(BLEStatus_t status, uint16_t con_handle) {
  if (status == BLE_STATUS_DONE) {
    //Rx
    ble.readValue(device.connected_handle,&device.service.chars[1].chars);    
  }
}

/**
 * @brief Callback for handling result of reading descriptor.
 *
 * @param[in]  status         BLE_STATUS_DONE/BLE_STATUS_OTHER_ERROR
 * @param[in]  con_handle  
 * @param[in]  value_handle   
 * @param[in]  *value
 * @param[in]  length
 *
 * @retval None
 */
void gattReadDescriptorCallback(BLEStatus_t status, uint16_t con_handle, uint16_t value_handle, uint8_t *value, uint16_t length) {
  uint8_t index;
  if(status == BLE_STATUS_OK) {
    Serial.println(" ");
    Serial.println("Read descriptor ok");
    Serial.print("conn handle: ");
    Serial.println(con_handle, HEX);
    Serial.print("value handle: ");
    Serial.println(value_handle, HEX);
    Serial.print("The value : ");
    for (index = 0; index < length; index++) {
      Serial.print(value[index], HEX);
      Serial.print(" ");
    }
    Serial.println(" ");
  }
  else if (status == BLE_STATUS_DONE) {
    // Enable notify.
    ble.writeClientCharsConfigDescritpor(device.connected_handle, &device.service.chars[0].chars, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
  }
}

/**
 * @brief Callback for handling result of writting client characteristic configuration.
 *
 * @param[in]  status         BLE_STATUS_DONE/BLE_STATUS_OTHER_ERROR
 * @param[in]  con_handle
 *
 * @retval None
 */
void gattWriteCCCDCallback(BLEStatus_t status, uint16_t con_handle) {
  if (status == BLE_STATUS_DONE) {
    Serial.println("gattWriteCCCDCallback done");
    if (gatt_notify_flag == 0) { 
      gatt_notify_flag = 1;
      ble.writeClientCharsConfigDescritpor(device.connected_handle, &device.service.chars[1].chars, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
    }
    else if (gatt_notify_flag == 1) {
      gatt_notify_flag = 2;
    }
  }
}

/**
 * @brief Callback for handling notify event from remote device.
 *
 * @param[in]  status         BLE_STATUS_OK
 * @param[in]  con_handle  
 * @param[in]  value_handle   
 * @param[in]  *value
 * @param[in]  length 
 *
 * @retval None
 */
void gattNotifyUpdateCallback(BLEStatus_t status, uint16_t con_handle, uint16_t value_handle, uint8_t *value, uint16_t length) {
  uint8_t index;
  Serial.println(" ");
  Serial.println("Notify Update value ");
  Serial.print("conn handle: ");
  Serial.println(con_handle, HEX);
  Serial.print("value handle: ");
  Serial.println(value_handle, HEX);
  Serial.print("The value : ");
  for (index = 0; index < length; index++) {
    Serial.print(value[index], HEX);
    Serial.print(" ");
  }
  Serial.println(" ");
}

/**
 * @brief Setup.
 */
void setup() {
  Serial.begin(115200);
  delay(5000);
  RGB.control(true);
  RGB.color(100, 0, 0);

  pinMode(L, OUTPUT); 
  pinMode(R, OUTPUT); 

    
  // Open debugger, must befor init().
  //ble.debugLogger(true);
  //ble.debugError(true);
  //ble.enablePacketLogger();
    
  Serial.println("BLE central demo!");
  // Initialize ble_stack.
  ble.init();
    
  // Register callback functions.
  ble.onConnectedCallback(deviceConnectedCallback);
  ble.onDisconnectedCallback(deviceDisconnectedCallback);
  ble.onScanReportCallback(reportCallback);

  ble.onServiceDiscoveredCallback(discoveredServiceCallback);
  ble.onCharacteristicDiscoveredCallback(discoveredCharsCallback);
  ble.onDescriptorDiscoveredCallback(discoveredCharsDescriptorsCallback);
  ble.onGattCharacteristicReadCallback(gattReadCallback);
  ble.onGattCharacteristicWrittenCallback(gattWrittenCallback);
  ble.onGattDescriptorReadCallback(gattReadDescriptorCallback);

  ble.onGattWriteClientCharacteristicConfigCallback(gattWriteCCCDCallback);
  ble.onGattNotifyUpdateCallback(gattNotifyUpdateCallback);

  // Set scan parameters.
  ble.setScanParams(BLE_SCAN_TYPE, BLE_SCAN_INTERVAL, BLE_SCAN_WINDOW);
  
  // Start scanning.
  ble.startScanning();
  Serial.println("Start scanning ");
}

/**
 * @brief Loop.
 */
void loop() {
  if(wpVol > 45){
    if(mpuVol > 0){
      analogWrite(L, wpVol - map(abs(mpuVol), 0, 127, 0, wpVol));
      analogWrite(R, wpVol + map(abs(mpuVol), 0, 127, 0, wpVol));
    }else{
      analogWrite(L, wpVol + map(abs(mpuVol), 0, 127, 0, wpVol));
      analogWrite(R, wpVol - map(abs(mpuVol), 0, 127, 0, wpVol));
    }
  }else {
    analogWrite(L, LOW);
    analogWrite(R, LOW);
  }
}

 

BLE Nano (peripheral)

Generated based on the following
 
The Arduino library for 6-axis motion sensor mpu6050 is located below (using mpu6050 and I2cdev).
 https://github.com/jrowberg/i2cdevlib/tree/master/Arduino
 
 
#include <BLE_API.h>
#include <Wire.h>
#include "I2Cdev.h"
#include "MPU6050.h"


BLE ble;
Timeout timeout;                
MPU6050 mpu;

#define TXRX_BUF_LEN 20

static uint8_t tx_buf[TXRX_BUF_LEN];

// The Nordic UART Service
static const uint8_t service1_uuid[]                = {0x71, 0x3D, 0, 0, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t service1_tx_uuid[]             = {0x71, 0x3D, 0, 3, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t service1_rx_uuid[]             = {0x71, 0x3D, 0, 2, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t uart_base_uuid_rev[]           = {0x1E, 0x94, 0x8D, 0xF1, 0x48, 0x31, 0x94, 0xBA, 0x75, 0x4C, 0x3E, 0x50, 0, 0, 0x3D, 0x71};

uint8_t tx_value[TXRX_BUF_LEN] = {0,};
uint8_t rx_value[TXRX_BUF_LEN] = {0,};

GattCharacteristic  characteristic1(service1_tx_uuid, tx_value, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE );

GattCharacteristic  characteristic2(service1_rx_uuid, rx_value, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);

GattCharacteristic *uartChars[] = {&characteristic1, &characteristic2};

GattService         uartService(service1_uuid, uartChars, sizeof(uartChars) / sizeof(GattCharacteristic *));

MPU6050 accelgyro;

int16_t ax, ay, az;
int16_t gx, gy, gz;

        
static void disconnectionCallBack(Gap::Handle_t handle, Gap::DisconnectionReason_t reason) {
    ble.startAdvertising();
}

void writtenHandle(const GattWriteCallbackParams *Handler) {
  uint8_t buf[TXRX_BUF_LEN];
  uint16_t bytesRead, index;

  if (Handler->handle == characteristic1.getValueAttribute().getHandle()) {
    ble.readCharacteristicValue(characteristic1.getValueAttribute().getHandle(), buf, &bytesRead);
    for(byte index=0; index<bytesRead; index++) {
      Serial.write(buf[index]);
    }
  }
}

void setup() {
  // join I2C bus (I2Cdev library doesn't do this automatically)
  #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    Wire.begin();
  #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
    Fastwire::setup(400, true);
  #endif
  
  Serial.begin(250000);

  // initialize device
  Serial.println("Initializing I2C devices...");
  accelgyro.initialize();

  // verify connection
  Serial.println("Testing device connections...");
  Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");

  
  mpu.setXAccelOffset(-1020);
  mpu.setYAccelOffset(-1030);
  mpu.setZAccelOffset(1470);
  mpu.setXGyroOffset(80);
  mpu.setYGyroOffset(-45);
  mpu.setZGyroOffset(30);
  

  //BLE設定
  ble.init();
  ble.onDisconnection(disconnectionCallBack);
  ble.onDataWritten(writtenHandle);
      
  // setup adv_data and srp_data
  ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
  ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
                                     (const uint8_t *)"TXRX", sizeof("TXRX") - 1);
  ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
                                     (const uint8_t *)uart_base_uuid_rev, sizeof(uart_base_uuid_rev));
                
  // set adv_type
  ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);    
  // add service
  ble.addService(uartService);
  // set device name
  ble.setDeviceName((const uint8_t *)"Simple Chat");
  // set tx power,valid values are -40, -20, -16, -12, -8, -4, 0, 4
  ble.setTxPower(4);
  // set adv_interval, 100ms in multiples of 0.625ms.
  ble.setAdvertisingInterval(160);
  // set adv_timeout, in seconds
  ble.setAdvertisingTimeout(0);
  // start advertising
  ble.startAdvertising();

  Serial.println("Advertising Start!"); 
}

void loop() {
  // read raw accel/gyro measurements from device
  accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

  /*
  Serial.print("a/g:\t");
  Serial.print(ax); Serial.print("\t");
  Serial.print(ay); Serial.print("\t");
  Serial.print(az); Serial.print("\t");
  Serial.print(gx); Serial.print("\t");
  Serial.print(gy); Serial.print("\t");
  Serial.println(gz);
  */
  
        
  //Tx DATA
  tx_buf[0] = map(ay, -18000, 18000, 0, 255); //MPU6050
  tx_buf[1] = map(analogRead(A5), 960, 0, 0, 255); //Wah Pedal
  Serial.print(tx_buf[0]); Serial.print("\t");
  Serial.println(tx_buf[1]);
  ble.updateCharacteristicValue(characteristic2.getValueAttribute().getHandle(), tx_buf, 2);
}

 

It would be interesting to be able to FPV in the head mount Desplay now!

由运动传感器和华踏板控制的 ble 车

我做了一辆由运动传感器和 wah 踏板控制的 ble 汽车。

配置

部分

  • Redbearlab BLE Nano
    [amazonjs asin=”B01G5EZTVE” locale=”JP” title=”RedBear DUO – Wi-Fi + BLE IoT Board”]

     

  • Redbear Duo
    [amazonjs asin=”B01G5EZTVE” locale=”JP” title=”RedBear DUO – Wi-Fi + BLE IoT Board”]
     
  • 6DOF MPU-6050
    [amazonjs asin=”B07FMLWWR9″ locale=”JP” title=”Pinbotronix Arduino GY-521 MPU-6050加速度センサーモジュール3軸ジャイロスコープ加速度計スタンドチルト”]
     
  • Motor Driver DRV8835
    [amazonjs asin=”B00R7EKBQA” locale=”JP” title=”デュアルモータードライバDRV8835″]
     
  • JIM DUNLOP wah pedal CRYBABY
    [amazonjs asin=”B005GJCG7A” locale=”JP” title=”JIM DUNLOP ワウペダル CRYBABY GCB95″]

车体

我使用红熊二者 (ble 中心) 接收控制器 (手柄和加速器) 信息并控制电机。

控制器

我用 ble 纳米 (ble 外围) 与汽车沟通。

6轴运动传感器 MPU6050 检测手柄的倾斜度 (y 轴加速度)。

我用 wah 踏板做加速器。

我把 wah 踏板上的可变电阻器连接到了 ble nano 上, 这样 ble 纳米就能检测到踏板的凹陷。

操作

通过按下 wah 踏板加速!

 

当你转动把手的时候, 把车开走!

 

arduino ide 代码

红熊多 (中)

基于以下各项生成
 
#if defined(ARDUINO) 
SYSTEM_MODE(SEMI_AUTOMATIC); 
#endif

/* 
 * BLE scan parameters:
 *     - BLE_SCAN_TYPE     
 *           0x00: Passive scanning, no scan request packets shall be sent.(default)
 *           0x01: Active scanning, scan request packets may be sent.
 *           0x02 - 0xFF: Reserved for future use.
 *     - BLE_SCAN_INTERVAL: This is defined as the time interval from when the Controller started its last LE scan until it begins the subsequent LE scan.
 *           Range: 0x0004 to 0x4000
 *           Default: 0x0010 (10 ms)
 *           Time = N * 0.625 msec
 *           Time Range: 2.5 msec to 10.24 seconds
 *     - BLE_SCAN_WINDOW: The duration of the LE scan. The scan window shall be less than or equal to the scan interval.
 *           Range: 0x0004 to 0x4000
 *           Default: 0x0010 (10 ms)
 *           Time = N * 0.625 msec
 *           Time Range: 2.5 msec to 10240 msec
 */
#define BLE_SCAN_TYPE        0x00   // Passive scanning
#define BLE_SCAN_INTERVAL    0x0060 // 60 ms
#define BLE_SCAN_WINDOW      0x0030 // 30 ms

int mpuVol;
uint8_t wpVol = 0; //Wah pedal値

int L = D8;
int R = D9;

/******************************************************
 *                      Type Define
 ******************************************************/
typedef struct {
  uint16_t  connected_handle;
  uint8_t   addr_type;
  bd_addr_t addr;
  struct {
    gatt_client_service_t service;
    struct {
      gatt_client_characteristic_t chars;
      gatt_client_characteristic_descriptor_t descriptor[2]; // User_descriptor and client charactersitc configuration descriptor.
    } chars[2];  
  } service; // Service contains two characteristics and each characteristic contains two descriptors.
} Device_t;

/******************************************************
 *               Variable Definitions
 ******************************************************/
// Connect handle.
static uint16_t connected_id = 0xFFFF;

Device_t device;
uint8_t  chars_index = 0;
uint8_t  desc_index = 0;

// The service uuid to be discovered.
static uint8_t service1_uuid[16] = { 0x71,0x3d,0x00,0x00,0x50,0x3e,0x4c,0x75,0xba,0x94,0x31,0x48,0xf1,0x8d,0x94,0x1e };

static uint8_t gatt_notify_flag = 0;

/******************************************************
 *               Function Definitions
 ******************************************************/
 /**
 * @brief Find the data given the type in advertising data.
 *
 * @param[in]  type          The type of field data.
 * @param[in]  advdata_len   Length of advertising data.
 * @param[in]  *p_advdata    The pointer of advertising data.
 * @param[out] *len          The length of found data.
 * @param[out] *p_field_data The pointer of buffer to store field data.
 *
 * @retval 0 Find the data
 *         1 Not find.
 */
uint32_t ble_advdata_decode(uint8_t type, uint8_t advdata_len, uint8_t *p_advdata, uint8_t *len, uint8_t *p_field_data) {
  uint8_t index = 0;
  uint8_t field_length, field_type;

  while (index < advdata_len) {
    field_length = p_advdata[index];
    field_type = p_advdata[index + 1];
    if (field_type == type) {
      memcpy(p_field_data, &p_advdata[index + 2], (field_length - 1));
      *len = field_length - 1;
      return 0;
    }
    index += field_length + 1;
  }
  return 1;
}

/**
 * @brief Callback for scanning device.
 *
 * @param[in]  *report
 *
 * @retval None
 */
void reportCallback(advertisementReport_t *report) {
  uint8_t index;

  Serial.println("reportCallback: ");
  Serial.print("The advEventType: ");
  Serial.println(report->advEventType, HEX);
  Serial.print("The peerAddrType: ");
  Serial.println(report->peerAddrType, HEX);
  Serial.print("The peerAddr: ");
  for (index = 0; index < 6; index++) {
    Serial.print(report->peerAddr[index], HEX);
    Serial.print(" ");
  }
  Serial.println(" ");

  Serial.print("The rssi: ");
  Serial.println(report->rssi, DEC);

  Serial.print("The ADV data: ");
  for (index = 0; index < report->advDataLen; index++) {
    Serial.print(report->advData[index], HEX);
    Serial.print(" ");
  }
  Serial.println(" ");
  Serial.println(" ");

  uint8_t len;
  uint8_t adv_name[31];
  // Find short local name.
  if (0x00 == ble_advdata_decode(0x08, report->advDataLen, report->advData, &len, adv_name)) {
    Serial.print("  The length of Short Local Name : ");
    Serial.println(len, HEX);
    Serial.print("  The Short Local Name is        : ");
    Serial.println((const char *)adv_name);
    if (0x00 == memcmp(adv_name, "TXRX", min(4, len))) {
      ble.stopScanning();
      device.addr_type = report->peerAddrType;
      memcpy(device.addr, report->peerAddr, 6);

      //ble.connect(report->peerAddr, report->peerAddrType);
      //ble.connect(report->peerAddr, BD_ADDR_TYPE_LE_PUBLIC);
      ble.connect(report->peerAddr, BD_ADDR_TYPE_LE_RANDOM);
    }
  }
}

/**
 * @brief Connect handle.
 *
 * @param[in]  status   BLE_STATUS_CONNECTION_ERROR or BLE_STATUS_OK.
 * @param[in]  handle   Connect handle.
 *
 * @retval None
 */
void deviceConnectedCallback(BLEStatus_t status, uint16_t handle) {
  RGB.color(0, 60, 25);
  switch (status) {
    case BLE_STATUS_OK:
      Serial.println("Device connected!");
      // Connect to remote device, start to discover service.
      connected_id = handle;
      device.connected_handle = handle;
      // Start to discover service, will report result on discoveredServiceCallback.
      ble.discoverPrimaryServices(handle);
      break;
    default: break;
  }
}

/**
 * @brief Disconnect handle.
 *
 * @param[in]  handle   Connect handle.
 *
 * @retval None
 */
void deviceDisconnectedCallback(uint16_t handle){
  RGB.color(100, 0, 0); //BLE非接続時にLED赤色
  analogWrite(L, LOW);
  analogWrite(R, LOW);
  Serial.print("Disconnected handle:");
  Serial.println(handle,HEX);
  if (connected_id == handle) {
    Serial.println("Restart scanning.");
    // Disconnect from remote device, restart to scanning.
    connected_id = 0xFFFF;
    ble.startScanning();
  }
}

/**
 * @brief Callback for handling result of discovering service.
 *
 * @param[in]  status      BLE_STATUS_OK/BLE_STATUS_DONE
 * @param[in]  con_handle  
 * @param[in]  *service    Discoverable service.
 *
 * @retval None
 */
static void discoveredServiceCallback(BLEStatus_t status, uint16_t con_handle, gatt_client_service_t *service) {
  uint8_t index;
  if (status == BLE_STATUS_OK) {   // Found a service.
    Serial.println(" ");
    Serial.print("Service start handle: ");
    Serial.println(service->start_group_handle, HEX);
    Serial.print("Service end handle: ");
    Serial.println(service->end_group_handle, HEX);
    Serial.print("Service uuid16: ");
    Serial.println(service->uuid16, HEX);
    Serial.print("The uuid128 : ");
    for (index = 0; index < 16; index++) {
      Serial.print(service->uuid128[index], HEX);
      Serial.print(" ");
    }
    Serial.println(" ");
    if (0x00 == memcmp(service->uuid128, service1_uuid, 16)) {
      Serial.println("Target uuid128");
      device.service.service = *service;
    }
  }
  else if (status == BLE_STATUS_DONE) {
    Serial.println("Discovered service done");
    // All sevice have been found, start to discover characteristics.
    // Result will be reported on discoveredCharsCallback.
    ble.discoverCharacteristics(device.connected_handle, &device.service.service);
  }
}

/**
 * @brief Callback for handling result of discovering characteristic.
 *
 * @param[in]  status           BLE_STATUS_OK/BLE_STATUS_DONE
 * @param[in]  con_handle  
 * @param[in]  *characteristic  Discoverable characteristic.
 *
 * @retval None
 */
static void discoveredCharsCallback(BLEStatus_t status, uint16_t con_handle, gatt_client_characteristic_t *characteristic) {
  uint8_t index;
  if (status == BLE_STATUS_OK) {   // Found a characteristic.
    Serial.println(" ");
    Serial.print("characteristic start handle: ");
    Serial.println(characteristic->start_handle, HEX);
    Serial.print("characteristic value handle: ");
    Serial.println(characteristic->value_handle, HEX);
    Serial.print("characteristic end_handle: ");
    Serial.println(characteristic->end_handle, HEX);
    Serial.print("characteristic properties: ");
    Serial.println(characteristic->properties, HEX);
    Serial.print("characteristic uuid16: ");
    Serial.println(characteristic->uuid16, HEX);
    Serial.print("characteristic uuid128 : ");
    for (index = 0; index < 16; index++) {
      Serial.print(characteristic->uuid128[index], HEX);
      Serial.print(" ");
    }
    Serial.println(" ");
    if (chars_index < 2) { 
      device.service.chars[chars_index].chars= *characteristic;
      chars_index++;
    }
  }
  else if (status == BLE_STATUS_DONE) {
    Serial.println("Discovered characteristic done");
    chars_index = 0;
    // All characteristics have been found, start to discover descriptors.
    // Result will be reported on discoveredCharsDescriptorsCallback.
    ble.discoverCharacteristicDescriptors(device.connected_handle, &device.service.chars[chars_index].chars);
  }
}

/**
 * @brief Callback for handling result of discovering descriptor.
 *
 * @param[in]  status         BLE_STATUS_OK/BLE_STATUS_DONE
 * @param[in]  con_handle  
 * @param[in]  *descriptor    Discoverable descriptor.
 *
 * @retval None
 */
static void discoveredCharsDescriptorsCallback(BLEStatus_t status, uint16_t con_handle, gatt_client_characteristic_descriptor_t *descriptor) {
  uint8_t index;
  if (status == BLE_STATUS_OK) {   // Found a descriptor.
    Serial.println(" ");
    Serial.print("descriptor handle: ");
    Serial.println(descriptor->handle, HEX);
    Serial.print("descriptor uuid16: ");
    Serial.println(descriptor->uuid16, HEX);
    Serial.print("descriptor uuid128 : ");
    for (index = 0; index < 16; index++) {
      Serial.print(descriptor->uuid128[index], HEX);
      Serial.print(" ");
    }
    Serial.println(" ");
    if (desc_index < 2) {
      device.service.chars[chars_index].descriptor[desc_index++] = *descriptor;
    }
  }
  else if (status == BLE_STATUS_DONE) {
    // finish.
    Serial.println("Discovered descriptor done");
    chars_index++;
    if (chars_index < 2) {
      desc_index=0;
      ble.discoverCharacteristicDescriptors(device.connected_handle, &device.service.chars[chars_index].chars);
    }
    else {   // Read value of characteristic, 
      // Result will be reported on gattReadCallback.
      ble.readValue(device.connected_handle,&device.service.chars[1].chars);
    }
  }
}

/**
 * @brief Callback for handling result of reading.
 *
 * @param[in]  status         BLE_STATUS_OK/BLE_STATUS_DONE/BLE_STATUS_OTHER_ERROR
 * @param[in]  con_handle  
 * @param[in]  value_handle   
 * @param[in]  *value
 * @param[in]  length
 *
 * @retval None
 */
void gattReadCallback(BLEStatus_t status, uint16_t con_handle, uint16_t value_handle, uint8_t *value, uint16_t length) {
  uint8_t index;
    
  if (status == BLE_STATUS_OK) {
    //Rx Data
    mpuVol = value[0] - 127; //MPU6050 Acc-y
    wpVol = value[1]; //Wah pedal
    Serial.print(mpuVol); Serial.print("\t");
    Serial.println(wpVol);
  }
  else if (status == BLE_STATUS_DONE) {
    uint8_t data[]= {0};
    // Result will be reported on gattWrittenCallback.
    // If use ble.writeValueWithoutResponse, will no response.
    ble.writeValue(device.connected_handle, device.service.chars[0].chars.value_handle, sizeof(data), data);
  }
}

/**
 * @brief Callback for handling result of writting.
 *
 * @param[in]  status         BLE_STATUS_DONE/BLE_STATUS_OTHER_ERROR
 * @param[in]  con_handle  
 *
 * @retval None
 */
void gattWrittenCallback(BLEStatus_t status, uint16_t con_handle) {
  if (status == BLE_STATUS_DONE) {
    //Rx
    ble.readValue(device.connected_handle,&device.service.chars[1].chars);    
  }
}

/**
 * @brief Callback for handling result of reading descriptor.
 *
 * @param[in]  status         BLE_STATUS_DONE/BLE_STATUS_OTHER_ERROR
 * @param[in]  con_handle  
 * @param[in]  value_handle   
 * @param[in]  *value
 * @param[in]  length
 *
 * @retval None
 */
void gattReadDescriptorCallback(BLEStatus_t status, uint16_t con_handle, uint16_t value_handle, uint8_t *value, uint16_t length) {
  uint8_t index;
  if(status == BLE_STATUS_OK) {
    Serial.println(" ");
    Serial.println("Read descriptor ok");
    Serial.print("conn handle: ");
    Serial.println(con_handle, HEX);
    Serial.print("value handle: ");
    Serial.println(value_handle, HEX);
    Serial.print("The value : ");
    for (index = 0; index < length; index++) {
      Serial.print(value[index], HEX);
      Serial.print(" ");
    }
    Serial.println(" ");
  }
  else if (status == BLE_STATUS_DONE) {
    // Enable notify.
    ble.writeClientCharsConfigDescritpor(device.connected_handle, &device.service.chars[0].chars, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
  }
}

/**
 * @brief Callback for handling result of writting client characteristic configuration.
 *
 * @param[in]  status         BLE_STATUS_DONE/BLE_STATUS_OTHER_ERROR
 * @param[in]  con_handle
 *
 * @retval None
 */
void gattWriteCCCDCallback(BLEStatus_t status, uint16_t con_handle) {
  if (status == BLE_STATUS_DONE) {
    Serial.println("gattWriteCCCDCallback done");
    if (gatt_notify_flag == 0) { 
      gatt_notify_flag = 1;
      ble.writeClientCharsConfigDescritpor(device.connected_handle, &device.service.chars[1].chars, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
    }
    else if (gatt_notify_flag == 1) {
      gatt_notify_flag = 2;
    }
  }
}

/**
 * @brief Callback for handling notify event from remote device.
 *
 * @param[in]  status         BLE_STATUS_OK
 * @param[in]  con_handle  
 * @param[in]  value_handle   
 * @param[in]  *value
 * @param[in]  length 
 *
 * @retval None
 */
void gattNotifyUpdateCallback(BLEStatus_t status, uint16_t con_handle, uint16_t value_handle, uint8_t *value, uint16_t length) {
  uint8_t index;
  Serial.println(" ");
  Serial.println("Notify Update value ");
  Serial.print("conn handle: ");
  Serial.println(con_handle, HEX);
  Serial.print("value handle: ");
  Serial.println(value_handle, HEX);
  Serial.print("The value : ");
  for (index = 0; index < length; index++) {
    Serial.print(value[index], HEX);
    Serial.print(" ");
  }
  Serial.println(" ");
}

/**
 * @brief Setup.
 */
void setup() {
  Serial.begin(115200);
  delay(5000);
  RGB.control(true);
  RGB.color(100, 0, 0);

  pinMode(L, OUTPUT); 
  pinMode(R, OUTPUT); 

    
  // Open debugger, must befor init().
  //ble.debugLogger(true);
  //ble.debugError(true);
  //ble.enablePacketLogger();
    
  Serial.println("BLE central demo!");
  // Initialize ble_stack.
  ble.init();
    
  // Register callback functions.
  ble.onConnectedCallback(deviceConnectedCallback);
  ble.onDisconnectedCallback(deviceDisconnectedCallback);
  ble.onScanReportCallback(reportCallback);

  ble.onServiceDiscoveredCallback(discoveredServiceCallback);
  ble.onCharacteristicDiscoveredCallback(discoveredCharsCallback);
  ble.onDescriptorDiscoveredCallback(discoveredCharsDescriptorsCallback);
  ble.onGattCharacteristicReadCallback(gattReadCallback);
  ble.onGattCharacteristicWrittenCallback(gattWrittenCallback);
  ble.onGattDescriptorReadCallback(gattReadDescriptorCallback);

  ble.onGattWriteClientCharacteristicConfigCallback(gattWriteCCCDCallback);
  ble.onGattNotifyUpdateCallback(gattNotifyUpdateCallback);

  // Set scan parameters.
  ble.setScanParams(BLE_SCAN_TYPE, BLE_SCAN_INTERVAL, BLE_SCAN_WINDOW);
  
  // Start scanning.
  ble.startScanning();
  Serial.println("Start scanning ");
}

/**
 * @brief Loop.
 */
void loop() {
  if(wpVol > 45){
    if(mpuVol > 0){
      analogWrite(L, wpVol - map(abs(mpuVol), 0, 127, 0, wpVol));
      analogWrite(R, wpVol + map(abs(mpuVol), 0, 127, 0, wpVol));
    }else{
      analogWrite(L, wpVol + map(abs(mpuVol), 0, 127, 0, wpVol));
      analogWrite(R, wpVol - map(abs(mpuVol), 0, 127, 0, wpVol));
    }
  }else {
    analogWrite(L, LOW);
    analogWrite(R, LOW);
  }
}

 

ble 纳米 (周边)

基于以下各项生成
 
用于6轴运动传感器 mpu6050 的 arduino 库位于下方 (使用 mpu6050 和 i2cdev)。
 https://github.com/jrowberg/i2cdevlib/tree/master/Arduino
 
 
#include <BLE_API.h>
#include <Wire.h>
#include "I2Cdev.h"
#include "MPU6050.h"


BLE ble;
Timeout timeout;                
MPU6050 mpu;

#define TXRX_BUF_LEN 20

static uint8_t tx_buf[TXRX_BUF_LEN];

// The Nordic UART Service
static const uint8_t service1_uuid[]                = {0x71, 0x3D, 0, 0, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t service1_tx_uuid[]             = {0x71, 0x3D, 0, 3, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t service1_rx_uuid[]             = {0x71, 0x3D, 0, 2, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t uart_base_uuid_rev[]           = {0x1E, 0x94, 0x8D, 0xF1, 0x48, 0x31, 0x94, 0xBA, 0x75, 0x4C, 0x3E, 0x50, 0, 0, 0x3D, 0x71};

uint8_t tx_value[TXRX_BUF_LEN] = {0,};
uint8_t rx_value[TXRX_BUF_LEN] = {0,};

GattCharacteristic  characteristic1(service1_tx_uuid, tx_value, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE );

GattCharacteristic  characteristic2(service1_rx_uuid, rx_value, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);

GattCharacteristic *uartChars[] = {&characteristic1, &characteristic2};

GattService         uartService(service1_uuid, uartChars, sizeof(uartChars) / sizeof(GattCharacteristic *));

MPU6050 accelgyro;

int16_t ax, ay, az;
int16_t gx, gy, gz;

        
static void disconnectionCallBack(Gap::Handle_t handle, Gap::DisconnectionReason_t reason) {
    ble.startAdvertising();
}

void writtenHandle(const GattWriteCallbackParams *Handler) {
  uint8_t buf[TXRX_BUF_LEN];
  uint16_t bytesRead, index;

  if (Handler->handle == characteristic1.getValueAttribute().getHandle()) {
    ble.readCharacteristicValue(characteristic1.getValueAttribute().getHandle(), buf, &bytesRead);
    for(byte index=0; index<bytesRead; index++) {
      Serial.write(buf[index]);
    }
  }
}

void setup() {
  // join I2C bus (I2Cdev library doesn't do this automatically)
  #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    Wire.begin();
  #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
    Fastwire::setup(400, true);
  #endif
  
  Serial.begin(250000);

  // initialize device
  Serial.println("Initializing I2C devices...");
  accelgyro.initialize();

  // verify connection
  Serial.println("Testing device connections...");
  Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");

  
  mpu.setXAccelOffset(-1020);
  mpu.setYAccelOffset(-1030);
  mpu.setZAccelOffset(1470);
  mpu.setXGyroOffset(80);
  mpu.setYGyroOffset(-45);
  mpu.setZGyroOffset(30);
  

  //BLE設定
  ble.init();
  ble.onDisconnection(disconnectionCallBack);
  ble.onDataWritten(writtenHandle);
      
  // setup adv_data and srp_data
  ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
  ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
                                     (const uint8_t *)"TXRX", sizeof("TXRX") - 1);
  ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
                                     (const uint8_t *)uart_base_uuid_rev, sizeof(uart_base_uuid_rev));
                
  // set adv_type
  ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);    
  // add service
  ble.addService(uartService);
  // set device name
  ble.setDeviceName((const uint8_t *)"Simple Chat");
  // set tx power,valid values are -40, -20, -16, -12, -8, -4, 0, 4
  ble.setTxPower(4);
  // set adv_interval, 100ms in multiples of 0.625ms.
  ble.setAdvertisingInterval(160);
  // set adv_timeout, in seconds
  ble.setAdvertisingTimeout(0);
  // start advertising
  ble.startAdvertising();

  Serial.println("Advertising Start!"); 
}

void loop() {
  // read raw accel/gyro measurements from device
  accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

  /*
  Serial.print("a/g:\t");
  Serial.print(ax); Serial.print("\t");
  Serial.print(ay); Serial.print("\t");
  Serial.print(az); Serial.print("\t");
  Serial.print(gx); Serial.print("\t");
  Serial.print(gy); Serial.print("\t");
  Serial.println(gz);
  */
  
        
  //Tx DATA
  tx_buf[0] = map(ay, -18000, 18000, 0, 255); //MPU6050
  tx_buf[1] = map(analogRead(A5), 960, 0, 0, 255); //Wah Pedal
  Serial.print(tx_buf[0]); Serial.print("\t");
  Serial.println(tx_buf[1]);
  ble.updateCharacteristicValue(characteristic2.getValueAttribute().getHandle(), tx_buf, 2);
}

 

现在能够在头部坐骑《绝望》中使用 fpv 将是一件有趣的事情!

Blynkでダイソー版プラレールコントロール!

いつのまにかBlynkがBLE対応してた!(まだβ版のようだが)
ということで早速以前作ったBLEトレインをBlynkで動かしてみましたので記載します。

Blynkライブラリ

最新ライブラリは以下にあります。
 https://github.com/blynkkk/blynk-library

今回はRedbearLabのBLE Nanoを使うので
 [スケッチの例] -> [Blynk] -> [Boards_BLE]-> [RedBearLab_BLE_Nano]を参考にコード生成しました。

BLE Nano設定

BLE Nano詳細はこちら
  
ボードプラットフォームを1.0.7にアップデートすると動かなくなる場合があるようです(mac OS 10.11.16では問題ありませんでした)。
 
 
 
暫定的な解決策として1.0.5のままで行くのですがBLE通信のクラスが古いようでBlynk BLE通信のコードが使えません。そこで最新ファームウェアである以下の
  • [cores]
  • boards.txt

をPC内のボードプラットフォーム1.0.5(例えばC:\hogehoge\Arduino15\packages\RedBearLab\hardware\nRF51822\1.0.5 )に上書きします。これでなんとかBlynk BLEライブラリが使えるようになります!

Blynk設定

新規プロジェクトを作成します。ハードウェアでBLE Nanoを選択し、
AUTH TOKENはArduinoコード生成時に使用しますので控えときます(もしくはメール送信します)。

ウィジェットとしてBLEとジョイスティックを配置します。

ジョイスティックの設定はこんな感じでヴァーチャルピンV1に2軸の数値を出力します。

Arduino IDE

[スケッチの例] -> [Blynk] -> [Boards_BLE]-> [RedBearLab_BLE_Nano]を参考にコード生成しました。

#define BLYNK_PRINT Serial

#include <BlynkSimpleRedBearLab_BLE_Nano.h>
#include <BLE_API.h>
#include <Wire.h>
#include <Servo.h>

Servo myservo; 
const int DRV8830 = 0x64;

int power = 0;
float angle = 0;
int rot = 0;

int Speed = 0;
int angleServo_ini = 35;
int angleServo = angleServo_ini;

// You should get Auth Token in the Blynk App.
char auth[] = "YourAuthTokenを入力";

uint8_t device_name[] = "Blynk";

//モータドライバ I2C制御 motor driver I2C
//Reference
//http://makers-with-myson.blog.so-net.ne.jp/2014-05-15
void writeMotorResister(byte vset, byte data1){
  int vdata = vset << 2 | data1;
  Wire.beginTransmission(DRV8830);
  Wire.write(0x00);
  Wire.write(vdata);
  Wire.endTransmission(true);
}

void setup() {
  Wire.begin(D3, D2, 400000L);
  Serial.begin(250000);
  writeMotorResister(0x00, 0x00);
  myservo.attach(D4);
  myservo.write(angleServo);
  
  delay(100);

  ble.init();

  ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
  ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
                                         device_name, sizeof(device_name) - 1);

  ble.gap().setDeviceName(device_name);
  ble.gap().setTxPower(4);

  // Add Blynk service...
  Blynk.begin(auth);

  ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
  ble.gap().setAdvertisingInterval(Gap::MSEC_TO_GAP_DURATION_UNITS(1000));
  ble.gap().setAdvertisingTimeout(0);
  ble.startAdvertising();

  Serial.println("Waiting for connections...");
}

//ジョイスティック値受信
BLYNK_WRITE(V1) {
  float x = param[0].asInt() - 128.0;
  float y = param[1].asInt() - 128.0;

  //モータスピード
  power = sqrt(x*x + y*y);
  if(power > 128){
    power = 128;
  }
  Speed = map(power, 0, 128, 5, 19);

  //サーボ角度
  angle = atan(y/x) * 180.0 / PI;
  if(x < 0 && y > 0){
    angle = angle * -1;
  }else if(x > 0 && y >= 0){
    angle = 180.0 - angle;
  }else if(x >= 0 && y < 0){
    angle = 180.0 + angle;
  }else if(x == 0 && y == 0 || power >= 0 && power < 57){
    angle = 90;
  }
  angleServo = map(angle, 180, 0, 0, angleServo_ini * 2);

  //モータ回転方向
  if(y >= 0){
    rot = 2; //前進
  } else {
    rot = 1; //後進
  }

  //モーター、サーボ実行
  if (power == 0){
    writeMotorResister(0x00, 0x00);
  }else {
    writeMotorResister((byte)Speed, (byte)rot);
  }
  myservo.write(angleServo);
  //delay(15);
  
  Serial.print("x: ");
  Serial.print(x);
  Serial.print("  y: ");
  Serial.print(y);
  Serial.print("  power: ");
  Serial.print(power);
  Serial.print("  Speed: ");
  Serial.print(Speed);
  Serial.print("  angleServo: ");
  Serial.print(angleServo);
  Serial.print("  rot: ");
  Serial.println(rot);
}

void loop() {
  Blynk.run();
}

Blynk BLE接続

BlynkプロジェクトのBLEウェジットをクリックして設定します。

“Connect BLE device”をクリックして Arduino IDE上で設定したデバイス名である”Blynk”が表示されたらOKをクリックして接続する。

動作

 

簡単にできた!
これでWiFiモジュールもBLEモジュールも簡単にスマホと通信できる!

今までAndroid用にコード書くのにメチャメチャ時間取られてたのでコレは非常に便利です♫

 

 

BLE Nano – Redbear Duo間通信でモータ&LED制御 w/ Android -球体POV製作への道 その6-

前回Redbear DuoでLEDテープ(Dotstar)を制御できるようにしました。んで今回は
 
ステップ4:スマホ – Redbear Duo でLED色・回転速度WiFi制御かつ
Redbear Duo – BLE Nanoでモーター速度制御&測定
 
です。いやー手こずりましたが。。。お盆休みあって良かった。。。
 
こちらはスマホ-Redbear Duo間はWiFi(TCP通信)でRedbear Duo-BLE Nano間はBLEで通信してBLE Nanoに接続されたLEDを双方向にコントロールするデモです。
 
このデモのコードは以下にアップされています。
 
今回はこちらのデモのコードをゴテゴテ改造して作成していますww

全体構成

  • スマホ(Android)でモータースピードやLEDカラーを指定してWiFi(TCP通信)でRedBear Duoに送信
  • Redbear DuoでLEDを送信された色で発光し、モータースピードをBLE Nanoに送信(BLE通信)
  • BLE Nanoで指定されたスピードでモーターを回転し、フォトリフレクタでモーター回転スピードを計測しRedbear Duoに送信(BLE通信)

動作

できたーーーーーーー!

まとめ

これで通信周りはたぶんOK!
次回はいよいよPOV動作の確認です!いつになることやら。。。。
 
  • ステップ5:POV基本動作確認
  • ステップ6:POV映像の書き出し方法検討

次の記事

LEDテープ比較 Neopixel vs Dotstar -球体POV製作への道 その7-

Redbear DuoでDotstarを制御 -球体POV製作への道 その5-

前回 BLE通信使用してRedbear Duoでモーター供給電圧を指定してBLE Nanoでモーターを回転&回転スピードDuoへ送信が確認しました。んで今回は
 
ステップ3:Redbear DuoでLEDテープ(Dotstar)を制御
 
です。新しいコアモジュールでこの手のLEDをコントロールする際は毎度手こずります。。。
 

DotStarとは

Adafruit製の高速点滅LEDテープです。

公式記事
[bc url = “https://learn.adafruit.com/adafruit-dotstar-leds”]
 
購入先
[bc url = “https://www.adafruit.com/product/2241”]
国内で買えないので$75+輸送費$60でかなり高くついた。。。(´Д⊂グスン
NeoPixelと比較

いつも使ってるLEDテープNeoPixelとの違い。()内がNeoPixel

  • LEDリフレッシュレート:19.2 KHz (400 Hz)
  • データ書き込み方式:2線式[CLK, DATA] SPI ~8 MHz  (独自1線式 800 KHz)

以上のように表示レート、書き込み速度ともにDotstarのほうが高速でPOV向きと言えます。

DotstarのArduino用ライブラリは以下にあります。
https://github.com/adafruit/Adafruit_DotStar

 
ですが、SPIライブラリが存在しないため残念ながらRedbear Duoでは使えません。。
技術掲示板によるとParticle Web IDE上にRedbear Duo用SPIライブラリありそうとのこと。。。
 

Particle Web IDEとは

SparkFun製のWiFi内蔵マイコンParticle Photon向けのWeb上のIDEです(mbedみたいなやつ)。Redbear DuoはArduinoの他にこのParticle IDEも使えるのです。
Particle Dotstarライブラリ->Arduino移植
mbedもそうなのですがどうもweb上のIDEって親しみがもてず管理もめんどいので今回はParticle上のDotstarライブラリをArduinoに移植しました。
 
 
  • Community Librariesに”dotstar”と記載 ライブラリ検索してDOTSTAR選択。
 
  • 1-strandtest.cppをコピーしてhogehoge.inoとして保存。dotstar.cppとdotstar.hは任意の場所(もしくはhogehoge.inoと同じフォルダ)に保存。
 
以上でRedbear DuoでもDotstarが使えるようになります。
 
 

全体動作

無事点滅!

Arduino IDE用コード

1-strandtest.cppをベースに生成
 
#include "application.h"
#include "dotstar.h"

#define NUMPIXELS 11 // Number of LEDs in strip

#define DATAPIN   D4
#define CLOCKPIN  D5
Adafruit_DotStar strip = Adafruit_DotStar(NUMPIXELS, DATAPIN, CLOCKPIN, DOTSTAR_BGR);

void setup() {
  strip.begin(); // Initialize pins for output
  strip.setBrightness(50); //輝度設定
  strip.show();  // Turn all LEDs off ASAP
}

// Runs 10 LEDs at a time along strip, cycling through red, green and blue.
// This requires about 200 mA for all the 'on' pixels + 1 mA per 'off' pixel.

int      head  = 0, tail = -10; // Index of first 'on' and 'off' pixels
uint32_t color = 0xFF0000;      // 'On' color (starts red)
uint32_t whiteColor  = strip.Color(30, 30, 30);

void loop() {

  strip.setPixelColor(head, color); // 'On' pixel at head
  strip.setPixelColor(tail, 0);     // 'Off' pixel at tail
  strip.show();                     // Refresh strip
  delay(20);                        // Pause 20 milliseconds (~50 FPS)

  if(++head >= NUMPIXELS) {         // Increment head index.  Off end of strip?
    head = 0;                       //  Yes, reset head index to start
    if((color >>= 8) == 0)          //  Next color (R->G->B) ... past blue now?
      color = 0xFF0000;             //   Yes, reset to red
  }
  if(++tail >= NUMPIXELS) tail = 0; // Increment, reset tail index
}
 

まとめ

よしあとはRedbear DuoのWiFi動作が確認できればほぼ基本確認は終了!
以下直近の実施予定項目です。
 
  • ステップ4:スマホ – Redbear Duo でLED色・回転速度WiFi制御
  • ステップ5:POV基本動作確認

次の記事

BLE Nano – Redbear Duo間通信でモータ&LED制御 w/ Android -球体POV製作への道 その6-

BLE Nano – Redbear Duo間通信でモータ制御 -球体POV製作への道 その4-

前回 BLE Nanoとスマホでモーターの回転スピード制御するところまで出来ましたので今回は
 
ステップ2:BLE Nano (Peripheral) – Redbear Duo (Central) のBLE通信でDuoで
       モーター供給電圧を指定してBLE Nanoから回転スピードを受信
 
を実施しました。BLE Nano – Redbear Duoの通信が意外と手こずりましたが。。。

全体概要

 

部品
  • BLE・WiFi搭載マイコン Redbear Duo
  • フォトリフレクタ QTR-1A
  • BLE搭載マイコン BLE Nano
  • モータードライバ DRV8830
  • DCモーター 100均の電動泡立て機のやつ(普通のモーター)
  • 10kohmボリューム

BLE Nano

設定方法記事

ワウペダルと加速度センサでBLE制御ラジコン!

Pin配置

Redbear Duo

設定方法記事

ワウペダルと加速度センサでBLE制御ラジコン!

Pin配置

動作

 

BLE介してRedbear Duoに接続した10kohmボリュームでDCモーター(BLE Nano)への供給電圧を0.5~3.0Vまで変化させ回転スピードを制御してます。
モータの羽(割り箸)付近にフォトリフレクタを配置し回転スピードを計測しBLE NanoからRedbear Duoへスピード値を送信しています。回転スピード[usec]はRedbear Duoを接続したPCに表示されています。

Arduino IDE用コード

Redbear Duo (Central)
以下をベースに生成
 
#if defined(ARDUINO) 
SYSTEM_MODE(SEMI_AUTOMATIC); 
#endif

/* 
 * BLE scan parameters:
 *     - BLE_SCAN_TYPE     
 *           0x00: Passive scanning, no scan request packets shall be sent.(default)
 *           0x01: Active scanning, scan request packets may be sent.
 *           0x02 - 0xFF: Reserved for future use.
 *     - BLE_SCAN_INTERVAL: This is defined as the time interval from when the Controller started its last LE scan until it begins the subsequent LE scan.
 *           Range: 0x0004 to 0x4000
 *           Default: 0x0010 (10 ms)
 *           Time = N * 0.625 msec
 *           Time Range: 2.5 msec to 10.24 seconds
 *     - BLE_SCAN_WINDOW: The duration of the LE scan. The scan window shall be less than or equal to the scan interval.
 *           Range: 0x0004 to 0x4000
 *           Default: 0x0010 (10 ms)
 *           Time = N * 0.625 msec
 *           Time Range: 2.5 msec to 10240 msec
 */
#define BLE_SCAN_TYPE        0x00   // Passive scanning
#define BLE_SCAN_INTERVAL    0x0060 // 60 ms
#define BLE_SCAN_WINDOW      0x0030 // 30 ms

uint8_t mdVol = 0;
uint16_t mSpeed; //受信モータスピード

/******************************************************
 *                      Type Define
 ******************************************************/
typedef struct {
  uint16_t  connected_handle;
  uint8_t   addr_type;
  bd_addr_t addr;
  struct {
    gatt_client_service_t service;
    struct {
      gatt_client_characteristic_t chars;
      gatt_client_characteristic_descriptor_t descriptor[2]; // User_descriptor and client charactersitc configuration descriptor.
    } chars[2];  
  } service; // Service contains two characteristics and each characteristic contains two descriptors.
} Device_t;

/******************************************************
 *               Variable Definitions
 ******************************************************/
// Connect handle.
static uint16_t connected_id = 0xFFFF;

Device_t device;
uint8_t  chars_index = 0;
uint8_t  desc_index = 0;

// The service uuid to be discovered.
static uint8_t service1_uuid[16] = { 0x71,0x3d,0x00,0x00,0x50,0x3e,0x4c,0x75,0xba,0x94,0x31,0x48,0xf1,0x8d,0x94,0x1e };

static uint8_t gatt_notify_flag = 0;

/******************************************************
 *               Function Definitions
 ******************************************************/
 /**
 * @brief Find the data given the type in advertising data.
 *
 * @param[in]  type          The type of field data.
 * @param[in]  advdata_len   Length of advertising data.
 * @param[in]  *p_advdata    The pointer of advertising data.
 * @param[out] *len          The length of found data.
 * @param[out] *p_field_data The pointer of buffer to store field data.
 *
 * @retval 0 Find the data
 *         1 Not find.
 */
uint32_t ble_advdata_decode(uint8_t type, uint8_t advdata_len, uint8_t *p_advdata, uint8_t *len, uint8_t *p_field_data) {
  uint8_t index = 0;
  uint8_t field_length, field_type;

  while (index < advdata_len) {
    field_length = p_advdata[index];
    field_type = p_advdata[index + 1];
    if (field_type == type) {
      memcpy(p_field_data, &p_advdata[index + 2], (field_length - 1));
      *len = field_length - 1;
      return 0;
    }
    index += field_length + 1;
  }
  return 1;
}

/**
 * @brief Callback for scanning device.
 *
 * @param[in]  *report
 *
 * @retval None
 */
void reportCallback(advertisementReport_t *report) {
  uint8_t index;

  Serial.println("reportCallback: ");
  Serial.print("The advEventType: ");
  Serial.println(report->advEventType, HEX);
  Serial.print("The peerAddrType: ");
  Serial.println(report->peerAddrType, HEX);
  Serial.print("The peerAddr: ");
  for (index = 0; index < 6; index++) {
    Serial.print(report->peerAddr[index], HEX);
    Serial.print(" ");
  }
  Serial.println(" ");

  Serial.print("The rssi: ");
  Serial.println(report->rssi, DEC);

  Serial.print("The ADV data: ");
  for (index = 0; index < report->advDataLen; index++) {
    Serial.print(report->advData[index], HEX);
    Serial.print(" ");
  }
  Serial.println(" ");
  Serial.println(" ");

  uint8_t len;
  uint8_t adv_name[31];
  // Find short local name.
  if (0x00 == ble_advdata_decode(0x08, report->advDataLen, report->advData, &len, adv_name)) {
    Serial.print("  The length of Short Local Name : ");
    Serial.println(len, HEX);
    Serial.print("  The Short Local Name is        : ");
    Serial.println((const char *)adv_name);
    if (0x00 == memcmp(adv_name, "Biscuit", min(7, len))) {
      ble.stopScanning();
      device.addr_type = report->peerAddrType;
      memcpy(device.addr, report->peerAddr, 6);

      //ble.connect(report->peerAddr, report->peerAddrType);
      //ble.connect(report->peerAddr, BD_ADDR_TYPE_LE_PUBLIC);
      ble.connect(report->peerAddr, BD_ADDR_TYPE_LE_RANDOM);
    }
  }
  else if (0x00 == ble_advdata_decode(0x09, report->advDataLen, report->advData, &len, adv_name)) {
    Serial.print("  The length of Complete Local Name : ");
    Serial.println(len, HEX);
    Serial.print("  The Complete Local Name is        : ");
    Serial.println((const char *)adv_name);
    if (0x00 == memcmp(adv_name, "Heart Rate", min(7, len))) {

    }
  }
}

/**
 * @brief Connect handle.
 *
 * @param[in]  status   BLE_STATUS_CONNECTION_ERROR or BLE_STATUS_OK.
 * @param[in]  handle   Connect handle.
 *
 * @retval None
 */
void deviceConnectedCallback(BLEStatus_t status, uint16_t handle) {
  RGB.color(0, 60, 25);
  switch (status) {
    case BLE_STATUS_OK:
      Serial.println("Device connected!");
      // Connect to remote device, start to discover service.
      connected_id = handle;
      device.connected_handle = handle;
      // Start to discover service, will report result on discoveredServiceCallback.
      ble.discoverPrimaryServices(handle);
      break;
    default: break;
  }
}

/**
 * @brief Disconnect handle.
 *
 * @param[in]  handle   Connect handle.
 *
 * @retval None
 */
void deviceDisconnectedCallback(uint16_t handle){
  RGB.color(100, 0, 0);
  Serial.print("Disconnected handle:");
  Serial.println(handle,HEX);
  if (connected_id == handle) {
    Serial.println("Restart scanning.");
    // Disconnect from remote device, restart to scanning.
    connected_id = 0xFFFF;
    ble.startScanning();
  }
}

/**
 * @brief Callback for handling result of discovering service.
 *
 * @param[in]  status      BLE_STATUS_OK/BLE_STATUS_DONE
 * @param[in]  con_handle  
 * @param[in]  *service    Discoverable service.
 *
 * @retval None
 */
static void discoveredServiceCallback(BLEStatus_t status, uint16_t con_handle, gatt_client_service_t *service) {
  uint8_t index;
  if (status == BLE_STATUS_OK) {   // Found a service.
    Serial.println(" ");
    Serial.print("Service start handle: ");
    Serial.println(service->start_group_handle, HEX);
    Serial.print("Service end handle: ");
    Serial.println(service->end_group_handle, HEX);
    Serial.print("Service uuid16: ");
    Serial.println(service->uuid16, HEX);
    Serial.print("The uuid128 : ");
    for (index = 0; index < 16; index++) {
      Serial.print(service->uuid128[index], HEX);
      Serial.print(" ");
    }
    Serial.println(" ");
    if (0x00 == memcmp(service->uuid128, service1_uuid, 16)) {
      Serial.println("Target uuid128");
      device.service.service = *service;
    }
  }
  else if (status == BLE_STATUS_DONE) {
    Serial.println("Discovered service done");
    // All sevice have been found, start to discover characteristics.
    // Result will be reported on discoveredCharsCallback.
    ble.discoverCharacteristics(device.connected_handle, &device.service.service);
  }
}

/**
 * @brief Callback for handling result of discovering characteristic.
 *
 * @param[in]  status           BLE_STATUS_OK/BLE_STATUS_DONE
 * @param[in]  con_handle  
 * @param[in]  *characteristic  Discoverable characteristic.
 *
 * @retval None
 */
static void discoveredCharsCallback(BLEStatus_t status, uint16_t con_handle, gatt_client_characteristic_t *characteristic) {
  uint8_t index;
  if (status == BLE_STATUS_OK) {   // Found a characteristic.
    Serial.println(" ");
    Serial.print("characteristic start handle: ");
    Serial.println(characteristic->start_handle, HEX);
    Serial.print("characteristic value handle: ");
    Serial.println(characteristic->value_handle, HEX);
    Serial.print("characteristic end_handle: ");
    Serial.println(characteristic->end_handle, HEX);
    Serial.print("characteristic properties: ");
    Serial.println(characteristic->properties, HEX);
    Serial.print("characteristic uuid16: ");
    Serial.println(characteristic->uuid16, HEX);
    Serial.print("characteristic uuid128 : ");
    for (index = 0; index < 16; index++) {
      Serial.print(characteristic->uuid128[index], HEX);
      Serial.print(" ");
    }
    Serial.println(" ");
    if (chars_index < 2) { 
      device.service.chars[chars_index].chars= *characteristic;
      chars_index++;
    }
  }
  else if (status == BLE_STATUS_DONE) {
    Serial.println("Discovered characteristic done");
    chars_index = 0;
    // All characteristics have been found, start to discover descriptors.
    // Result will be reported on discoveredCharsDescriptorsCallback.
    ble.discoverCharacteristicDescriptors(device.connected_handle, &device.service.chars[chars_index].chars);
  }
}

/**
 * @brief Callback for handling result of discovering descriptor.
 *
 * @param[in]  status         BLE_STATUS_OK/BLE_STATUS_DONE
 * @param[in]  con_handle  
 * @param[in]  *descriptor    Discoverable descriptor.
 *
 * @retval None
 */
static void discoveredCharsDescriptorsCallback(BLEStatus_t status, uint16_t con_handle, gatt_client_characteristic_descriptor_t *descriptor) {
  uint8_t index;
  if (status == BLE_STATUS_OK) {   // Found a descriptor.
    Serial.println(" ");
    Serial.print("descriptor handle: ");
    Serial.println(descriptor->handle, HEX);
    Serial.print("descriptor uuid16: ");
    Serial.println(descriptor->uuid16, HEX);
    Serial.print("descriptor uuid128 : ");
    for (index = 0; index < 16; index++) {
      Serial.print(descriptor->uuid128[index], HEX);
      Serial.print(" ");
    }
    Serial.println(" ");
    if (desc_index < 2) {
      device.service.chars[chars_index].descriptor[desc_index++] = *descriptor;
    }
  }
  else if (status == BLE_STATUS_DONE) {
    // finish.
    Serial.println("Discovered descriptor done");
    chars_index++;
    if (chars_index < 2) {
      desc_index=0;
      ble.discoverCharacteristicDescriptors(device.connected_handle, &device.service.chars[chars_index].chars);
    }
    else {   // Read value of characteristic, 
      // Result will be reported on gattReadCallback.
      ble.readValue(device.connected_handle,&device.service.chars[1].chars);
    }
  }
}

/**
 * @brief Callback for handling result of reading.
 *
 * @param[in]  status         BLE_STATUS_OK/BLE_STATUS_DONE/BLE_STATUS_OTHER_ERROR
 * @param[in]  con_handle  
 * @param[in]  value_handle   
 * @param[in]  *value
 * @param[in]  length
 *
 * @retval None
 */
void gattReadCallback(BLEStatus_t status, uint16_t con_handle, uint16_t value_handle, uint8_t *value, uint16_t length) {
  uint8_t index;
    
  if (status == BLE_STATUS_OK) {
    //受信処理
    Serial.print("Moter Speed : ");
    mSpeed = value[1] << 8 | value[0];
    Serial.println(mSpeed);
  }
  else if (status == BLE_STATUS_DONE) {
    //送信
    uint8_t data[]= {mdVol};
    // Result will be reported on gattWrittenCallback.
    // If use ble.writeValueWithoutResponse, will no response.
    ble.writeValue(device.connected_handle, device.service.chars[0].chars.value_handle, sizeof(data), data);
  }
}

/**
 * @brief Callback for handling result of writting.
 *
 * @param[in]  status         BLE_STATUS_DONE/BLE_STATUS_OTHER_ERROR
 * @param[in]  con_handle  
 *
 * @retval None
 */
void gattWrittenCallback(BLEStatus_t status, uint16_t con_handle) {
  if (status == BLE_STATUS_DONE) {
    //受信
    ble.readValue(device.connected_handle,&device.service.chars[1].chars);    
  }
}

/**
 * @brief Callback for handling result of reading descriptor.
 *
 * @param[in]  status         BLE_STATUS_DONE/BLE_STATUS_OTHER_ERROR
 * @param[in]  con_handle  
 * @param[in]  value_handle   
 * @param[in]  *value
 * @param[in]  length
 *
 * @retval None
 */
void gattReadDescriptorCallback(BLEStatus_t status, uint16_t con_handle, uint16_t value_handle, uint8_t *value, uint16_t length) {
  uint8_t index;
  if(status == BLE_STATUS_OK) {
    Serial.println(" ");
    Serial.println("Read descriptor ok");
    Serial.print("conn handle: ");
    Serial.println(con_handle, HEX);
    Serial.print("value handle: ");
    Serial.println(value_handle, HEX);
    Serial.print("The value : ");
    for (index = 0; index < length; index++) {
      Serial.print(value[index], HEX);
      Serial.print(" ");
    }
    Serial.println(" ");
  }
  else if (status == BLE_STATUS_DONE) {
    // Enable notify.
    ble.writeClientCharsConfigDescritpor(device.connected_handle, &device.service.chars[0].chars, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
  }
}

/**
 * @brief Callback for handling result of writting client characteristic configuration.
 *
 * @param[in]  status         BLE_STATUS_DONE/BLE_STATUS_OTHER_ERROR
 * @param[in]  con_handle
 *
 * @retval None
 */
void gattWriteCCCDCallback(BLEStatus_t status, uint16_t con_handle) {
  if (status == BLE_STATUS_DONE) {
    Serial.println("gattWriteCCCDCallback done");
    if (gatt_notify_flag == 0) { 
      gatt_notify_flag = 1;
      ble.writeClientCharsConfigDescritpor(device.connected_handle, &device.service.chars[1].chars, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
    }
    else if (gatt_notify_flag == 1) {
      gatt_notify_flag = 2;
    }
  }
}

/**
 * @brief Callback for handling notify event from remote device.
 *
 * @param[in]  status         BLE_STATUS_OK
 * @param[in]  con_handle  
 * @param[in]  value_handle   
 * @param[in]  *value
 * @param[in]  length 
 *
 * @retval None
 */
void gattNotifyUpdateCallback(BLEStatus_t status, uint16_t con_handle, uint16_t value_handle, uint8_t *value, uint16_t length) {
  uint8_t index;
  Serial.println(" ");
  Serial.println("Notify Update value ");
  Serial.print("conn handle: ");
  Serial.println(con_handle, HEX);
  Serial.print("value handle: ");
  Serial.println(value_handle, HEX);
  Serial.print("The value : ");
  for (index = 0; index < length; index++) {
    Serial.print(value[index], HEX);
    Serial.print(" ");
  }
  Serial.println(" ");
}

/**
 * @brief Setup.
 */
void setup() {
  Serial.begin(115200);
  delay(5000);
  RGB.control(true);
  RGB.color(100, 0, 0);
    
  // Open debugger, must befor init().
  //ble.debugLogger(true);
  //ble.debugError(true);
  //ble.enablePacketLogger();
    
  Serial.println("BLE central demo!");
  // Initialize ble_stack.
  ble.init();
    
  // Register callback functions.
  ble.onConnectedCallback(deviceConnectedCallback);
  ble.onDisconnectedCallback(deviceDisconnectedCallback);
  ble.onScanReportCallback(reportCallback);

  ble.onServiceDiscoveredCallback(discoveredServiceCallback);
  ble.onCharacteristicDiscoveredCallback(discoveredCharsCallback);
  ble.onDescriptorDiscoveredCallback(discoveredCharsDescriptorsCallback);
  ble.onGattCharacteristicReadCallback(gattReadCallback);
  ble.onGattCharacteristicWrittenCallback(gattWrittenCallback);
  ble.onGattDescriptorReadCallback(gattReadDescriptorCallback);

  ble.onGattWriteClientCharacteristicConfigCallback(gattWriteCCCDCallback);
  ble.onGattNotifyUpdateCallback(gattNotifyUpdateCallback);

  // Set scan parameters.
  ble.setScanParams(BLE_SCAN_TYPE, BLE_SCAN_INTERVAL, BLE_SCAN_WINDOW);
  
  // Start scanning.
  ble.startScanning();
  Serial.println("Start scanning ");
}

/**
 * @brief Loop.
 */
void loop() {
  //10kohm VR アナログ値読み取り
  mdVol = map(analogRead(A7), 0, 4096, 0, 27);
  //Serial.println(analogRead(A0));
  delay(15);
}
BLE Nano (Peripheral)
以下をベースに生成
 
#include <BLE_API.h>
#include <Wire.h>
#include <QTRSensors.h>
//フォトリフレクタライブラリ https://github.com/pololu/qtr-sensors-arduino

const int DRV8830 = 0x64;

#define NUM_SENSORS             1  // number of sensors used
#define NUM_SAMPLES_PER_SENSOR  1  // average 4 analog samples per sensor reading
#define EMITTER_PIN             QTR_NO_EMITTER_PIN  // emitter is controlled by digital pin 2

// sensors 0 through 5 are connected to analog inputs 0 through 5, respectively
QTRSensorsAnalog qtra((unsigned char[]) {A4}, 
  NUM_SENSORS, NUM_SAMPLES_PER_SENSOR, EMITTER_PIN);
unsigned int sensorValues[NUM_SENSORS];

unsigned long Time;
int QTRstate = 0;

uint8_t mdVol = 0;
uint16_t mSpeed = 0;

#define DEVICE_NAME       "BLE_Peripheral"
#define TXRX_BUF_LEN      20
// Create ble instance
BLE                       ble;

// The uuid of service and characteristics
static const uint8_t service1_uuid[]         = {0x71, 0x3D, 0, 0, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t service1_chars1_uuid[]  = {0x71, 0x3D, 0, 2, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t service1_chars2_uuid[]  = {0x71, 0x3D, 0, 3, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t service1_chars3_uuid[]  = {0x71, 0x3D, 0, 4, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
// Used in advertisement
static const uint8_t uart_base_uuid_rev[]    = {0x1E, 0x94, 0x8D, 0xF1, 0x48, 0x31, 0x94, 0xBA, 0x75, 0x4C, 0x3E, 0x50, 0, 0, 0x3D, 0x71};

// Initialize value of chars
uint8_t chars1_value[TXRX_BUF_LEN] = {0};
uint8_t chars2_value[TXRX_BUF_LEN] = {0,};
uint8_t chars3_value[TXRX_BUF_LEN] = {0};
uint8_t tx_value[TXRX_BUF_LEN] = {0,};

// Create characteristic
GattCharacteristic  characteristic1(service1_chars1_uuid, chars1_value, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE );
GattCharacteristic  characteristic2(service1_chars2_uuid, chars2_value, 2, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
GattCharacteristic  characteristic3(service1_chars3_uuid, chars3_value, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
GattCharacteristic *uartChars[] = {&characteristic1, &characteristic2, &characteristic3};
//Create service
GattService         uartService(service1_uuid, uartChars, sizeof(uartChars) / sizeof(GattCharacteristic *));



//モータドライバ I2C制御 motor driver I2C
//参考 http://makers-with-myson.blog.so-net.ne.jp/2014-05-15
void writeMotorResister(byte vset, byte data1){
  int vdata = vset << 2 | data1;
  Wire.beginTransmission(DRV8830);
  Wire.write(0x00);
  Wire.write(vdata);
  Wire.endTransmission(true);
}


HeartRateService         *hrService;
DeviceInformationService *deviceInfo;
// Init HRM to 100bps
static uint16_t hrmCounter = 100;
/** @brief  Disconnect callback handle
 *
 *  @param[in] *params   params->handle : connect handle
 *                       params->reason : CONNECTION_TIMEOUT                          = 0x08,
 *                                        REMOTE_USER_TERMINATED_CONNECTION           = 0x13,
 *                                        REMOTE_DEV_TERMINATION_DUE_TO_LOW_RESOURCES = 0x14,  // Remote device terminated connection due to low resources.
 *                                        REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF     = 0x15,  // Remote device terminated connection due to power off.
 *                                        LOCAL_HOST_TERMINATED_CONNECTION            = 0x16,
 *                                        CONN_INTERVAL_UNACCEPTABLE                  = 0x3B,
 */
void disconnectionCallBack(const Gap::DisconnectionCallbackParams_t *params) {
  Serial.print("Disconnected hande : ");
  Serial.println(params->handle, HEX);
  Serial.print("Disconnected reason : ");
  Serial.println(params->reason, HEX);
  Serial.println("Restart advertising ");
  writeMotorResister(0x00, 0x00);
  ble.startAdvertising();
}

/** @brief  Connection callback handle
 *
 *  @param[in] *params   params->handle : The ID for this connection
 *                       params->role : PERIPHERAL  = 0x1, // Peripheral Role
 *                                      CENTRAL     = 0x2, // Central Role.
 *                       params->peerAddrType : The peer's BLE address type
 *                       params->peerAddr : The peer's BLE address
 *                       params->ownAddrType : This device's BLE address type
 *                       params->ownAddr : This devices's BLE address
 *                       params->connectionParams->minConnectionInterval
 *                       params->connectionParams->maxConnectionInterval
 *                       params->connectionParams->slaveLatency
 *                       params->connectionParams->connectionSupervisionTimeout
 */
void connectionCallBack( const Gap::ConnectionCallbackParams_t *params ) {
  uint8_t index;
  if(params->role == Gap::PERIPHERAL) {
    Serial.println("Peripheral ");
  }

  Serial.print("The conn handle : ");
  Serial.println(params->handle, HEX);
  Serial.print("The conn role : ");
  Serial.println(params->role, HEX);

  Serial.print("The peerAddr type : ");
  Serial.println(params->peerAddrType, HEX);
  Serial.print("  The peerAddr : ");
  for(index=0; index<6; index++) {
    Serial.print(params->peerAddr[index], HEX);
    Serial.print(" ");
  }
  Serial.println(" ");

  Serial.print("The ownAddr type : ");
  Serial.println(params->ownAddrType, HEX);
  Serial.print("  The ownAddr : ");
  for(index=0; index<6; index++) {
    Serial.print(params->ownAddr[index], HEX);
    Serial.print(" ");
  }
  Serial.println(" ");

  Serial.print("The min connection interval : ");
  Serial.println(params->connectionParams->minConnectionInterval, HEX);
  Serial.print("The max connection interval : ");
  Serial.println(params->connectionParams->maxConnectionInterval, HEX);
  Serial.print("The slaveLatency : ");
  Serial.println(params->connectionParams->slaveLatency, HEX);
  Serial.print("The connectionSupervisionTimeout : ");
  Serial.println(params->connectionParams->connectionSupervisionTimeout, HEX);
}

/** @brief  write callback handle of Gatt server
 *
 *  @param[in] *Handler   Handler->connHandle : The handle of the connection that triggered the event
 *                        Handler->handle : Attribute Handle to which the write operation applies
 *                        Handler->writeOp : OP_INVALID               = 0x00,  // Invalid operation.
 *                                           OP_WRITE_REQ             = 0x01,  // Write request.
 *                                           OP_WRITE_CMD             = 0x02,  // Write command.
 *                                           OP_SIGN_WRITE_CMD        = 0x03,  // Signed write command.
 *                                           OP_PREP_WRITE_REQ        = 0x04,  // Prepare write request.
 *                                           OP_EXEC_WRITE_REQ_CANCEL = 0x05,  // Execute write request: cancel all prepared writes.
 *                                           OP_EXEC_WRITE_REQ_NOW    = 0x06,  // Execute write request: immediately execute all prepared writes.
 *                        Handler->offset : Offset for the write operation
 *                        Handler->len : Length (in bytes) of the data to write
 *                        Handler->data : Pointer to the data to write
 */

//モータドライバ用データ送受信
void gattServerWriteCallBack(const GattWriteCallbackParams *Handler) {
  uint8_t index;
  uint8_t buf[TXRX_BUF_LEN];
  uint16_t bytesRead;

  //受信
  Serial.print("Write Handle : ");
  // Check the attribute belong to which characteristic
  if (Handler->handle == characteristic1.getValueAttribute().getHandle()) {
    // Read the value of characteristic
    ble.readCharacteristicValue(characteristic1.getValueAttribute().getHandle(), buf, &bytesRead);
    mdVol = buf[0];
    Serial.println(mdVol, DEC);
  }

  //送信
  ble.updateCharacteristicValue(characteristic2.getValueAttribute().getHandle(), (uint8_t *)&mSpeed, 2);
}

/**
 * @brief  Set advertisement
 */
void setAdvertisement(void) {
  // A list of Advertising Data types commonly used by peripherals.
  //   FLAGS                              = 0x01, // Flags, refer to GapAdvertisingData::Flags_t.
  //   INCOMPLETE_LIST_16BIT_SERVICE_IDS  = 0x02, // Incomplete list of 16-bit Service IDs.
  //   COMPLETE_LIST_16BIT_SERVICE_IDS    = 0x03, // Complete list of 16-bit Service IDs.
  //   INCOMPLETE_LIST_32BIT_SERVICE_IDS  = 0x04, // Incomplete list of 32-bit Service IDs (not relevant for Bluetooth 4.0).
  //   COMPLETE_LIST_32BIT_SERVICE_IDS    = 0x05, // Complete list of 32-bit Service IDs (not relevant for Bluetooth 4.0).
  //   INCOMPLETE_LIST_128BIT_SERVICE_IDS = 0x06, // Incomplete list of 128-bit Service IDs.
  //   COMPLETE_LIST_128BIT_SERVICE_IDS   = 0x07, // Complete list of 128-bit Service IDs.
  //   SHORTENED_LOCAL_NAME               = 0x08, // Shortened Local Name.
  //   COMPLETE_LOCAL_NAME                = 0x09, // Complete Local Name.
  //   TX_POWER_LEVEL                     = 0x0A, // TX Power Level (in dBm).
  //   DEVICE_ID                          = 0x10, // Device ID.
  //   SLAVE_CONNECTION_INTERVAL_RANGE    = 0x12, // Slave Connection Interval Range.
  //   LIST_128BIT_SOLICITATION_IDS       = 0x15, // List of 128 bit service UUIDs the device is looking for.
  //   SERVICE_DATA                       = 0x16, // Service Data.
  //   APPEARANCE                         = 0x19, // Appearance, refer to GapAdvertisingData::Appearance_t.
  //   ADVERTISING_INTERVAL               = 0x1A, // Advertising Interval.
  //   MANUFACTURER_SPECIFIC_DATA         = 0xFF  // Manufacturer Specific Data.

  // AD_Type_Flag : LE_LIMITED_DISCOVERABLE = 0x01, Peripheral device is discoverable for a limited period of time
  //                LE_GENERAL_DISCOVERABLE = 0x02, Peripheral device is discoverable at any moment
  //                BREDR_NOT_SUPPORTED     = 0x03, Peripheral device is LE only
  //                SIMULTANEOUS_LE_BREDR_C = 0x04, Not relevant - central mode only
  //                SIMULTANEOUS_LE_BREDR_H = 0x05, Not relevant - central mode only
  ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
  // Add short name to advertisement
  ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,(const uint8_t *)"Biscuit", 7);
  // Add complete 128bit_uuid to advertisement
  ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,(const uint8_t *)uart_base_uuid_rev, sizeof(uart_base_uuid_rev));
  // Add complete device name to scan response data
  ble.accumulateScanResponse(GapAdvertisingData::COMPLETE_LOCAL_NAME,(const uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME) - 1);
}

void setup() {
  // put your setup code here, to run once
  Serial.begin(9600);
  Wire.begin(D3, D2, 400000L);
  writeMotorResister(0x00, 0x00);
  
  Serial.println("Start ");
  pinMode(D13, OUTPUT);
  ble.init();
  ble.onConnection(connectionCallBack);
  ble.onDisconnection(disconnectionCallBack);
  ble.onDataWritten(gattServerWriteCallBack);
  // set advertisement
  setAdvertisement();
  // set adv_type(enum from 0)
  //    ADV_CONNECTABLE_UNDIRECTED
  //    ADV_CONNECTABLE_DIRECTED
  //    ADV_SCANNABLE_UNDIRECTED
  //    ADV_NON_CONNECTABLE_UNDIRECTED
  ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
  // add service
  hrService  = new HeartRateService(ble, hrmCounter, HeartRateService::LOCATION_FINGER);
  deviceInfo = new DeviceInformationService(ble, "ARM", "Model1", "SN1", "hw-rev1", "fw-rev1", "soft-rev1");
  ble.addService(uartService);
  // set device name
  ble.setDeviceName((const uint8_t *)DEVICE_NAME);
  // set tx power,valid values are -40, -20, -16, -12, -8, -4, 0, 4
  ble.setTxPower(4);
  // set adv_interval, 100ms in multiples of 0.625ms.
  ble.setAdvertisingInterval(160);
  // set adv_timeout, in seconds
  ble.setAdvertisingTimeout(0);
  // ger BLE stack version
  Serial.print("BLE stack verison is : ");
  Serial.println(ble.getVersion());
  // start advertising
  ble.startAdvertising();
  Serial.println("start advertising ");
}

void loop() {
  //モータードライバ電圧指定
  if(mdVol < 6){
    writeMotorResister(0x00, 0x00);
  }else {
    writeMotorResister((byte)mdVol, 0x01);
  }
  
  //フォトリフレクタ処理
  // read raw sensor values
  qtra.read(sensorValues);

  if(sensorValues[0] < 900 && QTRstate == 0){
    QTRstate = 1;
    mSpeed = micros()-Time;
    Time = micros();
  }
  
  if(sensorValues[0] > 920 && QTRstate == 1){
    QTRstate = 0;
  }
}

まとめ

デバイス同士の通信が確認できて一安心。
以下直近の実施予定項目です。
 
  • ステップ3:Redbear DuoでLED(Dotstar)制御確認
  • ステップ4:スマホ – Redbear Duo でLED色・回転速度WiFi制御
  • ステップ5:POV基本動作確認

 

まだまだコレ↓を実現するには時間かかりそう。。。

次の記事

Redbear DuoでDotstarを制御 -球体POV製作への道 その5-

BLE NanoでDCモータ制御 w/ Android -球体POV製作への道 その3-

さて随分あいだがあいてしまいましたがPOV再開です。

球体POV製作への道 その1

前回ステッピングモータを使用してみたのですが全然スピード出なかったので方針変更して

  • DCモーターのスピードをBLE Nano介してスマホでコントロール
  • フォトリフレクタで回転スピード検出

で行こうと決め実行しました!

全体概要

部品

  • フォトリフレクタ QTR-1A
  • BLE搭載マイコン BLE Nano
  • モータードライバ DRV8830
  • DCモーター 100均の電動泡立て機のやつ(普通のモーター)

動作

BLE介してスマホのスライダでDCモーターへの供給電圧を0.5~3.0Vまで変化させ回転スピードを制御してます。
モータの羽(割り箸)付近にフォトリフレクタを配置し回転スピードを計測してます。スマホには一周あたりにかかる時間[usec]が表示されてます。

回転スピード計測

POV表示させるためには回転位置を把握する必要があるので位置検出にフォトリフレクタを採用しました。
全然関係ないけど赤外線ってスマホカメラでみると紫色にみえるよね。この前炭火焼きハンバーグ屋さんで炭撮ろうとしたら紫色に輝いてた。

どれほど効果あるかは不明ですがモーターの羽に使ってる割りばしの先を黒く塗ってますww 羽がフォトリフレクタを通過するとカウント開始し次の通過までの時間を測定します。

フォトリフレクタ QTR-1A

[amazonjs asin=”B014FB8E5C” locale=”JP” title=”QTR-1A フォトリフレクタ・モジュール (2個セット)”]

2個で550円。安い!Arduino用ライブラリは以下に。
https://github.com/pololu/qtr-sensors-arduino

POV表示の際には2個もしくは4個のフォトリフレクタ使って回転位置検出しようと考えています。
あとモーターもちゃんとしたの選定しないと。。。

ステップ1まとめ

とりあえず無線で回転制御の第一歩は出来ました。

ステップ2では
RedBear DuoとBLE Nano間での通信を確立し、Duo側から回転制御できるようにしようと思います。

えい!えい!おー!

次の記事

Redbear DuoでDotstarを制御 -球体POV製作への道 その5-

 

BLE Nanoでステッピングモータ制御 -球体POV製作への道 その2-

前回 考えた仕様の検証ステップ1ということで

の確認をしたいと思います。

BLE Nanoからパルス出してモータドライバをコントロールします。せっかくBLEなのでスマホのスライダで回転スピード制御できるようにもしました icon-bolt 

 

うん!一応うごいた!でもステッピングモータの回転が思いのほかおそい!
これじゃ残像残らないよね。。。こりゃモータ再考必要だな。。。

次の記事

BLE Nano – Redbear Duo間通信でモータ制御 -球体POV製作への道 その4-

球体POV製作への道 その1

以下のような球体のPOV(Persistent Of Vision)装置を作りたくこちらで
進捗など記載できればとおもいペンをとります。

 POV(Persistent Of Vision)とはLEDなどを高速に動かして残像で映像を表示するものです。

 システム(あくまで理想) 

回転部と制御部でどう結線(電源線やデータ線)するかず~っと悩んでたのですが
BLEやWiFi使えばいいじゃないか!と思いたち上の図のような感じでいこうと思います。
ちょっとずつ検証・製作の報告できればと。。
んで完成させて子供たちを驚かせるぞー! ウェイ ウェイ オー 💡 !
 

次の記事

BLE Nanoでステッピングモータ制御 -球体POV製作への道 その2-

 

BLE制御ダイソー版 プラレール製作工程

先日Maker Faire Bay Area 2016でも展示していただいたBLEトレインの製作工程を紹介します!
[bc url =”https://homemadegarbage.com/mfba16″]
BLE電車概要
  • 1両目に左右に歩行転換するためのサーボモータとバッテリーを搭載
  • 2両目にはモータドライバとBLEマイコンを搭載
  • モータと電源スイッチはもともと電車についてるものを流用
スマホ画面

スマホのジョイスティックの動きに連動してモータとサーボがうごき電車をコントロールします。
ジョイスティックは以下のライブラリを利用させていただきました
材料

1. 左右方向変更用サーボの搭載

1-1 2両目の車両のサーボモータ配線を通すための穴を開ける
 
1-2 サーボの余分な分切り取る
 
1-3 サーボを載せるため1両目の車輪部の後方切る
 
1-4 1両目切り取りサーボ接着
 
1-5 サーボの羽と車両連結部品 加工して接着
 
サーボ動作テスト

 

2. モータドライバ搭載

2-1 I2Cプルアップ抵抗4.7kohm実装
 
2-2 2両目モータ電極加工
 
2-3 スイッチ手前に電極追加(モータドライバとBLE Nanoへの電源配線付き)
 
2-4 モータ電極間に10nF実装
 
2-5 LiPoバッテリー用ジャンパーワイヤ接続
 
2-6 ドライバ実装
 
モータドライバ動作テスト

BLE Nano搭載、サーボ結線

3-1 BLE Nanoハンダ
 
3-2 サーボ結線
 
3-3 LiPoバッテリー接続

出来上がり

以上で完成です!! 🙂 
 

ハンダ付け動画

工程2-6から完成までの延々ハンダ付けの地獄の動画 ぜひご覧くださいwwww

Maker Faire Bay Area 2016 RedBear社ブースに協力させて頂きました

スマホで動く電車のおもちゃを作って動画やブログをアップしたのですが
[bc url =”https://homemadegarbage.com/ble-plarail”]
なんとこの電車に利用したBLE Nanoを製造・販売しているRed Bear Company様からMaker Faire Bay Area 2016に電車を展示したいとの依頼頂きました。
 
BLE Nanoを送付いただきBLE電車をデモ展示用に作製しました。
(RedBear DuoやRedBear RBLinkも送っていただいた!ありがたや~~( ノД`))。
 
 
せっせと製作し
 
丹精込めて梱包(家内制手工業)

Maker Faire Bay Area 2016会場の様子

 
 
 
 

みんなうちの子たちと同じようにあそんでるーー 😆 !カワイイ。。。
こうやってネット上だけでなくリアル物流も発展してるから海外でも簡単にモノ送りあって
数日でやりたいこと実現できるねぇ
素晴らしい時代だ!

WiFi MicroとBlynkで室温記録

してみました!

システム概要

 

DS3231ボードをI2CでWiFi Microにつないで温度情報をBlynkアプリでプロットします。
WiFi Microの詳細についでは以下も参照ください。
[bc url = “https://homemadegarbage.com/wifi-micro01”]

DS3231

正確な時間クロックを刻むリアルタイムクロック(RTC)デバイスです。温度センサも内蔵されてます。
[amazonjs asin=”B011DT3E36″ locale=”JP” title=”HiLetgo DS3231 AT24C32 時計モジュール リアル時間時計モジュール IICモジュール RTCモジュール for Arduino 並行輸入品”]
安すぎる。。。
以下にArduino用のライブラリとプログラム例アップされてます。
 こちらのDS3231_temperature.inoを参考にI2Cで温度取得します。

Blynk設定

Blynk詳細はhttp://www.blynk.cc/getting-started過去記事を参照ください。
以下のBlynk用ライブラリをDL、解凍し所定のEnergiaライブラリフォルダにアップします。
 
 
温度表示用のLabeled Valueと温度変化履歴をプロットするHistory Graphを配置。
おまけでButton配置してD13ピンを指定しました。
WiFi MicroのD13にはLEDが載ってますんでコレ押すとON/OFF出来ます

Energia用コード

#define BLYNK_PRINT Serial  
#include <SPI.h>
#include <WiFi.h>
#include <Wire.h>
#include <DS3231.h> //https://github.com/jarzebski/Arduino-DS3231
#include <BlynkSimpleRBL_CC3200.h>

DS3231 clock;
RTCDateTime dt;

float temp;

//Blynkアプリで取得したAuth Tokenを入力
char auth[] = "xxxxx";

//WiFiのSSID、パスワード指定
char ssid[] = "xxxxx";
char pass[] = "xxxxx";

void setup()
{
  Serial.begin(9600);

  // Initialize DS3231
  Serial.println("Initialize DS3231");
  clock.begin();
  
  Blynk.begin(auth, ssid, pass);
}

//ヴァーチャルピンV1に温度データアップ
BLYNK_READ(V1)
{
  clock.forceConversion();
  temp = clock.readTemperature();
  Blynk.virtualWrite(V1, temp);
  Serial.println(temp);
}

void loop()
{
  Blynk.run();
}

実行

最近平穏な気候過ぎて全然おもしろくないグラフに。。。。
 
冬にESP-WROOM-02でやった時は灯油ストーブが設定温度保とうと頑張ってる様子や
お母ちゃんがお迎え行ってストーブ消した様子も見れて面白かったですよ
 
ちなみに5/25にBlynkサーバ落ちたっぽく全然使えなくなった。。。。恐らく初めてだよね?コニュニティ賑わってたwww
独自のサーバ立てて使えるみたいだけど、そうなると ちと敷居高いよなぁ。。。。 🙄 

RedBearLab WiFi Micro の設定方法 for Windows

WiFi Microとは

RedBear社のTI製WiFiコアCC3200搭載の小型マイコンです。
上に刺さってるのがWiFi Microで下の基板がUSB書き込み用ボードのMK20
 
購入先
[amazonjs asin=”B018M1F1J8″ locale=”JP” title=”RedBearLab WiFi Microキット”]
すでにMK20を持ってる場合は
[amazonjs asin=”B018M18BR2″ locale=”JP” title=”RedBearLab WiFi Micro”] 
 
ピン配置
小さいけどピン数豊富でPWM出力やアナログ入力も複数あって便利!

MK20 USB boardの設定

初めてMK20を使用の場合はBLE Nanoの設定記事と同様にドライバ設定必要です。
  • https://developer.mbed.org/handbook/Windows-serial-configuration
    でmbed Windows serial port driverのexeファイルをダウンロードし実行
    無事インストールされるとMK20がシリアルポートとして認識されコード書き込みの準備が完了です♪
    “MBED”ドライブと表示されます。
  • ボタンを開放し”BOOTLOADER”ドライブにBLENano_MK20.binをドラッグ
  • 読み込まれるとLEDが高速で点滅しPCに再接続で”MBED”ドライブが表示されれば完了です。

Energia設定

EnergiaはTI製デバイスをサポートするオープン・ソースの統合開発環境(IDE)で
インターフェースはArduinoに非常に似ています。
 
以下ページの”Using Energia”の通りで設定できますが順をおって記載します。

   CC3200 LaunchPad CDC drivers zip file for Windows 32 and 64 bit
    DL、解凍してWindows 32bitの場合は DPinst.exeを、
    64bitの場合はDPinst64.exeを実行

これでEnergiaでWiFi Microを使う準備が整いました!

Energia IDEのメニュー[ツール]->[マイコンボード]でRedBearLab WiFi Micro w/ cc3200 (80MHz)を選択し[シリアルポート]で接続したWiFi Microを指定するとプログラム書き込みが可能となります 🙂