Submarine

잠수함 만들기 

Start, Stop Shell

start shell 
#!/bin/bash

echo
echo '##### START Submarine  #####'
echo

wpa_cli -i wlan0 status
echo
echo

FILENAME=/home/hyunsu/submarine/nohup.out
if [ -f "$FILENAME" ] ; then
        echo "nohup.out delete !"
        rm /home/hyunsu/submarine/nohup.out
else
        echo "file not exist"
fi

echo '##### START CCTV #####'
cd /home/hyunsu/submarine
nohup python3 /home/hyunsu/submarine/SubMarine.py &
sleep 3

echo '##### START BROD SOUND #####'
hwString=`pactl list | grep -A 40 'Source' | grep -A 20 'device.bus = "usb"' | grep 'device.string' | grep -o '[0-9]'`
echo -e "\n Mic HW = [$hwString]"

nohup cvlc -vvv alsa://plughw:$hwString --sout '#transcode{acodec=mp3,ab=64,channels=1}:standard{access=http,dst=0.0.0.0:8080/out.mp3}' 1> /dev/null 2>&1 &

echo
echo '##### STARTed Submarine  #####'
echo

Stop shell
#!/bin/bash

echo
echo '##### STOP  Submarine #####'
echo


ps -ef | grep SubMarine.py | grep -v grep
KILLPID=`ps -ef | grep SubMarine.py | grep -v grep | awk '{print($2)}'`
echo "Stop Submarine Process = " $KILLPID
kill -9 $KILLPID
sleep 3

ps -ef | grep vlc | grep -v grep
KILLPID=`ps -ef | grep vlc | grep -v grep | awk '{print($2)}'`
echo "Stop Brod Sound Process = " $KILLPID
kill -9 $KILLPID
sleep 3


echo
echo '##### STOPed Submarine #####'
echo

 

메인프로그램 SubMarine.py

SubMarine.py

메인 프로그램 

from flask import Flask, render_template, send_from_directory, Response, send_file, request, redirect, url_for
from flask_socketio import SocketIO
import argparse, logging, logging.config, conf
import os
from power import PowerStatus
from datetime import datetime
from commChecker import CommChecker
from gpioControl import GpioControl
from usbwebcamera import UsbWebCamera
from piwebcamera import PiWebCamera


app = Flask(__name__)
app.config['SECRET_KEY'] = '1764121q'
socketio = SocketIO(app)

logging.config.dictConfig(conf.dictConfig)
logger = logging.getLogger(__name__)

power = PowerStatus()
commChecker = CommChecker()
gpio = GpioControl()

usbcamera = UsbWebCamera(20,1)
usbcamera.run()

piwebcamera = PiWebCamera()
piwebcamera.run()

@app.after_request
def add_header(r):
    """
    Add headers to both force latest IE rendering or Chrome Frame,
    and also to cache the rendered page for 10 minutes
    """
    r.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
    r.headers["Pragma"] = "no-cache"
    r.headers["Expires"] = "0"
    r.headers["Cache-Control"] = "public, max-age=0"
    return r

@app.route("/")
@app.route("/index.html")
def index():
    logger.debug("Requested /")
    return render_template("index.html")

@app.route("/favorit.ico")
def favorit_ico():
    logger.debug("Requested favorit.ico image")
    filename = "favorit.ico"
    return send_file(filename)

@app.route("/VideoStatus")
def videostatus():
    logger.debug("Video Status change ")
    content = usbcamera.status()
    return Response(content, mimetype='text/xml')

@app.route("/SubmStatus")
def submStatus():
    logger.debug("Submarine Status change ")
    content = piwebcamera.status()
    return Response(content, mimetype='text/xml')
    
@app.route("/temperature")
def temperature():
    content = os.popen("vcgencmd measure_temp").readline()
    content = content.replace("temp=", "")
    powerstatus = power.getPowerStatus()
    return Response("내부온도:" + content+"  , 전원:"+powerstatus+" , 측정시간:"+str(datetime.now()), mimetype='text/xml')

@app.route("/commCheck")
def commcheck():
    connstatus = str(commChecker.checkQuality())
    return Response(connstatus+" , "+str(datetime.now()), mimetype='text/xml')

@app.route('/lightOnOff', methods=['GET', 'POST'])
def lightOnOff():
    gpio.light()
    logger.debug('message KK Fired !!!')
    return Response('Light ON', mimetype='text/html')

''' #############   MOVE    #############  '''

@app.route("/floating", methods=['GET', 'POST'])
def floating():
    if request.method == 'POST':
        moveOrder = request.form['moveCnt']
        if not moveOrder :
            reString = "Do not move"
        else :
            reString = gpio.Floating(int(moveOrder))
        print("Move floating ..." + moveOrder)
    return Response(reString, mimetype='text/html')

@app.route("/diving", methods=['GET', 'POST'])
def diving():
    if request.method == 'POST':
        moveOrder = request.form['moveCnt']
        if not moveOrder :
            reString = "Do not move"
        else :
            reString = gpio.Diving(int(moveOrder))
        print("Move diving ..." + moveOrder)
    return Response(reString, mimetype='text/html')
    
    
    
@app.route("/forward", methods=['GET', 'POST'])
def forward():
    if request.method == 'POST':
        moveOrder = request.form['moveFBLFCnt']
        if not moveOrder :
            reString = "Do not move"
        else :
            reString = gpio.Forward(int(moveOrder))
        print("Move Forward ..." + moveOrder)
    return Response(reString, mimetype='text/html')

@app.route("/backward", methods=['GET', 'POST'])
def backward():
    if request.method == 'POST':
        moveOrder = request.form['moveFBLFCnt']
        if not moveOrder :
            reString = "Do not move"
        else :
            reString = gpio.Backward(int(moveOrder))
        print("Move Backward ..." + moveOrder)
    return Response(reString, mimetype='text/html')
    
@app.route("/right", methods=['GET', 'POST'])
def right():
    if request.method == 'POST':
        moveOrder = request.form['moveFBLFCnt']
        if not moveOrder :
            reString = "Do not move"
        else :
            reString = gpio.TurnLeftF(int(moveOrder))
        print("Move Right ..." + moveOrder)
    return Response(reString, mimetype='text/html')
    
@app.route("/left", methods=['GET', 'POST'])
def left():
    if request.method == 'POST':
        moveOrder = request.form['moveFBLFCnt']
        if not moveOrder :
            reString = "Do not move"
        else :
            reString = gpio.TurnRightF(int(moveOrder))
        print("Move Left ..." + moveOrder)
    return Response(reString, mimetype='text/html')


@app.route("/video_usb_feed")
def video_usb_feed():
    return Response(genusb(usbcamera),
        mimetype="multipart/x-mixed-replace; boundary=frame")

def genusb(usbcamera):
    logger.debug("Starting USB stream")
    while True:
        frame = usbcamera.get_frame()
        yield (b'--frame\r\n'
               b'Content-Type: image/png\r\n\r\n' + frame + b'\r\n')


@app.route("/video_pi_snapshot")
def video_pi_snapshot():
    return Response(genpi(piwebcamera),
        mimetype="multipart/x-mixed-replace; boundary=frame")
               
def genpi(piwebcamera):
    logger.debug("Starting PI capchure")
    while True:
        frame = piwebcamera.get_frame()
        yield (b'--frame\r\n'
               b'Content-Type: image/png\r\n\r\n' + frame + b'\r\n')
   
    
if __name__=="__main__":
    logger.debug("Starting Submarine start")
#    socketio.run(app, log_output=True, host='0.0.0.0', port=8081, debug=True, use_reloader=False, allow_unsafe_werkzeug=True)
    socketio.run(app, log_output=True, host='0.0.0.0', port=8081, allow_unsafe_werkzeug=True)

