class Server(BaseHTTPRequestHandler):
def do_GET(self):
if "image.jpg" in self.path:
try:
self.send_response(200)
self.send_header('Content-type', 'image/jpg')
self.end_headers()
f = open('image.jpg', 'rb')
self.wfile.write(f.read())
f.close()
except:
pass
return
with open('index.html', 'r') as imgfile:
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
data = imgfile.read()
self.wfile.write(data)
if __name__ == "__main__":
# Start photos shooting
cmd = 'fswebcam -r 640x480 --loop 10 image.jpg'
photoThread = subprocess.Popen("exec " + cmd, stdout=subprocess.PIPE, shell=True)
# Start server
server_address = ('', 8000)
httpd = HTTPServer(server_address, Server)
print 'Starting httpd...'
try:
httpd.serve_forever()
except:
pass
# Close photo shooting
os.kill(photoThread.pid, signal.SIGINT)
Как можно видеть, все вполне просто. Если в строке запроса присутствует “image.jpg”, мы загружаем картинку, иначе “index.html”. Изменить частоту обновления изображений можно, поменяв параметр loop, там же можно поменять и разрешение.
Все готово - запускаем python web.py, и с любого браузера можем зайти на страницу http://192.168.0.104:8000 (адрес может быть другим) и увидеть картинку с камеры. Это можно будет сделать и удаленно, если настроить статический IP адрес и перенаправление порта 8000 на роутере.
Чтобы сервер автоматически стартовал при запуске Raspberry Pi, нужно будет добавить строку вызова в /etc/rc.local, например так:
cd /home/pi/Documents/Cam
python /home/pi/Documents/Cam/web.py &
Важно: поскольку сервер постоянно сохраняет изображения локально на карте памяти, это негативно скажется на ее ресурсе - количество операций записи для карт памяти ограничено. Если планируется постоянное использование такого сервера, рекомендуется создать RAM-диск в памяти и указать путь к нему в настройках fswebcam и index.html. Настройку RAM-диска желающие могут найти в онлайн-руководствах по Raspberry Pi.
4.13. Интервальная съемка (time-lapse photo)
С помощью fswebcam несложно делать серию фото, например каждые 5 секунд. Это позволяет делать интересные кадры, например для записи движения Луны или облаков.
Команда для запуска выглядит так:
fswebcam -l 10 -r 1280x720 test-%Y-%m-%d--%H-%M-%S.jpg
Здесь “-l 10” задает временной интервал, “-r 1280x720” задает разрешение, имя файла “test-%Y-%m-%d--%H-%M-%S.jpg” задает шаблон даты и времени.
Можно указывать разные форматы шаблонов даты-времени, воспользовавшись таблицей:
%d
День месяца [01..31]
%H
Час [00..23]
%I
Час в 12-часовом формате [00..12]
%j
День [001..366]
%m
Месяц [01..12]
%M
Минута [00..59]
%S
Секунда [00..59]
%W
Номер недели в году [00..53]
%w
День [0(Вс)..6]
%y
Год, 2х значное число [00..99]
%Y
Год, 4х значное число
Соответственно, при запуске вышеприведенной команды в текущей папке будут создаваться файлы вида test-2018-02-25--12-39-40.jpg, test-2018-02-25--12-40-50.jpg, test-2018-02-25--12-40-00.jpg и т.д. Потом их можно склеить в видео с помощью специальных утилит.
4.14. Подключаемся к камере с помощью OpenCV
Выше мы использовали fswebcam для записи изображений с камеры. Это хорошо работает, но если мы хотим большей гибкости настроек, то лучше написать собственный код. К тому же, как было сказано выше, постоянная запись файлов уменьшает ресурс карты памяти. Поэтому далее мы будем работать с камерой напрямую.
Для работы с изображениями есть полезная библиотека OpenCV. Для ее установки введем команду: sudo apt-get install python-opencv.
Теперь всего лишь в несколько строк кода, мы можем написать свой аналог fswebcam:
import cv2
import time
cam = cv2.VideoCapture(0) #set the port of the camera as before
try:
count = 0
while True:
retval, image = cam.read() #return a True bolean and and the image if all go right
print count
cv2.imwrite("frame-%d.jpg" % count, image)
count += 1
time.sleep(0.5)
except:
pass
cam.release()
Как можно видеть, мы создаем объект cam = VideoCapture и с помощью функции cam.read читаем изображение. Оно уже хранится в памяти, нам не нужен промежуточный файл, и это большой плюс. В частности, его можно сохранить в папке, вызовом функции cv2.imwrite. Мы также можем сохранять не все изображения, а лишь в случае срабатывания внешнего триггера, например кнопки или реле.
Помимо простого сохранения файлов, OpenCV имеет огромные возможности по обработке изображений - поворот, кадрирование, ресайз и прочие операции могут быть легко реализованы.
Самостоятельная работа: сделать селфи-камеру на Raspberry Pi. Для этого добавить в вышеприведенный код чтения состояния кнопки, и писать изображение в файл только в том случае, если кнопка нажата.
4.15. Запускаем сервер видеотрансляции
Мы уже транслировали фото с вебкамеры через веб-сервер. Осталось сделать следующий шаг, и транслировать полноценное видео. Тем более, что для этого никаких программ писать не потребуется, достаточно лишь установить необходимые компоненты.
Введем команду: sudo apt-get install motion.
Откроем файл настроек, введем команду sudo nano /etc/motion/motion.conf.
Зададим следующие параметры:
daemon off
width 640
height 480
framerate 15
output_pictures off
ffmpeg_output_movies off
stream_port 8081
stream_quality 100
stream_localhost off
webcontrol_localhost off
Кстати, параметры output_pictures и ffmpeg_output_movies отвечают за сохранение изображений и видеороликов - программу motion также можно использовать как детектор движения. Файлы при этом будут складываться в папку /var/lib/motion. Нам эта функция не нужна, так что устанавливаем параметр output_pictures в off.
Наконец, введем команду sudo motion. Сервер работает - можно зайти в браузере на адрес http://192.168.0.104:8081 и увидеть изображение с камеры (из соображений приватности картинка не показана).

4.16 Отправляем данные через Dropbox
Мы уже рассматривали отправку данных из ESP32 в Dropbox в главе 3.13. Разумеется, то же самое можно сделать и на Raspberry Pi. Рассмотрим отправку обычного файла и текстовых данных в виде строки. Предварительно поставим библиотеки для Dropbox командой sudo apt-get install dropbox. Затем необходимо подключить приложение к Dropbox и получить ключ, как описано в главе 3.13.
Сам код весьма прост. В отличие от ESP32, здесь нам не нужно писать самостоятельно запросы к серверу, все уже реализовано в библиотеке.
import dropbox
import os
token = "V3z9NpYlRxEAAAAAAACHVdBdhVRCnXXXXXXXX"
dbx = dropbox.Dropbox(token)
# 1. Upload file "data1.txt" from the current folder
fullname = "data1.txt"
with open(fullname, 'rb') as f:
data = f.read()
try:
dbx.files_upload(data, "/" + fullname, dropbox.files.WriteMode.overwrite, mute=True)
except dropbox.exceptions.ApiError as err:
print 'Dropbox API error', err
# 2. Upload string as a file
try:
dbx.files_upload("1234567".encode(), "/data2.txt", dropbox.files.WriteMode.overwrite)
except dropbox.exceptions.ApiError as err:
print 'Dropbox API error', err
Отметим здесь 2 полезных параметра. WriteMode.overwrite указывает, что файл будет перезаписан, в противном случае мы получим ошибку, если файл был уже создан. Опциональный параметр mute=True указывает, что файл надо добавить “молча”, без уведомления пользователя (в противном случае на синхронизированном с Dropbox компьютере появляется всплывающее окно). Это бывает полезно, если файлы обновляются постоянно, например, картинка с камеры, которая сохраняется каждые 5 минут.
4.17 Распознавание лиц с помощью OpenCV
Вычислительная мощность Raspberry Pi весьма высока, и позволяет использовать довольно сложные алгоритмы, недоступные на Arduino или ESP32. Одна из таких задач - это обработка изображений. Мы уже умеем получать изображения с Web-камеры, добавим теперь возможность распознавания лиц. Это позволит к примеру, отправлять изображение с охранной камеры только тогда, когда на нем есть человеческое лицо, или сделать робота, который будет поворачиваться к стоящему перед ним человеку.
Разумеется, сама по себе задача распознавания лиц на изображении, весьма сложна, ее программирование требует весьма сложной математики. К счастью для нас, такие алгоритмы уже написаны, потребуется лишь использовать готовые библиотеки. Для обработки изображений мы будем использовать библиотеку OpenCV, чтобы поставить ее, предварительно введем команду sudo apt-get install libopencv-dev python-opencv.
Для начала, рассмотрим задачу распознавание лиц на уже готовом изображении. Для распознавания лиц используется так называемый классификатор Хаара, реализация которого уже есть в OpenCV.
import cv2
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
img = cv2.imread('faces.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
cv2.rectangle(img, (x,y), (x+w,y+h), (255,0,0), 2)
print " ", x,y, x+w,y+h
cv2.imwrite('faces_out.png', img)
Как можно видеть, код весьма прост. Мы создаем объект “CascadeClassifier”, в качестве параметра которого указываем файл 'haarcascade_frontalface_default.xml'. Этот файл хранит заранее обученный на большом числе изображений, набор данных, его необходимо взять из дистрибутива OpenCV и положить в папку с программой. Далее, исходное изображение “faces.png” переводится в черно-белое, а вызов метода detectMultiScale собственно и делает всю работу по распознаванию - на выходе мы получаем массив прямоугольников faces, с которым можем делать что угодно, например вывести на экран. Для удобства просмотра результатов мы также рисуем прямоугольник поверх исходной картинки с помощью метода cv2.rectangle. Итоговая картинка сохраняется под именем faces_out.png.
В качестве теста был взят обычный скриншот из браузера, результаты работы программы показаны на картинке:

Как можно видеть, алгоритм работает вполне неплохо. В окне вывода мы также получаем координаты прямоугольников:
1092 256 1187 351
853 223 1024 394
30 255 236 461
579 231 791 443
298 238 515 455
Самостоятельная работа: добавить распознавание лиц в код чтения изображения с веб-камеры из главы 4.14. Опционально, можно сделать анализ координат полученного прямоугольника, что позволит определить, находится человек слева или справа от камеры.
На этом мы закончим изучение Raspberry Pi, хотя по сути, это только начало. На этой платформе можно сделать много чего интересного, по мере появления нового материала главы будут дополняться.
А сейчас мы перейдем к изучению платы для самых маленьких - микрокомпьютера BBC:Micro.
Часть 5. BBC Micro:bit - электроника для самых маленьких
5.1 Введение
Компьютеры BBC Micro имеют давную историю. Еще в 80х британская компания BBC запустила обучающий проект, целью которого было повышение уровня компьютерной грамотности. Компьютер по тем временам был действительно “микро”, и выглядел примерно так:

С тех пор прошло около 30 лет, и на свет появилась новая “модификация” на современной элементной базе - BBC Micro:bit.

Плата предназначена для обучения младших школьников программированию, причем всем школьникам Великобритании она поставляется … бесплатно. Цель устройства - в простой и понятной форме показать как создавать программы, с уклоном именно в современную электронику и “интернет вещей”.
«На борту» BBC Micro:bit есть процессор ARM Cortex-M0, 256Кб Flash ROM, 16Kб RAM, 16МГц тактовая частота. Также есть поддержка BTLE, 2.4ГГц-трансмиттер для одноранговой связи (101 канал), акселерометр, компас, термометр, и линейка пинов GPIO, среди которых довольно много всего:

Также есть 2 кнопки для ввода (еще для ввода доступен жест «встряхивание»), светодиодная матрица 5x5, и 4 «крупных» пина, рассчитанных на то, чтобы ребенок прикрутил проводами или «крокодилами» что-нибудь несложное, например датчик влажности для цветка или переменный резистор.
Гребенка пинов сделана плоской, так что ее можно вставить в плату расширения (цена вопроса 10-15 Евро).

Есть разные платы расширения, например плата управления моторами, что позволяет сделать такого робота:
