某インク銃型水鉄砲の赤外線リモコン化
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
さんが
2021/02/25
に
編集
をしました。
(メッセージ: 初版)
-
tokumi_robo
さんが
2021/02/25
に
編集
をしました。
-
tokumi_robo
さんが
2021/02/25
に
編集
をしました。
-
tokumi_robo
さんが
2021/02/25
に
編集
をしました。
-
tokumi_robo
さんが
2021/02/27
に
編集
をしました。
-
tokumi_robo
さんが
2021/02/27
に
編集
をしました。
-
tokumi_robo
さんが
2021/02/27
に
編集
をしました。
-
tokumi_robo
さんが
2021/09/10
に
編集
をしました。
-
tokumi_robo
さんが
2021/09/10
に
編集
をしました。
-
tokumi_robo
さんが
2022/01/18
に
編集
をしました。
ログインしてコメントを投稿する