IPCAM, a autonomous IP camera with Arduino and Adafruit serial JPG camera

Hello,

I'm a newbie in Arduino scene, so I have the skill to make a lot of mistake, I'm here to learn and improve my skill.
I would like to share my first working project, I use lot of code from well skilled programmers and I just do an integration rather than writing my own code.

Anyway, purpose of this project is to demonstrate how is capable a tiny atmega328p MCU to do some Internet Of Thing, with the help of dedicated hardware.

I saw a lot of Arduino sketch to control camera motion and control but nothing about a really IP cam with the Arduino uno. After learning a lot from Basic Ethernet Shield Arduino Web Server , the idea to transform a sample with a JPG web service into a real ip cam comes.

Update: youtube video

So this project aim to make a autonomous IP cam with an UNO, a Ethernet shield and a serial JPG camera.
What you can do with that?
Take some shoots, control Arduino outputs and read analog values, here a screen from this tiny web server:

And here a picture, with a far better camera, of the hardware:

Now the code, posted on Github, with a MIT licence:

How to do this working?
You have to modify the sketch, adding your ISP informations like local IP, ISP dns, MAC of ethernet shield and your no-ip account informations.
To be reachable via Internet you have to add a Network Adress Translation rules in your router, allowing redirection of http request (port 80 in the sketch) to your local IP adress where the Arduino is, for both UDP and TCP protocol.
Then you can reach from your smartphone this IP Cam!

Lots of improvements can be made and I would appreciate a lot to see other branchs on the github repositery :wink:

Have fun!

1 Like

we're waiting ....

Interesting project. With some javascript web page code it could be made self refreshing. With multiplexing chips additional cameras probably could be added and incorporated into a web page.

Hello,

Indeed with javascript a lot of things can be done. The html file provided already use javascript to do some things like general purpose output control and status, analog read also.
I didn't find how to do with javascript to upload a new picture 'on demand', so I do a 'refresh request' to the web browser, which is not an elegant way.

I will post soon a video which will show the device under work, and you will see how slow it is, a 640x480 JPG picture around 55KB takes approx 10 seconds to upload. This is because I use a software serial link to access the camera and the speed is limited to 38400 (some people tries to modify serial link speed inside DSP of camera without success and even bricked the camera).

Below are some old pages (the cam server is no longer on line) that use javascript to reload single frames from a cam server. View the page source to see the page code. Does the bottom code section buffer the bytes from the cam into a large packet prior to sending to the client?

http://web.comporium.net/~shb/wc2000.htm

http://web.comporium.net/~shb/wc2000-1.htm

http://web.comporium.net/~shb/wc2000pullscript.htm

                     cam.takePicture();
                      //client.println(F("HTTP/1.1 200 OK"));
                      client.println();
                      uint16_t jpglen = cam.frameLength();
                      pinMode(8, OUTPUT);
                      while (jpglen > 0) {
                      uint8_t bytesToRead = min(32, jpglen); // change 32 to 64 for a speedup but may not work with all setups!
                      client.write(cam.readPicture(bytesToRead), bytesToRead);
                      jpglen -= bytesToRead;

Hi zoomkat,

Thanks for advice about refreshing a fram from a cam server, I will take a look inside.
I'm cooking a youtube video which show device in action. Just the time to shadow my no-ip account and add some txt to the video.
I don't use buffer (actually a tiny 32B buffer) before sending via TCP, but Arduino RAM size don't allow me to buffer more than few tens of bytes, the TCP limit around 1500B seems difficult to reach with a 2048B RAM size. Before I try buffering picture to µSD but this process takes more time than direct transfert (time to upload picture 32/64B to 32/64B from CAM frame buffer to µSD + time to transfert from µSD to ethernet shiel wiznet 5100 chipset > time to directly transfer from cam frame buffer to wiznet 5100).

Below is a buffering setup for transferring files off of the SD card. Putting 64 bytes into a packet before using client.write(clientBuf,64); speeded up the file transfer to at least four times faster.

          //select file to send to browser
          if(readString.indexOf("servosld") >=0) {
            File myFile = SD.open("SERVOSLD.HTM");
            if (myFile) {

              byte clientBuf[64];
              int clientCount = 0;              

              while (myFile.available()) 
              {
                clientBuf[clientCount] = myFile.read();
                clientCount++;

                if(clientCount > 63)
                {
                  client.write(clientBuf,64);
                  clientCount = 0;
                }                
              }
              if(clientCount > 0) client.write(clientBuf,clientCount);            
              myFile.close();
            }
          }

Hello,

I measure time for a cam shoot order, it takes almost 30s! Indeed there are lots of improvements to earn here.
I try this code

cam.takePicture();
                      //client.println(F("HTTP/1.1 200 OK"));
                      client.println();
                      uint16_t jpglen = cam.frameLength();
                      pinMode(8, OUTPUT);
                      while (jpglen > 0) {
                      uint8_t *buffer;
                      uint8_t bytesToRead = min(32, jpglen); // change 32 to 64 for a speedup but may not work with all setups!
                      buffer = cam.readPicture(bytesToRead);
                      //clientBuf[clientCount] = cam.readPicture(bytesToRead);
                      client.write(buffer,bytesToRead);
                      
                      jpglen -= bytesToRead;
                    }

This change nothing, I unsucessful tried your way to work byte per byte with a loop, but I suppose compiler is doing this kind of thing when this line is runing: buffer = cam.readPicture(bytesToRead);
When I set buffer size to 64 byte I run out of RAM :confused:

With a 38400bps speed and an hypothesis of 10% of bandwidth overhead, a 55KB picture should take no more than 15 sec; so there is certainly some optimizations to do.

Hi zoomkat,

I toke a look into your cam server html code.
It seems when you need to refresh the picture you call a javascript function which change the .source of the picture with a new url pointing to your server. My problem is I think only a refresh commande make my arduino code to trig the code section which take a new picture and send it, I think even with your way my problem can not be solve because there is something wrong deeply inside my newbie code :slight_smile:

Regards

I actually got the old cam in the below link somewhat working last night (bad wire in cam connection from 10+ years of pan/tilt flexing) so you can see it in action. If you can actually get an image from the serial cam to a browser, that is progress!

http://web.comporium.net/~shb/wc2000-PT-script.htm

Hi Zoomkat,

Looking your javascript code, I understand that my javascript don't include 'combat cache' mechanism, then the browser don't ask for a new get request when I click my button.

My arduino code:

if (StrContains(HTTP_req, "GET /pic.jpg")) {

                      cam.takePicture();
                      //client.println(F("HTTP/1.1 200 OK"));
                      client.println();
                      uint16_t jpglen = cam.frameLength();
                      pinMode(8, OUTPUT);
                      while (jpglen > 0) {
                      uint8_t *buffer;
                      uint8_t bytesToRead = min(32, jpglen); // change 32 to 64 for a speedup but may not work with all setups!
                      buffer = cam.readPicture(bytesToRead);
                      //clientBuf[clientCount] = cam.readPicture(bytesToRead);
                      client.write(buffer,bytesToRead);
                      
                      jpglen -= bytesToRead;
                    }
                      cam.resumeVideo();

My today way to ask for a new picture (in htm code):

<button type="button" onclick = "showImg()">Cam shoot!!</button>

calling the javascript function:

function showImg()
		{
		window.location.reload();
		}

It's working, but not very efficient as the arduino resend all the htm page.

So if I modify my javascript function this way:

var i = 0;
function showImg()
		{
		i++;
		//window.location.reload();
		var obj=document.getElementById('image01');
		//obj.className = 'show';
		obj.src = "pic.jpg" + i;
		}

The brower send a new get /pic.jpg request, so this way I force the browser to made a new request because pic.jpg don't exist in cache.
But my function to compare string request don't work (arduino code):
```
*char StrContains(char *str, char *sfind)
{
    char found = 0;
    char index = 0;
    char len;
Serial.println("str");
  Serial.println(str);
  Serial.println("sfind");
  Serial.println(sfind);
    len = strlen(str);
    if (strlen(sfind) > len) {
        return 0;
    }
    while (index < len) {
        if (str[index] == sfind[found]) {
            found++;
            if (strlen(sfind) == found) {
                return 1;
            }
        }
        else {
            found = 0;
        }
        index++;
    }

return 0;
}
_
```*_
So I have to modify my arudino compare function or find another way to forec browser to make new request each time I click my button.