おもちゃラボ

Unityで遊びを作ってます

【Arduino】赤外線の送信機と受信機を作る(後編)

f:id:nn_hokuson:20210406214650j:plain

赤外線通信をする(前編)では赤外線通信に欠かせない搬送波の作成までを作りました。この記事では赤外線送信機と受信機を作っていきます。

nn-hokuson.hatenablog.com

目次は次のとおりです。

赤外線の送信機をつくる

それでは実際に赤外線通信の送信機を作ってみましょう。送信機といっても赤外線LEDとスイッチだけで構成された簡易的なものです。ハードウエアの構成は次のようになります。
f:id:nn_hokuson:20210414204200j:plain:w350

PWM出力をする10番ポートに赤外線LEDを接続します。また、4番ポートにタクトスイッチを接続します。このスイッチを押している間だけ赤外線通信が行われるようにします。今回は次の赤外線LEDを使用しました。

赤外線通信プログラム(Arduino版)

次にArduinoで赤外線の送信プログラムを作成しましょう。データのフォーマットは前回の記事で紹介したとおりです。このフォーマットに合わせてPWM出力をON/OFFします。次のプログラムをArduinoに書き込んでみましょう。

int top = 0;
const int onTime = 480; 
const int offTime = 380;

const unsigned char data[] = {0,1,0,0,1,0,1,1};

void setup() {
   pinMode(10, OUTPUT );    
   pinMode(4, INPUT_PULLUP);

  TCCR1A = B00100011;
  TCCR1B = B00011010;
  top = F_CPU / 38000 / 8 - 1;
  OCR1AL = top; 
  OCR1BL = OCR1AL / 3;
}

void sendData()
{
    //リーダ部
    OCR1A = top;
    _delay_us(3400);
    OCR1A = 0; 
    _delay_us(1700);

    //データ部
    for(int i = 0; i < 8; i++){
       OCR1A = top; 
       _delay_us(onTime);
       OCR1A = 0; 
       if(data[i]){ 
          _delay_us(offTime*3); 
       }
       else{   
          _delay_us(offTime);  
       }
    }

    //ストップ部
    OCR1A = top; 
    _delay_us(onTime);
    OCR1A = 0; 
    _delay_ms(65);
}

void loop() 
{
  if(digitalRead(4) == LOW){
    sendData();
  }
}

このプログラムではsetup関数の中でPWMを使って38kHzの搬送波を出力するように、レジスタの設定を行っています。レジスタの設定値については前回の記事を参照下さい。

nn-hokuson.hatenablog.com

sendData関数の中では赤外線通信のフォーマットに従って、ヘッダ部、データ部、ストップビット部の波形を作っています。OCR1A(PWM用のカウンタの上限値)を0設定するとPWMが停止することを利用して、ON/OFFを行っています。

赤外線通信プログラム(AVR版)

赤外線の送信機は、小型化したり、電池駆動にしたい場合も多いと思います。その場合はArduinoを使うのではなく、直接AVRを使うことになります。そこでAVR用のプログラムも参考程度に乗せておきます。下記はATTiny85を使用した場合のプログラムです。

//ATTiny85用のプログラム
#define F_CPU 1000000UL
#define F_IR  38000L  
#include <util/delay.h>

int top = 0;
const int onTime = 480; 
const int offTime = 380;
int Limit = 1000;

const unsigned char data[] =  = {0,1,0,0,1,0,1,1};
int prevD = LOW;

void setup() 
{
  pinMode(1, OUTPUT );
  pinMode(4, INPUT_PULLUP);

  // AVRだとdelayにTCCR0A/Bのタイマーを使うのでTCCR1を使う
  TCCR1 = B11010001;
  top = F_CPU / 38000  -  1; 
  OCR1C = top; 
  OCR1A = OCR1C / 3;  
}

