記事内に広告が含まれています

【ワレコの電子工作】Arduino UNOを使って赤外線リモコンでサーボモーター制御成功

この記事は約13分で読めます。
スポンサーリンク

ワレコ

Arduino UNOを使ってサーボモーターのリモコン制御に成功した。

これで自作オーディオ機器のボリュームをリモコン化する目途が立ったぞ。

前回記事はこちら↴

Arduino UNOやそれに使われているAVRマイコン(ATmega328P)のプログラミングを本格的に学習し始めて一ケ月くらい経った。

当初は右も左も分からなかったが、必死に勉強した結果、Arduino IDEやMicrochip Studioを使ってArduinoプログラミングを出来るようになってきた。

では本題に入ろう。

スポンサーリンク
スポンサーリンク

Arduino UNOを使ってサーボモーターを赤外線リモコン制御概要

まずは下動画でサーボモーターをリモコン制御している様子を示す。

動画 サーボモーターを赤外線(IR)リモコン制御している様子

使ったリモコンは下写真右端のやつ。

写真 サーボモーターのリモコン制御に使った赤外線リモコン送信機(右端)

右端のリモコンには0~9までの数字ボタン、「ー」、「+」などがある。

これらのボタンにサーボモーターの回転角度を割り当てた。

なお、下写真で示すサーボモーター実験回路は、前回記事で紹介したステッピングモーターも付けたままになっているが、今回の実験には無関係。

図 サーボモーターを赤外線(IR)リモコン制御している様子

上図で青色のモーターがサーボモーター。

その下にある大型のモーターはステッピングモーター(前回記事で解説あり)。

それと、ブレッドボード上にある10KBのボリュームはA0アナログ入力端子に接続しているが、このボリュームの回転に応じてサーボモーターを回転させる実験もやったので、その時に使ったものだ。

Arduinoはアナログ入力ピンやデジタル入出力ピンを使って機器を制御

Arduino UNOに使われているATmega328Pマイコンは8ビットのワンチップマイコンであり、下図に示すようにアナログ出力ピンやデジタル入出力ピンを持っている。

図 ATmega168/328P-Arduino Pin Mapping

引用元 https://www.arduino.cc/en/Hacking/PinMapping168

Arduinoプログラミングでは、C言語あるいはC++言語を使ってこれらの入出力ピンに接続した機器からの信号(アナログあるいはデジタル)を読み取ったり、あるいは出力する事で各種の機器を制御出来るのだ。

昔のZ80とか6800みたいなCPUでそんな制御をしようとすると、CPU以外にも発振回路、I/O用のLSIとかメモリ制御用のLSIやDRAM、SRAMなどが沢山並んだボードが必要であったが、ワンチップマイコンならそれらが全て入っているのでワテみたいな素人にでも簡単に扱えるのだ。

かつ、USBシリアル変換モジュールなど使えば、パソコンとも簡単に通信出来るのだ。

便利な時代になったもんだ。

ATmega328Pマイコンの仕様は以下の通り。

ATMEGA328P-PUの主な仕様
・シリーズ:ATMEGA
・電源電圧:1.8~5.5V
・コア:megaAVR
・コアサイズ:8bit
・クロック:20MHz
・プログラムメモリ:32kB
・EEPROM:1kB
・RAM:2kB
・GPIO:23pin
・ADC:6Ch
・UART/USART:1Ch
・I2C:1Ch
・SPI:1Ch
・タイマ:3Ch
・オシレータ:内蔵/外付
・パッケージ:DIP28

まあクロック20MHzでプログラムメモリが32KBもあればかなり高度な処理が可能だ。

昔のパソコンだとZ80は2MHzで動いていたし速くても4MHzくらいだったかな?

メモリも8KBくらいしか搭載していないパソコンもあったし。

サーボモーターのリモコン制御の詳細

下図に今回のサーボモーターリモコン制御実験の実体配線図を示す。

図 サーボモーターを赤外線(IR)リモコン制御する実体配線図

上図において、サーボモーターの三つのケーブルの内、二本は5V電源とGNDに接続する。残りの一本がPWM制御用のケーブルだ。

そのケーブルはデジタル2番ピンに挿した。

サーボモーターのリモコン制御に使ったスケッチ(プログラム)

次はプログラム開発だ。

Arduino IDEを起動して、以下のスケッチを作成した。Arduinoの場合、プログラムの事をスケッチと呼ぶのだ。その理由は知らない。

//#include "Stepper.h"
#include "IRremote.h"
#include <Servo.h>;

// 変数など
int pinReceiver = 6;  // IR receiver 入力をArduino Digital Pin 6に設定

