Как управлять роботом на Raspberry Pi с помощью пульта от телевизора
Если вы приобрели один из наших доступных наборов EduKit Robotics, вы, несомненно, дойдёте до момента, когда захотите продвинуться дальше, настраивая и создавая своего собственного уникального робота.
Многие наши покупатели добавляют способ дистанционного управления роботом, что позволяет вручную контролировать действия робота.
Существует множество способов сделать это, некоторые сложнее других. Для простого, гибкого и расширяемого варианта мы рекомендуем добавить FLIRC USB к вашему роботу.
FLIRC?
Если вы ещё не слышали о FLIRC или хотите узнать больше о том, как он работает, ознакомьтесь с нашей более ранней статьёй в блоге.
В ней вы найдёте всё, что вам нужно знать, включая информацию о том, как настроить USB-приёмник (что действительно просто!).
Управление роботом через FLIRC
Причина, по которой нам нравится использовать FLIRC USB на нашем роботе EduKit, заключается в том, что он позволяет использовать практически любой инфракрасный пульт в качестве контроллера. У вас, вероятно, есть несколько таких дома – пульты от телевизора, медиаприставки, DVD-плеера, Hi-Fi-системы и другие пульты обычно используют инфракрасную технологию.
Мы просто указываем FLIRC общаться с вашим Raspberry Pi (мы используем Raspberry Pi Zero W) так же, как клавиатура, и Python не видит разницы! Это делает программирование очень простым, поскольку не требуется никаких библиотек или дополнительного кода.
Шаги для достижения этого просты:
Создайте скрипт, который позволит вашему роботу EduKit принимать нажатия клавиш в качестве команд
Настройте FLIRC с помощью программного обеспечения FLIRC на вашем ПК/Mac/Linux
Подключите FLIRC к вашему Raspberry Pi
Вперёд!
Давайте покажем вам, как это сделать.
Допущения
Для этого руководства мы предполагаем, что вы уже собрали базового робота EduKit и протестировали его с помощью кода из рабочих листов EduKit.
Это означает, что вы уже должны быть знакомы со следующим:
Терминал
Директории
Создание и запуск Python-скриптов
Базовый код управления моторами EduKit
Установка библиотеки
Давайте обновим ваш Raspberry Pi перед началом работы – это просто хорошая практика.
Откройте сеанс терминала, введите следующую команду, нажмите Enter, а затем следуйте любым подсказкам на экране:
sudo apt-get update
Дождитесь завершения. После этого введите следующую команду, а затем снова нажмите Enter:
sudo apt-get upgrade
Затем, чтобы установить библиотеку inputs, введите следующую команду и снова нажмите Enter:
sudo pip3 install inputs
Библиотека Inputs
Код, используемый для управления вашим роботом через FLIRC, представляет собой сочетание кода из рабочих листов EduKit и небольшой Python-библиотеки под названием inputs.
Python-библиотека inputs позволяет обнаруживать ввод от широкого спектра устройств, включая обычную клавиатуру. Это отлично подходит для использования совместно с FLIRC USB, поскольку FLIRC позволяет нам использовать любой существующий ИК-пульт для отправки команд в виде клавиатурного ввода – привязывая любую кнопку пульта к любой клавише клавиатуры.
Ваш пульт затем общается с FLIRC по инфракрасному каналу, FLIRC общается с Raspberry Pi, как если бы он был клавиатурой, и Python (и библиотека inputs) ничего не подозревает!
Библиотека inputs отслеживает нажатие клавиши и состояние этой клавиши, т.е. она зарегистрирует нажатие клавиши „W“ как состояние 1, а также зарегистрирует клавишу „W“ как состояние 0, когда вы отпустите клавишу. Подробнее об этом в разделе кода ниже.
Код
Вот Python-скрипт для управления вашим роботом с помощью клавиш W (вперёд), S (назад), A (влево) и D (вправо) на клавиатуре. Я также назначил клавишу E для завершения программы (что останавливает все работающие моторы и также очищает GPIO).
Вы можете ввести код вручную (как описано в рабочем листе 1 робота EduKit) или скачать наш скрипт FLIRC EduKit Robot здесь.
Создайте свой Python-скрипт в той же директории, что и примеры EduKit, чтобы всё было в одном месте (используйте cd EduKitRobotics для перехода в эту директорию). Также, чтобы мы все следовали вместе, назовите свой скрипт EduKitFLIRC.py.
Мы покажем вам, как привязать FLIRC USB к кнопкам вашего пульта от телевизора чуть позже, а пока вот несколько пояснений о том, как работает код:
#!/usr/bin/python
# Imports
import RPi.GPIO as GPIO
from inputs import get_key
# Set GPIO mode to BCM
GPIO.setmode(GPIO.BCM)
# Motor A GPIO direction (output)
GPIO.setup(7, GPIO.OUT)
GPIO.setup(8, GPIO.OUT)
# Motor B GPIO direction (output)
GPIO.setup(9, GPIO.OUT)
GPIO.setup(10, GPIO.OUT)
def main(): # Our main program
lastkey = "" # Create a variable
while True: # Start a loop
# Start a for statement that will check for key presses
events = get_key()
for event in events:
# If statements for each key press
# Key press is state 1
# Key release is state 0
if event.code == "KEY_W" and event.state == 1: # If 'W' is 'pressed'
print ("Forwards")
GPIO.output(7, 1)
GPIO.output(8, 0)
GPIO.output(9, 1)
GPIO.output(10, 0)
lastkey = "KEY_W" # Change the lastkey variable to the key just pressed
if event.code == "KEY_S" and event.state == 1: # If 'S' is 'pressed'
print ("Backwards")
GPIO.output(7, 0)
GPIO.output(8, 1)
GPIO.output(9, 0)
GPIO.output(10, 1)
lastkey = "KEY_S" # Change the lastkey variable to the key just pressed
if event.code == "KEY_A" and event.state == 1: # If 'A' is 'pressed'
print ("Left")
GPIO.output(7, 1)
GPIO.output(8, 0)
GPIO.output(9, 0)
GPIO.output(10, 1)
lastkey = "KEY_A" # Change the lastkey variable to the key just pressed
if event.code == "KEY_D" and event.state == 1: # If 'D' is 'pressed'
print ("Right")
GPIO.output(7, 0)
GPIO.output(8, 1)
GPIO.output(9, 1)
GPIO.output(10, 0)
lastkey = "KEY_D" # Change the lastkey variable to the key just pressed
if event.code == "KEY_E" and event.state == 1: # If 'E' is 'pressed'
print ("quit")
quit() # Exit the script (runs the 'Finally' block at the bottom of this script)
# An elif statement to detect if the last key press (lastkey variable) was released (state 0)
# If the last key was released, this block triggers and stops the motors
elif event.code == lastkey and event.state == 0:
print("Stop")
GPIO.output(7, 0)
GPIO.output(8, 0)
GPIO.output(9, 0)
GPIO.output(10, 0)
"""
if Python is running this file as the main program, it sets the special __name__ variable
to have a value "__main__". As this will be true in this case, it means this try/except
block will always run at the start (which is what we want)
"""
if __name__ == '__main__':
try: # If no errors, run this block
main() #Run the main () function
except KeyboardInterrupt: #If the keyboard interrupts the program
pass
finally: # Turn off all motors and clean the GPIO before exit
print ("Stopping motors")
GPIO.output(7, 0)
GPIO.output(8, 0)
GPIO.output(9, 0)
GPIO.output(10, 0)
GPIO.cleanup()
print ("Bye for now")
Строка 5:
Импортируем часть библиотеки inputs, что просто подключает её к нашему скрипту, чтобы мы могли её использовать.
from inputs import get_key
Строка 20:
Мы определяем новую переменную „lastkey“, которая будет хранить последнюю нажатую клавишу (подробнее об этом ниже).
lastkey = "" # Create a variable
Строка 22:
Запускает цикл while. Он поддерживает скрипт в рабочем состоянии, пока мы вручную не выйдем из программы.
while True: # Start a loop
Строки 25-26:
Эти строки постоянно проверяют нажатие клавиш для срабатывания „события“.
events = get_key()
for event in events:
Строки 32-76:
Здесь у нас несколько операторов if, по одному для каждой назначенной клавиши. Если определённая клавиша нажата (event.state == 1), код под этим оператором if выполняется, а затем сразу же продолжается проверка нажатий клавиш.
Каждый оператор if заканчивается обновлением „lastkey“ клавишей, которая была нажата.
Мы делаем это, чтобы не определять отдельный блок для каждой клавиши, который сообщает Python, что делать при отпускании клавиши (event.state == 0), поскольку это было бы одно и то же действие/код для каждой клавиши, т.е. когда мы отпускаем клавишу, мы останавливаем робота.
Это реализовано в строках 71-76, где мы говорим Python «Если последняя нажатая клавиша имеет состояние 0 (отпущена), остановить робота». Это экономит нам много строк кода, которые по сути делали бы одно и то же.
if event.code == "KEY_W" and event.state == 1: # If 'W' is 'pressed'
print ("Forwards")
GPIO.output(7, 1)
GPIO.output(8, 0)
GPIO.output(9, 1)
GPIO.output(10, 0)
lastkey = "KEY_W" # Change the lastkey variable to the key just pressed
if event.code == "KEY_S" and event.state == 1: # If 'S' is 'pressed'
print ("Backwards")
GPIO.output(7, 0)
GPIO.output(8, 1)
GPIO.output(9, 0)
GPIO.output(10, 1)
lastkey = "KEY_S" # Change the lastkey variable to the key just pressed
if event.code == "KEY_A" and event.state == 1: # If 'A' is 'pressed'
print ("Left")
GPIO.output(7, 1)
GPIO.output(8, 0)
GPIO.output(9, 0)
GPIO.output(10, 1)
lastkey = "KEY_A" # Change the lastkey variable to the key just pressed
if event.code == "KEY_D" and event.state == 1: # If 'D' is 'pressed'
print ("Right")
GPIO.output(7, 0)
GPIO.output(8, 1)
GPIO.output(9, 1)
GPIO.output(10, 0)
lastkey = "KEY_D" # Change the lastkey variable to the key just pressed
if event.code == "KEY_E" and event.state == 1: # If 'E' is 'pressed'
print ("quit")
quit() # Exit the script (runs the 'Finally' block at the bottom of this script)
# An elif statement to detect if the last key press (lastkey variable) was released (state 0)
# If the last key was released, this block triggers and stops the motors
elif event.code == lastkey and event.state == 0:
print("Stop")
GPIO.output(7, 0)
GPIO.output(8, 0)
GPIO.output(9, 0)
GPIO.output(10, 0)
Строки 84-99:
Это наш блок try/except. Он позволяет указать, что должно произойти в случае ошибки. Секция „try“ (наша основная программа) выполняется, если ошибки нет, секция except выполняется, если есть – и мы определили „ошибку“ как прерывание с клавиатуры (нажатие ctrl+c).
Это сделано просто для того, чтобы мы могли корректно выйти из программы (остановив моторы и очистив GPIO), если мы программируем через терминал или подобное средство.
if __name__ == '__main__':
try: # If no errors, run this block
main() #Run the main () function
except KeyboardInterrupt: #If the keyboard interrupts the program
pass
finally: # Turn off all motors and clean the GPIO before exit
print ("Stopping motors")
GPIO.output(7, 0)
GPIO.output(8, 0)
GPIO.output(9, 0)
GPIO.output(10, 0)
GPIO.cleanup()
print ("Bye for now")
Настройка FLIRC как клавиатуры
Когда код вашего робота готов принимать ввод с клавиатуры, нам нужно настроить FLIRC USB как клавиатуру, а затем привязать кнопки нашего пульта к командам клавиатуры.
Вставьте FLIRC USB в ваш компьютер и откройте приложение FLIRC, затем выберите Controllers > Full Keyboard.
В приложении FLIRC выберите клавишу „W“ на клавиатуре (для движения вперёд):
Затем возьмите выбранный вами ИК-пульт и нажмите любую кнопку, которую считаете подходящей для движения робота вперёд (клавиша W). Как только FLIRC зарегистрирует нажатие кнопки на вашем пульте, вы должны увидеть подтверждающее сообщение, как в примере ниже:
Повторите это для всех команд в скрипте (W, S, A, D и E), затем закройте приложение.
Переместите FLIRC USB с вашего ПК на робот EduKit на Raspberry Pi (вам понадобится переходник USB-microUSB, если вы используете Raspberry Pi Zero), и загрузите его.
Запуск программы
Убедитесь, что вы находитесь в директории EduKit, введя следующую команду:
cd EduKitRobotics
Чтобы запустить код, введите следующую команду и нажмите Enter:
sudo python3 EduKitFLIRC.py
Теперь ваш пульт дистанционного управления должен управлять роботом с помощью кнопок, которые вы выбрали!