侵入者を見つけて教えてくれるはちゅねミクを作ってみた まとめ(仕組み編)

動作概要に続いて仕組みの説明です。動作概要編の記事をお読みになってない方は先にそちらをお読みになることをおすすめします。
今回のシステムを作るにあたって、アナログ回路設計、電子回路設計、マイコン、PCプログラミング、Webプログラミング、電子工作、機械工作と自分の全ての技術を出し切った感があります。現時点ではこれ以上のものは自分には作れませんw

ハードウェア

まずはハードウェアから説明していきます。

電子回路

人感センサには秋月電子で買った焦電型赤外線センサを利用しています。これ単体では検出できる距離があまりにも短いため、一緒に売っていたレンズを付けます。穴径が合わないため、接着剤で固定しました。商品説明を見ると20〜30m先まで検知できるようになるらしいですね。
回路はこのようになっています。アナログ回路をまじめに設計するのは初めてのことだったのでかなりの時間、試行錯誤を繰り返しました。オペアンプには2回路入りのLM358Nを買ってあったので、どうにかオペアンプの使用個数を2個に抑えようと頑張りました。本職の方から見ればひどい回路なのかもしれません^^;

基板を作るときにはこの回路の出力にダイオードを入れてノイズを多く含んでいた0.6V以下の成分をカットしました。
センサの前を人体が通過するとこの回路からこのような波形が出てきます。これをマイコンで読んで何かが通過したのか判断します。この写真ではピーク値がおよそ2.2Vです。

動作テストはブレッドボード上でオペアンプの真横に赤外線センサを置いていたのですが、ケースに組み込む際に導線で延長してセンサと基板の距離を離したところノイズが入ってまともに読み取れなくなってしまいました。
センサ横に増幅回路だけ設置する案も考えましたが、このことをTwitterに書いたところ数名の方からアドバイスを頂きました。ここでセンサ側にパスコンを入れるといいと伺ったので早速試してみたところかなりの改善になりました。パスコンといえばICや電源にだけ付けるものだと思っていたのですが、センサにも付けると有効であることを初めて知りました。


PCとの通信にはUSB-シリアル変換器を使用しました。


PCとの通信、センサ監視、LED制御、ボタン監視、スピーカの駆動、モータ制御などミク側での処理は全てPICマイコンが行っています。今回は使用するピンが12本でAD変換を使う必要があったためPIC16F88を選定しました。ちなみに1つ200円です。こんなに安いのに簡単にいろいろできるとは本当にすごい世の中だと思います。


ブレッドボード上で回路を組み、動作確認を行ないました。

回路図

(9/6)回路図を公開いたしました。必要な方はダウンロードしてご利用ください。→http://d.hatena.ne.jp/rinie/20100906/1283731612

基板は72mm×48mmのものを使用。配置と配線の設計にPCBEを利用しました。本来の使い方ではありませんが、各レイヤ毎に線の色が分かれていることを利用して、導線での配線用に線を引いたりしています。あまりきれいな配線にはできませんでした^^;

はんだ付けには3枚の基板で約6時間ほどかかりました。今後はUEWも使って配線してみたいです。


ICSP(In Circuit Serial Programming)ができるように基板上に端子を設けました。写真下でその端子にPICライタからの線を繋いでPICの書き換えをしています。

カメラ

搭載しているカメラにはLogicoolのC200を使用。Amazonで1,290円でした。
このままではケースに組み込むには大きいので分解して必要な部分だけ取り出しました。ねじを1本外すだけで簡単に分解できました。

レンズ部分を回転させるとピントの調整ができます。

動作機構

地震ミク同様、タミヤの楽しい工作シリーズ シングルギヤボックス(4速タイプ) クリアタイプを使用しています。前回はギア比を12.7:1に設定していましたが、あまりにも低速時の力が弱すぎたため今回は38.2:1に設定しました。これでも動画中の高速ネギ振りの時の速さでモータ出力50%程度です。

筐体

こちらも地震ミク同様透明ケースをひっくり返して使っています。ドリルとやすりでねじ穴やケーブルの穴、赤外線センサレンズ用の穴を開けました。
最初、透明ケースだから問題ないだろうと赤外線センサをケース内部に設置したところ、全く反応しなくて困りました。そこでケースにレンズ分の穴を開け、レンズの頭だけケーズ外に出るようにしたところ問題なく検出できるようになりました。熱を検知しているからケース越しだとだめなんですね。

ファームウェア

続いてPICのプログラムについてです。
動作の流れとしては、

平常時

ボタンを監視

監視待機時

LED点滅、ボタン監視

監視時

センサ値AD変換、ボタン監視

発見待機時

LED点滅、ボタン監視

発見時

モータ用PWM出力、シリアル通信、ボタン監視、音生成

デモモード

モータ用PWM出力、LED制御、ボタン監視


といった感じです。プログラムは約2,100行になりました。
シリアル受信にだけ割り込みを使い、その他ボタンの監視などはポーリングにより行っています。
通信に関しては、PCに対して0か1か2の数値を1バイト送っているだけで、PCからは0か1か2か3か4の数値を1バイト受け取っているだけです。PCとの通信の中身はシンプルなものです。

センサ値のAD変換処理はこのようになっています。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;AD変換処理部
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
adMain
	clrf adSubReg
	call adDo
	call adBeforeCheck

	;AD変換値モニタ用シリアル送信部
	;movfw adBeforeReg
	;movwf sendReg
	;call sendData

	movfw adResultReg
	movwf adBeforeReg
	return

adBeforeCheck
	movfw adBeforeReg
	subwf adResultReg,w			;adResultReg - adBeforeReg
	btfss STATUS,C
	return
	movwf adSubReg
	movlw d'20'				;しきい値幅
	subwf adSubReg,w			;adSubReg - しきい値幅
	btfsc STATUS,C
	goto adDetected
	return

;閾値以上=検知時
adDetected
	bsf adDoResultReg,0
	return

adDo
	movlw d'8'				;平滑化8回。ビットシフトとの兼ね合いもあるため回数変更不可
	movwf adCount
	clrf adResultReg
	clrf adResultTmp

adDoMain
	call adWaitLoop
	call adOn
	movfw ADRESH
	movwf adResultTmp
	bcf STATUS,C
	rrf adResultTmp,f
	bcf STATUS,C
	rrf adResultTmp,f
	bcf STATUS,C
	rrf adResultTmp,w
	addwf adResultReg,f
	decfsz adCount,f
	goto adDoMain
	return

adOn
	movlw b'10000101'
	movwf ADCON0
	btfsc ADCON0,2
	goto $-1
	return
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

赤外線センサの前を人体が通過するとセンサからの出力電圧が変化します。この部分の流れとしては、センサ値を8回読み取った平均値を1セット分とし、1セット前の値と比べて20の差、電圧で言うと390mV(= (5V / 256) * 20)以上変化した場合に人が通過したと判断しています。処理としては毎回の読み取り値を3回左ビットシフトして1/8の値にして8回足すことで8回分の平均値を得ています。


また今回工夫したところとしては、モータを低速で回転させるためにPWMのパルス幅を小さくしていたのですが、それではモータが始動してくれないという問題が起こりました。
そこで、始めに大きいデューティ比でモータに短時間の回転を与え、その小さいデューティ比に切り替えるという方法を使いました。
実際には始めにデューティ比39%で50msecだけPWM波をモータに与え、その後デューティ比16%のPWM波を与えています。

detectIevanStartNoSerialSend
	movlw d'100'				;モータ始動用
	movwf pwmReg
	call pwmOn
	call wait_50ms
	call pwmOff

	movlw d'40'				;Ievanの時のPWMスピード
	movwf pwmReg
	call pwmOn

	goto ievanPlay

以下にプログラム全文を掲載しておきます。→あまりにも長かったため別記事に移動しました。


ソフトウェア

PC側のソフト、プログラムは全てUbuntu 10.04 デスクトップ版で動作しています。

動画配信

今回、動画配信にはLinux向けフリーソフトであるmotionを利用しました。このソフトではカメラからの画像取得はもちろん、配信サーバ機能も付いています。さらに外部アクセスによるスナップショット機能もあります。
ちなみにこのソフト単体で動体検知機能もあるので、これを使えばわざわざ回路を組んでセンサーを載せる必要もなかったのですが、ハード的な検出をしたかったで回路を組みました^^
映像の配信形式はmotion jpegで、サイズは320×240、10fpsで送信しています。iPhoneで見ると大体5fps程度になります。
http://host:8081/のようにアクセスするだけで映像が見れます。またhttp://host:8080/には様々な設定メニューがあり、その中にスナップショット機能もあります。非常に有用なソフトです。

webページ

iPhoneで操作画面を表示していますが、これはiPhoneアプリではなくWebアプリとして実装されています。


始めに作ったページでは自分で作ったボタンのデザインがあまりにも酷かったので、iPhoneのようなトグルスイッチを使いたいと思って探していたところiCheckboxというものを見つけたので使ってみました。
ボタン操作を行うとAjaxによりCGIが実行されます。JavaScriptのライブラリにはjQueryを使いました。Web系は経験がまだまだ浅いので結構苦労しました。

以下のソースコードの一部または全部を利用する場合は個人的な範囲でお願いします。

  • index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
			 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
	<head>
		<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
		<meta name="viewport" content="width = 336 /">
		<title>MIKU-IDAS version 1.0</title>
		<style type="text/css">
		.iCheckbox_container {
			height:27px;
			width:94px;
			position: relative;
			overflow: hidden;
		}
		.iCheckbox_switch {
			height:27px;
			width:94px;
			background-image:url(images/iphone_switch.png); /* your actual slider image */
			background-repeat:none;
			background-position:0px;
		}
		.iCheckbox_checkbox { /* this is kinda moot since it gets hidden, but here to let you know it exists */
		}
		.iCheckbox_two_container {
			height:27px;
			width:94px;
			position: relative;
			overflow: hidden;
		}
		.iCheckbox_two_switch {
			height:16px;
			width:36px;
			background-image:url(images/bpm-lozenge.png); /* your actual slider image */
			background-repeat:none;
			background-position:0px;
		}
		.iCheckbox_two_checkbox { /* this is kinda moot since it gets hidden, but here to let you know it exists */
		}
		/*
		* below are styles to just pretty up the demo page... they have nothing to do with iCheckbox.
		*/
		.body_conts{
			width:800px;
			margin:0px;
			margin-left:auto;
			margin-right:auto;
			font-family:Arial, Helvetica, sans-serif;
			font-size:12px;
		}
		.magic_pink {
			background-color: #FF00FF;
			padding: 5px;
			margin:0px;
		}
		</style>
		<script src="jquery-1.4.2.min.js" type="text/javascript"></script>
		<script src="js.js" type="text/javascript"></script>
		<script src="jquery.iphone-switch.js" type="text/javascript"></script>
		<script src="jquery.iCheckbox.js" type="text/javascript"></script>
		<script type="text/javascript">
		var sw1st = 0;
		var sw2st = 0;
		var firstSt = 0;
		var a = "";
		var autoPush = 0;
		var adOption;
		adOption = location.search;

		// init the checkboxes at dom ready
		$(document).ready( function () {
			/*
			* first example - defaults
			*/
			$('#checkOne').iCheckbox();
			$('#checkOne').change(function(e){
				if ( $('#checkOne').attr('checked') == true ) {
					//console.log('checkbox one checked: '+$(e.target).attr('checked'));
				}
				if(firstSt == 2){
					if(sw1st == 0){
						sw1st = 1;
						if(sw2st == 1){
							autoPush = 1;
							document.all.alert.checkOne2.click();
						}
					}
					else{
						sw1st = 0;
					}

					if(autoPush == 0){			//人間が押した
						if(sw1st == 0){				//元々SW1がオンだった
							$.post("execute/shell/MIKU_IDAS_send.php?mode=none");
						}
						else{										//元々SW1がオフだった
							$.post("execute/shell/MIKU_IDAS_send.php?mode=beep");
						}
					}
					else{
						autoPush = 0;
					}
				}
				else{
					firstSt = 1;
				}
			});

			$('#checkOne2').iCheckbox();
			$('#checkOne2').change(function(e){
				if ( $('#checkOne2').attr('checked') == true ) {
					//console.log('checkbox one checked: '+$(e.target).attr('checked'));
				}
				if(firstSt == 2){
					if(sw2st == 0){
						sw2st = 1;
						if(sw1st == 1){
							autoPush = 1;
							document.all.alert.checkOne.click();
						}
					}
					else{
						sw2st = 0;
					}

					if(autoPush == 0){			//人間が押した
						if(sw2st == 0){				//元々SW2がオンだった
							$.post("execute/shell/MIKU_IDAS_send.php?mode=none");
						}
						else{										//元々SW1がオフだった
							$.post("execute/shell/MIKU_IDAS_send.php?mode=ievan");
						}
					}
					else{
						autoPush = 0;
					}
				}
				else{
					firstSt = 2;
				}
			});
			
			if(adOption == "?autoStartBeep"){
				autoPush = 1;
				sw1st = 1;
				document.all.alert.checkOne.click();
			}
			if(adOption == "?autoStartIevan"){
				autoPush = 1;
				sw2st = 1;
				document.all.alert.checkOne2.click();
			}
		});
		</script>
	</head>
	<body id="mainBody">
		<iframe src="http://192.168.1.5:8081/" width="320" height="240" frameborder="0"></iframe>
		<table border=0>
			<tr valign="top">
				<td>
					<table border=0>
						<tr>
							<td align="middle">
								<div id="btn1"><font size="5">alert1</font><input type="checkbox" name="alert" id="checkOne" /></div>
							</td>
							<td rowspan=2>
								<div id="btn3"><img src="images/camera.png"></div>
							</td>
						</tr>
						<tr>
							<td align="middle">
								<div id="btn2"><font size="5">alert2</font><input type="checkbox" name="alert" id="checkOne2" /></div>
							</td>
						</tr>
					</table>
				</td>
				<td>
					<div id="pic"></div>
				</td>
			</tr>
		</table>

		<br>
		<div id="nowClear"><img src="images/nowClear.png" width="320"/></div>
		<div id="allClear"><img src="images/allClear.png" width="320"/></div>
	</body>
</html>
  • js.js
jQuery(function($){
	var retTime;

	//snapshot
	$("#btn3").click(function () {
		$.ajax({
			async:false,
			url: "execute/snapShotAccess.php",
			cache: false,
			type: "GET",
			success: function(retData){
				retTime = "" + retData;
				retH = retTime.substring(8, 10);
				retM = retTime.substring(10, 12);
				retS = retTime.substring(12, 14);
			}
		});  //ajax end
		
		printtime = retH + "時" + retM + "分" + retS + "秒撮影";

		a = "<a href=\"http://192.168.1.5/motion/" + retTime + "-snapshot.jpg\" target=\"_blank\"><font size=\"4\">" + printtime + "</font></a><br>" + a;
		$("#pic").html(a);
	});  //click end

	$("#nowClear").click(function () {
		if(confirm("本当に解除しますか?")){
			$.ajax({
				async:false,
				url: "execute/shell/MIKU_IDAS_send.php?mode=nowClear",
				cache: false,
				type: "GET",
				success: function(){
					alert("解除されました。");
					$("#mainBody").html("<font size=\"5\">警報は解除されました。<br><br>MIKU-IDAS version 1.0</font>");
				}
			});  //ajax end
		}
	});  //click end

	$("#allClear").click(function () {
		if(confirm("本当に解除しますか?")){
			$.ajax({
				async:false,
				url: "execute/shell/MIKU_IDAS_send.php?mode=allClear",
				cache: false,
				type: "GET",
				success: function(){
					alert("解除されました。");
					$("#mainBody").html("<font size=\"5\">監視状態は解除されました。<br><br>MIKU-IDAS version 1.0</font>");
				}
			});  //ajax end
		}
	});  //click end
});
CGIなど

Ajaxで実行されるCGIについて説明します。と言ってもうまく説明できないのでソースコードだけ書いておきますw動作としてはボタンが操作されるとそれに対応した各プログラムが実行されるだけです。
全てローカルのアドレスで書かれていますが、それを書き換えて適切に設定を行うことで外部からアクセスも可能です。
なおこのシステムはローカルでのみテストを行っています。「とりあえず動けばいい」という考えの元で書いたプログラムなのでセキュリティやコードの安全性について何も考えていません。もしこのソースコードの一部または全部を利用して何か損害が発生したとしてもこちらは一切責任を持ちませんのでご了承下さい。
 さらにシェルスクリプトにバグがあることがわかっています。例えば監視状態を解除したあとはバックグラウンドで動作しているmotionを手動でkillする必要があったり、遠隔解除後に受信用のプログラムが自動では立ち上がらないという問題などがあります。現時点では解決法がわからないため、もし分かる方がいらっしゃったらアドバイスを頂けると非常にありがたいです。

  • MIKU_IDAS_receive.sh:ミク自体の監視開始ボタンを押したらミクからの信号受信のためにこのシェルスクリプトも実行しておかなければなりません。
echo "MIKU-IDAS PC receive program start"
./receiveMain
ret=$?
if [ $ret = -1 ]
then
	echo "serial port or data error"
elif [ $ret = 255 ]
then
	echo "serial port or data error"
