エアロバイクでストリートビュー進みたい！！ （その3）（Seeeduino XIAO化してみた）

## やりたいこと
エアロバイクしながらストリートビューでその場所に行った気になりたい。

過去記事の
[**エアロバイクでストリートビュー進みたい！！ （その1）**]
(https://qiita.com/dattaman9/items/e875132eab9dd43f1d83)
では、前にすすむだけ。右や左に方向転換するのにはWiiヌンチャクを使っていた。
[**エアロバイクでストリートビュー進みたい！！ （その2）**]
(https://qiita.com/dattaman9/items/5d9fb3f8ba51fc6bee67)
では、前に進む+方向転換ボタンで曲がれるようにしてみた。

→ずっとArduino Leonardoじゃなぁ。。

（※内容重複なところはそのまま）

---

### 背景
* 札幌なので、冬は自転車乗れないなー。運動したいなー。
で、エアロバイクを買って2年半。
こんなの。
![K0000788333.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634480/df4ae070-88db-a2d0-ec96-3ed0ba877877.png)
ALINCO(アルインコ) コンフォートバイク AFB4309W 8段階負荷調節 折りたたみ機能付 アルインコ(Alinco) 
https://www.amazon.co.jp/dp/B00VHWRXYG/

* 「こころ旅」をみながら、いいなー。チャリオで行きたいなー。　あ、とりあえずストリートビュー見ながらエアロバイクこげばいいじゃん！　と気づく。

---


### 動機
エアロバイクは、TV兼PCモニターが正面にあるので、ストリートビューを開く。

* USBキーボードをエアロバイクのハンドルに置き、進むたびに↑↑を連打。
　→なんか、カーソルキーしか使わないのにジャマ。
* ころがっていたWiiコントローラー&ヌンチャクをBluetoothでPCに接続。ヌンチャクで↑↑で進む。
　→やっぱり、こいだら前に進ませたい。

と悩んでいたところ、

@ie4　さんの記事を見つけた！　これはすごい。　やってみよー。
https://qiita.com/ie4/items/130308793444bd98179f


---


## 機能

[前提]
・エアロバイクの機能はこわさない
・GoogleMapのAPIはつかわない。履歴とか特にいいや。
　→エアロバイクをこぐと、ストリートビューが前に進むことだけ。
　→1こぎxxメートルとかの距離はあんまり気にしない。風景がみれればOK。

　となると、↓だけあればいいんだな。
* エアロバイクをこぐと、キーボードの上が入力される
あと、
* エアロバイクのハンドルに、右と左のタクトスイッチをつけ、押すとキーボードの右・左が入力される

---


## 構成

* Arduino Leonardo 的な、HID キーボードになるArduino
→これを、小さくしたいー。ということで、
[**Seeeduino XIAO**](https://www.seeedstudio.com/Seeeduino-XIAO-Arduino-Microcontroller-SAMD21-Cortex-M0+-p-4426.html) を買ってみた。

* 100均のステレオコード分岐
* 100均のステレオ延長コード
* タクトスイッチ2つ　（ホームセンターで適当なの）
* 平行コード（同じくホームセンターで適当なの）

---


で、

### エアロバイクのメーターコードと接続

* ステレオ延長コードをぶちっと切り、コードをArduinoに挿せるように加工
　→ひさしぶりのはんだ付け。
* エアロバイクの本体とモニターの間のコード連結に、ステレオコード分岐をかます
![Up.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634480/f401aa1a-41c8-cd75-fa2f-f613905101d0.png)

* ステレオコード分岐から、加工した延長コードをつなぐ
* ArduinoのGNDとDigital2に、LとRをつなぐ

---


### 左右スイッチ

* タクトスイッチに、平行ケーブルをつなぐ
* ArduinoのGNDと、右はDigital3, 左はDigital4につなぐ

### 適当すぎる回路図
こんな感じ。
![cycle2_回路図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634480/52406abc-f127-3f7d-3206-a0176d1072bc.png)

---


### ケーブル整理&はんだ付け
* エアロバイクメーター　>　ステレオケーブル　(L→Meter、R→GND。GNDは使わない)
* タクトスイッチ　>　イヤホンケーブル　(L、R、GND)

を、Meter、L、R、GNDの4つにまとめて、ころがってた電話線で延長して、Seeeduino XIAOにはんだ付け。
こんな感じ。ちいさいー。
![SeeduinoXiao1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634480/fa8ccf49-92a3-15dc-afcc-58ff17b21089.png)


---



## Seeeduino XIAO対応
Arduino Leonardoで書き込んでいたスケッチを、そのままSeeeduino XIAOに書き込もうとしたところ、エラー。。なんで。。

検索すると、TinyUSBをつかうらしい。
https://www.seeedstudio.com/blog/2020/04/30/tinyusb-stack-on-seeeduino-xiao/
https://github.com/adafruit/Adafruit_TinyUSB_Arduino

なるー。ツールのUSB Stack は、 TinyUSBを選ぶんかぃ。

ではTinyUSB付属のスケッチ例、Adafruit TinyUSB Library > HID > hid_keyboard を改造してくか。

---


まずは、そのまま書き込み。エラーなし！　おおー。

次は、キーボードの上と左右。
んー？何を書けばいいのか。。。
適当に、HID_KEY_UP_ARROW とかだと、定義がないって怒られる。。
ソース検索&いろいろググってみたけど、見つからない。。

---


しょーがない。
自分で定義しちゃぇ。
と、強引に定義したら、うまくいったー。

```c
#define KEY_UP_ARROW    0x52
#define KEY_LEFT_ARROW    0x50
#define KEY_RIGHT_ARROW   0x4F
```

---


## スケッチ
ということで、TinyUSBのhd_keyboardに、ちょっとだけ手を入れたスケッチ。

```c

/*********************************************************************
 Adafruit invests time and resources providing this open source code,
 please support Adafruit and open-source hardware by purchasing
 products from Adafruit!

 MIT license, check LICENSE for more information
 Copyright (c) 2019 Ha Thach for Adafruit Industries
 All text above, and the splash screen below must be included in
 any redistribution
*********************************************************************/

#include "Adafruit_TinyUSB.h"

/* This sketch demonstrates USB HID keyboard.
 * - PIN A0-A5 is used to send digit '0' to '5' respectively
 * - LED will be used as Caplock indicator
 */

#define KEY_UP_ARROW    0x52
#define KEY_LEFT_ARROW    0x50
#define KEY_RIGHT_ARROW   0x4F

// HID report descriptor using TinyUSB's template
// Single Report (no ID) descriptor
uint8_t const desc_hid_report[] = 
{
  TUD_HID_REPORT_DESC_KEYBOARD(),
};

Adafruit_USBD_HID usb_hid;

// Array of pins and its keycode
// For keycode definition see BLEHidGeneric.h
// uint8_t pins[]    = { A0, A1, A2, A3, A4, A5 };
// uint8_t hidcode[] = { HID_KEY_0, HID_KEY_1, HID_KEY_2, HID_KEY_3 , HID_KEY_4, HID_KEY_5 };

uint8_t pins[]    = { A2, A3, A4 };
uint8_t hidcode[] = { KEY_UP_ARROW, KEY_RIGHT_ARROW, KEY_LEFT_ARROW };

uint8_t pincount = sizeof(pins)/sizeof(pins[0]);

// the setup function runs once when you press reset or power the board
void setup()
{
  usb_hid.setPollInterval(2);
  usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
  usb_hid.setReportCallback(NULL, hid_report_callback);

  usb_hid.begin();

  // led pin
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  // Set up pin as input
  for (uint8_t i=0; i<pincount; i++)
  {
    pinMode(pins[i], INPUT_PULLUP);
  }

  // wait until device mounted
  while( !USBDevice.mounted() ) delay(1);
}


void loop()
{
  // poll gpio once each 2 ms
  delay(2);

//  // Remote wakeup
//  if ( USBDevice.suspended() && btn )
//  {
//    // Wake up host if we are in suspend mode
//    // and REMOTE_WAKEUP feature is enabled by host
//    USBDevice.remoteWakeup();
//  }

  if ( !usb_hid.ready() ) return;

  static bool keyPressedPreviously = false;
  bool anyKeyPressed = false;

  uint8_t count=0;
  uint8_t keycode[6] = { 0 };

  // scan normal key and send report
  for(uint8_t i=0; i < pincount; i++)
  {
    if ( 0 == digitalRead(pins[i]) )
    {
      // if pin is active (low), add its hid code to key report
      keycode[count++] = hidcode[i];

      // 6 is max keycode per report
      if (count == 6)
      {
        usb_hid.keyboardReport(0, 0, keycode);
        delay(2); // delay for report to send out

        // reset report
        count = 0;
        memset(keycode, 0, 6);
      }

      // used later
      anyKeyPressed = true;
      keyPressedPreviously = true;
    }
  }

  // Send any remaining keys (not accumulated up to 6)
  if ( count )
  {
    usb_hid.keyboardReport(0, 0, keycode);
  }

  // Send All-zero report to indicate there is no keys pressed
  // Most of the time, it is, though we don't need to send zero report
  // every loop(), only a key is pressed in previous loop()
  if ( !anyKeyPressed && keyPressedPreviously )
  {
    keyPressedPreviously = false;
    usb_hid.keyboardRelease(0);
  }
}

// Output report callback for LED indicator such as Caplocks
void hid_report_callback(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
{
  // LED indicator is output report with only 1 byte length
  if ( report_type != HID_REPORT_TYPE_OUTPUT ) return;

  // The LED bit map is as follows: (also defined by KEYBOARD_LED_* )
  // Kana (4) | Compose (3) | ScrollLock (2) | CapsLock (1) | Numlock (0)
  uint8_t ledIndicator = buffer[0];

  // turn on LED if caplock is set
  digitalWrite(LED_BUILTIN, ledIndicator & KEYBOARD_LED_CAPSLOCK);
}
```

---


## 動作確認
動いたー！
ぐるぐるすると、進むぞ進むぞ。
右スイッチで右を、左スイッチで左を向くぞー。

行ってみて楽しかったところ

* 久慈→小袖海岸 あまちゃん好きとしては欠かせない
* 青島　ねこだらけ
* 大久野島　うさぎだらけ
* 布部駅→麓郷　畑と山ばっかだったー。木材店があるー。
* 銀山温泉　雪景色だー。行ってみたい！
* 市川ぞうの国　視線が高い！もしかして、ぞうの上？

---


## 参考

【フィットネスバイク】のインターネットを作る！！
 https://qiita.com/ie4/items/130308793444bd98179f
　※この記事があればこそ、今回できました！

DENKOのアヤしいお部屋。
https://ht-deko.com/
　※Arduino、何を選ぶか勉強させていただきました！

---


## 最後に
小さくなったので、フリスクケースに入れるー。
でも、もうプログラミングじゃないな。Qiitaに書くのはこれでおしまい。

※エアロバイクって、商標かー。
フィットネスバイク？　コンフォートバイク？
一般的には、やっぱエアロバイクだよなぁ。。