Необходимо завершить цикл подпроцесса через пользовательский ввод (GPIO.input)

Мне нужно выполнить команду bash в программе python на Raspberry Pi, которая запускает запись, которая действительно начинает запись, если это звук выше определенной частоты, и заканчивается через 8 секунд или если есть тишина. После того, как запись закончена, она запускается сама и ждет записи нового звука. Каждая запись помечена временем. Это код, который я цитировал здесь:

while GPIO.input(26) == False:
    timestamp = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
    process = subprocess.Popen ("rec -c 2 -r 192000 --buffer 50000 -b 32" + filepath + timestamp + ".wav sinc 0.1k silence 1 0.1 0.8% 1 0.4 0.8% vol 6 trim 0 8", shell = True)
    process.communicate()

Как видите, для завершения цикла программа ждет сигнала GPIO-входа (кнопка). У меня есть дополнительный код, который ищет имя подпроцесса и убивает его.

Но вот моя проблема: пока цикл работает, он только «ищет» ввод в миллисекундах между завершением одной записи и началом новой». Если я нажимаю кнопку во время записи, цикл продолжается после записи. Он только прерывается если я нажму между ними.

Сначала я подумал, что, возможно, цикл while - плохой выбор... но, если я не ошибаюсь, проблема, похоже, в запущенном подпроцессе.

Итак, вот мой вопрос: как я могу выполнить этот цикл записи, но могу остановить/убить во время текущей записи с помощью пользовательского ввода через GPIO. (ctrl+c не подходит)

Большое спасибо


person Esmi    schedule 12.01.2016    source источник
comment
while GPIO.input(26) == False: ‹-- разве это не срабатывает несколько раз всякий раз, когда оно ложно? Я не вижу никакого использования логических значений или других механизмов блокировки/отклонения, чтобы ваша программа не запускала сотни подпроцессов. recording = False; while GPIO.input(26) == False and not recording: recording = True; start_recording(); # recording finishes... recording = False;   -  person jDo    schedule 09.03.2016


Ответы (1)


Проблема в том, что цикл while проверяет условие только один раз каждый раз в цикле. Вызов process.communicate() ожидает завершения команды rec, так что вы абсолютно правы — кнопка проверяется только один раз, сразу после rec и перед timestamp = ....

Решение состоит в том, чтобы следить за кнопкой в ​​отдельном потоке, работающем параллельно с rec. В этом ответе предлагается использовать обнаружение событий из библиотеки RPi.GPIO. Попробуйте что-то вроде этого:

should_exit = False

def my_callback(channel):
    if GPIO.input(26):
        should_exit = True

GPIO.add_event_detect(26, GPIO.RISING, callback=my_callback, bouncetime=300)

while not should_exit:
    timestamp = ...

Подпрограмма my_callback должна запускаться при нажатии кнопки и устанавливать флаг should_exit. Как только rec завершится, while проверит should_exit и завершит работу. (Внимание - не проверено!)

person cxw    schedule 12.01.2016
comment
большое спасибо, я попробую - моя проблема в том, что я также хотел бы отменить текущую запись - но я думаю - таким образом я могу выполнить kill-скрипт - person Esmi; 13.01.2016
comment
хорошо, я попробовал - и обнаружение событий работает - иногда - но это кажется очень ненадежным - person Esmi; 13.01.2016
comment
Рад, что это лучше, чем ничего! Боюсь, у меня нет личного опыта работы с RPi.GPIO. Есть ли у кнопки правильное подтягивание или опускание? Все соединения надежны? Прерывистая работа может быть связана с аппаратной проблемой. Кроме того, попробуйте цикл, который не запускает rec, а просто выводит отладочное сообщение и смотрите, правильно ли определяется кнопка. - person cxw; 13.01.2016
comment
я попробую спасибо. пока не знаю иногда ничего не работает, потом работает 2 раза подряд и перестает потом что-то обнаруживать и бывает время очень хорошо работает долгое время но перестает определять и на входе потом тоже - может это помехи между нормальным GPIO. в и обнаружение вызова - person Esmi; 13.01.2016