こんにちは、「メカのりまき」です。

この記事では、赤外線リモコンから信号を、Arduinoで受け取り、その結果をシリアルモニタに表示させるといったことを行いたいと思います。

本記事で使用するもの

本記事で私が使用した物は以下の通りです。

  • 「Arduino IDE2.2.1」をインストールしたPC(Windows11)
  • USBケーブル
  • Arduino Uno R3(ELEGOO UNO R3でも可)
  • 赤外線リモコン
  • 赤外線受信モジュール
  • ブレッドボード
  • ジャンパーワイヤー

「Arduino Uno R3」の互換ボードであれば、「ELEGOO UNO R3」以外のボードでも、本記事と同様な手順で動作可能だと思われますが、動作検証はしていないので、その点はご了承ください。

以下のリンクのスターターキットを購入した場合、上記で述べた使用するものは、PC以外すべて入手することができます。

Arduinoをまだ購入していないという方やArduinoで動かすことができるたくさんのパーツが欲しいという方は、購入を検討してみてください。

赤外線リモコンについて

赤外線リモコンとは、人間には見えない光である赤外線を発光させることにより、信号を送ることができるリモコンで、テレビ、照明、エアコンなどの操作にも利用されています。

上記で紹介したスターターキットにも、以下のような赤外線リモコンが入っており、ボタンを押すことにより赤外線の信号を送ることができます。

赤外線リモコンの写真

ボタンを押すと赤外線が発せられる カメラの種類によっては赤外線を可視化できる

赤外線リモコンは、押されたボタンなどに応じて、赤外線の発光パターンを変えて、信号を送ります。

赤外線の信号はボタンに応じて点灯のパターンが変化

しかし、Arduinoには赤外線を受信する機能はないため、信号を直接受信することはできません。

そこで、赤外線の信号を電気の信号に変換する役割を行うのが、以下の写真のような赤外線受信モジュールです。

赤外線受信モジュールの写真

この赤外線モジュールは赤外線の信号を電気の信号に変換することができるので、Arduinoに接続すれば、間接的に赤外線の信号を読み取ることができます。

赤外線受信モジュールは赤外線信号を電気信号に変換する

信号を読み取る方法としてライブラリを使用して読み取る方法がありますが、今回の記事では、後々、自分でカスタマイズが出来るように、一からスケッチを作成して、信号を読み取りたいと思います。

赤外線リモコンの信号を受信する

赤外線リモコンからの信号に応じて、何かの処理を行うためには、まず、どのような信号が送られているのかを解析する必要があります。

そこで、まず初めに、以下のように、受信モジュールの信号を読み取り、その情報をシリアルモニタに表示させるということを行いたいと思います。

信号のデータを表示する

空のスケッチを書き込む

回路を作成する前に、空のスケッチ(「ファイル」タブの「New Sketch」をクリックしたときに出てくる何の処理も書かれていないスケッチ)を書き込みます。

空のスケッチを書き込む

そうすることにより、前に書き込んだスケッチが、新しく作成しようとしている回路に影響を及ぼすことを防げます。

新しい回路を作成するときは、いつもこの作業をやっておくと、安全に回路を作成することができます。

回路を作成する

赤外線モジュールが以下の写真のように、基盤と一体になっているようなものの場合は、以下のような回路を作成します。

赤外線受信モジュール(基盤と一体)の写真とピンの並び
赤外線受信モジュール(基盤と一体)を扱う回路

赤外線モジュールが以下の写真のように、基盤と一体になっていないようなものの場合は、以下のような回路を作成します。

赤外線受信モジュールの写真とピンの並び
赤外線受信モジュールを扱う回路

ピンの並びについては、赤外線モジュールの種類によって異なる場合があるかもしれないので、可能であれば、データシートを確認して回路を作成してください。

スケッチを書き込む

回路の作成が終わりましたら、以下のようなスケッチを書き込みます。

スケッチの書き込みが終わりましたら、シリアルモニタを開き、入力部分の右に表示されている設定が「9600baud」、自動スクロールが「ON」になっているのを確認します。

シリアルモニタの設定

その後、リモコンを赤外線受信モジュールに向けてボタンを押すと、以下のように数値がいくつか表示されていくのが確認できます。

信号を受信すると数値が表示されていく

スケッチの解説

このスケッチでは、「micros()」という時間を測定するための関数を利用することにより、信号のパルスの長さを測定し、その情報をまとめるというものになっています。

