2019年7月27日土曜日

ESP32でラジコンサーボを動かしてみた

ESP32でTower ProのSG92Rっていうマイクロサーボを動かしてみた。秋月とかでも結構お安く売っている。Aliexpressだと一個250円ぐらいかも。

このサーボは4.8VなんだけどとりあえずUSBの5Vで動かしてみた。

今回はサーボ用のライブラリを使わずにESP32のPWM(ledc)だけで動かしてみた。サーボの標準的な通信は20ms周期の中でHighの割合が0.5ms~2.4msの間で角度が変化するようになってるのでESP32のPWMタイマーを50Hzにセットして0.5msから2.4ms相当のDutyで制御してみた。

#define servoPin 21 //入力Pin設定
#define servoPWMch 0 //サーボ用PWMチャンネル(0-15)
#define servoMin 102 //サーボ最小角度 0.5ms / 20ms * 4096(12bit)
#define servoMax 492 //サーボ最大角度 2.4ms / 20ms * 4096(12bit)

void setup() {
  Serial.begin(115200);
  ledcSetup(servoPWMch, 50, 12);//PWMタイマ初期化 0ch,50Hz(20ms),12bit
  ledcAttachPin(servoPin, servoPWMch);//PWMタイマに出力Pin割当
  //ledcWrite(servoPWMch, servoMin);//最小角度にセット
}

void setServo(uint8_t servoIn){
  uint16_t servoDuty = map(servoIn,0,255,servoMin,servoMax);//0-255で指定した角度をduty比に変換
  ledcWrite(servoPWMch, servoDuty);//指定角度にセット
}

void loop() {
  while (Serial.available() > 0)
  {
    char incomingCharacter = Serial.read();
    int val;
    switch (incomingCharacter)
    {
      case 's':
      {
        //Serial.print(incomingCharacter);
        val = Serial.parseInt();
        uint8_t servoOut = constrain(val, 0, 255);
        setServo(servoOut);
        Serial.println(val);
        break;
      }
      case 'S':
      {
        Serial.println(incomingCharacter);
        ledcWrite(servoPWMch, 0);//サーボオフ
        break;
      }
    }
  }
}
とりあえずこんな感じでシリアルコンソールでs0とかs255とか送れば0から255の間でサーボが0~180°の間で動いてくれる感じ。大文字のSを送るとPWM信号が止まるのでサーボもフリーになる。

ledcWriteを使えばLEDの調光やDCモータ制御だけじゃなくてラジコンサーボも動かせちゃうの便利だなぁ。一応16ch分タイマはあるっぽいのでこの単純なプログラムだけで16ch分は動かせそう。

2019年7月13日土曜日

ESP32用の自動書き込みアダプタを作ってみた。

前にESP-WROOM-02用に自動書き込みアダプタを作ったんだけど、ESP32-CAMとかのESP-WROOM-32にはうまく書き込めなかったので改良も兼ねて新しく作ってみた。
今回の改造ベースは秋月のFT232RQ USBシリアル変換モジュールキット。これも前回同様6Pinの出力だし、ピン配置も同じなのでベースとしてはいい感じ。USB端子もMiniUSBからMicroUSBになるし(これが大きいかも)。本当はTypeCが良かったなぁ

このモジュールは表面にDIPスイッチがあって3.3Vと5V切り替えたりLEDオンオフできたりするんだけど、今回はこちらのディップスイッチを外してそこに3.3Vレギュレータ設置できるかな。
ESP-WROOM-32だとリセットじゃなくてENを操作してるみたいなんだけど、タイミングによってはIO0がLOWになる前に立ち上がってしまったりして書き込みモードに入れないことがあるようなので起動遅延用にENとGNDの間にコンデンサを入れるといいらしい。

というわけで今回は前回の回路にコンデンサを一つ追加しただけ。
定数は環境にもよるらしいんだけど、0.1uFだと不具合が出ているような人がいるっぽいので念の為0.47uFにしてみた。1uFでも良さそう。

