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.
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.
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()
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();
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);