Arduino

10/30/2018

Arduino と RCWL-0516 を使って、動きを捉えた際に音を出す

Dscf0246 動物などの動きを捉えた時に、MicroSDカードに保存してある「sound.wav」の音を発する装置をブレッドボード上で組んでみた。

回路とsketchは出来上がっていて、SDカードも認識されている筈なのに、暫く音が上手く出なかった。音が出ない原因は、PCからプログラムを書き込む際に使っていたUSBケーブルからの供給電力不足。Arduino NANO にプログラムを書き込み後、AC電源から2.1Aの電力を供給できるUSB電源供給変換器を通して接続すると、上手く音を出すことが出来た。ただし、音量をかなり増幅しているので、信号の無いはずの際も大きな雑音が出てしまう。

Dscf0247 Arduinoarduino の出力ではスピーカを鳴らすのに少し弱弱しいので、LM386を使ってもう少し大きな音量で鳴らせるようにした。
左がブレッドボードに組んだもので、右側はFritzingを使って回路を記載したものである。
回路を組むうえで、RCWL-0516というマイクロ波レーダーセンサーを使ってみた。ドップラーレーダー技術を使って移動動体や人体等を検知するマイクロ波センサーモジュールというものだそうだ。技適に適合しているのだろうか?という疑問はある。

Fritzingを使って回路を分かりやすく纏めるうえで、Fritzingパーツが不可欠だが、探してみると、RCWL-0516のパーツを作られフリーで提供されているものを見つけたので、それを使わせて戴いた。場所は下記《参考情報》に記載したので、使われる際には参考にしてください。

作成時の課題、ここで使う「wavファイル」の作り方など・・・ 後ほど記載します。


《Sketch》

#include <SD.h>
#include <SPI.h>
#include <TMRpcm.h>
#define SD_ChipSelectPin 4

int rcwlPin   =  6;  // RCWL-0516 or PIR sensor out
int ledPin    =  8;  // LED for RCWL or PIR
int rcwlState =  LOW;   // states of RCWL or PIR at the initial

TMRpcm audio;
 
void setup(){
  Serial.begin(115200);
  pinMode( rcwlPin,  INPUT);   // RCWL or PIR
  pinMode(  ledPin, OUTPUT);
  audio.speakerPin = 9;
  digitalWrite( ledPin, LOW);  // LED:OFF
  
  // see if the card is present and can be initialized
  if (!SD.begin(SD_ChipSelectPin)) { 
  Serial.println("SD fail");
  return;                   // don't do anything more if not
  Serial.println("SD successful");
  }
  audio.setVolume(6);      //  Set volume level(0 to 7)
}
 
void loop(){
  // read the state of RCWL or PIR sensor
  rcwlState = digitalRead(rcwlPin);
  if (rcwlState == HIGH) {   // detected => "HIGH", if not-detected => "LOW"
                             // Detected!              
   digitalWrite( ledPin, HIGH);  // LED :ON
   audio.play("sound.wav");
   digitalWrite( ledPin,  LOW);  // LED: OFF
  }
}


《参考情報》
・fritzing parts RCWL-0516   「OMNIGATHERUM」 ここから入手
 このブログの中ほどに記載のされている「The parts are follows:」の下にあるNo.4のリストをクリックすると、fritzingのパーツがdownload出来る。

08/16/2018

ESP32 DEVKIT V1 とAE-GYSFDMAXB で$GPGSVを捕捉してみる

今度は、ハードウェアを、DOITの ESP32 DEVKIT V1 とし、前回までと同じように、$GPGSVのデータのみを表示するSketchを載せておく

Img_20180816_183457 使用した部品は、
DOIT ESP32 DEVKIT V1
②GPS module  AE-GYSFDMAXB
  「日本の準天頂衛星システム(QZSS)『みちびき』3機受信(193,194,195)に対応とある」
③ブレッドボード  サンハヤト SAD-101 ニューブレッドボード
その他、ジャンパーケーブル


Sketchで注意することは
1)GPSモジュールのTXD端子は、ESP32ボード側のRX2ピン(GPIO16)へ接続する。

2)Wemos Lolin32に対して、Sketchでの見かけ上での変更点は何もない。

3)ESP32 Dev Module を選べば動くようだが、出来れば、
ファイル⇒環境設定で 「追加のボードマネージャのURL」の入力枠に下記のように2つのURLをコンマで区切ったものを書き込めば、
https://dl.espressif.com/dl/package_esp32_index.json, http://arduino.esp8266.com/stable/package_esp8266com_index.json


 ボードには「DOIT ESP32 DEVKIT V1」が表示されるので、これを選択するのが良い。


《参考としたURL》
Maker Advisor   ESP32 vs ESP8266 - Pros and Cons
  https://makeradvisor.com/esp32-vs-esp8266/
Installing the ESP32 Board in Arduino IDE (Windows instructions)

    https://randomnerdtutorials.com/installing-the-esp32-board-in-arduino-ide-windows-instructions/


《Sketch》

// Search $GPGSV   for ESP32 DEVKIT V1-DOIT
// https://makeradvisor.com/esp32-vs-esp8266/ 
// https://randomnerdtutorials.com/installing-the-esp32-board-in-arduino-ide-windows-instructions/
  HardwareSerial GPSRaw(2);  // ESP32 UART2 GPIO-16 ( RXD2 ) --- GPS TXD
  static const uint32_t GPSBaud = 9600;
  char GPSRc;
  int  GPSRi;
  String Buffer;
  
void setup() {
  Serial.begin(115200);
// GPS TXD-pin should be connected to Lolin32 Pin-16
   GPSRaw.begin(GPSBaud, SERIAL_8N1, 16, 17);
}

void loop() {
  if (GPSRaw.available())  searchGSV();
}

void searchGSV(){
  GPSRc = GPSRaw.read(); // read 1 character
  GPSRi = int(GPSRc);
  if ( GPSRi == 36 ) {   // <= if the 1st character read is '$' 
    Buffer = "$";
    while ( GPSRi != 42 ) {
      char GPSRc = GPSRaw.read();
      GPSRi = int(GPSRc);
      if( GPSRi < 128 ) Buffer += GPSRc;   // add one character to the buffer
    }
    // if the buffer includes "GPGSV" at the beginning it will be zero
    // check the first six character of the buffer
    // Serial.print does not display anything until "$GPGSV" is found   
       if ( Buffer.indexOf("$GPGSV") == 0 )   Serial.println(Buffer);
  }
}

08/15/2018

M5Stack と専用GPS Function Moduleを使い $GPGSVデータを読んでみた

ハードウェアを、M5Stackに変更して、1つ前の記事で Wemos Lolin32でやった事「$GPGSVのデータのみを表示する」をやってみた

使用した部品は、
M5Stack Basic   (実は、2台所有している)
②M5Stack用GPS Function Module V2 (商品コード:M5STACK-GPS-02
)
        旧型 GPS Function Module

  GPS外部アンテナ付き

Gpgsv_m5stack Wemos Lolin32に対して、M5StackでSketchを変更する(追加する)のは、たったの 2行(2行目と11行目)だけである。

ボードで、”M5Stack-Core-ESP32” を選択するのを忘れないようにすること。

それでやってみたら・・・ 

A fatal error occurred: MD5 of file does not match data in flash!
 
というエラーが表示される。

何か間違ったことをしてしまったのだろうかとSketchを何度も見直し、エラーについて Google先生の力を借りて問題解決しようと試みたが・・・対策方法が良く分からずお手上げ状態。





それで、もしかすると・・・と、もう1台のM5Stackでやってみたら・・・
下図のように問題無く、書込みもパス!
M5stack_pass M5stack_gpgsv
受信結果を右側の図のように表示させることが出来た。

AE-GYSFDMAXBとほぼ同じ場所に置いて比較してみたが、AE-GYSFDMAXBの方が衛星の捕捉数が多いようだ。



Wemos Lolin32の場合、ケースを自作する必要があるが、
M5Stackは、コンパクトに纏められた商品なので、外に持ち歩くには、これが便利だなぁ。






《Sketch》
// Search $GPGSV   forM5Stack 
#include <M5Stack.h>
  HardwareSerial GPSRaw(2);  // ESP32 UART2 GPIO-16 ( RXD2 ) --- GPS TXD
  static const uint32_t GPSBaud = 9600;
  char GPSRc;
  int  GPSRi;
  String Buffer;
  
void setup() {
  Serial.begin(115200);
  M5.begin();
// GPS TXD-pin should be connected to Lolin32 Pin-16
   GPSRaw.begin(GPSBaud, SERIAL_8N1, 16, 17);
}

void loop() {
  if (GPSRaw.available())  searchGSV();
}

void searchGSV(){
  GPSRc = GPSRaw.read(); // read 1 character
  GPSRi = int(GPSRc);
  if ( GPSRi == 36 ) {   // <= if the 1st character read is '$' 
    Buffer = "$";
    while ( GPSRi != 42 ) {
      char GPSRc = GPSRaw.read();
      GPSRi = int(GPSRc);
      if( GPSRi < 128 ) Buffer += GPSRc;   // add one character to the buffer
    }
    // if the buffer includes "GPGSV" at the beginning it will be zero
    // check the first six character of the buffer
    // Serial.print does not display anything until "$GPGSV" is found   
       if ( Buffer.indexOf("$GPGSV") == 0 )   Serial.println(Buffer);
  }
}

Wemos Lolin32にAE-GYSFDMAXBを接続して$GPGSVデータを読んでみた

天頂衛星が捕捉出来るのかが、とても気になるので、ハードウェアは、Wemos Lolin32(以前書き込んだと同じ方法)とし、$GPGSVのデータのみを表示するようにSketchを新たに起こしてみた

使用した部品は、
Wemos Lolin32 ESP32 OLED display付き
②GPS module  AE-GYSFDMAXB
  「日本の準天頂衛星システム(QZSS)『みちびき』3機受信(193,194,195)に対応とある」
③ブレッドボード  サンハヤト SAD-101 ニューブレッドボード
その他、ジャンパーケーブル

ここで込み入った処理を行うと、データを取りこぼしてしまうので、
$GPGSVのセンテンスを表示するだけのsketchとした。
このsketchの応用例として、31行目の”$GPGSV”を他のセンテンスに変更すれば、そのセンテンスのデータのみを表示することが出来るだろうと思う。

Gpgsv 仮組したボードに、このsketchを組込み、窓際の室内で作動させた結果は、左の図のようになった。これを見ると、残念ながら天頂衛星は捕捉出来ていない。


sketchは、「$」で始まり、「*」で終わるセンテンスをピックアップしているので、処理の都合上、チェックサム部分は無視している。






Img_20180815_091233 Img_20180815_091421 尚、Wemos Lolin32は、ボードの幅が広く、これまで使っていたブレッドボードでは、ジャンパーピンを挿すスペースが無く、扱いにくい為、先日Amazonから「サンハヤトSAD-101 ニューブレッドボード」@505円のブレッドボードを購入し、それを使って回路を仮組してみた。

《Sketch》

// Search $GPGSV   for Wemos Lolin32 
  HardwareSerial GPSRaw(2);  // ESP32 UART2 GPIO-16 ( RXD2 ) --- GPS TXD
  static const uint32_t GPSBaud = 9600;
  char GPSRc;
  int  GPSRi;
  String Buffer;
  
void setup() {
  Serial.begin(115200);
// GPS TXD-pin should be connected to Lolin32 Pin-16
   GPSRaw.begin(GPSBaud, SERIAL_8N1, 16, 17);
}

void loop() {
  if (GPSRaw.available())  searchGSV();
}

void searchGSV(){
  GPSRc = GPSRaw.read(); // read 1 character
  GPSRi = int(GPSRc);
  if ( GPSRi == 36 ) {   // <= if the 1st character read is '$' 
    Buffer = "$";
    while ( GPSRi != 42 ) {
      char GPSRc = GPSRaw.read();
      GPSRi = int(GPSRc);
      if( GPSRi < 128 ) Buffer += GPSRc;   // add one character to the buffer
    }
    // if the buffer includes "GPGSV" at the beginning it will be zero
    // check the first six character of the buffer
    // Serial.print does not display anything until "$GPGSV" is found   
       if ( Buffer.indexOf("$GPGSV") == 0 )   Serial.println(Buffer);
  }
}


08/02/2018

Wemos Lolin32 を使ってNMEAデータの","区切り

Img_20180802_133910 Img_20180802_133950 天頂衛星が受信できるのかを調べたいと思い、Wemos Lolin32 OLED module を使って、
①NMEAのRawデータを受信しシリアルモニター表示する、
②受信したデータを後処理するために、”,” 区切りし、シリアルモニターに表示する

をやってみた。

受信データ間隔は極めて短いので、②の処理を、全てのデータについて一律に処理するのでは、データ区切りと判別処理で『もたついて』いる間に、受信データの取りこぼしをしてしまうことがわかった。

データを区切って、その後の処理に繋げるためには、「処理を行いたい部分のデータに特化したデータの読み込み」などを行わないと、受信データは正確性に欠けるように思う。


使ったパーツは、

Wemos Lolin32 ESP32 OLED display付き  Banggood から購入@1791円

②GPS module「
AE-GYSFDMAXB 」 秋月電子から購入@2100円
③ブレッドボード
④ジャンパー線


結線は、

①Lolin32とGPS moduleとの電源線の接続
②Lolin32の16番ピンとGPS module「AE-GYSFDMAXB
」 のTXDとの接続



ボードの設定、他

①WEMOS LOLIN32  を使う

②GPSとのSerial通信は、HardwareSerial GPSRaw(2) を使う

③赤字で「connecting ...」となったら、ボードの裏側の『Boot』ボタンを長押しして、次のステップに進むようにすること。

《Sketch-1:NMEAのRawデータを受信しシリアルモニター表示》

// for Wemos Lolin-EPS32
static const uint32_t GPSBaud = 9600;

// The serial connection to the GPS device
 HardwareSerial GPSRaw(2);  // ESP32 UART2 GPIO-16 ( RXD2 ) --> GPS TXD

void setup() {
  Serial.begin(115200);
  GPSRaw.begin(GPSBaud, SERIAL_8N1, 16, 17);
}

void loop() {
  if (GPSRaw.available())
  {
    String Buffer = "";
    while (GPSRaw.available())
    {
       char GPSRX = GPSRaw.read();
       Buffer += GPSRX;
    }
    Serial.print(Buffer);
  }
}

Rawデータ出力はこのようになる。
Gpsrawdata












《Sketch-2:GPS受信データを”,” 区切りし、シリアルモニター表示》
ここでは、配列の中に切り取ったデータを入れたが、シリアルモニターへの表示では、Bufferデータをそのまま表示している。(中途半端な処理だとは思うが・・・)

// for Wemos Lolin-EPS32
static const uint32_t GPSBaud = 9600;

// The serial connection to the GPS device
 HardwareSerial GPSRaw(2);  // ESP32 UART2 GPIO-16 ( RXD2 ) --> GPS TXD
String words[25];

void setup() {
  Serial.begin(115200);
  GPSRaw.begin(GPSBaud, SERIAL_8N1, 16, 17);
}

void loop() {
    String Buffer = "";
    int i=0;
    while (GPSRaw.available()) 
    {
        char GPSRX = GPSRaw.read();
        if(GPSRX == ',') {
          words[i] = Buffer;
          Serial.print("word[");
          Serial.print(i);
          Serial.print("]= ");
          Serial.print(Buffer);
          Serial.print("  ");
          Buffer = "";
          i++;
        }
        else
        {
        if(GPSRX == '\n') {
          words[i] = Buffer;
          Serial.print("word[");
          Serial.print(i);
          Serial.print("] = ");
          Serial.print(Buffer);
          Serial.println(""); 
          Buffer = "";
          i = 0;
          }
        else {
          Buffer += GPSRX;
        }
      }
   }
}

コンマ切り出力はこのようになる。
2

データの取りこぼしなどが起きてしまっている・・・

07/07/2018

Wemos Lolin32 OLED module に RobotDyn microSD boardを接続テスト

3 4 Wemos Lion32 OLED module(写真左)に RobotDyn製 microSD board(写真右) を接続した事例がなかなか見つけられずに、関連する情報から探ってみた結果、接続・書き込みが上手くいったので、ここにメモしておく。



先ず、RobotDyn製
microSD boardWemos Lion32 OLEDモジュール のピン接続であるが・・・

次のように接続すること。
  RobotDyn       ESP32
  SD Card   |   Lolin32
--------------------------------------------------
     D3/CS        CS    ⇒ pin14
     CMD/DI      MOSI ⇒ pin25
     GND          GND
     3.3V          3.3V
     CLK          SCK  ⇒ pin15
     DO           MISO  ⇒ pin13
(上記、表内に記載ミスがあり訂正しました。2018/07/11)
次に、僕が行った方法は、Arduino IDE を起動し、
ファイル ⇒ スケッチ例 ⇒ Wemos LOLIN32のスケッチ例 SD(esp32) ⇒ SD_Test を下記のように加筆修正した。

《SD_Test をWemos Lolin32+RobotDyn microSD board で動かすための修正部分について》
①16行目 #include "SD.h" → #include <SD.h> に変更

②17行目 #include "SPI.h" → #include <SPI.h> に変更

③下記4行の define文を17行目の下に追加
  #define PIN_NUM_MISO 13
  #define PIN_NUM_MOSI 25
  #define PIN_NUM_CLK  15
  #define PIN_NUM_CS   14

④setup()の 最初で、
  117行目から118行目 の下記部分を
  Serial.begin(115200);
    if(!SD.begin()){

  以下のように加筆修正
  Serial.begin(115200);
    auto SPI = SPIClass();
    SPI.begin(PIN_NUM_CLK, PIN_NUM_MISO, PIN_NUM_MOSI, PIN_NUM_CS);
    auto speed = 4000000;
    if(!SD.begin(PIN_NUM_CS, SPI, speed)){


5上記の修正で良い筈だが・・・、もしかして私が書き忘れているかもしれないので、問題無く動いたSketch リストを下記に添付しておく。


尚、テスト結果を左に添付しておく。







《 Sketch for "Wemos Lolin32" + "RobotDyn microSD board" SDcard Test 》
/*
 * Connect the SD card to the following pins:
 * RobotDyn  |  ESP32
 * SD Card   | Lolin32
 *    D3/CS    CS   pin14
 *    CMD/DI   MOSI pin25
 *    VSS      GND
 *    VDD      3.3V
 *    CLK      SCK  pin15
 *    VSS      GND
 *    DO       MISO pin13
 */
#include "FS.h"
#include <SPI.h>
#include <SD.h>
#define PIN_NUM_MISO 13
#define PIN_NUM_MOSI 25
#define PIN_NUM_CLK  15
#define PIN_NUM_CS   14

void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
    Serial.printf("Listing directory: %s\n", dirname);

    File root = fs.open(dirname);
    if(!root){
        Serial.println("Failed to open directory");
        return;
    }
    if(!root.isDirectory()){
        Serial.println("Not a directory");
        return;
    }

    File file = root.openNextFile();
    while(file){
        if(file.isDirectory()){
            Serial.print("  DIR : ");
            Serial.println(file.name());
            if(levels){
                listDir(fs, file.name(), levels -1);
            }
        } else {
            Serial.print("  FILE: ");
            Serial.print(file.name());
            Serial.print("  SIZE: ");
            Serial.println(file.size());
        }
        file = root.openNextFile();
    }
}

void createDir(fs::FS &fs, const char * path){
    Serial.printf("Creating Dir: %s\n", path);
    if(fs.mkdir(path)){
        Serial.println("Dir created");
    } else {
        Serial.println("mkdir failed");
    }
}

void removeDir(fs::FS &fs, const char * path){
    Serial.printf("Removing Dir: %s\n", path);
    if(fs.rmdir(path)){
        Serial.println("Dir removed");
    } else {
        Serial.println("rmdir failed");
    }
}

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

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

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

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

    File file = fs.open(path, FILE_WRITE);
    if(!file){
        Serial.println("Failed to open file for writing");
        return;
    }
    if(file.print(message)){
        Serial.println("File written");
    } else {
        Serial.println("Write failed");
    }
    file.close();
}

void appendFile(fs::FS &fs, const char * path, const char * message){
    Serial.printf("Appending to file: %s\n", path);

    File file = fs.open(path, FILE_APPEND);
    if(!file){
        Serial.println("Failed to open file for appending");
        return;
    }
    if(file.print(message)){
        Serial.println("Message appended");
    } else {
        Serial.println("Append failed");
    }
    file.close();
}

void renameFile(fs::FS &fs, const char * path1, const char * path2){
    Serial.printf("Renaming file %s to %s\n", path1, path2);
    if (fs.rename(path1, path2)) {
        Serial.println("File renamed");
    } else {
        Serial.println("Rename failed");
    }
}

void deleteFile(fs::FS &fs, const char * path){
    Serial.printf("Deleting file: %s\n", path);
    if(fs.remove(path)){
        Serial.println("File deleted");
    } else {
        Serial.println("Delete failed");
    }
}

void testFileIO(fs::FS &fs, const char * path){
    File file = fs.open(path);
    static uint8_t buf[512];
    size_t len = 0;
    uint32_t start = millis();
    uint32_t end = start;
    if(file){
        len = file.size();
        size_t flen = len;
        start = millis();
        while(len){
            size_t toRead = len;
            if(toRead > 512){
                toRead = 512;
            }
            file.read(buf, toRead);
            len -= toRead;
        }
        end = millis() - start;
        Serial.printf("%u bytes read for %u ms\n", flen, end);
        file.close();
    } else {
        Serial.println("Failed to open file for reading");
    }


    file = fs.open(path, FILE_WRITE);
    if(!file){
        Serial.println("Failed to open file for writing");
        return;
    }

    size_t i;
    start = millis();
    for(i=0; i<2048; i++){
        file.write(buf, 512);
    }
    end = millis() - start;
    Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end);
    file.close();
}

void setup(){
    Serial.begin(115200);
    auto SPI = SPIClass();
    SPI.begin(PIN_NUM_CLK, PIN_NUM_MISO, PIN_NUM_MOSI, PIN_NUM_CS);
    auto speed = 4000000;
    if(!SD.begin(PIN_NUM_CS, SPI, speed)){
        Serial.println("Card Mount Failed");
        return;
    }
    uint8_t cardType = SD.cardType();

    if(cardType == CARD_NONE){
        Serial.println("No SD card attached");
        return;
    }

    Serial.print("SD Card Type: ");
    if(cardType == CARD_MMC){
        Serial.println("MMC");
    } else if(cardType == CARD_SD){
        Serial.println("SDSC");
    } else if(cardType == CARD_SDHC){
        Serial.println("SDHC");
    } else {
        Serial.println("UNKNOWN");
    }

    uint64_t cardSize = SD.cardSize() / (1024 * 1024);
    Serial.printf("SD Card Size: %lluMB\n", cardSize);

    listDir(SD, "/", 0);
    createDir(SD, "/mydir");
    listDir(SD, "/", 0);
    removeDir(SD, "/mydir");
    listDir(SD, "/", 2);
    writeFile(SD, "/hello.txt", "Hello ");
    appendFile(SD, "/hello.txt", "World!\n");
    readFile(SD, "/hello.txt");
    deleteFile(SD, "/foo.txt");
    renameFile(SD, "/hello.txt", "/foo.txt");
    readFile(SD, "/foo.txt");
    testFileIO(SD, "/test.txt");
    Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
    Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
}

void loop(){

}

07/05/2018

AE-GYSFDMAXB と Wemos LOLIN32 で GPS 受信表示

Img_20180705_165137a Img_20180705_165223a 太陽誘電製の小型GPSモジュール「GYSFDMAXB」をWEMOS LOLIN32に繋いで、GPS受信表示してみた。

GYSFDMAXBは、日本の準天頂衛星システム(QZSS)「みちびき」3機受信(衛星番号193,194,195)に対応した太陽誘電製の小型高感度GPSモジュールで、秋月電子通商から購入した。
基板の大きさや性能等の詳細データは、秋月電子の商品ページから辿ることが出来る。

Wemos Lolin32は、Arduino ESP32 WiFi+Bluetooth デュアルESP-32SESP8266 OLEDモジュール(技適マーク付き)である。OLEDが既に装着されているので、携帯する機器を小型軽量に纏めるには便利かな・・・と思い、Banggoodから購入した。CNからの配送で1179円だった。購入し、これを使おうと思ってから気づいたが、これを使っての事例が少なく、動かせるようになるまで苦労した。

上記のディバイスを使ってのGPS受信結果は、左上の写真のようになった。
GYSFDMAXBの5V電源は、Wemos Lolin32のOLEDモジュール左下にある5V端子から、ブレッドボードの+電源へ、GNDはOLEDモジュールの中央部上にあるGND端子からLolin32のモジュールの下を通してブレッドボードの-端子側へ接続。

GYSFDMAXBの信号ケーブル「TXD」は、Lolin32の16番ピンへ接続した。(写真緑色の線->黄色(Lolin32の基板の下で、16番ピンに接続している))

③OLEDモジュールは、Lolin32の基板内部で結線されている。

《Sketch作成に関して》

①GPSの信号処理では「tinyGPS++」を用いたが、別のArduino基板で製作していたSketchを流用したのでその名残で使ってしまった。別のライブラリを使っても良かっただろうと思っている。

②Lolin32に付いているOLED1306を使うために”SSD1306Wire.h”が必要。
 ディスプレイは内部結線されているので、設定は、
  SSD1306Wire  display(0x3c, 5, 4)   となる。

③GPS信号は、Lolin32に読み込ませるだけなので、HadwareSerialを使うと Serial2で丁度16番ピンに繋ぐことができる。
 それで、HardwareSerial GPSRaw(2) とした。
 また、GPSの初期設定は、
  GPSRaw.begin(GPSBaud, SERIAL_8N1, 16, 17)   とした。
   ここで、GPSBaudは 9600 としている。

④ここまで決めれば、あとは自分の気に入ったように
Display用のSketchを書けばいい。
 面倒なのは、このOLEDは先に描いた場所に上書きすると重なった表示になるので、一度描いたら消さないといけない。これを解消するために簡単なテクニックが要る。

GPS受信のSketchを一度でも書いたことがある人なら、記載したSketchを見れば、処理の方法は概略分かると思うので、あまりSketchの中にコメントは記載しない。

⑤Sketch を書き込むときの注意点
 ・ボードは WEMOS LOLIN32
 ・らいぶらりーとして、ESP8266 and ESP32 Oled Driver for SSD1306 display by Daniel Eichhorn, Fabrice Weinberg Version 4.0.0 をインストールすること
 ・tinyGPS++.h のインストールを忘れないように。
 ・Sketchが書き込まれるときに Lolin32 裏面にある Boot ボタンを 書込みが始まるまで「カチカチ」と押してやる必要があります。これをしないと、Lolinが、「タイムオーバーで書き込めませんでした」と宣のですよ・・・

《Sketch》

// GPS Tracker    Sketch for Wemos LOLIN32  2018/07/05
// The serial connection to the GPS device
  #include <TinyGPS++.h>
  #include "SSD1306Wire.h"   // legacy include: '#include "SSD1306.h"'
  HardwareSerial GPSRaw(2);  // ESP32 UART2 GPIO-16 ( RXD2 ) --- GPS TXD
  const int UTC_offset = 9;  //  Japan Time
  static const int GPSBaud = 9600;
//  static const int MAX_SATELLITES = 40;
  TinyGPSPlus gps;  // The TinyGPS++ object
  TinyGPSCustom totalGPGSVMessages(gps, "GPGSV", 1); // $GPGSV sentence, first element
  TinyGPSCustom messageNumber(gps, "GPGSV", 2);      // $GPGSV sentence, second element
  TinyGPSCustom satsInView(gps, "GPGSV", 3);         // $GPGSV sentence, third element
  SSD1306Wire  display(0x3c, 5, 4);
  
void setup()
{
  Serial.begin(115200);
  GPSRaw.begin(GPSBaud, SERIAL_8N1, 16, 17);
  display.init();
}

void loop()
{
  if (GPSRaw.available() > 0)
  {
   gps.encode(GPSRaw.read());
   if (totalGPGSVMessages.isUpdated())
   {
    display.clear();
    printDateTime(gps.date, gps.time); 
    display.drawString(0,20,"Lat:");
    display.drawString(30,20,String(gps.location.lat(), 6));
    display.drawString(0,30,"Lng:"); 
    display.drawString(30,30,String(gps.location.lng(), 6)); 
    display.drawString(0,40,"Alt:");
    display.drawString(30,40,String(gps.altitude.meters()) + "m");
    display.display();

    int totalMessages = atoi(totalGPGSVMessages.value());
    int currentMessage = atoi(messageNumber.value());    
    if (totalMessages == currentMessage)
    {
     display.drawString(0,50,"Sat:");
     display.drawString(30,50,String(gps.satellites.value()) + " in use");
     display.display(); 
    }
   }
  }
}

static void printDateTime(TinyGPSDate &d, TinyGPSTime &t)
{
  display.setFont(ArialMT_Plain_10);
  if (!d.isValid())
  {
    display.drawString(0,0,"*****");  // 10 character
    display.display();
  }
  else
  {
  char sz[32];
  sprintf(sz, "%02d/%02d/%02d ", d.year(), d.month(), d.day());
  display.drawString(0,0,String(sz));
  display.display();
  }
  if (!t.isValid())
  {
  display.drawString(60,0,"*****");
  display.display();
  }
  else
  {
  char sz[32];
  sprintf(sz, "%02d:%02d:%02d ", t.hour() + UTC_offset, t.minute(), t.second());
  display.setFont(ArialMT_Plain_16);
  display.drawString(60,0,String(sz));
  display.display();
  display.setFont(ArialMT_Plain_10);
  }
}

05/09/2018

YHDC SCT-013-000 CT とArduinoで家庭内の電流を測定する

YHDC 非侵襲性AC電流センサSCT-013-000 CT  とArduinoを使って、電力量を測定する。(非侵襲性AC電流センサ は、Amazon(Hommy販売から @465円で購入))

参考にしたブログとスケッチ
1) Current monitoring with non-invasive sensor and arduino
2) SCT-013 – Sensor de Corrente Alternada com Arduino
3) openenergymonitor/EmonLib

YHDC SCT-013-000 CTの電流範囲は0〜100 Aです。
  VRefは、アナログ基準電圧で、ここでは、VRef = 5V

  Cmaxは、ADCの分解能で、ここでは、Cmax = 1024

  Rtは、電圧変換器比で、部品仕様から下記のように計算される。
     Rt = 100 A  ÷ 50 mA = 2000


  測定電流値 I = √2 * i(rms_current)= 1.414 * 100A = 141.4A

  センサーに流れる電流値 i は、次式で計算される。
       i =
測定電流値 I ÷ 電圧変換器比 Rt
        = 141.1A  ÷ 2000
         = 0.0707A


Arduinoは、電圧(0V〜5V)しか扱えないため、この電流を許容電圧に変換する必要がある。そのため、回路に負荷抵抗Rを追加する。

  電流は、0を中心に変動するので、
  センサ最大電圧は、Max_accepted_voltage(=5V) / 2 = 2.5V とすると、

       Rb(負荷抵抗)= U(センサ電圧)/ I(センサ電流)= 2.5V / 0.0707A =35.4Ω
  理想的な負荷抵抗Rb は 35.4Ωだが、そのような抵抗は無いので、
  33Ω(実際に使った抵抗の測定値は、テスターで計測した 32.8Ω)の抵抗を使用した。
図中、2個の抵抗(10kΩは、エネルギー消費を避けるため)、コンデンサ(10μF)は、交流電流が抵抗をバイパスする代替パス。

プログラム中に見られる数字は、
  counts = センサ入力ピンの電圧(=センサを通る二次電流×負荷抵抗値Rb) ÷ VRef × Cmax
 
  Isupply = counts ÷ ADCの分解能 Cmax × アナログ基準電圧VRef× 電流校正定数
      = Irms (←スケッチでの表示)
 
  ここに、電流校正定数 = Rt ÷ Rb
 
  YHDC SCT-013-000 CT センサと、テスターで計測した負荷抵抗を使い、
     電流校正定数 = Rt ÷ Rb
                = 2000 ÷ 32.8Ω = 60.976

計算は、オープンライブラリーの EnergyMonitor emon1 を利用したので、上記計算はそのライブラリーを使うための定数の理解と計算するためのステップである。

使った部品を含め、計測誤差の大きい回路構成なので、計測電流が流れていない時も0.3Aほどの電流が流れていると表示する。電流値がある値以下の場合には、スケッチの中にある様に、ゼロと表示するようにもできるが・・・。部品は安価に入手できるので、自宅で使っている電気(電流)の傾向を見るのには良いかもしれない。

《Fritzingと写真》
Sct013fritzing Img_20180417_200519SCT013のFritzingパーツがWeb上に見つからないので、僕はInkscapeの機能を使って、Fritzingに貼り付けられるよう、左図にある部品図を作った。この時参考にしたのは、Youtubeの『Fritzing Part Creation - Chapter9 - Using Photo and PDF』である。


《スケッチ》
// Current sensor SCT013-100A/50mA
#include "EmonLib.h"
#include <Wire.h>
#include <U8glib.h>

EnergyMonitor emon1;

//Oled表示設定
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE);

String str;
int characterlen;
double Irms = 0;  // the current measured

void draw()
{
  //ディスプレイのグラフィックスコマンドはここに配置する
  u8g.drawRFrame(0, 16, 128, 48, 4);
  u8g.drawRFrame(0, 0, 128, 16, 4);
  u8g.setFont(u8g_font_8x13B);
  u8g.setColorIndex(0);
  u8g.setColorIndex(1);
  u8g.drawStr( 40, 13, "Current");
  u8g.drawStr( 103, 60, "[A]");
  u8g.setFont(u8g_font_fur25);
  str = String(Irms);
  characterlen = str.length();
  u8g.setPrintPos(60 - (characterlen * 10), 53);
  u8g.print(Irms,3);
}

void setup(void)
{
  Serial.begin(9600);
  Serial.println("Current measurements value by SCT013"); 
  Serial.println("");
  Serial.println("");
  
// Theoretical CT Sensor Calibration = CT Ratio / Burden resistance
// ⇒ (100A / 0.05A) / 32.8 Ohms = 60.976
  emon1.current(1, 60.976);   // Current: inputpin No, calibration
    
  if ( u8g.getMode() == U8G_MODE_R3G3B2 ) {
    u8g.setColorIndex(255);     // white
  }
  else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) {
    u8g.setColorIndex(3);         // max intensity
  }
  else if ( u8g.getMode() == U8G_MODE_BW ) {
    u8g.setColorIndex(1);         // pixel on
  }
  else if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
    u8g.setHiColorByRGB(255, 255, 255);
  }
}

void loop(void)
{
  Irms = emon1.calcIrms(1480);  // 1480 is no_of_samples
//  if(Irms < 1.0 ) Irms = Irms -0.3; // 表示誤差分を取り除く見かけの処理
//  if(Irms < 0.20) Irms = 0.0;
  
  Serial.print("  Sensor 1: ");
  Serial.print("  Irms=");
  Serial.print(Irms,3);  // print to the third decimal place
  Serial.print("[A]");
  Serial.print("  Power=");
  Serial.print(Irms*100.0);  // Apparent power (100 is the Voltage)
  Serial.println("[W]");
  
  //画面上で描画ルーチンを呼び出し
  u8g.firstPage();
  do
  {
    draw();
  }
  while ( u8g.nextPage() );
  delay(150);
}

12/06/2017

Bluetooth modules(HC-05、HC-06)のPairing設定

Bluetooth modules(HC-05、HC-06)が互いに通信するための条件設定は何かを調べてみたので、メモとして残しておく。
本件に関しては、「Arduinoを簡単にBluetooth無線化するHC-05/HC-06
」(2015年2月20日の記事)、「Connecting 2 Arduinos by Bluetooth using a HC-05 and a HC-06: Pair, Bind, and Link 」(2014年11月の英文記事)がとても参考になる。

Bluetooth module HC-05の特徴は、
 ・Bluetoothの親機としても使用できる。(マスターでもスレーブとしてでも使用できる。)
 ・通信はBluetoothで行うが、入出力端子はシリアルのRX/TXとなっているため、Arduinoのシリアル RX/TXに接続するだけで通常のSerial通信と変わらず使用できる。

Bluetooth module HC-06の特徴は、
 ・3.3Vデバイスなので、Arduinoと接続する際には、5V Tx信号を抵抗分圧で、3.3Vにレベルシフトする必要が有る。
 ・通常Arduinoとの接続時には、再起動される。
 ・HC-06は、他のBluetooth module とペアリングしていない場合、ATコマンドを受け入れる。
 ・ATコマンドは、シリアルモニタの下端にある窓の設定は、「改行なし(No line ending、キャリッジリターン (CR) とラインフィード (LF)が無い状態
)」とし、且つ 1秒以内に送信する必要が有り、この時間を越えるとコマンドは無視される。

 ・ディバイスの名前:HC-06
 ・Password: 1234(デフォルト)
 ・Baud: 9600baud(デフォルト)


Bluetooth module HC-05およびHC-06が相互に
通信するための設定手順

①両方のデバイスで同じボーレートを設定する。

  (例)HC-05およびHC-06で、ボーレートを9600に設定する。

②両方のデバイスで、パスワードが同じであることを確認する。

  (例)HC-05とHC-06のパスワードを同じにする。

③次に、HC-06のアドレスを見つける必要がある。

  HC-06のATコマンドでは、自分(HC-06)のアドレスを調べる事は出来ないので、
  Androidデバイスから、あるいはHC-05を使って調べる事が出来る。
  
  ここの手順は、
Connecting 2 Arduinos by Bluetooth using a HC-05 and a HC-06: Pair, Bind, and Link 」の『3. Find the address of the HC-06』 に詳しく記載されているので、ここを確認するのが良い。

  HC-05で行う場合、HC-05をATコマンドモードにして以下のように行う。

  a)以前にペアになったデバイスをすべて消去するために、
    AT+RMAAD

  b)HC-05をマスタモードにする。
    
AT+ROLE=1

  c)
HC-05をリセットする。
    AT+RESET

  ピン34をHIGHにして(ATコマンドモードにして)から

  d)HC-05を任意のデバイスに接続するように設定する

    AT+CMODE=0

  e)最大5台のデバイスを9秒間検索するを行う場合、下記のコマンドを入力する。
    AT+INQM=0,5,9

  f)SPPプロファイルを開始する。もしSPPが既にアクティブであれば、無視することができるエラー(17)が表示される。
    AT+INIT
  g)ここで、他のBluetoothデバイスを検索する。
    AT+INQ
   Bluetoothデバイスが複数ある場合には、上記の設定により、5台までのデバイスが表示される。
   AT+INQは3つの値を返します。
     最初の値はアドレスで、これがペアリングの為に必要な値です。
     2番目の値はデバイスのモード。
     3番目の値はRSSI信号の強さ。

④HC-05をHC-06とペアリングする。(所謂、電話番号の交換)
  ペアリングするには、AT+PAIR= <addr>、<timeout>コマンドを使用する。
  (例) "AT + PAIR = 3014,10,171179,9"(引用符なし)と入力する。

     上記の例で、HC
-05がHC-06と 9秒以内にペアリングできない場合、
     エラーメッセージが表示される。
     ペアリングが成功すると、「OK」が表示される。

HC-06をHC-05にのアドレスとしてバインド設定する。(所謂、通話すること)
  "AT + BIND = 3014,10,171179"を使用してバインドする

⑥ペアリングされた特定の1台のデバイスにのみ接続するようにHC-05を設定する。
   CMODEコマンド でこれを行う。
  
   "AT + CMODE = 1"

HC-06へのリンク(HC-05からリモートデバイスであるHC-06への接続)
  リンクコマンドAT + LINK = <addr>を使用する

  (例)前述からの流れで示すと・・・
   "AT + LINK = 3014,10,171179" として行う。

  すべてがうまくいけば、「OK」 の応答が得られる。


  HC-05のLEDは、毎秒1回点滅し、HC-06のLEDは点灯状態(点滅ではない)。
  これで、HC-05とHC-06が接続した。

  接続設定が完了すると、HC-05は電源を入れるたびに自動的にHC-06に接続する。


  接続が確立されると、HC-05は通信モードに切り替わる。



通信の確認
テストスケッチで(私のブログならばここを参考に)確認を行う。

①HC-05とHC-06が接続された2台のArduinoの電源を切る。


②先ず、
HC-06の電源を入れる。
  LEDは1秒間に5回点滅している筈で、これは、接続を待っているか、ペアになっていることを示す。

③次に、
HC-05の電源を入れる。
  最初にLEDが数回点滅し、その後、通常パターンの点滅に変わる。

④HC-06のLEDが常時点灯する(点滅はしない)。

⑤以上で、2台のモジュールが接続される。



シリアルモニタを開くと、入力したコマンド等は、もう一方のデバイス用のモニタに表示され、逆も同様に表示される。


モジュールの電源がONになるたびに、接続し直す必要がある。モジュール間で接続していないことがわかったら、Arduinoの電源を入れ直すこと。

場合によっては、HC-05が接続しようとしてスタックしていることがある。この場合、HC-05のLEDの状況は、下記のようである。


1)2秒間に3回の点滅をしている。

2)あるいは、1秒に2回点滅します。
これは通常、HC-05をリセットしないで HC-06の電源を切り再度ONにしたときに発生する。

12/04/2017

HC-06 Bluetooth module のATコマンド

HC-05のATコマンドモードは、HC-05のプッシュボタンを押しながらArduinoの電源を入れれば、ATモードになり、それをLEDの点滅間隔で確認することができるが、HC-06にはHC-05のようなプッシュボタンが無いので、ATモード動作をどうやって行い、確認することが出来るのか?
調べてみると、「AT Command Mode of HC-05 and HC-06 Bluetooth Module by sayem2603 in wireless」に記載があった。要約したものをメモしておく。

《HC-06とHC-05の違い等について》

 ①HC05は、マスターとスレーブの両方として機能し、HC-06は、
常にスレーブに設定されていて、スレーブとしてのみ機能する。

 ② HC-06モジュールは、他のデバイスとペアリング設定されていない場合は、常にATモードになっている。したがって、HC-05のようにATモードになっていることを確認する点滅は無い。モジュールの電源を入れると、即ATコマンドモードになっている。HC-06のデフォルト設定内容を変更するには、ATコマンドを渡せば設定を変更できる。
下記にHC-06用にスケッチを書いてみると・・・
 【HC-06用のスケッチ】

// Basic Bluetooth sketch HC-06
// HC-06 モジュールと繋いで、シリアルモニタを使った通信用スケッチ
//
// HC-06 を電源ONした直後のデフォルト値と注意点は、
//   電源ON直後は ATモード(LEDの点滅とは関係なし)
//  ボーレートは 9600
//  NL+CR をコマンドに追加しない事
//   コマンドは、ATに続けて打ち込めばよい(例:AT+VERSION )
//
#include <SoftwareSerial.h>
  SoftwareSerial BTserial(2, 3); // RX | TX
// HC-06 の TX は、Arduino の RX pin2(D2)に接続する。 
// HC-06 の RX は、Arduino の TX 分電圧をして pin3(D3)に接続する。
// 
void setup() 
{
    Serial.begin(9600);
    Serial.println("AT コマンド入力 :");
// HC-06 のデフォルトでのシリアル速度は、9600
    BTserial.begin(9600);
}
void loop()
{
// HC-06 からコマンドを読み続けて、Arduino のシリアルモニタに通信する
    if (BTserial.available())
    {  
        Serial.write(BTserial.read());
    }
 
    // Arduino のシリアルモニタからのデータを読み続け、HC-06に通信する
    if (Serial.available())
    {
        BTserial.write(Serial.read());
    }
}


 ③HC-06では、ATコマンド入力の終了文字を待たず、1秒後に入力した文字に応じて動作する。したがって、1秒以内にコマンド入力を完了できない場合は、入力が無視される。
また、入力した文字のフィードバック出力も無い。このため、AT以外のATコマンドが無視されたかのように振る舞うことになる。そのため、IDE標準のシリアルモニタではなく、「Tera Term」等、別のモニタを使い、必要なATコマンドをエディタで編集して作成したものをコピーし、モニタの入力部分に貼り付けるの
が良いらしい。

  例えば、
  「
AT+VERSION」をマウスの右クリックメニューからコピーし、Tera Termに貼り付ければ、+Version:<version number>として表示されるはず。

 ④HC-06は、③の動作をするため、
複数の文字のバッチ送信を可能にする端末ソフトウェア(Tera Term等)を使用する必要がある。

 ⑤arduinoシリアルモニタで、 "AT"(引用符なし)で「Enterキー」を押すと、 "OK"が表示されATモードを確認出来る。しかし、HC-05と異なり、デフォルトの名前やボーレートは表示されない。出来るのは、それらを変更することだけ。

 ⑥HC-06で使用できるATコマンドには制限があるので、HC-05よりも少ないらしい。
  ・AT
  ・AT+NAME
  ・AT+BAUD
  ・AT+PIN
  ・AT+VERSION
  ・AT+UART
  など

 ⑦また、HC-06のコマンド入力では、HC-05とは違って、デフォルトの名前やボーレートは表示されないが、それを変更する事は出来る。
  ・名前を「PROTOTYPE」に変更する場合には、
   AT+NAMEPROTOTYPE  と記載すること。NAMEとPROTOTYPEの間にはスペースを入れないこと。

  ・ボーレートを変更するには、 AT+BAUDX  と記載すること。
   ここで、X は 1から8迄の数値をとることができる。
    1 --
> 1200bps
    2 --> 2400bps
    3 --> 4800bps
    4 --> 9600bps
    5 --> 19200bps
    6 --> 38400bps
    7 --> 57600bps
    8 --> 115200bps

   もし、38400bpsに設定したければ、 
AT+BAUD6  とすればよい。 

  因みに、ATコマンドに対して HC-06の応答は、このようになる・・・

    ATコマンド    HC-06の応答
    AT                     ->  OK
    AT+VERSION   ->    OKLinvorV1.8
    AT+BAUD4       ->    OK9600
    AT+PIN1234     ->    OK1234

December 2018
Sun Mon Tue Wed Thu Fri Sat
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          

Recent Trackbacks

無料ブログはココログ