ころちゃん

木工・電子工作・IoT・作ったもの試したものを記事にして投稿してます

Raspberry Piでアサガオ定点カメラ

time 更新日:  time 公開日:2020/09/23

Raspberry Piでアサガオ定点カメラ

ラズパイ(Raspberry Pi Zero W)を使って、あさがおの咲くところを定点カメラで撮影してみました。

仕組み・概要

Raspberry Pi Zero WにカメラモジュールVer1.3を取り付けて撮影。撮影した画像をサーバにアップロードして、タイムラプス風にして見られるようにしてみました。

概要

  • ラズパイで撮影、WiFi経由で即時サーバへアップロード。
  • 撮影は2分間隔、crontabで定時実行の処理。
  • 保存先はレンタルサーバとし、DBにテーブルを新規に構築。
  • サーバ側へはPOSTメソッドで画像をアップロード。
  • 画像保存と同時に、DBに時間・ファイル名をインサート。
  • JavaScriptで画像を連続して表示し、タイムラプス風にスライドショーで表示。

実際の撮影画像はこのようになります。咲くシーンのみ抽出しました。

  • 04:50

  • 04:52

  • 04:54

  • 04:56

  • 04:58

  • 05:00

  • 05:02

  • 05:04

  • 05:06

  • 05:08

  • 05:10

  • 05:12

  • 05:14

  • 05:16

  • 05:18

  • 05:20

  • 05:22

  • 05:24

  • 05:26

  • 05:28

  • 05:30

クライアント側プログラム

ハードウェアRaspberry Pi Zero W
OSRaspbian Buster with desktop:September 2019

クライアント側プログラム(asagao.sh)では、2つの処理をします。撮影と撮影画像をサーバにPOSTメソッドでアップロードです。2つの処理を1つのシェルで実行するようにしました。raspistillで撮影、2020-08-15_0600.jpgのようなファイル名で保存されます。curlでサーバを指定し撮影画像をアップロードしてます。

asagao.sh
#!/bin/bash
DATE=$(date +"%Y-%m-%d_%H%M")
raspistill -rot 90 -w 600 -h 400 -o /home/pi/asagao/$DATE.jpg

curl -X POST -F upload_file=@/home/pi/asagao/$DATE.jpg https://レンタルサーバのドメイン/asagao/post.php

このプログラムをあさがおの撮影時間に合わせて4時から11時まで2分間隔で動作するように、crontabに設定します。

crontab*/2 4-10 * * * /home/pi/asagao.sh

サーバ側 DBの準備

サーバは、DBが利用できる環境であれば、レンタルサーバ/クラウドサーバ/ローカルのサーバなんでも大丈夫です。今回はレンタルサーバのMySQLにimagesというテーブルを新たに作りました。テーブル構造は以下の通りです。

テーブル作成コマンド

CREATE TABLE `images` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `datetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `filename` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
)DEFAULT CHARSET=utf8mb4;

データが格納されている状況

サーバ側 表示プログラム

サーバ側プログラムはphpで作成しました。画像をPOSTメソッドで受け取るプログラム(post.php)と、JavaScriptでスライドショーを表示するプログラム(index.php)の2つです。

データベースへは、datetimeへ$timeを、filenameへ環境変数から取得のファイル名$_FILES[‘upload_file’][‘name’]の2項目をインサート。imagesディレクトリにファイルを保存します。

post.php<?php
$dsn = "mysql:host=localhost; dbname=mydatabase; charset=utf8";
$username = "myusername";
$password = "mypassword";
try {
    $dbh = new PDO($dsn, $username, $password);
} catch (PDOException $e) {
    echo $e->getMessage();
}
$time = date("Y-m-d H:i:s");
        $sql = "INSERT INTO images (id,datetime,filename) VALUES (NULL, :time, :name)";
        $stmt = $dbh->prepare($sql);
        $stmt->bindValue(':time', $time, PDO::PARAM_STR);
        $stmt->bindValue(':name', $_FILES['upload_file']['name'], PDO::PARAM_STR);
        if (is_uploaded_file($_FILES['upload_file']['tmp_name'])) {//ファイルが選択されていれば$imageにファイル名を代入
            move_uploaded_file($_FILES['upload_file']['tmp_name'], './images/'.$_FILES['upload_file']['name']);//imagesディレクトリにファイル保存
            $message = '画像をアップロードしました';
            $stmt->execute();
        }
?>
<?php if (isset($_POST['upload'])): ?>
    <p><?php echo $message; ?></p>
<?php else: ?>
    <form method="post" enctype="multipart/form-data">
        <p>アップロード画像</p>
        <input type="file" name="upload_file">
        <input type="submit" name="upload" value="送信">
    </form>
<?php endif;?>

JavaScriptで画像の一覧を取得するために、class=”slides”で指定しました。またスライドショーとは別に、アップロードされた画像を表形式で表示するようにしてみました。スライドショー画像右上に表示される時刻は、CSSのセレクタ”ul.slides li p”で指定し表示しています。

index.php<?php
$dsn = "mysql:host=localhost; dbname=mydatabase; charset=utf8";
$username = "myusername";
$password = "mypassword";
?>
<!DOCTYPE HTML>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>定点カメラ あさがお スライドショー</title>
       <style>
         ul.slides li {
         display:none;
         position:relative;
         list-style:none;
       }
         ul.slides li img {
         width:600px;
       }
         ul.slides li p {
         position:absolute;
         top:1em;
         left:25em;
         color:white;
         font-size:1.2em;
       }
       #slide_speed {
         transform: rotateY(180deg);
       }
    </style>
    </head>
    <body>
    <ul class="slides">
<?php
    try {
    $dbh = new PDO($dsn, $username, $password);
    // データベースからレコードを取得
    $sql = "SELECT * FROM `images` WHERE `datetime` >= '2020-08-14 18:00:00'";
    $stmt = $dbh->prepare($sql);
    $stmt->execute();
    while($row = $stmt->fetch(PDO::FETCH_ASSOC)){
?>
    <li><img src = "./images/<?=$row['filename'] ?>"><p><?=substr($row['datetime'],11,5) ?></p>
<?php
} }catch (PDOException $e) {
    echo $e->getMessage();
}
?>
    </ul>
    <p>速度(1000-50msec):<input type="range" id="slide_speed" value="1000" min="50" max="1000"></p>
    <hr>
    <p><a href=index.php>top</a></p>
    <hr>
    <table width="400" cellspacing="0" cellpadding="5" border="1">
    <tr align="center">
     <th>ID</th>
     <th>DateTime</th>
     <th>画像</th>
    </tr>
<?php
    try {
    $dbh = new PDO($dsn, $username, $password);
   // データベースからレコードを取得
    $sql = "SELECT * FROM `images` WHERE `datetime` >= '2020-08-14 18:00:00' ORDER BY `id` DESC";
    $stmt = $dbh->prepare($sql);
    $stmt->execute();
    while($row = $stmt->fetch(PDO::FETCH_ASSOC)){
?>
     <tr align="center">
      <td><?=$row['id'] ?></td>
      <td><?=$row['datetime'] ?></td>
      <td><a href="./images/<?=$row['filename'] ?>"><img src = "./images/<?=$row['filename'] ?>" width="100"></a></td>
     </tr>
<?php
    } }catch (PDOException $e) {
    echo $e->getMessage();
    }
?>
   </table>
       <script>
       //スライド用のliタグを全て取得
       var slides = document.getElementsByClassName('slides')[0].getElementsByTagName('li');

       //スライド表示用の関数を呼び出す(引数はスライドの切り替え時間)
       viewSlide();

       function viewSlide(slide_no = -1)
       {
       //現在のスライドを消す
       if (slides[slide_no]) {
       slides[slide_no].style.display = 'none';
       }
       //スライド番号をカウントアップ
       slide_no++;
       if (slides[slide_no]) {
       //次のスライドを表示
       slides[slide_no].style.display = 'block';
       } else {
       //次のスライドがなければ最初のスライドを表示
       slides[0].style.display = 'block';
       slide_no = 0;
       }
       var msec = document.getElementById('slide_speed').value;
       setTimeout(function(){viewSlide(slide_no);}, msec);
       }
       </script>
   </body>
</html>

サーバへのプログラム配置は以下の通りです。

root/
  ├ asagao/
           ├ images/
           ├ post.php
           └ index.php

画像表示のJavaScriptは下記のサイトを参考にさせていただきました。

タイムラプス風というか、パラパラ漫画風に表示できるJavaScriptの画像ビューアを色々とさがしました。Viewer.jsとかSwiper.jsとか。でも、参考サイトのものが軽量でシンプル、速度変更もできて一番適していました。

実行結果

別ページに遷移します。全体で50MBと少し重いページです。撮影時間7時間、200枚以上の写真をパラパラ漫画風に1分半で再生します。

定点カメラ あさがおスライドショー

※上述のindex.phpで生成されたページを、サンプル用に静的なHTMLファイルに加工しました。

日が差す頃に咲き始め、途中青色から紫色に変化し、そして10時過ぎたころにしぼみ始める様子がよくわかります。撮影実行中は、2分間隔で画像が追加され、更新されていきます。

設置

7尺の脚立の上に、カメラ用三脚を設置。2m以上の高さから撮影。前日夕方に咲きそうなものを見つけてセットしておきました。

通信は無線ですが、電源は家の中から電源延長ケーブルで伸ばしました。ラズパイの消費電力を考えれば、携帯電話充電用のモバイルバッテリーでもよかったかもしれません。

カメラモジュールと一緒に格納できる自作ケース。ほこりと水滴から守ります。

三脚へ取り付けるため、1/4インチねじが入るナットを付けました。カメラと同じ三脚が使えて便利です。

あとがき

タイムラプス風の撮影であれば、今どきのスマホアプリやデジカメの機能でも可能です。遠隔地にあるものをリアルタイムにタイムラプス風スライドショーで見えたら面白いなと思ってやってみました。

最低限のやりたいことは成功しました。撮影したスライドショーをみて、色んなものに応用できるなって思ってます。今回のように、遠隔地の植物の観察はもちろん、撮影スパンを変えて、建築中のビルとか、解体中の建物とか、季節の変動とか変化の分かるものだと面白そうです。

参考にしていただけたら幸いです。

sponsored link

down

コメントする




CAPTCHA


管理人

ころちゃん

木工で日用品を作ったり、懐中電灯を改造したりしてます。まだまだ素人ですがどうぞよろしく。



sponsored link

アーカイブ