前回、Arduino UNOを使い可変抵抗器からのアナログ値の読み取りをやってみました。
Arduino UNOのアナログ入力端子には10ビット分解能のADC(アナログーデジタルコンバーター)が内臓されており、入力端子の電圧0~5Vを0~1023の数値として読み込む事が出来るのが分かりました。
今回これを使い2軸アナログジョイスティックからの数値を読み取ってみたいと思います。
目次
アナログジョイスティックからの入力値を読み取る!
今回の目標
前回の応用、そしてこれまでの復習としてアナログジョイスティックからの入力値を読み取りLED点灯制御に使ってみたいと思います。
前回、可変抵抗器からのアナログ値の読み取りをやってみました。
今回使う2軸アナログジョイスティックはX軸方向とY軸方向で2つの可変抵抗器が内蔵されており、個別でそれぞれの値を読み取る事で制御が可能となります。
前回の応用&これまでの復習的な内容となります。
またジョイスティックにはセンタークリック機能があり押し込み判定が出来るものを今回使っています。
こちらもこれまでやってきたデジタル入力を使えば判定は簡単です。
ジョイスティックを使った制御が出来るようになるとサーボモーターを使ったロボット?みたいなものを動かしたりと、これからいろいろと使えそうです。
またプレステのコントローラーにあるアナログパッドを使ってBluetoothで動かす、なんて事も出来そうです。
サーボモーターの制御に関してはまだこちらで詳しくご紹介していないので、触り程度で紹介し、ジョイスティックからのアナログ値を取得し今回はPWMでLEDの明るさ制御する事をメインでやっていきたいと思います。
これまでのアナログ入力・デジタル入力の復習的な内容となりますが、それぞれ理解が深まればと思います。
アナログジョイスティックとは?
今回こちらのよく見かける安価な2軸タイプのアナログジョイスティックを使ってみます。
X軸方向・Y軸方向のアナログ値の読み取りに加え、センタークリック機能によりスティックを押し込むことによるON/OFF判定も出来るようになっています。
Arduinoのスターターキットにも同封されているものです。(後ほどご紹介)
内部構造は簡単で、X軸方向(横)とY軸方向(縦)にそれぞれ可変抵抗器が使われていてスティックにはプッシュスイッチも内蔵されています。
前回、可変抵抗器のアナログ値の取得をやってみました。
基本的にやり方は同じです。
先述のように2つの可変抵抗器が内蔵されているだけなので個別でそれぞれのアナログ値をアナログ入力端子から取得するだけです。
また押し込む事によりON/OFFの判定も出来ますが、これはデジタル入力端子から取得できます。
ただ単純な接点の短絡&開放のスイッチのため、接点が開放(OFFの時)の時に端子が浮いた状態(何も繋がれていない状態)となるので、動作を安定させるため入力側に何かしら電圧がかかりON/OFF判定出来るようにプルアップさせてあげる必要があります。
プルアップ・プルダウンについても以前ご紹介しました。
このあたりも踏まえ、これまでの復習として理解が深まればと思います。
そしてジョイスティックの接続は以下の5本の端子を接続します。
それぞれ、Vcc(+5V)・GND・VRx・VRy・SW端子となっています。
接続ピン | 詳細 |
GND | ArduinoのGNDに接続 |
+5V | Arduinoの5V出力端子に接続 |
VRx | X軸方向の読み取り(アナログピン) |
VRy | Y軸方向の読み取り(アナログピン) |
SW | センタークリックON/OFF(デジタルピン) |
※こちらのジョイスティックにはX軸方向・Y軸方向の検知に10kΩの可変抵抗器が使われています。
ジョイスティックの動作原理
今回使うアナログジョイスティックにはX軸方向・Y軸方向検知用に10kΩの可変抵抗器が使われています。
そして何も押されていない状態では自動的にセンターポジションに戻る構造となっています。
スティックを倒すことにより内部の可変抵抗器の抵抗値が変化してその抵抗の分圧によりアナログ入力端子に0~5Vの電圧値が入力されます。
その電圧値をArduinoのAD変換(アナログーデジタルコンバーター)機能により0~1023のデジタル値に変換され入力値となります。
その電圧をanalogRead関数を使いデジタル値(0~1023)に変換して読み取るということです。
そしてセンターポジションではX軸方向・Y軸方向のアナログ値はおおよそ0~1023の真ん中の512が読み取られるということです。
しかし実際には可変抵抗器の精度により取得できるアナログ値はそれより少しズレた値となるようです。
また、数値も前後少しずつ変化し揺らぎみたいなものも発生するようです。
このあたり実際に使う時に少し補正してあげる必要がありそうです。
そしてセンタークリック機能は単純なON/OFFのプッシュスイッチと同じで、その判定にはdigitalRead関数が使われます。
その際にスイッチが押されていない状態(宙に浮いた状態)ではデジタル入力の場合動作が不安定となるため、押されていない状態では常にHIGHが入力されるようにプルアップさせる必要があり、押した状態でLOWとなるようにGNDに接続する形となります。
プルアップさせるのでON/OFFが反転している点がポイントですね。
スティック | 状態(digitalRead関数で読み取った値) |
押されていない状態 | HIGHを検出 |
押した状態 | LOWを検出 |
それでは実際に回路を組んで試してみましょう。
ジョイスティックから取得した入力値をシリアルモニタで確認
まずはジョイスティックから取得したX軸方向・Y軸方向のアナログ値とプッシュスイッチの状態を取得しシリアルモニタで確認してみたいと思います。
X軸方向・Y軸方向の読み取りはアナログ入力ピンを使い、プッシュスイッチはデジタル入出力ピンを使って状態を読み取ります。
5V・GNDをArduino UNOから取り、VRx・VRyをアナログ入力ピンに接続(今回VRxをA0、VRyをA1に接続しました)、SWをデジタル入出力ピン(今回D2ピンを使いました)に接続します。
プッシュスイッチが押されていない状態(浮いた状態)を防ぐため、pinMode関数でD2ピンをプルアップして常にHIGH状態、そして押された状態ではGNDに繋がるようになっています。
プルアップ・プルダウンに関してはこちらを参考にしてみて下さい。
接続はこのようになります。
簡単ですね!
今回使ったジョイスティックとは下記回路図とピン配列が少し違いますが対応した箇所に接続して下さい!
VRx(ジョイスティック) → A0(Arduino)
VRy(ジョイスティック) → A1(Arduino)
SW(ジョイスティック) → D2(Arduino)
そしてスケッチはこちらを使用します。
前回のアナログ入力について理解出来ていれば簡単です。
アナログ入力に関してはこちらを参考にして下さい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | // Arduino入門編⑦ ジョイスティックからの入力値を読み取る // https://burariweb.info const int X_PIN = A0; // X軸方向の入力をアナログピンA0に const int Y_PIN = A1; // Y軸方向の入力をアナログピンA1に const int SW_PIN = 2; // センタースイッチの入力をデジタルピンD2に int X_POS ; // X軸方向の読み取り値の変数を整数型に int Y_POS ; // Y軸方向の読み取り値の変数を整数型に int SW_POS ; // センタースイッチの読み取り値の変数を整数型に void setup(){ pinMode(X_PIN, INPUT); // A0ピンを入力に(省略可) pinMode(Y_PIN, INPUT); // A1ピンを入力に(省略可) pinMode(SW_PIN, INPUT_PULLUP); // D2ピンをプルアップして入力に Serial.begin(9600); // シリアル通信の開始 } void loop(){ X_POS = analogRead(X_PIN); // X軸方向のアナログ値を読み取る Y_POS = analogRead(Y_PIN); // Y軸方向のアナログ値を読み取る SW_POS = digitalRead(SW_PIN); // センタースイッチの状態を読み取る Serial.print("X: "); // シリアルモニタにそれぞれの値を出力 Serial.print(X_POS); Serial.print(" Y: "); Serial.print(Y_POS); Serial.print(" SW: "); Serial.println(SW_POS); delay(100); } |
シリアルモニタを立ち上げるとこのようにジョイスティックから取得したX軸方向・Y軸方向のアナログ値、そしてプッシュスイッチの状態が表示されます。
ジョイスティックは何も押されていない状態ではセンターに戻る仕様なので先述したように本来アナログ入力値(0~1023)のちょうど真ん中の512くらいになるはずですが・・・少しバラツキがありますね!
そしてスティックをX軸方向・Y軸方向に動かしてみると、それぞれ最小0〜最大1023の範囲におさまっている事が確認できます。
また押し込みスイッチはプルアップされて接続しているので押されていない状態ではHIGH(1)、押されるとLOW(0)となる事も確認できます。
これらが確認&理解出来れば今回の目標は達成です。
簡単でしたね!
ここからこの入力された値を使いサーボモーターなどを動かしてみると視覚的に分かりやすいのですが、サーボモーターの制御に関してはまだ詳しくご紹介していないので後日詳しく出来ればと思います。
これまでやってきた事で分かりやすいのはLEDの点灯でしょうか?
アナログ値の取得が出来たので、ジョイスティックを動かし上下左右に対応したLEDの明るさを制御してみたいと思います。
ジョイスティックを使いLEDの点灯強度を制御する
ジョイスティックで取得した入力値を視覚化するため簡単な回路を組んでみました。
スティックを倒す向きと強さに応じて対応したLEDの明るさが変化し、プッシュスイッチが押されると真ん中の青色LEDが点灯するイメージです。(LEDの電流制限抵抗は今回150Ωのものを使っています)
LEDをそれぞれの出力ピンに繋いだだけの単純な回路となりますが、少し配線が面倒ですね!
スティックを倒す向きと強度によりその方向のLEDの点灯する明るさが変化します。
先程のスケッチに追加してこんな感じで書いてみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | // Arduino入門編⑦ ジョイスティックでLEDの点灯強度を制御 // https://burariweb.info const int X_PIN = A0; // X軸方向の入力をアナログピンA0に const int Y_PIN = A1; // Y軸方向の入力をアナログピンA1に const int SW_PIN = 2; // センタースイッチの入力をデジタルピンD2に const int Xmin_LED = 3; // 左LEDをデジタルピン3に const int Xmax_LED = 5; // 右LEDをデジタルピン5に const int Ymin_LED = 9; // 下LEDをデジタルピン9に const int Ymax_LED = 10; // 上LEDをデジタルピン10に const int SW_LED = 12; // スイッチ判定LEDをデジタルピン12に int X_POS ; // X軸方向の読み取り値の変数を整数型に int Y_POS ; // Y軸方向の読み取り値の変数を整数型に int SW_POS ; // センタースイッチの読み取り値の変数を整数型に float OFFSET = 0.05 ; // センター付近のオフセット値を5%に設定 int DUTY ; // ディーティ比用変数 void setup(){ pinMode(X_PIN, INPUT); // A0ピンを入力に(省略可) pinMode(Y_PIN, INPUT); // A1ピンを入力に(省略可) pinMode(SW_PIN, INPUT_PULLUP); // D2ピンをプルアップして入力に pinMode(Xmin_LED, OUTPUT) ; // pinMode(Xmax_LED, OUTPUT) ; // それぞれのピンを出力に設定 pinMode(Ymin_LED, OUTPUT) ; // pinMode(Ymin_LED, OUTPUT) ; // pinMode(SW_LED, OUTPUT); // D12ピンを出力に Serial.begin(9600); // シリアル通信の開始 } void loop(){ X_POS = analogRead(X_PIN); // X軸方向のアナログ値を読み取る Y_POS = analogRead(Y_PIN); // Y軸方向のアナログ値を読み取る SW_POS = digitalRead(SW_PIN); // センタースイッチの状態を読み取る if(SW_POS == 0){ digitalWrite(SW_LED, HIGH); // スイッチが押されるとLEDを点灯 } else{ // 押されていない場合は消灯させる digitalWrite(SW_LED, LOW); } if((X_POS > 512-512*OFFSET) && (X_POS < 512+512*OFFSET)){ // X軸方向のセンター(512)の前後OFFSET分はLEDを消灯 analogWrite(Xmin_LED, 0); analogWrite(Xmax_LED, 0); } if((Y_POS > 512-512*OFFSET) && (Y_POS < 512+512*OFFSET)){ // Y軸方向のセンター(512)の前後OFFSET分はLEDを消灯 analogWrite(Ymin_LED, 0); analogWrite(Ymax_LED, 0); } if(X_POS <= 512-512*OFFSET){ // スティックを左に倒したときの動作 DUTY = map(X_POS,512-512*OFFSET,0,0,255); // デューティー比を0~255の範囲に調整 analogWrite(Xmin_LED, DUTY); analogWrite(Xmax_LED, 0); } else if(X_POS >= 512+512*OFFSET){ // スティックを右に倒したときの動作 DUTY = map(X_POS,512+512*OFFSET,1023,0,255); // デューティー比を0~255の範囲に調整 analogWrite(Xmax_LED, DUTY); analogWrite(Xmin_LED, 0); } if(Y_POS <= 512-512*OFFSET){ // スティックを上に倒したときの動作 DUTY = map(Y_POS,512-512*OFFSET,0,0,255); // デューティー比を0~255の範囲に調整 analogWrite(Ymin_LED, DUTY); analogWrite(Xmax_LED, 0); } else if(Y_POS >= 512+512*OFFSET){ // スティックを下に倒したときの動作 DUTY = map(Y_POS,512+512*OFFSET,1023,0,255); // デューティー比を0~255の範囲に調整 analogWrite(Ymax_LED, DUTY); analogWrite(Ymin_LED, 0); } Serial.print("X: "); // シリアルモニタにそれぞれの値を出力 Serial.print(X_POS); Serial.print(" Y: "); Serial.print(Y_POS); Serial.print(" SW: "); Serial.println(SW_POS); delay(100); } |
アナログ出力(PWM)によりLEDの点灯強度を変えています。
PWM制御に関してはこちらの記事を参考にしてみて下さい。
上記スケッチについて少し解説しておきます。
センター付近のバラツキがあるのでこれを少し補正しています。
OFFSETという変数を作りセンター付近の判定をあまくしています。
本来のセンターポジションでのアナログ値は512が理想的ですが少しズレていて値もフラフラと定まらないので前後5%のオフセットを取ってこの範囲は誤差として無視する(LEDが光らないように)ようにしています。
今回のようにLEDの点灯では問題はあまりないと思いますが、例えばサーボモーターを使い同様の方法で動かそうとすると数値のバラツキでカタカタ動いてしまう場合があるので少し補正してあげる方がいいかもしれません!
大まかなスケッチの流れを少し解説しておきます。
例えばX軸方向を考えると何も押されていないセンター付近でのアナログ入力値は512(実際は少しズレていますが)、そして右に倒していくと最大で1023(512〜1023まで変化)、左に倒していくと最小の0(512〜0に変化)になります。
これを利用しanalogWrite関数を使いPWM出力(デューティー比0~255)にレンジを合わせてあげれば点灯強度を変えられるという事になります。
今回4本の赤色LED(上下左右)はPWM出力ができる3・5・9・10番ピンを使っています。
ここでこのスケールを合わせるために便利なmap関数を使っています。
このmap関数を使いそれぞれスティックの向きに応じたアナログ値をanalogWrite関数で出力できるPWM(0〜255)の範囲でレンジを調整しています。
具体的には、例えば左に倒していくとX軸方向のアナログ値は512⇒0と変化します。
これをLEDが徐々に明るくなるようにanalogWrite関数で出力する際の値を0⇒255の範囲にmap関数を使い調整しています。(実際にはセンター付近にオフセット5%を考慮しています。)
62 63 64 65 66 | if(X_POS <= 512-512*OFFSET){ // スティックを左に倒したときの動作 DUTY = map(X_POS,512-512*OFFSET,0,0,255); // デューティー比を0~255の範囲に調整 analogWrite(Xmin_LED, DUTY); analogWrite(Xmax_LED, 0); } |
map 関数
数値をある範囲から別の範囲に変換します。
(書式)map(vaue, a, b, X, Y);
変数valueのaからbまでの範囲の値をXからYの範囲の値に変換する。
範囲を指定するパラメータは負の数を扱う事も出来ます。
また計算の結果、小数が生じる場合は切り捨てられます。
あくまで返り値は整数となります。
それでは実際にスケッチを動かしてみて下さい。
スティックの向きに応じそれぞれ対応したLEDが点灯しスティックの傾きにより明るさが強弱変化します。
そしてスティックを押し込むと青色LEDが点灯するのも確認出来ます。
またこちらはM5StickCを使っていますが同様の制御によりサーボモーターを動かしています。
詳しくは後日ご紹介出来ればと思います。
【追記】ジョイスティックコントローラーを作ってみました!
Arduinoのテスト環境であると便利なジョイスティックコントローラーを3Dプリントパーツで作ってみました!
Arduinoで動くもののテストをする場合、コントローラーという形状にしておくと操作性もイメージしやすくプログラムの修正などにも役立つと思います。
本記事でご紹介したジョイスティックの使い方やポテンショメーターを使ったこちらの記事を参考に組めばテスト環境で便利に使えるかと思います。
【追記】ジョイスティックシールドが便利です!
Arduinoを使って何か動かしたい場合にジョイスティックやタクトスイッチを使うことはよくあります。
今回ご紹介したアナログジョイスティックですが、Arduinoとの接続自体は簡単ですが結構多くの配線を接続する必要があります。
テストで動かしたい場合など、ワイヤーの脱落などもよく起こることからジョイスティックシールドを使うようになりました。
ジョイスティック以外にも6つのタクトスイッチが使え、シールドなのでArduinoボードに接続するだけで使えるようになり配線をシンプルにする事ができます。
また無線モジュール(nRF24L01)との組み合わせで簡易的なコントローラーとして使うことも出来るので便利となります!
【追記】nRF24L01を使ったArduino無線コントローラーを製作!
Arduinoのアナログ入力/ジョイスティックの制御は、製作物を動かす際や様々なArduinoのテスト動作などでもよく使われます。
本記事を読んで頂いている方は、Arduinoを使った電子工作を始めたばかりの方だと思います。
気付けば私もArduinoを使った電子工作を始めて2年程が立ちました。
ある程度Arduinoの扱いにも慣れてきましたが、Arduinoは後発となるESP系のマイコンボードなどと比べると標準で無線機能が搭載されていません。
そのためこのようなArduinoを使った無線コントローラーを製作しました!
無線で操作できる物理コントローラーが1台あると、Arduinoを使った製作物を動かす際やちょっとした無線の動作テストなどで非常に便利に使えます。
この投稿をInstagramで見る
今回使ったパーツ
Arduino UNO
Arduinoはオープンソースのハードウェアなので正規品以外にも互換品が多数メーカーから販売されています。
互換品でも正規品と比べて特に問題なく使用でき数百円程度で購入が可能なのでArduino学習用としていいですね!
Arduino互換ボードは多数販売されていますが、個人的にElegoo製のArduino互換ボードは非常にいい印象を受けます。
Arduino スターターキット
これからArduino学習を進めていくにあたりArduino UNO(互換品)やブレッドボード、ジャンパーピンなどがセットになったスターターキットが販売されています。
私はGeekcreit製のスターターキットを使っていますが、ELEGOO製のものは国内Amazonなどでも購入可能で人気があるようです。(セット内容はほぼ同じです!)
そしてELEGOOのサイトからスターターキット用サンプルスケッチのダウンロードも可能です。(Geekcreitのキットでも使えます)
参考 チュートリアルダウンロードELEGOO基本的にこれからこのセットで出来るものから紹介していこうと考えていますが、かなり多くのことが出来ます。
電子工作を始めるにはまずブレッドボードやジャンパーピン、メインとなるArduino UNOやサーボ、LEDなどの基本的なパーツがないと実際に動かすことが出来ませんが、個々にパーツを購入して回路を組んでとなるとかなりの手間がかかります。
スターターキットがあればArduinoの初歩的なことはかなりの数こなすことが出来るのでオススメです!
そこからスキルアップに伴い個別でセンサーなど必要なものを増やしていくのがいいと思います。
今回使ったアナログジョイスティックはELEGOO製Arduinoスターターキットには含まれているようです。
アナログジョイスティック
今回使用したアナログジョイスティックは個別でも販売されています。
Arduinoを使い何かを動かす場合、使用頻度が高いパーツの1つになります。
学習用に手元にあると便利です!
LEDセット
ArduinoのスターターキットにもLEDは20個ほど入っています。
LEDはArduinoを使っていろいろ回路を組んで試す際に非常によく使うパーツになります。
個別で購入するよりセットになっているものは非常にお安く1セット持っていると便利だと思います。(200個ほど入っています)
今回使った関数(コマンド)まとめ
pinMode(pin,mode);
Arduino UNOが持っているデジタルピン(D0~D13)やアナログピン(A0~A5)の入出力設定をします。
pin:設定したいピンの番号
mode:入力[INPUT]・出力[OUTPUT]。プルアップを有効にする場合[INPUT_PULLUP]
analogRead(pin);
指定したアナログピンから値を読み取る。(A0~A5)
Arduino UNOには10ビットのAD変換器が搭載されており、0~5Vの入力電圧を0~1023の値に変換して読み取ります。
pin:読み取るピン番号(Arduino UNOの場合0~5またはA0~A5で指定)
digitalRead(pin);
指定したピンの値(HIGH or LOW)を読み取ります。(D0~D13)
事前にpinMode関数で入力(INPUT)に設定しておく必要があります。
map
数値をある範囲から別の範囲に変換します。
(書式)map(vaue, a, b, X, Y);
変数valueのaからbまでの範囲の値をXからYの範囲の値に変換する。
範囲を指定するパラメータは負の数を扱う事も出来ます。
また計算の結果、小数が生じる場合は切り捨てられます。
あくまで返り値は整数となります。
今回のポイント
- アナログジョイスティックはX軸方向・Y軸方向のスティック読み取りに可変抵抗器がそれぞれ使われていてアナログ入力(analogRead関数)でその値を読み取る事が可能!
- センタークリックの判定はデジタル入力(digitalRead関数)でその値を読み取る事が可能!(プルアップで使用)
最後に!
アナログジョイスティックを使えばサーボモーターなどで動くロボットを制御したりといろいろ楽しめそうですね!
今回はアナログ入力とデジタル入力の復習的な内容となりましたが、次回サーボモーターを動かしてみたいと思います。
サーボモーターを動かすにはPWM制御が使われています。
PWMでは周期的にパルスを出力しそのパルス幅によりサーボモーターの回転角度を制御しています。
実際にはサーボライブラリを使う事により簡単に動かす事が出来ますが、これまでやってきたPWM制御について分かっていれば理解もより深まると思います。
そしてもう少し先になりますがジャイロセンサーを使ってサーボモーターの制御などさせてみると面白そうですよね!
あ、すみません。勘違いしてました。その列は横につながっていないですね。
申し訳ございません。
コメントありがとうございます!
ブレッドボードの内部の繋がりは、縦?横?、最初は戸惑いますよね!
こちらも参考にして下さいね(^o^)
https://burariweb.info/electronic-work/electronic-work-bread-board.html
つい先日から始めたばかりの初心者です。
この配線図だと横の列(アルファベットの列)で他の部品とつながってしまうように思えるのですが、
大丈夫な理由は何でしょうか?