ESPr Developerでスマホから操作するロボットを作成する

スポンサーリンク
ESPr Developer

ESPr Developerを使って、スマホからWiFi経由で操作できるロボットを作ろうと思います。


子供部屋にころがっていた「タミヤ 楽しい工作シリーズ組み立てキット リモコンロボット(クローラータイプ)」を使います。


これを ESPr Developer と接続し、WiFi経由で動かせるようにしたいと思います。

ハードウェアの作成(電子回路)

まずは、ハードウェアのうち、電子回路の部分を作成しました。

モータは消費電力が大きいため、ESPr Developerの出力端子を直接繋ぐことはできません。ESPr Developerでモータを制御するためには、モータドライバを使う必要があります。

今回は、秋月電子で購入した「DRV8835使用 ステッピング&DCモータドライバモジュール」を使います。
これひとつで、2個のモータを駆動できます。
IN/INモードの時、以下のとおり動作します(「x」のところに「A」または「B」が入ります)。

MODExIN1xIN2xOUT1xOUT2FUNC
000ZZ空転
001LH逆転
010HL正転
011LLブレーキ

今回は、このモータドライバをふたつ使って、モータを4つまで制御できるようにしたいと思います。
回路図は以下のようにしました。下のモータドライバのBIN2はGNDに繋いでいますので、このモータのみ、回転方向を変えることはできず、モータの回転/停止だけを制御できます。

できあがりです。部品はブレッドボードに組み付けました。

動作確認のため、以下のようなスケッチを準備しました。1秒ごとに、各端子のHIGH/LOWを切り替えるだけのものです。

#define A_AIN1  15
#define A_AIN2  13
#define A_BIN1  12
#define A_BIN2  14
#define B_AIN1  4
#define B_AIN2  5
#define B_BIN1  2

void setup() {
  pinMode(A_AIN1, OUTPUT);
  pinMode(A_AIN2, OUTPUT);
  pinMode(A_BIN1, OUTPUT);
  pinMode(A_BIN2, OUTPUT);
  pinMode(B_AIN1, OUTPUT);
  pinMode(B_AIN2, OUTPUT);
  pinMode(B_BIN1, OUTPUT);
}

void loop() {
  digitalWrite(A_AIN1, HIGH);
  digitalWrite(A_AIN2, LOW);
  digitalWrite(A_BIN1, HIGH);
  digitalWrite(A_BIN2, LOW);
  digitalWrite(B_AIN1, HIGH);
  digitalWrite(B_AIN2, LOW);
  digitalWrite(B_BIN1, HIGH);
  delay(1000);
  digitalWrite(A_AIN1, LOW);
  digitalWrite(A_AIN2, HIGH);
  digitalWrite(A_BIN1, LOW);
  digitalWrite(A_BIN2, HIGH);
  digitalWrite(B_AIN1, LOW);
  digitalWrite(B_AIN2, HIGH);
  digitalWrite(B_BIN1, LOW);
  delay(1000);
}

モータを繋ぐ代わりにLEDを接続して、動作確認しました。所望のとおりに動作しています。

これで、スケッチの内容に従って、モータを動作させることができるはずです。

ソフトウェアの作成(HTMLファイル)

次にソフトウェアを作ります。

今回は、ESPr Developerを、Webサーバとして動作させます。ESPr Developerは、クライアント(スマホ)から受け取った要求に従って、各モータを動かすための処理を行います。

まずは、ソフトウェアのうち、クライアント(スマホ)で表示や操作を行うためのHTMLファイルを作成します。
ここで作ったHTMLファイルは、後ほど、ESPr Developerのフラッシュメモリに保存します。

HTMLファイルでは、formタグでPOST送信を行うことで、Webサーバに要求を送ることにします。
まずは、最も基本的なHTMLファイルを作りました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>WiFi Controller</title>
</head>
<body>
<form action="" method="post"><input type="hidden" name="FLAG" value="FF"><input type="submit" value="↑"></form>
</body>
</html>

スマホでの表示結果は以下のようになります。

ボタンを押すことで、ESPr Developerに要求を送ることができます。

