RaspberryPi
RaspberryPiで高精細電力計を作る
 自宅の消費電力量をリアルタイムに計測するため、RaspberryPiで高精細電力計をつくりました。
 原子力事故以来、省電力がさけばれており、自宅にもリアルタイムにデータをとりだせ、自由にコンピュータに表示可能な電力計を設置し、消費電力を管理していました。しかしながら、実際の電力は瞬間的に変化しいるのに、この機械は10分ごとの平均電力しか計測できず、より細かな記録をしたくなりました。メーカの製品はブラックボックスのため、改良が不可能でしたので、RaspberryPiで一から自作することとしました。

電流センサ
 電力を測定するには、引き込まれている電力線に流れている電流を測定しなければなりません。そのためには資格を持った人による工事が必要です。それに対し電線からもれる磁力線を電流トランス形のセンサーにより補足する方式は、特別の資格無しに電流測定が可能です。電流トランス形のセンサーの原理は、フェライトのリングコアに一次巻線ととして測定電線を貫通させ、二次巻線の負荷抵抗RLの両端に出る電圧Eoを計測することにより、測定電線に流れる電流値Ioを計測するものです。実際の電流センサは、写真のようにリングコアが分割でき、測定電線を挟み込んだあと、閉じるようになっています。
 
電流トランス形のセンサーの原理
(株式会社ユー・アール・ディー
  実際の電流センサ
CTL-10-CLS

 使用した電流センサCTL-10-CLSいろいろなところから入手可能です。次のような特性です。負荷抵抗RLの両端の電圧EoはIoに対し次の式で近似できます。
  Eo = (RL / N) * Io
 ここでNは電流センサーの巻き線比で、このセンサーの場合3000です。たとえば、RL を300Ωとすれば、Io = 10 アンペアの時、Eo = 1 Vとなります。
 http://www.u-rd.com/member/admin/product_image/explain_169_CTL-10-CLS_shutsuryoku.jpg
 CTL-10-CLSの出力電圧特性

 次の課題は、電流センサの出力Eoは交流で、これをどのようにしてデジタル化してパソコンに取り込むかです。またこのセンサは電力の分電盤の内部に設置することになり、その近所にLANケーブルがないため、無線で飛ばす必要があります。いろいろ調べると、つぎの方法が紹介されています。

(1) 電流センサの両端電圧Eo(AC) > ダイオードで整流(DC) > マイコン(Arduino) > 小電力無線Xbee > PC
 ArduinoのかわりにRaspberryPiで実験してみると、Eoの値は、1ボルト程度と小さく、ダイオードの立ち上がり電圧以下で、正確な値を求めることはできませんでした。

(2) 電流センサの両端電圧Eo(AC) > オペアンプでレベル変換 > ADコンバータMCP3204で デジタル化 > RaspberryPi
 これはなかなか良い方法ですが回路が少々複雑。

(3) 電流センサの両端電圧Eo(AC) > ACのままArduinoでサンプリングして読み込み > Xbee > PC
 高速のマイコンArduinoだから可能のようです。

 しかし、RaspberryPiでも適切なADコンバータを用い、C言語でプログラムを書けば、1秒に1000回くらいのサンプリングは可能ではないかと考え、結局もっともハード量の少ないシンプルな次の方式に行き着きました。

(4) 電流センサの負荷抵抗のEo(AC) > ACのままADコンバータでデジタル化 > RaspberryPiでサンプリング > 無線LAN > PC
 サンプリングされた電流値に電圧を掛け合わせ、二乗平均平方根により、電力値を求めます。

A/DコンバータADS1115を用いる
 地震計を作ろうと思い買ってあった16ビット4チャンネルA/DコンバータのADS1115が手元にありましたので、これを用いました。下に述べるように2チャンネルを使います。チップはTI社製ですが、基板にマウントしたものが Adafruit から発売され スイッチサイエンスのサイトから入手できます。データシートはこちら
     
 Adafruit ADS1115    ADS1115ブロック図

 ADS1115は-Vddから+Vddまでのアナログ値を変換し16ビットでI2Cインターフェースに出力します。ADS1115のデータシートをみると、最大毎秒860サンプリングが可能のようで、そのため、交流のままこのADS1115でデジタル化することとしました。
 I2Cインターフェースは雷センサーでも使いましたが、このデバイスのレジスタをRaspberryPiから制御、読み書きするので、しっかりデータシートを読み込む必要があります。かなり、苦労しましたが、思い通りのものができました。
 ADS1115の詳しい使い方はこちら(英語)にあります。
     
 ADS1115のレジスタ(データシートより)  

 ADS1115にはI2Cインターフェースからアクセスする3つのレジスタがあります。今回の設定は次のようにしました。

(1)レジスタにアクセスする場合まずポインタレジスタでレジスタのアドレスを指定します。
ビット[1:0]:0b00で変換レジスタ、0b01で設定レジスタを指定

(2)変換レジスタにはデジタルに変換された値が16ビットのバイナリ2の補数形式で入ります。

(3)もっとも重要なのが16ビットの設定レジスタで、ビットごとに次のように指定します。
ビット[14:12] :電流センサをつなぐ入力チャンネル(MUX)の指定 0b100でチャンネル = 0 0b101でチャンネル = 1
ビット[11:9]:プログラマブルゲインアンプ(PGA)の設定 フルスケール4.096Vの場合0b001
ビット[8]:連続変換モードを使います 0b0
ビット[7:5]:データレート(DR)を指定 毎秒のサンプリング速度SPS=860を指定します 0b111
ビット[4:0]:デフォルト値のまま使います

Cによるプログラム
高速サンプリングを行うため、プログラムはC言語で作ります。サンプルコードを参考にしました。(箇条書きはコメントに対応)

(1) RaspberryPiにはi2c-devライブラリが用意されていますので、includeしておきます。これによりI2Cインターフェースがファイルとして扱えるようになります。

つぎに2つの関数を作ります。
(2) set_config_register関数は設定レジスタをセットする関数。muxで入力チャンネル、pgaでプログラマブルゲインアンプを、drでサンプリングレートを指定します。

(3) read_current_rms関数は変換レジスタをよみとり、2の補数形式を変換し電圧値を得、さらに上記変換式で電流値を算出します。これをサンプリング数NUMBER回繰り返し、二乗平均平方根値を計算し返します。サンプル数NUMBERを適当に選び、1/2秒ごとに結果を返すようにします。

(4) mainではwhileで、(2)(3)の関数をチャンネル0とチャンネル1にたいし実行し、1秒ごとの無限ループとします。

(5) 1秒に1レコードを出力します。CSV形式で時刻,チャンネル0のワット数,チャンネル1のワット数が出力されます。たとえば
2015/06/26 00:00:09, 88.484291, 175.642396
ファイル名はたとえば 20150626wattmeter.txt
のように1日に1ファイル作ります。

 ワットメータ  wattmeter.c
/*ワットメータ
* 2015/06/19 (C) H.Ishikawa
*/

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <math.h>			//pow sqrt
#include <sys/types.h>		// open
#include <sys/stat.h>		// open
#include <fcntl.h> 			// open
#include <unistd.h>			// read/write usleep
#include <stdlib.h>			// exit
#include <inttypes.h>		// uint8_t, etc
#include <linux/i2c-dev.h> 	// (1) I2C bus definitions

//(2)
void set_config_register(int I2CFile, uint8_t registerByte[],int mux, int pga, int dr);
//(3)
double read_current_rms(int I2CFile, uint8_t registerByte[], double FS, int N, double R);

int main() {
	
	time_t timer;
	struct tm *date;
	char date_time[256];
	char year_date[256];
	uint8_t registerByte[3];	// I2C register 3バイトト
	int I2CFile;
	double i_rms0;
	double i_rms1;
	
	int ads_address = 0x48;	//I2Cデバイスアドレス ADDR端子をグランドに接続した場合
	int mux = 0b000;		//入力端子の指定 0b100でAIN = 0 0b101でAIN = 1
	int pga = 0b001;		//PGA値 0b001,0b010,0b011,0b100のいずれか	
	int dr = 0b111;			//データレート860SPSの場合
	double R = 300;			//電流センサーの負荷抵抗値(Ω)
	int N = 3000;			//電流センサーの巻き線比
	double FS;				//フルスケール値
	if (pga >= 0b001 & pga <= 0b100){
		FS = 4.096 / pow(2.0 , pga -1);//PGAからフルスケール値に変換
	}else{
		printf("Error: Couldn't convert to FS! \n");
		return 1;
	}
	
	// /dev/i2c-1 のI2Cデバイスを開く
	if ((I2CFile = open("/dev/i2c-1", O_RDWR)) < 0) {
		printf("Error: Couldn't open device! %d\n", I2CFile);
		return 1;
	}
	// ads1115 をスレーブモードに設定
	if (ioctl(I2CFile, I2C_SLAVE, ads_address) < 0) {
		printf("Error: Couldn't find device on address!\n");
		return 1;
	}
  
	//タイマー設定
	timer = time(NULL);  
	strftime(date_time, 255, "%Y/%m/%d %H:%M:%S", localtime(&timer));  	
	printf("measurement start %s\n",date_time);
	
	while (1){ //(4)無限ループ
		//channel 0
		mux = 0b100;//AIN = 0
		set_config_register(I2CFile, registerByte, mux, pga, dr);
		i_rms0 = read_current_rms(I2CFile, registerByte,  FS,  N, R);
		
		//channel 1
		mux = 0b101;//AIN = 1
		set_config_register(I2CFile, registerByte, mux, pga, dr);
		i_rms1 = read_current_rms(I2CFile, registerByte,  FS,  N, R);
					
		//(5)ファイル出力 1日1本
		timer = time(NULL);  				
		strftime(year_date, 255, "%Y%m%d", localtime(&timer));
		char filename[256] = "wattmeter/";   
		strcat( filename, year_date );
		strcat( filename, "wattmeter.txt" );
		FILE *fp;
		char *fname = filename;		
		fp = fopen( fname, "a" ); //追記形でオープン
		strftime(date_time, 255, "%Y/%m/%d %H:%M:%S", localtime(&timer)); 
		fprintf( fp ,"%s, %.6f, %.6f\n",date_time, i_rms0 * 100.0 , i_rms1 * 100.0);//電圧は100vとしワット数を計算
		printf( "%s, %.6f, %.6f\n",date_time, i_rms0 * 100.0 , i_rms1 * 100.0);
		fclose( fp );

	}
	close(I2CFile);

	return 0;
}

//(2)
void set_config_register(int I2CFile, uint8_t registerByte[],int mux, int pga, int dr) {

	registerByte[0] = 1;						// 変換レジスタ を指定
	registerByte[1] = 0x80 | mux<<4 | pga<<1 ;	//変換レジスタの上位バイトに、mux,pgaを設定
	registerByte[2] = 0x03 | dr<<5 ;			//変換レジスタの下位バイトに、データレート設定
	write(I2CFile, registerByte, 3);			// 変換レジスタに書き込み
}

//(3)
double read_current_rms(int I2CFile, uint8_t registerByte[], double FS, int N, double R) {
	int NUMBER = 1400;		//サンプリング数 クロックの速いCPUの場合は変更必要
	double sum = 0.0;		//二乗和
	int data = 0;
	int val;
	double e;
	double i;
	registerByte[0] = 0;					// 変換レジスタ を指定
	write(I2CFile, registerByte, 1);
	while (data < NUMBER ){   
		read(I2CFile, registerByte, 2); 	// 変換レジスタを読み込み			
		val = ((registerByte[0] + 128) % 256 -128) * 256 + registerByte[1];	//2の補数形式を変換
		e = (double)val * FS / 32768.0;	//2次側電圧値
		i = e * (double)N / R;			//巻き線比と抵抗値から1次側電流値を求める
		sum = sum + pow(i , 2.0);
		data = data + 1;
	}
	return ( sqrt(sum / (double)data));//二乗平均平方根
}		
	

本番設置
 分電盤にこの電流センサを設置します。一般家庭の電力引き込み線は、「単相3線式」が用いられています。単相3線式では、電圧のかからない接地された中性線と、両端の端子から位相が逆の対地電圧100Vの電圧がかかった電圧線2本とを引き出し、電圧線同士を接続して200V負荷に、電圧線と中性線を接続して100V負荷に供給することができます。
 自宅の分電盤を見てみましょう。分電盤のパネルを取り外すと、写真のように、アンペアブレーカーと漏電遮断器のあいだに、赤、白、黒の3線があります。これが単相3線です。白の線は中性線です。家の消費電力を測定するには、赤と黒の線に流れる電流をそれぞれ測定し、その合計を計測しなければなりません。写真のように、赤の線と黒の線に一つずつ電流センサを取り付けてあります。

 
「単相3線式100ボルト/200ボルト」の配線図
東京電力のホームページより(使用機器は当方と異なる)
  分電盤に電流センサを取り付ける
(赤丸)

 ADS1115を実装した小さい基板をつくります。接続は次の通りです。ADDR端子をグランドに接続すること。これによりI2Cデバイスアドレスが0x48に設定されます。
 ADS1115        RaspberryPi      入力
 VDD    3.3v (pin 1)     
 GND    GND    
 SCL    SCL (pin 5)     
 SDA    SDA (pin 3)     
 ADDR    GND    
 A0        チャンネル0
 A1        チャンネル1

この基板をRaspberryPiのGPIO端子にマウントします。ケースに入れUSB端子にWiFiアダプタを接続し分電盤のそばに設置します。2つの電流センサは、それぞれチャンネル0、チャンネル1に接続します。
   
ADS1115を実装した小さい基板
  左のコネクタに2つの電流センサを接続
小さい基板はいろいろ実験したので、回路図と一致しない
   
   
 分電盤のそばに設置
書斎まで無線LANで飛ばす
 


(1) RaspberryPiでI2Cインターフェースを使えるようにします。こちらです。

(2) RaspberryPiでWiFiが使えるようにします。こちらです。

(3) うえのプログラムを、Raspberry Pi上にwattmeter.cというなまえで保存し、コンパイルします。たとえば
$ gcc wattmeter.c -o wattmeter.exe -lm

(4) RaspberryPiで複数のセッションを動作させるために、GNU screenを使えるようにします。screenを使うと、プロセスを動作させたまま接続を切断したり、複数のセッションを起動することが可能です。
インストールはつぎによります。
$ sudo apt-get install screen

(5) 実行します。
$ screen
screenのグリーティングメッセージのあとreturnを入力し
$ sudo wattmeter.exe
でワットメータプログラムを実行します。
RaspberryPiのwattmeterディレクトリの中に20150626wattmeter.txtのようなCSV形式のファイルが1日に1本(約3.7メガバイト)できます。時々、本体に移すなど、ファイルの整理をしたほうがよろしい。心配したCPUの使用率は14%程度でした。


パソコンでの処理
 RaspberryPiに出来ているファイルを親PCから定期的に読みに行き、gnuplotで作図します。たとえば19時から21時までの2時間分をグラフ化したものをを以下に示します。

 1秒ごとの使用電力量変化をみることができます。今回初めて細かなスパイク状の変動があることがわかりました。夕方ですので、照明やテレビの消費電力がベースで、そのほかに19時30分頃の変化は湯沸かしポット、周期的なスパイクはIHI炊飯器の保温です。このほかウォシュレットの保温、テレビの待機電力など意外なところで電気を消費しているのが、明白になりました。これをみながらどの器機が電気を食っているか下手人探しを行い、省エネにつとめることといたします。

お断り
セキュリティ対策のため、測定結果をWebへのリアルタイム表示は行っていません。