パルスの長さを「unsigned int pulse_data[640]」にまとめている

その手順について、もう少し詳しく説明していきたいと思います。

まず、「micros()」について、の簡単な説明をしたいと思います。

「micros()」はArduinoが動作を始めてから、現在までの時間をマイクロ秒単位で返す関数です。

今回のスケッチでは、信号の「HIGH」と「LOW」が切り替わったタイミングでこの関数を使用し、時間を取得しています。

micros()で時間を取得

また、取得したときの時間を「now_time」、一つ前に取得した時間を「old_time」という変数に格納し、それらを引き算することにより、パルスの長さを測定しています。

信号の長さはnow_time-old_time

次に、信号の切替わりを検出する方法について、説明したいと思います。

今回のスケッチでは、ループの初めに、「digitalRead()」を利用して、ピンの状態を「val」という変数に格納しています。

そして、条件分岐の処理の先にある91行目では、「old_val」という変数に「val」の値を格納しており、これらの変数を比較することにより、信号の切替わりを検出しています。

毎回のループで信号の状態をチェック 前の信号と現在の信号の状態が異なっていた場合に、パルスの長さを測定&データ数のカウントをする

この検出の際に、先程説明した「micros()」を利用したパルスの長さの測定、データの数を記録する変数「pulse_count」を1増やすという処理をおこなっています。

ここで、最初の切替わりでは、パルスの長さのデータを取得しないため、「pulse_count」の初期値は「-1」としています。

2回目以降からパルスの長さを測定&データ数のカウント

また、信号が「HIGH」の状態で、一定の時間(上記の例では15000[μs])切り替わらなかった場合は、受信完了とみなし「receive_flag」という変数を「true」にします。

データの出力は、「receive_flag」が「true」のときのみ、実行され、まとめてきたデータをシリアルモニタに表示させていきます。

表示が終了した際は、フラグとカウントの変数である「receive_flag」と「pulse_count」を初期化するため、もう一度データの取得が終了するまで、表示の処理は実行されません。

HIGHの状態で15000[μs]信号が切り替わらなかったとき受信完了とみなし表示の処理へ

ここで、「15000」という数字については調整が必要になる場合があるかもしれません。

例えば、リモコンのボタンを長押しした際に、表示が全く行われず、ボタンを離したとき、いっきに大量の数値が表示される場合は、連続して送られてくる信号が一体化してしまっているので、「15000」という数字を小さくする必要があります。

信号が送られるスパンより速く受信完了にする必要がある

また、同じボタンを押しているのに、押している長さで、データの数が異なる場合は、信号が一体化している可能性が高いです。

私の持っているリモコンの中では、「PlayStation2」のリモコンがスパンの短いリモコンで、「10000」くらいまで値を小さくしなければ、うまく受信することができませんでした。

逆にデータが途中で、途切れている感じがした場合は、信号の中に長いパルスが含まれているため、「15000」という数字を大きくする必要があります。

受信完了までの時間をパルスの長さ以上にする必要がある

ちなみに、私が持っているリモコンでは、「DAIKINのエアコン」が「35000」くらいの長いパルス信号を途中で送っていました。

今回のスケッチは、複数の種類のリモコンに対応することができますが、受信完了とするまでの時間を固定しているため、条件次第では、対応しきれないリモコンが出てきます。

ご自身が利用したいリモコンに合わせて受信完了とする時間の設定をおこなってください。

信号のデータを解析するためのスケッチの説明は以上となります。

赤外線リモコンの信号をエンコードする

先程のスケッチで、ボタンに応じてどのような信号が出力されているのかという解析が行えるようになりました。

よって、特定のボタンが押されたときの信号のデータと、取得した信号のデータを比較するようにすれば、特定のボタンが押されたことを検知することが出来ると考えられます。

値がすべて一致していれば特定のボタンが押されたことになる

しかし、上記のような比較の場合、信号の長さには毎回誤差が生じるため完全な一致はほとんどないという点や、リモコンによっては、かなり大量のデータを比較しないといけないといった問題が生じます。

そこで、先程のスケッチで取得したデータの中で、比較に必要な情報だけを残して、データをエンコード(圧縮)するといったことを行おうと思います。

データを圧縮してデータを短くする

データの特徴を見る

まずは、先程のスケッチで測定したパルスの長さのデータを見てみます。

