MicroPythonでINA219を使った積算電流ロガーを作る

ESP32やESP8266上のMicroPythonで動作する、I2C接続の電流センサINA219を使った電流・電圧測定について以前の記事で取り上げた。

この時のMicroPythonプログラムをベースに、電流値を積算してファイルに記録する積算電流ロガーを作ったので記事にまとめる。

スポンサーリンク

積算電流の算出方法

積算電流とは「電流の瞬時値の時間積分」で得られる。例えば回路に1mAの電流がコンスタントに1時間流れたとすると積算電流は1mAhという事になる

以前の記事のMicroPythonコードを振り返ると、タイマで500msおきにmeasureメソッドを呼び出し、電圧と電流の測定を行っていた。

tim0.init(period=500, callback=lambda t:ivmes.measure(oled))

500msの測定間隔だと測定回数は1秒あたり2回、1時間あたりでは2回×60秒×60分=7200回となる。つまり、500msおきに得られる測定値を7200で割って足し込んで行けば積算電流が計算出来るということになる。(但し、500ms未満の時間内に電流変化があると誤差が発生する)

積算電流ロガーのMicroPythonプログラム

以前のプログラムに少しコードを追加し、積算電流値を計算/表示しファイルに記録するようにしたMicroPythonプログラムは以下の通り。

from machine import Timer
from ina219 import INA219
from machine import Pin, I2C
from ssd1306 import SSD1306_I2C
from logging import INFO
from os import stat

SHUNT_OHMS = 0.1
PERIOD = 0.5
LOG_PERIOD = 10
MAXLOGFILES = 20

class MeasureIV(object):
    def __init__(self, i2c, f=None):
        self.ina = INA219(SHUNT_OHMS, i2c, log_level=INFO)
        self.ina.configure()
        self.mah_coef = PERIOD/(60*60)
        self.f = f
        self.reset()

    def reset(self):
        self.elapsed_sec = 0.0
        self.log_sec = LOG_PERIOD - PERIOD
        self.accum_neg = 0.0
        self.accum_pos = 0.0
        self.voltage = 0.0
        self.current = 0.0

    def measure(self, disp):
        self.elapsed_sec += PERIOD
        self.voltage = self.ina.voltage()
        self.current = self.ina.current()
        if self.current > 0:
            self.accum_pos += self.current * self.mah_coef
        else:
            self.accum_neg += self.current * self.mah_coef
        if self.elapsed_sec > self.log_sec:
            if f is not None:
                f.write('%d,%.2f,%.2f,%.1f,%.1f\n' % (int(self.elapsed_sec), self.voltage, self.current, self.accum_pos, self.accum_neg))
                f.flush()
            self.log_sec += LOG_PERIOD
        else:
            disp.fill(0)
            disp.text('Voltage:%.2fV' % self.voltage, 0, 0);
            disp.text("Current:%.2fmA" % self.current, 0, 8);
            disp.text("Elapsed:%ds" % self.elapsed_sec, 0, 16);
            disp.text("Chg:%.1fmAh" % self.accum_pos, 0, 24);
            disp.text("Dis:%.1fmAh" % self.accum_neg, 0, 32);
            disp.show()

if __name__ == '__main__':
    i2c = I2C(0)
    oled = SSD1306_I2C(128, 64, i2c)
    f = None
    for n in range(MAXLOGFILES):
        fname = 'ivlog%d.csv' % n
        try:
            st = stat(fname)
        except:
            f = open(fname, 'w')
            break
    ivmes = MeasureIV(i2c, f)
    oled.fill(0)
    oled.show()

    tim0 = Timer(0)
    tim0.init(period=int(PERIOD*1000), callback=lambda t:ivmes.measure(oled))

電流の正負を分けて積算電流を表示/記録する

INA219は正負電流を測定することが出来るため、電流の符号を考慮せずに積算してしまうと正と負の電流量が相殺しまう。ので、電流の正負を分けて積算電流を計算するようにする。

ディスプレイの4行目に正の積算電流をChgラベル(Charge=充電)付きで、5行目に負の積算電流をDisラベル(Discharge=放電)付きでそれぞれ表示するようにした。

またファイルにはディスプレイに表示しているのと全く同じ情報をCSV形式で10秒おきに記録する。

測定値を記録するファイル名を連番にする

必要な時にマイコンの電源を入れてログ記録する使い方を想定すると、ファイル名が固定では毎回ファイルが上書きされてしまって不便。そこで、ivlog0.csv→ivlog1.csv→…のように起動のたびに連番で新しいファイルを開くようにした。ファイル数の上限はMAXLOGFILESで指定し、上限を超えた場合はファイル記録はされない。

測定ファイルをマイコンから取り出す方法

ampy を使えば、マイコンに記録された測定データを簡単にPCへコピー出来る。(但し、ampyのコマンドを使うと測定が止まってしまうので注意)

ファイルの一覧取得には、以下を実行。

ampy ls

ivlog7.csvをローカルにコピーするには以下を実行。

ampy get ivlog7.csv ivlog7.csv

ivlog0.csvを削除するには、以下を実行。(残念ながらワイルドカードは使えないのでivlog*.csvのような指定は出来ない)

ampy rm ivlog0.csv

マイコンに給電するリチウムイオン電池の充放電を記録する

18650リチウムイオン電池でマイコンに給電して上記プログラム動作させ、電池の充放電を測定/記録する様子の写真。

photo

リチウムイオン電池による電源回路に限らず測定は可能で、測定対象の回路にINA219を接続すればOK。

まとめ

MicroPythonのプログラムでINA219による積算電流計を作った。CSV形式でファイル記録されるのでPC上のPythonで読み込んでグラフ表示も簡単に出来て便利。マイコンへ電源投入するたびファイルが作られる現在の仕様でも問題なく使えているが、油断するとファイル数が上限に達してファイル記録されなくなるのでampyでこまめにファイルをPCに移す使い方が基本。

今の所必要性は感じないが、RTCのハードを追加するかWiFi接続経由でntpサーバから時刻を取得し日時の文字列でCSVファイル名を付ければ使い勝手がもう少し改善するかもしれない。

コメント