KkoRack 화성탐사

한국형 퍼서비어런스 꼬꼬락 화성 착륙

https://youtu.be/1ULRCABQgUI?si=RDhXUKBAGHkVIwxe

실행 동영상

실행 동영상 

Main

KKorack GPIO setting.pptx

RaspberryPi GPIO.png

startKK.sh

stopKK.sh

statusKK.sh

KKserver.py

StepMotor

 

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import RPi.GPIO as gpio
from time import sleep

gpio.setmode(gpio.BOARD)
gpio.setup(12, gpio.OUT)
gpio.setup(18, gpio.OUT)
p1 = gpio.PWM(12, 50)  # 50 Hz
p2 = gpio.PWM(18, 50)  # 50 Hz

p1.start(0)
p2.start(0)

#  0도 
#p.ChangeDutyCycle(3)
#sleep(1)

# 180도
#p.ChangeDutyCycle(12)
#sleep(1)

# 90도
p1.ChangeDutyCycle(7.5)
p2.ChangeDutyCycle(7.5)
p1.ChangeDutyCycle(0)
p2.ChangeDutyCycle(0)

exitLoop = True
while(exitLoop):
    val = input("input(3~7.5~12), #좌우(6), #상하(6) = ")
    if val == "-1":
        exitLoop = False
    else :
        p1.ChangeDutyCycle(float(val.split(',')[0]))
        p2.ChangeDutyCycle(float(val.split(',')[1]))
        sleep(0.2)
        p1.ChangeDutyCycle(0)
        p2.ChangeDutyCycle(0)
    

p1.stop()
p2.stop()
gpio.cleanup()

VideoStream

usbwebcamera.py

import os
import sys
import time
import math
import getopt
import numpy as np
import cv2
import threading
import subprocess
from collections import deque

from lock_manager import Lock_Manager
from util import Util