#define IR_CODE_MINUS   0xFFE01F    //  16769055  -ボタン
#define IR_CODE_PLUS    0xFFA857    //  16754775  +ボタン 
#define IR_CODE_0       0xFF6897    //  16738455  0
#define IR_CODE_1       0xFF30CF    //  16724175  1
#define IR_CODE_2       0xFF18E7    //  16718055  2
#define IR_CODE_3       0xFF7A85    //  16743045  3
#define IR_CODE_4       0xFF10EF    //  16716015  4
#define IR_CODE_5       0xFF38C7    //  16726215  5
#define IR_CODE_6       0xFF5AA5    //  16734885  6
#define IR_CODE_7       0xFF42BD    //  16728765  7
#define IR_CODE_8       0xFF4AB5    //  16730805  8
#define IR_CODE_9       0xFF52AD    //  16732845  9
#define IR_CODE_100PLUS     0xFF9867  //  16750695  100+ 
#define IR_CODE_200PLUS     0xFFB04F  //  16756815  200+
#define IR_CODE_EQ          0xFF906F  //  16748655  EQ
#define IR_CODE_PREV        0xFF22DD  //  16720605  <<
#define IR_CODE_NEXT        0xFF02FD  //  16712445  >>
#define IR_CODE_PLAY_PAUSE  0xFFC23D  //  16761405  PLAY/PAUSE
#define IR_CODE_CH_MINUS    0xFFA25D  //  16753245  CH-
#define IR_CODE_CH          0xFF629D  //  16736925  CH
#define IR_CODE_CH_PLUS     0xFFE21D  //  16769565  CH+

Servo myServo; // create a servo object
int const potPin = A0; // analog pin used to connect the potentiometer
int potVal;   // variable to read the value from the analog pin
int angle;    // variable to hold the angle for the servo motor


// モーターや赤外レシーバーの宣言
IRrecv irrecv(pinReceiver);     // create instance of 'irrecv'
decode_results results;         // create instance of 'decode_results'

void setup()
{
  irrecv.enableIRIn();          // Start the receiver
  Serial.begin(115200);         //
  Serial.println("setup out");  //
  myServo.attach(2);/// 9);     //
}

void loop()
{
  if (irrecv.decode(&results)) // IR signal受信チェック
  {
    Serial.println("if irrecv in");     // 追加した
    Serial.print("results.value=");     // 追加した
    Serial.println(results.value, HEX); // 追加した
    Serial.println(results.value);      // 追加した

    switch (results.value)
    {
      case IR_CODE_MINUS:   angle -= 10; myServo.write(angle); break;
      case IR_CODE_PLUS:    angle += 10; myServo.write(angle); break;
      case IR_CODE_0:       angle =   0; myServo.write(angle); break;
      case IR_CODE_1:       angle =  20; myServo.write(angle); break;
      case IR_CODE_2:       angle =  40; myServo.write(angle); break;
      case IR_CODE_3:       angle =  60; myServo.write(angle); break;
      case IR_CODE_4:       angle =  80; myServo.write(angle); break;
      case IR_CODE_5:       angle = 100; myServo.write(angle); break;
      case IR_CODE_6:       angle = 120; myServo.write(angle); break;
      case IR_CODE_7:       angle = 140; myServo.write(angle); break;
      case IR_CODE_8:       angle = 160; myServo.write(angle); break;
      case IR_CODE_9:       angle = 180; myServo.write(angle); break;
      case IR_CODE_100PLUS: angle += 30; myServo.write(angle); break;
      case IR_CODE_200PLUS: angle += 60; myServo.write(angle); break;
      case IR_CODE_EQ:          break;
      case IR_CODE_PREV:        break;
      case IR_CODE_NEXT:        break;
      case IR_CODE_PLAY_PAUSE:  break;
      case IR_CODE_CH_MINUS:    break;
      case IR_CODE_CH:          break;
      case IR_CODE_CH_PLUS:     break;
      default:
        break;
    }

    if (angle < 0) {
      angle = 0;
    }
    if (angle > 179) {
      angle = 179;
    }
    irrecv.resume(); // receive the next value
  }
}

コード Arduino UNOを使ったサーボモータリモコン制御用のスケッチ例

まあこのコードはネット検索して見付けたサンプルや前回記事のステッピングモーター実験用スケッチなどを即席でミックスして作ったものだ。

冒頭部分に#define文がずらずら並んでいるが、これは使用したリモコンのボタンを押して、そのコードを16進数で取得して作成したものだ。

スケッチをコンパイルしてArduino UNOに書き込めば、スケッチが実行開始する。

