Шестикнопочный пульт управления приложением Microsoft Soundscape

Пользоваться приложением Microsoft Soundscape (почему-то доступным только для операционной системы iOS), позволяющим слепым ориентироваться в пространстве и узнавать, что находится вокруг них, при помощи голосовых подсказок, будет ещё удобнее, если изготовить внешний шестикнопочный пульт, предложенный тремя авторами Instructables — Jazz Ang, Ana Liu и Venkatesh Potluri.

Строго говоря, Soundscape — разработка не самой корпорации Microsoft, а её подразделения под названием Microsoft Research, занимающегося экспериментами и исследованиями в самых разнообразных областях. Считается, что даже внутренняя атмосфера там совсем иная, чем во всей остальной корпорации.

Назначение кнопок на пульте:

1 — пуск/стоп проигрывания аудио- или видеофайла, а при запущенном и работающем в фоне приложении Soundsdape — также включение/выключение голосовых уведомлений от этой программы.

2 — полное включение/выключение звука, аналог кнопки Mute на пульте телевизора.

3 — переход к следующей дорожке в аудио- или видеопроигрывателе, а в программе Soundscape — переход к следующему голосовому уведомлению.

4 — переход к предыдущей дорожке или голосовому уведомлению.

5 — дублирует кнопку Home.

6 — управление режимом «Виртуальный контроллер» операционной системы iOS (позволяет пользоваться внешними пультами наподобие описываемого).

Как видно из схемы самоделки, составленной в программе Fritzing, кнопки, каждая из которых дополнена подтягивающим резистором на 10 кОм, подключены к выводам 11, 7, 15, 16, 27 и 25 довольно дорогой платы Adafruit Feather nRF52 Bluefruit LE, которая совместима с Arduino IDE и содержит Bluetooth-модуль. При пользовании устройством эта плата питается по стандартному Micro USB-кабелю от пауэрбанка, а при программировании — от ПК. Следует учитывать, что многие пауэрбанки при слишком малом потребляемом токе отключаются автоматически, причём порог отключения зависит от модели.

Собрав конструкцию по схеме, мастера настраивают Arduino IDE для работы с этой платой, как показано на следующих двух скриншотах:


Настроив всё, мастера заливают в плату скетч:

#include 

#define CONTROL_PLAY_PAUSE      0x00CD
#define CONTROL_SCAN_NEXT       0x00B5
#define CONTROL_SCAN_PREVIOUS   0x00B6
#define CONTROL_MUTE            0x00E2
#define AC_FORWARD              0x0225
#define AC_BACK                 0x0224
#define CONSUMER_BROWSER_HOME   0x0223

BLEDis bledis;
BLEHidAdafruit blehid;

bool hasKeyPressed = false;
//connect pins in the board
int playpauseButtonPin = 11;
int muteButtonPin = 7;
int nextButtonPin = 15;
int backButtonPin = 16;
int homeButtonPin = 27;
int switchControlButtonPin = 25; 

void setup() 
{
  pinMode(playpauseButtonPin, INPUT);
  pinMode(muteButtonPin, INPUT);
  pinMode(nextButtonPin, INPUT);
  pinMode(backButtonPin, INPUT);
  pinMode(homeButtonPin, INPUT);
  pinMode(switchControlButtonPin, INPUT);
  
  Serial.begin(115200);
  while ( !Serial ) delay(10);   // for nrf52840 with native usb

  Bluefruit.begin();
  Bluefruit.setTxPower(4);    // Check bluefruit.h for supported values
  Bluefruit.setName("TESTArroundMeBluefruit52");

  // Configure and Start Device Information Service
  bledis.setManufacturer("Adafruit Industries");
  bledis.setModel("Bluefruit Feather 52");
  bledis.begin();

  /* Start BLE HID
   * Note: Apple requires BLE device must have min connection interval >= 20m
   * ( The smaller the connection interval the faster we could send data).
   * However for HID and MIDI device, Apple could accept min connection interval 
   * up to 11.25 ms. Therefore BLEHidAdafruit::begin() will try to set the min and max
   * connection interval to 11.25  ms and 15 ms respectively for best performance.
   */
  blehid.begin();

  /* Set connection interval (min, max) to your perferred value.
   * Note: It is already set by BLEHidAdafruit::begin() to 11.25ms - 15ms
   * min = 9*1.25=11.25 ms, max = 12*1.25= 15 ms 
   */
  /* Bluefruit.Periph.setConnInterval(9, 12); */

  // Set up and start advertising
  startAdv();
}