同様のボタンを、モータの動作内容に基づいて追加しました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>WiFi Controller</title>
</head>
<body>
<form action="" method="post"><input type="hidden" name="FLAG" value="FL"><input type="submit" value="←"></form>
<form action="" method="post"><input type="hidden" name="FLAG" value="FF"><input type="submit" value="↑"></form>
<form action="" method="post"><input type="hidden" name="FLAG" value="FR"><input type="submit" value="→"></form>
<form action="" method="post"><input type="hidden" name="FLAG" value="SS"><input type="submit" value="ー"></form>
<form action="" method="post"><input type="hidden" name="FLAG" value="BL"><input type="submit" value="←"></form>
<form action="" method="post"><input type="hidden" name="FLAG" value="BB"><input type="submit" value="↓"></form>
<form action="" method="post"><input type="hidden" name="FLAG" value="BR"><input type="submit" value="→"></form>
</body>
</html>

tableタグを使って、ボタンを分かりやすく並べました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>WiFi Controller</title>
</head>
<body>
<table>
<tr>
<td colspan="3">WiFi Controller</td>
</tr>
<tr>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="FL"><input type="submit" value="←"></form></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="FF"><input type="submit" value="↑"></form></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="FR"><input type="submit" value="→"></form></td>
</tr>
<tr>
<td></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="SS"><input type="submit" value="ー"></form></td>
<td></td>
</tr>
<tr>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="BL"><input type="submit" value="←"></form></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="BB"><input type="submit" value="↓"></form></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="BR"><input type="submit" value="→"></form></td>
</tr>
</table>
</body>
</html>

スマホで適当なサイズで表示されるよう、記述を追加しました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>WiFi Controller</title>
</head>
<body>
<table>
<tr>
<td colspan="3">WiFi Controller</td>
</tr>
<tr>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="FL"><input type="submit" value="←"></form></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="FF"><input type="submit" value="↑"></form></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="FR"><input type="submit" value="→"></form></td>
</tr>
<tr>
<td></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="SS"><input type="submit" value="ー"></form></td>
<td></td>
</tr>
<tr>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="BL"><input type="submit" value="←"></form></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="BB"><input type="submit" value="↓"></form></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="BR"><input type="submit" value="→"></form></td>
</tr>
</table>
</body>
</html>

tableの体裁を整えるための記述を追加しました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>WiFi Controller</title>
<style type="text/css">
<!--
body {
  font-family: sans-serif;
}
.tbl {
  width: 320px;
  font-size: 20px;
  font-weight: bold;
  text-align: center;
}
-->
</style>
</head>
<body>
<table class="tbl">
<tr>
<td colspan="3">WiFi Controller</td>
</tr>
<tr>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="FL"><input type="submit" value="←"></form></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="FF"><input type="submit" value="↑"></form></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="FR"><input type="submit" value="→"></form></td>
</tr>
<tr>
<td></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="SS"><input type="submit" value="ー"></form></td>
<td></td>
</tr>
<tr>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="BL"><input type="submit" value="←"></form></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="BB"><input type="submit" value="↓"></form></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="BR"><input type="submit" value="→"></form></td>
</tr>
</table>
</body>
</html>

さらに、ボタンの体裁を整えるための記述を追加しました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>WiFi Controller</title>
<style type="text/css">
<!--
body {
  font-family: sans-serif;
}
.tbl {
  width: 320px;
  font-size: 20px;
  font-weight: bold;
  text-align: center;
}
.btn {
  border: none;
  padding: 1rem 2rem;
  background: limegreen;
  color: white;
  font-family: sans-serif;
  font-size: 1rem;
  font-weight: bold;
  -webkit-appearance: none;
  -moz-appearance: none;
}
-->
</style>
</head>
<body>
<table class="tbl">
<tr>
<td colspan="3">WiFi Controller</td>
</tr>
<tr>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="FL"><input type="submit" class="btn" value="←"></form></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="FF"><input type="submit" class="btn" value="↑"></form></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="FR"><input type="submit" class="btn" value="→"></form></td>
</tr>
<tr>
<td></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="SS"><input type="submit" class="btn" value="ー"></form></td>
<td></td>
</tr>
<tr>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="BL"><input type="submit" class="btn" value="←"></form></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="BB"><input type="submit" class="btn" value="↓"></form></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="BR"><input type="submit" class="btn" value="→"></form></td>
</tr>
</table>
</body>
</html>

