2020年4月2日更新
ラズパイを使ってパン・チルトもできるラズパイタンクを作りました!
今までESP8266をセンサーとしか組み合わせたことがなかったので、アクチュエーターとして一般的なモーターを使ってリモコンカーを作ってみることにしました。
カメラ付きキャタピラ車
ただ、リモコンカーだけだとちょっと寂しいので、少し工夫してスマホのカメラ映像を見ながら遠隔操作できるものにしてみました。
カメラ映像を見ながら操作できるBlynkリモコン
テストコース
スマホ画面をキャプチャした試走映像
使ったもの
買ったもの
- WeMos D1 Mini (ESP8266ボード)
AliExpressで購入 ¥340 (送料別) - Motor Shield For WeMos D1 mini I2C Dual Motor Driver
AliExpressで購入 ¥276 (送料別) - タミヤ 楽しい工作シリーズ No.168 ダブルギヤボックス(左右独立4速タイプ)
ヨドバシカメラ ¥677(税込) - タミヤ 楽しい工作シリーズ トラック&ホイールセット
ヨドバシカメラ ¥515(税込) - タミヤ 楽しい工作シリーズ ユニバーサルプレートセット
ヨドバシカメラ ¥310(税込) - 電池ボックス 単3×2本 リード線・背中合わせ 秋月電子 ¥60(税込)
- 【QIコネクタ】信号伝達コネクタ用ピン メス(5本1組) 千石電商 ¥63(税込)
- 【QIコネクタ】信号伝達コネクタ(黒)1×1 2個 千石電商 ¥22(税込)
- プチブロック ゾウ ダイソー ¥108(税込)
- 粘着タック ダイソー ¥108(税込)
持ってたもの
WeMos D1 Miniは亀の子のようにシールドを重ねることができるので、Motor Shieldを上に重ねてブレッドボード要らずの回路にしました。Motor Shieldにはモーター2個とモーターの電源として電池ボックスを繋いでいます。
亀の子状態のWeMos D1 MiniとMotor Shield
スマホの固定用にプチブロック、モバイルバッテリーの固定用に粘着タックを使用しました。モバイルバッテリーはWeMos D1 Miniの電源として使用しています。
キャタピラ車の裏
モーターとギアボックス、電池ホルダーはキャタピラ車の裏に取り付けました。モーターにはケーブルが付いていなかったので、ジャンパーワイヤ(オスーメス)のオス側を切ってモーターに半田付けしています。また、モーターのノイズ防止用にセラミックコンデンサをモーターに半田付けしています。
ソフトウェア
- Blynk (Android, iOS)
ESP8266やRaspberry Piなどをコントロールすることができるアプリ。今回はキャタピラ車に載せたスマホのカメラ映像の表示とキャタピラ車のJoystick操作を行います。残念ながら映像表示はAndroidのみに対応しているようです。 - IP Webcam (Android)
キャタピラ車に載せたスマホのカメラ映像を送信するアプリ。 - AZ スクリーン レコーダー (Android)
スマホの画面を映像で記録できるアプリ。
Blynk設定
BlynkリモコンにはJoystick WidgetとVideo Streaming Widgetの2つのWidgetを配置しています。
Joystick
JoystickはX軸とY軸のデータを繋げた機器に送ります。MERGEにするとX軸とY軸を一つのバーチャルピンにまとめることができます。
X軸とY軸のデフォルト値は0~1023になっていますが、その状態ではJoystickを放している時の値がX:512,Y:512になってしまうので、-100~100に変更してJoystickを放している時の値がX:0,Y:0になるように変更しました。
書き込み頻度は100msから設定できますが、データはBlynkのクラウドサーバーを経由して機器に届くため必ず少しのラグが出ます。
Video Streaming
URL ADDRESSにはストリーミングサーバーのURLを指定します。このWidgetはクラウドサーバーを使わないので、指定したURLに直にアクセスします。今回使用したIP Webcamではhttp://IP_ADDRESS:8080/video
と指定します。
スケッチ
スケッチはかなりシンプルです。使用ライブラリもBlynkとMotor Shieldの2つだけです。Motor Shieldのライブラリは商品説明ページの一番下にあるArduino Libraryリンクの先のGitHubからダウンロードできます。
少し苦労したのが、Joystickのデータを2つのモーターの制御にうまく使えるようにする方法でした。Jostick Widgetの設定でデータの範囲を-100~100にすることで、かなり単純に全方向動作を可能にすることができました。
WeMosのMotor SheildはI2CインターフェースでESP8266と繋がっているので、ESP2866のGPIOを直接制御する必要もなくM1.setmotor(正転・逆転, 速度)
で簡単にモーターを制御することができます。
Motor Shieldライブラリの修正 ※2017/10/21 追加
Joystick操作の反応が悪いのはクラウドサーバーを使っているからだと思っていたのですが、Motor Shieldライブラリに原因がありました。
libraries > WEMOS_Motor_Shield_Arduino_Library-master > src > WEMOS_Motor.cpp
スケッチフォルダにあるlibrariesフォルダからたどっていって、WEMOS_Motor.cppファイルの114行目をdelay(100);
からdelay(10);
に変更するとJoystick操作の反応が良くなります。
Motor Shieldのファームウェア更新 ※2017/12/18 追加
※2017/2/15 Motor Shieldのファームウェア更新方法の記事を書きました!
たまたま購入したMotor Shieldがハズレだったのかと思っていたのですが、出荷時のファームウェアは少し残念なもののようです。
Motor Shield Reprogrammingという記事にファームウェアの更新方法が書かれていたので、ファームウェアを書き込むのに必要なstm32flashユーティリティのソース(stm32flash-0.5.tar.gz)をここからダウンロードして、Raspberry Piでビルドしインストールしました。
新しいファームウェアはサイトに載っていた「motor_shield.bin」を使いました。あと、USB2TTLの代わりに秋月電子の超小型USBシリアル変換モジュールを使いました。
スケッチに合わせた配線 ※2017/10/21 写真修正
スケッチ ※2017/12/18 スケッチ修正
/*
* BlynkTank.ino
* December 18, 2017
* By Hiroyuki ITO
* http://intellectualcuriosity.hatenablog.com/
* MIT Licensed.
*/
#define BLYNK_PRINT Serial
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <WEMOS_Motor.h>
char auth[] = "Replace here at Your Blynk Auth Token";
char ssid[] = "Replace here at WiFi SSID";
char pass[] = "Replace here at WiFi Password";
//Motor shiled I2C Address: 0x30
//PWM frequency: 1000Hz(1kHz)
Motor MR(0x30,_MOTOR_A, 1000); //Motor A (Right)
Motor ML(0x30,_MOTOR_B, 1000); //Motor B (Left)
int mr_pwn = 0; // MR speed
int ml_pwn = 0; // ML speed
int mr_dir = 0; // MR direction
int ml_dir = 0; // ML direction
BLYNK_WRITE(V1) {
int x = param[0].asInt();
int y = param[1].asInt();
// Forward or Backward ?
if (y > -1) {
mr_pwn = y + x;
ml_pwn = y - x;
} else {
mr_pwn = y - x;
ml_pwn = y + x;
}
// Right Motor
if (mr_pwn > -1) {
mr_dir = _CW;
} else {
mr_dir = _CCW;
}
mr_pwn = abs(mr_pwn);
if (mr_pwn > 100) {
mr_pwn = 100;
}
MR.setmotor(mr_dir, mr_pwn);
// Left Motor
if (ml_pwn > -1) {
ml_dir = _CW;
} else {
ml_dir = _CCW;
}
ml_pwn = abs(ml_pwn);
if (ml_pwn > 100) {
ml_pwn = 100;
}
ML.setmotor(ml_dir, ml_pwn);
}
void setup() {
delay(10);
Serial.begin(74880);
Blynk.begin(auth, ssid, pass);
}
void loop() {
Blynk.run();
// Order to motor
MR.setmotor(mr_dir, mr_pwn);
ML.setmotor(ml_dir, ml_pwn);
// Standby ?
if (mr_pwn == 0 && ml_pwn == 0) {
MR.setmotor(_STANDBY); // Standby is not related to the left or right.
}
}
おしまい