よく見てみると、細かい数値の変化はなく、似たような数値が繰り返し使われているのが確認できます。

数値の種類はあまりない

実は、赤外線リモコンの通信方法にはいくつかフォーマットがあり、大体の赤外線リモコンはそれらのフォーマットに則って信号を送信しています。

以下に日本でよく使われている通信フォーマット2つの信号を大雑把に紹介したいと思います。

NECフォーマット

NECフォーマットの信号

家製協フォーマット

家製協フォーマットの信号

上記のフォーマット以外にもSONYフォーマットや会社独自のフォーマットも存在しており、どれも異なる特徴を持っていますが、大体のフォーマットで共通している特徴があります。

それは、信号のデータ部分に使用しているパルスの長さは2種類しか存在していないという点です。

データ部分は2種類の長さのパルスで構成されている

データを表すためのパルス信号の長さが2種類しか存在せず、その並び方によってデータを表しているとすれば、それらを2進数で表したとしてもデータの判別を行うことができます。

2進数に変換したデータを比べて一致していれば、特定のボタンがおされたことになる 0と1しか無いので、パルスの長さの値に多少の誤差があっても一致したことになる

パルスの長さのデータは「unsigned int型」で表していたので、1つのデータで16bit使用していますが、2進数で表した場合、1bitしか使用しないため、データは1/16に圧縮されることになります。

ここで、データを0か1に分ける閾値は、以下のように、測定したパルスの長さの値を参考にします。

閾値はデータ信号に出てくる小さめの数字とデータ信号にでてくる大きめの数字の間にある数値を指定

上手く閾値を設定すれば、複数のリモコンに対応することも可能です。

閾値の設定によっては複数のリモコンに対応可

ここで選定した値は、以下で書き込むスケッチで使用しますので、ご自身で選定をして、値をメモしておいてください。

私は色々なリモコンの信号を見て、閾値を「800」としました。

スケッチを書き込む

以下のようなスケッチを書き込みます。

黄色でマークされている部分が先程のスケッチから追加、変更した部分です。

また、168行目の数値「800」の部分は、先程メモをした数値に変更してください。

スケッチが正しければ、リモコンを赤外線受信モジュールに向けてボタンを押したとき、以下のようにエンコードしたデータも表示されるようになります。

パルス信号の長さのデータとエンコードしたデータの表示

スケッチの解説

今回のスケッチは、「void encode()」という新たな関数を作成し、データを以下のようにエンコードしてまとめています。

unsigned int pulse_data[640]のデータをエンコードして、encode_data[40]にまとめる

では、その仕組みについて、説明したいと思います。

まず、データに応じて、0と1に分けているのは、164行目から170行目の以下の文で、ビット演算を利用しています。

データを左に1シフトした後、条件に合わせてデータを入れる

for文により、データの数だけ上記のような処理が繰り返されますが、配列「encode_data[40]」は「unsigned int型」なので、16bit分のデータしか入れることができません。

よって、16bit分データをいれたら、次の要素に入れるように、158行目から162行目で以下のような文を記述しています。

16個分のデータを入れたら次の要素を初期化し同じようにデータを入れていく

ここで、作成した関数「encode()」は、信号の受信を確認した後に実行され、その後、結果をシリアルモニタに表示しています。

ここで、数値の後に、「U」をつけているのは、次の節で説明します。

信号のデータをエンコードするスケッチの説明は以上となります。

信号に応じた処理をする

上記までのスケッチで、信号の比較を行う準備が完了したため、次は、以下のように特定のボタンが押されたことを検知するといったことを行いたいと思います。

特定のボタンが押されたときそれに合わせた表示をおこなう それ以外のボタンが押されたときデータの表示をおこなう

以下で紹介するスケッチでは、エンコードしたデータの数値を使用しますので、2つほど好きなリモコンのボタンを押して、エンコードしたデータをメモしておいてください。

このとき、受信が上手くいかない場合もあるので、複数回同じボタンを押してデータを何度か確認してください。

私はスターターキットに入っていたリモコンの「1」と「2」ボタンを押して結果は以下の通りでした。

1のボタンを押したとき 67,49152U,5461U,16704U,5141U,2U 2のボタンを押したとき 67,49152U,5461U,16464U,5381U,2U

スケッチを書き込む

以下のようなスケッチを書き込みます。

黄色でマークされている部分が先程のスケッチから追加、変更した部分です。

ここで、106行目と109行目の引数の部分は先程メモしておいた数値に変更してください。

スケッチが正しければ、メモしたボタンを押したとき、以下のように絵文字が表示されるようになります。

メモしたボタン1が押されたとき、犬の絵文字を表示 メモしたボタン2がおせれたとき、猫の絵文字を表示 それ以外のボタンが押されたときデータの表示

スケッチの解説

今回のスケッチは、「bool check()」という新たな関数を作成して、データの比較をしています。

では、作成した「bool check()」について、説明していきたいと思います。

まず、関数の引数部分を見てみると、型を指定している引数は1つだけで、その後ろは「. . .」と記述しています。

実は、この関数は引数の数を指定しない可変長引数いうものを利用しています。

この可変長引数の関数は、引数の数が定まっていなくても関数を使うことができます。

そのため、引数の数が異なっていても同じ関数を使うといったことが可能となります。

引数の数が異なっていても同じ関数を利用できる

ここで、「. . .」の前の引数(上記の例では「bit」)は、通常の関数と同じように使用することができます。

今回の場合は、データの数が一致しているのかを見るため「pulse_count」と「bit」の値が不一致かどうかを確かめ、不一致の場合は、「return false」により、関数の値を「false」として関数を終了しています。

それ以降の引数を使用する場合は、少し変わった手順を踏まなければいけません。

可変個の引数を使うときは、まず初めに「va_list」という型の変数を宣言して、「va_start()」という関数を使用します。

このとき、「va_start()」の引数は、宣言した「va_list型」の変数と「. . .」の前の引数(上記の例では「bit」)を使用します。

次に引数の値を使いたいときは、「va_arg()」という関数を呼び出します。

この「va_arg()」の引数には、宣言した「va_list型」の変数と引数の型名を使用します。

ここで、関数(上記の例だと「check()」)を呼び出す際に使用した引数と、「va_arg()」の引数で使用した型名が異なる場合は、思っていた動作と異なる動作を行う可能性があります。

そのため、今回の場合、引数の数字の後ろに「U」を付けることにより、引数の数字を「unsigned int型」に固定するという対策を行っています。

関数の引数の型とva_arg()で指定した型は一致させる 数値の後ろに「U」を付けると「unsigned int」として扱われる

また、可変長引数の処理を終えるときは、「va_end()」という関数を呼び出します。

この「va_arg()」の引数には、宣言した「va_list型」の変数を使用します。

198行目から204行目では、for文を利用して、encode_data[40]の値と可変長引数の値を比較していき、不一致の場合は、可変長引数の処理を終わらせた後、関数の値を「false」として関数を終了しています。

ここで、上記の例を見ると、配列に関しては、番号(上記の例だと「i」)で要素をしていますが、「va_arg()」は何番目の引数を使うといった指定をおこなっていません。

実は、「va_arg()」の値は、呼び出されると、順番に値が変更される仕様になっています。

check(67,49152U,5461U,16704U,5141U,2U) va_arg() 1回目49152、2回目5461、3回目16704、4回目5141、5回目2

ちなみに、「va_arg()」の値は、呼び出されると勝手に変更され、変更した値はもとに戻すことができないため注意が必要です。

最後に206行目から208行目では、可変長引数の処理を終わらせた後、関数の値を「true」として関数を終了しています。

作成した関数は105行目から112行目の条件分岐に使用され、受信したデータと引数のデータが一致した場合、特定の表示を行うようにして、それ以外はパルス信号の長さのデータとエンコードしたデータの表示を行うようにしています。

特定のボタンが押されたことを検知するスケッチの説明は以上となります。

終わりに

皆さんリモコンの信号を受信することが出来たでしょうか。

今回は、ボタンに応じて、特定の文字を表示させる処理を行いましたが、これをLEDの点灯、消灯を行う処理など別の処理に置き換えれば、様々なものを操作することが可能です。

また、仕組みさえ分かっていれば、自分の行いたいことに合わせて、受信方法を最適なものにカスタマイズしていくことも可能なはずです。

是非、色々なリモコンで色々なものを操作してみてください。

次回の記事ではDCモータの制御を行いたいと思います。

本記事はここまでです。ご清覧ありがとうございました。

広告

楽天モーションウィジェットとGoogleアドセンス広告です。

気になる商品がございましたら、チェックをしてみてください。