最後に、ボタン類が画面の真ん中に表示されるよう、table全体をさらにtableで囲み、それをセンタリングしました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>WiFi Controller</title>
<style type="text/css">
<!--
body {
  font-family: sans-serif;
}
.tbl {
  width: 320px;
  font-size: 20px;
  font-weight: bold;
  text-align: center;
}
.btn {
  border: none;
  padding: 1rem 2rem;
  background: limegreen;
  color: white;
  font-family: sans-serif;
  font-size: 1rem;
  font-weight: bold;
  -webkit-appearance: none;
  -moz-appearance: none;
}
-->
</style>
</head>
<body>
<table border=0 cellpadding=0 cellspacing=0 width=100% height=100%>
<tr><td align=center valign=middle>
<table class="tbl">
<tr>
<td colspan="3">WiFi Controller</td>
</tr>
<tr>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="FL"><input type="submit" class="btn" value="←"></form></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="FF"><input type="submit" class="btn" value="↑"></form></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="FR"><input type="submit" class="btn" value="→"></form></td>
</tr>
<tr>
<td></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="SS"><input type="submit" class="btn" value="ー"></form></td>
<td></td>
</tr>
<tr>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="BL"><input type="submit" class="btn" value="←"></form></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="BB"><input type="submit" class="btn" value="↓"></form></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="BR"><input type="submit" class="btn" value="→"></form></td>
</tr>
</table>
</td></tr>
</table>
</body>
</html>

これで、HTMLファイルはできあがりです。

ソフトウェアの作成(ESPr Developer用スケッチ)

次に、ESPr DeveloperをWebサーバとして動作させるためのスケッチを作成します。

クライアント(スマホ)からWebサーバ(ESPr Developer)にアクセスすると、サーバはクライアントに、前回の記事で作ったホームページ(HTMLファイル)を表示させます。
クライアント側で、ホームページ上のボタンをタップすると、その要求がサーバに送られ、サーバはそれに従って、各モータを動かすための処理を行います。

スケッチは以下のような感じです。Arduino IDEのサンプルスケッチ「Arduino」>「ファイル」>「スケッチ例」>「ESP8266WiFi」>「WiFiAccessPoint」を元にして作成しました。

// ライブラリの読み込み
#include <ESP8266WiFi.h>               // ESP8266でWiFi接続するためのライブラリ
#include <ESP8266WebServer.h>          // ESP8266をWebサーバにするためのライブラリ
#include <FS.h>                        // ESP8266のフラッシュメモリに読み書きするためのライブラリ

// 変数の定義
const char *ssid = "robot04";          // ESP8266に立ち上げるWebサーバのSSID(適当に決める)
const char *password = "testdata";     // ESP8266に立ち上げるWebサーバのパスワード(適当に決める)
const char *path_root = "/index.html"; // ESP8266のフラッシュメモリに格納しているHTMLファイル名を指定
uint8_t buf[16384];                    // 読み出したHTMLファイルの内容を格納するバッファ

// ピンの割り当て(ピン番号を、分かりやすいピン名に置き換える)
#define A_AIN1 15
#define A_AIN2 13
#define A_BIN1 12
#define A_BIN2 14
#define B_AIN1 4                       // B_XXXは未使用
#define B_AIN2 5
#define B_BIN1 2

ESP8266WebServer server(80);           // Webサーバの設定

