Aurduino Uno with Arducam OV2640 and LED combination

I want to use my Arduino Uno (with Arducam OV2640 minicam) to turn on an LED with Python, capture the image, transfer the image from the CMOS via serial cable back to Python, then turn off the LED from Python.

I connected the Arducam OV2640 with provided jumpers and instructions to the Arduino. Then I connected a LED to pin 2 output and can turn on and off the LED via digitalWrite() in the sketch with Python. I can fully control the Arducam and the LED individually with Python.

The problem is that when these 2 processes are combined in the sketch/Python code, the image will not transfer back to Python. I just get empty bytes (b’ ’).

What is the problem running these 2 processes together in the same Arduino sketch and python program? I thought the Uno would be able to handle this OK.

Maybe the LED locks will not release the serial connection? I have tried closing the connection in Python and the sketch and then opening a new connection for camera use, then closing the connection and reopening a new connection for the LED to turn LED off – but still the same problem.

I would really be grateful for help with this one.

1 Like

Hello @Dean293311,

Welcome to the Forum!

Thanks for the detailed description. From what you’ve outlined, it sounds like both the camera and LED can be controlled successfully on their own through Python, but combining them causes the image data to fail when being transferred back, often resulting in just empty bytes.

This issue is likely related to how the Arduino Uno handles serial communication. The Uno has only one hardware serial port (shared between programming and data transfer), and it has very limited memory and serial buffer capacity. When you combine multiple tasks that use serial communication, like triggering the LED and transferring an image, it can easily become out of sync or overwhelmed.

Another possibility is timing. If your Python script sends commands too quickly, or tries to read image data before the Arduino is ready, it may capture an incomplete transfer or nothing at all. Similarly, if the Arduino is doing multiple tasks and not managing them in a predictable order, it may miss or interrupt a command.

The good news is that this can usually be solved by carefully structuring your Arduino sketch and Python code so that each action is clearly separated and synchronised. Typically, this involves having the Arduino respond to one command at a time, with each step clearly triggered and completed before the next starts.

Would you be able to share a snippet of your Arduino sketch and the relevant parts of your Python script? That would help pinpoint whether the issue is with how commands are being handled or if the image data is being sent in a way that Python isn’t properly receiving.

1 Like

Code Snippet below for Arduino and Python.
Python is now turning LED on and OFF correctly and also connecting to the Arducam OK, because I get the acknowledgement back to terminal. All communication timings seem to be good now. But Python still receiving empty bytes when transferring image data from the Arducam CMOS to Python.
Thanks in anticipation.

//Arduino sketch code:

#include <Wire.h>
#include <SPI.h>

static const int CS = 7;
Serial_ArduCAM_FrameGrabber fg;
ArduCAM_Mini_2MP myCam(CS, &fg);

int ledPin = 2; //pin 2 is a digital pin, for turning LED on/off.

void setup(void) 
{
    Wire.begin(); //ArduCAM Mini uses both I^2C and SPI buses
    SPI.begin();
    Serial.begin(115200);
    myCam.beginJpeg640x480(); // Start the camera in JPEG mode with a specific image size
    pinMode(ledPin, OUTPUT);
    digitalWrite(ledPin, LOW); //make sure LED is initially OFF
    while (!Serial) {
        continue; // wait for serial port to connect. Needed for native USB
    }
    while(Serial.available() != 0){ //flush Arduino serial buffer
        Serial.flush();
        delay(1000);
    }
}

void loop(void) 
{
    while(Serial.available() == 0){ //wait for data to arrive in buffer
        continue;
    }
    if (Serial.available()) { // Data is available to read
        byte incomingByte = Serial.read(); // Read the incoming byte in ASCII
        char myChar = (char)incomingByte;
        if (myChar == '1') {
            delay(100);
            digitalWrite(ledPin, HIGH); // Turn LED on
            //send message back to Python - 'T' for true confirms LED is "ON"
            byte outgoingByte = (byte)'T';
            Serial.write(outgoingByte);
        }
        //Get camera ready
        else if (myChar == 'C'){ //'C' for "capture image" 
             //send message back to Python - 'C' for "capturing image"
            byte outgoingByte = (byte)'C';
            Serial.write(outgoingByte); //confirmation sent back to Python.
            myCam.capture();
            delay(1000);
        }
        //turn off LED
        else { //((char)incomingByte == '0')
            digitalWrite(ledPin, LOW); // Turn LED off
            byte outgoingByte = (byte)'F';
            Serial.write(outgoingByte);
            Serial.end();
            delay(100);
            Serial.begin(115200);
        }
    }
}

