TOPへ

全自動イライラ機 製作記事

 
○概要
まずは私が作成した、こちらのページをご覧いただきたい↓↓↓
スイッチ?Web

「ON」を押すと「OFF」になるけど、別のスイッチが「ON」になる・・・というなんとも憎たらしい動きをするだけのアプリケーションです。
特に目的も意味もあるわけではないですが、ぼーっとしながら延々とスイッチをポチポチクリックしていくのは個人的にはなんとなく"頭が休まる感じ"がします。
こうしてポチポチ遊んでいたらPCを起動しなくても使用できる、これと同じ動作をするハードウェアを作ってみたくなりました。
今回はそんな特に目的も意味もない、純粋に"作ってみたい"という動機だけで作り始めた「全自動イライラ機」なるものの作り方を軽く紹介いたします。

〇手っ取り早く、出来たものを紹介
一体どんなものができたのか、YouTube・ニコニコ動画に動画をUPしました。「全自動イライラ機」という名称は回路師さん製作の「全自動引きこもり機」にちなんで命名いたしました。

「『全自動イライラ機』製作して遊んでみた」(YouTube)


「『全自動イライラ機』製作して遊んでみた」(ニコニコ動画)


〇主に必要な部品・材料類
・1枚:Arduino Uno
・1枚:100mm×150mm×10mm 朴版画板
・1枚:100mm×60mm×3mm アルミ板
・4個:タカハ機工製ソレノイド CB08470140(14Ω) ・18本:抵抗 1kΩ
・4本:抵抗 4.7kΩ
・適宜:ピンヘッダ・ソケット
・適宜:長ピンヘッダ
・適宜:M3ネジ・ナット・ワッシャー類
・1個:9V・1A程度以上のACアダプター(ソレノイドを駆動するため、容量は大き目のものが良いです)

秋月で購入した物
・4個:【I-02414】 NchパワーMOSFET 2SK2232(60V25A)
・4個:【I-00126】 整流用ショットキーダイオード(100V1A)1S10
・2個:【I-08605】 8ビットシフトレジスタ SN74HC595N
・4個:【I-01318】 高輝度5mm赤色LED 7cd60度 (10個入)
・1個:【I-05347】 オプトサプライ10バーLEDアレイ 3色(緑5黄3赤2)タイプ
・1枚:【P-03230】 片面ガラスコンポジット・ユニバーサル基板Bタイプ(95x72mm)
・2個:【P-00029】 丸ピンICソケット (16P)
・4個:【P-00300】 基板用トグルスイッチ3P
・1個:【P-09624】 Arduino用ユニバーサル基板 ガラスコンポジット(赤)
・3個:【P-01310】 ターミナルブロック 3ピン(緑)(縦)
・1個:【C-09408】 2.1mm標準DCジャック(4A) ユニバーサル基板取付用

○電気回路図
"スイッチ押したらソレノイドが押したスイッチ以外のスイッチを押し返す"みたいな動きをさせますのでソレノイド駆動基板とLED・スイッチ基板は別々に作ります。


〇作った基板類
―LED・スイッチ基板―
スイッチを押しやすいようにピンヘッダ・ソケットを極力端に寄せるようにします。この基板はArduinoと信号のやり取りさせます。
赤色LEDはスイッチのON-OFFに合わせて点灯・消灯させます。電気回路的に点灯できるようにしてもいいと思いますが今回はLEDもArduino側で点灯できるようにしています。
10バーLEDアレイは全自動イライラ機の機嫌を表示させるのに使おうかなと考えて取り付けました。これはシフトレジスタを使用して点灯させます。


―ソレノイド駆動基板―
Arduinoに連結して使用します。Arduino基板と連結するために長ピンのピンヘッダ―が必要でしょう。


―ソレノイド取付板―
今回は3mm厚のアルミ板を使用しましたが、ソレノイドをしっかりと固定できるものなら何でもよいです。
大事なのは
「スイッチの間隔とぴったり合うようにソレノイドを取り付けること」
です。ちょっと精度のいい加工が必要になります。


ソレノイド取付板の穴あけ寸法はちょっと見づらいですが下図です。
寸法がやたらと細かい数字なのは、スイッチ側が2.54mmピッチの基板に取り付けられているので、それに合わせてソレノイドの位置を決めたらこうなりました。


〇組立て完了
組立てた最終形態はこのような感じになります。
朴版画板にLED・スイッチ基板とソレノイド取付板を取り付けます。朴版画板の穴あけ寸法は、 ソレノイド取付板とLED・スイッチ基板の現物を合わせてみて適当な位置に穴を開けてます。
まずはソレノイド取付板の位置を決めてから、LED・スイッチ基板の取り付け位置をソレノイドに合わせる、とやった方が良いでしょう。
大事なのは
「ソレノイドと、ソレノイド側に倒したスイッチの間隔が1mm程度になるようにすること」
です。精度の良い組立てが必要になります。


○Arduinoのプログラム
ここまで組立てが終わったらArduinoのプログラミングです。コードは以下の通りです。
挙動としては
・起動後、スイッチを全てソレノイド側に倒したらメインルーチンスタート
・"スイッチをソレノイド側に倒したら、ソレノイドが別のスイッチを押し倒す"というのがメインの動作
・スイッチをソレノイド側に倒したらLED消灯し、基板側に倒したらLED点灯
・スイッチを入り切りするとイライラ機の機嫌が悪化し、10バーLEDアレイが緑・黄色・赤と変化
・10バーLEDアレイが緑・黄色・赤と全自動イライラ機の反応速度も速く
・5秒ごとに全自動イライラ機の機嫌も1ずつ良くなる
というような感じで作っています。


#include <stdio.h>

//スイッチとLED用
byte LED_PIN_01=0;
byte LED_PIN_02=1;
byte LED_PIN_03=2;
byte LED_PIN_04=3;
byte Switch_PIN_01=4;
byte Switch_PIN_02=5;
byte Switch_PIN_03=6;
byte Switch_PIN_04=7;
byte SOL_PIN_01=10;
byte SOL_PIN_02=11;
byte SOL_PIN_03=12;
byte SOL_PIN_04=13;

int NowSwitch=-1;
byte SolenoidOn=0;
bool WaitFlag=false;
bool before_switch_01=false;
bool switch_01=false;
bool before_switch_02=false;
bool switch_02=false;
bool before_switch_03=false;
bool switch_03=false;
bool before_switch_04=false;
bool switch_04=false;

byte SwitchAry[4]={0};

//シフトレジスタ用ピン指定
byte RCK_PIN=14;
byte SCK_PIN=15;
byte SI_PIN=16;

//機嫌
int BeforeMood=0;
int Mood=0;

//時間カウント用
unsigned long OnStartTime;
unsigned long OffStartTime;
unsigned long MoodStartTime;

//関数宣言
void OpeningShiftRegister();//起動時のLEDバーの点灯パターン
void LightingShiftRegister(byte Pattern);//LEDバーを一本だけ点灯させる
void ShiftRegister();//Moodの値からLEDバーを点灯させる
void LEDInit();//LED初期化
void SwitchInit();//現在のスイッチの状態を変数に格納
void Switch();
void LED();
void Solenoid();
void AddMood(int num);

void setup()
{ 
  //スイッチ・LEDピン設定
  pinMode(LED_PIN_01,OUTPUT);
  pinMode(LED_PIN_02,OUTPUT);
  pinMode(LED_PIN_03,OUTPUT);
  pinMode(LED_PIN_04,OUTPUT);
  pinMode(Switch_PIN_01,INPUT);
  pinMode(Switch_PIN_02,INPUT);
  pinMode(Switch_PIN_03,INPUT);
  pinMode(Switch_PIN_04,INPUT);
  pinMode(SOL_PIN_01,OUTPUT);
  pinMode(SOL_PIN_02,OUTPUT);
  pinMode(SOL_PIN_03,OUTPUT);
  pinMode(SOL_PIN_04,OUTPUT);
  
  //シフトレジスタピン設定
  pinMode(RCK_PIN,OUTPUT);
  pinMode(SCK_PIN,OUTPUT);
  pinMode(SI_PIN,OUTPUT);

  //ソレノイドピン初期化
  digitalWrite(SOL_PIN_01,LOW);
  digitalWrite(SOL_PIN_02,LOW);
  digitalWrite(SOL_PIN_03,LOW);
  digitalWrite(SOL_PIN_04,LOW);

  //機嫌変数初期化
  Mood=0;
  
  //スイッチ初期状態読み取り
  SwitchInit();

  //LED初期動作
  LEDInit();

  //LEDバー初期化
  ShiftRegister();
  
  //シフトレジスタ―の最初の動き
  OpeningShiftRegister();
  
  while(1)
  {
    int judge=0;
    SwitchInit();
    LEDInit();
    for(int i=0;i<4;i++)
    {
      judge=judge+SwitchAry[i];
    }
    if(judge==0)
    {
      SolenoidOn=rand()%4;
      delay(500);
      break;
    }
    delay(50);
  }

  //時間初期化
  OnStartTime=millis();
  OffStartTime=millis();
  MoodStartTime=millis();
} 

void loop()    //メインルーチン
{
  BeforeMood=Mood;

  //スイッチ処理
  Switch();
  
  //LED点灯
  LED();

  //5秒間隔でLEDバーの点灯を一つずつを減らしていく
  if(millis()>=(MoodStartTime+5000))
  {
    if(Mood==0)
    {
      Mood=0;
    }else AddMood(-1);
    
    MoodStartTime=millis();
  }else if(MoodStartTime>millis())//millis()オーバーフロー用
  {
    MoodStartTime=millis();
  }

  //LEDバー動作
  if(BeforeMood!=Mood)
  {
    ShiftRegister();//シフトレジスタ処理は機嫌に変化があった時のみ
  }

  if(WaitFlag==true)
  {
    if(Mood<=5)
    {
      delay(1000);
      WaitFlag=false;
    }else if(Mood>5 && Mood<=8)
    {
      delay(500);
      WaitFlag=false;
    }
  }

  //ソレノイド動作
  Solenoid();
  delay(50);
}

/////////////////////////////////////////////
//自作関数定義ここから
/////////////////////////////////////////////
void Switch()
{
  before_switch_01=switch_01;
  before_switch_02=switch_02;
  before_switch_03=switch_03;
  before_switch_04=switch_04;
  
  if(digitalRead(Switch_PIN_01)==HIGH)
  {
    SwitchAry[0]=1;
    switch_01=true;
  }else
  {
    SwitchAry[0]=0;
    switch_01=false;
  }

  if(digitalRead(Switch_PIN_02)==HIGH)
  {
    SwitchAry[1]=1;
    switch_02=true;
  }else
  {
    SwitchAry[1]=0;
    switch_02=false;
  }

  if(digitalRead(Switch_PIN_03)==HIGH)
  {
    SwitchAry[2]=1;
    switch_03=true;
  }else
  {
    SwitchAry[2]=0;
    switch_03=false;
  }

  if(digitalRead(Switch_PIN_04)==HIGH)
  {
    SwitchAry[3]=1;
    switch_04=true;
  }else
  {
    SwitchAry[3]=0;
    switch_04=false;
  }

  bool trigger=false;
  if(switch_01==false && before_switch_01==true)
  {
    MoodStartTime=millis();
    AddMood(1);
    NowSwitch=0;
    trigger=true;
  }else if(switch_02==false && before_switch_02==true)
  {
    MoodStartTime=millis();
    AddMood(1);
    NowSwitch=1;
    trigger=true;
  }else if(switch_03==false && before_switch_03==true)
  {
    MoodStartTime=millis();
    AddMood(1);
    NowSwitch=2;
    trigger=true;
  }else if(switch_04==false && before_switch_04==true)
  {
    MoodStartTime=millis();
    AddMood(1);
    NowSwitch=3;
    trigger=true;
  }

  int judge_count=0;
  for(int i=0;i<4;i++)
  {
    judge_count=judge_count+SwitchAry[i];
  }
  
  if(judge_count<3 && trigger==true)
  {
    WaitFlag=true;
    int buf=0;
    while(1)
    {
      buf=rand()%4;
      if(buf!=NowSwitch && SwitchAry[buf]==0)
      {
        SolenoidOn=buf;
        break;
      }
    }
  }else if(judge_count>=3)
  {
    SolenoidOn=-1;
    NowSwitch=-1;
  }
}

void LED()
{
  if(digitalRead(Switch_PIN_01)==HIGH)
  {
    digitalWrite(LED_PIN_01,HIGH);
  }else digitalWrite(LED_PIN_01,LOW);

  if(digitalRead(Switch_PIN_02)==HIGH)
  {
    digitalWrite(LED_PIN_02,HIGH);
  }else digitalWrite(LED_PIN_02,LOW);

  if(digitalRead(Switch_PIN_03)==HIGH)
  {
    digitalWrite(LED_PIN_03,HIGH);
  }else digitalWrite(LED_PIN_03,LOW);

  if(digitalRead(Switch_PIN_04)==HIGH)
  {
    digitalWrite(LED_PIN_04,HIGH);
  }else digitalWrite(LED_PIN_04,LOW);
}

void Solenoid()
{
  switch(SolenoidOn)
  {
  case 0:
    if(digitalRead(Switch_PIN_01)==LOW)
    {
      digitalWrite(SOL_PIN_01,HIGH);
    }else digitalWrite(SOL_PIN_01,LOW);
    break;

  case 1:
    if(digitalRead(Switch_PIN_02)==LOW)
    {
      digitalWrite(SOL_PIN_02,HIGH);
    }else digitalWrite(SOL_PIN_02,LOW);
    break;

  case 2:
    if(digitalRead(Switch_PIN_03)==LOW)
    {
      digitalWrite(SOL_PIN_03,HIGH);
    }else digitalWrite(SOL_PIN_03,LOW);
    break;

  case 3:
    if(digitalRead(Switch_PIN_04)==LOW)
    {
      digitalWrite(SOL_PIN_04,HIGH);
    }else digitalWrite(SOL_PIN_04,LOW);
    break;

  default:
    break;
  }

  if(digitalRead(SOL_PIN_01)==HIGH && digitalRead(Switch_PIN_01)==HIGH) digitalWrite(SOL_PIN_01,LOW);
  if(digitalRead(SOL_PIN_02)==HIGH && digitalRead(Switch_PIN_02)==HIGH) digitalWrite(SOL_PIN_02,LOW);
  if(digitalRead(SOL_PIN_03)==HIGH && digitalRead(Switch_PIN_03)==HIGH) digitalWrite(SOL_PIN_03,LOW);
  if(digitalRead(SOL_PIN_04)==HIGH && digitalRead(Switch_PIN_04)==HIGH) digitalWrite(SOL_PIN_04,LOW);
}

void SwitchInit()
{
  if(digitalRead(Switch_PIN_01)==HIGH)
  {
    SwitchAry[0]=1;
  }else SwitchAry[0]=0;

  if(digitalRead(Switch_PIN_02)==HIGH)
  {
    SwitchAry[1]=1;
  }else SwitchAry[1]=0;

  if(digitalRead(Switch_PIN_03)==HIGH)
  {
    SwitchAry[2]=1;
  }else SwitchAry[2]=0;

  if(digitalRead(Switch_PIN_04)==HIGH)
  {
    SwitchAry[3]=1;
  }else SwitchAry[3]=0;
}
void LEDInit()
{
  if(digitalRead(Switch_PIN_01)==HIGH)
  {
    digitalWrite(LED_PIN_01,HIGH);
  }else digitalWrite(LED_PIN_01,LOW);

  if(digitalRead(Switch_PIN_02)==HIGH)
  {
    digitalWrite(LED_PIN_02,HIGH);
  }else digitalWrite(LED_PIN_02,LOW);

  if(digitalRead(Switch_PIN_03)==HIGH)
  {
    digitalWrite(LED_PIN_03,HIGH);
  }else digitalWrite(LED_PIN_03,LOW);

  if(digitalRead(Switch_PIN_04)==HIGH)
  {
    digitalWrite(LED_PIN_04,HIGH);
  }else digitalWrite(LED_PIN_04,LOW);
}

void OpeningShiftRegister()
{
  for(int j=0;j<3;j++)
  {
    for(int i=9;i>=0;i--)
    {
      LightingShiftRegister(i);
      if(i!=0) delay(50);
    }
    for(int i=0;i<10;i++)
    {
      LightingShiftRegister(i);
      if(i!=9) delay(50);
    }
  }
  Mood=10;
  ShiftRegister();
  delay(500);
  Mood=0;
  ShiftRegister();
}

void LightingShiftRegister(byte Pattern)
{
  int LED_bit[10]={};
  if(Pattern>9) Pattern=9;
  LED_bit[9-Pattern]=1;
  
  digitalWrite(SI_PIN,LOW);
  digitalWrite(SCK_PIN,LOW);
  digitalWrite(RCK_PIN,LOW);
 
  for(int i=0;i<10;i++)
  {
      if(LED_bit[i]>0)
      {
          digitalWrite(SI_PIN,HIGH);
      }
      else
      {
          digitalWrite(SI_PIN,LOW);
      }
      //データ順次ビット送り
      digitalWrite(SCK_PIN,LOW);
      digitalWrite(SCK_PIN,HIGH);
  }
  
  //LED出力
  digitalWrite(RCK_PIN,HIGH);
  digitalWrite(RCK_PIN,LOW);
  
  //初期化
  digitalWrite(SI_PIN,LOW);
  digitalWrite(SCK_PIN,LOW);
  digitalWrite(RCK_PIN,LOW);
}

void ShiftRegister()
{
  digitalWrite(SI_PIN,LOW);
  digitalWrite(SCK_PIN,LOW);
  digitalWrite(RCK_PIN,LOW);
 
  unsigned char buf=Mood;
  
  for(int i=0;i<10;i++)
  {
      if(buf>0)
      {
          digitalWrite(SI_PIN,HIGH);
          buf=buf-1;
      }
      else
      {
          digitalWrite(SI_PIN,LOW);
      }
      //データ順次ビット送り
      digitalWrite(SCK_PIN,LOW);
      digitalWrite(SCK_PIN,HIGH);
  }
  
  //LED出力
  digitalWrite(RCK_PIN,HIGH);
  digitalWrite(RCK_PIN,LOW);
  
  //初期化
  digitalWrite(SI_PIN,LOW);
  digitalWrite(SCK_PIN,LOW);
  digitalWrite(RCK_PIN,LOW);
}

void AddMood(int num)
{
  Mood=Mood+num;
  if(Mood>10)
  {
    Mood=10;
  }else if(Mood<0)
  {
    Mood=0;
  }
}

○まとめ
・スイッチをどこまでもパチパチできる、なんとなく手持ち無沙汰なときにもってこいなものができました。

・動画ではちょっとわからないですが、ソレノイドが動いたときの「カチン」という音が結構うるさいです。できれば一人の時に遊びましょう。

・今回は朴版画板とアルミ板を使いましたが、このあたりの材質を色々と変えると上記した「うるさい音」も上品な聴きごたえのある音になるのだろうか?とは思います。

・プロジェクトと名をつけるのも憚られる感じもしますが、実用できようができまいが"作ってみたいものを作る"という動機の元、即座に作り始められるのは個人開発の特権です。面白いと思うものを作ってみましょう。

2018/8/9(Thu) 記

(C)2018 Iseba's Labo