kon104 が 2021年03月28日17時54分18秒 に編集
初版
タイトルの変更
iPadやPC問わずフィットネスバイクとストリートビューを連動するアダプター製作
タグの変更
Arduino
joystick
StreetView
メイン画像の変更
本文の変更
# はじめに リモートワークや外出自粛で巣ごもり生活が多くなったので 運動不足解消にフィットネスバイク(エアロバイク)を買ってみましたが、 ご多分に漏れず長続きしなかったので、ArduinoでGoogleストリートビューに連携するアダプターを作ってみました。 先駆者「[【フィットネスバイク】のインターネットを作る!!](https://qiita.com/ie4/items/130308793444bd98179f)」の事例等では、 ペダルのフィードバックをインターネット経由でストリートビューの進行に反映しているが、 今回作ったアダプターはUSBキーボードとして機能するため、ダイレクトにデバイスに伝わるので、 Windows PCやMacはモチロンのこと、iPadやAndroidのデバイスでも動作し、 エアロバイクとデバイスに繋ぐだけの簡単セットアップで、気軽にエクササイズを開始できます。 ハンドルの舵取りはジョイスティックで操作します。 なお、USBデバイスとして動作させるにはATmega32u4搭載のArduinoを利用するのが手っ取り早いので、 今回の製作では該当コントローラーを搭載しているArduino Microを使っています。 # イメージ ## 利用イメージ @[youtube](https://www.youtube.com/watch?v=PZ_syFKAs-Q) ## アダプター ダイソーの500円コインケースを加工して、Arduino Microとジョイスティックを組み込みました ![キャプションを入力できます](https://camo.elchika.com/f6b49df89232eab883346ad1edc6f18531b1367e/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f37623038363239362d656238322d346433362d396235632d6563353461396662373834372f38376135306633652d366630652d346465342d626436372d346137633862323234383861/) 加工したコインケースに配線前のArduinoを組み込みしてみた写真(左)と、iPadとフィットネスバイクに実際に繋いだ写真(右) ![キャプションを入力できます](https://camo.elchika.com/1b90fcb007358b2c226be128f010481d237d342e/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f37623038363239362d656238322d346433362d396235632d6563353461396662373834372f34636338646233302d646434362d343966652d626561612d336464376134323966303664/) # 構成 システム全体の構成図です ![キャプションを入力できます](https://camo.elchika.com/e17f911aa50702a689844abb5956f6878a094eb6/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f37623038363239362d656238322d346433362d396235632d6563353461396662373834372f61666564316365622d346537632d346531352d623438302d306639666461346432643363/) - 利用しているフィットネスバイクは「[ALINCO クロスバイク4417](https://www.alinco.co.jp/product/fitness/detail/id=4177)」 - ペダルの回転判定のメーターへの連動は、オーディオケーブルが使われている - メーターへの接続直前にオーディオ分配ケーブルを割り込ませ、アダプターを接続できるようにする - アダプターがストリートビューの進行を制御する - ペダルの回転でストリートビューを前進する - ハンドルの舵取りはジョイスティックで左右転回する - Lightning端子のiOSデバイスは「[Lightning - USBカメラアダプタ](https://www.apple.com/jp/shop/product/MD821AM/A/lightning-usb%E3%82%AB%E3%83%A1%E3%83%A9%E3%82%A2%E3%83%80%E3%83%97%E3%82%BF)」を使いUSBケーブルへ接続する - アプリ版のGoogleマップはキーボード移動に対応していないので、iPad/iPhone、Androidの場合でもブラウザ版を利用する - https://www.google.co.jp/maps/ # 材料 | 部品 | 型番 | 個数 | |---|---|:---:| | マイコンボード | [Arduino Micro ピンヘッダ無し](https://www.switch-science.com/catalog/1389/) | 1個 | | オーディオジャック | [ステレオジャック 3.5mm](https://www.amazon.co.jp/gp/product/B07K14BQMT/ref=ppx_yo_dt_b_asin_title_o01_s00) | 1個 | | オーディオケーブル | [ステレオ分配ケーブル 3.5mm (メス⇔オス×2) 0.2m](https://www.amazon.co.jp/gp/product/B004178WTE/ref=ppx_yo_dt_b_asin_title_o00_s00) | 1本 | | ジョイスティック | [ジョイスティック モジュール](https://www.amazon.co.jp/VKLSVAN-%E3%82%B2%E3%83%BC%E3%83%A0%E3%83%AC%E3%83%90%E3%83%BC%E3%82%BB%E3%83%B3%E3%82%B5%E3%83%BC-%E3%82%B8%E3%83%A7%E3%82%A4%E3%82%B9%E3%83%86%E3%82%A3%E3%83%83%E3%82%AF-%E3%82%B7%E3%83%BC%E3%83%AB%E3%83%89%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB-Arduino%E3%81%AB%E5%AF%BE%E5%BF%9C/dp/B08B8429JH/ref=sr_1_5) | 1個 | | ケーブル(オーディオジャック接続) | [ジャンパワイヤ(オス~オス)](https://www.switch-science.com/catalog/57/) | 2本 | | ケーブル(ジョイスティック接続) | [ジャンパワイヤ(オス~メス)](https://www.switch-science.com/catalog/209/) | 5本 | | スペーサー | [絶縁POM(ポム)スペーサー 六角 M3×15mm [RoHS]](https://eleshop.jp/shop/g/g5C2255/) | 4個 | | ネジ | [EV型導通ビス M3×5mm](https://eleshop.jp/shop/g/gG9H311/) | 8本 | | ケース | [コインケース 500円玉](https://www.daisonet.com/product/4984343730021) | 1個 | # 回路図 ![キャプションを入力できます](https://camo.elchika.com/b4127cd3df29fb52137421610ca4e886a7524292/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f37623038363239362d656238322d346433362d396235632d6563353461396662373834372f37333031343161662d356264622d343230392d616639372d306637353364363061666332/) | 部品 | 部品ソケット | Arduinoピン | ケーブル色 | |---|:---:|:---:|---| | オーディオジャック | RIGHT(RING) | GND | 黒 | | 〃 | LEFT(TIP) | D4 | 白 | | ジョイスティック | VCC | D7 | 水色 | | 〃 | VERT | A3 | オレンジ | | 〃 | HORZ | A0 | 黄緑 | | 〃 | SEL | 5V | 赤 | | 〃 | GND | GND | 黒 | # ソースコード ```C:link-pedal2key.ino #define DEBUGLOG 0 #if DEBUGLOG // definitions to log for debug when not to use 'keyboard.h'. #define KEY_UP_ARROW 'U' #define KEY_DOWN_ARROW 'D' #define KEY_LEFT_ARROW 'L' #define KEY_RIGHT_ARROW 'R' #else #include "Keyboard.h" #endif #define BIKE_PIN 4 #define LED_PIN 13 #define SW_PIN 7 #define X_PIN A0 #define Y_PIN A3 #define WAITING_MSEC 125 #define MAX_ROTATION 3 int rotation = 0; boolean stat_p = false; #define MAX_POS 1024 boolean stat_l = false; boolean stat_r = false; boolean stat_u = false; boolean stat_d = false; void printNumberOfRotation(int now, int max) { Serial.print("The pedal has rotated "); Serial.print(rotation); Serial.print("/"); Serial.print(MAX_ROTATION); Serial.println(" times."); } void printKeyboardEvent(String event, char key) { Serial.print(event); Serial.print(" keyboard ["); Serial.print(key); Serial.println("]"); } boolean ctrlStick2KeySmall(int pos, boolean stat, char key) { if (pos < (MAX_POS / 5)) { if (!stat) { Keyboard.press(key); stat = true; printKeyboardEvent("Pressed", key); } } else { if (stat) { Keyboard.release(key); stat = false; printKeyboardEvent("Released", key); } } return stat; } boolean ctrlStick2KeyLarge(int pos, boolean stat, char key) { if (pos > (MAX_POS - MAX_POS / 5)) { if (!stat) { Keyboard.press(key); stat = true; printKeyboardEvent("Pressed", key); } } else { if (stat) { Keyboard.release(key); stat = false; printKeyboardEvent("Released", key); } } return stat; } void setup() { // put your setup code here, to run once: Serial.begin(9600); Keyboard.begin(); pinMode(BIKE_PIN, INPUT_PULLUP); pinMode(LED_PIN, OUTPUT); pinMode(X_PIN, INPUT); pinMode(Y_PIN, INPUT); pinMode(SW_PIN, INPUT_PULLUP); } void loop() { // put your main code here, to run repeatedly: int pedal = digitalRead(BIKE_PIN); if (pedal == LOW) { if (!stat_p) { rotation++; printNumberOfRotation(rotation, MAX_ROTATION); if (rotation >= MAX_ROTATION) { Keyboard.press(KEY_UP_ARROW); Keyboard.release(KEY_UP_ARROW); digitalWrite(LED_PIN, HIGH); delay(WAITING_MSEC); digitalWrite(LED_PIN, LOW); rotation = 0; } stat_p = true; } } else { stat_p = false; } int x_pos = analogRead(X_PIN); int y_pos = analogRead(Y_PIN); stat_d = ctrlStick2KeySmall(x_pos, stat_d, KEY_DOWN_ARROW); stat_u = ctrlStick2KeyLarge(x_pos, stat_u, KEY_UP_ARROW); stat_l = ctrlStick2KeySmall(y_pos, stat_l, KEY_LEFT_ARROW); stat_r = ctrlStick2KeyLarge(y_pos, stat_r, KEY_RIGHT_ARROW); } ```