DIPスイッチ剥がせば全部表面に実装できそうだったので、DTRのパターンを途中でカットしてそこにトランジスタを載せてしまった。EN側のトランジスタの下で切れてコレクタはそのままパターン上にはんだ付けした。
RTSはICのピンからそのまま引き出した。ついでにFT232RQのCBUS4がLEDの近くだったのでLEDを駆動できるように改造した。FtProgでCBUS4のモードをTX/RXに変更すれば送受信時に点滅してくれる。
ちなみにDIPスイッチを剥がしてしまってもVIOは3.3Vに固定されるのでこのボードだと3.3V化はしなくてもオッケー。ダイオードを0Ωに変更しようか悩んだがとりあえずそのままで
レギュレータ用のコンデンサはディップスイッチの隣のVIAのところでパターンをカットしてそこに3.3Vを流せばいい感じにそのまま使えそう。

裏面にはわかりやすいように適当に印刷した紙をセロテープで貼って完成。
ESP32-CAMとかにつなぐときはEN端子が出ていないのでグラバークリップとかでENにつながってるコンデンサとかをつまむしかない…。
ESP-WROOM-02で使う場合はENをリセット品につなぐだけなので前と変わらず使える。
ESP32で3Mbps書き込みする場合はboards.txtを編集する必要がある。

CooltermのようにDTRの状態をいじれるターミナルを使えばPC側からリセットもかけられて便利だわー

2019年7月10日水曜日

Yinyoo BT4を買ってみた

iPhone 8のジャンクをお安く手に入れたので修理して使ってみてるけどイヤホン端子がない。ということで中華イヤホン用のBluetoothケーブルをこれまたジャンクで購入してみた。
MMCXではなくて2ピンタイプだった。

今回購入したのはYinyoo BT4のピン折れジャンク。
アマゾンの1/5以下ぐらいで手に入ったのでラッキー

片方はピンが折れて、もう片方は曲がってる。
とりあえず曲がった方のピンは真っ直ぐにして、折れてるところはヤスリで削ってから穴を開けた。


穴を開けたらそこに適当なピンヘッダのピンをはんだ付けして長さを合わせてハンダをデザインナイフで削って調整。


結構簡単に治ってラッキー。

Yinyoo BT4はCSR8645らしいのでApt-xとAAC対応してるみたい。
音質的には問題なさそう。音量も結構出てるのでハイインピーダンス系も行けそう。
とりあえずKZ ZSNで使用してるけど、端子の形状が微妙に違うけどピッチが同じなので刺さるからいいか

2019年7月6日土曜日

ESP32-CAMのサンプルスケッチを便利にしてみた

とりあえず技適対応のためにESP-WROOM-32に張り替えたり、ケースに入れたりしてそこそこ便利になってきたESP32-CAMなんだけど、面倒なフラッシュLED実装以外はほぼできたのでメモがてらおいておこうかな。
変更点はIO33につながってる赤色LEDを使えるようにWifiマネージャーのサンプルを移植。そしてmDNSで2台目つないだときにかぶらないように対策したぐらい。2台以降用に色々いじってみたものの変数をMDNS.begin()に入れるとうまく設定できなかったので…
WiFiマネージャーで設定したときに接続できないのもソフトリセットで対応…
本体のストリームもAsync対応させたいなぁ
以下サンプル編集したやつ。どこ編集したかわからなくなったのでメインのスケッチだけコピペしておいた。

2019年6月29日土曜日

ESP32で回転計を作ってみた。

最近モータをいじったりしていると回転計が欲しくなってしまったので、反射型の光センサが安く売っていたのでESP32で回転計を作ってみた。
ドローンやっていた頃からあったほうが便利かなぁと思っていたんだけどそこまで必要性を感じていなかったので結局買ってなかった…

今回はライントレースとかに使われている反射式の光センサをESP32に入力して回転数を計算させてみた。光センサモジュール自体にはコンパレータが内蔵されている(D0出力)のでモータに白とか黒とか反射率が異なるテープを張ってコンパレータの可変抵抗を調整して一回転に一回HIGHが出るように調整する。

ソフトの方はESP32のArduino Coreを使用してGPIO割り込みで回転数計算を行ってみた。光センサモジュールのデジタル出力をESP32のGPIOに入力して、割り込み時の時間を使って回転数を計算する方式にしてみた。パルスをカウントするより応答性高くて高精度なんじゃないかなと。

#define PLS 22 //入力Pin設定

#define aveNum 20
#define filtNum 5
unsigned long lastPulse = 0;
uint16_t aveRPM[aveNum];
uint8_t aveCnt = 0;
uint8_t aveDone = 0;

void IRAM_ATTR pulse() {
  unsigned long currTime = micros();
  static unsigned long fixedTime;
  for (int i = 0; i <= filtNum; i++) {
    delayMicroseconds(10);
    if (digitalRead(PLS) != HIGH)
    {
      return;
    }
  }
  lastPulse = fixedTime;
  fixedTime = currTime;

  float rawRPM = 60000000.00 / (fixedTime - lastPulse);
  aveRPM[aveCnt] = (uint16_t)(rawRPM + 0.5);
  aveCnt++;
  if (aveCnt > aveNum) {
    aveCnt = 0;
    aveDone = 1;
  }
}

uint16_t getRPM() {
  if (lastPulse + 2000000 <= micros())  {
    aveCnt = 0;
    for (int i = 0; i < aveNum; i++) {
      aveRPM[i] = 0;
    }
    aveDone = 0;
    return 0;
  } else {
    float average = 0;
    switch (aveDone) {
      case 0:
        for (int i = 0; i < aveCnt; i++) {
          average += aveRPM[i];
        }
        average = average / (float)aveCnt;
        break;
      case 1:
        for (int i = 0; i < aveNum; i++) {
          average += aveRPM[i];
        }
        average = average / (float)aveNum;
        break;
    }
    return (uint16_t)(average + 0.5);
  }
}

void setup() {
  pinMode(PLS, INPUT);
  attachInterrupt(PLS, pulse, RISING);//入力ピン割り込み設定
  Serial.begin(115200);
}

void loop() {
  static unsigned long lastRun = 0;
  if (lastRun + 200 <= millis())//200msごとにRPMをシリアルコンソールに表示
  {
    lastRun = millis();//次回実行のために値更新
    Serial.println(getRPM());
  }
}

ちょっとしたノイズが入っても回転数が乱れるのでノイズ対策として割り込みの中でノイズ対策として何回か入力Pinの状態を確認するようにしてみた。割り込みの中でdelayMicroseconds使ってるけど一応動いてるからよし…
これでだいぶノイズが少なくなった。センサとか測定対象に合わせて確認回数(filtNum)とかdelayMicrosecondsを変更してみるともっと安定するかも。あんまりdelayを大きくすると割り込み処理が終わらなくなってESP32がリセットしてしまう。

あとは回転数の移動平均を取るようにしたので回転数を読みやすくなった。センサが悪いのかモータが悪いのかわからないけど結構バラバラ動いて見にくかったので。

とりあえずこれでArduinoのシリアルコンソールとかシリアルプロッタで回転数が見れるようになったので気軽にモータの回転数が測れる。LCDとかつけてスタンドアロンにしても便利かも。

センサも今回は光学式を使ったけど、ホールセンサとかエンコーダとかパルスが発生できれば何でも良さそう。低速回転なら1回転に多数のパルスが出るエンコーダとかのほうが精度良く測れるかも。

2019年6月22日土曜日

ESP32-CAM単体でWifi設定できるようにしてみた

前回技適対応にしたESP32-CAMですが、サンプルスケッチそのままだとSSIDとパスワードを変更するたびに書き換えなかったりしないといけなかったり少し不便なのでWiFiマネージャーを使用して少し便利にしてみた。

まずWiFiマネージャーっていうのはESP-WROOM-32などのWifi搭載マイコンで家のWifiに接続する際にSSIDとパスワードをスマホなどから設定できるようにできるライブラリ。仕組み的にはステーションモードで接続できなかった場合は自分自身がAPモードで立ち上がってWebサーバを立て、そこにスマホなどでWifi接続してSSIDとパスワードを設定できる。一旦設定すればあとは自動で家のWifiに接続してくれるようになる。接続できなくなると自動的にAPモードで立ち上がってまた設定できるようになるというすぐれもの。

