tokumi_roboのアイコン画像
tokumi_robo 2021年02月25日作成 (2022年01月18日更新)
製作品 製作品 閲覧数 1451
tokumi_robo 2021年02月25日作成 (2022年01月18日更新) 製作品 製作品 閲覧数 1451

某インク銃型水鉄砲の赤外線リモコン化

某インク銃型水鉄砲の赤外線リモコン化

1.はじめに

たしかフリマサイトの2000円引きクーポンで買った某インク銃の水鉄砲です。
かなり前に作りかけて、家の隅の方でガラクタになっていた赤外線リモコン銃を今回完成させました。

2.仕様

ArduinoのIRremoteライブラリで、テレビのリモコン信号や扇風機、リビングの電気などの赤外線信号を解析し、ArduinoのAVR328pマイコンに保存、基板に実装して家電ごとにDIPスイッチで切り替え、トリガーのところにあるタクトスイッチを押すと赤外線を送信し同時に光線銃の音が鳴る仕組みです。

3.使用したもの

  • 某インク銃型水鉄砲
  • マイクロスピーカー 赤/黒リード付 8Ω
  • DFPlayer min(MP3プレーヤー)
  • AVR328p
  • フルカラーLED
  • タクトスイッチ
  • トグルスイッチ
  • DIPスイッチ
  • 赤外線LED
  • MOSFET 2N7000
  • 006Pアルカリ電池 (積層電池) 9V
  • バッテリースナップ
  • 各種抵抗
  • パスコン
  • DCDCコンバータ 9V→5V

4.回路図

キャプションを入力できます
回路図はこんな感じです。

Arduinoではデジタルの3ピンで赤外線信号を送信できるが出力が弱いのでMOSFETでパワーアップ

5.配線

キャプションを入力できます

ここの赤外線LEDの部分をモジュール化して

キャプションを入力できます

水鉄砲の先端部分にあった謎のくぼみに無理やり入れています。

キャプションを入力できます

ここのDIPスイッチとフルカラーLEDは外から見えるところにあった方が良いため、無理やり引っ張り出してきて前面にグルーガンで固定

キャプションを入力できます
こんな感じ

キャプションを入力できます

ピンク色の部分を外したところにある隙間に回路を実装しました。
水鉄砲の構造自体はいじっていないので本来の用途でも普通に使えると思う

キャプションを入力できます
              実験段階

キャプションを入力できます
              回路実装後
電子工作を始めたての時に配線したものですので配線は汚くなっております。。
トリガースイッチを押したときの光線銃の音のデータはMP3形式でMicroSDに入れ、DFPlayerに差し込んであります。

6.プログラム

赤外線リモコン銃

//赤外線リモコン銃プログラム #include "Arduino.h" #include "SoftwareSerial.h" #include "DFRobotDFPlayerMini.h" #include <IRremote.h>  //赤外線はArduinoのGPIO3で送信できる //ピン指定 #define BUSY_PINNO 9 #define trigerSW 8 #define sw1 7 #define sw2 6 #define sw3 5 #define sw4 4 #define RLED 13 #define GLED A1 #define BLED 12 SoftwareSerial mySoftwareSerial(10, 11); // (TX, RX) DFRobotDFPlayerMini myDFPlayer; void printDetail(uint8_t type, int value); IRsend irsend; void setup(){ Serial.begin(115200); // software serial init mySoftwareSerial.begin(9600); if (!myDFPlayer.begin(mySoftwareSerial)) { //Use softwareSerial to communicate with mp3. Serial.println(F("Unable to begin:")); Serial.println(F("1.Please recheck the connection!")); Serial.println(F("2.Please insert the SD card!")); while (true); } // BUSY_PINNO init pinMode(BUSY_PINNO, INPUT); //switch pinMode(trigerSW, INPUT_PULLUP); pinMode(sw1, INPUT_PULLUP); pinMode(sw2, INPUT_PULLUP); pinMode(sw3, INPUT_PULLUP); pinMode(sw4, INPUT_PULLUP); //LED pinMode(RLED, OUTPUT); pinMode(GLED, OUTPUT); pinMode(BLED, OUTPUT); // DFPlayer Init myDFPlayer.setTimeOut(500); //Set serial communictaion time out 500ms myDFPlayer.setTimeOut(10000000); myDFPlayer.volume(30); //Set volume value (0~30) myDFPlayer.EQ(DFPLAYER_EQ_NORMAL); myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD); } void PLAYBACK_MP3_MUSIC1(void) {//レーザー銃音 int isBusy = digitalRead(BUSY_PINNO); // 0:playing, 1:not playing (refer website) if (isBusy == 1) { myDFPlayer.play(1); //Play next mp3 every 3 second. } } void PLAYBACK_MP3_MUSIC2(void) {//機関銃音 int isBusy = digitalRead(BUSY_PINNO); // 0:playing, 1:not playing (refer website) if (isBusy == 1) { myDFPlayer.play(2); //Play next mp3 every 3 second. } } void PLAYBACK_MP3_MUSIC3(void) {//操作音 int isBusy = digitalRead(BUSY_PINNO); // 0:playing, 1:not playing (refer website) if (isBusy == 1) { myDFPlayer.play(3); //Play next mp3 every 3 second. } } void Stop(void) {//操作音ストップ int isBusy = digitalRead(BUSY_PINNO); // 0:playing, 1:not playing (refer website) if (isBusy == 1) { myDFPlayer.setTimeOut(100000); } } /*テレビ*/ void TVON(void) { //テレビON信号 //赤外線データコード int khz = 38;//搬送波38kHz unsigned int irSignal[] = {3450, 1500, 550, 300, 550, 1100, 550, 300, 500, 1150, 500, 350, 500, 1150, 500, 350, 500, 1150, 500, 350, 450, 1200, 500, 300, 500, 1200, 450, 1200, 450, 350, 500, 1200, 450, 350, 500, 1150, 500, 1200, 450, 1200, 450, 1200, 500, 350, 450, 350, 500, 350, 450, 1200, 500, 350, 450, 1200, 450, 350, 500, 350, 500, 1150, 500, 350, 450, 350, 500, 400, 450, 350, 450, 1200, 450, 1200, 500, 350, 450, 1200, 450, 400, 450, 350, 500, 350, 450, 1200, 450, 400, 450, 350, 500, 350, 450, 1200, 500, 350, 450, 1200, 450, 1200, 500 }; irsend.sendRaw(irSignal, sizeof(irSignal) / sizeof(irSignal[0]), khz); } void Channel_menu(void) {//番組表ボタン int khz = 38;//搬送波38kHz unsigned int irSignal[] = {3450, 1550, 550, 300, 500, 1150, 550, 300, 500, 1150, 500, 350, 500, 1150, 500, 300, 550, 1150, 500, 300, 500, 1150, 550, 300, 500, 1150, 500, 1150, 500, 350, 500, 1150, 500, 350, 500, 1150, 500, 1150, 500, 1200, 450, 1200, 500, 300, 500, 350, 500, 350, 450, 1200, 450, 350, 500, 1200, 450, 350, 500, 350, 450, 1200, 500, 350, 450, 350, 500, 350, 450, 350, 500, 350, 500, 350, 450, 350, 500, 350, 450, 1200, 500, 1150, 500, 350, 450, 400, 450, 1200, 450, 400, 450, 350, 450, 1200, 500, 1150, 500, 1150, 500, 1200, 450 }; irsend.sendRaw(irSignal, sizeof(irSignal) / sizeof(irSignal[0]), khz); } void Right(void) {//リモコンの右ボタン int khz = 38;//搬送波38kHz unsigned int irSignal[] = {3450, 1500, 550, 350, 500, 1150, 500, 300, 550, 1100, 550, 300, 500, 1150, 550, 300, 500, 1150, 500, 350, 500, 1150, 500, 350, 500, 1150, 500, 1150, 500, 350, 500, 1150, 500, 300, 500, 1200, 450, 1200, 500, 1150, 500, 1150, 500, 350, 500, 300, 500, 350, 500, 1150, 500, 350, 500, 1150, 500, 350, 450, 350, 500, 1200, 450, 350, 500, 350, 450, 350, 500, 350, 450, 400, 450, 350, 500, 1150, 500, 1200, 450, 350, 500, 1150, 500, 1200, 450, 1200, 450, 400, 450, 350, 500, 350, 450, 1200, 450, 1200, 500, 1150, 500, 1150, 500 }; irsend.sendRaw(irSignal, sizeof(irSignal) / sizeof(irSignal[0]), khz); } void Left(void) {//リモコンの左ボタン int khz = 38;//搬送波38kHz unsigned int irSignal[] = {3450, 1500, 550, 350, 500, 1150, 500, 300, 550, 1150, 500, 300, 500, 1150, 550, 300, 500, 1150, 500, 350, 500, 1150, 500, 350, 500, 1150, 500, 1150, 500, 350, 500, 1150, 500, 300, 500, 1200, 450, 1200, 500, 1150, 500, 1150, 500, 350, 500, 300, 500, 350, 500, 1150, 500, 350, 500, 1150, 500, 350, 450, 350, 500, 1200, 450, 350, 500, 350, 450, 350, 500, 1200, 450, 1200, 450, 1200, 500, 350, 450, 1200, 450, 350, 500, 1200, 450, 1200, 450, 1200, 500, 350, 450, 350, 500, 350, 450, 400, 450, 350, 500, 350, 450, 400, 450 }; irsend.sendRaw(irSignal, sizeof(irSignal) / sizeof(irSignal[0]), khz); } void Enter(void) {//決定ボタン int khz = 38;//搬送波38kHz unsigned int irSignal[] = {3500, 1500, 600, 250, 550, 1100, 600, 250, 550, 1100, 550, 300, 550, 1100, 550, 300, 500, 1150, 550, 300, 500, 1150, 500, 300, 550, 1100, 550, 1150, 500, 300, 550, 1150, 500, 350, 500, 1100, 550, 1150, 500, 1150, 500, 1150, 500, 350, 500, 350, 450, 350, 500, 1150, 500, 350, 500, 1150, 500, 350, 500, 300, 500, 1200, 450, 350, 500, 350, 500, 350, 450, 350, 500, 1150, 500, 350, 500, 350, 450, 1150, 500, 350, 500, 1150, 500, 350, 500, 1150, 500, 350, 500, 350, 450, 350, 500, 1150, 500, 350, 450, 1200, 500, 1150, 500 }; irsend.sendRaw(irSignal, sizeof(irSignal) / sizeof(irSignal[0]), khz); } /*扇風機*/ void Fan(void) {//扇風機のリモコン信号 int khz = 38;//搬送波38kHz unsigned int irSignal[] = {9050, 4400, 650, 1550, 650, 1600, 650, 450, 650, 500, 600, 500, 650, 1600, 600, 1600, 650, 500, 600, 500, 650, 450, 650, 1600, 650, 1600, 600, 1600, 650, 450, 650, 500, 650, 1600, 600, 500, 650, 1600, 600, 500, 650, 450, 650, 1600, 650, 450, 650, 500, 600, 500, 650, 1600, 600, 500, 650, 1600, 600, 1600, 650, 500, 600, 1600, 650, 1600, 600, 1600, 650 }; irsend.sendRaw(irSignal, sizeof(irSignal) / sizeof(irSignal[0]), khz); } void loop() { int value; value = digitalRead(trigerSW); //変数 int mode1; int mode2; int mode3; int mode4; //ディップスイッチ判定 if (digitalRead(sw1) == HIGH) { mode1 = 1; } else { mode1 = 0; } if (digitalRead(sw2) == HIGH) { mode2 = 1; } else { mode2 = 0; } if (digitalRead(sw3) == HIGH) { mode3 = 1; } else { mode3 = 0; } if (digitalRead(sw4) == HIGH) { mode4 = 1; } else { mode4 = 0; } //TVON_赤 if (mode1 == 0 && mode2 == 0 && mode3 == 0 && mode4 == 0) { digitalWrite(RLED, HIGH); //赤 delay(100); digitalWrite(RLED, LOW); if ( value == LOW ) {//トリガーの判断 digitalWrite(RLED, LOW); PLAYBACK_MP3_MUSIC1(); delay(100); TVON(); delay(500); } else { Stop(); } } //番組表mode_青 if (mode1 == 1 && mode2 == 0 && mode3 == 0 && mode4 == 0) { digitalWrite(BLED, HIGH); //青 delay(100); digitalWrite(BLED, LOW); if ( value == LOW ) {//トリガーの判断 digitalWrite(BLED, LOW); PLAYBACK_MP3_MUSIC3(); delay(100); Channel_menu(); delay(500); } else { Stop(); } } //右_mode_黄 if (mode1 == 0 && mode2 == 1 && mode3 == 0 && mode4 == 0) { digitalWrite(GLED, HIGH); //黄 digitalWrite(RLED, HIGH); delay(100); digitalWrite(GLED, LOW); digitalWrite(RLED, LOW); if ( value == LOW ) {//トリガーの判断 digitalWrite(GLED, LOW); digitalWrite(RLED, LOW); PLAYBACK_MP3_MUSIC3(); delay(100); Right(); delay(500); } else { Stop(); } } //左_mode_緑 if (mode1 == 1 && mode2 == 1 && mode3 == 0 && mode4 == 0) { digitalWrite(GLED, HIGH); //緑 delay(100); digitalWrite(GLED, LOW); if ( value == LOW ) {//トリガーの判断 digitalWrite(GLED, LOW); PLAYBACK_MP3_MUSIC3(); delay(100); Left(); delay(500); } else { Stop(); } } //決定_mode_シアン if (mode1 == 0 && mode2 == 1 && mode3 == 1 && mode4 == 0) { digitalWrite(GLED, HIGH); //シアン digitalWrite(BLED, HIGH); delay(100); digitalWrite(GLED, LOW); digitalWrite(BLED, LOW); if ( value == LOW ) {//トリガーの判断 digitalWrite(GLED, LOW); digitalWrite(BLED, LOW); PLAYBACK_MP3_MUSIC3(); delay(100); Enter(); delay(500); } else { Stop(); } } //扇風機&Gan_mode_マゼンタ if (mode1 == 1 && mode2 == 1 && mode3 == 1 && mode4 == 1) { //Light_mode digitalWrite(RLED, HIGH); //マゼンタ digitalWrite(BLED, HIGH); delay(100); digitalWrite(RLED, LOW); digitalWrite(BLED, LOW); if ( value == LOW ) {//トリガーの判断 digitalWrite(RLED, LOW); digitalWrite(BLED, LOW); PLAYBACK_MP3_MUSIC2(); delay(100); Fan(); delay(100); } else { Stop(); } } }

DIPスイッチを切り替えてトリガースイッチを押すことで
TVのオンオフ、番組表、決定、方向キー、扇風機など切り替えれるようにしてある。

扇風機.....っていつの夏に作ったんだよ

7.動作確認

twitter上に動作の様子をアップしました。

8.課題と問題点

IRremoteライブラリで赤外線のデータを解析したのですが、Arduinoに書き込む際にrawデータで書き込んだことにより、長い赤外線コードを書き込まなければならず、AVR328pのメモリがぎりぎりで動作が不安定なまま書き込みをしました。
もっとうまくコードが書ける方法があるはず。
さらに、基板や6p電池が大きいため水鉄砲の中に入らず、無理やり押し込んで配線が飛び出たり汚くなってます。プリント基板化等すれば、より小型にできたと思います。←当時はそんな技術力ない。

tokumi_roboのアイコン画像
こんにちは。大学でロボット相撲をしてます。電子工作やパワエレに興味があります。たまーにモノを作って上げようと思います。 Twitter→@tokumi_robo Youtube→https://www.youtube.com/channel/UCfrWZ3wYANxSnQf3GeVgXqQ はてなブログ→https://tokumi-electronics.hatenablog.jp/
ログインしてコメントを投稿する