void startAdv(void)
{  
  // Advertising packet
  Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
  Bluefruit.Advertising.addTxPower();
  Bluefruit.Advertising.addAppearance(BLE_APPEARANCE_HID_KEYBOARD);
  
  // Include BLE HID service
  Bluefruit.Advertising.addService(blehid);

  // There is enough room for the dev name in the advertising packet
  Bluefruit.Advertising.addName();
  
  /* Start Advertising
   * - Enable auto advertising if disconnected
   * - Interval:  fast mode = 20 ms, slow mode = 152.5 ms
   * - Timeout for fast mode is 30 seconds
   * - Start(timeout) with timeout = 0 will advertise forever (until connected)
   * 
   * For recommended advertising interval
   * https://developer.apple.com/library/content/qa/qa1931/_index.html   
   */
  Bluefruit.Advertising.restartOnDisconnect(true);
  Bluefruit.Advertising.setInterval(32, 244);    // in unit of 0.625 ms
  Bluefruit.Advertising.setFastTimeout(30);      // number of seconds in fast mode
  Bluefruit.Advertising.start(0);                // 0 = Don't stop advertising after n seconds
}

//using this function to control phone 
void sendCommand(uint16_t command) {
  // Make sure we are connected and bonded/paired
  for (uint16_t conn_hdl=0; conn_hdl < BLE_MAX_CONNECTION; conn_hdl++)
  {
    BLEConnection* connection = Bluefruit.Connection(conn_hdl);

    if ( connection && connection->connected() && connection->paired() )
    {
      // Turn on red LED when we start sending data
      digitalWrite(LED_RED, 1);
      Serial.println("Sending command...");

      // Send key press
      blehid.consumerKeyPress(conn_hdl, command);

      // Delay a bit between reports
      delay(10);

      // Send key release
      blehid.consumerKeyRelease(conn_hdl);

      // Turn off the red LED
      digitalWrite(LED_RED, 0);
      Serial.println("Command sent!");
    }
  }

  delay(250);
}

//using this function to configure with switch control 
void sendSwitchControl(String command) {
  for (int i = 0; i < command.length(); i++) {
    blehid.keyPress(command.charAt(i));
    Serial.write(command.charAt(i));
    delay(5);
  }
  delay(250); // avoid sending the same command again and again
}

void loop() 
{
  //button to play or pause players
  if (digitalRead(playpauseButtonPin) == HIGH) {
    sendCommand(CONTROL_PLAY_PAUSE);
  }

  //button to mute the phone
  if (digitalRead(muteButtonPin) == HIGH) {
    sendCommand(CONTROL_MUTE);
  }

  //button to play next media
  if (digitalRead(nextButtonPin) == HIGH) {
    sendCommand(CONTROL_SCAN_NEXT);
    sendCommand(AC_FORWARD);
  }

  //button to play last media
  if (digitalRead(backButtonPin) == HIGH) {
    sendCommand(CONTROL_SCAN_PREVIOUS);
    sendCommand(AC_BACK);
  }

//button to go back home
  if (digitalRead(homeButtonPin) == HIGH) {
    sendCommand(CONSUMER_BROWSER_HOME);
  }

//switch control 'select' 
  if (digitalRead(switchControlButtonPin) == HIGH) {
    sendSwitchControl("SELECT");
    if (pressed){
      blehid.keyRelease(switchControlButtonPin);
      pressed=false;
      }
  }
 
  delay(5);
}

Со стороны операционной системы iOS мастера настраивают сначала сопряжение с пультом по Bluetooth:

Затем — функции всех кнопок в разделе специальных возможностей:

Убедившись, что всё работает, мастера печатают на 3D-принтере толкатели для кнопок и делятся необходимыми для этого файлами с читателями на Thingiverse под лицензией CC-BY 3.0. Эти детали можно изготовить и другими способами, либо не изготавливать вообще.

На следующих двух видео показано, как мастера испытывают пульт в действии:

Остаётся пересобрать пульт по той же схеме, но пайкой, и поместить результат в корпус, а в iOS установить приложение Soundscape и запустить его в фоне, и устройством можно пользоваться.

Источник

(Visited 8 times, 1 visits today)

About the author

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *