kipopytokyoのアイコン画像
kipopytokyo 2021年02月20日作成 (2023年07月25日更新) © CERN-OHL-P 2
製作品 製作品 閲覧数 2205
kipopytokyo 2021年02月20日作成 (2023年07月25日更新) © CERN-OHL-P 2 製作品 製作品 閲覧数 2205

流し忘れても安心!立ったら勝手に流してくれるリモコン

流し忘れても安心!立ったら勝手に流してくれるリモコン

elchika初投稿です!宜しくお願い致します 😉

みなさんは、トイレでうっかり流し忘れてしまうことありませんか?
高級なトイレの場合は、デフォルトで自動洗浄機能が付いていますが、安かったり、古いトイレの場合、自動洗浄機能はありません。
そこで思い立ち、「立ったら勝手に流してくれるリモコン」(早い話が自動洗浄機能)を製作しましたので、紹介しましょう。

😄まずは下ごしらえ😄

このリモコンを作るには、トイレを自動で流す機能が必要です。一から作るとなると、結構な労力です。そこで、出来合いの物を購入することにしました。
LIXIL(旧TOTO)から発売されている「流せるもん CWA-67B」という物を購入。コイツは、赤外線リモコンを使用して、トイレをモーター制御で流すというもの。
13000円位と少々お高めではありますが、モーターや赤外線リモコン、その他付属品が付いており、TOTO製の「流せるもん CWA-67B」の適合しているトイレではなかったのですが、付属品を微調整して、中のフロートを上げ下げできるようにすることで動かすことができました。
今まで通り、普通に流すこともできますが、リモコン操作でも流せることができ、何かちょっと感動。
でも、これはあくまでもスタートです。
「流せるもん~」の詳細は、私のブログで紹介しておりますので、ご参照ください。

😉リモコンを作る😉

当初は、折角リモコンがあるので、それを改造すればいいじゃないか…そう思い、センサーやマイコンを付けて改造したのですが、意外とセンサーが大飯食らいなので、電池2本では何日も使えないような代物になってしまいました(「流せるもん」は、単三電池2本)。

困っていた所、おあつらえ向きなガジェットを見つけました。elchikaをご覧になっている方ならお馴染みの「M5Stick C」です。
私はどちらかというと、部品を組み合わせてはんだ付けするのが好きなのですが、色々調べると、M5Stick CにジャストフィットするHATやM5Stack・Grove用に用意されているモジュール類がそのまま使えるらしく、私の用途では、HATとM5STACK用IRモジュールを使うと用が足りてしまいます。

後はプログラムさえ作ればよく、ホント便利な世の中になったものです(すっかりオヂさんな気分)。
昔のように、回路を組んでガシガシやるのではなく、あるものを使って、スマートに使いこなすのが、今の時代にマッチした電子工作の姿なのかも知れませんね。

オリジナルのリモコンと自動洗浄用のリモコンの2個あることになりますが、オリジナルの方は常時動いているわけではないし、2個あることによる支障はないので、まっ、結果オーライです😅

これにも、実は顛末記があり、M5Stick Cに内蔵されているIR LEDでも狭いトイレの中では、充分動いてくれたのですが、ToFユニットを付けてしまうと、IR LEDの穴が塞がってしまうというオチが。

折角ToFユニットを買ったので、それを生かすことにし、IRの方を別の物(M5Stack用赤外線送受信ユニット)とすることにしたのですが、今度は、何故か赤外線の飛びが悪く、結局は、M5Stick C+ToF測距センサユニット(https://www.switch-science.com/catalog/5219/)の組み合わせに変更しました。

人の動きをとらえるセンサーには人感センサーがよく使われますが、センサー付きLED電球で経験された方はご存じと思いますが、明るい所では全く役に立ちません。
赤外線を使って、戻ってくる時間を測定するというToF(タイムオブフライト)センサーは(使われているデバイスは)940nmの赤外線を使用しており、明るさに影響を受けません。
今回の用途には、まさに打ってつけです!

😙材料😙

部品 個数 値段 購入先
M5Stick C 1 ¥1,980 スイッチサイエンスなど
M5Stack用ToF測距センサユニット 1 ¥1,177 スイッチサイエンスなど

(以下は、お好みに応じて)

部品 個数
USB Cケーブル
USB 5V電源 1

送料を除けば、ケーブル込みで大体4,000円少々でできました。
M5Stick Cには、バッテリーが内蔵されているのですが、バッテリー切れを嫌って、私はUSB電源を使用しました。
M5Stick-Cの電源をOFFにしていても、ある程度電流が流れているのか、一晩放置していたら、全く動かなくなってしまいました。
慌てて、USB電源をつないでもダメでした。どうもプログラムが消えてしまったようで…。ユニットを付けるとダメなんでしょうか。トホホ…😭
そのような訳で、長時間使う向きにはUSB電源をお勧めします。
接続図

😮プログラム紹介😮

下記のプログラムは、私のオリジナルではなく、今回の用途のためにサンプルを合体させ、更にモディファイしたものです。
ToFサンプル:https://github.com/m5stack/M5-ProductExampleCodes/blob/master/Hat/tof-hat/Arduino/ToF
IRサンプル:https://github.com/crankyoldgit/IRremoteESP8266/issues/706

特に、IRの箇所は、TVやエアコンなどの実例はあれど、トイレ用などのものは殆ど見つけることができませんでした。
色々実験した所、上記のサンプルの結果が良かったので、IR送信の部分はそちらを参考にしました。

ライブラリはそのまま流用しているので、Arduino IDEのライブラリマネージャから必ずIRremoteESP8266をゲットしてくださいね。
それと、M5***を始めて使う人は、https://github.com/m5stack/M5StickCからライブラリ(Zipファイル)をゲットして、こちらもインストールしてください。
公式では、Arduino IDEのライブラリマネージャからM5StickCライブラリをインストールするような指示になっていますが、ファイルが足りなくて、悲しいかなコンパイルができません(2021年2月現在)。
早く改善して~😭

立ったら勝手に流してくれるリモコンの例(ArduinoIDE用)

#include <Arduino.h> #include <IRremoteESP8266.h> #include <IRsend.h> #include <M5StickC.h> #include <Wire.h> // byte SEND_PIN = 32; // IR Unit:32 byte SEND_PIN = 9; // 本体IR:9 IRsend irsend(SEND_PIN); #define VL53L0X_REG_IDENTIFICATION_MODEL_ID 0xc0 #define VL53L0X_REG_IDENTIFICATION_REVISION_ID 0xc2 #define VL53L0X_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD 0x50 #define VL53L0X_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD 0x70 #define VL53L0X_REG_SYSRANGE_START 0x00 #define VL53L0X_REG_RESULT_INTERRUPT_STATUS 0x13 #define VL53L0X_REG_RESULT_RANGE_STATUS 0x14 #define ToF_ADDR 0x29//the iic address of tof //「流せるもん」のコードに合わせています。 const uint16_t kInaxHdrMark = 9000; const uint16_t kInaxHdrSpace = 4434; const uint16_t kInaxBitMark = 600; const uint32_t kInaxOneSpace = 1675; const uint32_t kInaxZeroSpace = 570; const uint64_t InaxData = 0x5C30CF; //「大」ボタンのコード byte gbuf[16]; uint16_t dist; uint16_t tmp1; uint8_t i, countdown; void measure_distance(); uint16_t bswap(byte); uint16_t makeuint16(int, int); uint16_t VL53L0X_decode_vcsel_period(short); void write_byte_data(byte); void write_byte_data_at(byte, byte); void write_word_data_at(byte, uint16_t); byte read_byte_data(); byte read_byte_data_at(byte); uint16_t read_word_data_at(byte); void read_block_data_at(byte, int); void setup() { // Wire.begin(0, 26, 400000);// join i2c bus (HATの場合) Wire.begin(32, 33, 400000);// join i2c bus (ToFユニットの場合) M5.begin(); M5.Lcd.setRotation(2); irsend.begin(); pinMode(10, OUTPUT); digitalWrite(10, HIGH); } void sendWashletCommand(uint64_t data, uint16_t nbytes, uint16_t repeat) { irsend.enableIROut(38); for (uint16_t r = 0; r <= repeat; r++) { // Header irsend.mark(kInaxHdrMark); irsend.space(kInaxHdrSpace); // Data irsend.sendData(kInaxBitMark, kInaxOneSpace, kInaxBitMark, kInaxZeroSpace, data, nbytes, true); // Footer irsend.mark(kInaxBitMark); irsend.space(100000); } } void loop() { tmp1 = 0; measure_distance(); delay(100); if (dist > 200){ digitalWrite(10,HIGH); } else if (dist == 20){ //時々、誤動作なのか、一瞬 数値が20(0cmの距離)となる時があった。 //distが20になっても何もしないようダミーとする。 }else { digitalWrite(10,LOW); while (dist < 200){ //着座している時はループ measure_distance(); delay(100); } //立ったら、30秒(30秒*2=60)ディレイ //iを増減すると、離れてから流す時間を変えられます。 //変数countdownは、表示に用います。 countdown = 30; i = 60; while (i > 0){ //0.5秒間隔で、M5Stick CのLED(G10)を点滅させる。 if (digitalRead(10)){ digitalWrite(10, LOW); M5.Lcd.setCursor(0, 80); M5.Lcd.fillScreen(BLACK); M5.Lcd.setTextFont(7); M5.Lcd.print(countdown); countdown--; } else { digitalWrite(10, HIGH); } i--; delay(500); } M5.Lcd.fillScreen(BLACK); M5.Lcd.setTextFont(1); M5.Lcd.setCursor(20,80); M5.Lcd.print("Flash!"); digitalWrite(10, LOW); sendWashletCommand(InaxData, 24, 0); delay(2000); M5.Lcd.fillScreen(BLACK); digitalWrite(10, HIGH); } } void measure_distance() { write_byte_data_at(VL53L0X_REG_SYSRANGE_START, 0x01); read_block_data_at(VL53L0X_REG_RESULT_RANGE_STATUS, 12);//read 12 bytes once dist = makeuint16(gbuf[11], gbuf[10]);//split distance data to "dist" M5.Lcd.fillScreen(BLACK); M5.Lcd.setCursor(20, 80); M5.Lcd.setRotation(2); M5.Lcd.setTextFont(1); M5.Lcd.print(dist); } uint16_t bswap(byte b[]) { // Big Endian unsigned short to little endian unsigned short uint16_t val = ((b[0] << 8) & b[1]); return val; } uint16_t makeuint16(int lsb, int msb) { return ((msb & 0xFF) << 8) | (lsb & 0xFF); } uint16_t VL53L0X_decode_vcsel_period(short vcsel_period_reg) { // Converts the encoded VCSEL period register value into the real // period in PLL clocks uint16_t vcsel_period_pclks = (vcsel_period_reg + 1) << 1; return vcsel_period_pclks; } /* * IIC Functions */ /* function description: write one byte data */ void write_byte_data(byte data) { Wire.beginTransmission(ToF_ADDR); Wire.write(data); Wire.endTransmission(); } /* function description: write one byte data to specifical register */ void write_byte_data_at(byte reg, byte data) { Wire.beginTransmission(ToF_ADDR); Wire.write(reg); Wire.write(data); Wire.endTransmission(); } /* function description: read two bytes data to specifical register */ void write_word_data_at(byte reg, uint16_t data) { byte b0 = (data &0xFF); byte b1 = ((data >> 8) && 0xFF); Wire.beginTransmission(ToF_ADDR); Wire.write(reg); Wire.write(b0); Wire.write(b1); Wire.endTransmission(); } /* function description: read one byte data */ byte read_byte_data() { Wire.requestFrom(ToF_ADDR, 1); while (Wire.available() < 1) delay(1); byte b = Wire.read(); return b; } /* function description: read one byte data from specifical register */ byte read_byte_data_at(byte reg) { //write_byte_data((byte)0x00); write_byte_data(reg); Wire.requestFrom(ToF_ADDR, 1); while (Wire.available() < 1) delay(1); byte b = Wire.read(); return b; } /* function description: read two bytes data from specifical register */ uint16_t read_word_data_at(byte reg) { write_byte_data(reg); Wire.requestFrom(ToF_ADDR, 2); while (Wire.available() < 2) delay(1); gbuf[0] = Wire.read(); gbuf[1] = Wire.read(); return bswap(gbuf); } /* function description: read multiple bytes data from specifical register */ void read_block_data_at(byte reg, int sz) { int i = 0; write_byte_data(reg); Wire.requestFrom(ToF_ADDR, sz); for (i=0; i<sz; i++) { while (Wire.available() < 1) delay(1); gbuf[i] = Wire.read(); } }

😋動作を解説😋

主要動作であるメインループの箇所をチャートで纏めてみました(ライブラリに関しては、各ソースをご参照ください)。

動作(一部)

以下、簡単に説明します。

  1. ToFモジュールの測定値を確認し、値が200より大きければ(離れている)M5Stick Cに内蔵されている本体LEDを消灯。
  2. 200未満(着座)であれば、本体LEDを点灯。
  3. 再び測定値が200より大きくなれば(立つ)、30秒本体LEDを点滅させ、「大」のコードを赤外線送信する。
  4. LEDを消灯した後、距離を測るループに入る。

以上のような流れです。

😓実際に使ってみた😓

短いですが、YouTubeにアップしましたので、様子をご覧ください。

ここに動画が表示されます

これは、我が家の介護用として製作したもので、いざ使ってみると、立ったときに自動で流してくれるのは便利よね…と思ったりして。立ってから30秒は短いかも知れません。
センサーに手をかざしてもOKですので、手を触れることなく自動洗浄できますよ。コロナ禍の今にピッタリかも。
「kInax~(赤外線のパルス幅を設定)」という変数をいじれば、他の会社のリモコンにも応用できるはずなので、興味ある方は、色々実験してみてくださいね😉
My weblog:https://kinopy.info/kinopy

kipopytokyoのアイコン画像
自作ができなかった元ラジオ少年です。 本業で、機械の電装系だけでなく、プログラミングの類をやったり、おっかなびっくり治具の加工をしたりして、一体何屋さんなんだろうと考える今日この頃。 ラジオキットから始まり、BCL・アマチュア無線などを経て、大人になるにつれて、色々と迷作が作れるようになり、プログラミングをかじり、更にどうしようもない物を製作する 子育て中の おっさんです。 https://www.kinopy.info/kinopy/及びhttps://crijpa.com/にてブログ公開しています。
ログインしてコメントを投稿する