title


Raspberry Pi
[赤外線センサー映像送信システム][English]
system
 
[構成]
connect
Raspberry Pi2
USB電源KSY UB310-0520
ケース
USBカメラC270
USB無線LANWLI-UC-G301N
USBハブU2H-TZ420SBK
赤外線センサーHC-SR501
ジャンパワイヤメス-メス 10cm 3本

 
[機能概要]
  • 赤外線センサーで、人体検出します。
  • 検出次第、カメラで一定期間ムービーを保存します。
  • 保存したAVI形式ファイルを、ガラケーの3gp形式ファイルに変換します。
  • 変換したファイルをメールで送信します。
これで、自宅の防犯や家族の帰宅の様子を確認することが出来ます。
 
[Raspbian設定]
  • SDカードにOSを入れます。約4.7GB使うので、8GB以上のカードが必要。
    Raspberry Pi FoundationのDOWNLOADSから、RASPBIANのイメージファイルをダウンロードして、Win32DiskImagerでSDカードへ書き込みます。
  • まずはLANケーブルでネットにつなげで起動し、HDMIケーブルでTV画面、USBマウス、USBキーボードで操作します。
  • Config画面が出たら、Expand Filesystemを選択してSDカードサイズ分の領域を使えるようにします。
  • Change User Passwordでパスワードを設定します。
  • Internationalization OptionsでAsia-Tokyoを選択します。
  • Advanced Optionsから、SSHをEnableにしてLAN経由でパソコンからアクセスできるようにします。
  • Finishを選択してリブートします。
[リモート設定]
  • Raspberry Pi本体側で、ifconfigコマンドでinet addrにあるIPアドレスを確認します。
  • パソコンにTeraTermなどの端末ソフトをインストールします。
  • 端末ソフトで、IPアドレスを入力し、IDはpi、Password入力して接続します。
[FTPサーバ設定]
  • パソコンでムービーを確認したいため、FTPサーバを入れます。vsftpdをインストールします。インストール前にupdateとupgrade実施しておきます。
    pi@raspberrypi ~ $ sudo apt-get update
    (省略)
    pi@raspberrypi ~ $ sudo apt-get upgrade
    (省略)
    pi@raspberrypi ~ $ sudo apt-get install vsftpd
    (省略)
  • /etc/vsftpd.confを以下変更します
    anonymous_enable=NO
    local_enable=YES
    write_enable=YES
    local_umask=022
    ascii_upload_enable=YES
    ascii_download_enable=YES
    chroot_local_user=YES
    chroot_list_enable=YES
    chroot_list_file=/etc/vsftpd.chroot_list
  • /etc/vsftpd.chroot_listを作成して1行だけユーザー名追加。デフォルトユーザー名ならpiの2文字だけ追加。
  • リスタート&リブート
    pi@raspberrypi ~ $ sudo service vsftpd restart
    Stopping FTP server: vsftpd.
    Starting FTP server: vsftpd.
    pi@raspberrypi ~ $sudo reboot
[USBカメラ設定]
  • Raspberry PiのUSB電源供給が弱いため、USBカメラは電源付きのUSBハブ経由でつなぎます。直接つなぐと、撮影した瞬間にUSB接続が切れて再接続するなど、不安定になることがあります。
  • lsusbコマンドで接続を確認します。
    Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
    Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
    Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp.
    Bus 001 Device 004: ID 05e3:0608 Genesys Logic, Inc. USB-2.0 4-Port HUB
    Bus 001 Device 005: ID 1c4f:0027 SiGma Micro
    Bus 001 Device 006: ID 046d:0825 Logitech, Inc. Webcam C270
    Bus 001 Device 007: ID 093a:2510 Pixart Imaging, Inc. Optical Mouse
    それらしいものがあれば認識してる。
  • fswebcamをインストール
    pi@raspberrypi ~ $ sudo apt-get install fswebcam
    (省略)
  • fswebcamで撮影してみる。
    pi@raspberrypi ~ $ fswebcam test.jpg
    --- Opening /dev/video0...
    Trying source module v4l2...
    /dev/video0 opened.
    No input was specified, using the first.
    Adjusting resolution from 384x288 to 352x288.
    --- Capturing frame...
    Corrupt JPEG data: 1 extraneous bytes before marker 0xd6
    Captured frame in 0.00 seconds.
    --- Processing captured image...
    Writing JPEG image to 'test.jpg'.
    Corrupt JPEG dataとか出てますが画像は撮れてます。
  • C270では2回目以降に以下のようなエラーが出ますが、rebootするとなぜかそれ以降は問題なくなります。
    Unable to find a compatible palette format.
  • FFFTPなどのftpソフトを使ってpiから撮った画像をパソコンで確認。
[USB無線LAN設定]
  • 電源付きのUSBハブ経由でつなぎます。lsusbで接続確認。
    pi@raspberrypi ~ $ lsusb
    Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
    Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
    Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp.
    Bus 001 Device 004: ID 05e3:0608 Genesys Logic, Inc. USB-2.0 4-Port HUB
    Bus 001 Device 005: ID 1c4f:0027 SiGma Micro
    Bus 001 Device 008: ID 0411:016f BUFFALO INC. (formerly MelCo., Inc.) WLI-UC-G301N Wireless LAN Adapter [Ralink RT3072]
    Bus 001 Device 006: ID 046d:0825 Logitech, Inc. Webcam C270
    Bus 001 Device 007: ID 093a:2510 Pixart Imaging, Inc. Optical Mouse
  • WiFiソフトwpa_supplicantの設定をします。/etc/_supplicant/_supplicant.confを編集。詳細は公式サイト
    ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
    update_config=1
    
    network={
            ssid="接続するWIFIルータのID"
            #psk="xxxxxxxxxxxxxxx"
            psk=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
            proto=RSN
            key_mgmt=WPA-PSK
            pairwise=CCMP
            auth_alg=OPEN
    }
  • パスワードpskの部分は以下コマンドで作成。
    pi@raspberrypi ~ $ wpa_passphrase abcdef0123 abcdef0123
    network={
            ssid="abcdef0123"
            #psk="abcdef0123"
            psk=36dffc3bde1f01ef91d3ad5a92929b740abff208e6f09b69a09d345cde445d81
    }
  • ネットワークの設定をします。/etc/network/interfacesを編集。詳細はDebian Wiki
    auto wlan0
    
    iface lo inet loopback
    iface eth0 inet dhcp
    
    allow-hotplug wlan0
    iface wlan0 inet static
    address 192.168.1.xx
    netmask 255.255.255.0
    gateway 192.168.1.1
    dns-nameservers 192.168.1.1
    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
  • リブートしてリモート接続を確認します。
  • ただ、WiFiは何日も連続稼働しているとたまに切れることがあり、この方法だと切れたら切れたままで困ってしまうので、wicdを使って自動で復帰するようにしました。その場合こういう設定はすべて不要で、設定はPC同様にGUI上で設定します。wicdもDebian Wiki。少しとまどうのは、ケーブル接続とワイヤレス接続を併用できないところで、ケーブル接続のVNC経由でリモートでワイヤレス接続開始すると、その瞬間にネットワークが切れます。
[OpenCV設定]
  • OpenCVは画像処理のライブラリです。顔検出してお面の画像をかぶせるとかも出来ますが、Raspberry Piでは処理が遅すぎて映像として表示させるのは無理がありました。opencv.orgのInstallation in Linuxに従って作業します。libtbb2等のoptionalは無いといわれるので消してます。
    pi@raspberrypi ~/opencv $ sudo apt-get install build-essential
    (省略)
    pi@raspberrypi ~/opencv $ sudo apt-get install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev
    (省略)
    pi@raspberrypi ~/opencv $ sudo apt-get install python-dev python-numpy
    (省略)
  • opencv.orgには記載ありませんが、libv4l-devもインストール必要なのでインストール。
    pi@raspberrypi ~/opencv $ sudo apt-get install libv4l-dev
    (省略)
  • OpenCVソースコードを取得します。
    pi@raspberrypi ~ $ git clone https://github.com/Itseez/opencv.git
    Cloning into 'opencv'...
    remote: Counting objects: 176319, done.
    remote: Compressing objects: 100% (6/6), done.
    remote: Total 176319 (delta 2), reused 2 (delta 2), pack-reused 176311
    Receiving objects: 100% (176319/176319), 431.51 MiB | 3.20 MiB/s, done.
    Resolving deltas: 100% (119549/119549), done.
    Checking out files: 100% (4656/4656), done.
  • 取得したソースのディレクトリにreleaseディレクトリ作成し、cmake実行します。
    pi@raspberrypi ~/opencv $ mkdir release
    pi@raspberrypi ~/opencv $ cd release/
    pi@raspberrypi ~/opencv/release $ cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local ..
    最後の「..」は「続くけど省略するので自分で調べろ」ではなく「1つ上のディレクトリ」です。ハマりました。
  • 最後に出てくるconfigurationは下記。いろいろnot foundやfailedなどありますが、ここで作るプログラムでは支障ないです。
    -- General configuration for OpenCV 3.0.0-dev =====================================
    --   Version control:               3.0.0-1-g424c2bd
    --
    --   Platform:
    --     Host:                        Linux 3.18.11-v7+ armv7l
    --     CMake:                       2.8.9
    --     CMake generator:             Unix Makefiles
    --     CMake build tool:            /usr/bin/make
    --     Configuration:               RELEASE
    --
    --   C/C++:
    --     Built as dynamic libs?:      YES
    --     C++ Compiler:                /usr/bin/c++  (ver 4.6.3)
    --     C++ flags (Release):         -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fvisibility=hidden -fvisibility-inlines-hidden -O3 -DNDEBUG  -DNDEBUG
    --     C++ flags (Debug):           -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fvisibility=hidden -fvisibility-inlines-hidden -g  -O0 -DDEBUG -D_DEBUG
    --     C Compiler:                  /usr/bin/gcc
    --     C flags (Release):           -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fvisibility=hidden -O3 -DNDEBUG  -DNDEBUG
    --     C flags (Debug):             -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fvisibility=hidden -g  -O0 -DDEBUG -D_DEBUG
    --     Linker flags (Release):
    --     Linker flags (Debug):
    --     Precompiled headers:         YES
    --     Extra dependencies:          dl m pthread rt
    --     3rdparty dependencies:
    --
    --   OpenCV modules:
    --     To be built:                 hal core flann imgproc ml photo video imgcodecs shape videoio highgui objdetect superres ts features2d calib3d stitching videostab python2
    --     Disabled:                    world
    --     Disabled by dependency:      -
    --     Unavailable:                 cudaarithm cudabgsegm cudacodec cudafeatures2d cudafilters cudaimgproc cudalegacy cudaobjdetect cudaoptflow cudastereo cudawarping cudev java python3 viz
    --
    --   GUI:
    --     QT:                          NO
    --     GTK+ 2.x:                    YES (ver 2.24.10)
    --     GThread :                    YES (ver 2.40.0)
    --     GtkGlExt:                    NO
    --     OpenGL support:              NO
    --     VTK support:                 NO
    --
    --   Media I/O:
    --     ZLib:                        /usr/lib/arm-linux-gnueabihf/libz.so (ver 1.2.7)
    --     JPEG:                        libjpeg (ver 90)
    --     WEBP:                        build (ver 0.3.1)
    --     PNG:                         /usr/lib/arm-linux-gnueabihf/libpng.so (ver 1.2.49)
    --     TIFF:                        build (ver 42 - 4.0.2)
    --     JPEG 2000:                   build (ver 1.900.1)
    --     OpenEXR:                     build (ver 1.7.1)
    --     GDAL:                        NO
    --
    --   Video I/O:
    --     DC1394 1.x:                  NO
    --     DC1394 2.x:                  NO
    --     FFMPEG:                      YES
    --       codec:                     YES (ver 54.35.0)
    --       format:                    YES (ver 54.20.4)
    --       util:                      YES (ver 52.3.0)
    --       swscale:                   YES (ver 2.1.1)
    --       resample:                  NO
    --       gentoo-style:              YES
    --     GStreamer:                   NO
    --     OpenNI:                      NO
    --     OpenNI PrimeSensor Modules:  NO
    --     OpenNI2:                     NO
    --     PvAPI:                       NO
    --     GigEVisionSDK:               NO
    --     UniCap:                      NO
    --     UniCap ucil:                 NO
    --     V4L/V4L2:                    Using libv4l1 (ver 1.0.0) / libv4l2 (ver 1.0.0)
    --     XIMEA:                       NO
    --     Xine:                        NO
    --     gPhoto2:                     NO
    --
    --   Other third-party libraries:
    --     Use IPP:                     NO
    --     Use Eigen:                   NO
    --     Use TBB:                     NO
    --     Use OpenMP:                  NO
    --     Use GCD                      NO
    --     Use Concurrency              NO
    --     Use C=:                      NO
    --     Use pthreads for parallel for:
    --                                  YES
    --     Use Cuda:                    NO
    --     Use OpenCL:                  YES
    --
    --   OpenCL:
    --     Version:                     dynamic
    --     Include path:                /home/pi/opencv/3rdparty/include/opencl/1.2
    --     Use AMDFFT:                  NO
    --     Use AMDBLAS:                 NO
    --
    --   Python 2:
    --     Interpreter:                 /usr/bin/python2.7 (ver 2.7.3)
    --     Libraries:                   /usr/lib/libpython2.7.so (ver 2.7.3)
    --     numpy:                       /usr/lib/pymodules/python2.7/numpy/core/include (ver 1.6.2)
    --     packages path:               lib/python2.7/dist-packages
    --
    --   Python 3:
    --     Interpreter:                 /usr/bin/python3 (ver 3.2.3)
    --
    --   Python (for build):            /usr/bin/python2.7
    --
    --   Java:
    --     ant:                         NO
    --     JNI:                         NO
    --     Java wrappers:               NO
    --     Java tests:                  NO
    --
    --   Matlab:
    --     mex:                         NO
    --
    --   Documentation:
    --     Doxygen:                     NO
    --     PlantUML:                    NO
    --
    --   Tests and samples:
    --     Tests:                       YES
    --     Performance tests:           YES
    --     C/C++ Examples:              NO
    --
    --   Install path:                  /usr/local
    --
    --   cvconfig.h is in:              /home/pi/opencv/release
    -- -----------------------------------------------------------------
  • makeします。時間かかります。3時間ほど。
    pi@raspberrypi ~/opencv/release $ make
    Scanning dependencies of target libtiff
    [  0%] Building C object 3rdparty/libtiff/CMakeFiles/libtiff.dir/tif_aux.c.o
    .
    (省略)
    .
    [100%] Built target opencv_annotation
  • インストールします。
    pi@raspberrypi ~/opencv/release $ sudo make install
    (省略)