class UsbWebCamera(threading.Thread):
        def __init__(self, video_source=1, source=None, do_record=True, do_display=True, do_add_contours=True, do_add_target=False):
                threading.Thread.__init__(self)

                self.name = self.__class__.__name__
                self.archive = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'archive')

                self.writer = None
                self.current_frame = None

                self.codec = cv2.VideoWriter_fourcc('M','J', 'P', 'G')
                self.OBSERVER_LENGTH = 5 # Time in seconds to be observed for motion
                self.threshold = 15

                self.CAMERA_SOURCE = video_source
                self.REMAIN_RECORDING_FILES = 3 # 10이상 부터 삭제 후 저장
                self.do_display = do_display
                self.do_record = do_record
                self.do_add_contours = do_add_contours
                self.do_add_target = do_add_target
                self.current_file = None
                self.source = cv2.VideoCapture(source) if source is not None else self.init_camera()
                self.fps = self.find_fps(self.source)
                self.height, self.width = self.get_dimensions(self.source)
                Util.log(self.name, "Initializing usb camera class with video_source=" + str(self.CAMERA_SOURCE))
                Util.log(self.name,"width: {"+str(self.width)+"}, height : {"+str(self.height)+"}")

                self.lock_manager = Lock_Manager("motion")

        def __del__(self):
                # Release camera
                self.source.release()

                # Close all windows
                cv2.destroyAllWindows()

                # Remove lock if exists
                self.lock_manager.remove()

        def get_frame(self):
                """
                Return the current frame

                @return bytes
                """
                return self.frame_to_jpg(self.current_frame) if self.current_frame is not None else None

        def frame_to_jpg(self, frame):
                """
                Convert video frame to jpg

                @param array frame
                @return bytes
                """
                ret, jpeg = cv2.imencode('.jpg', self.current_frame)
                return jpeg.tobytes()

        def get_dimensions(self, source):
                """
                Determine height and width of the video source

                @return tuple(int, int)
                """
                frame = cv2.cvtColor(source.read()[1],cv2.COLOR_RGB2GRAY)
                return frame.shape[0: 2]

        def find_fps(self, source):
                """
                Determine frames per second of the video source

                @param video source
                @return int
                """
                Util.log(self.name, "Determining FPS...")

                # How many frames to capture
                num_frames = 120

                # Start time
                start = time.time()

                # Grab a few frames
                for i in range(0, num_frames):
                        ret, frame = source.read()

                # End time
                end = time.time()

                # Calculate frames per second
                fps = int(math.floor(num_frames / (end - start)))
                Util.log(self.name, "Setting FPS to " + str(fps))

                return fps

        def init_camera(self):
                """
                Start the camera

                @return cv2.VideoCapture
                """
                # Init camera
                camera = cv2.VideoCapture(self.CAMERA_SOURCE)
                #camera.set(3, 320)
                #camera.set(4, 240)

                # Wait half a second for light adjustment
                time.sleep(0.5)

                return camera

        def start_recording(self):
                """
                Setup the recorder
                """

                self.current_file = self.archive + "/" + self.detected_at + "-usb.avi"

                Util.log(self.name, "Motion detected! Recording...")

                # Set path and FPS
                self.writer = cv2.VideoWriter(self.current_file, self.codec, self.fps, (self.width, self.height))

        def stop_recording(self):
                """
                Reset values to default
                """
                self.writer = None
                self.current_file = None
                self.detected_at = None

        def convert_to_mp4(self, path):
                """
                Convert video file to mp4 using ffmpeg

                @param string path
                """
                try:
                        Util.log(self.name, "Converting video...")
                        destination = os.path.splitext(path)[0] + '.mp4'
                        cmd = 'ffmpeg -i "{}" "{}" 2> /dev/null && rm "{}"'.format(path, destination, path)
                        #cmd = 'for i in ' + self.archive + '/*.avi; do ffmpeg -i "$i" "${i%.*}.mp4" 2> /dev/null && rm "$i"; done'
                        p = subprocess.Popen(cmd, shell=True)
                        (output, err) = p.communicate()

                except subprocess.CalledProcessError:
                        Util.log(self.name, "Error converting video")

        def run(self):
                """
                Main worker
                """
                observer = deque(maxlen=self.fps * self.OBSERVER_LENGTH)
                previous_frame = None

                while True:
                        # Grab a frame
                        (grabbed, self.current_frame) = self.source.read()

                        # End of feed
                        if not grabbed:
                                break

                        # Gray frame
                        frame_gray = cv2.cvtColor(self.current_frame, cv2.COLOR_BGR2GRAY)

                        # Blur frame
                        frame_blur = cv2.GaussianBlur(frame_gray, (21, 21), 0)

                        # If there's no previous frame, us the current one
                        if previous_frame is None:
                                previous_frame = frame_blur
                                continue

                        # Delta frame
                        delta_frame = cv2.absdiff(previous_frame, frame_blur)

                        # Threshold frame
                        threshold_frame = cv2.threshold(delta_frame, 15, 255, cv2.THRESH_BINARY)[1]

                        # Dilate the thresholded image to fill in holes
                        kernel = np.ones((5, 5), np.uint8)
                        dilated_frame = cv2.dilate(threshold_frame, kernel, iterations=4)

                        # Find difference in percent
                        res = dilated_frame.astype(np.uint8)
                        movement = (np.count_nonzero(res) * 100) / res.size

                        # Add movement percentage to observer
                        observer.append(movement)

                        if self.do_add_contours or self.do_add_target:
                                self.current_frame, targets = self.add_contours(self.current_frame, dilated_frame)

                                if self.do_add_target:
                                        self.current_frame = self.add_target(self.current_frame, targets)

                        if self.do_record and self.detected(sum([x > self.threshold for x in observer]) > 0):
                                if not self.recording():
                                        self.start_recording()

                                self.writer.write(self.current_frame)
                        elif self.recording():
                                # Delete Old files
                                self.delete()
                                
                                # Convert
                                self.convert_to_mp4(self.current_file)

                                # Reset all
                                self.stop_recording()

                                Util.log(self.name, "Observing...")

                        # Set blurred frame as new previous frame
                        previous_frame = frame_blur

                        # Display
                        if self.do_display:
                                cv2.imshow("Current frame:", self.current_frame)

                        # Exit on 'q'
                        key = cv2.waitKey(1) & 0xFF

                        if key == ord('q'):
                                break

        def delete(self):
                """
                delete mic data to a mp4 file.
                @param list data
                """
                count = 0
                Util.log(self.name, "Delete USB Cam video...")
                
                file_list = sorted(os.listdir(self.archive), reverse=True)
                for filename in [file for file in file_list if file.endswith("usb.mp4")]:
                        if not filename.startswith('.'):
                                type = self.get_type(filename)
                                if type == "video":
                                        count = count + 1
                                        if self.REMAIN_RECORDING_FILES < count:
                                                Util.log(self.name, "Delete USB video filename=" + filename + ", type=" + type + ", count=" + str(count))
                                                os.remove(self.archive + "/" + filename)

        def get_type(self, filename):
                name, extension = os.path.splitext(filename)
                return 'video' if extension == '.mp4' else 'video' if extension == '.avi' else 'audio' if extension == '.wav' else 'audio' if extension == '.mp3' else 'photo'

        def add_contours(self, raw_frame, dilated_frame):
                """
                Add contours to frame

                @param array raw_frame
                @param array dilated_frame
                @return tuple(array, list)
                """
                # Find contours on thresholded image
                _, contours, nada = cv2.findContours(dilated_frame.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

                # Make coutour frame
                contour_frame = raw_frame.copy()

                # Target contours
                targets = []

                # Loop over the contour
                for c in contours:
                        # If the contour is too small, ignore it
                        if cv2.contourArea(c) < 500:
                                # Make sure this has a less than sign, not an html escape
                                continue

                        # Contour data
                        M = cv2.moments(c)
                        cx = int(M['m10']/M['m00'])
                        cy = int(M['m01']/M['m00'])
                        x, y, w, h = cv2.boundingRect(c)
                        rx = x + int(w / 2)
                        ry = y + int(h / 2)
                        ca = cv2.contourArea(c)

                        # plot contours
                        cv2.drawContours(contour_frame,[c],0,(0,0,255),2)
                        cv2.rectangle(contour_frame,(x,y),(x+w,y+h),(0,255,0),2)
                        cv2.circle(contour_frame,(cx,cy),2,(0,0,255),2)
                        cv2.circle(contour_frame,(rx,ry),2,(0,255,0),2)

                        # save target contours
                        targets.append((rx,ry,ca))

                return contour_frame, targets

        def add_target(self, raw_frame, targets):
                """
                Add crosshairs to frame

                @param array raw_frame
                @param list targets
                @return array
                """
                # Make target
                area = sum([x[2] for x in targets])
                mx = 0
                my = 0

                if targets:
                        for x, y, a in targets:
                                mx += x
                                my += y
                        mx = int(round(mx / len(targets), 0))
                        my = int(round(my / len(targets), 0))

                # Plot target
                tr = 50
                target_frame = raw_frame.copy()

                if targets:
                        cv2.circle(target_frame, (mx, my), tr, (0, 0, 255, 0), 2)
                        cv2.line(target_frame, (mx - tr, my), (mx + tr, my), (0, 0, 255, 0), 2)
                        cv2.line(target_frame, (mx, my - tr), (mx, my + tr), (0, 0, 255, 0), 2)

                return target_frame

        def detected(self, has_motion):
                """
                Check if this or another detector detected something

                @param boolean has_motion
                @return boolean
                """
                if has_motion:
                        self.lock_manager.set()
                else:
                        self.lock_manager.remove()

                self.detected_at = self.lock_manager.get_lock_time()

                return self.detected_at is not None

        def recording(self):
                """
                Check if currently recording

                @return boolean
                """
                return self.writer is not None

if __name__ == "__main__":
        args = sys.argv[1:]
        source = None
        do_display = False

        try:
                opts, args = getopt.getopt(args, "hs:d",["source=", "display"])
        except getopt.GetoptError:
                print('python3 motion_detector.py -s <source> [-d]')
                sys.exit(2)

        for opt, arg in opts:
                if opt == '-h':
                        print('python3 motion_detector.py -s <source> [-d]')
                        sys.exit()
                elif opt in ("-s", "--source"):
                        source = arg.strip()
                elif opt in ("-d", "--display"):
                        do_display = True

        if source is not None:
                print('Input: ', source)
        else:
                print('Input: Camera')

        if source is not None and not os.path.isfile(source):
                print(str(source) + " does not exist")
        else:
                md = Motion_Detector(source=source, do_display=do_display, do_add_contours=True)
                md.start()

              

piwebcamera.py

import os
import sys
import time
import math
import getopt
import numpy as np
import cv2
import threading
import subprocess
from collections import deque

from lock_manager import Lock_Manager
from util import Util

class PiWebCamera(threading.Thread):
        def __init__(self, video_source=0, source=None, do_record=True, do_display=True, do_add_contours=True, do_add_target=False):
                threading.Thread.__init__(self)

                self.name = self.__class__.__name__
                self.archive = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'archive')

                self.writer = None
                self.current_frame = None

                self.codec = cv2.VideoWriter_fourcc('M','J', 'P', 'G')
                self.OBSERVER_LENGTH = 5 # Time in seconds to be observed for motion
                self.threshold = 15

                self.CAMERA_SOURCE = video_source
                self.REMAIN_RECORDING_FILES = 3 # 10이상 부터 삭제 후 저장
                self.do_display = do_display
                self.do_record = do_record
                self.do_add_contours = do_add_contours
                self.do_add_target = do_add_target
                self.current_file = None

                self.source = cv2.VideoCapture(source) if source is not None else self.init_camera()

                self.fps = self.find_fps(self.source)
                self.height, self.width = self.get_dimensions(self.source)
                Util.log(self.name, "Initializing pi camera class with video_source=" + str(self.CAMERA_SOURCE))
                Util.log(self.name,"width: {"+str(self.width)+"}, height : {"+str(self.height)+"}")

                self.lock_manager = Lock_Manager("motion")

        def __del__(self):
                # Release camera
                self.source.release()

                # Close all windows
                cv2.destroyAllWindows()

                # Remove lock if exists
                self.lock_manager.remove()

        def get_frame(self):
                """
                Return the current frame

                @return bytes
                """
                return self.frame_to_jpg(self.current_frame) if self.current_frame is not None else None

        def frame_to_jpg(self, frame):
                """
                Convert video frame to jpg

                @param array frame
                @return bytes
                """
                ret, jpeg = cv2.imencode('.jpg', self.current_frame)
                return jpeg.tobytes()

        def get_dimensions(self, source):
                """
                Determine height and width of the video source

                @return tuple(int, int)
                """
                frame = cv2.cvtColor(source.read()[1],cv2.COLOR_RGB2GRAY)
                return frame.shape[0: 2]

        def find_fps(self, source):
                """
                Determine frames per second of the video source

                @param video source
                @return int
                """
                Util.log(self.name, "Determining FPS...")

                # How many frames to capture
                num_frames = 120

                # Start time
                start = time.time()

                # Grab a few frames
                for i in range(0, num_frames):
                        ret, frame = source.read()

                # End time
                end = time.time()

                # Calculate frames per second
                fps = int(math.floor(num_frames / (end - start)))
                Util.log(self.name, "Setting FPS to " + str(fps))

                return fps

        def init_camera(self):
                """
                Start the camera

                @return cv2.VideoCapture
                """
                # Init camera
                camera = cv2.VideoCapture(self.CAMERA_SOURCE)
                #camera.set(3, 320)
                #camera.set(4, 240)

                # Wait half a second for light adjustment
                time.sleep(0.5)

                return camera

        def start_recording(self):
                """
                Setup the recorder
                """

                self.current_file = self.archive + "/" + self.detected_at + "-pic.avi"

                Util.log(self.name, "Motion detected! Recording...")

                # Set path and FPS
                self.writer = cv2.VideoWriter(self.current_file, self.codec, self.fps, (self.width, self.height))

        def stop_recording(self):
                """
                Reset values to default
                """
                self.writer = None
                self.current_file = None
                self.detected_at = None

        def convert_to_mp4(self, path):
                """
                Convert video file to mp4 using ffmpeg

                @param string path
                """
                try:
                        Util.log(self.name, "Converting video...")
                        destination = os.path.splitext(path)[0] + '.mp4'
                        cmd = 'ffmpeg -i "{}" "{}" 2> /dev/null && rm "{}"'.format(path, destination, path)
                        #cmd = 'for i in ' + self.archive + '/*.avi; do ffmpeg -i "$i" "${i%.*}.mp4" 2> /dev/null && rm "$i"; done'
                        p = subprocess.Popen(cmd, shell=True)
                        (output, err) = p.communicate()

                except subprocess.CalledProcessError:
                        Util.log(self.name, "Error converting video")

        def run(self):
                """
                Main worker
                """
                observer = deque(maxlen=self.fps * self.OBSERVER_LENGTH)
                previous_frame = None

                while True:
                        # Grab a frame
                        (grabbed, self.current_frame) = self.source.read()

                        # End of feed
                        if not grabbed:
                                break

                        # Gray frame
                        frame_gray = cv2.cvtColor(self.current_frame, cv2.COLOR_BGR2GRAY)

                        # Blur frame
                        frame_blur = cv2.GaussianBlur(frame_gray, (21, 21), 0)

                        # If there's no previous frame, us the current one
                        if previous_frame is None:
                                previous_frame = frame_blur
                                continue

                        # Delta frame
                        delta_frame = cv2.absdiff(previous_frame, frame_blur)

                        # Threshold frame
                        threshold_frame = cv2.threshold(delta_frame, 15, 255, cv2.THRESH_BINARY)[1]

                        # Dilate the thresholded image to fill in holes
                        kernel = np.ones((5, 5), np.uint8)
                        dilated_frame = cv2.dilate(threshold_frame, kernel, iterations=4)

                        # Find difference in percent
                        res = dilated_frame.astype(np.uint8)
                        movement = (np.count_nonzero(res) * 100) / res.size

                        # Add movement percentage to observer
                        observer.append(movement)

                        if self.do_add_contours or self.do_add_target:
                                self.current_frame, targets = self.add_contours(self.current_frame, dilated_frame)

                                if self.do_add_target:
                                        self.current_frame = self.add_target(self.current_frame, targets)

                        if self.do_record and self.detected(sum([x > self.threshold for x in observer]) > 0):
                                if not self.recording():
                                        self.start_recording()

                                self.writer.write(self.current_frame)
                        elif self.recording():
                                # Delete Old files
                                self.delete()
                                
                                # Convert
                                self.convert_to_mp4(self.current_file)

                                # Reset all
                                self.stop_recording()

                                Util.log(self.name, "Observing...")

                        # Set blurred frame as new previous frame
                        previous_frame = frame_blur

                        # Display
                        if self.do_display:
                                cv2.imshow("Current frame:", self.current_frame)

                        # Exit on 'q'
                        key = cv2.waitKey(1) & 0xFF

                        if key == ord('q'):
                                break

        def delete(self):
                """
                delete mic data to a mp4 file.
                @param list data
                """
                count = 0
                Util.log(self.name, "Delete PI Cam video...")
                
                file_list = sorted(os.listdir(self.archive), reverse=True)
                for filename in [file for file in file_list if file.endswith("pic.mp4")]:
                        if not filename.startswith('.'):
                                type = self.get_type(filename)
                                if type == "video":
                                        count = count + 1
                                        if self.REMAIN_RECORDING_FILES < count:
                                                Util.log(self.name, "Delete PIC video filename=" + filename + ", type=" + type + ", count=" + str(count))
                                                os.remove(self.archive + "/" + filename)

        def get_type(self, filename):
                name, extension = os.path.splitext(filename)
                return 'video' if extension == '.mp4' else 'video' if extension == '.avi' else 'audio' if extension == '.wav' else 'audio' if extension == '.mp3' else 'photo'

        def add_contours(self, raw_frame, dilated_frame):
                """
                Add contours to frame

                @param array raw_frame
                @param array dilated_frame
                @return tuple(array, list)
                """
                # Find contours on thresholded image
                _, contours, nada = cv2.findContours(dilated_frame.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

                # Make coutour frame
                contour_frame = raw_frame.copy()

                # Target contours
                targets = []

                # Loop over the contour
                for c in contours:
                        # If the contour is too small, ignore it
                        if cv2.contourArea(c) < 500:
                                # Make sure this has a less than sign, not an html escape
                                continue

                        # Contour data
                        M = cv2.moments(c)
                        cx = int(M['m10']/M['m00'])
                        cy = int(M['m01']/M['m00'])
                        x, y, w, h = cv2.boundingRect(c)
                        rx = x + int(w / 2)
                        ry = y + int(h / 2)
                        ca = cv2.contourArea(c)

                        # plot contours
                        cv2.drawContours(contour_frame,[c],0,(0,0,255),2)
                        cv2.rectangle(contour_frame,(x,y),(x+w,y+h),(0,255,0),2)
                        cv2.circle(contour_frame,(cx,cy),2,(0,0,255),2)
                        cv2.circle(contour_frame,(rx,ry),2,(0,255,0),2)

                        # save target contours
                        targets.append((rx,ry,ca))

                return contour_frame, targets

        def add_target(self, raw_frame, targets):
                """
                Add crosshairs to frame

                @param array raw_frame
                @param list targets
                @return array
                """
                # Make target
                area = sum([x[2] for x in targets])
                mx = 0
                my = 0

                if targets:
                        for x, y, a in targets:
                                mx += x
                                my += y
                        mx = int(round(mx / len(targets), 0))
                        my = int(round(my / len(targets), 0))

                # Plot target
                tr = 50
                target_frame = raw_frame.copy()

                if targets:
                        cv2.circle(target_frame, (mx, my), tr, (0, 0, 255, 0), 2)
                        cv2.line(target_frame, (mx - tr, my), (mx + tr, my), (0, 0, 255, 0), 2)
                        cv2.line(target_frame, (mx, my - tr), (mx, my + tr), (0, 0, 255, 0), 2)

                return target_frame

        def detected(self, has_motion):
                """
                Check if this or another detector detected something

                @param boolean has_motion
                @return boolean
                """
                if has_motion:
                        self.lock_manager.set()
                else:
                        self.lock_manager.remove()

                self.detected_at = self.lock_manager.get_lock_time()

                return self.detected_at is not None

        def recording(self):
                """
                Check if currently recording

                @return boolean
                """
                return self.writer is not None

if __name__ == "__main__":
        args = sys.argv[1:]
        source = None
        do_display = False

        try:
                opts, args = getopt.getopt(args, "hs:d",["source=", "display"])
        except getopt.GetoptError:
                print('python3 motion_detector.py -s <source> [-d]')
                sys.exit(2)

        for opt, arg in opts:
                if opt == '-h':
                        print('python3 motion_detector.py -s <source> [-d]')
                        sys.exit()
                elif opt in ("-s", "--source"):
                        source = arg.strip()
                elif opt in ("-d", "--display"):
                        do_display = True

        if source is not None:
                print('Input: ', source)
        else:
                print('Input: Camera')

        if source is not None and not os.path.isfile(source):
                print(str(source) + " does not exist")
        else:
                md = Motion_Detector(source=source, do_display=do_display, do_add_contours=True)
                md.start()

capture.py

import os
import cv2
import datetime, time
from pathlib import Path

archive_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'archive')

def capture_and_save(im):
    s = im.shape
    # Add a timestamp
    font = cv2.FONT_HERSHEY_SIMPLEX
    bottomLeftCornerOfText = (10,s[0]-10)
    fontScale = 1
    fontColor = (20,20,20)
    lineType = 2

    cv2.putText(im,datetime.datetime.now().isoformat().split(".")[0],bottomLeftCornerOfText,font,fontScale,fontColor, lineType)

    m = 0
    p = Path(archive_path)
    for imp in p.iterdir():
        if imp.suffix == ".png" and imp.stem != "last":
            num = imp.stem.split("_")[1]
            try:
                num = int(num)
                if num>m:
                    m = num
            except:
                print("Error reading image number for",str(imp))
    m +=1
    lp = Path(archive_path + "/last.png")
    if lp.exists() and lp.is_file():
        np = Path(archive_path + "/img_{}.png".format(m))
        np.write_bytes(lp.read_bytes())
    cv2.imwrite(archive_path + "/last.png",im)

if __name__=="__main__":
    capture_and_save()
    print("done")

Noise Detector

 

noise_detector.py

# Threshold / Sliding window
# https://raw.githubusercontent.com/jeysonmc/python-google-speech-scripts/master/stt_google.py

# WebSocket streaming:
# https://gist.github.com/fopina/3cefaed1b2d2d79984ad7894aef39a68

import pyaudio
import wave
import audioop
import subprocess
import os
import time
import math
import struct
import threading
import io
import numpy as np
from collections import deque

from lock_manager import Lock_Manager
from util import Util

class Noise_Detector(threading.Thread):
        def __init__(self):
                threading.Thread.__init__(self)

                self.name               = self.__class__.__name__

                self.FORMAT             = pyaudio.paFloat32
                self.RATE               = 48000 # Hz, so samples (bytes) per second
                self.CHUNK_SIZE                 = 8192 # How many bytes to read from mic each time (stream.read())
                self.CHUNKS_PER_SEC             = math.floor(self.RATE / self.CHUNK_SIZE) # How many chunks make a second? (16.000 bytes/s, each chunk is 1.024 bytes, so 1s is 15 chunks)
                self.CHANNELS           = 1
                self.HISTORY_LENGTH     = 2 # Seconds of audio cache for prepending to records to prevent chopped phrases (history length + observer length = min record length)
                self.OBSERVER_LENGTH    = 5     # Time in seconds to be observed for noise
                self.NOTIFICATION_LIMIT = 1 # Seconds before a notification is sent
                self.LIMIT_RECODING     = 100 # 최대 Recoding chunk 수 
                self.CURRENT_RECODING_TIME = 0 # 현재 Recoding chunk 수 
                self.REMAIN_RECORDING_FILES = 3 # 10이상 부터 삭제 후 저장 
                self.RECODING_OVER_THRESHOLD = 5 # Recoding 임계값을 연속 넘는 회수로 저장 여부 판단 

                self.archive            = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'archive')
                self.current_file       = None
                self.chunk              = None
                self.record             = [] # Stores audio chunks
                self.notified           = False # If we already sent a notification

                self.audio              = pyaudio.PyAudio()
                self.stream             = self.get_stream()

                self.threshold          = self.determine_threshold()

                self.lock_manager       = Lock_Manager("noise")
                self.detected_at        = None

        def __del__(self):
                # Stop recording
                if self.stream:
                        self.stream.close()

                if self.audio:
                        self.audio.terminate()

                # Remove lock if exists
                self.lock_manager.remove()

        def get_stream(self):
                """
                Open audio stream

                @return PyAudio
                """
                return self.audio.open(
                        format=self.FORMAT,
                        channels=self.CHANNELS,
                        rate=self.RATE,
                        input=True,
                        frames_per_buffer=self.CHUNK_SIZE
                )

        def determine_threshold(self):
                """
                Determine threshold noise intensity using RMS
                Anything below the threshold is considered silence

                @return float
                """
                Util.log(self.name, "Determining threshold...")

                res = []
                for x in range(50):
                        block = self.stream.read(self.CHUNK_SIZE)
                        rms = self.get_rms(block)
                        res.append(rms)

                # Set threshold to 20% above avergae
                threshold = (sum(res) / len(res)) * 1.7 #1.2
                Util.log(self.name, "Setting threshold to: " + str(threshold))

                return threshold

        def get_rms(self, block):
                """
                Calculate Root Mean Square (noise level) for audio chunk

                @param bytes block
                @return float
                """
                d = np.frombuffer(block, np.float32).astype(np.float)
                return np.sqrt((d * d).sum() / len(d))

        def start_recording(self):
                """
                Setup the recorder
                """
                self.current_file = self.archive + "/" + self.detected_at + ".wav"

                Util.log(self.name, "Noise detected! Recording...")

        def stop_recording(self):
                """
                Reset variables to default
                """
                self.current_file = None
                self.detected_at = None
                self.notified = False
                self.record = []
                self.CURRENT_RECODING_TIME = 0

        def run(self):
                """
                Detect noise from microphone and record
                Noise is defined as sound surrounded by silence (according to threshold)
                """

                # Stores audio intensity of previous sound-chunks
                # If one of these chunks is above threshold, recording gets triggered
                # Keep the last {OBSERVER_LENGTH} seconds in observer
                observer = deque(maxlen=self.OBSERVER_LENGTH * self.CHUNKS_PER_SEC)

                # Prepend audio from before noise was detected
                # Keep the last {HISTORY_LENGTH} seconds in history
                history = deque(maxlen=self.HISTORY_LENGTH * self.CHUNKS_PER_SEC)

                Util.log(self.name, "Listening...")

                try:
                        while True:
                                # Current chunk of audio data
                                self.chunk = self.stream.read(self.CHUNK_SIZE, exception_on_overflow = False)
                                history.append(self.chunk)

                                # Add noise level of this chunk to the sliding-window
                                rms = self.get_rms(self.chunk)
                                #Util.log(self.name, "Noise threshold=" + str(rms))
                                observer.append(rms)

                                if self.detected(sum([x > self.threshold for x in observer]) > self.RECODING_OVER_THRESHOLD) and self.LIMIT_RECODING > self.CURRENT_RECODING_TIME:
                                        self.CURRENT_RECODING_TIME = self.CURRENT_RECODING_TIME + 1 
                                        # There's at least one chunk in the sliding-window above threshold
                                        if not self.recording():
                                                self.start_recording()

                                        #Util.log(self.name, "Record.append noise level="+ str(sum([x > self.threshold for x in observer])) + ", time=" + str(self.CURRENT_RECODING_TIME) )
                                        self.record.append(self.chunk)

                                        if not self.notified and len(self.record) > self.NOTIFICATION_LIMIT * self.CHUNKS_PER_SEC:
                                                self.notify()
                                elif self.recording():
                                        # Silence limit was reached, finish recording and save
                                        self.delete()
                                        self.save(list(history) + self.record)
                                        self.stop_recording()

                                        Util.log(self.name, "Listening...")
                except KeyboardInterrupt:
                        Util.log(self.name, "Interrupted.")

        def get_chunk(self):
                """
                Return the current chunk of audio data

                @return bytes
                """
                return self.chunk

        def delete(self):
                """
                delete mic data to a WAV file.
                @param list data
                """
                count = 0
                Util.log(self.name, "Delete audio...")
                for filename in sorted(os.listdir(self.archive), reverse=True):
                        if not filename.startswith('.'):
                                type = self.get_type(filename)
                                if type == "audio":
                                        count = count + 1
                                        if self.REMAIN_RECORDING_FILES < count:
                                                Util.log(self.name, "Delete audio filename=" + filename + ", type=" + type + ", count=" + str(count))
                                                os.remove(self.archive + "/" + filename)
                                
        def get_type(self, filename):
                name, extension = os.path.splitext(filename)
                return 'video' if extension == '.mp4' else 'video' if extension == '.avi' else 'audio' if extension == '.wav' else 'audio' if extension == '.mp3' else 'photo'

        def save(self, data):
                """
                Save mic data to a WAV file.

                @param list data
                """
                Util.log(self.name, "Saving audio...")

                # Flatten the list
                data = b''.join(data)

                # Write converted data to file
                with open(self.current_file, "wb+") as file:
                        file.write(self.generate_wav(data))

                # Convert 음질 개떡 
                #self.convert_to_mp3(self.current_file)

        def bytes_to_array(self, bytes, type):
                """
                Convert raw audio data to TypedArray

                @param bytes bytes
                @return numpy-Array
                """
                return np.frombuffer(bytes, dtype=type)

        def generate_wav(self, raw):
                """
                Create WAVE-file from raw audio chunks

                @param bytes raw
                @return bytes
                """
                # Check if input format is supported
                if self.FORMAT not in (pyaudio.paFloat32, pyaudio.paInt16):
                        print("Unsupported format")
                        return

                # Convert raw audio bytes to typed array
                samples = self.bytes_to_array(raw, np.float32)

                # Get sample size
                sample_size = pyaudio.get_sample_size(self.FORMAT)

                # Get data-length
                byte_count = (len(samples)) * sample_size

                # Get bits/sample
                bits_per_sample = sample_size * 8

                # Calculate frame-size
                frame_size = int(self.CHANNELS * ((bits_per_sample + 7) / 8))

                # Container for WAVE-content
                wav = bytearray()

                # Start RIFF-Header
                wav.extend(struct.pack('<cccc', b'R', b'I', b'F', b'F'))
                # Add chunk size (data-size minus 8)
                wav.extend(struct.pack('<I', byte_count + 0x2c - 8))
                # Add RIFF-type ("WAVE")
                wav.extend(struct.pack('<cccc', b'W', b'A', b'V', b'E'))

                # Start "Format"-part
                wav.extend(struct.pack('<cccc', b'f', b'm', b't', b' '))
                # Add header length (16 bytes)
                wav.extend(struct.pack('<I', 0x10))
                # Add format-tag (e.g. 1 = PCM, 3 = FLOAT)
                wav.extend(struct.pack('<H', 3))
                # Add channel count
                wav.extend(struct.pack('<H', self.CHANNELS))
                # Add sample rate
                wav.extend(struct.pack('<I', self.RATE))
                # Add bytes/second
                wav.extend(struct.pack('<I', self.RATE * frame_size))
                # Add frame size
                wav.extend(struct.pack('<H', frame_size))
                # Add bits/sample
                wav.extend(struct.pack('<H', bits_per_sample))

                # Start data-part
                wav.extend(struct.pack('<cccc', b'd', b'a', b't', b'a'))
                # Add data-length
                wav.extend(struct.pack('<I', byte_count))

                # Add data
                for sample in samples:
                        wav.extend(struct.pack("<f", sample))

                return bytes(wav)

        def convert_to_mp3(self, path):
                """
                Convert wav-file to mp3

                @param string path
                """
                Util.log(self.name, "Converting audio...")

                try:
                        cmd = 'lame --preset insane "{}" 2> /dev/null && rm "{}"'.format(path, path)
                        p = subprocess.Popen(cmd, shell=True)
                        (output, err) = p.communicate()

                except subprocess.CalledProcessError:
                        Util.log(self.name, "Error converting audio")

        def detected(self, has_noise):
                """
                Check if this or another detector detected something

                @param boolean has_noise
                @return boolean
                """
                if has_noise:
                        self.lock_manager.set()
                else:
                        self.lock_manager.remove()

                self.detected_at = self.lock_manager.get_lock_time()

                return self.detected_at is not None

        def recording(self):
                """
                Check if currently recording

                @return boolean
                """
                return len(self.record) > 0

        def notify(self):
                """
                Notify
                """
                Util.log(self.name, "Notifying")
                self.notified = True

if __name__ == "__main__":
        nd = Noise_Detector()
        nd.start()

Listen Speech

 

listenSpeech.py

from google_trans_new import google_translator  
from google_speech import Speech
from time import sleep

translator = google_translator()

class ListenSpeech(object):
    def speech(self,message):
        ko_result = translator.translate(message, lang_tgt='ko')
        print(' -> ', ko_result)
        speech = Speech(ko_result, 'ko')
        speech.play()
        en_result = translator.translate(message, lang_tgt='en')
        speech = Speech(en_result, 'en')
        speech.play()
        it_result = translator.translate(message, lang_tgt='it')
        speech = Speech(it_result, 'it')
        speech.play()
        ja_result = translator.translate(message, lang_tgt='ja')
        speech = Speech(ja_result, 'ja')
        speech.play()
        returnString = ko_result + " , EN=" + en_result + " , IT=" + it_result + ", JA=" + ja_result
        print("Return message = " + returnString)
        return returnString
        

GPIO

gpioControl.py

import RPi.GPIO as GPIO
from time import sleep

ina1 = 33
ina2 = 35
ena = 37

inb1 = 31
inb2 = 29
enb = 23

GPIO.setmode(GPIO.BOARD)

GPIO.setup(12, GPIO.OUT, initial=1)
GPIO.setup(18, GPIO.OUT, initial=1)

GPIO.output(12, GPIO.LOW)
GPIO.output(18, GPIO.LOW)
GPIO.setup(ina1,GPIO.OUT)
GPIO.setup(ina2,GPIO.OUT)
GPIO.setup(ena,GPIO.OUT)
GPIO.setup(inb1,GPIO.OUT)
GPIO.setup(inb2,GPIO.OUT)
GPIO.setup(enb,GPIO.OUT)

p1 = GPIO.PWM(18, 50)  # 50 Hz
p2 = GPIO.PWM(12, 50)  # 50
pa = GPIO.PWM(ena,1000)
pb = GPIO.PWM(enb,1000)


cameraInitPositionY = 6.0
cameraInitPositionX = 6.5

verticalVal = cameraInitPositionY
horizontalVal = cameraInitPositionX


class GpioControl(object):

    def __init__(self):
        global verticalVal
        global horizontalVal
        global p1
        global p2
        p1.start(0)
        p2.start(0)
        pa.start(25)
        pb.start(25)
        p1.ChangeDutyCycle(cameraInitPositionY)
        p2.ChangeDutyCycle(cameraInitPositionX)
        sleep(0.1)
        p1.ChangeDutyCycle(0)
        p2.ChangeDutyCycle(0)
        verticalVal = cameraInitPositionY
        horizontalVal = cameraInitPositionX
        #print("> Init Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal))

    def __del__(self):
        global p1
        global p2
        p1.stop()
        p2.stop()
        print(" GPIO.__del__() ")
        GPIO.cleanup()
        
    def cleanUp(self):
        global p1
        global p2
        p1.stop()
        p2.stop()
        print(" GPIO.cleanUp() ")
        GPIO.cleanup()
        sleep(2)
    
    def initMotorPosition(self):
        # Init
        global verticalVal
        global horizontalVal
        global cameraInitPositionY
        global cameraInitPositionX
        global p1
        global p2
        p1.ChangeDutyCycle(float(cameraInitPositionY))
        p2.ChangeDutyCycle(float(cameraInitPositionX))
        sleep(0.1)
        p1.ChangeDutyCycle(float(0.0))
        p2.ChangeDutyCycle(float(0.0))
        verticalVal = cameraInitPositionY
        horizontalVal = cameraInitPositionX
        #print("> Init Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal))
        return "Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal)

    def moveUp(self):
        global verticalVal
        global horizontalVal
        global p2
        if(verticalVal>3.5): 
            verticalVal = float(round(verticalVal-0.2, 1))
            p2.ChangeDutyCycle(verticalVal)
            #print("> UP Vert=%.2f ,Hort=%.2f" % (verticalVal, horizontalVal))
            sleep(0.1)
            p2.ChangeDutyCycle(0)
        return "UP Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal)
        
    def moveDown(self):
        global verticalVal
        global horizontalVal
        global p2
        if(verticalVal<8.1):
            verticalVal = float(round(verticalVal+0.2, 1))
            p2.ChangeDutyCycle(verticalVal)
            #print("> Down Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal))
            sleep(0.1)
            p2.ChangeDutyCycle(0)
        return "DOWN Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal)
        
    def moveRight(self):
        global verticalVal
        global horizontalVal
        global p1
        if(horizontalVal>2.5):
            horizontalVal = float(round(horizontalVal-0.2, 1))
            p1.ChangeDutyCycle(horizontalVal)
            #print("> Right Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal))
            sleep(0.1)
            p1.ChangeDutyCycle(0)
        return "RIGHT Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal)
        
    def moveLeft(self):
        global verticalVal
        global horizontalVal
        global p1
        if(horizontalVal<10):
            horizontalVal = float(round(horizontalVal+0.2, 1))
            p1.ChangeDutyCycle(horizontalVal)
            #print("> Left Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal))
            sleep(0.1)
            p1.ChangeDutyCycle(0)
        return "LEFT Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal)

        
    def goForward(self,time):
        print("Go forward")
        pa.ChangeDutyCycle(75)
        GPIO.output(ina1,GPIO.HIGH)
        GPIO.output(ina2,GPIO.LOW)
        pb.ChangeDutyCycle(75)
        GPIO.output(inb1,GPIO.HIGH)
        GPIO.output(inb2,GPIO.LOW)
        sleep(0.1*int(time))
        GPIO.output(ina1,GPIO.LOW)
        GPIO.output(ina2,GPIO.LOW)
        GPIO.output(inb1,GPIO.LOW)
        GPIO.output(inb2,GPIO.LOW)
        return " >> Go Forward"

    def goBackward(self,time):
        print("Go backward")
        pa.ChangeDutyCycle(75)
        GPIO.output(ina1,GPIO.LOW)
        GPIO.output(ina2,GPIO.HIGH)
        pb.ChangeDutyCycle(75)
        GPIO.output(inb1,GPIO.LOW)
        GPIO.output(inb2,GPIO.HIGH)
        sleep(0.1*int(time))
        GPIO.output(ina1,GPIO.LOW)
        GPIO.output(ina2,GPIO.LOW)
        GPIO.output(inb1,GPIO.LOW)
        GPIO.output(inb2,GPIO.LOW)
        return " >> Go Backward"

    def goTurnleftback(self,time):
        print("Go Turn Left back")
        pa.ChangeDutyCycle(75)
        GPIO.output(inb1,GPIO.LOW)
        GPIO.output(inb2,GPIO.HIGH)
        sleep(0.1*int(time))
        GPIO.output(ina1,GPIO.LOW)
        GPIO.output(ina2,GPIO.LOW)
        GPIO.output(inb1,GPIO.LOW)
        GPIO.output(inb2,GPIO.LOW)
        return " >> Go Turn Left back"

    def goTurnrightback(self,time):
        print("Go Turn Right back")
        pb.ChangeDutyCycle(75)
        GPIO.output(ina1,GPIO.LOW)
        GPIO.output(ina2,GPIO.HIGH)
        sleep(0.1*int(time))
        GPIO.output(ina1,GPIO.LOW)
        GPIO.output(ina2,GPIO.LOW)
        GPIO.output(inb1,GPIO.LOW)
        GPIO.output(inb2,GPIO.LOW)
        return " >> Go Turn Right back"

    def goTurnleftforward(self,time):
        print("Go Turn Left forward")
        pa.ChangeDutyCycle(75)
        GPIO.output(inb1,GPIO.HIGH)
        GPIO.output(inb2,GPIO.LOW)
        sleep(0.1*int(time))
        GPIO.output(ina1,GPIO.LOW)
        GPIO.output(ina2,GPIO.LOW)
        GPIO.output(inb1,GPIO.LOW)
        GPIO.output(inb2,GPIO.LOW)
        return " >> Go Turn Left forward"

    def goTurnrightforward(self,time):
        print("Go Turn Right forward")
        pb.ChangeDutyCycle(75)
        GPIO.output(ina1,GPIO.HIGH)
        GPIO.output(ina2,GPIO.LOW)
        sleep(0.1*int(time))
        GPIO.output(ina1,GPIO.LOW)
        GPIO.output(ina2,GPIO.LOW)
        GPIO.output(inb1,GPIO.LOW)
        GPIO.output(inb2,GPIO.LOW)
        return " >> Go Turn Right forward"


        

Etc

util.py

from datetime import datetime

class Util:
        def log(source, msg):
                print(datetime.now().strftime("%Y%m%d_%H%M%S") + " | " + source + " | " + str(msg))

lock_manager.py

import os
import datetime

class Lock_Manager:
        def __init__(self, name):
                self.locks = os.path.dirname(os.path.realpath(__file__)) + "/locks"
                self.name = name + ".lock"
                self.path = os.path.join(self.locks, self.name)

                if not os.path.exists(self.locks):
                        os.makedirs(self.locks)

        def set(self):
                if not os.path.exists(self.path):
                        print("Setting {} lock".format(self.name))
                        timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")

                        with open(self.path, 'w+') as f:
                                f.write(timestamp)

        def remove(self):
                if os.path.isfile(self.path):
                        os.remove(self.path)

        def get_lock_time(self):
                for filename in os.listdir(self.locks):
                        with open(self.locks + "/" + filename) as f:
                                return f.read()

                return None

conf.py

from pathlib import Path

p = Path("logs")
if not p.exists():
    p.mkdir()

dictConfig = {
    'version': 1,
    'disable_existing_loggers': True,
    'formatters': {
        'standard': {
            'format': '%(asctime)s [%(levelname)s] %(name)s:: %(message)s',
        },
    },
    'handlers': {
        'default': {
            'level': 'DEBUG',
            'formatter': 'standard',
            'class': 'logging.StreamHandler',
            'stream': 'ext://sys.stdout',
        },
        'file': {
            'class': 'logging.handlers.RotatingFileHandler',
            'level': 'DEBUG',
            'formatter': 'standard',
            'filename': 'logs/logfile.log',
            'mode': 'a',
            'maxBytes': 5_242_880,
            'backupCount': 3,
            'encoding': 'utf-8',
        },
    },
    'loggers': {
        '__main__': {
            'handlers': ['default','file'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'camera': {
            'handlers': ['default', 'file'],
            'level': 'DEBUG',
            'propagate': False,
        },
    }
}

power.py

from vcgencmd import Vcgencmd

vcgm = Vcgencmd()

class PowerStatus(object):
    def __init__(self):
        print("> vcgm.version()=" + vcgm.version())
        
    def getPowerStatus(self):
        output=vcgm.get_throttled()
        print("raw_data=" + output['raw_data'])
        print("binary=" + output['binary'])
        return "raw_data=" + output['raw_data'] + ", binary=" + output['binary']
    

StreamingVideo

작성 중 

StreamingVideo

import io
import picamera
import logging
import socketserver
from threading import Condition
from http import server
import os
from gpioControl import GpioControl
from listenSpeech import ListenSpeech
from urllib.parse import parse_qs


ONAIR = True
gpio = GpioControl()
listenspeech = ListenSpeech()

# Load HTML file
file = open("view.html", "r")
PAGE=file.read()
file.close()

class StreamingOutput(object):
    def __init__(self):
        self.frame = None
        self.buffer = io.BytesIO()
        self.condition = Condition()

    def write(self, buf):
        if buf.startswith(b'\xff\xd8'):
            # New frame, copy the existing buffer's content and notify all
            # clients it's available
            self.buffer.truncate()
            with self.condition:
                self.frame = self.buffer.getvalue()
                self.condition.notify_all()
            self.buffer.seek(0)
        return self.buffer.write(buf)

class StreamingHandler(server.BaseHTTPRequestHandler):
    def do_POST(self):
        if self.path == '/msg':
            self.data_string = self.rfile.read(int(self.headers['Content-Length']))
            getMessage=self.data_string.decode()
            reString = listenspeech.speech(getMessage);
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(reString.encode()))
            self.end_headers()
            print("Return message = " + reString)
            self.wfile.write(reString.encode())
        elif self.path == '/forward':
            self.data_int = self.rfile.read(int(self.headers['Content-Length']))
            moveOrder=self.data_int
            self.send_response(200)
            if not moveOrder :
                reString = "Do not move"
            else :
                reString = gpio.goForward(moveOrder)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(reString.encode()))
            self.end_headers()
            self.wfile.write(reString.encode())
            print("Go Forward ...")
        elif self.path == '/backward':
            self.data_int = self.rfile.read(int(self.headers['Content-Length']))
            moveOrder=self.data_int
            self.send_response(200)
            if not moveOrder :
                reString = "Do not move"
            else :
                reString = gpio.goBackward(moveOrder)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(reString.encode()))
            self.end_headers()
            self.wfile.write(reString.encode())
            print("Go Backward ...")
        elif self.path == '/turnleftback':
            self.data_int = self.rfile.read(int(self.headers['Content-Length']))
            moveOrder=self.data_int
            self.send_response(200)
            if not moveOrder :
                reString = "Do not move"
            else :
                reString = gpio.goTurnleftback(moveOrder)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(reString.encode()))
            self.end_headers()
            self.wfile.write(reString.encode())
            print("Go Turn Left back...")
        elif self.path == '/turnrightback':
            self.data_int = self.rfile.read(int(self.headers['Content-Length']))
            moveOrder=self.data_int
            self.send_response(200)
            if not moveOrder :
                reString = "Do not move"
            else :
                reString = gpio.goTurnrightback(moveOrder)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(reString.encode()))
            self.end_headers()
            self.wfile.write(reString.encode())
            print("Go Turn Right back...")
        elif self.path == '/turnleftforward':
            self.data_int = self.rfile.read(int(self.headers['Content-Length']))
            moveOrder=self.data_int
            self.send_response(200)
            if not moveOrder :
                reString = "Do not move"
            else :
                reString = gpio.goTurnleftforward(moveOrder)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(reString.encode()))
            self.end_headers()
            self.wfile.write(reString.encode())
            print("Go Turn Left forward...")
        elif self.path == '/turnrightforward':
            self.data_int = self.rfile.read(int(self.headers['Content-Length']))
            moveOrder=self.data_int
            self.send_response(200)
            if not moveOrder :
                reString = "Do not move"
            else :
                reString = gpio.goTurnrightforward(moveOrder)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(reString.encode()))
            self.end_headers()
            self.wfile.write(reString.encode())
            print("Go Turn Right forward...")


    def do_GET(self):
        global ONAIR
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/stream.mjpg':
            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
            self.end_headers()
            try:
                while ONAIR:
                    with output.condition:
                        output.condition.wait()
                        frame = output.frame
                    self.wfile.write(b'--FRAME\r\n')
                    self.send_header('Content-Type', 'image/jpeg')
                    self.send_header('Content-Length', len(frame))
                    self.end_headers()
                    self.wfile.write(frame)
                    self.wfile.write(b'\r\n')
            except Exception as e:
                logging.warning(
                    'Removed streaming client %s: %s',
                    self.client_address, str(e))

        elif self.path == '/init':
            self.send_response(200)
            reString = "Camera position init : " + gpio.initMotorPosition()
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(reString.encode()))
            self.end_headers()
            self.wfile.write(reString.encode())
            print("Init Cam ...")

        elif self.path == '/up':
            self.send_response(200)
            reString = gpio.moveUp()
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(reString.encode()))
            self.end_headers()
            self.wfile.write(reString.encode())
            print("Move Up ...")

        elif self.path == '/down':
            self.send_response(200)
            reString = gpio.moveDown()
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(reString.encode()))
            self.end_headers()
            self.wfile.write(reString.encode())
            print("Move Down ...")

        elif self.path == '/left':
            self.send_response(200)
            reString = gpio.moveLeft()
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(reString.encode()))
            self.end_headers()
            self.wfile.write(reString.encode())
            print("Move Left ...")

        elif self.path == '/right':
            self.send_response(200)
            reString = gpio.moveRight()
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(reString.encode()))
            self.end_headers()
            self.wfile.write(reString.encode())
            print("Move Right ...")

        elif self.path == '/temperature':
            content = os.popen("vcgencmd measure_temp").readline()
            content = content.replace("temp=", "")
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content.encode()))
            self.end_headers()
            self.wfile.write(content.encode())

        else:
            self.send_error(404)
            self.end_headers()

class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
    allow_reuse_address = True
    daemon_threads = True

with picamera.PiCamera(resolution='640x480', framerate=24) as camera:
    output = StreamingOutput()
    #Uncomment the next line to change your Pi's Camera rotation (in degrees)
    camera.rotation = 180 
    camera.start_recording(output, format='mjpeg')
    try:
        address = ('', 8081)
        server = StreamingServer(address, StreamingHandler)
        server.serve_forever()
    finally:
        camera.stop_recording()

gpioControl.py

import RPi.GPIO as GPIO
from time import sleep


GPIO.setmode(GPIO.BOARD)

ina1 = 33
ina2 = 35
ena = 37

inb1 = 31
inb2 = 29
enb = 23

GPIO.setup(12, GPIO.OUT, initial=1)
GPIO.setup(18, GPIO.OUT, initial=1)
GPIO.setup(11, GPIO.OUT, initial=1) # light

GPIO.setup(ina1,GPIO.OUT)
GPIO.setup(ina2,GPIO.OUT)
GPIO.setup(ena,GPIO.OUT)

GPIO.setup(inb1,GPIO.OUT)
GPIO.setup(inb2,GPIO.OUT)
GPIO.setup(enb,GPIO.OUT)

p1 = GPIO.PWM(18, 50)  # 50 Hz
p2 = GPIO.PWM(12, 50)  # 50
p1.start(0)
p2.start(0)
p1.ChangeDutyCycle(0)
p2.ChangeDutyCycle(0)

pa=GPIO.PWM(ena,1000)
pa.start(25)

pb=GPIO.PWM(enb,1000)
pb.start(25)

verticalVal = 6.5
horizontalVal = 6

cameraPositionX = 6.5
cameraPositionY = 6

# Set up camera constants
IM_WIDTH = 640
IM_HEIGHT = 480