void sendData()
{
    //リーダ部
    OCR1C = top; 
    _delay_us(3400); //AVRでdelayMicrosecondsはx8倍されるバグあり
    OCR1C = 0;
    _delay_us(1700);

    //データ部
    for(int i = 0; i < 8; i++){
       OCR1C = top; 
       _delay_us(onTime);
       OCR1C = 0; 
       if(data[i]){
          _delay_us(offTime*3);
       }
       else{  
          _delay_us(offTime);
       }
    }

    //ストップ部
    OCR1C = top;       
    _delay_us(onTime);
    OCR1C = 0;  
    _delay_ms(65);
}

void loop() 
{
  if( digitalRead(4) == LOW){
    sendData();
  }
}

Arduinoを使った赤外線送信プログラムとほぼ同じですが、タイマーのレジスタにはTCCR1A/Bの代わりにTCCR1 を使っています。また、タイマーの上限値はOCR1Cレジスタに、デューティー比はOCR1Aレジスタに設定します。

AVRにプログラムを書き込むには、専用のライターを使うのが簡単です。Arduino IDEを使ってAVRにプログラムを書き込む方法は次の記事を参考にして下さい。

nn-hokuson.hatenablog.com

赤外線の受信機をつくる

最後に赤外線の受信機を作成しましょう。使用した赤外線受信モジュールは下記のものです。赤外線受信モジュール自体は一般的なものなので、秋月電子などで購入したものでも同じような構成で動くはずです。

受信機のハードウエアは次のとおりです。赤外線持っジュールのスペックシートによると、正面から見て一番右の足がVcc、真ん中がGND、左がデータになっています。そこで、赤外線受信モジュールの左のピンをArduinoの7番ポートに接続しています。

f:id:nn_hokuson:20210414211415j:plain:w350

赤外線を受信するArduinoのプログラムは次のとおりです。

int input_pin = 7;

void setup()
{
    Serial.begin(9600);   
    pinMode(input_pin, INPUT); 
}

void loop()
{
  unsigned long dt; 
  int i , cnt;
  int receiveData[8];
  dt = 0;
  
  if (digitalRead(input_pin) == LOW) { 
    dt = micros();                             
    while (digitalRead(input_pin) == LOW) ;
    dt = micros() - dt;  
  }

  if (dt >= 3400) {  
    i = 0 ;
    while(digitalRead(input_pin) == HIGH) ;   
    while (1) {
      while(digitalRead(input_pin) == LOW) ; 
      dt = micros(); 
      cnt = 0 ;
      while(digitalRead(input_pin) == HIGH) { 
        delayMicroseconds(10) ; 
        cnt++ ;
        if (cnt >= 1200){ 
          break ;
        }
      }
      dt = micros() - dt;  
      if(dt >= 10000){ 
        break;
      }
      receiveData[i] = (dt >= 800) ? 1 : 0; 
      i++;
    }

    // 受信データの表示
    if (i != 0) {
      for(int j=0; j<i; j++){
        Serial.print(",");
        Serial.print(data[j]);
     }
    }
  }
}

この記事の最初にArduinoで作った赤外線送信機のボタンを押して、受信機でちゃんと正しいデータが送られてくることを確認しましょう!

まとめ

Arduinoで赤外線通信をする(前編)では赤外線通信に必要なフォーマットや、搬送波の作り方を説明しました。またArduinoで赤外線通信をする(後編)では赤外線の送信機と受信機を作りながらArduinoで赤外線通信をする方法を紹介しました。

【Arduino】赤外線の送信機と受信機を作る(前編)

f:id:nn_hokuson:20210406214650j:plain

電子工作をしていると、作った機器を無線化したい場合が時々あります。方法としてはBLEや315Mhzの無線、Wifiを使うなどの方法があります。ただ、これらの方法は少し大掛かりになってしまうため、簡単に作れて取り回しの良い、赤外線通信の方法を紹介したいと思います。

この記事では、前編で赤外線通信で使用する38kHzの搬送波を作ります。また、後編では赤外線の送信機と、赤外線の受信機をそれぞれ作ることにします。目次は次のとおりです。

赤外線通信の概要

赤外線通信はTVのリモコンや、Nintendo DS、ガラケーなどの通信に使われている無線通信技術です。赤外線LEDを一定のパターンで光らせることでデータを送信します。

f:id:nn_hokuson:20210406192901p:plain:w400

このとき、単に赤外線LEDをON/OFFしてデータを送ることもできますが、通常手法は取られていません。これは太陽光やシーリングライトにも赤外線が含まれており、これらの外光がノイズになって機器が誤動作してしまうためです。

そのため、赤外線通信する場合は38kHzの搬送波で変調してデータを送信します。変調というと難しそうですが、ONのとき赤外線LEDを38kHzで発振させ、OFFのときは赤外線を消灯します。

f:id:nn_hokuson:20210406202700p:plain:w450

赤外線ONのときをデータの「1」、OFFのときをデータの「0」に割り当てることもできますが、これだと受信側でのデコードがシビアになります。どういうことかというと、次のようにデータのサンプリングのタイミングを厳密に合わせないと、データのデコードにミスってしまうのです。

そこで、少し冗長ではありますが、次のように最初にON、その後にOFFの期間を設けます。ONに続くOFFの時間が800us未満であればデータ「1」、800us以上であればデータ「0」とします。このようにすることで、受信側では確実にデータをデコードすることができるようになります。

f:id:nn_hokuson:20210406202746p:plain

最後にデータの最初と最後を定義するパターンも用意してやります。ここでは、ONの時間が3400us以上続くパターンをヘッダ、OFFの時間が10000us以上のパターンをストップビットとして使用します。

f:id:nn_hokuson:20210406204220p:plain:w500

Arduinoで赤外線通信をするために必要な基礎知識はこれでOKです。次は実際にArduinoで38kHzの搬送波を作っていくことにします。

38kHzの搬送波を作る

まずは最初に搬送波を作ります。ここで作る搬送波は38kHzでONとOFFを繰り返す矩形波になります。Arduinoを使ってこの矩形波を作るにはPWM(Pulse Width Modulation)という機能を使います。

PWMを使うには次の4つの手順に従って、それぞれのレジスタにパラメータを設定する必要があります。

  1. PWMに使うポート(出力ポート)を指定する
  2. TCCR1AとTCCR1Bのレジスタにパラメータをセットする
  3. OCR1Aのレジスタで周波数を決める
  4. OCR1Bでデューティ比を決める

それぞれの手順について、詳細に確認していきましょう。

PWMに使うポートを指定する

ArduinoのPWMで使用できるポートは9番と10番ポートです。ここでは10番ポートからPWMを出力して赤外線LEDを光らせるので、次のようにして10番ポートを出力に設定します。

pinMode(10, OUTPUT );    

TCCR1AとTCCR1Bのレジスタにパラメータをセットする

ここがPWM出力のキモになる設定です。TCCRx系のレジスタは、タイマーに使用するレジスタです。タイマーに使えるレジスタはTCCR0A/BとTCCR1A/Bがあるのですが、TCCR0系はArduinoの内部処理(delay関数など)に使われているので、プログラマが使えるのはTCCR1系になります。

TCCR1AとTCCR1Bの設定項目をまとめると下図のようになります。

f:id:nn_hokuson:20210406205437p:plain:w500

詳しくは公式のドキュメントを参照してください。
https://avr.jp/user/DS/PDF/megaXX8PA.pdf:image=https://avr.jp/user/DS/PDF/megaXX8PA.pdf

■ 使用ポートの設定
TCCR1Aの4〜7ビット目で使用するポートを宣言します。9番ポートを使う場合は6~7ビットを10に、使用しない場合は00に設定します。10番ポートを使う場合は4~5ビットを10に、使用しない場合は00に設定します。

■ タイマーモードの設定
TCCR1Aの0〜1ビット目とTCCR1Bの3〜4ビット目を使ってタイマーモードを設定します。主な設定項目には次のようなものがあります。ここではPWM出力をするため全ビットを1に設定します。

出力モード 設定値
標準 0000
CTC 0100
高速PWM 1111

■ 分周の設定
TCCR1Bの0〜1ビット目でシステムクロックの分周率を決めます。分周とは、システムクロック周波数を1/n倍して、より周波数の低いクロックを作成する仕組みです。

