ZbychuW Kwiecień 6, 2022 Autor tematu Udostępnij Kwiecień 6, 2022 (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 Kwiecień 6, 2022 przez ZbychuW
ethanak Kwiecień 7, 2022 Udostępnij Kwiecień 7, 2022 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.
Pomocna odpowiedź
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ę »