ライブラリ自体は何種類かあるようだけど今回はAsyncに対応しているESPAsyncWiFiManagerを使用させてもらった。このライブラリを動作させるために必要なライブラリもあるので3つ入れる必要があった。

ESPAsyncWiFiManager
ESPAsyncWebServer
AsyncTCP

そんでもってCameraWebServerサンプルをベースに変更を加えていく。
ついでにmDNSにも対応してみた。
主に変更するのはスケッチの上の方なので変更する付近のみ紹介。(コピペする場合はサンプルを開いて相当する箇所に変更箇所のみ上書きしないと動かない)

#include "esp_camera.h"
#include <WiFi.h>
#include <ESPmDNS.h>//追加
#include <ESPAsyncWebServer.h>//追加
#include <ESPAsyncWiFiManager.h>//追加
AsyncWebServer server(80);//追加
DNSServer dns;//追加

//
// WARNING!!! PSRAM IC required for UXGA resolution and high JPEG quality
//            Ensure ESP32 Wrover Module or other board with PSRAM is selected
//            Partial images will be transmitted if image exceeds buffer size
//

// Select camera model
//#define CAMERA_MODEL_WROVER_KIT // Has PSRAM  //コメントアウト
//#define CAMERA_MODEL_ESP_EYE // Has PSRAM
//#define CAMERA_MODEL_M5STACK_PSRAM // Has PSRAM
//#define CAMERA_MODEL_M5STACK_V2_PSRAM // M5Camera version B Has PSRAM
//#define CAMERA_MODEL_M5STACK_WIDE // Has PSRAM
//#define CAMERA_MODEL_M5STACK_ESP32CAM // No PSRAM
#define CAMERA_MODEL_AI_THINKER // Has PSRAM //コメント外す
//#define CAMERA_MODEL_TTGO_T_JOURNAL // No PSRAM

#include "camera_pins.h"

//const char* ssid = "*********"; //コメントアウト
//const char* password = "*********"; //コメントアウト

void startCameraServer();

void setup() {
  Serial.begin(115200);
  Serial.setDebugOutput(true);
  Serial.println();

  AsyncWiFiManager wifiManager(&server,&dns);//追加
  wifiManager.autoConnect("ESP32-CAM");//追加

中途半端なところで切ってるけど上の方はこんな感じで編集。
あとは下の方でWiFi.begin(ssid, password);してるところを変更。

  //WiFi.begin(ssid, password);//コメントアウト
  WiFi.begin();//追加
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  MDNS.begin("cam");//追加

これで完成。

あとはこれを書き込むとWiFiの設定がされていない場合はESP32-CAMというWifiネットワークが作成されるのでそれにスマホからアクセスして、http://192.168.4.1を開いて設定すればOK。ライブラリにはCaptive Portal機能も埋め込まれているのでiPhoneなどの対応機種であればAPに接続して少しすると自動で設定画面が開くはず。あとはSSIDとパスワードを設定画面から設定すれば完了である。

あとは家のWifiに接続されてからはmDNSが動くのでhttp://cam.localにアクセスすればmDNS対応(Windows 10やiOS)であればIPアドレスを調べる必要がないので便利。Androidの場合は.Local FinderとかでmDNSからIPアドレスを調べられるので便利かも?
エラーコード500が出る場合はESP32-CAMを一旦再起動すると良さそう…多分これはESPAsyncWiFiManagerのバグ?で初回設定時にポートが閉じられていなさそう。

とりあえずこのレベルでも結構使いやすくなったのであとはUPnPとかでポートも自動で開けられたりDDNSに自動で登録できるようにすれば完璧かな…

ちなみにESP-WROOM-32内に保存されたSSIDとパスワードを消去するときはsetup直下とかで一旦以下の2行を実行すれば良いらしい。(デバッグとかでよく使った…

WiFi.mode(WIFI_STA);
WiFi.disconnect(true,true);

一旦WiFiマネージャーで設定完了してしまうと勝手につながってWiFiマネージャーのテストができなくなってしまったときに多用した…

そういや小さいケースが欲しかったけどタカチとかのケースで基板ピッタリのサイズが無かったので設計してみた。電源はmicroUSBから取れるようにしてみた。

ESP32-CAM ケース
ケースに入れることによってハンドリングがしやすくなった反面、ファームの書き換えが面倒に。一応折れないギリギリでスナップフィットにしてみたのでかなり小型化できたと思う。
micro USBの穴とmicroSDの穴が開いてる。結構ぎりぎり突っ込んだのでmicro USB基板はESP-WROOM-32のシールドの上に乗ってる感じ。カプトンテープで一応絶縁しておいたけど。

2019年6月15日土曜日

ESP32-CAMを技適対応にしてみた

ESP-32SとOmnivisionのOV2640が一つのPCBに乗っていてかなりお安いモジュールが合ったので買ってみた。その名もESP32-CAM。PSRAMとしてIPUS IPS6404も搭載されているっぽい。
ピンヘッダもはんだ付け済みでカメラを繋いでファームウェアを書き込めば動く感じ。
Aliexpressで6.99ドルだった(送料込み)
ただし、開発ボードみたいにUSBシリアル変換アダプタが内蔵されていないので別途必要。

ESP-32Sが乗っているが、Ai-Thinkerのではなさそう?
この手のIPEX端子がついてるESP32-Sって書いてあるモジュールってロゴ違いで何種類かあるのかな?
残念なことにこのモジュールは技適マークが付いていないっぽい。ピン配置はESP-WROOM-32と同じ。

ということで早速解体。
ピンヘッダも5V入力側IOはmicroSDカードにつながってるのと共通だし、反対側はデバッグと書き込みにしか使わなそうなので外してしまった。ケースに収めるとき邪魔だし。
部品が飛んでいかないようにカプトンテープでマスキングしてヒートガンの細ノズルを使っていい感じに温めて剥がす!
マキタの温調付きのヒートガンで風量と温度最大でちょうどよいぐらい。

そんでもって手持ちのESP-WROOM-32を取り付けてみた。これも使わなくなったESP-WROOM-32をピッチ変換基板からヒートガンで剥がしたんだけどね!
ちなみに剥がしたあとは吸い取り線できれいに掃除してから隙間ができないように取り付けた。
これで技適対応のESP32-CAMあらため、ESP-WROOM-32-CAMが完成した。
ピン配置同じなのでプログラムは同じものが動くはず。
外部アンテナが使いたい場合はESP32-WROOM-32Uをつければ良さそう。
ちなみに取り付けたのはRevision1でした。取り外したやつは不明…

カメラ側には白色LEDがついててこれはGPIO4で駆動用のFETらしきものを介して制御できるようになっている。HIGHで光るんだけど超眩しい。PWMで調光したほうが良さそう。
反対側にはGPIO33にLED1とシルクで書かれている赤色LEDがついていた。これはLOWで光る。

とりあえずArduinoでESP32のCAMERAのサンプルにESP Asynk WiFi Managerを組み込んでテストしてみた。
LED1はWiFi ManagerのステータスLEDとしてプログラムしてみた。
あとはフラッシュを使えるようにプログラムを修正すれば良さそう。

ちなみにVCCはデフォルトでは3.3Vにつながってるっぽいので、もしVCCから電源を供給したい場合はジャンパー抵抗を交換しないと行けないので注意。まぁ5Vか3.3Vって書いてあるところに電源を繋げばいい話なんだけれども。


最後にシルクの向きで縦置きかと思ったんだけど実際はこの向きなのね
SVGAで1時間ぐらい放置してみたけど問題なさそう。このぐらいの解像度だと10FPSぐらい出る。そしてESP-WROOM-32がめっちゃ熱くなる
安定化電源で3.3V入れてると表示が170mAぐらいだしな…

今回使用したスケッチは長くなりそうなのでもう少し編集してから次回紹介したいと思います。
Arduinoで開発する場合はライブラリや情報も豊富なので、FTPとかクラウドに一定間隔で画像をアップロードするWebサイト埋め込みのライブカメラ的なやつとかも簡単に作れそう。もはやPCいらずで単体マイコンでできる時代とは…