Webでサービスできるカメラ

投稿日:

 一昨日遊んだカメラ。今日はこれにETHERNET SHIELD 2を取り付けて遊んでみる。

  •  間欠的に写真を撮り続ける。
  •  SDに保存する。
  •  ウェブアクセスがあると、一覧でサービスする。

 まあ、これくらいで。サムネイル画像などハデに出したい気もするが、Arduinoはメモリも小さく、そんなに気の利いたウェブサービスはできない。

 プロトタイピングシールドのブレッドボードに組み付ける。

IMG_3136

 まず、スケッチはこんなところだろう。

//
//  camera2Web.ino
//    27.07.20(月) 0850~
//    佐藤俊夫
//    Adafruit製小型TTLシリアルJPEGカメラ+ETHERNET SHIELD 2で
//    間欠撮影をし、Webでダウンロードできるようにする。
//
#include <Adafruit_VC0706.h>
#include <SPI.h>
#include <SD.h>
#include <SoftwareSerial.h>
#include <Ethernet2.h>

#define CHIPSELECT 4

SoftwareSerial CAMCONNECTION(2, 3);
Adafruit_VC0706 CAM = Adafruit_VC0706(&CAMCONNECTION);
const unsigned long int INTERVAL = 30L * 1000L;
byte MAC[] = {  0x90, 0xA2, 0xDA, 0x0F, 0xF6, 0x74 };
IPAddress IP(192, 168, 1, 129);
EthernetServer SERVER(80);
EthernetClient CLIENT;

void setup() {
  pinMode(10, OUTPUT);
  if(!SD.begin(CHIPSELECT)) return;
  if(!CAM.begin()) return;
  CAM.setImageSize(VC0706_320x240);
  Ethernet.begin(MAC, IP);
  SERVER.begin();
  delay(1000);
}

void loop() {
  static unsigned long int prevtime = 0;
  char c;
  String rstr = "";
  //  INTERVALおきに写真を撮る
  if(millis() >= prevtime + INTERVAL){
    prevtime = millis();
    takePicture();
  }
  //  Webサーバ
  CLIENT = SERVER.available();
  if(CLIENT) {
    while(CLIENT.connected()) {
      if(CLIENT.available()) {
        c = CLIENT.read();
        rstr += c;
        if(rstr.endsWith("\r\n")){
          break;
        }
      }
    }
    if(rstr.indexOf("IMG") >= 0){
      String filename = "DCIM/";
      char cfilename[17];
      filename.concat(rstr.substring(rstr.indexOf("IMG"), rstr.indexOf("JPG") + 3));
      filename.toCharArray(cfilename, 17);
      CLIENT.println("HTTP/1.1 200 OK");
      CLIENT.println("Content-Type: image/jpg");
      CLIENT.println("Connection: close");
      CLIENT.println();
      File img = SD.open(cfilename);
      while(img.available()){
        CLIENT.write(img.read());
      }
      img.close();
    }else{
      sendform();
    }
    rstr = "";
    delay(1);
    // close the connection:
    CLIENT.stop();
  }
  delay(20);
}

void sendform(){
  //  フォームを送る。
  CLIENT.println("HTTP/1.1 200 OK");
  CLIENT.println("Content-Type: text/html");
  CLIENT.println("Connection: close");
  CLIENT.println();
  CLIENT.println("<!DOCTYPE HTML>");
  CLIENT.println("<html><head></head><body><center>");
  File dcim = SD.open("/DCIM");
  while(true) {
    File imgfile =  dcim.openNextFile();
    if(!imgfile){
      dcim.rewindDirectory();
      break;
    }
    CLIENT.write("<a href=\"");
    CLIENT.write(imgfile.name());
    CLIENT.write("\">");    
    CLIENT.write(imgfile.name());
    CLIENT.println("</a><br>");
    imgfile.close();    
  }
  dcim.close();
  CLIENT.println("</center></body></html>");
}

void takePicture(){
  static unsigned int pnum = 0;
  char filename[] = "DCIM/img0000.jpg";
  CAM.takePicture();
  filename[8]  = '0' + pnum / 1000;
  filename[9]  = '0' + (pnum / 100) % 10;
  filename[10] = '0' + (pnum /  10) % 10;
  filename[11] = '0' + pnum % 10;
  pnum ++;
  if(pnum > 9999) pnum = 0;
  if(SD.exists(filename)) return;
  File imgFile = SD.open(filename, FILE_WRITE);
  uint16_t jpglen = CAM.frameLength();
  pinMode(8, OUTPUT);
  while (jpglen > 0) {
    uint8_t *buffer;
    uint8_t bytesToRead = min(32, jpglen);
    buffer = CAM.readPicture(bytesToRead);
    imgFile.write(buffer, bytesToRead);
    jpglen -= bytesToRead;
  }
  imgFile.close();
}

  で、電源をつないで放置しておくと、写真が撮れるわけだ。既存のファイル名を避けるような芸コマなことはしてないけど、これはこれでけっこう面白い。

 いつもの100円ショップのアクリル枠にねじ止めする。このカメラは上下が逆に映るので、こうすると丁度カメラが逆さまになって具合が良い。