スケッチ実行中にArduino IDEでシリアルモニタの画面を表示しておくと、スケッチ中に入れている Serial.print コマンドで文字を表示出来る。これらの機能を使ってリモコンボタンのHEXコードを取得したのだ。

ワテが使ったサーボモーターは0~179度までの回転角を指定出来る。サーボモータは一般的にそのような仕様なのかどうかは未確認だ。

=>その後の調査で回転角度は270度や360度などのサーボモーターも有るようだ。

今回ワテが使ったのは、下写真のようなArduino UNOスターターキットに入っていたやつ。

下写真のように、似たようなサーボモーターは単体でも安く売っている。

もし高トルクが必要なら下写真のようなのもある。

このサーボモーターの場合、トルクは20.5 kg-cm(5V)との記載があるので例えば長さ10cmの棒をモーター軸に取り付ければ2Kgの錘を持ち上げられると言う事か。

かなり強力だな。

ちなみにワテが使ったサーボモーターは小型だけれどトルクはまあまあ有るので、ボリュームを回すくらいなら出来ると思う。

Arduino UNOはデジタルピン3、5、6、9、10、11がPWM制御用

Arduino 日本語リファレンスのanalogWrite(pin, value)の項目を引用すると以下の通り。

analogWrite(pin, value)
指定したピンからアナログ値(PWM波)を出力します。LEDの明るさを変えたいときや、モータの回転スピードを調整したいときに使えます。

analogWrite関数が実行されると、次にanalogWriteやdigitalRead、digitalWriteなどがそのピンに対して使用されるまで、安定した矩形波が出力されます。PWM信号の周波数は約490Hzです。ただし、Unoの5、6番ポートとLeonardoの3、11番ピンは約980Hzで出力します。

UnoのようにATmega328Pを搭載しているArduinoボードでは、デジタルピン3、5、6、9、10、11でこの機能が使えます。Leonardoはデジタルピン13もPWM対応です。

引用元 http://www.musashinodenpa.com/arduino/ref/index.php?f=0&pos=2153

今回のサーボモーター実験では、デジタルピンの2番(PWM非対応)でも3番(PWM対応)でも同じように動いたのだが、なぜ2番でも正常に動いたのかは未確認だ。

まとめ

ワレコ

ArduinoやAVRマイコンの勉強を始めて一ケ月くらい経過した。

当初はArduinoとAVRマイコンの違いすら良く分かっていなかったが、今ではある程度は分かって来た。

今回のサーボモーターリモコン制御実験の成功で、オーディオ機器のボリュームをリモコン制御する目途が立った。

あとは3Dプリンタなど活用してサーボモーター式ボリュームのハードウェア製作を予定している。

それと、今回の実験で使ったArduino UNOボードをそのまま組み込む訳には行かないので、AVRマイコン(ATmega328P)を最小構成で動かせる基板を製作して、その基板を組み込む予定だ。

KiCadを使った基板の設計作業は既に始めている。

(続く)

スポンサーリンク
コメントを読む

この記事には読者の方からコメントが 16件あります。
興味ある人はこのページ下部にあるコメントを参照下さい。

ArduinoDIY&電子工作
スポンサーリンク
シェアする
warekoをフォローする
スポンサーリンク

