Найти - Пользователи
Полная версия: Проблема с потоками
Начало » Python для новичков » Проблема с потоками
1
alexzlo
Пишу самоходную коляску с ip камерой. Python скрипт на компе, принимает rtsp поток с камеры и отсылает http запросы на управление двигателями в зависимости от нажатых клавиш. Сделано в 2 потока, но есть проблемка. Когда я жму стрелку для движения на компе, то в окне питона видео зависает, пока не отпущу клавишу, потом видео догоняет и я вижу что произошло и куда я уехал. Очень не удобно, а как придумать что бы видео не останавливалось пока жмешь клавишу ни как не могу понять. Хелп.

 import threading
import cv2
import requests
import numpy as np
import math
from pynput import keyboard
from threading import Thread
class Roboto:
    def __init__(self):
        self.u = 0
        self.d = 0
        self.l = 0
        self.r = 0
        self.rtsp = 'rtsp://192.168.1.118:554/ch0_1.h264'
        self.token = '******************************'
    def move(self, forward, side):
        response = requests.get(
            'http://blynk-cloud.com/' + self.token + '/update/V0?value=' + str(side) + '&value=' + str(forward))
    def on_press(self, key):
        k = format(key)
        if k == 'Key.up' and self.u == 0:
            self.move(10, 0)
            self.u = 1
        if k == 'Key.down' and self.d == 0:
            self.move(-10, 0)
            self.d = 1
        if k == 'Key.left' and self.l == 0:
            self.move(0, -5)
            self.l = 1
        if k == 'Key.right' and self.r == 0:
            self.move(0, 5)
            self.r = 1
    def on_release(self, key):
        k = format(key)
        if k == 'Key.down' or k == 'Key.up' or k == 'Key.left' or k == 'Key.right':
            self.move(0, 0)
            self.u = 0
            self.d = 0
            self.l = 0
            self.r = 0
        if key == keyboard.Key.esc:
            # Stop listener
            return False
    def camera(self):
        cam = cv2.VideoCapture(self.rtsp)
        cv2.namedWindow('cam')
        while True:
            ret, frame = cam.read()
            if ret:
                frame = frame[0:360, 0:640]
                frame = cv2.rotate(frame, cv2.ROTATE_90_CLOCKWISE)
                cv2.imshow('cam', frame)
            else:
                print("Cam not release")
                break
            k = cv2.waitKey(24) & 0xFF
            if k == 27:
                break
        cam.release()
        cv2.destroyAllWindows()
    def controll(self):
        with keyboard.Listener(
                on_press=self.on_press,
                on_release=self.on_release) as listener:
            listener.join()
def main():
    roboto = Roboto()
    thread1 = Thread(name='camera', target=roboto.camera)
    thread2 = Thread(name='controll', target=roboto.controll)
    thread1.start()
    thread2.start()
    thread1.join()
    thread2.join()
if __name__ == '__main__':
    main()
doza_and

Мдаа… Интересный проект. Похоже не хватает быстродействия цикла передачи данных от клавиатуры.
Надо залоггировать действия в файл и посмотреть где тормозит. press release move(те http get) и посмотреть сколько команды вместе требуют времени и влезают ли они в цикл генерации событий от клавы.

Что неясно:
Что такое format
Как устроен чам робот, что с той стороны. Каков код, аппаратура.

Что можно сделать:
Очевидно форматирование строк в цикле рального времени не гуд.
  def on_press(self, key):
        #k = format(key) - Убираем формтирование
#        if k == 'Key.up' and self.u == 0:
# Проверка строк это нехорошо сравнивать коды. Сначала проверять то что быстрее проверяется self.u == 0
        if self.u == 0 and k == code_up:
            self.move(10, 0)
            self.u = 1
# if k == 'Key.down' and self.d == 0:
# зачем все 4 варианта проверять?
 elif k == code_dn and self.d == 0:
            self.move(-10, 0)
            self.d = 1
Очевидно плохо сделан релиз.
 def on_release(self, key):
        if key == keyboard.Key.esc:
              return False
        else:
            self.move(0, 0)
            self.u = 0
            self.d = 0
            self.l = 0
            self.r = 0

Судя по архитектуре вы вообще зря используете треды. У вас их 4 - основной поток, два ваших и еще один который запустил puinput. По уму вам надо зарегистрировать обработчики событий клавиатуры и в основном потоке показывать видео.

Начните с того что упростите код. Там слишком много лишнего. А потом надо таймировать.
alexzlo
На той стороне старый робот пылесос с ip камерой, мозгом пылесоса выступает nodemcu, который принимает get запросы через облачный сервис blynk и рулит моторами. Сделано все так потому что нет pasberry py. Собрал из того что нашел в тумбочке.

format взят из примеров либы pynput, либу использую потому что как я понял из коробки python не умеет отслеживать нажатие стрелочных клавиш.

Изначально у меня был цикл видео и цикл pynput, но оно не работало, скрипт вечно висел в одном из циклов, смотря какой из них первый в скрипте, поэтому пришел к Threads.
alexzlo
Сейчас проверил, если использовать камеру ноутбука, а не rtsp поток то видео не зависает
doza_and
По идее от вас команда уходит только в начале периода когда вы кнопку зажали, поэтому не должно видео виснуть на весь период нажатия. Обмен с локальной камерой идет по другому каналу связи, что конечно влияет на все процессы.

Поэтому результат этого эксперимента не отменяет необходимости залоггировать последовательность происходящих событий.
alexzlo
Изначально у меня был цикл видео и цикл pynput,

О каком цикле pynput вы говорите???? У вас нет цикла. И ни в какой реализации он не нужен.

   def controll(self):
        with keyboard.Listener(
                on_press=self.on_press,
                on_release=self.on_release) as listener:
            listener.join()

По уму вам надо использовать событийно ориентированную архитектуру приложения чтото из tkinter, pyqt, wxwidgets, asyncio. Кто его знает как устроен pynput.

Ну а так, может у вас робот в принципе не может смотреть если едет. Мы же не знаем как оно там сделано.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB