3.ソフトウェア(パソコン制御ニッケル水素電池充放電器の製作)

3.1.プリンターポート制御
3.2.漏れ電流対策
3.3.満充電検出
3.4.放電終了検出

3.1.プリンターポート制御

この充電器で独自に決めたピン割り当て、および、(一般的な話の)レジスタとの対応は、以下のようになっています。
(I/Oは、パソコンから見てです。また、反転、というのは、ビットONで電圧がL、ビットOFFで電圧がHになるものです。
また、「xxxxの返し」というのは、パルスで指示したDAコンバーターの電圧より、測定対象の電圧が大きい場合に、電圧がHとして返ってくる、ということです。)

I/O 意味 レジスタ レジスタビット位置 反転
1 O マルチプレクサ、端子Aへの指示 CTRL 反転
2 O 放電、スロット0 DATA 0
3 O 放電、スロット1 DATA 1
4 O 放電、スロット2 DATA 2
5 O 放電、スロット3 DATA 3
6 O 充電、スロット0 DATA 4
7 O 充電、スロット1 DATA 5
8 O 充電、スロット2 DATA 6
9 O 充電、スロット3 DATA 7
10 I 温度測定電圧の返し STAT 6
11 I 基準電圧2.5Vの返し STAT 7 反転
12 I 放電電流測定電圧の返し STAT 5
13 I 充電電流測定電圧の返し STAT 4
14 O マルチプレクサ、端子Bへの指示 CTRL 2 反転
15 I 電池電圧の返し STAT 3
16 O DAコンバーターカウンタパルス CTRL 3
17 O ATX電源ON CTRL 4 反転

プログラムとしては、CTRLレジスタ、DATAレジスタに対して書き込み、STATレジスタを読み込むことになります。
例えば、freebsdの場合の、充放電指示のプログラムは以下のような感じになります。

    /* デバイスのオープン */
    fd = open( "/dev/ppi0", O_RDWR );

    /* 充放電指示 */
    dt = 0;
    if ( slot0 放電 ) dt = dt | 0x01;
    else if ( slot0 充電 ) dt = dt | 0x10;
    if ( slot1 放電 ) dt = dt | 0x02;
    else if ( slot1 充電 ) dt = dt | 0x20;
    if ( slot2 放電 ) dt = dt | 0x04;
    else if ( slot2 充電 ) dt = dt | 0x40;
    if ( slot3 放電 ) dt = dt | 0x08;
    else if ( slot3 充電 ) dt = dt | 0x80;
    ret = ioctl( fd, PPISDATA, &dt );

3.2.漏れ電流対策

漏れ電流の現象は、こんなグラフを見てもらえばわかるかな。

27秒充電、3秒停止、という設定で、充電終了判定がバグってる状態のグラフです。

55分のところで、赤色の電池の判定に失敗してることがわかって、電池を抜きました。
同じく、59分あたりで、黄色の電池を抜いて、63分あたりで緑の電池を抜きました。
なので、充電終了を見極めた補正が動いてない状態でのグラフです。

問題としては、2つあります。

問題1:電池を抜いたところで、他の電池の測定電圧が下がってますよね。
     これ自体は、−ΔVの検出を妨げてしまうので、なんとかしなきゃいけません。
問題2:測定されて表示されてる電圧が、高めに表示されています。

問題1について

単純に、ある電池の充電が終わると、他の電池について、前回の測定値との差分で下駄を履かせることにしました。
とりあえずは、これで問題なしです。(前回の値の測定で誤差があれば、もろに効いてくる可能性があるので、本来は、しばらく様子を見たあと、統計的処理を加えるのが、正しいと思いますが、これ、かなりプログラムが複雑になってしまうとか、生中継できなくなるとかいう問題があるので。)

問題2について

これについては、充電開始時に、
  対象電池だけ充電しているときの対象電圧を測定(V1)
  他の電池もすべてを充電しているときの対象電圧を測定(V2)
として、−(V2−V1)×(電池本数−1)÷(電池本数)

という下駄をはかせることにしました。(電池本数−1)÷(電池本数)のところは、、、ちょっと根拠が怪しいが、、、ちょっと、実験式です。ええっと、根拠は、その電池自体の充電回路の影響を受けていると思う(マルチプレクサの漏れ電流の影響ではなく、充電回路との分離ができてないのが原因と思うので、、、といった程度です。
ま、とりあえずは、うまく補正できてるように思います。少なくとも、私が持ってる、貧弱なテスターで測定できる精度では、うまく補正できてます。(てか、俺が持ってるテスターの精度が悪すぎ(笑))。

以上の問題は、6月1日に、ほぼすべて解決しました。
詳しくは、測定誤差との戦い解決編を、、、

3.3.満充電検出

基本的に、電池の温度、電池の電圧を使用しますが、温度は、最終的な危険回避という意味でしか使用しません。
もっぱら、電圧の測定が中心になります。
というのは、いろいろと実験を繰り返すうちに、電池の電圧のほうが素直に電池の状況をあらわすことが解ってきたからです。
もちろん、単純に値だけ見てると、温度のほうが、敏感ですが、、、値だけみるのではなく、、、というのは、以下に書きます。
(ま、そんなことがわかったのは、温度を測定していたから、なのですが。)

一般的に、充電のグラフは以下のようになります。

充電初期は、充電中電圧休止時電圧ともに、急速に電圧が上昇します。
しばらくすると、電池によっては、充電中電圧がピークを迎えます。これを、偽ΔVといいます。この偽ΔVが検出されても、無視しなくてはいけません。
満充電が近くなってくると、充電中電圧、充電休止時電圧ともに、急上昇します(*1)。
これと同時に、充電されたのを「逃す」反応が起こり、電池の温度が上昇してゆきます。電池の温度が上昇すると、電池の内部抵抗が下がるため、充電中電圧が下がろうとします(*2)。

で、*1と、*2は、平衡に達すると、充電中電圧が本当に下がります。これを、−ΔVといい、一般的な充電器が、検出につかっている方法です。

余談ですが、、私が測定した範囲では、充電休止時電圧が、−ΔVを検出することはありませんでした。

で、以上は、一般論なのですが、せっかくパソコンまで使って大げさに充電しているんだから、図中の、変曲点を、検出して、満充電、としようという企画です。早めに満充電を検出するのは、電池の寿命を延ばすことになり、一般的に500回といわれてる寿命を、何倍にも延ばすことになると思います。(ちなみに、500回が1000回になった、、、なんてのを測定するのは、仕事でもないので、無理なんですけどね(笑)。

で、ソフトウェアとしての具体的な動きは以下の通りです。
  過去120回分のデータを使い、最小二乗法を使い、傾きを計算する。
  傾きの、最大値を保持しておく。
  傾きが、これまでの傾きの最大値より、20mV/h 少なくなったら、変曲点を検出、満充電とする。

  なお、傾きの最小値も保持しており、これを下回ると、傾きの最大値をリセットします。
  つまり、傾きが減少している間は、上記の検出はおこなわれません。これで偽ΔVを無視することにもなります。
  なお、充電休止時電圧が、1.5V以上になると、傾きの最大値をリセットする操作はおこなわれません。
  これは、満充電に近い電池を、充電しようとした場合の対策です。

なお上記中の数値は、チューニング中で、充電実行時に、設定できるようになっています。

3.3.放電終了検出

これは、、、書くまでもないけど、1.0Vを下回ると、放電を停止するようになっています。