wvogel日記

自分用の技術備忘録が多めです.

家電をRN4020+androidで一括制御する その壱(ハードウェア側)

先日妹が結婚し新居での生活を始めた.
新生活に当たり欲しいものがないか聞いたところ,下記スマートリモコンをお願いされた.

Nature スマートリモコン Nature Remo 

ネット経由でアクセスし,赤外線で家電を操作してくれるらしいです.
ちなみに,amazon echoとも連携してくれるらしい.便利.
でもなんか,これくらい作れそうじゃね?

我が家は1Kと手狭なので,机の上くらいは広く使いたいところすが,リモコンを置くことでそれなりに場所を占有されるうえに,なんか整理整頓されていない感じが出てしまっています.
うん,私も机の上からリモコンを消そう.
残念ながら我が家にはamazon echoはなく,また特に屋外から家電を操作したいという欲求もないので,シンプルにandroid/BLE/PICを使ってリモコンレスを目指します.

プロジェクト名

可視光ではないけれど光を使った装置ということで,それにちなんだ名前として今回はNightHeronを採用します.
日本語だとゴイサギなのですが,このゴイサギには”青鷺火”(別名:五位の火)といって鷺のからだが青白く発光する怪現象が伝えられているようです.
 

リモコンでの家電制御

リモコンからの家電制御は,シンプルに1,0のバイト列を送信しているわけではなく,およそ38kHzで変調したCW信号で制御しています.この変調波形は,家電に信号を認識させるためのReader部,LSBファーストのデータ部,そして信号の終了を示すTrailer部から構成されており
0.35ms <= T <= 0.5ms としたとき,データ部において
'0'を送信 -> 38kHz明滅をT[ms],消灯をT[ms]送信
'1'を送信 -> 38kHz明滅をT[ms],消灯を3T[ms]送信
することとなっています.
ちなみにReader部は,8T変調後4T消灯,Trailer部ではT[ms]変調後,およそ40ms以上消灯します.

回路設計

何かないかと部品箱を漁ったらRN4020が出てきたのでこれを使いましょう.ドラえもんがポケット漁る時もこんな感じなのかな.
家電製品の赤外LEDはおおよそ940nm付近のものが使われており,部品箱を漁ると,こちらもちょうど940nmのものがありました.
  ・赤外LED ... L-53F3BT (940nm)
  ・フォトトランジスタ ... BPW76A (940nm)
動けばいいので回路は適当に設計します.

f:id:wvogel00:20200322235823p:plain
回路図
 
なお,シンプルにエミッタ接地で制御すると,38kHz変調時に波形追従が悪く若干鈍ってしまうので,スピードアップコンデンサを追加しました.
定数は下記LTSpiceシミュレーション結果に従います.右回路がスピードアップコンデンサを追加した回路で,波形を見ると立ち上がり・立下り応答が改善されていることがわかります.画像では立下り後に若干持ち上がりがあるものの,オシロバラック回路を観測した限りでは特に気になりませんでした.(この時のオシロ波形も保存しておけばよかった..)
解析結果を見ると,追従性能が改善したためかLEDに流れる電流量も稼げていることがわかります.
f:id:wvogel00:20200323000221p:plain
スピードアップコンデンサ定数評価

基板開発

適当に基板に起こします.
画像のピンク線で囲まれた領域は,RN4020のアンテナ特性を損なわないための開口領域なので,ここには部品・パターンを配置しないようにしましょう.
...ただ,3DCGを見るとわかるように,右上にあけたドリル穴に少しランドが残っていることを見落としてしまいました.
発注した基板にも当然残っている.そこまで影響しないはずなので目を瞑る.
ちなみに,RN4020のアンテナはメアンダ逆Fアンテナでした.

f:id:wvogel00:20200323000612p:plain
pcb図面
f:id:wvogel00:20200323000716p:plain
3D基板
 

いつもはFusionPCBを使っているが,今回はお試しの意味でJLCPCBに発注.
DHLは確実ですね,1weekで届きました(この基板を発注する前に別基板を発注,SF Expressに配送を依頼していますが,一か月経つ今もまだ届かず...)

さて,基板が届いたら実装しますよね.
赤外LEDは3つまで実装できますが,指向性が強く家電との位置取りを考える必要があるため,写真では一つしか実装していません.

f:id:wvogel00:20200323001447p:plain
届いた基板(両面)
f:id:wvogel00:20200323001609p:plain
マイコン
f:id:wvogel00:20200323001656p:plain
RN4020側


シリアル通信を試験しなかったので,デバッグの意味も込めてシリアル-USB変換モジュールを搭載していますが,
開発が終了したらば,ただのmicro-USB端子あるいはその他電源端子でいいです.
常に給電しながら動作させるので,けちらずに32MHzで動作させます.このおかげでRN4020のdefault baud rate(115200)で通信できます.

また,フォトトランジスタが搭載されているのは,あとで家電が増えた時に信号の読み込みができるようにするためですが,まだ機能は実装していません.

 

ソフトウェア

さあ,適当にソースコードを書いていきます.
なお,androidアプリが実装できたらリモコンの制御バイト列データはすべてandroidから送信する予定ですが,
今はまだandroidアプリがないのでソースコードに埋め込んでいます.
github( https://github.com/wvogel00/NightHeron.X )に置いていますが,説明が必要な箇所だけ抜粋します.

まず38kHz変調をかける箇所ですが,この中での20us遅延は,赤外光の変調周波数をオシロで確認しながら決定しました.
マイコンの動作周波数が変わると当然変わるので注意していください.(8MHzクロックの時は大体12us遅延)
今思うとPWM使ったら良かったかな.

void Output1T()
{
    //pulse width = 26.2us when 38.2kHz modulation
    const int repeatN = 400/26.2; // 400us / pulse width
    for(char i = 0; i < repeatN; i++)
    {
        IR = HIGH;
        __delay_us(20);
        IR = LOW;
    }
}

続いて制御信号は,上で述べたフォーマットに従ってSendIUCommand関数で生成しています.
すでに述べたように,Reader-data-trailerから構成され,データ列はLSBファーストです.

void SendIRCommand(char* data, int n)
{
    //Reader
    for(int i = 0; i < 8; i++)
        Output1T();
    __delay_us(1600);
    
    //data
    for(int i = 0; i < n; i++)
    {
        char c = data[i];
        for(int j = 0; j < 8; j++)  //LSB first
        {
            if (0x01 & c)
                Output1();
            else
                Output0();
            c = (c >> 1);
        }
    }
    
    //Traller
    Output1();
}


RN4020の設定をします.
折角プロジェクト名を決めたのでデバイス名もこれに合わせます.
SSコマンドではサーバーサービスを決定します.今回はユーザー定義を使うので0x00000001に設定します.
SRコマンドでは使用する機能を設定します.今回はAuto Advertize, Support MDLP, No Direct Advertisement, UART Flow Controlを設定します.まあ実際にはフロー制御はしないのですが,MLDPを使うのに必要なので.
PSコマンドでprivate serviceのUUIDを設定します.
最後にPCコマンドでprivate characteristicを設定しますが,PCコマンドはPSコマンドの後に実行する必要があります.
ここでは読み書き両方設定するので0x42,そして第三引数はcharacteristicが保持する最大バイト数です.
最後にRコマンドで再起動し設定を反映します.

void SetRN4020()
{
    WAKE_HW = HIGH;
    __delay_ms(100);
    WAKE_SW = HIGH; // RN4020 send the text, "CMD", through UTX line
    __delay_ms(10);    

    SendText_UART("PZ", 2);  //clear private service
    SendText_UART("SN,NightHeron", 13);     //device name
    SendText_UART("SDM,NightHeron", 14);    //Model-Characteristic name
    SendText_UART("SDN,WTORII", 10);        //manufacture name
    SendText_UART("SS,00000001", 11);       //private profile
    SendText_UART("SR,36000000", 11);
    SendText_UART("PS,cd3152d04ddb86610f4d7fd794da92f9",35);
    SendText_UART("PC,cd3162d04ddb86610f4d7fd794da92f9,42,05", 41);
    
    SendText_UART("R,1", 3);    
}

Main関数ではMLDPモードに入るまでの監視だけ実行します.
RN4020にはMLDP機能(Microchip Low-energy Data Profile)が搭載されており,
このモードに入るとペアリングしたデバイスから送信したバイト列がシリアル通信経由でPICで受け取ることができます.
PICからMLDPをONするピンを接続し忘れましたが,ペアリングしたデバイスから何かしらのバイト列を送信するとMLDPモードに入ってくれます.

void main(void) {
    Initialize();
    SetRN4020();
    
    while(1)
    {
        __delay_ms(2000);
        if(IsEqual(uartBuf, "CMD", 3) || IsEqual(uartBuf, "ERR", 3))
        {
            ;//do nothing
        }
        else if(IsEqual(uartBuf, "MLDP",4))
        {
            waitingMode = 1;
            //SendText_UART("ready",5);
        }
    }
    return;
}

android側はこれから開発していきます.

ちなみに,まだ基板とPICだけはいくつか在庫があるので,もし欲しい方がいればお譲りします.