else
	echo "serial data received"
	echo "start motion"
	#motion起動
	motion &
	#motionの起動が完了するまで5秒待ってあげる
	./wait5sec
	#snapshot
	echo "take snapshot"
	php ../snapShotAccess.php
	#スナップショットを撮るために念のため1秒待ってあげる
	./wait1sec
	#twitter
	echo "twitter post process start"
	php ../twitter/main.php
	echo "finished"
	#gmail
	echo "mail send process start"
	case $ret in
		0 )
			php ../gmail/main0.php
			echo "gmail send : autoStartNone"
			;;
		1 )
			php ../gmail/main1.php
			echo "gmail send : autoStartBeep"
			;;
		2 )
			php ../gmail/main2.php
			echo "gmail send : autoStartIevan"
			;;
		* ) echo "gmail send process error : receiveMain return value error"
			;;
	esac
	echo "All process finished"
fi
  • wait5(or 1)sec.c:5(or 1)秒待機するプログラムです。
#include <stdio.h>

void main(void)
{
	puts("5 second wait...");
		sleep(5);
	puts("finished");
}
  • receiveMain.c:シリアル受信を行います。受信した数値を戻り値として返します。この記事のリンク先に載っていたソースをほぼそのまま使用しています。
#include<stdio.h>
#include<stdlib.h>
#include<strings.h>
#include<termios.h>
#include<unistd.h>
#include<fcntl.h>

#define BAUDRATE B9600
#define MODEMDEVICE "/dev/ttyUSB0"

int main(void)
{
  int fd, c, res, retVal;
  struct termios oldtio, newtio; /* 通信ポートを制御するためのインターフェイス */
  char buf[255];

  if((fd=open(MODEMDEVICE, O_RDWR | O_RDWR))== -1){

    perror(MODEMDEVICE);
    exit(-1);
  }

  tcgetattr(fd, &oldtio);          /* 現在のシリアルポートの設定を退避させる */
  bzero(&newtio, sizeof(newtio));  /* 新しいポートの設定の構造体をクリア */

  newtio.c_cflag= (BAUDRATE | CS8 | CLOCAL | CREAD);

  newtio.c_iflag=IGNPAR;

  newtio.c_oflag=0;
  newtio.c_lflag=0;

  newtio.c_cc[VTIME]=0;
  newtio.c_cc[VMIN]=1;

  tcflush(fd,TCIFLUSH);           /* ポートのクリア */
  tcsetattr(fd, TCSANOW, &newtio); /* ポートの設定を有効にする */

  read(fd, buf, 1);
  retVal = (int)buf[0];
  printf("received : %d\n", retVal);

	if(retVal == 0){
		puts("autoStart = none");
	}
	else if(retVal == 1){
		puts("autoStart = beep");
	}
	else if(retVal == 2){
		puts("autoStart = Ievan");
	}
	else{
		puts("received value error");
		retVal = -1;
	}

  tcsetattr(fd, TCSANOW, &oldtio);  /* 退避させた設定に戻す */
  close(fd);                       /* COM1のシリアルポートを閉じる */
  return(retVal);
}
  • snapShotAccess.php:スナップショット撮影のためにmotionの特定のページを叩くプログラムです。メール添付用にシェルスクリプト内でも実行されていますが、写真へのリンクを表示するJavaScriptに渡すために撮影時間を戻り値にしています。
<?php
	$ret = file("http://192.168.1.5:8080/0/action/snapshot");
	$time = date("YmdHis");
	echo $time;
?>
  • MIKU_IDAS_send.php:ユーザ側からミクに指示を出す時に使われます。sendMainは引数の数値をシリアルで送信するプログラムです。
<?php
	$input = $_GET["mode"];
	if($input == "none"){
		exec("./sendMain 0");
		echo "input = none";
	}
	else if($input == "beep"){
		exec("./sendMain 1");
		echo "input = beep";
	}
	else if($input == "ievan"){
		exec("./sendMain 2");
		echo "input = ievan";
	}
	else if($input == "nowClear"){
		exec("./sendMain 3");
		echo "input = nowClear";
	}
	else if($input == "allClear"){
		exec("./sendMain 4");
		echo "input = allClear";
	}
	else{
		echo "MIKU_IDAS_send.php input error";
	}
?>
  • sendMain.c:シリアルで引数の数値を送信するプログラムです。
#include<stdio.h>
#include<stdlib.h>
#include<strings.h>
#include<termios.h>
#include<unistd.h>
#include<fcntl.h>

#define BAUDRATE B9600
#define MODEMDEVICE "/dev/ttyUSB0"
#define _POSIX_SOURCE 1 /* POSIX 準拠のソース */
#define FALSE 0
#define TRUE 1

