カテゴリ: なんでも工作

磁気エンコーダでターンテーブル制御
磁気ロータリーエンコーダでDCブラシレスモーターの制御ができることを知ったので、ターンテーブル制御にも使えるはずと考えた。3個のホールセンサによるローター角検出では相位置をピンポイントで検出することしかできないが、このエンコーダを使えばモーター軸の回転角を12bit分解能で読み取ることができる。ブラシレスモーターの駆動制御は次ステップの課題として、まずは回転速度の検出器としての応用を試みる。

こんなもの↓を作った。
RotPickUpRotPickUpSide

磁気ロータリーエンコーダはAS5601チップを使ったもの。AS5601はインクリメンタル信号出力があるので、このパルスを速度検出信号として使う。PIC (12F1822)はAS5601をI2C接続して設定コマンド(初期設定)を送るため。ターンテーブルの回転数を検出するためにモーター軸の回転を直接計測したいところだが、プラッターの下にあるモーターの軸端にはどうしてもアクセスできないので、このような車輪を回転するプラッタの縁に押し当てて回転させることにした。


■ 回路図
AS5601

ターンテーブル制御回路は±5V電源で動作しているので、AS5601のパルス出力0-5Vを0V中心の信号にトランジスタでレベルシフトする。LEDは回転動作の確認用。


■ PICプログラム
I2C接続が必要なのでMSSPを設定する。MCCを使えば簡単。I2Cクロック設定は400kHz。
2024-03-17 102026

ピンアサインもMCCで。
2024-03-17 101906


I2C通信コマンドはMCCが生成した関数を使い、バイトデータの送受信を行う。ソースコートはこれ↓だけ。Write1ByteRegister()による設定書き込みは、インクリメンタル出力Bのパルス数が一回転あたり16となるように設定するためのConfiguration registerのABN Mapping設定値の書き込み。

main.c
#include "mcc_generated_files/mcc.h"
#include "mcc_generated_files/examples/i2c_master_example.h"
#include "mcc_generated_files/pin_manager.h"

#define slvadr 0x36  //The 7-bit slave address of the AS5600 is 0x36 (0110110 in binary).
#define OUT LATA4

void main(void)
{
   // initialize the device
    SYSTEM_Initialize();
    
    I2C_Write1ByteRegister(slvadr, 0x9, 0b0011);
        
    while (1)
    {
        OUT = (I2C_Read1ByteRegister(slvadr, 0x0c) & 0b1000)? HIGH : LOW;
    }
}

■ テスト
ターンテーブル回転時の速度パルスとそれによる速度制御信号のオシロ計測結果。速度パルスの間隔が速度制御信号に変換されるので、速度パルス幅にムラがあると速度制御信号も揺らぎが大きくなる。
まずは、従来の光学式速度センサによる計測。速度制御信号(水色)が細かくばらついている。これは速度パルス(黄色)の間隔にばらつきがあるため。速度パルスの間隔が揃わないのは、速度センサのターゲットにしているストロボパターンの縞の間隔にばらつきがあるため。
LED20ms


これに対して、今回の磁気エンコーダによる速度センサによる計測。速度制御信号はかなりなめらかになった。ゆっくりと揺らいでいるのはターンテーブル回転数にムラがあるためであろう。
MEC20ms


■ 課題
・車輪にはタミヤのΦ30プーリーを使った。これにOリングを嵌めて仕上がり径が31mm(プラッター外径が310mmなのでその1/10)になるのを狙ったが正確ではない。ここが正確であればプラッター一回転で車輪は正確に10回転(=160パルスを検出)となるが、そうでないと回転数制御誤差となる。プラスチックではなくアルミなどの金属製プーリーが欲しいところ。
・前述のように、モーターの軸端を直接エンコーダで検出するのが理想であるが、モーター軸の下端はカバーでおおわれている。構造が不明であるが何等かのスラスト受け構造になっているだろうから軸端はフリーではないであろう。もし軸端にエンコーダがつけば、モータ角度の検出ができるのでデジタル制御で正弦波駆動ができると思う。せっかくアナログでできているのだからわざわざデジタルでやることもないか。


■ 磁気ロータリーエンコーダでターンテーブル制御はうまくいったのか?