IMG_3138

 それで、以前にWIZnetで紹介されて愉快だったアレのリベンジをやってみよう。携帯用のカメラホルダーに取り付け、ベランダに出して放置。

IMG_3139

投稿者: 佐藤俊夫

 50代後半の爺。技術者。元陸上自衛官。2等陸佐で定年退官。ITストラテジストテクニカルエンジニア(システム管理)基本情報技術者

「Webでサービスできるカメラ」への6件のフィードバック

  1. はじめまして
    「Webでサービスできるカメラ」に興味を持ち、同じように作ってみましたが
    web上からファイルを閲覧することはできませんでした
    arduinoがフリーズしたり、真っ白画面になってしまいます
    ブラウザはchromeを使用しました

    カメラの映像は定期的にSDへ保存されています
    ここに来るまで、4,10ピンの出力モード設定等いろいろ試行錯誤しました
    何かアドバイスが頂けると嬉しいです
    arduino1.6.11を使用しております
    「空の写真リベンジ」のコードも同じようになってしまいました

    何かライブラリの変更などなさったのでしょうか

    よろしくお願いいたします

    1. >seki様

       当サイトの拙い記事を参考にしてくださっているとのこと、恐縮です。

       うまく動かないとのこと。ご参考になるかどうかわかりませんが、私の作例でも、「軽々と動く」わけではありませんでした。特に、写真のサイズを、この記事の作例では最小にしておりましたが、これを大きいサイズにしたりすると途端に停止したり、作動しなくなっておりました。

       しかし、そうはいうものの、この作例の通りであれば、「のろのろと」ではありますが、画像を取得することはできておりました。ご指摘のように特段ライブラリを変更する等はしておらず、ごくごくノーマルのままです。

       但し、この記事ではWebで写真が閲覧できることを主眼にしていましたので、作動を確認していますが、参考にしてくださった別の記事、「空の写真リベンジ」のほうでは、SDカードに写真を保存することを主眼にしていましたので、Webで正常に写真がブラウズできるかどうかは、あまりテストしていません。そのため、ひょっとしたらうまく動かないかもしれません。

       しかし、この記事の作例は、遅いながらも作動はしておりましたので、貴環境でどうしてフリーズしたり真っ白になったりするものか、なんとも推定いたしかねます。

       ここからは憶測ですが、Eathernet Shieldのほうのなんらかの違いがあるのかもしれません。

       ご参考になるかどうかはなはだ心もとないところですが、ArduinoはリッチなWebコンテンツを扱うには少々コンピュータパワーの点で劣るところがあり、この点ではRaspberry Piなどを併用するなどして補うのも一案かと思います。特にRaspberry Piですと、ArduinoでWebサービスするのとは異なり、ApacheなどフルサイズのWebサーバを使うことができますので……。Raspberry Piなどを併用されては如何でしょうか。

      1. 佐藤様

        お忙しい所、お返事ありがとうございました。
        色々調べて見ましたが、改善されず
        sendform内のファイル表示が飛ばされている感じです
        この部分のスケッチを実行させserialprintさせると
        ファイル一覧は出てくるのですが・・・
        頑張ってみます。

        m

        seki

        1. >seki様

           ファイル表示が飛ばされている感じとのこと。

           次の下り、

              if(rstr.indexOf("IMG") >= 0){
                String filename = "DCIM/";
                char cfilename[17];
                filename.concat(rstr.substring(rstr.indexOf("IMG"), rstr.indexOf("JPG") + 3));
                filename.toCharArray(cfilename, 17);
                CLIENT.println("HTTP/1.1 200 OK");
                CLIENT.println("Content-Type: image/jpg");
                CLIENT.println("Connection: close");
                CLIENT.println();
                File img = SD.open(cfilename);
                while(img.available()){
                  CLIENT.write(img.read());
                }
                img.close();
              }else{
                sendform();
              }
          
          

          ……の実行状況について、「CLIENT.println」を「Serial.println」に置き換えて出力を観測してみることなども意味がありそうです。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください