はじめに
みなさんこんにちは.初投稿です.
これは,第8回ソレノイドコンテストに応募した作品の解説記事になります.
ソレノイドコンテスト概要,結果については主催しているタカハソレノイドさんのHPをご覧ください.
残念ながら受賞することはできなかったのですが,ここで解説記事を書くことで供養したいと思います.
また,[自分の作品]も含めて紹介動画がyoutubeにアップロードされているので是非ご覧ください.
素晴らしい作品が目白押しです.
これが自分の作品です.
応募期限の前日に動画を撮影し始めたり,当日に動画編集を始めたり,期限の6時間前に動画の長さに制限があることを知るなど,てんやわんやでしたが,なんとか間に合いました.
(もうちょっとこだわりたいポイントがあったので悔しさもあったりなかったり.
準備するって大切ですねー)
動画をご覧いただいたうえで記事を読んでくださると,仕組みやテーマなど理解していただきやすいかと思います.宜しくお願い致します.
ジョーネツストライクとは
ジョーネツストライクとは,『アナタのオモイをトドけるキカイ』 をテーマとした作品です.
誰かに想いを伝えたいとき,合格発表などなかなか見るのに勇気がいるとき,ガチャで絶対に引きたいものがあるとき,とにかく神だのみしたいとき...そんなときありますよね?(あるある~)
ソシャゲでガチャを引くときに,キャラ名とか(例えば『えるたそ~』とか)叫びながらタップすると当たりそうな気がする,そんな感じです.
(物欲センサの塊)
そんなとき,この作品が使えます!!
あなたのジョーネツに反応し,スマホ画面をタップしたり,PCのキーボードを押してくれるのです!
賢いぞ.
それだけではなく,この作品だけのジョーネツインジケータ,ジョーネツダイアルを備えています.
インジケータはジョーネツレベルを可視化し、ダイアルによりそのレベルを調整できるのです.
(ちょっとのジョーネツならレベルを低く,猛烈なジョーネツならレベルを最大値にする...といった利用方法)
作品コンセプトについてはこれくらいにして,次からはタップの仕組みやハードウェア,回路,プログラムについて説明していきます.
(動作の様子などは最初に載せたものをご覧ください~)
ハードウェアについて
こだわりポイントその1,外観デザイン.
モデリングをAutodesk Fusion360で行い,出力は3dプリンタのFlashforge Adventurer3で行っています.
お手軽で使いやすく,いつもお世話になっています.
足向けて寝れない.
特に,モデリングでは近未来感,メカチックな雰囲気を意識しました.
(その中にも,流線的な要素も含めてメリハリつけたり)
さらに,お手頃に持ち運べるためにできるだけコンパクトなモデルに仕上げています.
もしデータが欲しい方はコメントまで宜しくお願い致します.
これまでFusion360で遊んで学んだモデリング技術が生かすことができたかなぁ.
こだわりポイントその2,タップ機構
内部はこんな感じになっています.
タッチペン部分をプッシュするためには,SSBH-0830という5Vで動作するソレノイドを使っています.
5Vでいいのですんごい楽です.600mAくらいで駆動するので電源も一般的なUSBアダプタで供給できる.
次に,ペン先について説明します.
先端には100円均一で買ってきたスマホ用タッチペンの先端を流用して使っています.
(導電性繊維タイプ)
ここでちょっとスマホ画面の話.
スマホは,画面から電荷が指へ移動することにより反応します.スマホタッチパネルの仕組み
タッチペンの場合は,ペンから握ってる手を通ってアースまで流れていくことになります.
ということは?
今回みたいな省スペースでタッチ機能を追加しようと思うと,繊維部分からアースまで落とすような仕組みがあればよいということになります.
作品中では,下図のようにペン先アタッチメントの中に電線を通し,皮膜を向いた先端を繊維と接触させています.
そして,この電線の逆側は電源供給のためのMicroUSBのGNDに繋がっています.
案外これでいけました.
今回の作品で一番試行錯誤した部分かも.
こだわりポイントその3,LED部分
動画を見ていただくとわかりやすいのですが,LEDの筒をむき出しにするのではなくて,3Dプリントする際に薄いPLAの壁を通して,光を漏らすようにしています.
そのおかげで,ぼや~っとした光り方を実現できました.
まぁ,Twitterでちらっとみたアイデアを参考にしただけですけど.
回路について
回路構成は次の通り.
ここでA0は制御に使用しているArduino nanoのアナログ0番ピンを指します.
こちらのサイトを参考にさせていただきました.
コンデンサマイクKUC2123の出力をオペアンプLM358Nで二段階かけて増幅しています.
増幅方法は非反転増幅になります.
また,300Ωの下にある半固定抵抗がハードウェア編で説明したジョーネツダイアルの部分です.
(ボリューム抵抗は0 ~ 5kΩまで変動するものを使用.)
これにより,60 ~ 90dBの音をマイクで拾ったときにA0へ4.5V位を出力することができ,音の大きさによる反応のしきい値をコントロールできます.
ソレノイドの制御については,使用しているソレノイドの仕様上,付属回路の入力端子に5Vを突っ込めば動くので回路図は省略させていただきます.
余談ですが,今回コンテストに参加して恐ろしく計画性のないスケジュールだったわけですが,ある程度回路が構成されているようなハードウェア製品のありがたみを感じました.
単純に開発期間に余裕が生まれるし,動かなかった時の罪悪感,燃やしてしまった時の悲しさがありません.精神衛生上非常によろしい.
プログラムについて
プログラムについて説明する前に,コンデンサマイクから出力される波形を簡単に説明します.
大声を出してるときの波形をオシロで見ると下図の様になるのですが,特徴としてはスパイクノイズの様な幅がとても短い波形になるということです.
実験する前は声を出している間はず~っとハイレベルの波形が出るかと思っていました.困った.
ちなみに波形間隔は10msとかそんくらいなもんです.
つまり,マイコンの周期によってはうまく読めない場合もありえるかもしれない...そんなことを踏まえてアルゴリズムを考えてみました.
(見づらくてすいません...)
流れに沿って説明します.それぞれの番号はStep数です.
-
しきい値を超えるとOK,Step2へ移行.このときに時間を測定してTimer2という変数へ格納
-
次にいつしきい値を超えるかを判定.また,初めに超えた時間 (= Timer2)から少し経った後かつ一定時間内までに超えた場合にStep3へ移行.
ここの処理が地味に大切になります.(プログラムではif (timer2 + 500 <= millis() <= timer2 + 1000)というところに該当)
ここで少しったった後,つまりTimer2 + millis()をしないと,短い間での大きな音,つまり物音とかにも反応してしまうことになります.
なので,人間の声でジョーネツを伝えることを前提に,ここでは少し時間にオフセットを設けています.
逆に,timer2 + 1000以内,とすることでスパイクノイズだったりの想定しない出力による誤動作を防ぐ狙いがあります.
- ここではソレノイドの駆動のための処理を行っています.今まではしきい値を超えたときに~ということを考えていましたがここではある一定期間しきい値を超えなかった場合,を考えます.
つまり,声を出し終わった後,ということになります.
声を出している間(しきい値を超えた場合)はTimer3を更新し続け,しきい値を超えなかった場合,かつTimer3 + 1000msの条件を満たしたときにソレノイドを駆動します.
以上のアルゴリズムでジョーネツストライクは構築されており(あとはインジケータの制御部),マイコンにはみんな大好きArduino nanoを使っています.
安くて使いやすい,いい子ですね.
CADも3Dプリンタもですけど,長い物に巻かれる人間なのでこういう使いやすくて情報があふれてるものばっかり使っちゃいますね~.
以下,Arduinoのプログラムです.
作った時はこんな解説記事を書く気はなかったんですけど,ちゃんと関数使ってまともそうなプログラムにしておいてよかったデス.
公開できる最低レベルくらいはあって欲しい(コメントなくてすいません)
ジョーネツストライクPG
#define solenoid_switch 6
#define device_state_LED 8
#define LED_1 9
#define LED_2 10
#define LED_3 11
#define LED_4 12
#define led_on_time 100
#define push_time 200
#define analogPin 0;
double val = 0;
double convert_num = 1024;
boolean step_flag = 0;
double timer2 = 0;
double timer3 = 0;
int step_num = 1;
int LED_array[4] = {LED_1, LED_2, LED_3, LED_4};
void setup() {
pinMode(solenoid_switch, OUTPUT);
pinMode(device_state_LED, OUTPUT);
pinMode(LED_1, OUTPUT);
pinMode(LED_2, OUTPUT);
pinMode(LED_3, OUTPUT);
pinMode(LED_4, OUTPUT);
digitalWrite(device_state_LED, HIGH);
}
void loop() {
val = analogRead(analogPin);
Serial.println(val);
step_flag = voice_check(val);
switch (step_num) {
case 1:
if (step_flag == 1) {
step_num++;
timer2 = millis();
}
break;
case 2:
if (timer2 + 500 <= millis() <= timer2 + 1000) {
if (step_flag == 1) {
step_num++;
timer3 = millis();
}
}
else if (millis() >= timer2 + 1000) {
step_num = 1;
}
break;
case 3:
if (step_flag == 1) {
timer3 = millis();
} else {
if (millis() > timer3 + 1000) {
solenoid();
step_num = 1;
}
}
break;
}
delay(20);
}
void LED_pattern(int num) {
for (int i = 0; i < 4; i++) {
if (i <= num - 1) {
digitalWrite(LED_array[i], HIGH);
} else {
digitalWrite(LED_array[i], LOW);
}
}
}
void solenoid() {
LED_pattern(0);
delay(500);
digitalWrite(solenoid_switch, HIGH);
delay(push_time);
digitalWrite(solenoid_switch, LOW);
delay(1000);
}
boolean voice_check(double val) {
boolean flag = 0;
if (val >= convert_num * 0.6) {
LED_pattern(4);
delay(led_on_time);
flag = 1;
} else if (val >= convert_num * 0.5) {
LED_pattern(3);
delay(led_on_time);
} else if (val >= convert_num * 0.4) {
LED_pattern(2);
delay(led_on_time);
} else if (val >= convert_num * 0.3) {
LED_pattern(1);
delay(led_on_time);
} else {
LED_pattern(0);
}
return flag;
}
最後に
これでこの解説(?)記事は以上になります.
いやはや,まさか記事を書くなんて思ってなかったし,やったこともなかったのでちゃんと皆さんの参考になるかとても不安です.
わからない,こうしたほうがええよ、って点がありましたらご教授いただけると大変助かります.
来年もソレコンに応募できたらいいなぁ.
...さて,就活してきますか
-
chaoscomb
さんが
2021/02/28
に
編集
をしました。
(メッセージ: 初版)
ログインしてコメントを投稿する