К книге
Цифровая электроника для начинающихСтраница 15
94%
Страница 15
15

<html>

<head><title>Raspberry Pi server</title></head>

<body>

Turn <a href="/H">LED ON</a><br>

Turn <a href="/L">LED OFF</a><br>

</body>

</html>

Сам код сервера будет весьма прост. Естественно, это минимальный пример, реальный веб-сервер может поддерживать практически все современные технологии - POST и GET-запросы, Javascript и пр. Полет фантазии тут неограничен. Нам же будет достаточно следующего кода:

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer

class Server(BaseHTTPRequestHandler):

def do_GET(self):

self.send_response(200)

self.send_header('Content-type', 'text/html')

self.end_headers()

with open('index.html', 'r') as myfile:

data = myfile.read()

self.wfile.write(data)

if "/H" in self.path:

print "LED ON"

if "/L" in self.path:

print "LED OFF"

if __name__ == "__main__":

server_address = ('', 8000)

httpd = HTTPServer(server_address, Server)

print 'Starting httpd...'

try:

httpd.serve_forever()

except:

pass

print 'Done'

Самостоятельная работа: дописать код включения и выключения светодиода вместо функции print "LED ON" и print "LED OFF". Перед вызовом сервера serve_forever также нужно будет дописать код инициализации GPIO.

4.10. Дистанционное управление со смартфона

С помощью портов ввода-вывода мы уже можем управлять внешними устройствами, например платой управления двигателем. Мы также можем запустить собственный сервер, как было показано выше. Добавим в наш сервер возможность реакции на нажатие и отпускание кнопок, это позволит использовать смартфон как полноценный пульт дистанционного управления. Такой интерфейс сейчас весьма популярен и используется, например, для управления мини-дронами.

Наш интерфейс, впрочем, будет попроще - сделаем страницу с всего двумя кнопками LEFT и RIGHT, при нажатии на которые на Raspberry Pi будут генерироваться соответствующие события.

Основная работа здесь будет в модификации файла index.html - в него мы добавим код, срабатывающий при нажатии и отпускании кнопок. Это позволит например, управлять радиоуправляемым танком, если поставить на него Raspberry Pi.

Для создания кнопки в HTML есть тег button, а для подписки на события нажатия и отпускания мы будем использовать Javascript, который поддерживается всеми браузерами.

Обновленный код index.html приведен ниже.

<html>

<head><title>Raspberry Pi server</title></head>

<body>

<button id="btn_left" type="button" style="height:60px;width:60px">Left</button>

<button id="btn_right" type="button" style="height:60px;width:60px">Right</button>

<script>

document.getElementById("btn_left").onmousedown = function() { mouseDownL() };

document.getElementById("btn_left").onmouseup = function() { mouseUpL() };

document.getElementById("btn_left").onmouseleave = function() { mouseUpL() };

document.getElementById("btn_right").onmousedown = function() { mouseDownR() };

document.getElementById("btn_right").onmouseup = function() { mouseUpR() };

document.getElementById("btn_right").onmouseleave = function() { mouseUpR() };

function httpGetAsync(theUrl, callback) {

console.log('httpGetAsync: ' + theUrl);

var xmlHttp = new XMLHttpRequest();

xmlHttp.onreadystatechange = function() {

if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {

// callback(xmlHttp.responseText);

console.log(xmlHttp.responseText);

}

}

xmlHttp.open("GET", theUrl, true); // true for asynchronous

xmlHttp.send(null);

}

function mouseDownL() {

httpGetAsync(window.location.href + "?BtnLeftDown", null);

}

function mouseUpL() {

httpGetAsync(window.location.href + "?BtnLeftUp", null);

}

function mouseDownR() {

httpGetAsync(window.location.href + "?BtnRightDown", null);

}

function mouseUpR() {

httpGetAsync(window.location.href + "?BtnRightUp", null);

}

</script>

</body>

</html>

Разберем код подробнее. Как можно видеть, мы создали 2 кнопки с идентификаторами btn_left и btn_right. Далее мы добавили к каждой кнопке обработчики событий onmousedown, onmouseup и onmouseleave (на смартфоне нет мыши, но события нажатия и отпускания пальца называются также). Они будут вызываться когда пользователь нажимает или отпускает кнопку. Внутри каждого события вызывается соответствующая функция для левой (Left) или правой (Right) кнопки, например mouseDownL(). Наша задача - уведомить сервер, посылкой ему соответствующего GET-запроса. Для этого написана функция httpGetAsync. В обработчике каждой из кнопок мы вызываем разные функции, например BtnRightDown, BtnLeftDown. Переменная window.location.href хранит адрес сервера, таким образом при нажатии кнопки LEFT на сервер отправляется запрос http://192.168.0.124:8000/?BtnLeftDown.

На этом клиентская часть закончена. Сохраним этот файл как index.html. Сам сервер тоже необходимо дописать, чтобы он корректно обрабатывал новые запросы. Код сервера показан ниже, как можно видеть, изменения в нем минимальны.

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer

class Server(BaseHTTPRequestHandler):

def do_GET(self):

print self.path

if "?BtnLeftDown" in self.path:

self.send_response(200)

self.send_header('Content-type', 'text/plain')

self.end_headers()

self.wfile.write("ok left start")

return

if "?BtnLeftUp" in self.path:

self.send_response(200)

self.send_header('Content-type', 'text/plain')

self.end_headers()

self.wfile.write("ok left end")

return

if "?BtnRightDown" in self.path:

self.send_response(200)

self.send_header('Content-type', 'text/plain')

self.end_headers()

self.wfile.write("ok right start")

return

if "?BtnRightUp" in self.path:

self.send_response(200)

self.send_header('Content-type', 'text/plain')

self.end_headers()

self.wfile.write("ok right end")

return

with open('index.html', 'r') as htmlfile:

self.send_response(200)

self.send_header('Content-type', 'text/html')

self.end_headers()

data = htmlfile.read()

self.wfile.write(data)

if __name__ == "__main__":

# Start server

server_address = ('', 8000)

httpd = HTTPServer(server_address, Server)

print 'Starting httpd...'

try:

httpd.serve_forever()

except:

pass

Мы проверяем, есть ли в запросе нужная строка (например BtnLeftDown), и если есть, то выполняем соответствующее действие. В данном случае мы отправляем клиенту подтверждение вида “ok left start”, это удобно для отладки. В реальности нужно будет добавить дополнительный код, например для активации соответствующих портов ввода-вывода.

Теперь все готово, сохраняем наш файл и запускаем сервер. Кстати, для тестирования можно использовать тот же компьютер, используя ip-адрес http://127.0.0.1:8000. Запускаем браузер, нажимаем кнопки, и в окне отладки браузера видим ответы сервера.

Теперь мы можем управлять чем угодно с помощью длинных или коротких нажатий кнопок. Можно кстати, приобрести на ebay специальную плату с гусеницами и моторами, и управлять ею удаленно.

Самостоятельная работа: добавить код еще для двух кнопок “вперед”, “назад”, это позволит сделать вполне полноценное управление.

4.11. Подключаем веб-камеру

Мы не будем рассматривать подключение к Raspberry Pi всех датчиков, которые рассматривались в главе про Arduino - по сути принцип тот же, и сделать “по аналогии” совсем не сложно. На крайний случай, подключение например, того же DS18S20 к Raspberry Pi можно найти в Гугле за 5 минут. Мы пойдем дальше, и рассмотрим то, что на Arduino или ESP32 сделать нельзя. Например, подключим к Raspberry Pi веб-камеру и посмотрим, что с ней можно сделать. Вычислительная мощность Raspberry Pi весьма неплоха, и позволяет решать интересные задачи, в том числе и по обработке изображений. Тем более, что камера вполне пригодится рассмотренном ранее на радиоуправляемом танке, если мы захотим сделать его на базе Raspberry Pi.

Рекомендуется использовать веб-камеры, которые уже были проверены на совместимость с Raspberry Pi, список таких камер можно найти здесь: https://elinux.org/RPi_USB_Webcams. Я использовал Logitech C920, которая в этом списке как раз есть.

Первым делом необходимо подключить камеру и убедиться, что она видна в системе. Наберем команду lsusb, мы должны увидеть список типа такого.

Если камера видна в системе, можно двигаться дальше. Самый простой способ получить изображение с камеры - установить программу fscam. Наберем команду sudo apt-get install fswebcam.

Получим картинку с камеры: введем команду fswebcam image.jpg. В текущем каталоге будет создано изображение с одноименным названием. В моем случае изображение оказалось пересвеченным, камера не успела настроиться на освещение. Для исправления этого можно добавить параметр задержки: fswebcam --delay=1 image.jpg.

Чтобы узнать список доступных разрешений, можно ввести команду v4l2-ctl --list-formats-ext. Для Logitech C920 максимальное разрешение составляет 1920x1080, что вполне неплохо. С fswebcam почему-то оно не заработало, максимальное разрешение составило 1280х720, что тоже неплохо. Для того чтобы указать разрешение, надо ввести команду: fswebcam -r 1280x720 image.jpg. Несложно сделать и так, чтобы изображения делались постоянно: fswebcam -r 1280x720 --loop 10 image.jpg. С помощью параметра loop задается время в секундах, в нашем примере оно равно 10 - каждые 10 секунд изображение будет перезаписываться на новое.

Несложно записать и видео, для этого нужно поставить программу avconv: sudo apt-get install libav-tools. Теперь можно записать видео, введя команду avconv -f video4linux2 -s 640x480 -i /dev/video0 video0.avi (для примера выбрано разрешение 640х480). Если в системе присутствует несколько камер, вместо /dev/video0 возможно придется указать другое устройство (список можно посмотреть, введя команду ls /dev/video*).

Самостоятельная работа: поэкспериментировать с различными настройками фото и видео, оценить требуемый объем данных для хранения или передачи таких данных.

4.12. Запускаем видеонаблюдение

Используя материал предыдущей страницы, несложно сделать на базе Raspberry Pi свой сервер видеонаблюдения. Для этого достаточно добавить на наш веб-сервер код отдачи изображения, и параллельно запустить fswebcam, который будет делать снимки. Правда, это будет не совсем “видео”, а скорее “фото” наблюдение, но тем не менее, это все равно интересно.

Шаг 1. Мы уже умеем запустить веб-сервер, который будет показывать страницу index.html из текущей папки. Поменяем файл index.html, чтобы он имел следующий вид:

<html>

<head><title>Raspberry Pi server</title></head>

<body>

Camera image:<BR/>

<img src="image.jpg"/>

</body>

</html>

Как нетрудно видеть, мы добавили туда элемент img, чтобы показывалась наша картинка.

Шаг 2. Сделаем чтобы программа fswebcam запускалась при старте, и закрывалась при выходе. Это не сложно сделать средствами Python:

cmd = 'fswebcam -r 640x480 --loop 10 image.jpg'

photoThread = subprocess.Popen("exec " + cmd, stdout=subprocess.PIPE, shell=True)

os.kill(photoThread.pid, signal.SIGINT)

Мы создаем поток photoThread командой subprocess.Popen, а в конце работы приложения посылаем потоку команду закрытия.

Шаг 3. Добавим в наш веб-сервер возможность “отдавать” файлы jpeg. Для этого нужно добавить новый тип Content-type = 'image/jpg', чтобы браузер “знал” что передаваемые данные это картинка jpg.

Готовый код показан ниже.

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer

import os, subprocess, signal

Предыдущая главаГлава 15 из 16Следующая глава