LEGOとATOM LiteでDIYリモコンカー 6 (IOTなサーボモータ編)

 IOT的にサーボモータを動かします。IOT的なLチカで使った「SimpleWiFiServer」に以下の記事で作ったコードを埋め込んでいく感じです。

haseharu.hatenablog.com

#include <M5Atom.h>
#include <ESP32Servo.h>

Servo myservo1;
Servo myservo2;

void setup() {
  M5.begin(true, false, false);

  ESP32PWM::allocateTimer(0);
  ESP32PWM::allocateTimer(1);
  ESP32PWM::allocateTimer(2);
  ESP32PWM::allocateTimer(3);
  
  myservo1.setPeriodHertz(50);
  myservo1.attach(22, 500, 2500);

  myservo2.setPeriodHertz(50);
  myservo2.attach(33 500, 2500);
}

 ここまではまるっと入れていく感じだと思います。
 リモートカーの動作は「前進」「後進」「右向く」「左向く」「停止」の5つとし、クライアントからATOM Liteへ送信するデータは「F」「B」「R」「L」「S」とします。ここは何でもよいです。「client.print」でATOM Liteから出力するhtmlを書いていきます。

client.print("<html lang=\"ja\"><head><meta charset=\"UTF-8\"></head><body>");
client.print("<a href=\"/F\">↑ すすめ</a><br>");
client.print("<a href=\"/R\">→ みぎ</a><br>");
client.print("<a href=\"/L\">← ひだり</a><br>");
client.print("<a href=\"/B\">↓ うしろ</a><br>");
client.print("<a href=\"/S\">■ とまれ</a><br>");
client.print("</body></html>");

 クライアントへのデータ出力部分と受け取る部分はaタグのhref属性に書いていきます。エスケープシーケンスでダブルクォーテーション(")のところにバックスラッシュ(or ¥もある?)が入っています。
 loop関数部分は「myservo1.write()」「myservo2.write()」をそれぞれの動作にあわせて追記していきます。

if (currentLine.endsWith("GET /F")) {
 servo1.write(150); 
 servo2.write(40);
}
if (currentLine.endsWith("GET /B")) {
 servo1.write(40); 
 servo2.write(150);
}
if (currentLine.endsWith("GET /R")) {
 servo1.write(110); 
 servo2.write(110);
}
if (currentLine.endsWith("GET /L")) {
 servo1.write(70); 
 servo2.write(70);
}
if (currentLine.endsWith("GET /s")) {
 servo1.write(90); 
 servo2.write(90);
}

 サーボモータの出力値は調整が必要です。右回り、左周りもこの例だと逆転させていますが、他にもやり方があると思います。あと、モータの右左の付け方によっては、前進と後進、右向き、左向きが想定していた向きと逆になると思います。その場合GPIO部分を差し替えればコードの修正は不要だと思います(雑ですみません)。
 というところまでで以下のようなコードになると思います。

#include <M5Atom.h>
#include <ESP32Servo.h>
#include <WiFi.h>

Servo myservo1;
Servo myservo2;

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

IPAddress ip(XXX,XXX,XX,XX);
IPAddress subnet(255,255,255,0);

WiFiServer server();

void setup()
{
    Serial.begin(115200);
    
    M5.begin(true, false, true);
    delay(50);
    M5.dis.drawpix(0, 0x0ff000);

    //servo motor
    ESP32PWM::allocateTimer(0);
    ESP32PWM::allocateTimer(1);
    ESP32PWM::allocateTimer(2);
    ESP32PWM::allocateTimer(3);

    myservo1.setPeriodHertz(50); // standard 50 hz servo
    myservo1.attach(22, 600, 2400);
    myservo2.setPeriodHertz(50); // standard 50 hz servo
    myservo2.attach(33, 600, 2400);
    delay(1000);

    // wifi
    WiFi.config(ip,ip,subnet);
    delay(10);

    Serial.println();
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);

    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }

    Serial.println("");
    Serial.println("WiFi connected.");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    
    server.begin();
}

int value = 0;

void loop(){
 WiFiClient client = server.available();

  if (client) {
    Serial.println("New Client.");
    String currentLine = "";
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        if (c == '\n') {

          if (currentLine.length() == 0) {
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println();

            client.print("<html lang=\"ja\"><head><meta charset=\"UTF-8\"></head><body>");
            client.print("<a href=\"/F\">↑ すすめ</a><br>");
            client.print("<a href=\"/R\">→ みぎ</a><br>");
            client.print("<a href=\"/L\">← ひだり</a><br>");
            client.print("<a href=\"/B\">↓ うしろ</a><br>");
            client.print("<a href=\"/S\">■ とまれ</a><br>");
            client.print("</body></html>");
            
            client.println();
            break;
          } else {
            currentLine = "";
          }
        } else if (c != '\r') {
          currentLine += c;
        }

        if (currentLine.endsWith("GET /F")) {
           myservo1.write(150); 
           myservo2.write(40);
        }
        if (currentLine.endsWith("GET /B")) {
          myservo1.write(40);
          myservo2.write(150);
        }
        if (currentLine.endsWith("GET /R")) {
          myservo1.write(110);
          myservo2.write(110);
        }
        if (currentLine.endsWith("GET /L")) {
          myservo1.write(70);
          myservo2.write(70);
        }
        if (currentLine.endsWith("GET /S")) {
          myservo1.write(90);
          myservo2.write(90);
        }
        
      }
    }
    client.stop();
    Serial.println("Client Disconnected.");
  }
}

 
 まっすぐ走らない、回るスピードが早すぎる遅すぎるなどは調整いただければある程度は解消されると思います。ATOM TailBATフル充電で10分くらい走りますので「電池が切れたらおしまい」という点でこどもと少し遊ぶにはよいおもちゃだと思います。

 もう少し作り込もうかと、Raspberry Pi Zeroにカメラモジュールを付けて、それをリモコンカーにのせて、ライブ映像を受信できるようやろうとやってみましたが、そのときはLEGOにガチガチに作り込んだラズパイ+カメラが重くて、リモコンカーの馬力が足りず動作が少し残念でした。

www.switch-science.com

akizukidenshi.com

 あと、ブレッドボードと乾電池利用での例を記録しておしまいにしようと思います。

 f:id:haseharu:20210804220735j:plain

 ATOM Liteは仕様上は5Vでの動作となります。

docs.m5stack.com

 5V出力昇圧DCDCコンバータを使います。注意としてはあくまでも昇圧なので、今回であれば5V以上の電源をつながない、でしょうか。9V電池を三端子レギュレータで5Vに降圧させて動作させる、などでも良いかなと思います。

akizukidenshi.com

 データシート上は入力は「0.9-5V」で出力が「5V」になります、とのことです。

akizukidenshi.com

 とりあえず単4電池を2本、

f:id:haseharu:20210804223622j:plain

 およそ3Vあるものをコンバータにつなげてみると、

f:id:haseharu:20210804223519j:plain

 「4.97V」です、いいですね。「3V」から「5V」へきちんと昇圧されています。仕事してくれてます。この5VをATOM Liteとサーボモータへつなげます。本当はモータとATOM Liteの電源を別にして上げたほうがいいんでしょうがとりあえず動くのができれば良しとします。想定していたよりもジャンパワイヤが結構必要でやはりぴょんぴょんしてつながりがわかりにくいですね。手軽でいいのですが、見づらくなるのが難点。

f:id:haseharu:20210804223056j:plain

 この部品とケーブル類を処理してあげれば完成です。単4電池2本を5V昇圧で何分位動作するかは試していないのでご注意ください。

 ということでここでおしまいとなります。

 この記事は7月中に終わらせる予定だったのが想定外に長引きました。というか1年に1本書くか書かないかのテンポで書いてきたブログだったので、これで6年分程度は先に書ききりました。

LEGOとATOM LiteでDIYリモコンカー 5 (IOTなLチカ編)

 IOTでLチカしてみます。コード例があるのでそちらを使います。
 Arduino IDEの「File」->「Example」->[Examples for ESP32 Pico Kit]内->「WiFi」->「SimpleWiFiServer」です。選ぶとコード例が出てきます。以下、コメントを削除したものを載せます。

#include <WiFi.h>

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

WiFiServer server(80);

void setup()
{
    Serial.begin(115200);
    pinMode(5, OUTPUT);

    delay(10);

    Serial.println();
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);

    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }

    Serial.println("");
    Serial.println("WiFi connected.");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    
    server.begin();

}

int value = 0;

void loop(){
 WiFiClient client = server.available();

  if (client) {
    Serial.println("New Client.");
    String currentLine = "";
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        if (c == '\n') {

          if (currentLine.length() == 0) {
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println();

            client.print("Click <a href=\"/H\">here</a> to turn the LED on pin 5 on.<br>");
            client.print("Click <a href=\"/L\">here</a> to turn the LED on pin 5 off.<br>");

            client.println();

            break;
          } else {
            currentLine = "";
          }
        } else if (c != '\r') {
          currentLine += c;
        }

        if (currentLine.endsWith("GET /H")) {
          digitalWrite(5, HIGH);
        }
        if (currentLine.endsWith("GET /L")) {
          digitalWrite(5, LOW);
        }
      }
    }
    // close the connection:
    client.stop();
    Serial.println("Client Disconnected.");
  }
}

 「WiFi.h」をincludeしています。setup関数は少し長めですが、機能的な部分で役割を果たしているのは、以下の2行です。

WiFi.begin(ssid, password);
server.begin();

WiFi.begin」でWiFi接続し、「server.begin」でクライアントからの接続待ちとなります。

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

 それぞれの環境のWiFiへの接続情報はここに入れておきます。

 loop関数ではクライアントからのアクセスを処理しています。あれこれ書いてありますが、なるべく構造部分を取り出すと以下のような感じです。

String currentLine = "";  
char c = client.read();
Serial.write(c);
if (c == '\n') {
 if (currentLine.length() == 0) {
  client.println("HTTP/1.1 200 OK");
  client.println("Content-type:text/html");
 }
 if (currentLine.endsWith("GET /H")) {
  digitalWrite(5, HIGH);
 }
 if (currentLine.endsWith("GET /L")) {
  digitalWrite(5, LOW);
 }
}

client.stop();

 client.readでクライアントからのデータ取得します。そのデータを元に場合分けしてclient.printlnでクライアントへ応答を返しています。抜き出した部分には入れていませんが、コード例だと、

client.print("Click <a href=\"/H\">here</a> to turn the LED on pin 5 on.<br>");
client.print("Click <a href=\"/L\">here</a> to turn the LED on pin 5 off.<br>");

 がhttpで返ってきてクライアントの手元のブラウザ的なものに表示されます。「the LED on pin 5 on」の方をブラウザ的なものでクリックすると、ATOM Liteへ「H」がデータとして送付されます。

if (currentLine.endsWith("GET /H")) {
 digitalWrite(5, HIGH);
}

 「H」がATOM Liteへ送付されると「digitalWrite(5, HIGH);」となりLチカとなります。

 無事にWiFiにアクセスできた場合、「Serial.println(WiFi.localIP());」でシリアルモニターにIPアドレスが表示させます。そのIPアドレスへ同じWiFi環境からブラウザ的なものでIPアドレス直打ちでアクセスをするとブラウザ的なものからIOTなLチカできる感じです。

 コード例はGPIO5をオンにする、というものなので、LED抵抗とブレッドボード、ジャンパワイヤなどで試せる場合はそのまま使う、でも良いと思います。

 今回はATOM Liteの本体LEDで手動チカチカしてみたいと思います。以前の回で示したコードを埋め込んでいく感じです。

haseharu.hatenablog.com

 さきほどのコード例のコメントを削除して、ATOM Liteの本体LEDを手動チカチカ部分を追記したコードがこちらです。

#include <M5Atom.h> //added
#include <WiFi.h>

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

WiFiServer server(80);

void setup()
{
  M5.begin(false, false, true); //added
  
  Serial.begin(115200);
    //pinMode(5, OUTPUT);
    delay(10);

    Serial.println();
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);

    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }

    Serial.println("");
    Serial.println("WiFi connected.");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    
    server.begin();

}

int value = 0;

void loop(){
 WiFiClient client = server.available();

  if (client) {
    Serial.println("New Client.");
    String currentLine = "";
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        if (c == '\n') {

          if (currentLine.length() == 0) {
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println();

            //client.print("Click <a href=\"/H\">here</a> to turn the LED on pin 5 on.<br>");
            //client.print("Click <a href=\"/L\">here</a> to turn the LED on pin 5 off.<br>");

            client.print("Click <a href=\"/H\">here</a> to turn the LED on.<br>"); //added
            client.print("Click <a href=\"/L\">here</a> to turn the LED off.<br>"); //added
            
            client.println();

            break;
          } else {
            currentLine = "";
          }
        } else if (c != '\r') {
          currentLine += c;
        }

        if (currentLine.endsWith("GET /H")) {
          //digitalWrite(5, HIGH);
          M5.dis.drawpix(0, 0xff0000); // Green
          delay(1000);
        
        }
        if (currentLine.endsWith("GET /L")) {
          //digitalWrite(5, LOW);
          M5.dis.drawpix(0, 0x000000); //Off
          delay(1000);
        }
      }
    }

    client.stop();
    Serial.println("Client Disconnected.");
  }
}

 うまくいくとこんな感じです。シリアルモニターでATOM Liteに割り振られたIPアドレスを確認してからブラウザ的なものに打ち込んでください。

youtu.be

 ここまでで、ほぼ完成だと思うのですが、IPアドレスをシリアルモニターで確認する、ままだとケーブルをつなぎっぱなしになります。IPアドレスを固定して取得させれば、シリアルモニターでIPアドレスを確認する必要なくなるため、外部電源をつないで固定IPアドレスをブラウザ的なものに直うちすれば動作可能です。固定IPアドレスにさせるには以下の設定を追加します。

IPAddress ip(192,168,xx,xx); // your IPaddress
IPAddress subnet(255,255,255,xxx); // your subnet

 をincludeの下あたりで設定します。あとはsetup関数に、

WiFi.config(ip,ip,subnet);

 を追記します。追記場所は「WiFi.begin()」よりも先にする必要があります。第2引数はgatewayを設定する箇所なので、もし設定が必要であれば「IPAddress gateway(X,X,X,X)」を追記してカスタマイズする必要があります。さきほどの固定しないバージョンで動作させたときに割り振られたIPアドレスとして固定して上げれば良いと思います。

 ここまででほぼ要素は揃ったと思います。このあと続けると長いので、一旦区切って次回でおしまいにしようかと思います。

 なお、今回、コード例を使いましたが、他にもたくさんあるので活用できると思います。また、今回のブログではコード、と書いていますが、Arduinoの世界では「スケッチ」と表現します。
 
 それからいまさらの補足ですが、ハンダ付とブレッドボードと分けて書いてきましたが、実際のところはブレッドボードでプロトタイプ的に作って、最終的に目指している動きをすることを確認してから、基板などにハンダ付をして作り込んでいく、という流れが一般的でやりやすい流れかと思います。ブレッドボードやジャンパワイヤはいくつあっても困らないです。ブレッドボードは今回使っている小さいもの以外にも、横につながっているラインがある中くらいのもの、

akizukidenshi.com

 さらに長めのもの、

akizukidenshi.com

 あとESP32 DevKitで、

akizukidenshi.com

 WiFiとかIOT的なプロトタイプ作成をバンバン試したいぞ、という人は穴が多い6穴版の、

akizukidenshi.com

 あたりが良いです。というかブレッドボードは個人的につい欲しくなる部品の一つで、上記のものを複数持っていて上記以外はあまり使ったことがないので比較していません。比較できるのは値段くらいで他と比べると安めの価格帯の商品だと思います。

LEGOとATOM LiteでDIYリモコンカー 4 (サーボモータを動かしてみる 2/2)

 サーボモータ2回目です。の前に、LEGOとの組み合わせを少し書いておきます。今回は使いませんが、このGeekServoとLEGOとの組み合わせて使う際の組み方です。

f:id:haseharu:20210730203445j:plain

f:id:haseharu:20210730203524j:plain

f:id:haseharu:20210730203535j:plain

 おそらくこれがこの向きでの一番ミニマムな組み方です。後ろをもう一つ削れると思いますが、その辺はお好みで。

 今回、2つのサーボモータの制御についてです。サーボモータに入る、電源(赤)とGND(黒)はブレッドボードでつなげて一本にまとめてATOM Liteにつなげます。茶色の線はつなげずにATOM LiteのGPIOにつなげて別々にコントールします。

f:id:haseharu:20210730210153j:plain
 
 プログラムは以下のものです。

#include <M5Atom.h>
#include <ESP32Servo.h>

Servo myservo1;
Servo myservo2;

void setup() {
  M5.begin(true, false, false);

  ESP32PWM::allocateTimer(0);
  ESP32PWM::allocateTimer(1);
  ESP32PWM::allocateTimer(2);
  ESP32PWM::allocateTimer(3);
  
  myservo1.setPeriodHertz(50);
  myservo1.attach(22, 500, 2500);

  myservo2.setPeriodHertz(50);
  myservo2.attach(33, 500, 2500);
}

void loop() {
  myservo1.write(120);
  myservo2.write(120);
  delay(1000);
}

 前回のプログラムとほぼ同じです。「Servo」クラスのオブジェクトを2つ作ります。「myservo1」と「myservo2」を作っておいて、「myservo.attach」でGPIOの「22」と「33」を設定してあります。こんな感じで動くと思います。前回の動画、サーボモータの動きがわかりにくかったので、適当にパーツをつけてあります。

youtu.be

 ここまではブレッドボードを使っていますが、ハンダでも良い方はATOMITプロトキットがおすすめです。

www.switch-science.com


f:id:haseharu:20210730212638j:plain

f:id:haseharu:20210730212620j:plain

 これ、個人的にとても好きで「たぶんどっかで使うはずよね、きっと」と意味もなくカートに入れてしまいがちなものの一つです。

f:id:haseharu:20210730212725j:plain

 サーボモータ用の線を出しています。裏側でハンダ付で配線をしています。GPIOは全部引き出しているわけではなく、今回使っている「22」と「33」のみ引き出しています。

f:id:haseharu:20210730212743j:plain

 ここにATOM Liteがカチッと入ります。

f:id:haseharu:20210730213725j:plain

 この蓋の部分、とっても取りにくいです。毎回苦戦していますが、少しずつ外すのがうまくなってきた気がします。もし電池とかで動かしたい場合は、5V昇圧のコンバータを入れるのが良いです。ここでは使っていませんが、サイズ的には問題なく入りますので、うまく配線すればたとえば単3電池3本を5V昇圧で動かせると思います。

akizukidenshi.com

 サーボモータはこんな感じでカチカチくっつけてしまいます。

f:id:haseharu:20210730215337j:plain
f:id:haseharu:20210730215210j:plain
f:id:haseharu:20210731164922j:plain

 電源はATOM TailBATを使っています。

www.switch-science.com

 さきほどのプログラムは一部修正をします。モータの回る方向が一緒だとこの向きで組んだときに、片方が逆になります。90の前後で回転が逆転するので、90を基準に「120(90+30)」「60(90-30)」としました。

void loop() {
  myservo1.write(120);
  myservo2.write(60);
  delay(1000);
}

 ということでここまでで、とにかくまっすぐ進むカーができた感じです。
 
youtu.be

 動画だとやや右にずれていっているのがわかると思います。おそらく個体差だと思いますが、ちょっとモータの回るスピードの調整が必要です。サーボモータ2個をブレッドボード or プロトタイプキット的なもので配線ができました。あとはこれをWifiでなにかのブラウザ的なものからコントロールできればほぼ完成です。

 次回は少し戻りますが、Wifi編ということでIOT的なLチカだと思います。

LEGOとATOM LiteでDIYリモコンカー 3 (サーボモータを動かしてみる 1/2)

 今回はサーボモータを動かしたいと思います。

f:id:haseharu:20210721074840j:plain

www.youtube.com

 これ、税込みで550円です。LEGOがかちっとはまる物理的互換あり、です。とてもおすすめです。我が家では自然発生的にいつの間にか増えLEGOと一緒に転がっています。

www.switch-science.com

 サーボモータで遊ぶ前に、シリアルモニタについて簡単に触れておきます。Arduino IDEではシリアル通信を通じてデータを送り、Arduino IDE側のシリアルモニタにデータを表示することができます。たとえば以下のコードです。
 

#include <M5Atom.h>

void setup() {
  M5.begin(true, false, false);
  Serial.begin(115200);
  Serial.println("Hello World!");
}

void loop() {
  for (int i=1;i<=3;i++){
    Serial.println(i);
  }
}

 M5.beginについては前回のLEDのときは「false」になっていたUARTの引数が「true」になっています。また、そのあと「Serial.begin」でシリアル通信の速度を設定しています。ここでは「115200」としています。この数字は、Arduino IDE側のシリアルモニタでも「同じ数値」を設定する必要があります。「Serial.println」(改行不要の場合は、Serial.print)でテキストを各種出力しています。
 Arduino IDEで「Tools」→「Serial Monitor」を表示します。右下に通信の速度を設定する場所があるのでそこを先ほどのコード中で指定していた数字とあわせて「115200」を設定します。
 その後、コードをアップロードするとシリアルモニターにテキストが表示されると思います。改行がうまく入らない場合は、「Serial.println」のあとに「delay」で少し間を入れてあげると改善するかもしれません。
 今回のサーボモータでは、数字もみながら動きをみるコードを書いておきたいと思いますので、そこで使うかと思います。
 
f:id:haseharu:20210721212912p:plain

 ここからサーボモータに入ります。

 ジャンパワイヤ3本をサーボモータから生えているケーブル先のコネクタに3本接続します。それをATOM Liteにつなげてあげます。以下の感じです。

f:id:haseharu:20210721075645j:plain

 今回「ESP32Servo」ライブラリを利用します。Arduino IDEの「Tools」→「Manage Libraries」で「esp32servo」と入れていただくと目的のライブラリが出てくると思います。「ESP32Servo360」の方ではなく「ESP32Servo」の方をインストールしていただければ。

f:id:haseharu:20210721090810p:plain

 コードは以下のとおりです。

#include <M5Atom.h>
#include <ESP32Servo.h>

Servo myservo;

void setup() {
  M5.begin(true, false, false);

  ESP32PWM::allocateTimer(0);
  ESP32PWM::allocateTimer(1);
  ESP32PWM::allocateTimer(2);
  ESP32PWM::allocateTimer(3);
  
  myservo.setPeriodHertz(50);
  myservo.attach(22, 500, 2500);
}

void loop() {
  myservo.write(120);
  delay(1000);
}

 「M5Atom.h」の他に、先にいれておいた「ESP32Servo.h」を読み込みます。つづけて「Servo」クラスのオブジェクト「myservo」を作ります。

  M5.begin(true, false, false);

 今回、UARLをサーボモータ以外で使う予定なので今の段階で「true」にしておきました。上のコードではあまり意味をなしていません。

  ESP32PWM::allocateTimer(0);
  ESP32PWM::allocateTimer(1);
  ESP32PWM::allocateTimer(2);
  ESP32PWM::allocateTimer(3);
  
  servo1.setPeriodHertz(50);

 この辺はおまじないと考えていただければ。詳細は、こちらです。

github.com

platformio.org

  myservo.attach(22, 500, 2500);

 ここで引数に設定している箇所でGPIOの22番を指定しています。その後ろもモーター制御のPWM用の値が入っているのですが、とりあえずはおまじないとしてこのままで良いと思います。
 

  myservo.write(120);
  delay(1000);

 「myservo.write」でモーターの出力値を設定します。引数で入っている「120」がモーターの出力値です。LEDのときと同様、delayでモーターの出力を継続しています。loop関数なので、出力値「120」で延々とサーボモータの回転軸が延々と回ります。
 出力値は「0-180」で設定しますが、360回転するモーターなので、「0-90、90-180」と「90」を境に回る方向が変わります。回転軸を上に向けておいたときに「0-90」のときは軸は右に周り、「90-180」のときは軸は左に回ります。実際には、ATOM Liteからの3.3Vか5V出力どちらの場合も「80-100」の間はほぼ停止している感じです。

 出力値とモーターの回転軸の回り方を追いかけて確認してみたいと思います。loop関数内をfor文で「myservo.write」への入力値を0から180に数字が1ずつ上がっていく感じで記述します。その入力値をSerial.printで出力してArduino IDE側のシリアルモニターで確認できるようにします。

  for (int i = 0; i <= 180; i += 1){
    myservo.write(i);
    Serial.println(i);
    delay(200);
  }

 とします。シリアル通信で数字の変化も追いたいので、「Serial.println」を入れます。全部まとめると、以下でしょうか。

#include <M5Atom.h>
#include <ESP32Servo.h>

Servo myservo;

void setup() {
  M5.begin(true, false, false);
  Serial.begin(115200);

  ESP32PWM::allocateTimer(0);
  ESP32PWM::allocateTimer(1);
  ESP32PWM::allocateTimer(2);
  ESP32PWM::allocateTimer(3);
  
  myservo.setPeriodHertz(50);
  myservo.attach(22, 500, 2500);
}

void loop() {
  for (int i = 0; i <= 180; i += 1){
    myservo.write(i);
    Serial.println(i);
    delay(200);
  }
}

 無事に動くとこんな感じになるかと思います。

www.youtube.com

 ちょっと長くなってきたので、一旦ここで切りたいと思います。次もサーボモータの続き(たぶん)

LEGOとATOM LiteでDIYリモコンカー 2 (Lチカ的な)

 まずはHello World的なLチカから。

 Arduino IDEを使います。Win,Mac,Linux対応しています。

www.arduino.cc

 自分は、2021年1月にMacからChromeBookに乗り換えたので、ChromeBookに入れて使っています。ChromeBookに入れる方法はこちらを参考にしました。ただ、最新版がうまく起動できなかったので、少し古いバージョンを入れてみてそれが動いているのでとりあえずいいかな、と使っています。画面等最新版のIDEと画面が一部違うかもしれませんが、そういう理由です。

https://www.stevencombs.com/arduino/2020/01/20/arduino-on-chromeos.html

 Arduino IDEインストール後、ATOM Lite用の設定をします。公式はこちら「m5-docs」です。

  • Boards Manager -> For Atom Matrix/Atom Lite
  • M5Stack Library -> For Atom Matrix/Atom Lite

 の2つです。M5StickやらM5Stackなどほかのものも混ざっているので少し見づらいかもしれません。日本語だと、この辺のブログに書かれていますので参考にしながらも、最終的には公式の最新情報を参照いただくのがよいかと思います。

msr-r.net

 ここまで準備ができたら、Lチカをやってみます。

 今回利用するM5STACK社のATOM Liteは「RGB LED」が本体についています。押しボタンもあります。赤外線も使えて、Wifiつながります。本体についている「RGB LED」でLチカしましょう。

docs.m5stack.com

 なお、GPIOについて詳細はこちらのブログが詳しいです(今回はそれほどGPIOの表とにらめっこする必要はないです)。

lang-ship.com

 今回はArduino言語で書いていきます。C/C++をベースとした言語です。
 C言語にある、main関数はなく、代わりに「setup関数」と「loop関数」があります。あります、というかこの2つが必ず必要です。「setup関数」は起動時一回のみ処理されますので初期設定を書き込むことが多いです。「loop関数」は「setup関数」起動後、延々と繰り返し実行させるプログラムを書きます。

#include <M5Atom.h>

void setup() {
  M5.begin(false, false, true);
}

void loop() {
  M5.dis.drawpix(0, 0xff0000);
  delay(1000);
  M5.dis.drawpix(0, 0x000000);
  delay(1000);
}

 最初の一行目、「M5Atom.h」を読み込んでいますがATOM Liteのお約束と考えていただければ。
 setup関数に入っている「M5.begin(true, false, true);」は「UART, I2C, 本体LED」を利用するかどうかの設定で先の並び順に引数になっています。今回、LEDのみなので、第3引数をtrueにしています。
 loop関数の「M5.dis.drawpix(0, 0xf00000);」でLEDを光らせています。第1引数はLED番号でATOM Liteは1個しかないので「0」で固定、と考えてよいです。ATOM Matricsは本体LEDが25個あるのでここを「0-24」に変えてLEDを指定してピカチカできるわけです。ATOM Matricsは持っていませんが。第2引数は色指定です。RGBの並びではなく「0xff0000」->緑、 「0x00ff00」->赤、「0x0000ff」->青、なのでGRBの順です。今回、とりあえず緑にしました。

delay(1000);

 でLEDが光っていることを「1,000ミリ秒=1秒」持続します。これでLEDが光る、状態になります。
 続く「M5.dis.drawpix(0, 0xf00000);」はLEDを消灯、になります。もう一度「delay(1000);」で消灯状態を1秒継続します。
 USB-TypeCで接続して、Arduino IDEで書き込みます。もし失敗するようであれば、Board : "ESP32 Pico Kit" , Upload Speed : "115200" , Port : USB-TypeCの接続ポートが表示、あたりが設定されているか確認すると良いです。成功すれば、緑が1秒光って、1秒間消灯、緑Lチカチカが延々と続くと思います。ATOM Liteにはプログラムをアップロード済なので、電源さえあたえてあげればいつでもどこでも緑Lチカチカをできることになります。G->R->B->白->消灯、だと以下の感じです。

#include <M5Atom.h>

void setup() {
  M5.begin(false, false, true);
}

void loop() {
  M5.dis.drawpix(0, 0xff0000); // Green
  delay(1000);
  M5.dis.drawpix(0, 0x00ff00); // Red
  delay(1000);
  M5.dis.drawpix(0, 0x0000ff); // Blue
  delay(1000);
  M5.dis.drawpix(0, 0xffffff); // White
  delay(1000);
  M5.dis.drawpix(0, 0x000000); //Off
  delay(1000);
}

 特にsetup関数やloop関数が空ではいけない、ということもないようなので、たとえば「SDGsの時代なんだから2回だけ光らせればいいんだよ」みたいな方は、setup関数でチカチカさせてあげてloop関数は空にしてしまう、でよいと思います*1

#include <M5Atom.h>

void setup() {
  M5.begin(false, false, true);
  delay(3000);
  M5.dis.drawpix(0, 0xff0000);
  delay(1000);
  M5.dis.drawpix(0, 0x000000);
  delay(1000);
  M5.dis.drawpix(0, 0xff0000);
  delay(1000);
}

void loop() {
}

 ここまででよいのですが、GPIO使ってLED光らせるブレッドボード的なものもやっておきたいですよね。ブレッドボードと赤色LEDと抵抗とジャンパワイヤ数本を用意してGPIOでのLチカもやってみたいと思います。

f:id:haseharu:20210721072653j:plain

 LEDは秋月電子通商で購入した赤色LEDがあったのでそれで。

akizukidenshi.com

  • LED 1個
  • 抵抗 65Ω 1個 (LEDの性能によります)
  • ブレッドボード 1個
  • ジャンパワイヤ 2本

 あと、もしここから先の手順を試して見る方は、保護メガネも用意したほうが良いです、LEDは割れることがあります。熱を持つ部品もあります。電気も通します、ので電子工作の一般的な注意事項をもれなく適用していただくようお願いします。濡れた手で触らない、おかしな匂いや抵抗など部品の色が変わったと思ったら電源を抜く、保護メガネをする、整理整頓をして作業をする、電流を流す前に配線違いがないかやショートを起こしていないかもう一度確認する、とかでしょうか。どこまでいっても最終的には自己責任でお願いいたします。

 ATOM Liteは3.3V出力で*2、用意したLEDが順方向電圧が2VでこのLEDに20mA流すと想定して、オームの法則で計算すると必要な抵抗値は65Ωでしょうか。秋月電子通商で購入した抵抗で75Ωがあったのでそれを使いました。ATOM Liteをひっくり返すと、なにやら穴が空いていると思います。対応表がずれていて見にくいのですが、左側の列の上から2番目、対応表上は「G22」という番号、「22」番のGPIOを使います。それから、右の一番下、「G」も使います。グランド(GND)です。

f:id:haseharu:20210721072559j:plain

 LEDは向きがあるので注意が必要です。ATOM LiteのGにつないでいる方がカソード、線が短いほうです。ATOM LiteのGPIO22番側、抵抗側についているのが線の長い方がアノードです。抵抗の方は向きはありません。ブレッドボードがはじめて、という方は、この辺がわかりやすいかもしれません。

iot.keicode.com

 今回使っているミニブレッドボードは秋月電子通商で購入したもので、長辺を横にしておいたとき、縦の5つの穴が内部で連結されているものです。横の連結がないものなので部品の数が多くなるとつなげにくくなります。ちょっとつなげるときや工作物に載せるときに場所を取りたくないときに使います。

akizukidenshi.com

 ATOM Lite GPIO 「22」→(ジャンパワイヤ)→75Ω抵抗→LEDアノード→LEDカソード→(ジャンパワイヤ)→ATOM LITE G(GND)、とつながっています。

 プログラムは以下のような感じです。

#include <M5Atom.h>

void setup() {
  pinMode(22, OUTPUT);
}

void loop() {
  digitalWrite(22, HIGH);
  delay(1000);
  digitalWrite(22, LOW);
  delay(1000);
}

 ATOM Lite用のM5Atom.hのヘッダーファイルを読み込みます。これはお約束ですね。
 続いて初回のsetup関数、LEDをチカチカさせる、が今回の目的なのでGPIO「22」をOUTPUTにしておきます。これで22番につながったLEDをチカチカする準備が整いました。
 延々とループするloop関数にはチカチカ部分を書き込みます。

digitalWrite(22, HIGH);

が22番を光らせろ、です。あるいは、22番ピンをオンにしろ、電流流してね、という感じでしょうか。ただし、この1行だけだと、目視できない時間光ることになります(あるいは実際には光っていないのかもしれません)。

delay(1000);

でLEDが光っていることを「1,000ミリ秒=1秒」持続します。これでLEDが光る、状態になります。

void loop() {
  digitalWrite(22, HIGH);
  delay(1000);
}

ここまで書いたもので実行すると、上のものが延々と実行され続けるのでLEDが1秒光る、を延々繰り返し、つまり光っぱなしという感じになります。これでも良いですが、Lチカにならないので、チカチカさせたいと。

digitalWrite(22, LOW);

 さきほどの「HIGH」が「LOW」になっています。22番ピンを消せ、です。あるいはオフにしろ、電流を止めろ、です。同じように、止めたあとに、

delay(1000);

 を入れてあげます。ここまでで1秒光って1秒消えてまた光る、が繰り返しになると思います。delayを変えれば時間を変えられます。

 あとは、ピン番号なんかは定数として名前をつけてあげると書きやすいし、読みやすいし、あとから変更が効きやすいです。

#define LED_PIN 22

としてあげれば

  digitalWrite(LED_PIN, HIGH);
  digitalWrite(LED_PIN, LOW);

と書けます。以下のように書き換えられます。

#include <M5Atom.h>
#define LED_PIN 22

void setup() {
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_PIN, HIGH);
  delay(1000);
  digitalWrite(LED_PIN, LOW);
  delay(1000);
}

 もちろんユーザ定義の関数もかけますので、LED点灯部分を関数化して、

#include <M5Atom.h>
#define LED_PIN 22
#define DELAY_TIME 1000

void blink(int PIN,int TIME){
  digitalWrite(PIN, HIGH);
  delay(TIME);
  digitalWrite(PIN, LOW);
  delay(TIME);
}

void setup() {
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  blink(LED_PIN,DELAY_TIME);
}

 とも書けます。ここだけみれば何やら見づらいですが、コードが膨らんでいくとまた変わってきます。これ以上変更しないものであれば最初の書き方の方がみたままなのでわかりやすいと思いますが。

 今日はここまで、としたいと思います。次はサーボモータでしょうか。
 
 そういえば、諸々の説明が正確さを欠けているものだと思って読んでいただけると。仕上がりも、コードも、まずは動かすこと、形にして楽しむこと、を最優先で作った過程を記録したものです。ただ、自分自身がそうなのですが、自分の昔のコードも、他人のコードも少しずつ分解して部分的に動かしながらしか再現・理解できないため、部分的に動かしていく流れで書き留めておきます。

*1:もっとスマートな書き方があるはず。今回はブランクでよい、の説明として読んでいただければ

*2:最初5Vだと思って記事を書いたのですが、後ほど訂正。実際に測ると3.1Vくらいしか出力されていない感じでしたが、3.3Vで計算

LEGOとATOM LiteでDIYリモコンカー 1

 ATOM Liteはさわっていて本当に楽しいガジェットです。小さいし高機能。基盤むき出しも好きだけど、ATOM Liteはこどもにもべたべたと触らせられるデザイン。あと値段も千円と少しで入手できます。ESP32-PICOなので、Wifiつながります。ここがすごいです。もちろん電池もくいますが、プロトタイプ的なものづくり、こどもとも遊べるガジェットとしてはまったく問題ないです。自分はSWITCH SCIENCEさんから1台買って、すぐに仲間のもう1台がやってきました。

www.switch-science.com

 これを使って簡単なLEGOのリモコンカーを作ってこどもと遊んでいました。

www.youtube.com

 リモコンとしての通信部分は、Bluetooth利用の選択肢もあるかと思います。今回は自分にとっては一番簡単なwifiを経由してhttp通信でのコントロールとしました。動画だとiPadで操作しています。ブラウザなどhttp通信可能な端末から操作可能ですので、リモコン側の作りが一番簡単でパソコンやスマートフォンiPad的なものなどブラウザを搭載したものが手元にあればコントロール可能、追加でものを用意しなくて良い、というメリットがあります。Bluetoothならwifi依存しないので、外でも設定に苦労せずに遊べるだろう、というメリットがあると思います。ATOM TailBatで動かしていますが、動くのは10分程度でしょうか。

 あと、リモコンカー自体の本体はLEGOで作りました。なにせ、5歳児がいるうちの家にはLEGOがたくさんあります。この人達もどんどん増えていきます。使わない手はないだろう、と。というかこういうプロトタイプ的な仕組みをかちゃかちゃと作るのはLEGOが簡単です。ただ、最終的に自分が使ったものは少し入手しづらい部品を使っているかもしれません。
 また、360度回転しLEGOと接続しやすいサーボモータは以下の本で存在を知りました。本体部分のLEGOも含めて手本にさせてもらっています。

www.amazon.co.jp

 Kindle Unlimitedに入っていたタイトルで全体をななめ読みしてパーツ部分しか参考にしていないのですが、リモコン的な部分はあったかな、なかったかな。超音波センサなどで周りの状況を判断して自動で動くロボットカーだったかと。Arduinoをすでにお持ちの方はこちらを参考に進めていただくのも良いと思います。今回は、ESP32-PICOを搭載したATOM Liteを使って操作可能なリモコンカーを作成します。

 Lチカからはじめて何回かに分けて、作り方を記録しておきたいと思います。あと、個人的に完成したときのソースコードがまるっとおいてあってもコピペで動かないと対処できないことも多く、部品を少しずつ動かすところを書いて残しておきたいと思います。

使うもの

 使っているものはこの写真に写っているもので全部です。

f:id:haseharu:20210626174609j:plain

  • ATOM Lite
  • ATOM TailBAT
    • ATOM Liteは5Vでの動作なので、5V出力のモバイルバッテリーがあればそれでも代用できると思います(USB-TypeC接続です)。あるいは単3乾電池2-3本+5V出力昇圧DCDCコンバーターでもよいと思います。
  • ATOMプロトキット
    • 配線をスッキリさせるために使っていますが、ハンダ付が必要なためその部分を回避したい、という方はプロトキットは使わずに「小さめのブレッドボード」と「ジャンパワイヤ」を6本ではなく10本程度準備していただければ。というか動作確認をする段階ではブレッドボードでのプロトタイプ作成をまずしていただくことをおすすめします。その後、作り込む場合はプロトキットなどでハンダ付け、の順番でしょうか。
  • GeekServo 9G 360° Motor-Orange × 2個
  • ジャンパワイヤ:オスーオス 6本〜10本
    • 10本以上あると良いと思います。

 ATOMプロトキットとATOM TailBATは他のものでも代用可能です。ATOM Lite関係とGeekServoのサーボモータもSWITCH SCIENCEさんで購入できます。

www.switch-science.com

www.switch-science.com

 ATOMプロトキットを使わない場合は、小さめのブレッドボードを準備したほうがよいと思います。色はお好みで。自分はこれと同じものを使っています。

www.switch-science.com

 ATOM LiteはバッテリーがないためATOM TailBATをつけていますが、お金には余裕がある、という方は、バッテリー付きのM5StickC Plusも良いと思います。自分は持っていませんが、これは1台でかなり遊べると思います。

