site﻿メニューとウィジェットLanguage:日本語English文系人間ですが、Arduinoを使った電子工作に関することをメインにアップしていきます。参考にして頂けるのは嬉しいですが、あくまで自己責任で行ってください。twitterアカウント取得しました。サイトの更新情報がフィードされます。@jumbleat_com検索でヒットする“@jumbleat”は一切関係ありません。2019-01-16RSSメールで通知メール登録でサイトの更新情報が届きます。info@jumbleat.comにご連絡ください。]analogRead関数を使う標準的な回避1.読み取り間隔を伸ばす2.分解能を下げる3.平均値化するちょっとずつ更新するanalogRead関数を使うArduinoでは可変抵抗器、いわゆるボリュームつまみを簡単に読み取ることが出来ます。上記のようにArduinoUnoを配線し、スケッチを書きます。改行シリアルプリント}これだけでつまみの値がIDEのシリアルモニタへ表示できるようになります。5voltが可変抵抗器で分圧された電圧になり、それをA0ピンで読み取ることで値を得ているわけです。この値を特定の値に計算、変換してやることでボリュームがコントローラーとしての役割できるようになります。モータのスピードを変えたりとか。この値、何もしてなくても微妙に動いてます。これは多分アナログゆえの問題です。5voltっていうのは「ほぼ5volt」ってことなんですよね。例えれば、流しそうめんの水量を500mlキッカリで流し続けたとしても、全ての水面が同じ高さにはならない、ってのと同じことだと(と、僕は理解しています)大まかでいいならこれでもどうにかなりそうですが、これで反応よく操作できるコントローラーを作りたいって言うと難ありです。この問題、やっぱり基本的な話らしく、調べるとweb上では打開策が色々書かれています。その解決方法は大体3つに絞られます。読み取り間隔を伸ばす分解能を下げる平均値化する結論から言うと、これ以外にオススメの方法があるのですが、1個ずつ検証しながらどういうことか説明していきたいと思います。標準的な回避1.読み取り間隔を伸ばす最初のスケッチだと、「A0ピンを読んでシリアル出力する」というのをひたすらloopしてるので、細かいゆらぎも拾ってしまいます。「ひたすら」ってのは普通の感覚ではありません。命令文の実行速度はマイクロセコンド(1/1000秒の更に1/1000秒)単位です。その読み取る間隔を伸ばしてやれば、グラグラも気にならなくなるんじゃないかっていう話です。簡単な話、delay(一時停止)を挟みます。1000ms(1秒)待つ}12行目に1秒delay関数入れました。これで読み込みの処理は1秒おきになります。動作自体を止めてしまうので、その間何もできません。他にさせたい処理も遅らせてしまいます。反応は芳しくありません。そこで時間を測るmillis()関数を利用してもう少し実用的な方法を考えます。time_readに読み取りとした現在時間を代入}}現在時間(millis())から前回読み取りした時間(time_read)を引けば、どれだけ時間が経過したかが分かります。12行目のif文でその差が1000ミリ秒を超えていたら、読み取り作業をするように仕向けます。その作業が完了した時間をまたtime_read変数に代入します。するとLoopする中で、一定時間超えると動作するタイマー的な仕組みができます。この方法結構勝手がいいので、覚えておくといいかもしれません。この方法では結局ゆらぎがなくなるわけじゃありません。2.分解能を下げるArduinoUnoではanalogReadは10bitで1024段階の変化を区別できます、値0を含むので表示では0-1023ですが。分解能を下げるってのは、要は値を割って端数をはしょっちゃえって話です。改行シリアルプリント}この場合、一旦読み取った値を10で割って1の位の変化を切り捨てます。その後10倍して一応、前と同じ桁数に戻します。ゆらぎが1の位で収まっていれば、きれいに取り除かれます。この場合、一度10分の1にしているので、分解能自体は102段階に落ちてしまします。この範囲でも事足りるならこれでもアリですが、analogWrite出力などで扱うPWMは256段階だったりするので足りません。値を4倍して元の桁数と同じにするやはりちょっと不安定です。3.平均値化する例えばテストの平均点を取るにはクラス全員の点数を足して人数分で割ります。何回か読み取りして、その合計点を回数分で割ります。「繰り返し読んで足す」ためにFor文を使います。+=~」ってのは変数vol_valの今の値に付け足すって意味なので気をつけてください。analogRead(A0);」はvol_valの中身をまるっと差し替えているって事です。してみると結構安定して見えてるのですが、少しおぼつかない時があります。以上3種類の方法を試してきましたが、web上で解説されているさまざまな解決方法はだいたいこれらを1つ、或いは複数を組み合わせる方法を使っています。これだと分解能を落とすか、反応を鈍らせるかの犠牲があって、今ひとつ歯がゆい感じです。ないものねだたりのわがままですが、もっといい方法はないのかと探しまくったら、こういう方法を提案しているところがありました。それが、ちょっとずつ更新するこの方法は理系の友人に言わせると「ローパス処理」ということなんですが、文系の僕にはこれがローパスフィルタを指し示す計算式なのか分かりません。やり方は超シンプルです。改行シリアルプリント}これだけ。前回のvol_valの値9割と、そこへ新しく読み取ったA0ピンの値1割を足し、100%にした値をvol_valに代入します。C言語では整数の変数には小数点は入らないですけど、数字にピリオドを打つと、その計算だけは小数点以下までしてくれるそうです。?かなり安定して読み取れていると思います。分解能は少し下がってフルビット分の値が出てくれません(小数点以下の端数の影響だと思います)。それでも1000以上の分解能があるので、扱うには充分です。更新している訳なので、繰り返しの回数が多いほうが反応がよくなるということことに注意してください。delayを使ったりしてloop全体のインターバルが遅くなると意味がありません。他の命令文に対しても工夫が必要になってくると思います。最後に、これに対して「平均値化」も付け足したスケッチを残しておきます。