記事公開日

カード自動配り&シャッフラー装置

プレイする人数に合わせて、カードを自動で振り分ける装置を作りました。

スイッチをONするとテーブルが回転し、カードを一枚ずつ等間隔に排出します。

カード自動配りモード

また、[ランダム振り分けモード]に設定することで、ディールシャッフルのような混ぜ方をすることができます。

オートシャッフルモード(ランダム振り分けモード)

※ピカチュウの人形は、ローラーとカードを密着させるための重りです。

装置構成

この装置の肝は「確実にカード一枚を排出できるか?」にかかっています。

摩擦によってカードがくっついて2枚続けて排出されてしまったり、モーターに取り付けたローラーがカードをうまく噛んでくれずにカードが排出されないタイミングが一度でも起きてしまうと、カード配り装置として意味を成しません。

カードを一枚だけ排出

カードフィーダー部

カードフィーダー部には、上下2つのモーターを搭載しています。

上下2つのモーター
  • 下:ミニモーター標準ギヤボックス(8速)ギヤ比 ⇒ 8.5:1
  • 上:ミニモーター薄型ギアボックス(2速)ギヤ比 ⇒ 71.4:1

カードホルダーの下にあるモーターが、カードを前方に送り出します。

カード排出のタイミングになると、このモーターが回転し、カード一枚分の高さしかないゲートを通って、一枚だけが送り出されます。

カードを前方に送り出すモーター

確実にカードを送り出せたかどうかは光センサによって検知しています。

光センサの上にカードが覆いかぶさると、光センサが反応し、カード送りモーターはストップします。

カードを送り出せたかどうかは光センサによって検知

上側のモーターは、カードを完全に外に押し出すためのもので、常に回転しています。

このモーターがないと、下のモーターとゲートのところで送り出しが止まってしまいます。

カードを完全に外に押し出すためのモーター

カードの押し出しについては、下記の過去記事が参考になると思います↓

カード排出ユニット(カードガチャの機構)

回転テーブル部

回転するテーブル

カードを一枚排出すると、次のカードを排出する位置までテーブルが回転します。

シングルギヤボックス(4速タイプ)を[ギヤ比]344.2:1で使用しています。

配線図

カード自動配り&シャッフラー装置の配線図

テーブルを回転させるためのモーターは、結構な重量物を抱えているため、大きなトルクが必要です。

マイコンから供給する電流ではトルクが足りないので、外部電源が利用できるモータードライバーを使用し、単三電池2個をこのモーターだけの電源に使用しています。

モーターの動作はPWM制御を行っているので、Arduinoは「波線」が付いているピンを使用します。

光センサは、ボリュームで反応する光量を調整して「1」「0」の信号を出力できるモジュールを使用しています。

使用部品

プログラム

// 光センサ(CDS)からの信号を受け取るピン
int csdPin = 4;

// カード送りモーター
int motorShotPin1L = 5;
int motorShotPin1R = 6;

// カード排出モーター
int motorShotPin2L = 10;
int motorShotPin2R = 11;

// テーブル回転モーター
int motorShotPin3L = 3;
int motorShotPin3R = 9;

// モーター速度(0が停止・255が最大)
int motorSpeed = 255;

// テーブルの現在ポジション
int pos = 1;

// 次のポジション
int nextPos = 1;

// 回転する時間
int move = 0;

// 各モーターの回転開始タイミングを設定するためのフラグ
int flag = 0;

// モード変更(1:順番にカードを配るモード、2:ランダムにカードを配るシャッフルモード)
int mode = 1;

// カードを配る人数
int maxcard = 4;

// -------------------------------------------
//                   SETUP
// -------------------------------------------
void setup() {

  // シリアルデータの通信速度
  Serial.begin(9600);

  // 光センサ
  pinMode(csdPin, INPUT);

  // 各モーター
  pinMode(motorShotPin1L, OUTPUT);
  pinMode(motorShotPin1R, OUTPUT);
  pinMode(motorShotPin2L, OUTPUT);
  pinMode(motorShotPin2R, OUTPUT);
  pinMode(motorShotPin3L, OUTPUT);
  pinMode(motorShotPin3R, OUTPUT);

}

// -------------------------------------------
//                   LOOP
// -------------------------------------------
void loop() {

    // カード排出モーターをON
    analogWrite(motorShotPin2L, motorSpeed);
    analogWrite(motorShotPin2R, 0); 

  // 光センサが暗くなったとき
  if (digitalRead(csdPin)) {
    
      // テーブル回転モーターをRESET
      digitalWrite(motorShotPin3L, LOW);
      digitalWrite(motorShotPin3R, LOW);
      delay(300);

    // カード送りモーターをOFF
    analogWrite(motorShotPin1L, 0);
    analogWrite(motorShotPin1R, 0);
    //delay(300);

    // カードを送り出して光センサが暗を判定したタイミングでイベント開始
    flag = 1;

  // CDSが明るい状態のとき
  } else {

    // イベント開始フラグがONになっていたら
    if (flag) {

      // カード送りモーターをOFF
      analogWrite(motorShotPin1L, 0); 
      analogWrite(motorShotPin1R, 0);
      delay(300);

      // 順番にカードを配るモード
      if (mode == 1) {

        nextPos = nextPos + 1;

        if(nextPos > maxcard) {

          // テーブルを初期位置に戻す
          digitalWrite(motorShotPin3L, LOW);
          digitalWrite(motorShotPin3R, HIGH);
          delay(520);

          // テーブル回転モーターをRESET
          //digitalWrite(motorShotPin3L, LOW);
          //digitalWrite(motorShotPin3R, LOW);
          //delay(300);

          // テーブルポジションを初期値に戻す
          nextPos = 1;

        } else {
     
          // テーブルの移動時間を細かく指定可能
          switch (nextPos) {
            case 2:
              move = 180;
              break;
            case 3:
              move = 180;
              break;
            case 4:
              move = 180;
              break;
          }

          digitalWrite(motorShotPin3L, HIGH);
          digitalWrite(motorShotPin3R, LOW);
          delay(move);

        }

      // ランダムにカードを配るシャッフルモード)
      } else {

        while(1) {
          nextPos =  random(1,maxcard);
          if (nextPos != pos) {
            break;
          }
        }

        // 現在のポジションより大きいポジションまで回転するとき(差分を正転)
        if (nextPos > pos) {
          move = (nextPos - pos) * 180;
          digitalWrite(motorShotPin3L, HIGH);
          digitalWrite(motorShotPin3R, LOW);
          delay(move);
        }

        // 現在のポジションより小さいポジションまで回転するとき(差分を逆転)
        else if (nextPos < pos) {
          move = (pos - nextPos) * 180;
          digitalWrite(motorShotPin3L, LOW);
          digitalWrite(motorShotPin3R, HIGH);
          delay(move);
        }
      }

      Serial.print("nextPos: ");
      Serial.println(nextPos);
      Serial.print("pos: ");
      Serial.println(pos);
      Serial.println("");


      // 回転が終わったら現在のポジションとして設定
      pos = nextPos;

      // テーブル回転モーターをRESET
      digitalWrite(motorShotPin3L, LOW);
      digitalWrite(motorShotPin3R, LOW);
      delay(300);

      flag = 0;

    }

  }

  if (!flag) {
    
    // カード送りモーターをON
 
    analogWrite(motorShotPin1L, motorSpeed); 
    analogWrite(motorShotPin1R, 0);
    
  }
 
}

テーブルの回転に使用しているモーターは、DCモーターです。

カードを排出する位置までのテーブル回転は、時間(delay関数)で管理しています。

多少のズレは覚悟していましたが、思ったよりも正確にポジションを維持してくれます。

本来であれば、「ステッピングモーター」や「サーボモーター」を使うのが適切ですが、今回はできるだけタミヤの楽しい工作シリーズを使って作りたかったので・・・

この記事のURLをコピー

メールアドレスは公開されませんのでご安心ください。また、* が付いている欄は必須項目となります。

内容に問題なければ、下記の「コメントを送信する」ボタンを押してください。

関連情報

運営者プロフィール
コダマ

職業はIT系フリーランス。過去、電子配線業務の経験が10年ある為、はんだづけも得意です。宮崎県在住、30代・2児の父親。

プロが教える!イチからわかるハンダ付けのコツ(工学社)の著者です。

カテゴリー