コメント

  1. サーボモーター より:

    赤外線サーボモーター制御のプログラムなのですが
    スケッチに書いたのですが上から6行目くらいの
    #include ”IRrenote.h” にエラーが出てしまいます
    どのように書き直すと良いのでしょうか?
    あと画像にあったリモコンの真ん中を使うのですが
    見本にあるプログラムでも出来ますか?
    たくさん聞いてしまってすみません

    • wareko より:

      サーボモーター様
      この度は小生の記事にコメントありがとうございました。
      さて、
      >#include ”IRrenote.h” にエラーが出てしまいます
      との事ですが、具体的にはどのようなエラーでしょうか?
      IRremote.h をincludeして使う為には、事前にIRremoteと言うライブラリをインストールする必要があります。
      インストールは
       ツール ー> ライブラリを管理
      から入るメニューで可能です。

  2. サーボモーター より:

    2行目です

  3. サーボモーター より:

    入れてみましたでも次は
    そのしたにエラーが出てしまいました
    #include expects”FILENAME”or[FILENAME]と出ています

  4. サーボモーター より:

    バージョンが上がったので何かつけないといけないのでしょうか
    初心者なものであまり分かっていなくすみません

  5. ドットマトリックス より:

    Constとかつけたらいいのでしょうか?

  6. サーボモーター より:

    うまくいきました
    3行目にエラーが出ていたのでをそのあとに入れるとにいれると
    いけました
    でもいざやると出来ません
    リモコンが違うからかなと思うのですが
    この記事にあった写真の真ん中のを使いたいのですが
    プログラムは変わるのでしょうか?

    • wareko より:

      サーボモーター様

      上手く行きましたか!
      それは良かったです。

      >写真の真ん中のを使いたいのですが
      >プログラムは変わるのでしょうか?
      プログラムは変わりますよ。

      具体的には以下の部分が変ります。

      #define IR_CODE_MINUS   0xFFE01F    //  16769055  -ボタン
      #define IR_CODE_PLUS    0xFFA857    //  16754775  +ボタン 
      #define IR_CODE_0       0xFF6897    //  16738455  0
      #define IR_CODE_1       0xFF30CF    //  16724175  1
      #define IR_CODE_2       0xFF18E7    //  16718055  2
      #define IR_CODE_3       0xFF7A85    //  16743045  3
      #define IR_CODE_4       0xFF10EF    //  16716015  4
      #define IR_CODE_5       0xFF38C7    //  16726215  5
      #define IR_CODE_6       0xFF5AA5    //  16734885  6
      #define IR_CODE_7       0xFF42BD    //  16728765  7
      #define IR_CODE_8       0xFF4AB5    //  16730805  8
      #define IR_CODE_9       0xFF52AD    //  16732845  9
      #define IR_CODE_100PLUS     0xFF9867  //  16750695  100+ 
      #define IR_CODE_200PLUS     0xFFB04F  //  16756815  200+
      #define IR_CODE_EQ          0xFF906F  //  16748655  EQ
      #define IR_CODE_PREV        0xFF22DD  //  16720605  <<
      #define IR_CODE_NEXT        0xFF02FD  //  16712445  >>
      #define IR_CODE_PLAY_PAUSE  0xFFC23D  //  16761405  PLAY/PAUSE
      #define IR_CODE_CH_MINUS    0xFFA25D  //  16753245  CH-
      #define IR_CODE_CH          0xFF629D  //  16736925  CH
      #define IR_CODE_CH_PLUS     0xFFE21D  //  16769565  CH+

      もし中央のリモコンを使いたい場合には、まずは私のプログラムを動かした状態で、リモコンのどれかのボタンを押します。
      そうすると以下のSerial.printlnで、押したボタンのHEXコードがシリアルモニタ画面に表示されます。

          Serial.println("if irrecv in");     // 追加した
          Serial.print("results.value=");     // 追加した
          Serial.println(results.value, HEX); // 追加した
          Serial.println(results.value);      // 追加した

      そのHEXコードを使って、この#define文の中身をそのボタンに応じて書き換えます。
      リモコンの全部のボタンに対して、この#difine文を再作成出来たら完成です。

      あとは、その新しいプログラムを実行すれば、押したボタンに応じてswtich-case 文で分岐出来るようになりますので、自分でやりたい操作をそれぞれのボタンに割り当てると良いでしょう。

      • サーボモーター より:

        返信ありがとうございます
        やってみたのですが
        19:48:23.241 ->?としかでません
        シリアルモニターにいって何かするのでしょうか

        • wareko より:

          シリアル通信は送信側と受信側とで設定を合わせておく必要があります。
          プログラム側では
          Serial.begin(115200);
          で送信していますので、シリアルモニター画面で115200にする必要があります。

          それと115200と言う送信速度はかなり速いので、最初は1200とか2400あたりの遅い速度で通信するほうが文字化けなどが出にくいと思います。

  7. サーボモーター より:

    ボタンを押すと反応するのですが?とか記号が出てきてわかりません
    押す長さによっても違います

  8. サーボモーター より:

    If irrecv in
    results.value=(ローマ字 )
    数字

    の形で表示されてて良いのでしょうか
    止まらず出てくるのですが

    • wareko より:

      文字化けは解消したようですね。
      >の形で表示されてて良いのでしょうか
      それで良いです。

      >止まらず出てくるのですが
      ボタンを押すたびに数行表示されて止まるはずですが、止まらないのでしょうか?

      ここまで来ればサーボモーターさんは私のプログラムで何をやっているのかを理解出来ているはずですので、あとは、ちょっとずつプログラムを書き換えるなどして、自力で解決出来ると思います。
      頑張ってください。

  9. サーボモーター より:

    ありがとうございます
    自力で頑張ります!!

  10. サーボモーター より:

    場所が問題でした
    部屋にいっぱい検出してたみたいで

  11. サーボモーター より:

    足そうと思ったら数値リテラル演算子が見つかりませんと出ます
    足すにはどうするのでしょう