Уведомления

Группа в Telegram: @pythonsu

#1 Окт. 9, 2020 01:17:26

alexzlo
Зарегистрирован: 2020-10-09
Сообщения: 3
Репутация: +  0  -
Профиль   Отправить e-mail  

Проблема с потоками

Пишу самоходную коляску с 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()

Отредактировано alexzlo (Окт. 9, 2020 01:18:27)

Офлайн

#2 Окт. 9, 2020 09:51:19

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  252  -
Профиль   Отправить e-mail  

Проблема с потоками


Мдаа… Интересный проект. Похоже не хватает быстродействия цикла передачи данных от клавиатуры.
Надо залоггировать действия в файл и посмотреть где тормозит. 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. По уму вам надо зарегистрировать обработчики событий клавиатуры и в основном потоке показывать видео.

Начните с того что упростите код. Там слишком много лишнего. А потом надо таймировать.



Офлайн

#3 Окт. 9, 2020 11:34:26

alexzlo
Зарегистрирован: 2020-10-09
Сообщения: 3
Репутация: +  0  -
Профиль   Отправить e-mail  

Проблема с потоками

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

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

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

Отредактировано alexzlo (Окт. 9, 2020 11:40:10)

Офлайн

#4 Окт. 9, 2020 13:28:51

alexzlo
Зарегистрирован: 2020-10-09
Сообщения: 3
Репутация: +  0  -
Профиль   Отправить e-mail  

Проблема с потоками

Сейчас проверил, если использовать камеру ноутбука, а не rtsp поток то видео не зависает

Офлайн

#5 Окт. 9, 2020 14:07:35

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  252  -
Профиль   Отправить e-mail  

Проблема с потоками

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

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

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.

Ну а так, может у вас робот в принципе не может смотреть если едет. Мы же не знаем как оно там сделано.



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version