光学式速度センサとの置き換えでターンテーブル制御はそのまま動作した。(プラッター一回転のパルス数が216から160に変わったので、回転制御クロック周波数は120Hzから88.8Hzへ変更した)
光学式パルス信号はどうしても間隔ムラができるが、磁気エンコーダはきれいなパルス信号を出してくれるので精神的に気持ち良い。音も良くなったように錯覚する。



2024.3.20

(2024/Mar.)
RCプロポ送信機(JR製 PCM-9X)のトレーナー出力(D.S.C.出力)を使って、フライトシミュレータX-Planeを操縦するコントローラを作ったが、MSFSにも使ってみた。
ちょっと気づきがあって、マイコン(ProMicro)のプログラムを修正した。

PCM-9Xは9チャンネルの操作ができるのですべてのチャンネルをフライトシミュレータで使えるようにした。ただしアナログ操作軸は5チャンネルであり、残り4チャンネルはトグルスイッチとなる。
PCM9X

マイコン(ProMicro)のプログラム
前回のプログラムからの変更点:
・④の左側スティックの左右操作信号は、RudderではなくRxAxis信号として出力
・⑦と⑨のトグルスイッチ操作をON/OFF信号出力として追加



// Trget board is "Arduino Leonardo"
#include <Joystick.h> //ArduinoJoystickLibrary-version-2.0

#define hidReportId 0x02
#define joystickType 0x04
#define buttonCount 8 //ここに使いたいボタンの数を指定する
#define hatSwitchCount 0

#define includeXAxis  true //for Roll control
#define includeYAxis  true //for Pitch control
#define includeZAxis  false
#define includeRxAxis  false
#define includeRyAxis  false
#define includeRzAxis  true //for Yaw control (Changed from Rudder 20240225)
#define includeRudder  false
#define includeThrottle  true //for Throttle control
#define includeAccelerator false
#define includeBrake true  //for  Speed breaks control
#define includeSteering false

Joystick_ joySt(hidReportId, joystickType, buttonCount, hatSwitchCount,
              includeXAxis, includeYAxis, includeZAxis,
              includeRxAxis, includeRyAxis, includeRzAxis,
              includeRudder, includeThrottle, includeAccelerator,
              includeBrake, includeSteering);  

void setup()
{
  pinMode(7,INPUT_PULLUP);

  joySt.setXAxis(127);
  joySt.setYAxis(127);
  joySt.setRzAxis(127); //Changed from Rudder 20240225
  //joySt.setRudder(127);
  joySt.setThrottle(0);
  joySt.setBrake(127);
   
  
  joySt.begin();
  joySt.setXAxisRange(0,255);
  joySt.setYAxisRange(0,255);
  joySt.setRzAxisRange(0,255); //Changed from Rudder 20240225
  //joySt.setRudderRange(0,255);
  joySt.setThrottleRange(0,255);
  joySt.setBrakeRange(0,255);
  
}

void loop()
{
  static int ch = 0;
  unsigned long cnt = pulseIn(7,LOW,3000);//パルス幅(us)の検出(3msecを超える場合は0となる)
  unsigned int width[9];  
  bool gearSw;
  bool aux2Up, aux2Dn;
  bool flapUp, flapDn;
  bool aux4sW;
  
  if(cnt == 0){//連続パルスが途切れたことの検出
    interrupts(); 
    delay(2);
    
    ch = 0;//パルス列開始に備えてch値をリセット
    
    while(digitalRead(7) == LOW);  //最初のパルスの立ち上がりまで待つ
    noInterrupts();

  }else{
    width[ch] = cnt;//各ch毎の検出パルス幅をメモリしておく
    ch++;    
  }
  
  if(ch == 9){//パルス列検出が終了したのでメモリしておいたパルス幅を0-255値(または0/1)に変換して送信する。
        //Ch 1(右手上下スティック)
        joySt.setThrottle(map(width[0],700,1500,0,255));//スロットル操作へ割付
        //Ch 2(右手左右スティック)
        joySt.setXAxis(map(width[1],700,1500,0,255));//エルロン操作へ割付
        //Ch3(左手上下スティック)
        joySt.setYAxis(map(width[2],700,1500,0,255));//エレベータ操作へ割付
        //Ch4(左手左右スティック)
        joySt.setRzAxis(map(width[3],700,1500,0,255));  //ラダー操作へ割付
        //Ch5(右トグルスイッチ)
        gearSw = width[4] < 1100 ? 1 : 0;
        joySt.setButton(0,gearSw);// ギアダウン操作
        joySt.setButton(1,!gearSw);//ギアアップ操作
        //Ch6(フラップトグルスイッチ)
        flapUp = width[5] > 1200 ? 1 : 0;
        flapDn = width[5] < 1000 ? 1 : 0;
        joySt.setButton(2,flapUp);// フラップ操作(フラップトグルスイッチ上)
        joySt.setButton(3,flapDn);// フラップ操作(フラップトグルスイッチ下)
        //Ch7(右側AUX2トグルスイッチ上下)
        aux2Up = width[6] > 1200 ? 1 : 0;
        aux2Dn = width[6] < 1000 ? 1 : 0;
        joySt.setButton(4,aux2Up); // xx ON操作(トグルスイッチ上)
        joySt.setButton(5,aux2Dn); // xx OFF操作(トグルスイッチ下)
        //Ch8(右側回転レバー)
        joySt.setBrake(map(width[7],700,1500,0,255));// ブレーキ(スポイラー)操作へ割付
        //Ch9(左トグルスイッチ)AUX4スイッチ
        aux4sW = width[8] < 1100 ? 1 : 0;
        joySt.setButton(6,aux4sW);// xx ON操作
        joySt.setButton(7,!aux4sW);// xx OFF操作
        
  }
}