int main(int argc, char *argv[])
{
  int fd, c, res;
  struct termios oldtio, newtio;
  char buf[255];

	if(argc != 2){
		puts("receiveMain input value error");
		exit(-1);
	}

  if((fd=open(MODEMDEVICE, O_WRONLY | O_NOCTTY))== -1){

    perror(MODEMDEVICE);
    exit(-1);
  }

  tcgetattr(fd, &oldtio);          /* 現在のシリアルポートの設定を退避させる */
  bzero(&newtio, sizeof(newtio));  /* 新しいポートの設定の構造体をクリア */

  newtio.c_cflag= (BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD);

  newtio.c_iflag=IGNPAR;

  newtio.c_oflag=0;
  newtio.c_lflag=0;

  newtio.c_cc[VTIME]=0;
  newtio.c_cc[VMIN]=1;

  tcflush(fd,TCIFLUSH);           /* ポートのクリア */
  tcsetattr(fd, TCSANOW, &newtio); /* ポートの設定を有効にする */

  buf[0] = atoi(argv[1]);
  write(fd, buf, 1);
  printf("sent : %d\n", (int)buf[0]);

  tcsetattr(fd, TCSANOW, &oldtio);  /* 退避させた設定に戻す */
  close(fd);                       /* COM1のシリアルポートを閉じる */
  return(0);
}


gmailの送信はPHPMailerを使っています。ダウンロードしたらサンプル内にgmail用のサンプルがあるので利用しました。

  • main0〜2.php:それぞれ自動起動なし、自動起動beep音、自動起動Ievan Polkka用となっています。リンクのクエリ部分がそれぞれでautoStartNone、autoStartBeep、autoStartIevanと変わっているだけです。
<?php
mb_language("japanese");
mb_internal_encoding("UTF-8");

require("class.phpmailer.php");

$body = "<img src=\"http://192.168.1.5/motion/lastsnap.jpg\" height=\"150\"><br>現在の映像を見る場合は以下のURLを<br>クリックしてください。<br><a href=\"http://192.168.1.5/MIKU_IDAS/index.html?autoStartNone\">http://192.168.1.5/MIKU_IDAS/index.html?autoStartNone</a><br><br>MIKU-IDAS version 1.0";

$mailer = new PHPMailer();

$mailer->CharSet = "UTF-8";

$mailer->IsSMTP();
$mailer->Host = 'ssl://smtp.gmail.com:465';
$mailer->SMTPAuth = TRUE;
$mailer->Username = 'yourAddress@gmail.com';  // Gmailのアカウント名
$mailer->Password = 'yourPassword';  // Gmailのパスワード

$mailer->From     = 'yourAddress@gmail.com';  // Fromのメールアドレス
$mailer->FromName = mb_encode_mimeheader(mb_convert_encoding("見張りミク","JIS","UTF-8"));
$mailer->Subject  = mb_encode_mimeheader(mb_convert_encoding("ミクが何かを見つけたようです。","JIS","UTF-8"));
$mailer->MsgHTML($body);
$mailer->AddAddress('yourAddress@yourDomain.jp'); // 宛先

if(!$mailer->Send()) {
   echo "Message was not sent<br/ >";
   echo "Mailer Error: " . $mailer->ErrorInfo;
} else {
		echo "mode : autoStartNone\n";
   echo "Message has been sent\n";
}
?>


Twitterに投稿するプログラムです。この記事で参考にしたページのプログラムを利用させて頂きました。

<?php
require_once("twitteroauth.php");

// Consumer keyの値
$consumer_key = "";
// Consumer secretの値
$consumer_secret = "";
// Access Tokenの値
$access_token = "";
// Access Token Secretの値
$access_token_secret = "";

// OAuthオブジェクト生成
$to = new TwitterOAuth($consumer_key,$consumer_secret,$access_token,$access_token_secret);

// TwitterへPOSTする。パラメーターは配列に格納する
$tweet = "家に侵入者なう。 (" . date("m/d H:i") . ", from MIKU-IDAS) 【侵入者検知システム動作試験中】";

$req = $to->OAuthRequest("https://twitter.com/statuses/update.xml","POST",array("status"=>$tweet));

echo "twitter posted\n";
?>


説明は以上です、最後のプログラム部分はまったく説明できませんでいた。自分でもまだまだ弱い部分です。
見張りミクのシステムについてさらに詳しい説明が必要だったり質問などがありましたらお気軽にコメントやメール、Twitter(@Hayato0o)でご連絡ください。分かる範囲で回答させて頂きます。


長々とありがとうございました!