| “ラムネマシーン” とは? |
今回製作するラムネマシーンとは、オリオン株式会社が製造販売する ミニシリーズ,クレヨンしんちゃんミニみっくすじゅうす を自動で1個ずつ払い出すおもちゃのことです。既に販売キットが比較的安価で購入できる様ですので、今更感もありますが、とりあえずやってみます。
今回、オリオンのラムネを選んだのは価格的にも、工作用のモーターで自動払い出しするサイズとしても手頃と思ったからです。また、円筒形状なので搬出する時に引っかかって止まる様なことも少ないと考えました。
※オリオンラムネのサイズ:直径約28mmX長さ約53mm

| “ラムネマシーン” |
いきなりですが、下の写真の様なものが出来ました。写真③④が全体です。ストッカー部に10個くらいのラムネを保管できます。プッシュスィッチを押すとラムネを1個づつ払い出し、トグルスィッチを入力すると対応する向きに回転し、連続的に払い出すことができます。
払い出しの仕組について説明します。飲料缶を回転させると飲料缶に開けた開口部がストッカー内のラムネの下に来た時にラムネは自重で開口部の中に落下します。ラムネは飲料缶の回転中心である回転軸に当たって止まり、飲料缶の開口部が下を向いた時にラムネは開口部から払い出されます。プッシュスィッチ入力で1個づつラムネを払い出す時は、飲料缶は払い出し後も回転を続け、ちょうど1回転して止まります。1回転したことはリードスィッチ入力によってわかります。リードスィッチは磁石に反応してスィッチが入力状態になるセンサーです。スチール製の飲料缶の底面に磁力でついているネオジム磁石が、飲料缶の回転によってリードスィッチ近くに再び戻ってくると飲料缶が1周したと判断することができます。尚、動力は写真の通りチェーンを使って伝達しています。飲料缶とスプロケットの固定は4本のスペーサーを使って固定しています。
制御装置は「ESPr DEVELOPERでモーターを動かす」の外部操作用接続配線にモーターをつなぎ変えて、飲料缶の回転を検出するリードスィッチを追加したものとなっています。

動きを動画で確認します。まず、プッシュスィッチ入力の1サイクル払い出しを数回行い、次に連続払い出しを行います。
| 主要部品 |
主な部品を紹介します。
| ◆主要部品◆ | ||
| 番号 | 名 前 | メーカー |
| 1 | シングルギアボックス(No167) | TAMIYA |
| 2 | ラダーチェーン&スプロケットセット(No142) | TAMIYA |
| 3 | スペーサーセット(P-01861) | 秋月電子 |
| 4 | リードスィッチ(P-03676) | 秋月電子 |
| 5 | 磁石(直径10mmX長さ10mm) | 不明 |
| 6 | 中心軸(ステンレス等棒,直径4~5mm) | ホームセンター |
| 7 | 飲料缶(ポッカサッポロ aromax等、170ml リシール缶 直径52.5mm程度) | 自販機 他 |
| 8 | その他は適当。ブックエンド,段プラ,お菓子の箱,金具など | 100均、 ホームセンター |
4.リードスィッチは安く、非接触で磁石と反応するので気に入ってます。ただ、ガラスなのでリードを曲げるときに割れてしまうことがありますので注意が必要です。
5.磁石はリードスィッチが反応すれば、ネオジム磁石でなくても大きさが違っても良いと思います。組み合わせで変わりますので、予め確認したり調整できる様にしておきます。また、今回磁力でスチール缶に固定していますが、磁力が弱いとズレたりするかもしれません。逆に今回は磁力が強かったので、リードスィッチを少し上の方に離して固定しています。
6.中心軸はステンレス等の丸棒をホームセンター等で購入し、金ノコ等で切断します。
7.飲料缶はポッカサッポロの170mlリシール缶が今回の目的には最適でした。ラムネが入る幅に開口部を開くと丁度ラムネが中心軸にあたって止まるので、払い出しの構造をある程度 簡単につくることが出来ます。
下の写真は開口部ですが、今回、両端を金ノコで切り、次に中央を切って、最後に折り曲げます。この折り曲げによって横のガタを少なくしていると思っています。
ついでに、リードスィッチが2つ右上についています。ネオジム磁石は缶の底面についていますので、すぐ近くではなく少し上の方に離れてついているのが判ると思います。
飲料缶の蓋とスプロケットに回転軸の穴と連結用のスペーサ固定穴を開けます。スプロケットにはもともと穴が開いていますので、この穴を利用して穴を大きくします。飲料缶の底面にも回転軸用の穴を開けます。
その他の構造については、てきとうにしていますので詳細の説明は省略します。
| プログラム |
先ず、I/Oエキスパンダー(MCP23017-E/SP)と各SW,LEDの接続状態です。
GPA6、7にそれぞれリードSWを追加しています。2個追加しているのは、どちらかがうまく動かない時もどちらかが動いていれば、通常の運転をするようにする為です。また、リードSWが入力時、LED4、5をそれぞれ点灯させて、入力状態を判るようにしました。
SW3のプッシュスィッチは、自動運転スィッチにしています。手動SWがいずれもオフ状態(LED3点灯)に入力すると自動運転(1サイクル払い出し)を開始し、自動運転中 LED6が点灯します。

それではプログラムについて簡単に説明します。
トグルスィッチによる手動運転の部分は「ESPR DEVELOPERでモータを動かす」で最終的に作成したプログラムと大きく変更はありません。今回、手動SWがいずれもオフ状態(LED3点灯)に自動運転SWを入力すると自動運転(1サイクル払い出し)を開始する様にしています。行番100~102で、停止状態から自動運転を開始する判定とLED6(自動運転中)の点灯の設定を行っています。次に行番121~140が自動運転全体で、自動運転をする場合、先ず行番123~126で正転方向に運転を開始します。次に行番128~133では運転開始時にリードSWの入力がある場合、一旦完全に入力がなくなるまで、この部分の処理を繰り返します。
リードSWの入力がなくなると、再びリードSWが入力されるまで運転を続けます。この部分の処理は行番135~140です。リードSWの入力を再び確認すると“drv_brake() ; ”関数を実行し、1サイクル払い出しを完了します。
#include <Wire.h>
// ★ IO-EXPANDER(MCP23017)定数・変数
#define DVC_MCP23017 0x20 // IO-EXPANDER_00 アドレス(外部端子設定)
uint8_t U_PA = 0 ; // I/O 読込変数
// 共通
uint8_t r_MODE ;
String DRV_STS = "" ;
String STS_BEF = "" ;
String ATO_STS = "" ;
int chk_cnt ;
// ◆ DRV8830 I2Cアドレス(モータ制御基板)
#define ADR_DVC 0x64 // I2Cデバイスアドレス(DRV8830)
#define CTR_ADR 0x00 // CONTROL_レジスタ
#define FLT_ADR 0x01 // FAULT___レジスタ
// ◆ 駆動制御
#define D_RDY 0x00 // スタンバイ
#define D_REV 0x01 // 逆転
#define D_STD 0x02 // 正転
#define D_BRK 0x03 // ブレーキ
// ◆ 電圧設定
byte SET_V[]={ 0x00 , 0x12 };
// ◆ 制御コマンド送信
void w_rg_v(byte reg , byte v_set , byte cont_d){
int reg_data = v_set << 2 | cont_d ;
wrt_reg( ADR_DVC , reg , reg_data);
}
// ★ 指定レジスタにデータ書き込み
void wrt_reg(byte dvc_adrs , uint8_t reg , uint8_t value) {
Wire.beginTransmission(dvc_adrs); // デバイス指定、通信開始
Wire.write((uint8_t)reg); // レジスタ指定
Wire.write((uint8_t)(value)); // データ書込
Wire.endTransmission(); // 送信完了
}
// ★ 指定レジスタからデータ読み出し
uint8_t read_reg(byte dvc_adrs , uint8_t reg) {
Wire.beginTransmission(dvc_adrs); // 送信処理開始
Wire.write(reg); // レジスタ指定
Wire.endTransmission(false); // 送信完了(コネクション維持)
Wire.requestFrom(dvc_adrs , 1); // 1byteデータに要求
if (! Wire.available()) return -1; // データ有無判定
return (Wire.read()); // 1byteデータ
}
// モータブレーキ(停止)
void drv_brake(){
w_rg_v(CTR_ADR , SET_V[ 0 ] , D_BRK);
DRV_STS = "";
STS_BEF = "" ;
ATO_STS = "" ;
delay(600);
}
// 起動後、初回処理
void setup() {
Wire.begin(12,14);
// スタンバイ
w_rg_v(CTR_ADR , SET_V[0] , D_RDY);
Serial.begin(115200);
Serial.println("STAND BY");
// DVC_MCP23017(DVCアドレス:0x20)
wrt_reg( DVC_MCP23017 , 0x00 , 0xFF ); // I/O-PortA 入力設定
wrt_reg( DVC_MCP23017 , 0x0C , 0xFF ); // I/O-PortA 入力プルアップ設定
wrt_reg( DVC_MCP23017 , 0x01 , 0x00 ); // I/O-PortB 出力設定
wrt_reg( DVC_MCP23017 , 0x13 , 0x00 ); // I/O-PortB 全OFF
delay(1000);
}
// 繰り返し処理
void loop() {
U_PA = read_reg( DVC_MCP23017 , 0x12 ); // デバイス・レジスタ指定しデータ読取
uint8_t P_PA = 255 - U_PA ; // 補数(High/Low反転処理)
// LED出力変数初期化
byte OUT_LED[]={ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
uint8_t LMT_SW1 = P_PA & 64 ; // リードSW1入力
uint8_t LMT_SW2 = P_PA & 128 ; // リードSW2入力
if (LMT_SW1 == 64){ OUT_LED[3]=8 ; } // LED出力設定(リードSW1)
if (LMT_SW2 == 128){OUT_LED[4]=16; } // LED出力設定(リードSW2)
if ((P_PA & 1 ) == 1 ){ OUT_LED[0] = 1 ;
r_MODE = D_STD ; DRV_STS = "STD" ; // トグルSW1入力(正転)
}else if ((P_PA & 2 ) == 2 ){ OUT_LED[1] = 2 ;
r_MODE = D_REV ; DRV_STS = "RVS" ; // トグルSW2入力(逆転)
}else if ((P_PA & 4 ) == 4 || DRV_STS == "ATO"){
OUT_LED[5] = 32; // 自動運転LED出力(自動処理終了まで継続)
r_MODE = D_STD ; DRV_STS = "ATO" ; // トグルSW未入力時、押しボタンSW入力
} else { OUT_LED[2] = 4 ;
r_MODE = D_BRK ; DRV_STS = "" ; // トグルSW未入力(停止)
}
byte L_OUT_ALL=OUT_LED[0]+OUT_LED[1]+OUT_LED[2]+OUT_LED[3]+OUT_LED[4]+OUT_LED[5]+OUT_LED[6];
wrt_reg( DVC_MCP23017 , 0x13 , L_OUT_ALL ); // DVC00 I/O-PortB 出力設定(LED点灯)
// 運転モード設定によるモータ駆動
if (r_MODE != D_BRK && DRV_STS != "ATO"){
// トグルSWによる手動モータ駆動
if(STS_BEF==""){
w_rg_v(CTR_ADR , SET_V[1] , r_MODE);
STS_BEF = DRV_STS ;
} else if (DRV_STS != STS_BEF) {
drv_brake() ; // ブレーキ
}
} else if (r_MODE != D_BRK && DRV_STS == "ATO"){
// 自動運転(手動SW入力、又は自動運転完了まで継続駆動)
if (ATO_STS == ""){
w_rg_v(CTR_ADR , SET_V[1] , r_MODE);
ATO_STS = "STARTED" ; chk_cnt = 0 ;
}
if ((ATO_STS == "STARTED") && (LMT_SW1 != 64) && (LMT_SW2 != 128)){
chk_cnt = chk_cnt + 1 ;
if (chk_cnt > 3) {
ATO_STS = "CHK_LMT_SW" ; chk_cnt = 0 ;
}
}
if ((ATO_STS == "CHK_LMT_SW") && ((LMT_SW1 == 64) || (LMT_SW2 == 128))){
chk_cnt = chk_cnt + 1 ;
if (chk_cnt > 3) {
drv_brake() ; // ブレーキ
}
}
} else {
// ブレーキ
if(STS_BEF != ""){
drv_brake() ; // ブレーキ
}
}
delay(100);
}
| まとめ |
ESPr DEVELOPERからモーターを動かし、ちょっとしたおもちゃ(ラムネマシーン)を作ってみました。ただ、これはまだIoTとは言えません。次回はこのラムネマシーンのIoT化について検討してみたいと思います。