マイコンにプログラムを書き込むとゲームコントローラーとしてWindows10に認識される。Windows10の検索バーに「デバイスとプリンター」と入力するとArduino Leonaldoと名前が付いたアイコンが見えるようになっているので、右クリックして「ゲームコントローラの設定」→プロパティ を選ぶと、動作テストができる。

スクリーンショット 2024-03-02 145526

左側スティックの左右操作は、Z回転 として認識されるようになった。フライトシミュレータ側でこれをラダー操作に割り付ければ良い。ボタンは8個(On/Offスイッチ4個分)が表示されるようになった。


■ X-Planeにおける操作割り付け:
XPsetting
アナログ操作軸が5つ表示される。ボタンは、ギア操作とフラップ上げ下げ操作に加えて、エレベータトリムの上げ下げ操作と、全面スクリーンの切り替えに割り付けてみた。

↓はグライダーを操縦するときの割り付け。スロットル操作スティックはスポイラーに割り付けた。右手回転レバーはエレベータトリムの操作に割り付けた。微妙なピッチトリム調整に便利だ。
XPsettingGlider


■ MSFSにおける操作割り付け:
まずはSENSITIVITY設定画面。X-Plane11と違ってアナログ操作が4つしか表示されない。
MSFSsensitivitySetting


アナログ操作の割り付け
MSFSprimarySetting


ボタン操作の割り付け
MSFSsecondarySetting



以上。

DCアンプ保護制御回路をPICマイコンでつくる
 DCアンプ保護制御回路とは、DCアンプの出力に異常なオフセット電圧が発生した場合にアンプの電源を遮断する回路である。素子の異常やトランジスタの熱暴走などでDCアンプのバランスが崩れると出力には異常電圧が発生することがあり得る。この状態が続くとスピーカーのボスコイルを焼損することもあるので、DCアンプにはこの保護制御機能の実装が必須となる。

■従来の保護制御回路はロジックICによる構成。基本回路は保護動作発生時に状態をラッチするフリップフロップ回路だが、これに555タイマーICとカウンタICによりタイマーオン回路を追加している。これはパワーオン後にしばらくして終段トランジスタの電源を投入するためのオンディレイタイマである。初段増幅を真空管で組んだハイブリッドパワーアンプで必要となる。
protection_delay


■PICマイコンで同じ機能を実現
ラッチング動作であればPICマイコンでプログラムできるのではと思いついた。但し保護動作は素早い動作が必要なので、マイコンのソフトウェア処理ではなくCLC(Configurable Logic Cell)によるロジックゲート回路を利用する。そのほかの機能はソフトウェアで組めるであろう。
・保護制御動作のラッチング(状態保持)はCLCのSRラッチで実現する。
・オンディレイタイマ(パワーディレイオン動作)はPICのソフトウェアでタイマカウントのプログラムを組む。タイマー設定はアナログ入力でポテンショメータの電圧を読み込んだ値を使うことでタイマー設定値を可変にする。
・バッテリーチェックはコンパレータを使ってPIC内部の定電圧レファレンス(FVR)と比較することで実現する。

PICマイコンはPIC16F18323を使った。低電圧(2.3~5.5V)で動作し、CLCを2個持っている。

■ブロック図
DcAmpProtection


■回路図
DcAmpProtectionCircuit


■PICマイコンのプログラム
CLCを使うにはMCC(MPLAB Code Configulator)で設定するのが良い。入出力ピンの設定もMCCで設定してみた。

・入出力ピンの設定
pinModule

↓はピン設定結果の表示。
PinMgrPkgView

・CLCの設定
CLC

・タイマー(TMR1)の設定
TMR1

・ADCの設定
ADC


・コンパレータの設定
CMP1


・電圧レファレンス(FVR)の設定
FVR


 ・タイマカウントのプログラム (main.c)

#include "mcc_generated_files/mcc.h"

void main(void)
{
    // initialize the device
    SYSTEM_Initialize();
    
    uint8_t count = 0;  // 起動タイマのカウント変数
    bool    Pulse;      // 
    bool    CountUp = false;
    adc_result_t    sw_value;

    CNTUP_SetHigh();
    
    // 起動時にタイマー設定値をVR電圧から読み込む
    sw_value = ADC_GetConversion(AIN); 
    sw_value /= 4; //  0-511 を 0-127 へ変換
    
    while (1)
    {
          if(PIR1bits.TMR1IF)
          {
              PIR1bits.TMR1IF = false;
              TMR1_Reload();
              Pulse = !Pulse;
              if(!CountUp)
                count++;
          }
          
          if(count == sw_value){ //カウントアップしたのでFFをセットする
              CNTUP_SetLow();
          }
          
          if(count > sw_value){ //カウントアップ後はカウントを停止する
              CountUp = true;             
              CNTUP_SetHigh();
          }
          
          // モニタリングLEDの表示
          if(SETIN_GetValue() || Pulse)// 正常時は連続点灯。保護動作時は点滅
              LED_SetHigh();
          else
              LED_SetLow();
    }
}



■実装
秋月電子のユニバーサル基板に組んだ。
Board



■動作確認
・電源投入でACTIVE LEDが点滅を開始する。
・タイマカウントアップでACTIVE LEDが連続点灯となり、OUT端子が+5Vになる。
・DET入力端子をGNDにタッチすると、OUT端子が0Vになる。ACTIVE LEDは点滅。
・RESETスイッチをオンすると、OUT端子が+5Vに復帰する。ACTIVE LEDは連続点灯。
・DET入力端子をGNDにタッチした状態でRESETスイッチをオンしてもOUT端子は0Vのまま(リセット動作は不可)
・BATT入力端子に可変電圧源をつなぎ電圧を4.1V以下にするとLOW BATT LEDが点灯。

※CLCによるラッチ回路の入力→出力の反応速度を測ってみた。およそ100nsec(0.1μs)と思われる。CMOS ICによる回路より若干遅いのかもしれない。これが保護制御として十分な反応速度かどうかは評価できないが、マイコンのソフトウェア処理よりは早いはずだ。
DS1Z_QuickPrint1


(2023.8.31)

(2023/Feb.)
フライトシミュレータの操作はマウスでは難しく、ジョイスティックが必須だ。

使わなくなったRCプロポ送信機(JR製)のトレーナー出力(D.S.C.出力)を使ってジョイスティックに代わる操作器を作った。

PCとはUSB接続し、HIDとして動作するマイコンを使ってトレーナー出力を取り込む。マイコンはAruidino Leonardoなどatmega32u4を使ったもの。今回はPro Micro互換機を使った。

プロポはJRのPCM9X。PCMモードにも対応しているがModulationの設定でPPMモードにしておく必要がある。
プロポ送信機のトレーナー出力はフローティングになっているみたいなのでトランジスタ回路で0-5V信号にレベルシフトした。
JRpropInput

パルス列信号をオシロスコープで確認してみた。トランジスタ回路を通したのでプラスマイナスが反転している。
PPMosc1

0.4msecのオンパルスが10回並ぶ。このオンパルスの間の時間(0.7msec~1.5msec)が送信機スティックの操作角度に比例する。これで9チャンネル分の操作信号が送信されている。
このパルス列はおよそ10msecの休止期間を挟んで繰り返し送信されている。

この方式をパルス位置変調というらしい。(PPM-encording)
マイコンのプログラムはこのパルス列をスキャンして、各チャンネルに対応する場所のオフ時間を計測する。
DSC_0315

マイコン(ProMicro)のプログラム
Joystickライブラリを使う。パルス列をスキャンして得られたパルス長(0.7msec~1.5msec)を0~255の数値に変換し、JoySticオブジェクトに入力する。パルス列の先頭から順に各パルス信号に①~⑨と番号をつけると、各番号の信号と送信機のスティックと操作スイッチは下図のように対応する。⑦と⑨も対応するスイッチがあるが使わない。PCM9X
フラップに使うトグルスイッチは3ポジションになっている。下に下げるとフラップダウン操作、上にあげるとフラップアップ操作、となるようフライトシミュレータの設定で割り付ける。ブレーキ操作の回転レバーはフライトシミュレータの設定でエンジン逆噴射に割り付けてみた。
パルス列のスキャンを行う部分が肝だが、pulseIn()を使うと簡単である。DigitalReadによる割り込みで時間計測をキックするプログラムも試してみたが、パルス列開始の検出にはpulseIn()を使うことになるので、結局はpulseIn()だけで書いた方がシンプルになった。スキャン実行中は検出したパルス長を配列変数に保存しておき、パルス列のスキャンが一巡した後にまとめてJoystickオブジェクトにスキャン結果を書き込むようにした。各パルスをスキャンするたびにJoystickを呼び出すとちょっと処理時間が追い付かなくなるのか、うまく動かないようだった。

// Trget board is "Arduino Leonardo"
#include  //ArduinoJoystickLibrary-version-2.0

#define hidReportId 0x02
#define joystickType 0x04
#define buttonCount 4 //ここに使いたいボタンの数を指定する
#define hatSwitchCount 0

#define includeXAxis  true
#define includeYAxis  true
#define includeZAxis  false
#define includeRxAxis  false
#define includeRyAxis  false
#define includeRzAxis  false
#define includeRudder  true
#define includeThrottle  true
#define includeAccelerator false
#define includeBrake true
#define includeSteering false


Joystick_ joySt(hidReportId, joystickType, buttonCount, hatSwitchCount,
              includeXAxis, includeYAxis, includeZAxis,
              includeRxAxis, includeRyAxis, includeRzAxis,
              includeRudder, includeThrottle, includeAccelerator,
              includeBrake, includeSteering);  


void setup()
{
  pinMode(7,INPUT_PULLUP);

  joySt.setXAxis(127);
  joySt.setYAxis(127);
  joySt.setThrottle(0);
  joySt.setRudder(127);
  joySt.setBrake(0);
  
  joySt.begin();
  joySt.setXAxisRange(0,255);
  joySt.setYAxisRange(0,255);
  joySt.setThrottleRange(0,255);
  joySt.setRudderRange(0,255);
  joySt.setBrakeRange(0,255);
}

void loop()
{
  static int ch = 0;
  unsigned int cnt = pulseIn(7,LOW,3000);//パルス幅(us)の検出(3msecを超える場合は0となる)
  unsigned int width[9];  
  bool pb;
  bool flapUp;
  bool flapDn;
  
  if(cnt == 0){//連続パルスが途切れたことの検出
    interrupts(); 
    delay(2);
    
    ch = 0;//パルス列開始に備えてch値をリセット
    
    while(digitalRead(7) == LOW);  //最初のパルスの立ち上がりまで待つ
    noInterrupts();

  }else{
    width[ch] = cnt;//各ch毎の検出パルス幅をメモリしておく
    ch++;    
  }
  
  if(ch == 9){//パルス列検出が終了したのでメモリしておいたパルス幅を0-255値(または0/1)に変換して送信する。
        joySt.setThrottle(map(width[0],700,1500,0,255));//スロットル操作
        joySt.setXAxis(map(width[1],700,1500,0,255));//エルロン操作
        joySt.setYAxis(map(width[2],700,1500,0,255));//エレベータ操作
        joySt.setRudder(map(width[3],700,1500,0,255));//ラダー操作
        pb = width[4] < 1100 ? 1 : 0;// ギア(トグルスイッチ)操作
        flapUp = width[5] > 1200 ? 1 : 0;// フラップ操作
        flapDn = width[5] < 1000 ? 1 : 0;        
        joySt.setBrake(map(width[7],700,1500,0,255));// ブレーキ(逆噴射)操作
        joySt.setButton(0,pb);
        joySt.setButton(1,!pb);
        joySt.setButton(2,flapUp);
        joySt.setButton(3,flapDn);
  }
}

マイコンにプログラムを書き込むとゲームコントローラーとしてWindows10に認識される。Windows10の検索バーに「デバイスとプリンター」と入力するとArduino Leonaldoと名前が付いたアイコンが見えるようになっているので、右クリックして「ゲームコントローラの設定」→プロパティ を選ぶと、動作テストができる。

GameControllerSetting
プログラムでボタンの数を4個にしているのでこのテスト画面にもボタンが4つ現れている。ラダー操作(yaw)の動作がなぜかこの画面には出てこないが、フライトシミュレータの設定画面ではちゃんと表示される。フライトシミュレータの設定(下図)にて、ボタンにはギヤアップダウンとフラップ上げ、下げ操作を割り当てる。ブレーキ操作にはReverse(逆噴射)動作を割り当てた。スティックの操作が逆に動く場合はReverse Axisのチェックを入れて動作方向を合わせる。
FSsetting


以上で完成。フライトシミュレータが送信機で操れるようになった。実はジョイスティックは昔買ったものを所有している。今ではもう売っていないMicrosoftのSidewinder。今でもWindows10でちゃんと動く。ドライバーも不要。しかしゲーム用には良いのかもしれないがセンター位置の遊びが多くて、フライトシミュレータにはとても使い物にならない。特に着陸時には微妙なセンター合わせピッチ操作が必要になる。RC送信機であれば全く問題ない。

DSC_0305_2

(2023 Jan.)
TWELITEの特徴は省電力動作であり、乾電池で長時間の駆動ができるメリットは大きい。 温度センサと組み合わせれば電源が無いところにも簡単に設置できる無線温度計測器が実現する。TWELITE+温湿度センサにより屋外環境を計測したい。屋内環境の温湿度は既にWELITEで計測しているので、2台目のTWELITE子機(送信機能)を追加する。TWELITE親機(受信機能)1台に対して複数のTWELITE子機(送信機能)との通信ができることもTWELITEの特徴だ。

1.ハードウェア
マイコン:TWELITE DIP
センサ: 温湿度センサモジュール(SHT31)
電源: 単三電池x2
マイコン書き込み器:TWE-lite-R (PCとusb接続して使う)


センサーモジュールはI2C通信でマイコンに接続する。通信ラインのプルアップ抵抗はセンサモジュール基板に実装されているので外付けは不要だ。
DSC_0135




2.マイコンのソフトウェア
新品にはあらかじめ「標準アプリ」がインストールされているが使わない。センサをつないで送信機として使うために「無線タグアプリ」をインストールする。このアプリ(プログラム)は設定を変えるだけで各種センサに対応し、間欠送信動作ができるので省電力運用ができる。「無線タグアプリ」は専用のインストーラー(TWELITEステージアプリ)に含まれている。

a. TWELITEステージアプリ をMono wirelessのサイトからダウンロードし、ファイル一式をPCの新規フォルダーに保存する。
https://mono-wireless.com/jp/products/stage/index.html

b. マイコン(DIP基板)をマイコン書き込み器に挿して、USBケーブルでPCにつなぐ。

c. TWELITEステージアプリを起動して「無線タグアプリ」を書き込む。
https://mono-wireless.com/jp/products/stage/stage-app.html

TWELITE STAGEのメニューから[アプリ書換] → [TWELITE APPSビルド&書換] → [App_Tag]を選択

[App_Tag]を選択し出てくるリストから   App_Tag_EndDevice_input を選ぶ。
    


自動的にコンパイルとインストール(書き込み)が行われる。
 

d. マイコン書き込み器に挿した状態で、インタラクティブモードに入る。
https://mono-wireless.com/jp/products/TWE-APPS/App_Tag/interactive.html

