M5StickC Plus に Grove Water Level Sensor をつなげるメモ

M5StickC Plus に Grove Water Level Sensor をつなげるメモです。

先日行われた 【オンラインコラボ企画】ゆるメカトロ・Noodl・ビジュアルプログラミングで合同もくもく会 で進めたものをまとめました。

Grove Water Level Sensor

image

スイッチサイエンスで Grove – 水位センサ(10cm) を購入しました。

image

このセンサーは 0 ~ 100 mm で 5mm 刻みで I2C でデータが取れます。実際の動かし方は Seeed 社本家の Wiki の Arduinoソースを参考にしました。

Grove – Water Level Sensor – Seeed Wiki

M5Stick C Plus の Hello World でハマる

M5StickC のソースのまま M5StickC Plus 動かそうとしたら全然動かなくて、「え、M5StickC Plus、M5StickCと違うの?」ってなったとき、以下の記事もとても助かりました。ありがとうございます~。

M5StickCとM5StickC Plusの違い – Lang-ship

M5StickC Plus の独立してる Arduino ライブラリとして入れて動かします。

image

このようなソースです。

// #include <M5StickC.h>
#include <M5StickCPlus.h>

void setup(){
  // Initialize
  M5.begin();

  // LCD display
  M5.Lcd.setRotation(3);
  M5.Lcd.setTextSize(2);
  M5.Lcd.println("[M5StickCPlus]");
  M5.Lcd.println("");
  M5.Lcd.setTextSize(3);
  M5.Lcd.println("Hello World,");
  M5.Lcd.setTextSize(2);
  M5.Lcd.println("finally(>_<;)");
}

void loop() {
}

M5Stick C Plus に Grove Water Level Sensor をつなげる

あとは こちらのプログラム を M5Stick C Plus に合体させればOKです。

image

このセンサーはタッチセンサーのような仕組みで水をとらえているようで、実は指で抑えてもテストすることができます。

ちゃんと 0 cm のところから連続して触れると水位レベルとしてとらえられます。仮に、指が一部密着 0 cm のところから密着しているところまでが水位となりますのでテスト時は注意ください。

実際にはこのようなソースを書きました。

// #include <M5StickC.h>
#include <M5StickCPlus.h>

#include <Wire.h>
 
#ifdef ARDUINO_SAMD_VARIANT_COMPLIANCE
#define SERIAL SerialUSB
#else
#define SERIAL Serial
#endif
 
unsigned char low_data[8] = {0};
unsigned char high_data[12] = {0};
 
 
#define NO_TOUCH       0xFE
#define THRESHOLD      100
#define ATTINY1_HIGH_ADDR   0x78
#define ATTINY2_LOW_ADDR   0x77
 
void getHigh12SectionValue(void)
{
  memset(high_data, 0, sizeof(high_data));
  Wire.requestFrom(ATTINY1_HIGH_ADDR, 12);
  while (12 != Wire.available());
 
  for (int i = 0; i < 12; i++) {
    high_data[i] = Wire.read();
  }
  delay(10);
}
 
void getLow8SectionValue(void)
{
  memset(low_data, 0, sizeof(low_data));
  Wire.requestFrom(ATTINY2_LOW_ADDR, 8);
  while (8 != Wire.available());
 
  for (int i = 0; i < 8 ; i++) {
    low_data[i] = Wire.read(); // receive a byte as character
  }
  delay(10);
}
 
void check()
{
  int sensorvalue_min = 250;
  int sensorvalue_max = 255;
  int low_count = 0;
  int high_count = 0;
  while (1)
  {
    uint32_t touch_val = 0;
    uint8_t trig_section = 0;
    low_count = 0;
    high_count = 0;
    getLow8SectionValue();
    getHigh12SectionValue();
 
    Serial.println("low 8 sections value = ");
    for (int i = 0; i < 8; i++)
    {
      Serial.print(low_data[i]);
      Serial.print(".");
      if (low_data[i] >= sensorvalue_min && low_data[i] <= sensorvalue_max)
      {
        low_count++;
      }
      if (low_count == 8)
      {
        Serial.print("      ");
        Serial.print("PASS");
      }
    }
    Serial.println("  ");
    Serial.println("  ");
    Serial.println("high 12 sections value = ");
    for (int i = 0; i < 12; i++)
    {
      Serial.print(high_data[i]);
      Serial.print(".");
 
      if (high_data[i] >= sensorvalue_min && high_data[i] <= sensorvalue_max)
      {
        high_count++;
      }
      if (high_count == 12)
      {
        Serial.print("      ");
        Serial.print("PASS");
      }
    }
 
    Serial.println("  ");
    Serial.println("  ");
 
    for (int i = 0 ; i < 8; i++) {
      if (low_data[i] > THRESHOLD) {
        touch_val |= 1 << i;
 
      }
    }
    for (int i = 0 ; i < 12; i++) {
      if (high_data[i] > THRESHOLD) {
        touch_val |= (uint32_t)1 << (8 + i);
      }
    }
 
    while (touch_val & 0x01)
    {
      trig_section++;
      touch_val >>= 1;
    }
    SERIAL.print("water level = ");
    SERIAL.print(trig_section * 5);
    SERIAL.println("% ");

    M5.Lcd.setCursor(0, 50);
    // M5.Lcd.fillScreen(TFT_BLACK);
    // M5.Lcd.print("water level = ");
    M5.Lcd.setTextSize(5);
    M5.Lcd.print(trig_section * 5);
    // M5.Lcd.setTextSize(4);
    M5.Lcd.println("% ");
    
    SERIAL.println(" ");
    SERIAL.println("*********************************************************");
    delay(1000);
  }
}

// the setup routine runs once when M5StickC starts up
void setup(){
  // Initialize the M5StickC object
  M5.begin();

  M5.Lcd.setRotation(3);
  M5.Lcd.setTextSize(2); 
  
  // LCD display
  M5.Lcd.print("Hello World");

  M5.Lcd.setCursor(0, 0);

  M5.Lcd.setTextSize(3);
  M5.Lcd.fillScreen(TFT_BLACK);
  M5.Lcd.print("[water Lv]");

  SERIAL.begin(115200);
  Wire.begin();
}

// the loop routine runs over and over again forever
void loop() {
  check();
}

実際にはこのように動きます。