www.switch-science.com

 サーボモータはこちらです。たぶんうちには今5個くらいやいのやいのと遊びにきています。LEGOの純正パワーファンクションモータを買うことを考えれば、7-8個買っても惜しくない感じです。

www.switch-science.com

 このモータのレッドの方は*1、電圧をかければ駆動するタイプですのでまずはオレンジのものを準備いただくと良いと思います。単純に電池駆動でモータを回して遊びたい、ATOM Liteとかマイコン的な制御は不要という利用ではレッドが良いと思います。

www.switch-science.com

 LEGOのパーツはほとんどがこのセットで入手可能です。上の写真に写っているパーツがすべて入っているわけではありませんが駆動部分で使っているパーツは揃っていると思います。といいながら、手元に箱がないのでウェブで検索して写真でみていますが、コネクターペグが少し足りないかもしれません。

afrel-shop.com

 パーツはBrickersで揃えてもよいのですが、金額的にはセットを買ってしまったほうが安くすみます。すでにお持ちのパーツをあれこれして作っていただくのもLEGOの醍醐味でよいかと。今回使用するサーボモータLEGOテクニックでよく使われているコネクターペグがカチッとはまります。

f:id:haseharu:20210626174513j:plain

 ジャンパワイヤは秋月電子通商さんのものだとこの辺でしょうか。少し高いのですが品質もよいのでよく使っています。

akizukidenshi.com

 多少、不具合があっても良い、という方はこちらで。テスターで通電チェックすると5-6本はつながっていないものがあります。あと、ワイヤ部分にバリがあることがあり刺さりにくいので、その辺はご注意ください。

akizukidenshi.com

 SWITCH SCIENCEさんだと、この辺?(買ったことがないものです)

www.switch-science.com

 あとはATOM Liteにプログラムを書き込むパソコンが必要です。Arduino IDEインストール済のパソコンを想定して進めます。

www.arduino.cc

 ワイヤ類をまとめたりATOM Liteを本体とくっつける部分はマスキングテープを使っています(てきとー)。

 プログラム部分はArduino言語です。C++をベースにした言語です。

 ちょっと長くなったのでこの辺で、また次回。

*1:他にもあるようですが

2020年を振り返る

なにか形に残しておきたいよね、と思いつつ、2020年の記録をブログに書いておこうと思います。少なくとも去年書いたブログの「2020年にやりたいこと」の振り返りはしておきたいと。

haseharu.hatenablog.com

コロナウィルスの影響で働き方改革のために準備されてきたテレワークの仕組みが突如導入されたことは一番大きな変化だったと思います。緊急事態宣言後、単身赴任先からテレワークを数ヶ月実施する、という謎状況にあったことは書いておきたいと思いますが、その後、移動方法を電車から車に変える、仕事の整理をすることで週のうちほとんどを自宅でテレワーク実施できるようになりました。これは本当に大きな変化だったと思います。

それから家族にとって大きな転機となる一年だったのではないかと思います。「家族の仕事の支援を少しでもできればと考えています。」と書いた去年のエントリ、あまり支援はできなかったけれども、こつこつと形にし始めたものを出版社から声をかけてもらってさらに2年程度かけ、目に見える成果としての形に仕上げたので2020年の一大イベントだったと思います。

2020年の振り返り、

・こどもと遊びのバリエーションを増やす
→ 大人二人とも大好きなLEGOが遊べるようになってきた、のでここぞとばかりにLEGOで遊ぶことが多くなったきました。お話が通じるので、遊びのバリエーションは自然と増えています。

・仕事と生活で良い習慣を1つでも増やしたい
→ かなり意識的に習慣を増やすようこころがけました。ただ、2019年にはじめた習慣を続ける、がほとんどだったかも。

タイムマネジメントを意識して生活したい
→ これ、なんだっけ?

Androidアプリを作りたい
→ Pixel3a、けっこういいです。

・今まで作ったサービスを一度見直してサービス終了させるもの、継続させるもの、ちゃんとしたい
→ けっこう整理しました。本当にごめんなさい、という感じで終了させるものを主軸に整理。

あとは、

「ともかく、ラズパイだけは買うのか買わないのか2020年でケリをつけたいと思います。」
「あ、あとNintendo Switch買いたいです。」

を天秤にかけまして、2020年年末についにラズパイを買ってしまいました。たぶん2014年位から買いたい買いたい、と毎年作っている「今年買いたいもの」リストの常連さんだったラズパイ。何度応募しても抽選漏れのNintendo Switchに別れを告げ、ついに自分自身の気持ちにケリをつけて、ラズパイを買ってしまいました。ただ、Nintendo Switchも何度か抽選に応募して落ちたので2021年も分からないぞ、とも思います。

ラズパイがきてからは、すぐにArduinoも遊びにきましたし(時間の問題ですよね)、ESP32やらATOM Liteやらも遊びにきたので(Wifiでお話できるとか優秀すぎる)、にぎやかな2021年のスタートとなりました。やはりラズパイはお友達を呼んで増殖する性質があるようです。たぶん数千円のガジェット、と認識せずに一歩踏み出せなかった理由はここにあるんだろうな、と思います。

ATOM Liteは本当に楽しいのと、こどもに渡しても全然問題ないインターフェースなので、何台あっても困らない感じです*1。あとはM5Stack類はLEGOとの相性がよいので増殖する予感があります。

最初にうちにきたラズパイ4が気が付かないうちにしれっと仲間を呼び始め、ラズパイゼロが2台、ラズパイピコ、Arduino UNO、Arduino Nano Every、ESP32 W-ROVER開発ボード1台とW-ROVERピッチ変換基盤2台、ATOM Lite2台、と一大勢力を形成しつつあります。

2021年の3月には先のエントリのネタだった秋月電子通商用のブラウザ拡張機能を書き始めていますが、これは2021年の振り返りにしたいと思います。

haseharu.hatenablog.com

*1:いまうちにあるATOM Liteは2台