USB 카메라 프로그램 (Thread)

USB 카메라 프로그램 (Thread)

import cv2
import threading
import time
import logging
import os

logger = logging.getLogger(__name__)
archive_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'archive')

thread = None
status = True

class UsbWebCamera:

    def __init__(self,fps=20,video_source=0):
        logger.info("Initializing usb camera class with {fps} " + str(fps) + " and video_source={" + str(video_source) + "}")
        self.fps = fps
        self.video_source = video_source
        self.camera = cv2.VideoCapture(self.video_source)

        self.camera.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
        self.camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
        
        self.max_frames = 5*self.fps
        self.frames = []
        self.isrunning = False
        
    def run(self):
        logging.debug("Perparing Usb Camera thread")
        global thread
        if thread is None:
            logging.debug("Creating thread")
            thread = threading.Thread(target=self._capture_loop,daemon=True)
            logger.debug("Starting thread")
            self.isrunning = True
            thread.start()
            logger.info("Thread started")

    def _capture_loop(self):
        global status
        dt = 1/self.fps
        logger.debug("Observation started")
        while self.isrunning:
            if(status):
                v,im = self.camera.read()
                im = cv2.flip(im, 1)
                #im = cv2.flip(im, 0)
                if v:
                    if len(self.frames)==self.max_frames:
                        self.frames = self.frames[1:]
                    self.frames.append(im)
            time.sleep(dt)
        logger.info("Thread stopped successfully")

    def status(self):
        global status
        logger.debug("Status isrunning" + str(status))
        if(status):
            content = "STOP THREAD !"
            status = False
        else:
            content = "START THREAD !"
            status = True
        return content
        
    def get_frame(self, _bytes=True):
        if len(self.frames)>0:
            if _bytes:
                img = cv2.imencode('.png',self.frames[-1])[1].tobytes()
            else:
                img = self.frames[-1]
        else:
            logger.info("Change cam source 1")
            self.video_source = 1
            self.camera = cv2.VideoCapture(self.video_source)
            self.camera.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
            self.camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
            with open(archive_path+"/not_found.jpeg","rb") as f:
                img = f.read()
        return img
       

 

PI 카메라 프로그램 (Thread)

PI 카메라 프로그램 (Thread)

# import the necessary packages
from picamera.array import PiRGBArray
from picamera import PiCamera
import cv2
import threading
import time
import logging
import os

logger = logging.getLogger(__name__)
archive_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'archive')

thread = None
status = False

# Set up camera constants
#IM_WIDTH = 1024
#IM_HEIGHT = 768
IM_WIDTH = 640
IM_HEIGHT = 480

class PiWebCamera:
    def __init__(self,fps=20):
        logger.info(f"Initializing pi camera class with {fps} fps ")
        self.fps = fps
        self.camera = PiCamera(framerate=24)
        self.camera.resolution = (IM_WIDTH,IM_HEIGHT)
        # self.camera.rotation = 180 
        self.rawCapture = PiRGBArray(self.camera, size=(IM_WIDTH,IM_HEIGHT))
        self.rawCapture.truncate(0)
        self.max_frames = 5*self.fps
        self.frames = []
        self.isrunning = False
        
    def run(self):
        logging.debug("Perparing Pi Camera thread")
        global thread
        if thread is None:
            logging.debug("Creating PI thread")
            thread = threading.Thread(target=self._capture_loop,daemon=True)
            logger.debug("Starting PI thread")
            self.isrunning = True
            thread.start()
            logger.info("Thread PI started")

    def _capture_loop(self):
        global status
        dt = 1/self.fps
        logger.debug("Observation started")
        while self.isrunning:
            if(status):
                self.camera.capture(self.rawCapture, format="bgr", use_video_port=True)
                self.rawCapture.truncate(0)
                image = self.rawCapture.array
                if len(self.frames)==self.max_frames:
                    self.frames = self.frames[1:]
                self.frames.append(image)
            time.sleep(dt)
        logger.info("Thread stopped successfully")

    def status(self):
        global status
        logger.debug("Status isrunning" + str(status))
        if(status):
            content = "STOP THREAD !"
            status = False
        else:
            content = "START THREAD !"
            status = True
        return content

        
    def get_frame(self, _bytes=True):
        if len(self.frames)>0:
            if _bytes:
                img = cv2.imencode('.png',self.frames[-1])[1].tobytes()
            else:
                img = self.frames[-1]
        else:
            with open(archive_path+"/not_found.jpeg","rb") as f:
                img = f.read()
        return img
        

 

메인 화면 index.html

메인 화면 index.html

{% extends "base.html" %}

{% block content %}
<div class="container">
    <center>
    Submarine 0.1 
    </center>
    <form name="frm">
    <table>
        <tr>
            <td colspan=3>
            Temperature = <span id="temperature"> 내부 온도 </span>
            </td>
        </tr>
        <tr>
            <td colspan=3>
            메시지:<span id="resultmessage">...</span><br><BR>
            <input type="button" value="VideoStatus" id="btnVideoStatus" /> Video Status=<span id="videostatus">STARTING</span>
            <audio autoplay controls> 
                <source src="http://web.kkorack.com:19080/out.mp3" type="audio/mp3"> 
            </audio>
            <BR>
            </td>
        </tr>
        <tr>
            <td>
                <table>
                    <tr>
                        <td></td>
                        <td><input type="button" value=" LIGHT ON " id="btnLightOn" /></td>
                        <td><br><br><br></td>
                    </tr>
                    <tr>
                        <td></td>
                        <td><input type=text id="moveFBLFCnt" maxlength="5" size="5" value=1 />
                        <td><br><br><br></td>
                    </tr>
                    <tr>
                        <td></td>
                        <td><center><input type="button" value=" ^ " id="btnForward" /></center></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><center><input type="button" value=" v " id="btnBackward" /></center></td>
                        <td></td>
                    </tr>
                </table>
            </td>
            <td>
                <img src="{{ url_for('video_usb_feed') }}" class="border border-dark">
            </td>
            <td>
                <table>
                    <tr>
                        <td colspan=3>
                            <input type="button" value="SubmarineStatus" id="btnSubmStatus" /> Submarine Status=<span id="submstatus">STOPED</span><br>
                            <img src="{{ url_for('video_pi_snapshot') }}" width=400 class="border border-dark">
                            <br>
                            <span id="communicationlevel"> 통신 정보 </span><br>통신이 중지되면 부상
                        </td>
                    </tr>
                    <tr>
                        <td colspan=3>
                            <input type=text id="moveCnt" maxlength="5" size="5" value=1 />
                        </td>
                    </tr>
                    <tr>
                        <td></td>
                        <td><input type="button" value=" UP " id="btnFloating" /></td>
                        <td></td>
                    </tr>
                    <tr>
                        <td></td>
                        <td><input type="button" value=" DOWN " id="btnDiving" /></td>
                        <td></td>
                    </tr>
                </table>
            </td>
        </tr>
        <tr>
            <td colspan=3>
                <span id="alertmessage"> 알림 메시지 </span><br>
            </td>
        </tr>
    </table>
    </form>
</div>    
<script type="text/javascript">


var tempId = null;
tempId = setInterval(getTemperatureFunc, 1000*60);
var commCheck = null;
commCheck = setInterval(getCommStatus, 1000*30);
//clearInterval(timerId);

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


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

    /////////////////////////////////////////////////////////////////////////////////////////////

    window.onload = function() {
        document.getElementById("btnLightOn").onclick = setLightOnOff;
        document.getElementById("btnFloating").onclick = getFloatingFunc;
        document.getElementById("btnDiving").onclick = getDivingFunc;
        document.getElementById("btnForward").onclick = getForwardFunc;
        document.getElementById("btnBackward").onclick = getTurnBackwardFunc;
        document.getElementById("btnLeft").onclick = getLeftFunc;
        document.getElementById("btnRight").onclick = getRightFunc;
        document.getElementById("btnVideoStatus").onclick = getVideoStatusFunc;
        document.getElementById("btnSubmStatus").onclick = getSubmStatusFunc;
    }
        
    function setLightOnOff() {
         var fName = "/lightOnOff";
         xhr = new XMLHttpRequest();
         xhr.open("POST", fName, true);
         xhr.onreadystatechange = function() { 
              if (xhr.readyState == 4) {
                   if (xhr.status == 200) {
                        document.getElementById("alertmessage").value = xhr.responseText;
                   } else {
                        alert("ERROR : " + xhr.status);
                   }
             }
        }
        xhr.send(null); 
    }    
        
        function getFloatingFunc() {
            var fName = "/floating"; 
            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("resultmessage").innerHTML = xhr.responseText;
                    } else {
                        alert("ERROR : " + xhr.status);
                    }
                }
            }
            xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
            xhr.send("moveCnt=" + data);
        }

        function getDivingFunc() {
            var fName = "/diving"; 
            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("resultmessage").innerHTML = xhr.responseText;
                    } else {
                        alert("ERROR : " + xhr.status);
                    }
                }
            }
            xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
            xhr.send("moveCnt=" + data);
        }

        function getForwardFunc() {
            var fName = "/forward"; 
            data=document.getElementById("moveFBLFCnt").value;
            xhr = new XMLHttpRequest();
            xhr.open("POST", fName, true);
            xhr.onreadystatechange = function() { 
                if (xhr.readyState == 4) {
                    if (xhr.status == 200) { 
                        document.getElementById("resultmessage").innerHTML = xhr.responseText;
                    } else {
                        alert("ERROR : " + xhr.status);
                    }
                }
            }
            xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
            xhr.send("moveFBLFCnt=" + data);
        }

        function getTurnBackwardFunc() {
            var fName = "/backward"; 
            data=document.getElementById("moveFBLFCnt").value;
            xhr = new XMLHttpRequest();
            xhr.open("POST", fName, true);
            xhr.onreadystatechange = function() { 
                if (xhr.readyState == 4) {
                    if (xhr.status == 200) { 
                        document.getElementById("resultmessage").innerHTML = xhr.responseText;
                    } else {
                        alert("ERROR : " + xhr.status);
                    }
                }
            }
            xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
            xhr.send("moveFBLFCnt=" + data);
        }
        
        
        
        function getRightFunc() {
            var fName = "/right"; 
            data=document.getElementById("moveFBLFCnt").value;
            xhr = new XMLHttpRequest();
            xhr.open("POST", fName, true);
            xhr.onreadystatechange = function() { 
                if (xhr.readyState == 4) {
                    if (xhr.status == 200) { 
                        document.getElementById("resultmessage").innerHTML = xhr.responseText;
                    } else {
                        alert("ERROR : " + xhr.status);
                    }
                }
            }
            xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
            xhr.send("moveFBLFCnt=" + data);
        }

        function getLeftFunc() {
            var fName = "/left"; 
            data=document.getElementById("moveFBLFCnt").value;
            xhr = new XMLHttpRequest();
            xhr.open("POST", fName, true);
            xhr.onreadystatechange = function() { 
                if (xhr.readyState == 4) {
                    if (xhr.status == 200) { 
                        document.getElementById("resultmessage").innerHTML = xhr.responseText;
                    } else {
                        alert("ERROR : " + xhr.status);
                    }
                }
            }
            xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
            xhr.send("moveFBLFCnt=" + data);
        }

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

        
</script>

{% endblock %}