エントリー

ロギング装置の作製とESP8266のセットアップ

ロギング装置の構想は前々からあるのだがロギングするようなシステム作ってないので着手しなかった

ところが今回作製した放電器はロギングの必要性が高いと感じログ装置を作製することにする

どう実現するか,基本スタンドアロンでのロギングするとして,装置毎(例えば放電器)にSDカード等を実装して保存する内蔵型か,UART通信などを経由してので外付け型となる

外付け型ならSDカード保存の他にフラッシュメモリー保存や無線通信にてクラウド保存も可能だし融通がききそう

そこで楽しめそうな外付け型でSDカードへのロギングをやってみることにした

SDログ

この装置は前にも似たような物を作製したことあるのでさくっと実験版は完成

SDカードは3.3Vロジックのため3.3V版Arduino(AVR)を利用したほうが回路が楽になる

外付けなのでプロトコルが必要となるが通信は無手順,ログの記録として開始と終了のみ決めた

 開始:@Begin

 終了:@End

ログ装置側のプログラム(簡単すぎだけど公開)

//    Serial Logging To SD Card
//
//    シリアル出力のロギングをSDカードに書き込む
//    シリアル:9600bps
//    SD:ファイル名は連番(Ex.log.1xxxx.txt)
//    プロトコル
//        @Begin. - @End.間をSDに書き込む
//    Ex.
//        @Begin.
//        ;Constant current : 500mA
//        ;End voltage : 1000mV
//        0, 1237, 0, 0
//        1, 1237, 499, 8
//        2, 1226, 501, 16
//        131, 1051, 499, 1088
//        @End.
//
#include <EEPROM.h>
#include <SPI.h>
#include <SD.h>

// SD card attached to SPI bus as follows:
// * MOSI - pin 11
// * MISO - pin 12
// * CLK  - pin 13
// * CS   - pin 10
// ※CS pinは使用しているシールドで変更する必要がある
//        イーサーネットシールドは 4
//        Adafruit のSDシールドは 10
//        Sparkfun のSDシールドは 8
//
//#define DEBUG        1

#define CSPIN        10                  //チップセレクト
#define LEDPIN        8                  //状態表示LED
#define BLINKTIME    1000                //点滅間隔

static char strBegin[] = { '@', 'B', 'e', 'g', 'i', 'n', '.', '\r', '\n', '\0' };
static char strEnd[] = { '@', 'E', 'n', 'd', '.', '\r', '\n', '\0' };

static uint16_t year = 2017;
static uint8_t month = 1, day = 1, hour = 19, minute = 0, second = 0;

static char fileName[16];                //ログファイル名

static boolean sd = false;               //SD書込み開始フラグ
static boolean light;                    //LED点灯フラグ
static int timer;                        //LED点滅時間カウンタ

static int getByte() {
    for(;;) {
        timer++;
        if(Serial.available()) {
            return(Serial.read());
        }
        delay(1);
        if(timer > BLINKTIME) {
            timer = 0;
            if(sd) {
                if(light) {
                    digitalWrite(LEDPIN, LOW);
                    light = false;
                } else {
                    digitalWrite(LEDPIN, HIGH);
                    light = true;
                }
            }
        }
    }
}

void dateTime(uint16_t *date, uint16_t *time) {
    // FAT_DATEマクロでフィールドを埋めて日付を返す
    *date = FAT_DATE(year, month, day);
    // FAT_TIMEマクロでフィールドを埋めて時間を返す
    *time = FAT_TIME(hour, minute, second);
}

static void makeFileName() {
    int fileNum = (EEPROM.read(0)<<8) + EEPROM.read(1);
    if(fileNum < 10000) fileNum = 10001;
    sprintf(fileName, "log%5d.txt", fileNum);
    //次のファイル番号
    fileNum++;
    EEPROM.write(0, fileNum>>8);
    EEPROM.write(1, fileNum&0xff);
}