※↓の説明に注意。
「子機は間欠駆動しているため、+ を3回入力してインタラクティブモードに移行する方法が使用できません。

インタラクティブモードに入るには、M2をGNDに接続し、電源を投入します。(TWELITE 2525AはSETピン、TWELITE SWINGはSCピンをGNDに接続し電源を投入します。)」
DSC_0136
(↑ M2:ピン26とGNDを接続した状態)

e. インタラクティブモードにて無線タグアプリの設定変更を行う。
https://mono-wireless.com/jp/products/TWE-APPS/App_Tag/mode_SHT31.html

 1). センサ種別(m)を0x3Aに設定
        センサにSHT31を使う場合の設定。
  

    2). 論理デバイスIDの設定 
  デフォルトは id=0 なのでこれを id=1に設定する。すでに導入している子機の設)定は id=0であるので、これと区別するため。
  


    3). オプションビットの設定
  定期送信間隔のランダマイズを有効にする。0x00000040
  

※最後に設定の書き込みのためにメニューから S を入力して設定完了。


3. 動作確認(受信信号の確認)
親機となるTWELITEモジュールはRaspberry Piとシリアル通信接続してある。

Raspberry PiにSSH接続してターミナルを開き、cuコマンドでシリアル通信受信をモニタする。


↑ id=1となっている行が今回追加したTWELITE子機からの受信データ。


4. 受信した温湿度データの処理
受信したデータはRaspberry Piのpythonプログラムで処理して、データクラウドに定期的に送信する。データクラウドサービスはAmbientを使う。子機から受信した信号に含まれるid番号により、どっちの子機から受け取った信号かを判定する。両方の子機からデータを受け取るまで受信のループを回すが、子機が何らかの理由で応答しない場合は無限ループになってしまうため、最大10回のループカウントで終了させる。

↓ SendWeatherToAmbient.py (このプログラムをcrontabに設定して定期実行させる)

# -*- coding: utf-8 -*-
import ambient

import openweatherdata
import getSensorData

chID = xxxxx
wkey = 'xxxxxxxxxxxxxxxx'

am = ambient.Ambient(chID, wkey)

# センサー計測データ読み込み
count = 10
get_bme = False
get_sht = False
while count > 0 and (not get_bme or not get_sht):
   sensdata = getSensorData.readData()
   id = sensdata[0]

   if id == 0:
     bme_t = sensdata[1]
     bme_p = sensdata[2]
     bme_h = sensdata[3]
     get_bme = True
   elif id == 1:
     sht_t = sensdata[1]
     sht_h = sensdata[3]
     get_sht = True

   count = count -1

#気象情報APIよりデータ取得
webdata = openweatherdata.readData() 
web_t = webdata[0]
web_h = webdata[1]
web_p = webdata[2]


r = am.send({
           'd1': bme_t,
           'd2': bme_p,
           'd3': bme_h,
           'd4': web_t,
           'd5': web_p,
           'd6': web_h,
           'd7': sht_t,
           'd8': sht_h
           })
print(r.status_code)
r.close()


getSensorData.pyは↓としている。


#coding: utf-8
import time
import datetime
import serial

def readData():
    ser = serial.Serial("/dev/ttyAMA0", 115200, timeout=30)
    line = ser.readline().decode('utf-8')
    list1 = line.split(":")
    datetime_now = datetime.datetime.now().strftime("%H:%M:%S")

    id = str(list1[6].lstrip("id="))
    if id == '0':
      temp = str(int(list1[10].lstrip("tm="))/100)
      humd = str(int(list1[11].lstrip("hu="))/100)
      pres = list1[12].lstrip("at=").rstrip()
      print(datetime_now)
      print("Temp.= " + temp + "deg.C")
      print("Humid.= " + humd + "%RH")
      print("Press.= " + pres + "hPa")
      print("ID= " + id)
      return 0, temp, pres, humd

    elif id == '1':
      temp = str(int(list1[10].lstrip("te="))/100)
      humd = str(int(list1[11].lstrip("hu="))/100)
      print(datetime_now)
      print("Temp.= " + temp + "deg.C")
      print("Humid.= " + humd + "%RH")
      print("ID= " + id)
      return 1, temp, 0, humd

    ser.close()


if __name__ == '__main__':
    try:
        readData()
    except KeyboardInterrupt:
        pass



↑このページのトップヘ