[FFMPEGインストール]
  • コーデック変換で使います。
    pi@raspberrypi ~ $ sudo apt-get install ffmpeg
    (省略)
[メインプログラム]
  • 赤外線センサーは、VCC/GNDと、信号はGPIO4(ピン番号7)に接続しています。制御はeLinux-RPi Low-level peripheralsから持ってきてます。
  • 監視プログラムとして実行しっぱなしにするため、daemon()でデーモン化し、出力ファイルのディレクトリもchdir()で直接指定します。ログはsyslog()を使います。ただし最初からデーモン化するとデバッグしづらいので、動作を確認出来た後、最後に入れます。
  • どこでキャッシュされているのか不明ですが、VideoCaptureの最初の数フレームに前回の残り映像が入るため、ダミーReadを入れています。
  • 監視中はUSBカメラ映像は取得せず、100mSスリープでループさせます。赤外線センサー検出次第、スリープ無しで録画開始します。
  • プログラムの実行時間だけで時間がとられるため、うちの環境(たぶんRPi2なら同じと思いますが)で8fps程度です。cvGetTickCount関数でループ1回分の時間を調べることが出来ます。8fpsの設定で、一旦AVI形式のMP42コーデックでファイル保存します。
  • AVI形式ファイルを、ffmpeg(avconv)でDocomo 3gp形式へ変換し、スクリプト実行でメール送信します。
  • 記録するフレーム数は約15秒程度、また、玄関で何か作業するケースを考慮して、連続して1分間赤外線センサーが非検出になるまで、次の記録を開始しないようにします。また、誤検出を繰り返すのを考慮して記録する回数に制限をつけます。
  • 朝は検出しても無視するようにします。深夜も暗視カメラではないので無視します。
  • ソースコード
    #include <iostream>
    #include <string>
    
    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <time.h>
    #include <sys/time.h>
    #include <sys/mman.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <syslog.h>
     
    #define BCM2708_PERI_BASE        0x3F000000
    #define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
    #define PAGE_SIZE (4*1024)
    #define BLOCK_SIZE (4*1024)
    #define MOVIEFPS 8
    #define MAXMOVIENUM 5
    #define MOVIETIME 100
    #define DETECTINT 600
    
    using namespace std;
    using namespace cv;
    
    int  mem_fd;
    void *gpio_map;
    // I/O access
    volatile unsigned *gpio;
     
    // GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
    #define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
    #define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
    #define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
     
    #define GPIO_SET *(gpio+7)  // sets   bits which are 1 ignores bits which are 0
    #define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
     
    #define GET_GPIO(g) (*(gpio+13)&(1<<g)) // 0 if LOW, (1<<g) if HIGH
     
    #define GPIO_PULL *(gpio+37) // Pull up/pull down
    #define GPIO_PULLCLK0 *(gpio+38) // Pull up/pull down clock
     
    int movienumber;
    int timecount;
    bool rec;
    
    void setup_io();
    
    int main(int argc, char *argv[])
    {
        if (daemon(1,0) == -1) {
            syslog(LOG_USER|LOG_INFO,"failed to launch daemon.\n");
            return -1;
        }
    
        VideoWriter outputVideo;
        char outfile[20];
        char workcommand[150];
    
    #ifdef DEBUG
            double ticFrequency;
            double processTime;
            int    startTic;
            int    stopTic;
            ticFrequency = cvGetTickFrequency();
    #endif
        struct timespec wt={0,100000000}; // sleep time of main loop 100mS.
    
        struct tm *s_time;
        time_t the_time;
    
        chdir("/home/pi/cpp/humandetector"); // Movie output directory
    
        syslog(LOG_USER|LOG_INFO,"Start");
    
        setup_io();
        INP_GPIO(4);
    
        movienumber = 0;
        timecount = 0;
        rec = false;
    
        VideoCapture inputVideo(0);
        if (!inputVideo.isOpened())
        {
            syslog(LOG_USER|LOG_INFO,"Could not open the input video.\n");
            return -1;
        }
        Size S = Size((int) inputVideo.get(CV_CAP_PROP_FRAME_WIDTH), (int) inputVideo.get(CV_CAP_PROP_FRAME_HEIGHT));
    
        Mat frame,clrframe;
        inputVideo >> clrframe; // Dummy read to start camera
    
        for (;;) 
        {
    #ifdef DEBUG
                startTic = cvGetTickCount();
    #endif
            if (rec){
                inputVideo >> frame;
                if(!frame.empty()){ 
                    outputVideo << frame;
                }
                timecount++;
                if(timecount>MOVIETIME){
                    rec = false;
                    outputVideo.release();
                    syslog(LOG_USER|LOG_INFO,"released. convert avi to 3gp.");
                    sprintf(workcommand, "avconv -y -i %s -r:v 30 -codec:v mpeg4 -b:v 64k -s:v 320x240 -codec:a libaac -ar:a 48000 000.3gp", outfile);
                    system(workcommand);
                    syslog(LOG_USER|LOG_INFO,"send 3gp to docomo.");
                    system("sh mymail.sh 000.3gp");
                    if(movienumber>=MAXMOVIENUM){break;}
                    timecount=DETECTINT;
                    syslog(LOG_USER|LOG_INFO,"done.");
                }
            }else if(GET_GPIO(4) > 0){
                (void) time(&the_time);
                s_time=localtime(&the_time);
                if(timecount>0){
                    timecount=DETECTINT;
                }else if(s_time->tm_hour>=8 && s_time->tm_hour<=21){
                    rec = true;
                    timecount=0;
                    sprintf(outfile, "%03d.avi", movienumber++);
                    outputVideo.open(outfile, CV_FOURCC('M', 'P', '4', '2'), MOVIEFPS, S, true);
                    if (!outputVideo.isOpened())
                    {
                        syslog(LOG_USER|LOG_INFO,"Could not open the output video.");
                        return -1;
                    }
                    inputVideo >> clrframe; // Dummy reads to skip old cache.
                    inputVideo >> clrframe;
                    inputVideo >> clrframe;
                    inputVideo >> clrframe;
                    syslog(LOG_USER|LOG_INFO,"detected.");
                }
            }else{
                nanosleep(&wt,NULL);
                if(timecount>0){timecount--;}
            }
    
    #ifdef DEBUG
                stopTic = cvGetTickCount();
                processTime = (stopTic-startTic)/ticFrequency;
                printf("time=%fus\n",processTime);
    #endif
        }
        outputVideo.release();
        inputVideo.release();
        syslog(LOG_USER|LOG_INFO,"Finished.");
        return 0;
    }
    
    //
    // Set up a memory regions to access GPIO
    //
    void setup_io()
    {
       /* open /dev/mem */
       if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
          syslog(LOG_USER|LOG_INFO,"can't open /dev/mem ");
          exit(-1);
       }
     
       /* mmap GPIO */
       gpio_map = mmap(
          NULL,             //Any adddress in our space will do
          BLOCK_SIZE,       //Map length
          PROT_READ|PROT_WRITE,// Enable reading & writting to mapped memory
          MAP_SHARED,       //Shared with other processes
          mem_fd,           //File to map
          GPIO_BASE         //Offset to GPIO peripheral
       );
     
       close(mem_fd); //No need to keep mem_fd open after mmap
     
       if (gpio_map == MAP_FAILED) {
          syslog(LOG_USER|LOG_INFO,"mmap error %d", (int)gpio_map);//errno also set!
          exit(-1);
       }
     
       // Always use volatile pointer!
       gpio = (volatile unsigned *)gpio_map;
     
     
    } // setup_io
    
[メイク]
  • make用のCMakeLists.txtファイル作成。内容は以下。
    cmake_minimum_required(VERSION 2.8)
    project( humandetector )
    set(SOURCES humandetector.cpp)
    find_package( OpenCV REQUIRED )
    add_executable( humandetector ${SOURCES} )
    target_link_libraries( humandetector ${OpenCV_LIBS} )
  • cmake
    pi@raspberrypi ~/cpp/humandetector $ cmake .
    -- The C compiler identification is GNU 4.6.3
    -- The CXX compiler identification is GNU 4.6.3
    -- Check for working C compiler: /usr/bin/gcc
    -- Check for working C compiler: /usr/bin/gcc -- works
    -- Detecting C compiler ABI info
    -- Detecting C compiler ABI info - done
    -- Check for working CXX compiler: /usr/bin/c++
    -- Check for working CXX compiler: /usr/bin/c++ -- works
    -- Detecting CXX compiler ABI info
    -- Detecting CXX compiler ABI info - done
    -- Configuring done
    -- Generating done
    -- Build files have been written to: /home/pi/cpp/humandetector
  • make
    pi@raspberrypi ~/cpp/humandetector $ make
    Scanning dependencies of target humandetector
    [100%] Building CXX object CMakeFiles/humandetector.dir/humandetector.cpp.o
    Linking CXX executable humandetector
    [100%] Built target humandetector
    これで実行ファイル作成は完了。
[メール送信設定]
  • nkfインストール。文字コード変換用。
    pi@raspberrypi ~ $ sudo apt-get install nkf
    (省略)
  • ssmtpインストール
    pi@raspberrypi ~ $ sudo apt-get install ssmtp
    (省略)
  • ssmtpのconfigファイル設定。/etc/ssmtp/ssmtp.confの編集。Gmailを使います。Googleの2段階認証はOFFにはせず、アプリパスワードを取得してAuthPassに設定します。
    #
    # Config file for sSMTP sendmail
    #
    # The person who gets all mail for userids < 1000
    # Make this empty to disable rewriting.
    root=xxxxx@gmail.com
    
    # The place where the mail goes. The actual machine name is required no
    # MX records are consulted. Commonly mailhosts are named mail.domain.com
    mailhub=smtp.gmail.com:587
    AuthUser=xxxxx@gmail.com
    AuthPass=xxxxxxx
    AuthMethod=LOGIN
    UseSTARTTLS=YES
    UseTLS=Yes
    
    # Where will the mail seem to come from?
    #rewriteDomain=
    
    # The full hostname
    hostname=localhost
    
    # Are users allowed to set their own From: address?
    # YES - Allow the user to specify their own From: address
    # NO - Use the system generated From: address
    #FromLineOverride=YES
  • メール送信起動ファイルを作ります。mymail.shとして保存します。
    #!/bin/sh
    
    FILE=$1
    NKF='/usr/bin/nkf'
    SENDMAIL='/usr/sbin/sendmail'
    TO='xxxxxxxx@docomo.ne.jp'
    FROM='xxxxxxx@gmail.com'
    BOUND=`date +"%Y%m%d%H%M%S"`
    
    Err(){ echo "$1">&2; exit 1; }
    Check_file(){ test -f $1 || return 1; return 0; }
    
    Msg()
    {
    echo "To:${TO}
    Subject: sendmail
    MIME-Version: 1.0
    Content-Type: multipart/mixed;
     boundary=\"---------${BOUND}\"
    
    -----------${BOUND}
    Content-Type: Text/Plain; charset=ISO-2022-JP
    Content-Transfer-Encoding: 7bit
    
    from RasPi
    
    -----------${BOUND}
    Content-Type: application/octet-stream;
     name=\"${FILE}\"
    Content-Transfer-Encoding: base64
    Content-Disposition: attachment;
     filename=\"${FILE}\"
    
    " | ${NKF} -j -m0
    
    cat ${FILE} | base64
    
    echo ""
    echo "-----------${BOUND}--"
    }
    
    ## main
    Check_file ${FILE} || Err "Warning : Cannot open ${FILE}"
    Msg | ${SENDMAIL} -f${FROM} ${TO}
    
    exit 0
[デーモン化]
  • /etc/init.d/の下に実行ファイル作成。humandetectorとして保存。INIT INFOのところはコメント文ですが後述のupdate-rc.dコマンドで使用されるため必要です。/lib/lsb/init-functionsもstatus_of_procコマンドで必要です。
    #! /bin/sh
    ### BEGIN INIT INFO
    # Provides:          humandetector
    # Required-Start:    $remote_fs $syslog
    # Required-Stop:     $remote_fs $syslog
    # Default-Start:     2 3 4 5
    # Default-Stop:      0 1 6
    ### END INIT INFO
    
    PATH=/sbin:/usr/sbin:/bin:/usr/bin
    DESC="humandetector"
    NAME=humandetector
    DAEMON=/home/pi/cpp/humandetector/$NAME
    SCRIPTNAME=/etc/init.d/$NAME
    
    # Exit if the package is not installed
    [ -x "$DAEMON" ] || exit 0
    
    # Define LSB log_* functions.
    # Depend on lsb-base (>= 3.2-14) to ensure that this file is present
    # and status_of_proc is working.
    . /lib/lsb/init-functions
    
    #
    # Function that starts the daemon/service
    #
    do_start()
    {
        # Return
        #   0 if daemon has been started
        #   1 if daemon was already running
        #   2 if daemon could not be started
        start-stop-daemon --start --quiet --exec $DAEMON --test > /dev/null \
                || return 1
        start-stop-daemon --start --quiet --exec $DAEMON \
                || return 2
        return 0
    }
    
    #
    # Function that stops the daemon/service
    #
    do_stop()
    {
        # Return
        #   0 if daemon has been stopped
        #   1 if daemon was already stopped
        #   2 if daemon could not be stopped
        #   other if a failure occurred
        start-stop-daemon --stop --quiet --name $NAME
        RETVAL="$?"
        return "$RETVAL"
    }
    
    case "$1" in
      start)
        do_start
        ;;
      stop)
        do_stop
        ;;
      status)
        status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
        ;;
      *)
        echo "Usage: $SCRIPTNAME {start|stop|status}" >&2
        exit 3
        ;;
    esac
    
    :
  • update-rc.dコマンドでリンク作成。/etc/rc0.d/〜/etc/rc6.d/の下にリンクが作成されます。これで、rebootするとhumandetectorが起動します。
    pi@raspberrypi ~ $ sudo update-rc.d humandetector defaults
    update-rc.d: using dependency based boot sequencing
    pi@raspberrypi ~ $ ls /etc/rc[0-6].d/*humandetector*
    /etc/rc0.d/K01humandetector  /etc/rc2.d/S02humandetector  /etc/rc4.d/S02humandetector  /etc/rc6.d/K01humandetector
    /etc/rc1.d/K01humandetector  /etc/rc3.d/S02humandetector  /etc/rc5.d/S02humandetector
  • 停止させたり、実行されているかどうか確認したい場合、serviceコマンドを使います。
    pi@raspberrypi ~ $ sudo service humandetector start
    pi@raspberrypi ~ $ sudo service humandetector status
    [ ok ] humandetector is running.
    pi@raspberrypi ~ $ sudo service humandetector stop
    pi@raspberrypi ~ $ sudo service humandetector status
    [FAIL] humandetector is not running ... failed!