So my setup is a Raspberry Pi 3 with a GrovePi+ board attached and the newest raspberry pi camera module. Connected to the GrovePi+ I have 3 temperature/humidity sensors, 1 magnetic reed switch, and a relay all attached to digital ports. The camera connected via the ribbon cable and the Raspberry Pi camera port. I have a script that runs every 15 minutes to take readings from the temperature/humidity and reed switch. The relay is activated manually through a script when it is needed. I have a script running continuously using the camera to detect motion by taking an initial picture and then continuously looping through another picture and comparing the images to detect changes and therefor motion, which then causes a video to start recording. After a different amount of time the script runs, it errors out with this message.
mmal: mmal_vc_component_enable: failed to enable component: ENOSPC
mmal: camera component couldn’t be enabled
mmal: main: Failed to create camera component
mmal: Failed to run camera app. Please check for firmware updates.
Everything is up to date and I am able to pictures or video manually whenever I want with no issues, it’s just when the script runs that I get this error. After some research it seems this error is do to a few possible things. Up to date firmware which mine is up to date. Accessing the camera from more than one process, which I do not believe to be caused by my script, I have the same script running on a Pi Zero with no GrovePi and do not experience this error. Another cause I have seen is the GPU Memory not being set high enough, I had it at 128 in /boot/config.txt and saw a post to bump it up to 144 and it fixed their issue, but that has not solved mine.
My question is, has there been any reported issues, I haven’t been able to find in the forum, related to the GrovePi’s I2C communication interfering with the camera port?
My camera script is below, maybe I missed something within it that causes the problem, possibly the camera process not closing out so when it comes back around it thinks the camera is being accessed by 2 different process.
import StringIO
import subprocess
import os
import time
from datetime import datetime
from PIL import Image
Motion detection settings:
Threshold - how much a pixel has to change by to be marked as “changed”
Sensitivity - how many changed pixels before capturing an image, needs to be higher if noisy view
ForceCapture - whether to force an image to be captured every forceCaptureTime seconds, values True or False
filepath - location of folder to save photos
filenamePrefix - string that prefixes the file name for easier identification of files.
diskSpaceToReserve - Delete oldest images to avoid filling disk. How much byte to keep free on disk.
cameraSettings - “” = no extra settings; “-hf” = Set horizontal flip of image; “-vf” = Set vertical flip; “-hf -vf” = both horizontal and vertical flip
threshold = 10
sensitivity = 30
forceCapture = False
forceCaptureTime = 60 * 60 # Once an hour
filepath = "/home/pi/Hub6/Camera"
filenamePrefix = "Hub6"
diskSpaceToReserve = 40 * 1024 * 1024 # Keep 40 mb free on disk
cameraSettings = “”
settings of the photos to save
saveWidth = 1296
saveHeight = 972
saveQuality = 15 # Set jpeg quality (0 to 100)
Test-Image settings
testWidth = 100
testHeight = 75
this is the default setting, if the whole image should be scanned for changed pixel
testAreaCount = 1
testBorders = [ [[1,testWidth],[1,testHeight]] ] # [ [[start pixel on left side,end pixel on right side],[start pixel on top side,stop pixel on bottom side]] ]
testBorders are NOT zero-based, the first pixel is 1 and the last pixel is testWith or testHeight
with “testBorders”, you can define areas, where the script should scan for changed pixel
for example, if your picture looks like this:
…XXXX
…
…
“.” is a street or a house, “X” are trees which move arround like crazy when the wind is blowing
because of the wind in the trees, there will be taken photos all the time. to prevent this, your setting might look like this:
testAreaCount = 2
testBorders = [ [[1,50],[1,75]], [[51,100],[26,75]] ] # area y=1 to 25 not scanned in x=51 to 100
even more complex example
testAreaCount = 4
testBorders = [ [[1,39],[1,75]], [[40,67],[43,75]], [[68,85],[48,75]], [[86,100],[41,75]] ]
in debug mode, a file debug.bmp is written to disk with marked changed pixel an with marked border of scan-area
debug mode should only be turned on while testing the parameters above
debugMode = False # False or True
Capture a small test image (for motion detection)
def captureTestImage(settings, width, height):
command = “raspistill %s -w %s -h %s -t 200 -e bmp -n -o -” % (settings, width, height)
imageData = StringIO.StringIO()
imageData.write(subprocess.check_output(command, shell=True))
imageData.seek(0)
im = Image.open(imageData)
buffer = im.load()
imageData.close()
return im, buffer
Save a full size image to disk
def saveImage(settings, width, height, quality, diskSpaceToReserve):
keepDiskSpaceFree(diskSpaceToReserve)
timestr = time.strftime("%m-%d-%Y_%H:%M:%S")
filename = filepath + “/” + filenamePrefix
print “Captured %s” % filename + timestr
os.system("raspivid -o /home/pi/Hub6/Camera/Hub6_"+timestr+".h264 -vf -t 60000 -n")
os.system("sudo chmod 777 /home/pi/Hub6/Camera/Hub6_"+timestr+".h264")
os.system("avconv -r 30 -i /home/pi/Hub6/Camera/Hub6_"+timestr+".h264 -vcodec copy /home/pi/Hub6/Camera/Hub6_"+timestr+".mp4")
os.system("sudo rm /home/pi/Hub6/Camera/Hub6_"+timestr+".h264")
Keep free space above given level
def keepDiskSpaceFree(bytesToReserve):
if (getFreeSpace() < bytesToReserve):
for filename in sorted(os.listdir(filepath + “/”)):
if filename.startswith(filenamePrefix) and filename.endswith(".jpg"):
os.remove(filepath + “/” + filename)
# print “Deleted %s/%s to avoid filling disk” % (filepath,filename)
if (getFreeSpace() > bytesToReserve):
return
Get available disk space
def getFreeSpace():
st = os.statvfs(filepath + “/”)
du = st.f_bavail * st.f_frsize
return du
Get first image
image1, buffer1 = captureTestImage(cameraSettings, testWidth, testHeight)
Reset last capture time
lastCapture = time.time()
while (True):
# Get comparison image
image2, buffer2 = captureTestImage(cameraSettings, testWidth, testHeight)
# Count changed pixels
changedPixels = 0
takePicture = False
if (debugMode): # in debug mode, save a bitmap-file with marked changed pixels and with visible testarea-borders
debugimage = Image.new("RGB",(testWidth, testHeight))
debugim = debugimage.load()
for z in xrange(0, testAreaCount): # = xrange(0,1) with default-values = z will only have the value of 0 = only one scan-area = whole picture
for x in xrange(testBorders[z][0][0]-1, testBorders[z][0][1]): # = xrange(0,100) with default-values
for y in xrange(testBorders[z][1][0]-1, testBorders[z][1][1]): # = xrange(0,75) with default-values; testBorders are NOT zero-based, buffer1[x,y] are zero-based (0,0 is top left of image, testWidth-1,testHeight-1 is botton right)
if (debugMode):
debugim[x,y] = buffer2[x,y]
if ((x == testBorders[z][0][0]-1) or (x == testBorders[z][0][1]-1) or (y == testBorders[z][1][0]-1) or (y == testBorders[z][1][1]-1)):
# print "Border %s %s" % (x,y)
debugim[x,y] = (0, 0, 255) # in debug mode, mark all border pixel to blue
# Just check green channel as it's the highest quality channel
pixdiff = abs(buffer1[x,y][1] - buffer2[x,y][1])
if pixdiff > threshold:
changedPixels += 1
if (debugMode):
debugim[x,y] = (0, 255, 0) # in debug mode, mark all changed pixel to green
# Save an image if pixels changed
if (changedPixels > sensitivity):
takePicture = True # will shoot the photo later
if ((debugMode == False) and (changedPixels > sensitivity)):
break # break the y loop
if ((debugMode == False) and (changedPixels > sensitivity)):
break # break the x loop
if ((debugMode == False) and (changedPixels > sensitivity)):
break # break the z loop
if (debugMode):
debugimage.save(filepath + "/debug.bmp") # save debug image as bmp
# print "debug.bmp saved, %s changed pixel" % changedPixels
# else:
# print "%s changed pixel" % changedPixels
# Check force capture
if forceCapture:
# if time.time() - lastCapture > forceCaptureTime:
# takePicture = True
if takePicture:
lastCapture = time.time()
saveImage(cameraSettings, saveWidth, saveHeight, saveQuality, diskSpaceToReserve)
# Swap comparison buffers