分周を使うことで、タイマーにシステムクロックよりも低い周波数を使うことができます。クロックを設定値は次の通りで、ここではArduino Unoのシステムクロック16Mhzを8分周して使いたいので「010」に設定します。

分周率 設定値
分周なし 000
分周1/8 010
分周1/64 011
分周1/256 100
分周1/1024 101

OCR1AとOCR1Bのレジスタにパラメータをセットする

OCR1Aのレジスタにはタイマーの上限値(=リセットする時間)を設定します。この上限値によって、下図のように生成するPWMの周波数が決まります。OCR1Bではデューティー比(PWMがONになっている期間とOFFになっている時間の比)を決めます。タイマーの値がOCR1Bで設定した値よりも小さい場合はON、大きい場合はOFFになります。

f:id:nn_hokuson:20210406210949p:plain:w500

赤外線通信では38kHzの搬送波を作りたいので、PWMで作成する波形の周期は1/38kHz=0.00002631578947秒となります。クロックの周期はシステムクロックを8分周しているため、1/(16Mhz/8)=1/2Mhz=0.00000005秒です。したがって、0.00002631578947÷0.00000005=51カウントしたときに、リセットがかかるようにOCR1Aには51を設定します。

f:id:nn_hokuson:20210406212052p:plain:w300

また、赤外線通信では電力消費を考えてデューティー比を3:1にします。そのためOCR1BにはOCR1Aで設定した値の1/3(=17)を設定します。

搬送波のプログラム

ここまでで38kHzの搬送波を作る方法がわかりました。これをふまえて、プログラムを作ってみましょう。

void setup() {
  pinMode(10, OUTPUT );    
  TCCR1A = B00100011;
  TCCR1B = B00011010;
  OCR1AL = F_CPU / 38000L / 8 - 1;  
  OCR1BL = OCR1AL / 3; 
}

上のプログラムでは10番ポートを出力に設定し、TCCR1A/BのレジスタでPWM出力を行うように設定しています。OCR1Aにはタイマの上限値を設定しています。F_CPUはArduinoで定義されている定数でシステムクロック周波数(Arduino Unoでは16Mhz)が格納されています。また、OCR1Bにはデューティー比が1/3になるように設定しています。

実行して、10番ポートにオシロスコープをあてて出力波形を見てみてください(ここでは赤外線LEDは接続しなくても大丈夫です)。次のように38kHzの矩形波が出力されていれば成功です。

f:id:nn_hokuson:20210406214949j:plain:w330

後編では、ここで作成した38kHzの搬送波を使って赤外線の送信機と、赤外線の受信機をそれぞれ作ることにします。後編の記事はコチラ!
nn-hokuson.hatenablog.com

使用したパーツなど

今回のようにPWM出力を確認したいときにはオシロスコープがあると便利です。今回のように、観測したい周波数が100kHz程度でよければ安価な製品もあるので、チェックしてみてください!

【Blender】Moduler Treeを使って10分で木を作る

Blenderで木を作る場合、Sapling Tree Genという標準Addonがありますが、設定が必要なパラメータが多く、設定パネルを一度閉じると再調整できないなどの問題があり、使いにくいのが現状です。そこで、この記事ではModuler TreeというAddonを使って手軽に木を作る方法を紹介します。

f:id:nn_hokuson:20210116210201j:plain

Moduler Treeのインストール

まずはModulerTreeのアドオンを次のサイトからzip形式でダウンロードして下さい。
github.com

「Code」→「Download Zip」でModuler Treeのアドオンをダウンロードできます。
f:id:nn_hokuson:20210112205654p:plain:w400

次に今ダウンロードしたModuler TreeをBlenderにインストールします。Blenderを開き、メニューバーから「編集」→「Preferences」を選択してパネルを開いて下さい。

パネルの左カラムから「アドオン」を選択して、右上の「インストール」ボタンをクリックして、先ほどダウンロードしたModuler Treeのzipファイルを選択して下さい。

f:id:nn_hokuson:20210112210122p:plain:w500

これでModuler TreeのアドオンがBlenderにインストールできました。

幹と枝を作る

Moduler Treeのアドオンがインストールできたので、次は木の幹と枝を作っていきます。Moduler Treeではシェーダと同じようにノードをつないで木を作成します。

そこで、まずはエディタータイプを「Mtree Node Tree」に切り替えます。
f:id:nn_hokuson:20210112210743p:plain:w400

Moduler Tree Nodeのエディタに切り替わったら、まずは画面上部の「新規」をクリックして下さい。
f:id:nn_hokuson:20210112211342p:plain:w550

次に「Shift+A」→「ノード」を選択して、次の3つのノードを作成して下さい。

  • Tree Parameters
  • Trunk Node
  • Branch Node

また、「Trunk Node」と「Branch Node」を接続しておいて下さい。Trunk Nodeは幹のパラメータ、Branch Nodeは枝のパラメータを制御するノードです。

f:id:nn_hokuson:20210112211754p:plain:w550

Tree Parametersノードの「Create Tree」ボタンを押すと、「Trunk Node」と「Branch Node」で設定した値を元にして、3Dエディタ上に木のモデルが生成されます。

f:id:nn_hokuson:20210112212739p:plain:w200 f:id:nn_hokuson:20210112212853p:plain:w440

木の形や枝の付き方を変えたいときは「Trunk Node」と「Branch Node」のパラメータを設定した上で「Tree Parameter」の「Update Tree」ボタンをクリックします。「Tree parameters」ノードの「auto update」にチェックを入れておくと、「Trunk Node」と「Branch Node」のパラメータがリアルタイムで3Dエディタに反映されます。

f:id:nn_hokuson:20210112213433p:plain:w200

作成した幹と枝の色は、マテリアルを作ることで設定できます。枝のオブジェクトを選択した状態で右側のマテリアルタブから「新規」をクリックして、「ベースカラー」に幹と枝の色を指定して下さい。
f:id:nn_hokuson:20210116205535j:plain:w600

オススメ画面設定

Moduler Treeを使うときは、次のように2画面に分割して、一方を3Dエディタ、もう一方をModuler Treeのノードエディタにしておくと便利ですよ!
f:id:nn_hokuson:20210112213638j:plain

Images as Planesを使って葉を作る

次に木に葉を茂らせましょう。枝に葉をつけるには、まず葉の板ポリを用意して、Moduler Treeで作成した板ポリを指定します。葉っぱのテクスチャには次のものを使いました。

f:id:nn_hokuson:20210116201604p:plain:w200

葉のテクスチャはアルファを含むので、Blender側で透過処理が必要になります。この設定をShadingノードで行うのは手間なので、ここでは「Image as Planes」のアドオンを使います。

メニューバーから「編集」→「プリファレンス」を開き、アドオンの項目から「Images as Planes」を探してチェックを入れて下さい。
f:id:nn_hokuson:20210116200141p:plain:w500

次に板ポリを作ります。メニューバーから「ファイル」→「インポート」→「Images as Planes」を選択して、葉のテクスチャを選択して下さい。
f:id:nn_hokuson:20210116205240j:plain:w600

枝に葉をつける

作成した葉の板ポリを枝に設定します。Moduler Treeのノードエディタで「Tree Parameter」の「Create Leafs」にチェックを入れ、「leaf:」の欄に先程作成した板ポリの葉っぱを指定します。葉っぱは枝に対して生成されるため、ある程度枝の本数は増やしておいたほうが良いでしょう。枝の本数は「Branch Node」の「split_proba」で指定できます。
f:id:nn_hokuson:20210116203417p:plain:w600

これで木が生成できました。Moduler Treeのアドオンには調整可能な様々なパラメータが用意されているので、作りたい木のイメージになるように変更してみて下さい。
f:id:nn_hokuson:20210116204807j:plain

まとめ

この記事ではModuler Treeのアドオンを使って木を作る方法を紹介しました。Blenderでは木を作るアドオンがいくつか用意されていますが、Moduler Treeは比較的簡単に使えて便利なアドオンだと思います。