Search code examples
pythonraspberry-pi

Access Picamera2 within a surrounding class on Raspberry Pi


I am working on a robot, and am in the process of connecting to the hardware through python on a raspberry pi. All of my mini test programs work, but I am having issues merging them into 1 class that contains all hardware interactions. Everything works except the Picamera2 camera. Please see class below. Running this directly through idle as the main class works no problem. Calling this class and making an object in another results in the error

Traceback (most recent call last):
  File "/home/sox/Documents/Sox/main.py", line 6, in <module>
    soxHardware = Hardware()
  File "/home/sox/Documents/Sox/utils/HardwareUtils.py", line 72, in __init__
    self.picam2 = Picamera2()
  File "/usr/lib/python3/dist-packages/picamera2/picamera2.py", line 249, in __init__
    raise RuntimeError("Camera __init__ sequence did not complete.")
RuntimeError: Camera __init__ sequence did not complete.

Class code

#NOTE: ALL FUNCTIONS CAN BE BYPASSED
#Just call the object directly
#import time
import board


import digitalio
import time

#for battery
import smbus
import struct

#for gyro
import adafruit_mpu6050

#for touch
import adafruit_mpr121

#for servoDriver
from adafruit_pca9685 import PCA9685
from adafruit_motor import servo

#for camera
from picamera2 import Picamera2





class Hardware:

     def __init__(self):
          #setup all IO ports
          self.ledRed = digitalio.DigitalInOut(board.D11)
          self.ledGreen = digitalio.DigitalInOut(board.D9)
          self.ledBlue = digitalio.DigitalInOut(board.D10)

          self.ledEars = digitalio.DigitalInOut(board.D22)
          self.ledLaser = digitalio.DigitalInOut(board.D27)

          self.speakerMute = digitalio.DigitalInOut(board.D17)


          #set port direction as output
          self.ledRed.direction = digitalio.Direction.OUTPUT
          self.ledGreen.direction = digitalio.Direction.OUTPUT
          self.ledBlue.direction = digitalio.Direction.OUTPUT

          self.ledEars.direction = digitalio.Direction.OUTPUT
          self.ledLaser.direction = digitalio.Direction.OUTPUT

          self.speakerMute.direction = digitalio.Direction.OUTPUT

          #i2c setup
          i2c = board.I2C()  # uses board.SCL and board.SDA
          #gyro
          self.gyro = adafruit_mpu6050.MPU6050(i2c, 0x69)
          #touch
          self.touch = adafruit_mpr121.MPR121(i2c)
          #servoDriver
          pca = PCA9685(i2c)
          pca.frequency = 50
          self.servo0 = servo.Servo(pca.channels[0])

          #battery
          self.I2C_ADDR    = 0x36
          self.bus = smbus.SMBus(1) # 0 = /dev/i2c-0 (port I2C0), 1 = /dev/i2c-1 (port I2C1)


          #set up camera
          self.picam2 = Picamera2()
          camera_config = self.picam2.create_preview_configuration()
          self.picam2.configure(camera_config)
          self.picam2.start()
          time.sleep(2)


     def readVoltage(self):
          read = self.bus.read_word_data(self.I2C_ADDR, 2)
          swapped = struct.unpack("<H", struct.pack(">H", read))[0]
          voltage = swapped * 1.25 /1000/16
          return voltage

     def readCapacity(self):
          read = self.bus.read_word_data(self.I2C_ADDR, 4)
          swapped = struct.unpack("<H", struct.pack(">H", read))[0]
          capacity = swapped/256
          return capacity



     def laser(self, status):
         self.ledLaser.value = status
         return True

     def flashlight(self, status):
         self.ledRed.value = status
         self.ledGreen.value = status
         self.ledBlue.value = status
         return True

     def ears(self, status):
         self.ledEars.value = status
         return True

     def muteSpeaker(self, status):
         self.speakerMute.value = status
         return True

     def checkBatteryStatus(self):
         print(self.readVoltage())
         print(self.readCapacity())
         return True

     def readGyro(self):
         print("Acceleration: X:%.2f, Y: %.2f, Z: %.2f m/s^2" % (self.gyro.acceleration))
         print("Gyro X:%.2f, Y: %.2f, Z: %.2f rad/s" % (self.gyro.gyro))
         print("Temperature: %.2f C" % self.gyro.temperature)
         print("")

     def getTouch(self, index):
         return self.touch[index].value

     def getTouchArray(self):
         array = [False]*12
         for i in range(12):
             array[i] = self.touch[i].value
         return array

     def takeImage(self,path):
          self.picam2.capture_file(path)


if __name__ == '__main__':
     hardware=Hardware()
     hardware.checkBatteryStatus()
     hardware.readGyro()
     print(hardware.getTouch(0))
     print(hardware.getTouchArray())


     hardware.takeImage("img.png")

     while True:
         hardware.servo0.angle = 0
         time.sleep(1)
         hardware.servo0.angle = 180
         time.sleep(1)

Test program that crashes with the error mentioned above

from utils.HardwareUtils import Hardware


soxHardware = Hardware()

I am also willing to refactor this entire section to make it more friendly, and know that there are probably some bad practices in it. I have used python as a scripting language extensively, but not as an object oriented language


Solution

  • i`ve tested your code. its OK:

    import time
    
    #for camera
    from picamera2 import Picamera2
    
    
    class Hardware:
    
         def __init__(self):         
              
              #set up camera
              self.picam2 = Picamera2()
              camera_config = self.picam2.create_preview_configuration()
              self.picam2.configure(camera_config)
              self.picam2.start()
              time.sleep(2)
    
         def takeImage(self,path):
              self.picam2.capture_file(path)
    
    
    if __name__ == '__main__':
         hardware=Hardware()
         
         hardware.takeImage("img.png")
    

    the error usually appears when u didnt close (picam2.close()) camera from the last use of it.