void handleRoot() {                    // クライアントから「/」リクエストを受信した時に実行する関数
  if (server.method() == HTTP_POST) {  // POSTで受信した場合、以下を実行
    String s = server.arg("FLAG");     // FLAGの内容に応じて、各ピンのHIGH/LOWを切り替える
    if (s == "FL") {
      digitalWrite(A_AIN1, HIGH);
      digitalWrite(A_AIN2, LOW);
      digitalWrite(A_BIN1, HIGH);
      digitalWrite(A_BIN2, HIGH);
    } else if (s == "FF") {
      digitalWrite(A_AIN1, HIGH);
      digitalWrite(A_AIN2, LOW);
      digitalWrite(A_BIN1, HIGH);
      digitalWrite(A_BIN2, LOW);
    } else if (s == "FR") {
      digitalWrite(A_AIN1, HIGH);
      digitalWrite(A_AIN2, HIGH);
      digitalWrite(A_BIN1, HIGH);
      digitalWrite(A_BIN2, LOW);
    } else if (s == "SS") {
      digitalWrite(A_AIN1, HIGH);
      digitalWrite(A_AIN2, HIGH);
      digitalWrite(A_BIN1, HIGH);
      digitalWrite(A_BIN2, HIGH);
    } else if (s == "BL") {
      digitalWrite(A_AIN1, LOW);
      digitalWrite(A_AIN2, HIGH);
      digitalWrite(A_BIN1, HIGH);
      digitalWrite(A_BIN2, HIGH);
    } else if (s == "BB") {
      digitalWrite(A_AIN1, LOW);
      digitalWrite(A_AIN2, HIGH);
      digitalWrite(A_BIN1, LOW);
      digitalWrite(A_BIN2, HIGH);
    } else if (s == "BR") {
      digitalWrite(A_AIN1, HIGH);
      digitalWrite(A_AIN2, HIGH);
      digitalWrite(A_BIN1, LOW);
      digitalWrite(A_BIN2, HIGH);
    } else {
      digitalWrite(A_AIN1, LOW);
      digitalWrite(A_AIN2, LOW);
      digitalWrite(A_BIN1, LOW);
      digitalWrite(A_BIN2, LOW);
    }
  }
  server.send(200, "text/html", (char *)buf); // クライアントにHTMLファイルを送信
}

void setup() {
  pinMode(A_AIN1, OUTPUT);
  pinMode(A_AIN2, OUTPUT);
  pinMode(A_BIN1, OUTPUT);
  pinMode(A_BIN2, OUTPUT);
  pinMode(B_AIN1, OUTPUT);             // B_XXXは未使用
  pinMode(B_AIN2, OUTPUT);
  pinMode(B_BIN1, OUTPUT);
  digitalWrite(A_AIN1, LOW);
  digitalWrite(A_AIN2, LOW);
  digitalWrite(A_BIN1, LOW);
  digitalWrite(A_BIN2, LOW);
  digitalWrite(B_AIN1, LOW);           // B_XXXは未使用
  digitalWrite(B_AIN2, LOW);
  digitalWrite(B_BIN1, LOW);

  SPIFFS.begin();                      // ファイルシステムを起動
  File htmlFile = SPIFFS.open(path_root, "r"); // 読み込みモードでHTMLファイルを開く
  size_t size = htmlFile.size();       // HTMLファイルのサイズを確認
  htmlFile.read(buf, size);            // HTMLファイルの内容をバッファに読み込む
  htmlFile.close();                    // HTMLファイルを閉じる

  WiFi.softAP(ssid, password);         // 設定したSSIDとパスワードでWiFiアクセスポイントを起動
  IPAddress myIP = WiFi.softAPIP();
  delay(500);

  server.on("/", handleRoot);          // クライアントからの要求に対して、実行する関数を指定
  server.begin();                      // Webサーバを起動
}

void loop() {
  server.handleClient();               // クライアントから受け取ったリクエストを処理
}

ESPr DeveloperのFlashメモリへデータを書き込むためには、Arduino IDEに、SPIFFSファイルシステムアップローダーというものをインストールしておきます。
インストール後、スケッチと同じ場所に「data」フォルダを作り、この下に、前回の記事で作成したHTMLファイルを置きます。

この状態で「Arduino」>「ツール」>「ESP8266 Sketch Data Upload」を実行すると、HTMLファイルをFlashメモリにアップロードすることができます。なお、シリアルモニタを開いている状態ではアップロードできないようです。

この後、スケッチもESPr Developerに書き込みます。これで、ソフトウエアの準備は完了です。

ハードウェアの作成(ロボット)

電子回路ハードウェアをロボットに取り付け、実際にスマホから操作してみたいと思います。

先ほど作成した電子回路ハードウェアはこちらです。ESPr Developerをひとつ、2CHのモータドライバをふたつ搭載しており、4個までのモータの動作を制御できます。

電子回路ハードウエアを取り付けるロボットはこちらです。ふたつのモータで左右のキャタピラを動かすだけのものです。もともと上部に付いていたロボットハンドは、今回は取り除き、ただ走るだけの状態にしています。モータをブレッドボードに接続するために、モータの端子にコネクタピンを取り付けています。

まず最初に、ハードウェアに電池を取り付けます。
ESPr Developerとモータを同じ電池で駆動しようとすると、ESPr DeveloperのWiFi接続が不安定になってしまったため、両者の電池を分けることにしました。今回は、ESPr Developerには単三のニッケル水素電池を4本(1.2V*4=4.8V)、モータ用には同じ電池を2本(1.2V*2=2.4V)使うことにしました。
回路図は以下のとおりです。

ブレッドボードに電池を取り付けると、以下のようになります。

次に、これらをロボットに載せ、モータを接続します。輪ゴムで簡単に固定しているだけです。

いよいよ動かします。
電池をONにした後、スマホでWiFi設定メニューを開くと、WiFiネットワークの中に「robot04」というのが現れますので、それを選択し、パスワード入力欄で「testdata」と入力します。どちらもスケッチの中で定義しているものです。

次に、SafariなどのWebブラウザを開き、アドレス欄に「192.168.4.1」と入力します。これでESPr Developerに格納したHTMLファイルを表示できます。

あとは各ボタンを押すだけで、ロボットを操作できます。

応用編

ここまでで出来上がったものは、ロボットが前後左右に動くだけのもので、操作しているモータは2個だけです。
せっかく、モータを4個まで制御できるようにハードウエアを作ったので、モータをもうひとつ追加してみたいと思います。

なにか面白いネタがないか、いろいろ考えたのですが、あまりいいものが思い浮かばなかったので、全然面白くはありませんが、とりあえずアームを動かす機能を追加することにしました。

まずはHTMLファイルの更新です。テーブルの中に3つのボタンを追加しました。

        :
<table class="tbl">
<tr>
<td colspan="3">WiFi Controller</td>
</tr>
<tr>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="PR"><input type="submit" class="btn" value="↓"></form></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="PS"><input type="submit" class="btn" value="ー"></form></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="PF"><input type="submit" class="btn" value="↑"></form></td>
</tr>
<tr><td colspan="3">====================</td></tr>
<tr>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="FL"><input type="submit" class="btn" value="←"></form></td>
<td><form action="" method="post"><input type="hidden" name="FLAG" value="FF"><input type="submit" class="btn" value="↑"></form></td>
        :

次はスケッチの更新です。handleRoot()関数の中に、追加した3つのボタンに対応する処理を追加しました。

        :
    } else if (s == "BR") {
      digitalWrite(A_AIN1, HIGH);
      digitalWrite(A_AIN2, HIGH);
      digitalWrite(A_BIN1, LOW);
      digitalWrite(A_BIN2, HIGH);
    } else if(s == "PF") {
      digitalWrite(B_AIN1, HIGH);
      digitalWrite(B_AIN2, LOW);
    } else if(s == "PS") {
      digitalWrite(B_AIN1, HIGH);
      digitalWrite(B_AIN2, HIGH);
    } else if(s == "PR") {
      digitalWrite(B_AIN1, LOW);
      digitalWrite(B_AIN2, HIGH);
    } else {
      digitalWrite(A_AIN1, LOW);
      digitalWrite(A_AIN2, LOW);
      digitalWrite(A_BIN1, LOW);
      digitalWrite(A_BIN2, LOW);
      digitalWrite(B_AIN1, LOW);
      digitalWrite(B_AIN2, LOW);
    }
  }
  server.send(200, "text/html", (char *)buf); // クライアントにHTMLファイルを送信
}
        :

ロボットには、追加のモータ、ギヤボックスとアームを取り付け、モータは、あまっている方のモータドライバのAOUT1、AOUT2に繋ぎました。

再度、スケッチとHTMLファイルをESPr Developerに書き込みます。
前回と同様、スマホのWiFi設定を行えば、以下のように操作できます。

アイデア次第で、いろいろ面白いものも作れそうです。