class GpioControl(object):

    def __init__(self):
        global verticalVal
        global horizontalVal
        global p1
        global p2
        p1.ChangeDutyCycle(6.5)
        p2.ChangeDutyCycle(6)
        sleep(0.1)
        p1.ChangeDutyCycle(0)
        p2.ChangeDutyCycle(0)
        verticalVal = 6.5
        horizontalVal = 6
        print("> Init Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal))
   
    def click(self):
        GPIO.output(11, GPIO.LOW)
        sleep(0.5)
        GPIO.output(11, GPIO.HIGH)
        sleep(1)

    def __del__(self):
        global p1
        global p2
        p1.stop()
        p2.stop()
        print(" GPIO.__del__() ")
        GPIO.cleanup()
        
    def cleanUp(self):
        global p1
        global p2
        p1.stop()
        p2.stop()
        print(" GPIO.cleanUp() ")
        GPIO.cleanup()
        sleep(2)
    
    def initMotorPosition(self):
        # Init
        global verticalVal
        global horizontalVal
        global p1
        global p2
        p1.ChangeDutyCycle(6.5)
        p2.ChangeDutyCycle(6)
        sleep(0.1)
        p1.ChangeDutyCycle(0)
        p2.ChangeDutyCycle(0)
        verticalVal = 6.5
        horizontalVal = 6
        print("> Init Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal))
        return "Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal)

    def moveUp(self):
        global verticalVal
        global horizontalVal
        global p2
        verticalVal = round(verticalVal-0.2, 1)
        p2.ChangeDutyCycle(verticalVal)
        print("> UP Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal))
        sleep(0.1)
        p2.ChangeDutyCycle(0)
        return "Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal)
        
    def moveDown(self):
        global verticalVal
        global horizontalVal
        global p2
        verticalVal = round(verticalVal+0.2, 1)
        p2.ChangeDutyCycle(verticalVal)
        print("> Down Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal))
        sleep(0.1)
        p2.ChangeDutyCycle(0)
        return "Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal)
        
    def moveRight(self):
        global verticalVal
        global horizontalVal
        global p1
        horizontalVal = round(horizontalVal-0.2, 1)
        p1.ChangeDutyCycle(horizontalVal)
        print("> Right Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal))
        sleep(0.1)
        p1.ChangeDutyCycle(0)
        return "Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal)
        
    def moveLeft(self):
        global verticalVal
        global horizontalVal
        global p1
        horizontalVal = round(horizontalVal+0.2, 1)
        p1.ChangeDutyCycle(horizontalVal)
        print("> Left Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal))
        sleep(0.1)
        p1.ChangeDutyCycle(0)
        return "Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal)

        
    def goForward(self,time):
        print("Go forward")
        pa.ChangeDutyCycle(75)
        GPIO.output(ina1,GPIO.HIGH)
        GPIO.output(ina2,GPIO.LOW)
        pb.ChangeDutyCycle(75)
        GPIO.output(inb1,GPIO.HIGH)
        GPIO.output(inb2,GPIO.LOW)
        sleep(0.1*int(time))
        GPIO.output(ina1,GPIO.LOW)
        GPIO.output(ina2,GPIO.LOW)
        GPIO.output(inb1,GPIO.LOW)
        GPIO.output(inb2,GPIO.LOW)
        return " >> Go Forward"

    def goBackward(self,time):
        print("Go backward")
        pa.ChangeDutyCycle(75)
        GPIO.output(ina1,GPIO.LOW)
        GPIO.output(ina2,GPIO.HIGH)
        pb.ChangeDutyCycle(75)
        GPIO.output(inb1,GPIO.LOW)
        GPIO.output(inb2,GPIO.HIGH)
        sleep(0.1*int(time))
        GPIO.output(ina1,GPIO.LOW)
        GPIO.output(ina2,GPIO.LOW)
        GPIO.output(inb1,GPIO.LOW)
        GPIO.output(inb2,GPIO.LOW)
        return " >> Go Backward"

    def goTurnleftback(self,time):
        print("Go Turn Left back")
        pa.ChangeDutyCycle(75)
        GPIO.output(inb1,GPIO.LOW)
        GPIO.output(inb2,GPIO.HIGH)
        sleep(0.1*int(time))
        GPIO.output(ina1,GPIO.LOW)
        GPIO.output(ina2,GPIO.LOW)
        GPIO.output(inb1,GPIO.LOW)
        GPIO.output(inb2,GPIO.LOW)
        return " >> Go Turn Left back"

    def goTurnrightback(self,time):
        print("Go Turn Right back")
        pb.ChangeDutyCycle(75)
        GPIO.output(ina1,GPIO.LOW)
        GPIO.output(ina2,GPIO.HIGH)
        sleep(0.1*int(time))
        GPIO.output(ina1,GPIO.LOW)
        GPIO.output(ina2,GPIO.LOW)
        GPIO.output(inb1,GPIO.LOW)
        GPIO.output(inb2,GPIO.LOW)
        return " >> Go Turn Right back"

    def goTurnleftforward(self,time):
        print("Go Turn Left forward")
        pa.ChangeDutyCycle(75)
        GPIO.output(inb1,GPIO.HIGH)
        GPIO.output(inb2,GPIO.LOW)
        sleep(0.1*int(time))
        GPIO.output(ina1,GPIO.LOW)
        GPIO.output(ina2,GPIO.LOW)
        GPIO.output(inb1,GPIO.LOW)
        GPIO.output(inb2,GPIO.LOW)
        return " >> Go Turn Left forward"

    def goTurnrightforward(self,time):
        print("Go Turn Right forward")
        pb.ChangeDutyCycle(75)
        GPIO.output(ina1,GPIO.HIGH)
        GPIO.output(ina2,GPIO.LOW)
        sleep(0.1*int(time))
        GPIO.output(ina1,GPIO.LOW)
        GPIO.output(ina2,GPIO.LOW)
        GPIO.output(inb1,GPIO.LOW)
        GPIO.output(inb2,GPIO.LOW)
        return " >> Go Turn Right forward"




    def move_to_position(self,ObjX, ObjY):
        global cameraPositionX
        global cameraPositionY
        global p1
        global p2
        print(" >> Move to location x="+str(ObjX)+", y="+str(ObjY))
        moveLoop = True
        movX = int(IM_WIDTH/2)-ObjX
        movY = int(IM_HEIGHT/2)-ObjY
        print(" >> Center location movX="+str(movX)+", movY="+str(movY))
        
        xx = 1
        xy = 0
        yx = 1
        yy = 0
        while(moveLoop):
            if( xy < abs(movX) ):
                p1.ChangeDutyCycle(cameraPositionX)
                sleep(0.1)
                p1.ChangeDutyCycle(0)
                print("xx=" + str(xx) + ", xy="+ str(xy) +" cameraPositionX=" +str(round(cameraPositionX,1)))
                xy = xx*xx * 12
                xx = xx + 1
                if(movX > 0): cameraPositionX = cameraPositionX - 0.2
                else: cameraPositionX = cameraPositionX + 0.2
            if( yy < abs(movY) ):
                p2.ChangeDutyCycle(cameraPositionY)
                sleep(0.1)
                p2.ChangeDutyCycle(0)
                print("yx=" + str(yx) + ", yy="+ str(yy) +" cameraPositionY=" +str(round(cameraPositionY,1)))
                yy = yx*yx * 12
                yx = yx + 1
                if(movY > 0): cameraPositionY = cameraPositionY + 0.2
                else: cameraPositionY = cameraPositionY - 0.2
            elif( xy >= movX and yy >= movY):
                print(" >> Center location movX="+str(movX)+", movY=" + str(movY))
                print(" >> Position location xy="+str(xy)
                      +", yy="+str(yy)
                      +" cameraPositionX="+str(round(cameraPositionX,1))+
                       " cameraPositionY="+str(round(cameraPositionY,1))+" .. ")
                moveLoop = False

ListenSpeech

from googletrans import Translator
from google_speech import Speech
from time import sleep

translator = Translator()

class ListenSpeech(object):
    def speech(self,message):
        ko_result = translator.translate(message, dest='ko')
        print(' -> ', ko_result.text)
        speech = Speech(ko_result.text, 'ko')
        speech.play()
        en_result = translator.translate(message, dest='en')
        speech = Speech(en_result.text, 'en')
        speech.play()
        it_result = translator.translate(message, dest='it')
        speech = Speech(it_result.text, 'it')
        speech.play()
        ja_result = translator.translate(message, dest='ja')
        speech = Speech(ja_result.text, 'ja')
        speech.play()
        returnString = ko_result.text + " , EN=" + en_result.text + " , IT=" + it_result.text + ", JA=" + ja_result.text
        print("Return message = " + returnString)
        return returnString
        

view.html

<html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta charset="UTF-8" />
<head>
<title>Raspberry Pi - HYUNSU Camera</title>

<script type="text/javascript">

window.onload = function() {
    document.getElementById("btnInit").onclick = getInitFunc;
    document.getElementById("btnMsg").onclick = getMsgFunc;

    document.getElementById("btnLeft").onclick = getLeftFunc;
    document.getElementById("btnRight").onclick = getRightFunc;
    document.getElementById("btnUp").onclick = getUpFunc;
    document.getElementById("btnDown").onclick = getDownFunc;
    
    document.getElementById("btnForward").onclick = getForwardFunc;
    document.getElementById("btnBackward").onclick = getBackwardFunc;
    document.getElementById("btnTurnrightback").onclick = getTurnrightbackFunc;
    document.getElementById("btnTurnleftback").onclick = getTurnleftbackFunc;
    document.getElementById("btnTurnrightforward").onclick = getTurnrightforwardFunc;
    document.getElementById("btnTurnleftforward").onclick = getTurnleftforwardFunc;
}

var xhr;

function getInitFunc() {
    var fName = "/init"; 
    xhr = new XMLHttpRequest();
    xhr.open("get", fName, true);
    xhr.onreadystatechange = function() { 
        if (xhr.readyState == 4) {
            if (xhr.status == 200) { 
                document.getElementById("systemMessage").innerHTML = xhr.responseText;
            } else {
                alert("ERROR : " + xhr.status);
            }
        }
    }
    xhr.send(null); 
}

function getMsgFunc() {
    var fName = "/msg";
    // var data = new FormData();
    data=document.getElementById("textInput").value;
    xhr = new XMLHttpRequest();
    xhr.open("post", fName, true);
    xhr.onreadystatechange = function() { 
        if (xhr.readyState == 4) {
            if (xhr.status == 200) {
                document.getElementById("systemMessage").innerHTML = xhr.responseText;
            } else {
                alert("ERROR : " + xhr.status);
            }
        }
    }
    xhr.send(data); 
}


function getLeftFunc() {
    var fName = "/left"; 
    xhr = new XMLHttpRequest();
    xhr.open("get", fName, true);
    xhr.onreadystatechange = function() { 
        if (xhr.readyState == 4) {
            if (xhr.status == 200) { 
                document.getElementById("systemMessage").innerHTML = xhr.responseText;
            } else {
                alert("ERROR : " + xhr.status);
            }
        }
    }
    xhr.send(null); 
}

function getRightFunc() {
    var fName = "/right"; 
    xhr = new XMLHttpRequest();
    xhr.open("get", fName, true);
    xhr.onreadystatechange = function() { 
        if (xhr.readyState == 4) {
            if (xhr.status == 200) { 
                document.getElementById("systemMessage").innerHTML = xhr.responseText;
            } else {
                alert("ERROR : " + xhr.status);
            }
        }
    }
    xhr.send(null); 
}

function getUpFunc() {
    var fName = "/up"; 
    xhr = new XMLHttpRequest();
    xhr.open("get", fName, true);
    xhr.onreadystatechange = function() { 
        if (xhr.readyState == 4) {
            if (xhr.status == 200) { 
                document.getElementById("systemMessage").innerHTML = xhr.responseText;
            } else {
                alert("ERROR : " + xhr.status);
            }
        }
    }
    xhr.send(null); 
}

function getDownFunc() {
    var fName = "/down"; 
    xhr = new XMLHttpRequest();
    xhr.open("get", fName, true);
    xhr.onreadystatechange = function() { 
        if (xhr.readyState == 4) {
            if (xhr.status == 200) { 
                document.getElementById("systemMessage").innerHTML = xhr.responseText;
            } else {
                alert("ERROR : " + xhr.status);
            }
        }
    }
    xhr.send(null); 
}



function getForwardFunc() {
    var fName = "/forward"; 
    data=document.getElementById("moveCnt").value;
    xhr = new XMLHttpRequest();
    xhr.open("post", fName, true);
    xhr.onreadystatechange = function() { 
        if (xhr.readyState == 4) {
            if (xhr.status == 200) { 
                document.getElementById("systemMessage").innerHTML = xhr.responseText;
            } else {
                alert("ERROR : " + xhr.status);
            }
        }
    }
    xhr.send(data); 
}


function getBackwardFunc() {
    var fName = "/backward"; 
    data=document.getElementById("moveCnt").value;
    xhr = new XMLHttpRequest();
    xhr.open("post", fName, true);
    xhr.onreadystatechange = function() { 
        if (xhr.readyState == 4) {
            if (xhr.status == 200) { 
                document.getElementById("systemMessage").innerHTML = xhr.responseText;
            } else {
                alert("ERROR : " + xhr.status);
            }
        }
    }
    xhr.send(data); 
}


function getTurnleftbackFunc() {
    var fName = "/turnleftback"; 
    data=document.getElementById("moveCnt").value;
    xhr = new XMLHttpRequest();
    xhr.open("post", fName, true);
    xhr.onreadystatechange = function() { 
        if (xhr.readyState == 4) {
            if (xhr.status == 200) { 
                document.getElementById("systemMessage").innerHTML = xhr.responseText;
            } else {
                alert("ERROR : " + xhr.status);
            }
        }
    }
    xhr.send(data); 
}


function getTurnrightbackFunc() {
    var fName = "/turnrightback"; 
    data=document.getElementById("moveCnt").value;
    xhr = new XMLHttpRequest();
    xhr.open("post", fName, true);
    xhr.onreadystatechange = function() { 
        if (xhr.readyState == 4) {
            if (xhr.status == 200) { 
                document.getElementById("systemMessage").innerHTML = xhr.responseText;
            } else {
                alert("ERROR : " + xhr.status);
            }
        }
    }
    xhr.send(data); 
}


function getTurnleftforwardFunc() {
    var fName = "/turnleftforward"; 
    data=document.getElementById("moveCnt").value;
    xhr = new XMLHttpRequest();
    xhr.open("post", fName, true);
    xhr.onreadystatechange = function() { 
        if (xhr.readyState == 4) {
            if (xhr.status == 200) { 
                document.getElementById("systemMessage").innerHTML = xhr.responseText;
            } else {
                alert("ERROR : " + xhr.status);
            }
        }
    }
    xhr.send(data); 
}


function getTurnrightforwardFunc() {
    var fName = "/turnrightforward"; 
    data=document.getElementById("moveCnt").value;
    xhr = new XMLHttpRequest();
    xhr.open("post", fName, true);
    xhr.onreadystatechange = function() { 
        if (xhr.readyState == 4) {
            if (xhr.status == 200) { 
                document.getElementById("systemMessage").innerHTML = xhr.responseText;
            } else {
                alert("ERROR : " + xhr.status);
            }
        }
    }
    xhr.send(data); 
}



function getTemperatureFunc() {
    var fName = "/temperature"; 
    xhr = new XMLHttpRequest();
    xhr.open("get", fName, true);
    xhr.onreadystatechange = function() { 
        if (xhr.readyState == 4) {
            if (xhr.status == 200) { 
                document.getElementById("temperature").innerHTML = xhr.responseText;
            } else {
                alert(" temperature ERROR : " + xhr.status);
            }
        }
    }
    xhr.send(null); 
}

var timerId = null;
timerId = setInterval(getTemperatureFunc, 30000);
//clearInterval(timerId);

</script>

</head>
<body>
<form name="frm">
<center>
<h3>꼬꼬락 KKoLack</h3>
<h4>system temperature = <span id="temperature">...</span></h4>

<table border=0>
<tr>
    <!-- Image section -->
    <td> 
        <img src="stream.mjpg" width="300">    
    </td>
    <!-- Control section -->
    <td>
        <table border=0>
            <tr>
                <td>
                Message = <span id="systemMessage"> ... </span> 
                <br>
                <input type=text id="textInput" lenght=20 ><input type="button" value="Send Message" id="btnMsg" />
                </td>
            </tr>
            <tr>
                <td>
                    <center>
                    Control Camera Section
                    
                    <table>
                    <tr>
                        <td></td>
                        <td><input type="button" value=" ^ " id="btnUp" /></td>
                        <td></td>
                    </tr>
                    <tr>
                        <td><input type="button" value=" < " id="btnLeft" /></td>
                        <td></td>
                        <td><input type="button" value=" > " id="btnRight" /></td>
                    </tr>
                    <tr>
                        <td></td>
                        <td><input type="button" value=" v " id="btnDown" /></td>
                        <td></td>
                    </tr>
                    </table>
                    </center>
                </td>
            </tr>
            <tr>
                <td>
                    <center>
                    Control Engine Section
                    <br>Move cont (0.1 ~ 10) = <input type=text id="moveCnt" maxlength="5" size="5" />
                    <br>
                    <table>
                    <tr>
                        <td></td>
                        <td><input type="button" value=" ^ " id="btnForward" /></td>
                        <td></td>
                    </tr>
                    <tr>
                        <td><input type="button" value=" ^ " id="btnTurnleftforward" /></td>
                        <td></td>
                        <td><input type="button" value=" ^ " id="btnTurnrightforward" /></td>
                    </tr>
                    <tr>
                        <td><input type="button" value=" v " id="btnTurnleftback" /></td>
                        <td></td>
                        <td><input type="button" value=" v " id="btnTurnrightback" /></td>
                    </tr>
                    <tr>
                        <td></td>
                        <td><input type="button" value=" v " id="btnBackward" /></td>
                        <td></td>
                    </tr>
                    </table>
                    </center>
                </td>
            </tr>
        </table>
    </td>
</tr>
</table>
    <input type="button" value="Initialization Camera" id="btnInit" /><br>
</center>
</form>
</body>
</html>

http://web.joang.com:9000/jcook/StreamingVideo

StreamingSound

StreamingSound

TensorFlow OpenCV Slack Flack

TensorFlow OpenCV Slack Flack

main.py : 웹 메인 서버

#!/usr/bin/env python
#
# Project: Streaming Tensorflow image with Flask
# Author: jframework@gmail.com
# Date: 2020/05/11
# Website: http://www.joang.com
# Description:
# Publishing a video from room , Tensorflow and OpenCV and GPIO, Flask
# Usage:
# 1. Install Python dependencies: tensorflow, opencv, gpio, cv2, flask. (wish that pip install works like a charm)
# 2. Run "python3 main.py".
# 3. Navigate the browser to the local webpage. http://web.joang.com:8081/
#
#
from flask import Flask, render_template, Response, request
from camera import VideoCamera
from gpioControl import GpioControl
import os

app = Flask(__name__)

def shutdown_server():
    func = request.environ.get('werkzeug.server.shutdown')
    if func is None:
        raise RuntimeError('Not running with the kkoRack Server')
    func()

ONAIR = True
gpio = GpioControl()


@app.route('/')
def index():
    temp = os.popen("vcgencmd measure_temp").readline()
    return render_template('index.html', temperature=(temp.replace("temp=","")))

## Video ##
def gen(camera):
    global ONAIR
    while(ONAIR):
        frame = camera.get_frame()
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')

@app.route('/video_feed')
def video_feed():
    return Response(gen(VideoCamera()),
                    mimetype='multipart/x-mixed-replace; boundary=frame')



## Init ##
@app.route('/init')
def video_init():
    print("video_init")
    reString = gpio.initMotorPosition()
    return "Camera position init : " + reString




## camera movement ##
@app.route('/right')
def video_right():
    print("video_right")
    reString = gpio.moveRight()
    return "Camera Move right : " + reString

@app.route('/left')
def video_left():
    print("video_left")
    reString = gpio.moveLeft()
    return "Camera Move left : " + reString

@app.route('/up')
def video_up():
    print("video_up")
    reString = gpio.moveUp()
    return "Camera Move up : " + reString

@app.route('/down')
def video_down():
    print("video_down")
    reString = gpio.moveDown()
    return "Camera Move down : " + reString




## gpio on/off ##
@app.route('/clicklight')
def clicklight():
    reString = gpio.click()
    return "Light Click"


## System ##
@app.route('/stop')
def video_stop():
    global ONAIR
    ONAIR = False
    print("video_stop")
    return render_template('index.html')

@app.route('/start')
def video_start():
    global ONAIR
    ONAIR = True
    return render_template('index.html')

@app.route('/shutdown')
def shutdown():
    gpio.cleanUp()
    shutdown_server()
    return 'Server shutting down...'

@app.route('/temperature')
def temperature():
    temp = os.popen("vcgencmd measure_temp").readline()
    return (temp.replace("temp=",""))


if __name__ == '__main__':
    app.run(host='0.0.0.0', port='8081', debug=True)

camera.py : 카메라 기능

import cv2
from objectDetector import ObjectDetector
    
# Set up camera constants
IM_WIDTH = 640
IM_HEIGHT = 480

# Initialize frame rate calculation
frame_rate_calc = 1
freq = cv2.getTickFrequency()
font = cv2.FONT_HERSHEY_SIMPLEX

objDetector = ObjectDetector()


class VideoCamera(object):
    def __init__(self):
        # Using OpenCV to capture from device 0. If you have trouble capturing
        # from a webcam, comment the line below out and use a video file
        # instead.
        self.video = cv2.VideoCapture(0)
        # If you decide to use video.mp4, you must have this file in the folder
        # as the main.py.
        # self.video = cv2.VideoCapture('video.mp4')
        print( "width: {}, height : {}".format(self.video.get(3), self.video.get(4) ) )
        ret = self.video.set(3,IM_WIDTH)
        ret = self.video.set(4,IM_HEIGHT)
    
    def __del__(self):
        self.video.release()
    
    def get_frame(self):
        global frame_rate_calc
        t1 = cv2.getTickCount()
        success, frame = self.video.read()
        # We are using Motion JPEG, but OpenCV defaults to capture raw images,
        # so we must encode it into JPEG in order to correctly display the
        # video stream.
        frame = objDetector.objectDetector(frame)
        
        # Draw FPS
        cv2.putText(frame,"FPS: {0:.2f}".format(frame_rate_calc),(30,50),font,1,(255,255,0),2,cv2.LINE_AA)

        # FPS calculation
        t2 = cv2.getTickCount()
        time1 = (t2-t1)/freq
        frame_rate_calc = 1/time1
        
        ret, jpeg = cv2.imencode('.jpg', frame)
        return jpeg.tobytes()

objectDetector.py : 이미지 식별

#!/usr/bin/python
# -*- coding: UTF-8 -*-

# Import packages
import os
import cv2
import numpy as np
import tensorflow as tf
from time import sleep
import sys
from gpioControl import GpioControl
from slackmsg import SlackMsg

# Set up camera constants
IM_WIDTH = 640
IM_HEIGHT = 480

# This is needed since the working directory is the object_detection folder.
sys.path.append('/home/pi/tensorflow1/models/research')
sys.path.append('/home/pi/tensorflow1/models/research/object_detection')

# Import utilites
from utils import label_map_util
from utils import visualization_utils as vis_util

# Grab path to current working directory
#CWD_PATH = os.getcwd() + "/tensorflow1/models/research/object_detection"
CWD_PATH = "/home/pi/tensorflow1/models/research/object_detection"
#IMG_PATH = os.getcwd() + "/Pictures"
IMG_PATH = "/home/pi/Pictures"
print(" \n ###################################")
print("  Base Path %s" % CWD_PATH)
print("  Image Path %s" % IMG_PATH)
print(" ###################################")


#### Initialize TensorFlow model ####

# Name of the directory containing the object detection module we're using
MODEL_NAME = 'ssdlite_mobilenet_v2_coco_2018_05_09'

# Path to frozen detection graph .pb file, which contains the model that is used
# for object detection.
PATH_TO_CKPT = os.path.join(CWD_PATH,MODEL_NAME,'frozen_inference_graph.pb')

# Path to label map file
PATH_TO_LABELS = os.path.join(CWD_PATH,'data','mscoco_label_map.pbtxt')

# Number of classes the object detector can identify
NUM_CLASSES = 80

print(" \n ###################################")
print("  Load the label map ")
print(" ###################################")
## Load the label map.
# Label maps map indices to category names, so that when the convolution
# network predicts `5`, we know that this corresponds to `airplane`.
# Here we use internal utility functions, but anything that returns a
# dictionary mapping integers to appropriate string labels would be fine
label_map = label_map_util.load_labelmap(PATH_TO_LABELS)
categories = label_map_util.convert_label_map_to_categories(label_map, max_num_classes=NUM_CLASSES, use_display_name=True)
category_index = label_map_util.create_category_index(categories)

# Load the Tensorflow model into memory.
detection_graph = tf.Graph()
with detection_graph.as_default():
    od_graph_def = tf.compat.v1.GraphDef()
    with tf.io.gfile.GFile(PATH_TO_CKPT, 'rb') as fid:
        serialized_graph = fid.read()
        od_graph_def.ParseFromString(serialized_graph)
        tf.import_graph_def(od_graph_def, name='')

    sess = tf.compat.v1.Session(graph=detection_graph)

print(" \n ###################################")
print("  Define input and output tensors (i.e. data) for the object detection classifier ")
print(" ###################################")

# Input tensor is the image
image_tensor = detection_graph.get_tensor_by_name('image_tensor:0')

# Output tensors are the detection boxes, scores, and classes
# Each box represents a part of the image where a particular object was detected
detection_boxes = detection_graph.get_tensor_by_name('detection_boxes:0')

# Each score represents level of confidence for each of the objects.
# The score is shown on the result image, together with the class label.
detection_scores = detection_graph.get_tensor_by_name('detection_scores:0')
detection_classes = detection_graph.get_tensor_by_name('detection_classes:0')

# Number of objects detected
num_detections = detection_graph.get_tensor_by_name('num_detections:0')

print(" \n ###################################")
print("  Initialize other parameters ")
print(" ###################################")
# Initialize frame rate calculation
frame_rate_calc = 1
freq = cv2.getTickFrequency()
font = cv2.FONT_HERSHEY_SIMPLEX

# Initialize control variables used for pet detector
detected_inside = False
detected_outside = False

inside_counter = 0
outside_counter = 0

ObjX = 0
ObjY = 0

pause = 0
pause_counter = 0



gpio = GpioControl()
slackmsg = SlackMsg()


class ObjectDetector(object):
    
    def objectDetector(self, frame):
        # Use globals for the control variables so they retain their value after function exits
        global detected_inside, detected_outside
        global inside_counter, outside_counter
        global pause, pause_counter

        frame_expanded = np.expand_dims(frame, axis=0)
        
        # Perform the actual detection by running the model with the image as input
        (boxes, scores, classes, num) = sess.run(
            [detection_boxes, detection_scores, detection_classes, num_detections],
            feed_dict={image_tensor: frame_expanded})

        # Draw the results of the detection (aka 'visulaize the results')
        vis_util.visualize_boxes_and_labels_on_image_array(
            frame,
            np.squeeze(boxes),
            np.squeeze(classes).astype(np.int32),
            np.squeeze(scores),
            category_index,
            use_normalized_coordinates=True,
            line_thickness=8,
            min_score_thresh=0.40)

        # Draw boxes defining "outside" locations.
        TL_outside = (int(IM_WIDTH*0.6),int(IM_HEIGHT*0.25))
        BR_outside = (int(IM_WIDTH*0.85),int(IM_HEIGHT*.85))
        cv2.rectangle(frame,TL_outside,BR_outside,(255,20,20),3)
        cv2.putText(frame,"Outside room",(TL_outside[0]+10,TL_outside[1]-10),font,1,(255,20,255),3,cv2.LINE_AA)

        # Check the class of the top detected object by looking at classes[0][0].
        # If the top detected object is a person (73)
        # boxes ( xmin, xmax, ymin, ymax )
        threshold = 0.8
        for index, value in enumerate(classes[0]):
            ymin = boxes[0][index][0] * IM_HEIGHT
            xmin = boxes[0][index][1] * IM_WIDTH
            ymax = boxes[0][index][2] * IM_HEIGHT
            xmax = boxes[0][index][3] * IM_WIDTH
            #print(' =1= %s' % category_index.get(value) )
            if category_index.get(value) != None:
                personclassname = (category_index.get(value)).get('name')
                widthvalue = int((xmax - xmin) / 2)  # width 길이
                heightvalue = int((ymax - ymin) / 2)  # height 길이
                if( scores[0, index] != 0.0 ): print('> Score = %s, Object = %s , pause = %s' % (scores[0, index], personclassname, pause) )
                if scores[0, index] > threshold and personclassname == 'person' and pause == 0:
                    print('> Detected %s' % personclassname )

                    ObjX = int(((boxes[0][0][1]+boxes[0][0][3])/2)*IM_WIDTH)
                    ObjY = int(((boxes[0][0][0]+boxes[0][0][2])/2)*IM_HEIGHT)
                    
                    # Draw a circle at center of object
                    cv2.circle(frame,(ObjX,ObjY), 5, (75,13,180), -1)

                    # If object is in outside box, increment outside counter variable
                    if ((ObjX > TL_outside[0]) and (ObjX < BR_outside[0]) and (ObjY > TL_outside[1]) and (ObjY < BR_outside[1])):
                        outside_counter = outside_counter + 1
                    else :
                        inside_counter = inside_counter + 1

                
        # If pet has been detected inside for more than 10 frames, set detected_inside flag
        # and send a text to the phone.
        if inside_counter > 10:
            detected_inside = True
            cv2.imwrite(IMG_PATH+'/inside_' + str(ObjX) + '_' + str(ObjY) + '_counter.jpg', frame)
            captureImg=os.path.join(IMG_PATH, 'inside_' + str(ObjX) + '_' + str(ObjY) + '_counter.jpg')
            response = slackmsg.uploadImage("Inside Photo", captureImg)
            captureImg=response['file']['permalink']
            slackmsg.sendMsg("Inside", captureImg)
            
            # Set move to detected object  
            gpio.move_to_position(ObjX, ObjY)

            inside_counter = 0
            outside_counter = 0
            ObjX = 0
            ObjY = 0
            # Pause pet detection by setting "pause" flag
            pause = 1

        # If pet has been detected outside for more than 10 frames, set detected_outside flag
        # and send a text to the phone.
        if outside_counter > 10:
            detected_outside = True
            cv2.imwrite(IMG_PATH+'/outside_' + str(ObjX) + '_' + str(ObjY) + '_counter.jpg', frame)
            captureImg=os.path.join(IMG_PATH, 'outside_' + str(ObjX) + '_' + str(ObjY) + '_counter.jpg')
            response = slackmsg.uploadImage("Outside Photo", captureImg)
            captureImg=response['file']['permalink']
            slackmsg.sendMsg("Outside", captureImg)

            # Set move to detected object  
            gpio.move_to_position(ObjX, ObjY)

            inside_counter = 0
            outside_counter = 0
            ObjX = 0
            ObjY = 0
            # Pause pet detection by setting "pause" flag
            pause = 1

        # If pause flag is set, draw message on screen.
        if pause == 1:
            if detected_inside == True:
                cv2.putText(frame,'Inside!',(int(IM_WIDTH*.1),int(IM_HEIGHT*.5)),font,1,(0,0,0),7,cv2.LINE_AA)
                cv2.putText(frame,'Inside!',(int(IM_WIDTH*.1),int(IM_HEIGHT*.5)),font,1,(95,176,23),5,cv2.LINE_AA)

            if detected_outside == True:
                cv2.putText(frame,'Outside!',(int(IM_WIDTH*.1),int(IM_HEIGHT*.5)),font,1,(0,0,0),7,cv2.LINE_AA)
                cv2.putText(frame,'Outside!',(int(IM_WIDTH*.1),int(IM_HEIGHT*.5)),font,1,(95,176,23),5,cv2.LINE_AA)

            # Increment pause counter until it reaches 30 (for a framerate of 1.5 FPS, this is about 20 seconds),
            # then unpause the application (set pause flag to 0).
            pause_counter = pause_counter + 1
            if pause_counter > 30:
                pause = 0
                pause_counter = 0
                detected_inside = False
                detected_outside = False

        # Draw counter info
        cv2.putText(frame,'Detection counter: ' + str(max(inside_counter,outside_counter)),(10,100),font,0.5,(255,255,0),1,cv2.LINE_AA)
        cv2.putText(frame,'Pause counter: ' + str(pause_counter),(10,150),font,0.5,(255,255,0),1,cv2.LINE_AA)

        return frame

gpioControl.py : 등 켜기 등 릴ㄹ레이 모듈 , 카메라 위치 조정 스텝 모터 조정

import RPi.GPIO as GPIO
from time import sleep


GPIO.setmode(GPIO.BOARD)
GPIO.setup(12, GPIO.OUT, initial=1)
GPIO.setup(18, GPIO.OUT, initial=1)
GPIO.setup(11, GPIO.OUT, initial=1) # light
p1 = GPIO.PWM(12, 50)  # 50 Hz
p2 = GPIO.PWM(18, 50)  # 50
p1.start(0)
p2.start(0)
p1.ChangeDutyCycle(0)
p2.ChangeDutyCycle(0)

verticalVal = 6.5
horizontalVal = 6.5

cameraPositionX = 6.5
cameraPositionY = 6.5

# Set up camera constants
IM_WIDTH = 640
IM_HEIGHT = 480


class GpioControl(object):

    def __init__(self):
        global verticalVal
        global horizontalVal
        global p1
        global p2
        p1.ChangeDutyCycle(6.5)
        p2.ChangeDutyCycle(6.5)
        sleep(0.1)
        p1.ChangeDutyCycle(0)
        p2.ChangeDutyCycle(0)
        verticalVal = 6.5
        horizontalVal = 6.5
        print("> Init Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal))
   
    def click(self):
        GPIO.output(11, GPIO.LOW)
        sleep(0.5)
        GPIO.output(11, GPIO.HIGH)
        sleep(1)

    def __del__(self):
        global p1
        global p2
        p1.stop()
        p2.stop()
        print(" GPIO.__del__() ")
        GPIO.cleanup()
        
    def cleanUp(self):
        global p1
        global p2
        p1.stop()
        p2.stop()
        print(" GPIO.cleanUp() ")
        GPIO.cleanup()
        sleep(2)
    
    def initMotorPosition(self):
        # Init
        global verticalVal
        global horizontalVal
        global p1
        global p2
        p1.ChangeDutyCycle(6.5)
        p2.ChangeDutyCycle(6.5)
        sleep(0.1)
        p1.ChangeDutyCycle(0)
        p2.ChangeDutyCycle(0)
        verticalVal = 6.5
        horizontalVal = 6.5
        print("> Init Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal))
        return "Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal)

    def moveUp(self):
        global verticalVal
        global horizontalVal
        global p2
        verticalVal = round(verticalVal+0.2, 1)
        p2.ChangeDutyCycle(verticalVal)
        print("> UP Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal))
        sleep(0.1)
        p2.ChangeDutyCycle(0)
        return "Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal)
        
    def moveDown(self):
        global verticalVal
        global horizontalVal
        global p2
        verticalVal = round(verticalVal-0.2, 1)
        p2.ChangeDutyCycle(verticalVal)
        print("> Down Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal))
        sleep(0.1)
        p2.ChangeDutyCycle(0)
        return "Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal)
        
    def moveRight(self):
        global verticalVal
        global horizontalVal
        global p1
        horizontalVal = round(horizontalVal+0.2, 1)
        p1.ChangeDutyCycle(horizontalVal)
        print("> Right Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal))
        sleep(0.1)
        p1.ChangeDutyCycle(0)
        return "Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal)
        
    def moveLeft(self):
        global verticalVal
        global horizontalVal
        global p1
        horizontalVal = round(horizontalVal-0.2, 1)
        p1.ChangeDutyCycle(horizontalVal)
        print("> Left Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal))
        sleep(0.1)
        p1.ChangeDutyCycle(0)
        return "Vert=" + str(verticalVal) + ",Hort=" + str(horizontalVal)
        
 
    def move_to_position(self,ObjX, ObjY):
        global cameraPositionX
        global cameraPositionY
        global p1
        global p2
        print(" >> Move to location x=%s, y=%s" % (ObjX, ObjY))
        moveLoop = True
        movX = int(IM_WIDTH/2)-ObjX
        movY = int(IM_HEIGHT/2)-ObjY
        print(" >> Center location movX=%s, movY=%s" % (movX, movY))
        
        xx = 1
        xy = 0
        yx = 1
        yy = 0
        while(moveLoop):
            if( xy < abs(movX) ):
                p1.ChangeDutyCycle(cameraPositionX)
                sleep(0.1)
                p1.ChangeDutyCycle(0)
                print("xx=" + str(xx) + ", xy="+ str(xy) +" cameraPositionX=" +str(round(cameraPositionX,1)))
                xy = xx*xx * 12
                xx = xx + 1
                if(movX > 0): cameraPositionX = cameraPositionX - 0.2
                else: cameraPositionX = cameraPositionX + 0.2
            if( yy < abs(movY) ):
                p2.ChangeDutyCycle(cameraPositionY)
                sleep(0.1)
                p2.ChangeDutyCycle(0)
                print("yx=" + str(yx) + ", yy="+ str(yy) +" cameraPositionY=" +str(round(cameraPositionY,1)))
                yy = yx*yx * 12
                yx = yx + 1
                if(movY > 0): cameraPositionY = cameraPositionY + 0.2
                else: cameraPositionY = cameraPositionY - 0.2
            elif( xy >= movX and yy >= movY):
                print(" >> Center location movX="+str(movX)+", movY=" + str(movY))
                print(" >> Position location xy="+str(xy)
                      +", yy="+str(yy)
                      +" cameraPositionX="+str(round(cameraPositionX,1))+
                       " cameraPositionY="+str(round(cameraPositionY,1))+" .. ")
                moveLoop = False