grbl1.1+Arduino CNCシールドV3.5+bCNCを使用中。
BluetoothモジュールおよびbCNCのPendant機能でスマホからもワイヤレス操作可能。
その他、電子工作・プログラミング、機械学習などもやっています。
MacとUbuntuを使用。

CNCマシン全般について:
国内レーザー加工機と中国製レーザー加工機の比較
中国製レーザーダイオードについて
CNCミリングマシンとCNCルーターマシンいろいろ
その他:
利用例や付加機能など:
CNCルーター関係:



*CNCマシンの制作記録は2016/04/10〜の投稿に書いてあります。


ラベル ESP32 の投稿を表示しています。 すべての投稿を表示
ラベル ESP32 の投稿を表示しています。 すべての投稿を表示

2017年10月20日金曜日

ESP32:SPIFFSファイルアップローダー

ようやくESP32のSPIFFファイルアップローダーが出来上がったようです。これでESP8266のように、Webサーバーをたてたときにindex.htmlなどの付属する外部ファイルを、Arduino IDEを使ってESP32内にアップロードできるようになりました。
ファイルアップローダーについてのページはこちら

インストール方法:
リンク先のこのページから、ESP32FS_v0.1.zipをダウンロードし解凍。
Macの場合は、toolsディレクトリを以下のようにつくって、そこに入れろということです。

~/Documents/Arduino/tools/ESP32FS>tool>esp32fs.jar

以前、ESP8266のときには、Arduino.app内にインストールしたので、Arduino.appを右クリックして「パッケージの内容を表示」してから、
Arduino.app>Contents>Java>tools>ESP32FS>tool>esp32fs.jar
となるようにインストールしても大丈夫そうです。
ただし、今回のアップローダーをインストールする前に、最新のArduino-esp32ライブラリをインストールし直したほうがいいかもしれません(古いのを捨てた後、再度このページからインストールし直しました)。

インストール後、Arduino IDEでさっそく試してみました。
まずは、「スケッチの例>SPIFFS>SPIFFS_Test」のサンプルを開き、いくつか内容を書き換えて別名保存します。とりあえず、HTMLファイル(index.html)だけをアップロードしてみました。

ファイルの追加とアップロード:
用意したindex.htmlを「スケッチ>ファイルを追加」で追加します。
追加されたかどうか、「スケッチ>スケッチのフォルダを表示」で確認。
そうすると、こんな感じで自動生成されたdataフォルダ内にindex.htmlが追加されています。
あとは、この状態でindex.htmlをESP32内へアップロードします。
ファイルアップローダーがきちんと所定の場所へインストールされていれば、上のように「ESP32 Sketch Data Upload」が表示されているので、これでアップロードします。このへんはESP8266のときと同じ要領

アップロードされた内容のチェック:
アップロードされた内容をチェックするために、以下のreadFile()のところを少し変更。file.readString()を使って読み込み、シリアル出力させてindex.htmlの中身をチェック。

void readFile(fs::FS &fs, const char * path){
    Serial.printf("Reading file: %s\n", path);

    File file = fs.open(path);
    if(!file || file.isDirectory()){
        Serial.println("Failed to open file for reading");
        return;
    }

    Serial.print("Read from file: ");
    while(file.available()){
        //Serial.print(file.read());
        Serial.print(file.readString());
    }
}

あらかじめ、String contentsなどと文字列型変数を用意しておいて、Serial.print(file.readString());の代わりに、contents=file.readString();とすれば変数contentsへ文字列として渡すことができるかと思います。
そして、loop()内にシリアル通信キー入力で内容確認できるようにしてみました。

int val;

void loop(){
  if(Serial.available()>0){
    val=Serial.read();
    if(val=='l'){
      listDir(SPIFFS, "/", 0);
    }else if(val=='r'){
      readFile(SPIFFS, "/index.html");
    }else if(val=='d'){
      deleteFile(SPIFFS, "/index.html");
    }
  }
}

このようにサンプルのSPIFFS_Test.inoを多少内容変更して別名保存後ESP32へアップロード。
シリアルモニターを開いて、'l'でルートディレクトリ内を表示、'r'でindex.htmlの読み込み、'd'でindex.htmlを消去。
そうすると、シリアルモニターの画面では、

ルート内ディレクトリの表示(1〜2行目)、
index.htmlの読み込みと内容表示(3〜18行目)、
index.htmlの消去(20〜21行目)、
再度ルート内ディレクトリの表示(22行目)
という順番で出力され、問題なく機能しているようです。
これで、やっとESP8266同様ファイルアップロードが使えるようになったわけですが、同時にMicropythonのバイナリデータもアップロードできるようになったので、もしかするとMicropythonを搭載したほうがいろいろと便利かもしれません。

最近はもっぱらDeep Learningばかりで、ESP32やRaspberry Pi Zero Wもあまりやっていませんが、ESP32もけっこう環境が整ってきたようなので、そのうち何かに使ってみようと思います。

AliExpress.com Product - Lolin ESP32 OLED Module For Arduino ESP32 OLED WiFi + Bluetooth Dual ESP-32 ESP-32S ESP8266 OLED Module Board1206円(送料無料)この液晶画面がついているESP32 Lolin(Wemos)が便利そうです。

2017年4月30日日曜日

ESP32:Webサーバから外部ファイルを読み込み

ESP32も少しずつ試してはいるのですが、SPIFFSファイルアップロードの仕方がわからない。ESP8266の場合、HTMLファイルなどをアップロードするためには以前やったように「esp8266fs.jar」を使えばよかったのですが、ESP32には「esp8266fs.jar」のようなものはまだないのでしょうか?
Arduino IDEには、「ライブラリのインポート」では一応「FS」があり、インポートはできるようになっているけれども、ファイルのアップロード自体どうすればいいのか?
追記:2017年10月
どうやらESP32のファイルアップローダーできたみたいです。ファイルアップローダーの使い方についてはこちらへ

インクルードされたライブラリもESP8266のとは違うので、ESP8266と同じ要領ではできなさそう。
ネットで調べてみても、これといったものがないし、フォーラムにもいくつか載っていたけれども、具体的にどうすればいいのかサンプルなどがないのでわかりにくい。
Virtual filesystem compornent(vfs)
partitions
この辺を見ればいいのかもしれないけれども、かなりわかりにくい。SPIFFS用のパーティションのオフセットは0x210000らしい。
おそらく、SPIFFSやFATなどのファイルシステムAPIをパーティション0x210000へflashするとつかえるようになるのかもしれない。Lua-RTOS-ESP32が唯一使えるというような投稿もあるけど、具体的なサンプルなどがないのでわからない。だれか成功例のサンプルをどこかに挙げてもらいたいですね。その他、JavaScriptをベースにするEspruinoやDuktape、あるいはMicroPythonを載せてしまうという手もあるけど。あとは、サンプルのあるSDカードから読み込む方法となるのかも。

ESP8266に関しては、かなりのサンプルが見つかるので扱いやすいけど、ESP32のほうはまだそんなにないというか、仕組みもESP8266よりも複雑みたいで、そのぶん扱いにくいのかも。しかたないのでしばらく待つことにして、かわりに以下の方法で。

他のWebサーバからESP32のRAMへ読み込ませる:
ソース(C言語/Arduino言語)の中にHTML(CSS、JavaScript)を埋め込んで毎回アップロードするのは面倒なので、どうせ読み込んだHTMLデータはString変数へ入れられるので、わざわざROMにアップロードしておかなくてもいいはず。電源を落とせば、RAMの場合消えてしまうけど、毎回電源を入れるたびに、setup()内で外部から読み込ませれば同じことかもしれない。
ということで、ESP32からHTTPリクエストを出して他のサーバに置いてあるHTMLファイルを読み込ませようという実験をしてみました。

まずHTMLファイルをアップロードできる無料Webサーバに、今回の場合data.htmlというファイルをあげておきます。data.htmlには、ESP32(Webサーバ)にリクエストがあった場合のレスポンス用HTMLが書いてあります。ブラウザ上にスイッチのON/OFFなどの画面が出てきて制御できるということになります。

#include <WiFi.h>
#include <ESPmDNS.h>
#include <WiFiClient.h>
#define ledPin 23

const char* ssid = "*****";
const char* password = "*****";

const char* host = "www.abc.com";//無料サーバのホスト
String url ="/esp32/data.html";//読み込ませるデータのurl
String header = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
String footer = "\r\n\r\n";
String webPage = "";
const uint16_t port = 80;

WiFiServer server(port);

void setup(void){  
    Serial.begin(115200);
    pinMode(ledPin, OUTPUT);
    //webPage += "<!DOCTYPE HTML>\r\n<html>No Contents, yet.</html>\r\n\r\n";

    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    //固定IPアドレス
    WiFi.config(IPAddress(192,168,3,20),IPAddress(),IPAddress());
    Serial.print("Connected to ");
    Serial.println(ssid);
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
    
    //DNSサーバ名(esp32.local)
    if (!MDNS.begin("esp32")) {
        Serial.println("Error setting up MDNS responder!");
        while(1) {
            delay(1000);
        }
    }
    Serial.println("mDNS responder started");

    server.begin();
    Serial.println("TCP server started");
    MDNS.addService("http", "tcp", port);
    httpRequest();//ここで外部ファイルをロードしておく
}

void loop(void){
    WiFiClient client = server.available();
    if (!client) {
        return;
    }
    Serial.println("");
    Serial.println("New client");

    while(client.connected() && !client.available()){
        delay(1);
    }

    String req = client.readStringUntil('\r');

    int addr_start = req.indexOf(' ');
    int addr_end = req.indexOf(' ', addr_start + 1);
    if (addr_start == -1 || addr_end == -1) {
        Serial.print("Invalid request: ");
        Serial.println(req);
        return;
    }
    req = req.substring(addr_start + 1, addr_end);
    Serial.print("Request: ");
    Serial.println(req);
    client.flush();

    String s;
    if (req == "/"){//ルートへアクセスした場合はロードしていないHTMLを表示
        IPAddress ip = WiFi.localIP();
        String ipStr = String(ip[0]) + '.' + String(ip[1]) + '.' + String(ip[2]) + '.' + String(ip[3]);
        s = header;
        s += "<!DOCTYPE HTML>\r\n<html>Hello from ESP32 at ";
        s += ipStr;
        s += "<div><a href=\"/on\">TEST: ON</a></div>";
        s += "<div><a href=\"/off\">TEST:OFF</a></div>";
        s += "<div><a href=\"/load\">LOAD DATA</a></div></html>";
        s += footer;
    }else if(req == "/load"){//ロードする画面
        httpRequest();//外部サーバへリクエスト
        s = header;
        s += "<!DOCTYPE HTML>\r\n<html>";
        s += "<div><a href=\"/on\">TEST: ON</a></div>";
        s += "<div><a href=\"/off\">TEST:OFF</a></div>";
        s += "<div>HTML Data Loaded</div></html>";
        s += footer;
    }else if(req == "/on"){//ロードされた画面
        s = header;
        s += webPage;
        s += footer;
        digitalWrite(ledPin, HIGH);
    }else if(req == "/off"){//ロードされた画面
        s = header;
        s += webPage;
        s += footer;
        digitalWrite(ledPin, LOW);
    }else{
        s = "HTTP/1.1 404 Not Found\r\n\r\n";
    }
    client.print(s);
}

void httpRequest(){//ロード用のリクエスト
    Serial.print("connecting to ");
    Serial.println(host);
    WiFiClient myclient;

    if (!myclient.connect(host, port)) {
        Serial.println("connection failed");
        delay(5000);
        return;
    }

    myclient.print(String("GET ") + url + " HTTP/1.1\r\n" +
                 "Host: " + host + "\r\n" +
                 "Connection: close\r\n\r\n");
    
    delay(100);
    
    boolean start=false;
    while(myclient.available()){
        String line = myclient.readStringUntil('\r');
        if(line.indexOf("<!DOCTYPE html>")>0){
          start=true;
        }
        if(start){
            webPage+=line;
        }
    }
    Serial.println("closing connection");
    myclient.stop();
}

サンプルのつぎはぎなので、もしかすると矛盾があるかもしれないけれども、一応機能しました。
ESP32の電源を入れると、setup()内の最後に書いてあるhttpRequest()によって外部サーバにリクエストを出して、そのURLのHTMLを読み込みます。読み込んだ内容はwebPageという変数に入れてしまいます。これが表示用のHTMLデータとなります。
今回の場合はESP32がWebサーバとして機能しており、静的IPアドレス192.168.3.20に固定され、それ以下のディレクトリにアクセスすると:

/(ルート):もともとソースに書き込まれた単純なHTMLを表示
/load :再度HTMLデータを読み込むとき(表示はもともとのHTML)
/on :ロードしたHTMLによる画面表示、23番ピンに接続したLEDをON
/off :ロードしたHTMLによる画面表示、23番ピンに接続したLEDをOFF

となります。
外部サーバからのレスポンスには「HTTP/1.1 200 OK」などのheaderの情報が含まれるので、
line.indexOf("<!DOCTYPE html>")
をつかってHTMLデータの始まりを確認してから、変数webPageに入れていきます。今回の場合は、CSSやJavaScriptもHTMLファイル内に書き込んであるので、このHTMLファイルだけを読み込めばOKということにしています。

ちょっとだけHTMLを書き換えて確かめたいときは、このやり方のほうが早いのかもしれません。毎回ESP32にアップロードするのは確かに面倒。こうすれば、ESP32にはHTML(CSSやJavaScript)データをアップロードしなくてもすむので楽かなと。
ESP8266の場合も、ファイルアップローダを使うとけっこう時間(5分とか)かかるので、この方法のほうが早そうです。
AliExpress.com Product - Official DOIT ESP32 Development Board WiFi+Bluetooth Ultra-Low Power Consumption Dual Core ESP-32 ESP-32S ESP 32 Similar ESP8266976円(送料無料)最近だとAliExpressなら1000円以下になったみたいです。技適マークつきで、秋月のと同じタイプだと思います。

2017年3月22日水曜日

IoTその3:ESP-WROOM-32/Arduino IDEとESP-IDF

先日、秋月でESP32(WROOM-32)を購入しました(1480円)。
ESP32はWifiとBluetoothが内蔵されており、しかもArduinoよりもメモリが多くクロック数も高いにもかかわらず、この小型なサイズと値段というのは驚きです。


ただのモジュールだけなら700円で、


aitendoに売っている専用のピッチ変換基板(295円)や、


さらにもっとシンプルな基板(150円)にとりつければ、1000円以下でWifiもBluetoothも使えるということになります。この場合、USBシリアル接続はついていませんが、一度OTA(無線でアップロード)を書き込んでしまえばUSB端子も不要なので、このほうがシンプルでいいかもしれません。

ちなみにAliExpressだとESP32は少し安いくらいです。
AliExpress.com Product - ESP32 ESP-32S Development Board WiFi+Bluetooth Ultra-Low Power Consumption Dual Cores ESP-32 ESP-32S Board New Arrival
1281円(送料無料)。
秋月のと同じものなのか、一応技適マークがついています。


Arduino IDEで試してみる:
まずは、ESP32用のライブラリをこちらのサイトからインストール。ターミナルで入力ですが、書いてある数行のコマンドをまとめてコピペして実行すれば一気に終わります。

USBシリアル変換ドライバのインストール:
さらに、この秋月のボードの場合はCP2012というUSBシリアル変換チップが搭載されているので、このドライバもこちらのサイトからダウンロード&インストールします。

Arduino IDEでアップロード:
ESP32をUSB接続し、とりあえずBlinkをアップロードしてみることにしました。
設定はこんな感じ(そのまま)。
ESP32ボードの角にGNDがあり、そのとなりに23番ピンがあるので、その二つにLEDを差し込んでみました。そのため、以下のBlinkのコードでは23番ピンをデジタル出力に設定してます。
アップロードスピードが921600もあるせいか、あっというま。


とくに問題なし。リセットボタンなど押してからアップロードかと思いましたが、何も押さなくてもアップロードできました(もしかしたら、開発用ボードだからでしょうか?)。
こんなに便利で安いと、もうArduinoボードを買わなくなりそうです。
ちなみに、この秋月のESP32ボードだと、通常のブレッドボードに差し込むと片側に1列しか余白ができません。サンハヤトのニューブレッドボードであれば一列ずつ幅広(通常5列なのが6列になっている)なので大丈夫ですが、意外に高い。


あるいは、

AliExpress.com Product - Free shipping ESP32-T Shield ESP32-Bit Development Board Compatible For ESP-32S Bluetooth WiFi Module ESP32S Wireless Board788円(送料無料)。このボードに搭載するなら、1列分幅が狭いので、通常のブレッドボードでも両脇1列ずつ余裕ができます。これは、aitendoでも売ってますが(680円)、現在品切れ。

ESP-IDF:さらにESP32について調べてみると、どうやらEspressif公式のESP-IDFという開発フレームワークもあるようです。より細かな設定などは、ESP-IDFのほうがいいかもしれないので、そちらも試してみることにしました。

ESP-IDFのインストール:
このサイトにインストール方法がのっています。基本的にターミナルで入力ですが、手順に沿ってやっていけば大丈夫だと思います。

唯一、パスを通すところが面倒かもしれません。

export PATH=$PATH:$HOME/esp/xtensa-esp32-elf/bin
この部分ですが、これを不可視ファイルの.profileに記入。.profileは/Users/username/.profileにあるはずです。不可視ファイルなので、今回はFunterを使って可視化してエディタで上記パスを直接書き込みました(vimやemacsをつかえばいいのかもしれませんが、慣れていないので)。Macなら$HOME(Linuxぽい)は/Users/usernameと同じなので、このままでも大丈夫そうです。
パスを記入する不可視ファイルは.bashrcや.bach_profileなどありますが、今回は.profileに書き込みました。
ただ、書き込んだだけではまだパスが通っていないらしく、

source ~/.profile
をターミナルで入力する必要があるようです。
さらに、パスが通ったか確認するには、

echo $PATH
を入力します。そうすると、先ほど追加したパスが出てきます。他のパスも書き込んである場合、複数でてきます。これでパスに関しては大丈夫かと。

あとは、サンプルとなるmyappをgit clone(ダウンロード)して、書き込むという手順ですが、myappがあるディレクトリへ移動し、
cd ~/esp/myapp
などと入力し、あるいはmyappがなくて、examplesのhello_worldで試すなら、
cd ~/esp/esp-idf/examples/get-started/hello_world
へ移動し、

make menuconfig
この↑コマンドを入力すると、青い画面がでてきて、ESP32ボードのシリアルポートを設定します。
矢印キーで移動しながら、リターンキーで決定しつつ、先ほどのArduino IDEでも選んだシリアルポートを以下の欄に書き込みます。


以下の画面で<Save>を選択してリターンキー。

あとは<Exit>で画面から抜け出て、またターミナルの通常の画面に戻ります。
シリアルポートを見つけるにはMacの場合なら、
ls /dev/tty.*
この↑コマンドで出てくるはずです。これででてこなければ、ドライバがインストールされていないか、それともUSB接続してないかということです。
そして、最後に
make flash
このコマンドで書き込みということになります。


/Users/username/esp/myapp/main/main.cがプログラムです。
これをエディタなどで開いて書き直し、
/Users/username/esp/myappのディレクトリへ移動して
make flashを入力すれば、いいというわけです。

とくに複雑なプログラムじゃないかぎりは、Arduino IDEで十分だと思います。Arduino IDEのほうが他のセンサーなどのライブラリも使えるので。
しかし、ESP-IDFにしかないようなサンプルの場合はこちらを使ったほうがいいかもしれません。例えば、ESP32-camera-demoなどのサンプルは個人的に興味あるので、これはESP-IDFを使おうかなという感じです。

PlatformIO:
その後、開発環境について調べてみると、PlatformIOを使うと便利ということがわかり、早速インストールしました。

いろいろとやることが増えて面倒かと思いましたが、PlatformIOはAtomというエディタの上で動くIDEで、使ってみるとかなり便利そうでした。
Arduino以外にもいろんなボードに対応しており、サンプルなどのインポート、シリアルモニタ、ターミナル、ボードへのアップロードが全てひとつでできます。さらに、プラグインでHTMLの表示もできます。
Arduino IDEも以前に比べるとボードの種類も増え、ボードごとに設定などを変えてアップロードするように複雑になってきたので、それほど面倒さはかわらないかもしれません。この際、PlatformIOに変えて使ったほうがよさそうです。
たとえばArduino Unoのプログラムの際、書いているのはC++ファイルなのですが、#include "Arduino.h"があるためか、内容はArduinoで使っているコマンドと同じで、構造もvoid setup()とvoid loop()という感じです。PlatformIOに変えると、途端に全てがC言語っぽくなるのかと思ったら、そうでもありませんでした。いままでと変わらないので、すぐに使えると思います。

一度Arduino UnoやESP8266あるいはESP32にアップロードしてみるところまでやってみれば、使い方はだいたいわかるので、思ったより手間が増えるというわけでもなかったです(Arduino IDEの簡単さとあまりかわりませんでした)。これからは、たぶんPlatformIOを使っていこうと思います。
ハードウェア/ソフトウェアの種類、プログラミング言語の種類などがいろいろ増えて、どれからやればいいかという感じですが、PlatformIOはそれらをまとめてくれるような感じかもしれません。おかげで手段や方法で悩むより、最終的にやりたいことに集中できそうです。


ちなみに、ESP8266でCNCマシンを動かしている例もあるようです。

ESP32ならピンの数も多いし、さらにメモリやクロック数も上で、WifiだけでなくBluetoothもあるので、もしGrblが移植できるのであればワイヤレスそしてIP化がすぐ可能というわけです。たった切手サイズの1000円以下のマイコンでここまでできるというのは、すごい時代になったと思います。近いうちに全ての電化製品にIPアドレスが割り振られてしまうのでしょうね。

関連:
ESP32:Webサーバから外部ファイルを読み込み

人気の投稿