Skocz do zawartości

Mobilny robot z kamerą


ZbychuW

Pomocna odpowiedź

(edytowany)

Ethanak, z serwerem działa fajnie. Poszczególne polecenia testuję z pomocniczego panelu (kod poniżej). Po naciśnięciu przycisku wysyłane jest polecenie a przy okazji generowany jest tekst komunikatu. Jeśli w czasie, gdy komunikat jest odtwarzany kliknę inny przycik, polecenia są wysyłane bez opóźnień, jak to miało przedtem miejsce.

Komunikaty są nadmiarowo długie ale to dla testów.

Dzięki za pomoc. Pozdrawiam.

Wrzucam kawałek kodu (klasa przygotowana do testów opóźnień komunikatów), gdyby ktoś miał ochotę to powtórzyć. Zawiera również obsługę kamery.

from PIL import Image, ImageTk
import tkinter as tk
import argparse
import datetime
import cv2
import os
import time
import threading
import socketserver 
import socket
from time import ctime
import serial
from serial.tools.miniterm import unichr
import subprocess as cmdLine
import kedrigern
cmdLine.run("clear")

class Application:
    def __init__(self, output_path = "./"):
        self.vs = cv2.VideoCapture(0) # capture video frames, 0 is your default video camera
        self.vs.set(3,320)
        self.vs.set(4,240)
        self.output_path = output_path  # store output path
        self.current_image = None  # current image from the camera

        self.root = tk.Tk()  # initialize root window
        self.root.title("PyImageSearch PhotoBooth")  # set window title
        # self.destructor function gets fired when the window is closed
        self.root.protocol('WM_DELETE_WINDOW', self.destructor)
        
        self.serial = serial.Serial(
            port='/dev/ttyAMA0',
            baudrate = 19200,
            parity=serial.PARITY_NONE,
            stopbits=serial.STOPBITS_ONE,
            bytesize=serial.EIGHTBITS,
            timeout=1
        )
        self.voice = kedrigern.Voice()

        self.panel = tk.Label(self.root)  # initialize image panel
        self.panel.pack(padx=10, pady=10)
        
        # create a button, that when pressed, will take the current frame and save it to file
        btn = tk.Button(self.root, text="Snapshot!", command=self.takeSnapshot)
        btn.pack(fill="both", expand=True, padx=10, pady=10)
        
        # create a button, that when pressed, will stops all motors
        btn = tk.Button(self.root, text="STOP", command=self.stop)
        btn.pack(fill="both", expand=True, padx=10, pady=10)
        
        #Buttons to controll motors
        self.motorSpeed = tk.Scale(self.root, from_=-250, to=250, orient = tk.HORIZONTAL, label = "Robot speed", command=self.changeMotorSpeed)
        self.motorSpeed.set(0)
        self.motorSpeed.pack(fill="both", expand=True, padx=0, pady=0)
        
        self.servoBottomPosition = tk.Scale(self.root, from_=0, to=180, orient = tk.HORIZONTAL, label = "Bottom Servo", command=self.changeBottomServoPosition)
        self.servoBottomPosition.set(90)
        self.servoBottomPosition.pack(fill="both", expand=True, padx=0, pady=0)
        
        self.servoTopPosition = tk.Scale(self.root, from_=0, to=180, orient = tk.HORIZONTAL, label = "Top Servo", command=self.changeTopServoPosition)
        self.servoTopPosition.set(90)
        self.servoTopPosition.pack(fill="both", expand=True, padx=0, pady=0)
        
        # start a self.video_loop that constantly pools the video sensor
        # for the most recently read frame
        self.videoLoop()
    
    def sendCommand(self, command):
        #self.serial.write(b'START_LF\n')
        self.serial.write(bytes(command+'\n','utf-8'))
        print(command)
        
    def videoLoop(self):
        """ Get frame from the video stream and show it in Tkinter """
        ok, frame = self.vs.read()  # read frame from video stream
        if ok:  # frame captured without any errors
            frame = cv2.flip(frame, 180) # Flip camera vertically
            cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)  # convert colors from BGR to RGBA
            self.current_image = Image.fromarray(cv2image)  # convert image for PIL
            imgtk = ImageTk.PhotoImage(image=self.current_image)  # convert image for tkinter
            self.panel.imgtk = imgtk  # anchor imgtk so it does not be deleted by garbage-collector
            self.panel.config(image=imgtk)  # show the image
        self.root.after(30, self.videoLoop)  # call the same function after 30 milliseconds

    def takeSnapshot(self):
        """ Take snapshot and save it to the file """
        ts = datetime.datetime.now() # grab the current timestamp
        filename = "{}.png".format(ts.strftime("%Y-%m-%d_%H-%M-%S"))  # construct filename
        p = os.path.join(self.output_path, filename)  # construct output path
        self.current_image.save(p, "PNG")  # save image as jpeg file
        print("[INFO] saved {}".format(filename))
        
    def stop(self):
        self.motorSpeed.set(0)
        self.servoBottomPosition.set(90)
        self.servoTopPosition.set(90)
        self.voice.say("Zatrzymanie wszystkich silnikĂłw", freq=1)
        
    def changeMotorSpeed(self,speed):
        self.sendCommand("SET_SPEED,"+ speed)
        self.voice.say("Uwaga, zmiana prędkości", freq=1)
        
    def changeBottomServoPosition(self,position):
        self.sendCommand("SET_SERVO_POSITION,1," + position )
        self.voice.say("Uwaga, zmiana położenia kamery", freq=1)
        
    def changeTopServoPosition(self,position):
        self.sendCommand("SET_SERVO_POSITION,2," + position )
        self.voice.say("Uwaga, zmiana położenia kamery", freq=1)
 
    def destructor(self):
        """ Destroy the root object and release all resources """
        print("[INFO] closing...")
        self.root.destroy()
        self.vs.release()  # release web camera
        cv2.destroyAllWindows()  # it is not mandatory in this application
        
# construct the argument parse and parse the arguments

ap = argparse.ArgumentParser()
ap.add_argument("-o", "--output", default="./",
    help="path to output directory to store snapshots (default: current folder")
args = vars(ap.parse_args())

# start the app
print("[INFO] starting...")
pba = Application(args["output"])
pba.root.mainloop()

 

Edytowano przez ZbychuW
Link do komentarza
Share on other sites

9 godzin temu, ZbychuW napisał:

z serwerem działa fajnie

No to się cieszę 🙂

I jeszcze parę drobiazgów:

Możesz pobawić się parametrami freq i tempo (przyjmują wartości od 0.5 do 2.0). U mnie wygląda to tak (domowa centralka do wszystkiego, dla mnie trochę za wolno ale to ma służyć wszystkim w domu):

self.voice = kedrigern.Voice(tempo = 0.85, freq = 0.85)

Jeśli komunikaty są długie, warto dać voice.stop() przed voice.say() - bez stop() komunikaty będą kolejkowane, z stop() poprzedni zostanie przerwany (o ile akurat coś mówi), a kolejka zostanie wyczyszczona(o ile coś w niej jest).

Głośność możesz regulować globalnie w pliku /etc/defaults/kedrigern (domyślna wartość 14 może w niektórych przypadkach być za mała).

A tak poza tym to fajny robocik 🙂 Napisz coś więcej o mapowaniu.

 

 

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.