Python Code:

    PORT = 'COM3'
    BAUD = 115200
    port = serial.Serial(PORT, BAUD, timeout=2)
    time.sleep(2)

    # Now retrieve image from OV2640 CMOS
    getack(port) # Get acknowledgment from camera for serial transfer of image from CMOS Sensor.
    time.sleep(0.2)

    # Transfer bytes from CMOS to build .jpeg image file and save.
    # Send start flag
    sendbyte(port, 1)

    # We'll report frames-per-second
    # start = time.time()
    count = 0

    done = False
    captureNum = 0
    while not done:

        # Open a temporary file that we'll write to and read from
        tmpfile = open("tmp.jpg", "wb")
        #blank_image = np.zeros((480, 640, 3), dtype=np.uint8)
        #cv2.imwrite("tmp.jpg", blank_image)

        # Loop over bytes from Arduino for a single image
        written = False
        prevbyte = None
        while not done:

            # Read a byte from Arduino
            currbyte = port.read(1)

            # If we've already read one byte, we can check pairs of bytes
            if prevbyte:

                # Start-of-image sentinel bytes: write previous byte to temp file
                if ord(currbyte) == 0xd8 and ord(prevbyte) == 0xff:
                    tmpfile.write(prevbyte)
                    written = True

                # Inside image, write current byte to file
                if written:
                    tmpfile.write(currbyte)

                # End-of-image sentinel bytes: close temp file and display its contents
                if ord(currbyte) == 0xd9 and ord(prevbyte) == 0xff:
                    tmpfile.close()
                    img = cv2.imread("tmp.jpg")
                    captureNum = captureNum + 1
                    if captureNum == 2:
                        try:
                            cv2.imshow("ArduCAM [ESC to quit]", img)
                            cv2.waitKey(0)
                            cv2.imwrite("tmp.jpg", img)
                        except:
                            pass
                    #if cv2.waitKey(1) == 27:
                        done = True
                        break
                    count += 1
                    break

            # Track previous byte
            prevbyte = currbyte

    # Send stop flag
    sendbyte(port, 0)

time.sleep(1)

#close connection
if 'port' in locals() and port.is_open:
    port.close()
    print("Serial port closed.")

# Close image display window
cv2.destroyAllWindows()
2 Likes

Hi Dean,

Very interesting project!

Have you been able to verify the camera is working? ArduCam have their application and ino to stream from an Uno via Serial to a computer. That was my starting point when developing the Micropython driver.

Could you please also send through the library you are using for the camera? I couldn’t track one down with the function myCam.capture();

In this example the actual photo transfer happens on the lines around here: Arduino/ArduCAM/examples/mini/ArduCAM_Mini_2MP_Plus_VideoStreaming/ArduCAM_Mini_2MP_Plus_VideoStreaming.ino at 066a7ea1ccae4813e9a9b9d04e55f96bb8b4039e · ArduCAM/Arduino · GitHub

But a lot of the ‘bloat’ in there is to handle the multiple settings from the computer application.

Keen to see this one come together!
Liam

1 Like

Hi Liam.
Thanks so much.
I am using GitHub - simondlevy/BreezyArduCAM: A simple Arduino API for the ArduCAM Mini
I am more than happy to change to something else though.
Thanks again.

You need to read the image data from ArduCAM’s FIFO buffer after calling capture() and then send it via Serial.write().

1 Like

It’s probably best to start with the bare metal example (as recommended by the manufacturer) and add complexity as needed.

Hey @Dean293311 ,

Thanks for the updates! It seems the main issue is that after the camera captures an image, the Arduino isn’t reading the image data from the camera and sending it over serial.

Here’s what I suggest:

  • Start by running one of ArduCAM’s official example sketches that properly capture and transmit an image.
  • Once that’s working, add your LED control code.
  • Make sure the Arduino handles one task at a time (for example, turn on the LED, then capture the image, then turn off the LED), and that your Python script waits for each step to complete before moving on.

Also, avoid restarting the serial port inside the Arduino sketch while it’s running, as this can cause communication problems.

// Remove these lines from //turn off LED else{:
// Serial.end();
// delay(100);
// Serial.begin(115200);