Friday, May 24, 2013

Adafruit TTL Serial JPEG Camera & the Beaglebone Black

The Adafruit TTL Serial JPEG Camera is a 5 volt device, but the serial (TTL) voltage is only 3.3 volt, so it is safe to use with the 3 volt pins on the Beaglebone Black.

See this post for information on how to configure the UART1 (/dev/ttyO1) pins.  This needs to be done every time the Beaglebone Black is rebooted.

Connections


Camera  Beaglebone Black
+5V     P9 7  (SYS_5V)
GND     P9 1  (GND)
RX      P9 24 (uart1_txd)
TX      P9 26 (uart1_rxd)


Code


The following Python code sets the picture size to 640 x 480 pixels, takes a picture and saves it to the /tmp directory with a file name made up of the date and time (including seconds, so duplicate names shouldn't be a problem).

import serial
import time
import datetime

# Initialize camera
serial = serial.Serial("/dev/ttyO1", baudrate=38400)
serial.write(b'\x56\x00\x26\x00')
resp = ""
time.sleep(1)
while(serial.inWaiting() > 0):
        data = serial.read()
        resp += data
        if "Init end\r\n" in resp:
                print "Ready"
                break

# Set image size to 640 x 480
serial.write(b'\x56\x00\x54\x01\x00')
resp = ""
time.sleep(1)
while (serial.inWaiting() > 0):
        data = serial.read()
        resp += data
        if b'\x76\x00\x54\x00\x00' in resp:
                print "Size set"
                break

# Take picture
serial.write(b'\x56\x00\x36\x01\x00')
resp = ""
time.sleep(2)
while(serial.inWaiting() > 0):
        data = serial.read()
        resp += data
        if b'\x76\x00\x36\x00\x00' in resp:
                print "Picture taken"
                break

#Get JPG size
serial.write(b'\x56\x00\x34\x01\x00')
resp = ""
time.sleep(1)
while(serial.inWaiting() > 0):
        data = serial.read()
        resp += data
        if b'\x76\x00\x34\x00\x04\x00\x00' in resp:
                msb = serial.read()
                lsb = serial.read()
                print "Image file size: %d bytes" % (ord(msb) << 8 | ord(lsb))

# Write image to file
serial.write(b'\x56\x00\x32\x0C\x00\x0A\x00\x00\x00\x00\x00\x00%c%c\x00\x0A'
% (msb,lsb))
time.sleep(5)
now = datetime.datetime.now()
filename = "%d.%02d.%02d.%02d.%02d.%02d.jpg" % \
(now.year,now.month,now.day,now.hour,now.minute,now.second)
resp = serial.read(size=5)
if b'\x76\x00\x32\x00\x00' in resp:
        with open("/tmp/" + filename, 'wb') as f:
                while(serial.inWaiting() > 0):
                        data = serial.read()
                        f.write('%c' % data)
        print "Image written to /tmp/%s" % (filename)


16 comments:

  1. Hello Brad. I've been trying to figure out how to make my own home security system and I think that the Arduino wont accept the amount of code I want to use (the HMI menu pages will likely over fill the file size.) I was thinking of adding a Raspberry Pi, but it appears the BB-Black is now the better choice. I would like to keep the Arduino as part of the system (I have it working with a high voltage relay board) but have the BB-B handle most of the HMI. I would have the two items communicate in the method you've explained here, even though I don't know Python and so don't follow this code. Knowing all you know, would you suggest a different route? P.S. I'd like to source my parts from Adafruit, so would this logic converter (http://www.adafruit.com/products/757) do the same thing the sparkfun does?
    This blog is exactly what I need to continue learning. Thank you for sharing your knowledge!

    ReplyDelete
    Replies
    1. Hi Quiver -

      I agree - I think the Beaglebone Black is the better choice, especially with the reduced price compared to the original Beaglebone. The logic level converter you mention should be fine. I haven't used this one, but it looks very similar to those I have from Sparkfun. Serial/UART communication between the Beaglebone Black and the Arduino will definitely work. You will need to experiment a bit to see what baud rate you will need to use to keep the connection working over longer connections. Longer wires normally require a lower baud rate. I think you'll be able to master enough Python fairly quickly.

      Delete
  2. Is it possible to send a command from a computer running a python script to the bbb to initiate the camera to take a picture and then have it stored on the computer?

    ReplyDelete
    Replies
    1. Hi -

      Yes, I'm sure you could create a Web app or even Web service with the HTTP server or other network libraries. I've run a simple Web server on the Beaglebone Black and had it display images on a Web page. You could do something as simple as use the Python urllib2 to get the images from the Web server on the Beaglebone to the computer. Python offers a number of approaches, so you can make things as simple or as complex as you like.

      Delete
  3. How did you figure out the commands to send to the camera? Is there a manual somewhere with the correct commands?

    ReplyDelete
    Replies
    1. Hi Eric -

      I took them from the manual for the camera: http://dlnmh9ip6v2uc.cloudfront.net/datasheets/Sensors/LightImaging/LinkSprite%20JPEG%20Color%20Camera%20Manual.pdf. I have a similar but not identical board from SparkFun, and they have a link to the manual on their product page.

      Delete
  4. How will I be able to show the whole image? Because the image that is saved is not full. What seems to be the problem?

    ReplyDelete
    Replies
    1. Hi Jasmin - Try adjusting (lengthening) the pauses provided by the calls to time.sleep(). I have found the incomplete images seem to be caused by pauses in the program flow that are too short. Let me know what you find out.

      --Brad

      Delete
  5. Hello Brad :) Thank you for the quick response. I have already tried to extend the pauses for the calls and it has no effect. The image that is saved is still not complete, not even half of the image is saved. Is there any other way you can suggest?

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
    2. Hi Jasmin -

      What image size are you using and what is the longest pause length you have tried in the section of the code that writes the image to the file? I have recently broken the Adafruit camera that I used for this post, so I can't test again right now, but I do have another one on order. With the Beaglebone Black, I found repeatedly that 5 seconds was enough time to wait in order to avoid truncation, but using a similar camera with a pcDuino, I found that it required 7 seconds to read the whole image (640 x 320). The Adafruit FAQ at the end of their tutorial indicates that it may take up to 30 seconds, but I didn't find that it took that long in my experiments.

      Delete
    3. Hi Jasmin -

      My replacement camera has arrived. I have made multiple tests using the code above and it has worked consistently. I have not been able to reproduce the problem you have encountered. Sorry - I don't know what to recommend.

      Delete
  6. Hi Brad! I'm having problems with capturing images using a windows pc. When using the the lowest resolution for the camera, i get the jpeg EOF FF D9. However, increasing the resolution, I'm having the same problems as Jasmin. The image is incomplete and when I sniff the serial hex output of the jpeg read command, i don't get the FF D9 hex. Your insight is greatly appreciated. Much thanks! :D

    ReplyDelete
  7. hi Brad! i want to use this camera for capturing video, is that possible??

    ReplyDelete
  8. awesome! I made some very small changes to get this working with the UART module in Adafruit_BBIO: https://github.com/yosemitebandit/quandry/commit/71de711f42ef94dae0f38f519479ddb9bc0ebc29

    ReplyDelete