void setup() {
    Serial.begin(9600);                    // 9600bpsでポートを開く
#ifdef DEBUG
//    Serial.println("Start");
#endif
    //SSピンは使用しない場合でも出力にしないとSDライブラリが動作しない
    //pinMode(SS, OUTPUT);
   
    //SDライブラリの初期化
    if(!SD.begin(CSPIN)) {
        Serial.println("SD Card failed");
        for(;;);
    }   
    //日付と時刻を返す関数を登録
    //登録することでファイルの作成日時や変更日時が記録できる
    SdFile::dateTimeCallback(&dateTime);

    //初期化正常で開始
    pinMode(LEDPIN, OUTPUT);
    digitalWrite(LEDPIN, HIGH);            //点灯
    light = true;
    sd = false;
    timer = 0;
}

void loop() {
    char c, buf[128];
    int n = 0;
    File dataFile;

    for(;;) {
        c = getByte();
        buf[n++] = c;
        if(c == '\n') {
            buf[n] = '\0';
            n = 0;
#ifdef DEBUG
//            Serial.print(buf);
#endif
            if(!sd) {
                if(!strcmp(buf, strBegin)) {
                    //sd write start
                    makeFileName();
                    if(dataFile = SD.open(fileName, FILE_WRITE)) {
                        sd = true;
#ifdef DEBUG
                        Serial.println("logging start");
#endif
                    } else {
                        //ファイルが開けなかったらエラーを出力
                        Serial.print("can not open ");
                        Serial.println(fileName);
                    }
                }
#ifdef DEBUG
                else {
                    //ignore string
                    Serial.print("ignore : ");
                    Serial.print(buf);
                }
#endif
            } else {
                if(!strcmp(buf, strEnd)) {
                    //sd write done
                    dataFile.close();
                    sd = false;
#ifdef DEBUG
                    Serial.println("logging done");
#endif
                } else {
                    //sd writting
                    dataFile.print(buf);
#ifdef DEBUG
                    Serial.print("sd wrt : ");
                    Serial.print(buf);
#endif
                }
            }
        }
    }
}

ログ装置側が動作してるかどうか判るようにLEDで通知(点灯:Reday,点滅:Logging)するようにした

・・・

さてボードに組み込もうかと思ったところで,どうせならってことで・・・

ESP-WROOM-02

いつか使おうと思いながら購入して置きっぱなしだった「ESP-WROOM-02」を取り出す(世間では「ESP-WROOM-32」が旬みたいだけど・・・)

いつもお世話になってるこちらを参考にしてブレッドボードに展開

ブレッドボード

ATコマンドで動作確認して(115200bps8N1,行末:CR+LF)

AT1

AT2

