2022年5月6日金曜日

ArduinoとINA260で電力ロガーを作製する

ArduinoとINA260モジュールを使用してPC接続型の電力ロガーを製作した.


 これまで機器の消費電力の時系列データを取得する際は,2台のDMMを使用して電圧と電流を同時に測定し,DMMの画面を動画に撮影,それを見ながら電流と電圧をエクセルに転記して電力を計算していた.しかし,この方法では手間がかかることやデータの刻み時間を短くするのが難しいことが課題だった.

 このため,ArduinoとTIのINA260を搭載したモジュールを使用して電力ロガーを作成した.INA260はI2C接続の電流・電圧センサで,最高15A,36Vまでの直流電流・電圧を測定できる.


主要な構成部品

・Arduino Uno Rev3
 (INA260自体の仕様はこちら


組み立て

 Arduino Uno Rev3とINA260モジュールをバニラシールド経由で接続した.配線はこちらを参考にした.刻印が同じピン同士を配線するだけなので簡単である.ALRTの配線は必須ではなく今回は行わない.
 なお,このINA260モジュールはI2Cアドレスを設定するために基板上の端子をショートさせる必要がある.今回は後述のAdafluit INA260ライブラリのデフォルトである0x40(2進数の1000000)となるようにショートさせた.

 組み立てた状態が以下の写真で,モジュール上にある金属製の端子台が電流測定用の端子,緑色のターミナルブロックが電圧測定用の端子となる.負荷との接続方法は一般的な電流・電圧計と同様である.


スケッチの作成

 このINA260モジュールはadafruitのINA260ライブラリを利用できるので,ライブラリマネージャからAdafruit INA260 Libraryをインストールする.

ArduinoのスケッチはAdafruitのINA260ライブラリのサンプルを以下のように改造した.
  1. #include < adafruit_ina260.h >
  2. Adafruit_INA260 ina260 = Adafruit_INA260();
  3. int loggingInterval;
  4. long nn;
  5. float ss;
  6. void setup() {
  7. Serial.begin(115200);
  8. // Wait until serial port is opened
  9. while (!Serial) { delay(10); }
  10. Serial.println("Adafruit INA260");
  11. if (!ina260.begin()) {
  12. Serial.println("Couldn't find INA260 chip");
  13. while (1);
  14. }
  15. Serial.println("Found INA260 chip");
  16. //A/D変換時間と平均化標本数を設定
  17. //値を更新するのに必要な時間は,AD変換時間*平均化標本数で計算される
  18. //INA260_TIME_*とINA260_COUNT_*の値はAdafruit_INA260.hを参照
  19. //A/D変換時間を設定.デフォルトは1.1ms
  20. //ina260.setCurrentConversionTime(INA260_TIME_8_244_ms);
  21. //ina260.setVoltageConversionTime(INA260_TIME_8_244_ms);
  22. //平均化標本数を128に設定(デフォルトは1)
  23. ina260.setAveragingCount(INA260_COUNT_64);
  24. //測定値送信間隔[ms]を設定.
  25. loggingInterval = 500;
  26. //グローバル変数初期化
  27. nn = 0;
  28. ss = 0;
  29. }
  30. void loop() {
  31. long diff;
  32. //delay()では送信間隔を短く設定するとloop内の処理時間の影響を受けやすく送信間隔がずれる.
  33. //タイマを使用すれば精度よく定期実行できるがハードウェア依存があり移植性に難がある.
  34. //このため,mills()を使用してarduino起動後の経過時間を取得し,loggingInterval経過する度に処理を実行する.
  35. //loop内の処理時間がloggingIntervalよりも長いと更新間隔が狂う.
  36. diff = millis() - nn;
  37. if(diff > = loggingInterval){
  38. nn += loggingInterval;
  39. ss += diff;
  40. //出力書式はCurrent, Bus Voltage, Power
  41. //単位がmA, mV, mWなのでA, V, Wに変換して出力
  42. //Current
  43. Serial.print(ina260.readCurrent()/1000);
  44. Serial.print(",");
  45. //Bus Voltage
  46. Serial.print(ina260.readBusVoltage()/1000);
  47. Serial.print(",");
  48. //Power
  49. Serial.println(ina260.readPower()/1000);
  50. }
  51. }
 このスケッチでは単位変換した電流・電圧・電力をCSVデータとして利用できるように成形し,0.5秒間隔でデータをPCへ送信する.今回の構成では時間間隔を変えるにはスケッチの編集・再書き込みが必要なので,必要であればディップスイッチで変更できるようにした方がいい.

PCでのデータ受信と保存

 PCでデータの受信と記録を行うプログラムはPythonで以下のように作成した.なお,シリアル通信用のモジュールとしてpyserialを使用している.
  1. import serial
  2. import time
  3. import datetime
  4. import os
  5. #定数
  6. fName='ina260.csv' #データを記録するファイルの名
  7. recordingRate=0.5 #データの刻み時間.経過時間カウントに使用.値はスケッチと合わせる.
  8. try:
  9. #シリアル通信を宣言
  10. ser=serial.Serial('COM3',115200,timeout=1)
  11. #バッファクリア
  12. ser.reset_input_buffer()
  13. #記録用ファイルをカレントフォルダに作成して開く
  14. fPath=os.path.join(os.getcwd(),fName)
  15. f=open(fPath,'w')
  16. #ファイルのヘッダ部分
  17. #日付時刻(fはマイクロ秒),経過時間,電流,電圧,電力
  18. f.write('Date[YYYY-mm-dd H:M:S:f],Elapsed Time[s],Current[A],Bus Voltage[V],Power[W]\n')
  19. #シリアル通信のゴミデータを読み飛ばすためスケッチで設定した文字列が出現するまで読み飛ばす.
  20. #読み飛ばす回数が20を超える場合は処理を中断
  21. c=0
  22. while 'Found' not in ser.readline().decode('utf-8'):
  23. print('Wait:' + str(c))
  24. if c > 20:
  25. print('Timeout')
  26. raise Exception
  27. c=c+1
  28. #Ctrl-Cが入力されるまで無限ループ
  29. #記録間隔はArduino側で設定するのでこちら側では処理不要
  30. print('Start Recording')
  31. t=0
  32. while True:
  33. now=datetime.datetime.now()
  34. #電流,電圧,電力データ取得.ser.readline()がbytes型なのでdecodeによりstr型に変換する
  35. strSer=ser.readline().decode('utf-8')
  36. print(now.strftime('%Y-%m-%d %H:%M:%S:%f') + ',' + str(t) + ',' + strSer.strip())
  37. f.write(now.strftime('%Y-%m-%d %H:%M:%S:%f') + ',' + str(t) + ',' + strSer.strip() + '\n')
  38. t=t+recordingRate
  39. #Ctrl-Cの入力によりKeyboardInterruptを発生させることで,任意のタイミングで記録を正常に中断する
  40. except KeyboardInterrupt:
  41. print('Stop Recording')
  42. f.write('Stop Recording')
  43. f.close()
  44. ser.close()
  45. except Exception:
  46. print('Unknown Error')
  47. f.write('Unknown Error')
  48. f.close()
  49. ser.close()
  50. finally:
  51. f.close()
  52. ser.close()

動作確認

 INA260を使用して,CrystalDiskMark実行中のNVMe SSDの消費電力を測定した.
 まず,データを記録したCSVファイルは以下となる.

 グラフ化するとこうなる.




 

0 件のコメント:

コメントを投稿