Всем привет! В прошлой статье я рассказал как работает веб интерфейс управления роботом, эдакий передатчик команд. В этой статье было бы логично рассказать как работает "приемник этих самых команд".
Если Вы следите за трелло, то знаете, что в планах было реализовать управление роботом по сокетам и с помощью REST API, но от последнего я отказался.
Собственно, начнем.
Стек технологий на самом деле легко предсказать: нам нужно принимать команды и применять их каким-то образом. Вспоминаем, что мы собираем робота на RPi, значит нам пригодится RPi.GPIO, ну а принимать команды мы будем с помощью python-socketio:
%lang(python)% import eventlet import socketio import mech
mech это самописный модуль, его импорты таковы:
%lang(python)% import RPi.GPIO as GPIO
Сначала нужно проинициализировать сокет сервер:
%lang(python)%
sio = socketio.Server(cors_allowed_origins='*')
app = socketio.WSGIApp(sio, static_files={
'/': {'content_type': 'text/html', 'filename': 'index.html'}
})
Мы инициализируем его как WSGI приложение, однако пользоваться этим мы не будем)))
Не будем ставить на малину веб сервер, будем просто кидать запросы на ip:port.
Обращаю внимание, что мы разрешаем делать запросы откуда угодно. Это нужно потому что запрос с ПК оператора робота на малину считается cross-origin (что логично), и без такой настройки он просто не пройдет.
Далее инициализируем наш mech модуль:
%lang(python)% mech.init()
Вот код иницализации:
%lang(python)%
GPIO.setmode(GPIO.BCM) # настраиваем логический маппинг пинов (их 2)
GPIO.setwarnings(False) # говорим, что нам неинтересно знать, что там уже используется
for pin in pins_on:
GPIO.setup(pin, GPIO.OUT) # настраиваем все пины на выход
left_right_motors_off() # на всякий случай ставим их в логический 0
pins_on это массив GPIO, которые мы используем.
Рассмотрим низкоуровневые функции работы с GPIO:
%lang(python)%
def left_right_motors_off():
for pin in pins_on:
GPIO.output(pin, False)
def left_motor_on(ward):
level = True if ward == 'forward' else False
GPIO.output(21, level)
GPIO.output(22, not level)
def right_motor_on(ward):
level = True if ward == 'forward' else False
GPIO.output(23, level)
GPIO.output(24, not level)
Мы просто в зависимости от переданного аргумента (forward/backward) устанавливаем пины в нужные логические уровни. Моторы подключены через драйвер TB6612FNG:
Таким образом, мы можем менять направление вращения ротора моторов.
Условно есть 2 пина A и B. Если A = 1, B = 0, то вращение, например, по часовой стрелке, иначе - против.
Пины PWM этого драйвера мы не используем, поэтому просто подадим на них лог. 1.
На пин STBY подаем лог. 1 (Это пин включения драйвера, пускай всегда будет включен)
Остались пины питания и входы-выходы драйверы, но тут все вроде бы логично.
Теперь посмотрим чуть выше:
%lang(python)%
def go(direction):
print('go', direction)
right_motor_on(direction)
left_motor_on(direction)
def stop():
print('stop')
left_right_motors_off()
def turn(direction):
print('turn', direction)
if direction == 'left':
left_motor_on('forward')
right_motor_on('backward')
else:
left_motor_on('backward')
right_motor_on('forward')
В зависимости от направления включаем моторы в нужном порядке в нужные стороны вращения.
Все довольно просто.
Но как же все это работает в совокупности?
А вот как:
%lang(python)%
@sio.event
def connect(sid, environ):
print('connect ', sid)
@sio.event
def disconnect(sid):
print('disconnect ', sid)
@sio.on('go')
def go(sid, data):
mech.go(data)
@sio.on('turn')
def turn(sid, data):
mech.turn(data)
@sio.on('stop')
def stop(sid, data):
mech.stop()
Мы регистрируем слушателей событий. И в момент, когда эти события приходят с веб-интерфейса, вызываем нужные функции. Все!
Остается разве что запустить сервер:
%lang(python)%
if __name__ == '__main__':
eventlet.wsgi.server(eventlet.listen(('', 8765)), app)
Практика подходит к концу. Остается немного времени. На днях я соберу весь материал в кучу и мы посмотрим, что нам удалось собрать. Следите за обновлениями!
Спасибо за внимание.