開発環境を整え(参考

IDE

プログラムを書き込み動作させることができた

注意点や嵌った事など

デフォルトでは「softAP」モードになっていて先ずは「station」モードに変更しないとWiFiが使えない(AT+CWMODE=1)

cc版でないとESPは扱えないのでダウンロードしてarduino.1.8.1を設定(和解統合されてIDEはorg版オンリーになったようだが),拙者はcc版だと何故か問題があったためorgを使っていたので,これまでのローカル設定が全部使えてない

尚,分裂時のorg版とは共存できるようなので良かった

ボード選択設定(追加)

ボード Generic ESP8266 Module
Flash Mode QIO
Flash Frequency 40MHz
CPU Frequency 80MHz
Flash Size 4M(3M SPIFFS)
Debug port Disabled
Debug Level なし
Reset Method 手動SWなら「ck」,自動の場合(スイッチサイエンスの開発ボードなら)「nodemcu」
Upload Speed 115200
シリアルポート シリアルポート番号

放電器の作製(その4)

アルミのアングルを2枚増やして放熱版を改良(大して発熱なかったので手抜きしたのがミス)

これで1A以上の放電でも放熱できるようになったようだ

そこで長期放置(3カ月以上半年未満位)の充電池を放電処理した(尚,管理者は年1回は長期放置の充電池をまとめて再充電している)

放電は定電圧放電1.0V,終止電流250mAで行う

VOLCANO

VOLCANO(単4形,750mAh)

VOLCANO

管理番号 内部抵抗(mΩ) 放電容量(mAh) 備考
188 595 ¥100 NiMH
146 610 ¥100 NiMH
208 602 ¥100 NiMH
146 615 ¥100 NiMH
146 590 ¥100 NiMH
208 578 ¥100 NiMH
210 148 ¥100 NiMH
eneloop(単4形,Min.750mAh)

eneloop

管理番号 内部抵抗(mΩ) 放電容量(mAh) 備考
159 604 HR-4UTGA
139 677 HR-4UTGB
199 601 HR-4UTGA
Ni-MH700(単4形,650mAh,min.600mAh)

Ni-MH700

管理番号 内部抵抗(mΩ) 放電容量(mAh) 備考
140 426 旧新品
100 331 旧新品
STAMINA(Cyber-shot用 単4形,min.740mAh)

STAMINA

管理番号 内部抵抗(mΩ) 放電容量(mAh) 備考
632 513 旧新品

 

全てにおいて放電容量が公称値より少ないのでオペアンプの倍率の調整ミスかプログラムの計算ミスかと思ってシャント抵抗の電圧を計測してみたが問題ないようだ

放電器の作製(その3)

充電部をブレッドボードに統合して確認しようと充電回路を試用確認したブレッドボードを見たら・・・

充電部1充電部2

焼けていた・・・ので,ブレッドボードへの展開は止めてユニバーサル基板へ載せることにした

C基板(秋月サイズ)では無理そうだったので,(2階建ても考えたが)B基板にしてみたらスペース余ったので電池ボックスも入った(スタンドアロンでロギングのためのSDカード設置もできそう)

基板1基板2

ちなみに裏は

基板3

とりあえず確実なエネループ(単三)で確認

エネループ

内部抵抗は115mΩ

内部抵抗

1000mA電流,1.0V未満で終了にして放電する

放電1放電2

放電容量は1560mAhとなったが,まだ余力はあるようだ

(ブレッドボードから基板に載せて判った事)

  • 同PWM値で流れる電流が増えた(接触抵抗が減ったのか)
  • 放電用トランジスタの発熱が多い

 

ロギング出力(定電流放電500mA,終止電圧1.0V)をOpenOfficeでグラフ化(上記の充電池のログではない)

放電器の作製(その2)

放電器の作製の続きで(時間も少なく)進みは悪いが改良や苦労してる点など記録

シャント抵抗とオペアンプの組み合わせは楽ではない

平日は少し古い充電池で放電テストを行いながら調整していたら,正常そうな放電容量とならない事(例えば1600mAhの物が2000mAhとかになることがある)が判り,どこに問題があるのか悩むことに・・・

  • プログラムの問題はない
  • リファレンス電圧は問題なくバッテリー電圧値は正常

    Ref

  • 時間カウントも正常(1時間経過で誤差1秒未満だった)
  • オペアンプのオフセット電圧も問題ではないようだ

となると,電流の測定が問題かと,そしてブレッドボードに置いたシャント抵抗が怪しい

さすがに0.01Ωのシャント抵抗をブレッドボードで使うと誤差が出るのだろう

別のボードでシャント抵抗とオペアンプを含む電流電圧回路を組み込みブレッドボードで使えるようにすることも考えたが,低抵抗だと電圧が乗らないので算出した電流値の変動が大きいこともあってシャント抵抗値を0.1Ωに変更することにして,手持ちの小さい(表面実装)0.1Ωのシャント抵抗をブレッドボードで使えるように加工する

0.1加工

ピンの間に半田付けした

ピン

0.1Ω(左),0.01Ω(右)

(しばらく確認した)結果,放電容量は若干の調整は必要だが大きな誤差は無くなった

だが使用した0.1Ωのシャント抵抗は0.2Wなので最大1.4Aが限界となり予定の仕様を超えるため0.15Ωの金属被膜抵抗を並列にして0.75Ωを作る

0.075

また正確な抵抗値を出しておきたいので4端子法で計測(低抵抗測定器が欲しいな)

抵抗計測1抵抗計測2

そこでまた問題が・・・なんか値がおかしい,そう抵抗値が4倍以上も大きいのだ

0.075Ωのはずが,24.7(mV) ÷ 50.0(mA)= 0.494

0.01Ωのはずが,2.4(mV) ÷ 50.0(mA) = 0.048

放電容量の誤差は気にならない程少ないので4倍にもなることはない

原因が特定できず仕方なく再度確認してみたら,なんと!使用したブレッドボード(緑)の接触抵抗が酷かったことが分かった(これは注意

不良品

上の緑のミニブレッドボードが異常なほど接触抵抗が酷い,下の(見え難いが)スケルトンのミニブレッドボードで再度計測したら正常に測定できた

(0.075Ω:0.078Ω,0.1Ω:0.112Ω,0.01Ω:0.012Ωという満足できる結果となる)

この緑のミニブレッドボードはaitendoで購入したプロトタイプシールドに付属していたボードで色がいまいちだったので使用せず手持ちのミニブレッドボード(白)と交換して空いていた物

現在実装しているブレッドボードは大丈夫だろうかとチェックしたら問題なくてほっとした

余談だがブレッドボードは白系がパーツを載せる時(載った時も)一番見易くてよい(スケルトンとか恰好は良いがピンとか観難い)

電池ボックスに注意

放電テストを行っていると正常な充電池の場合,表示している電流や電圧の変動が少ない事が判ってきた

また正常な放電流が表示できるようになってからだが,どんなに頑張っても1Aも放電できないこともあり,そんなはずはないのだけどな?っと充電池が劣化すると内部抵抗が悪くなるって記憶があるので内部抵抗測定を追加することを考えた

電池の内部抵抗測定とかかなり昔にやったことあるがもうやり方を覚えていない・・・で,調べてみて実験回路を作成して試験する

仕組みは充電池に抵抗器に繋いで電流を流した状態と流してない状態の電圧差で計算

①充電池の電圧をE(V)

内部抵抗2

②抵抗器の抵抗値をR(Ω)

内部抵抗1

③抵抗器に充電池を繋いで電流を流した状態の充電池の電圧をV(V)

内部抵抗3

④内部抵抗をr(Ω)として

 r = R( E / V - 1) = R(E - V)/ V

試験できたので本体に組み込み

内部抵抗4

上は946mΩで合ってそうだが,下は4.91Ωで異常そう

内部抵抗5

最小は充電池が終わっていると思って放電試験してみたら正規の放電量だったので再度内部抵抗を計測すると正常

すったもんだの挙句,充電池をボックスで動かしたら内部抵抗が変動することをつきとめた

つまり電池ボックスの接触抵抗で正常な内部抵抗が測定できていない

そこで(どこかの記事で観た)端子に(銅)線を巻く対応を施したら劇的に改善することに(素晴らしい)

電池ボックス

接触抵抗が1Ωもあれば1A放電できないし,充電池が電池ボックスに正常にセットされているか判断できるようになり,内部抵抗測定を実装したのは正解のようだ

現在の回路図

回路図3

前回からの変更点

・放電用のトランジスタをFETからバイポーラに交換

  PWMの±1に対する抵抗値の変動が大きいので変更

  ON・OFFを繰り返すため電流測定に難ありなのでLPFは外していない

・充電部のLPFは必要ないので外す

  ON・OFFで単位当たりの充電量を調整する

・R12の1Mの抵抗を追加

  バッテリが無い時0Vになるようにプルダウン

・内部抵抗測定部を追加

・オペアンプのオフセット電圧取得ため入力を短絡(回路図にない)

  モード選択画面でボタンを長押しで実行

充電回路の試験

別ボードで組み込み試験完了している

充電シーケンスは19秒充電し1秒待機で電圧確認を繰り返す(今後いろんなパターンを計画)

充電終了条件(以下のいずれか)

  • 終止電圧になった場合
  • 充電中に限界上限電圧を超えた場合
  • 充電しても電圧が上がらなくなった場合

充電

/* 充電プログラム(後に充放電器として統合)
 */

#define PIN_CHRGER         11                //充電コントロールピン
#define PIN_LED            13                //LEDピン
#define PIN_BTV            A0                //バッテリー電圧測定

#define CHG_VOLT         1450                //充電終止電圧mV(25℃時)
#define CHG_UPPER        1600                //充電中最大限界電圧mV

//25℃程度の室温において充電終止電圧1.45V
//ニッケル水素電池電圧は温度が1℃上がるごとに約3mV低下(温度係数-3mV/℃)

#define CHG_ON_TIME     19000                //充電ON時間(ms)
#define CHG_OFF_TIME     1000                //充電OFF時間(ms)
#define CHG_MON_TIME     1000               //充電監視時間間隔

#define RDC_ANALOG         10                //analogReadの平均化カウント
#define REF_VOLT         5000                //mV

//電圧測定Pinから読込み(*1000のmV)
static int readVolt() {
    int val = 0;
    for(int i = 0; i < RDC_ANALOG; i++) {
        val += analogRead(PIN_BTV);
    }
    val /= RDC_ANALOG;
    return(map(val, 0, 1023, 0, REF_VOLT));
}

void setup() {
    Serial.begin(9600);                      //Serial設定9600bps
    pinMode(PIN_CHRGER, OUTPUT);
    pinMode(PIN_LED, OUTPUT);
    analogReference(DEFAULT);
    pinMode(PIN_BTV, INPUT);
}

void loop() {
    int volt = readVolt();
    Serial.print("Volt: "); Serial.print(volt); Serial.print("mV ");
    if(volt >= CHG_VOLT) {
        //終了
        Serial.println(" End.");
        for(;;);
    }

    //充電
    digitalWrite(PIN_CHRGER, HIGH); digitalWrite(PIN_LED, HIGH);

    //監視
    int n = 0;
    do {
        delay(CHG_MON_TIME);
        Serial.print(">");
        volt = readVolt();
    } while(++n < (CHG_ON_TIME/CHG_MON_TIME) && volt < CHG_UPPER);

    Serial.print(" Voltage after charging: "); Serial.print(volt); Serial.println("mV");
    //
    digitalWrite(PIN_CHRGER, LOW);  digitalWrite(PIN_LED, LOW);
    delay(CHG_OFF_TIME);
}

本回路で充電した充電池を放電して放電量も問題なし

今後の予定

単なる放電器を超えて充電池チェッカーツールになった

今後もしばらくは試行を続け,更に自動化した充電池チェッカープログラムを検討する予定

ニッケル水素充電池の放電時の挙動(追加)

放電テストなどで気付いた点など列挙しておく

  • 新しい充電池は電圧,電流ともに安定して放電される
  • 古い充電池で大容量(500mA以上)は放電できないがある程度の電流(400mA前後)なら長く放電できる
  • 最初は少なめの放電流だが次第に放電流が増えていく古い充電池がある(定電圧放電使用で確認)

ユーティリティ

検索

エントリー検索フォーム
キーワード

新着コメント

Re:SDRplay社RSP1クローンを購入
2025/05/25 from 匿名希望
Re:Mozilla FirefoxではNHKプラスを再生できない件
2025/05/09 from Donabeyaki
Re:ATS-25を作製する
2025/03/23 from kazu
Re:ATS-25を作製する
2025/03/22 from admin
Re:ATS-25を作製する
2025/03/22 from kazu

過去ログ

Feed