камеры шаговым двигателем по TCP/IP сети с помощью Ардуино

advertisement
Позиционирование IP – камеры шаговым двигателем по TCP/IP
сети с помощью Ардуино. Элементы технологии «умный дом» по
сети Интернет
Практика для студентов. Мясищев А.А.
1. Постановка задач, которые должны выполняться устройством
2. Структура и настройка сети, в которой установлено устройство
3. Электронные блоки, составляющие устройство и схема их подключения
4. Программа, реализующая работу Web – сервера на Ардуино
5. Задание для самостоятельной работы
1. Постановка задач, которые должны выполняться устройством
Удаленное управление объектами можно осуществлять через сеть Интернет. Здесь
рассмотрим позиционирование IP – камеры с помощью шагового двигателя через TCP/IP
сеть. Управление шаговым двигателем выполняется с помощью микроконтроллера
ATmega1280, установленного на плате Arduino Mega и драйвера шагового двигателя Dual
Step Motor Driver shield на базе микросхемы A3967SLB. Шаговый двигатель используется
от 5-и дюймового накопителя на гибких магнитных дисках. Микроконтроллер к
компьютерной сети подключен с помощью Ethernet Shield W5100. На валу шагового
двигателя установлена IP – камера D-Link DCS-930. Камера вращается только в одной
(горизонтальной) плоскости. К микроконтроллеру подключены также подсветка для
работы камеры в темноте и датчик температуры для определения температуры в
помещении. Управление устройством выполняется удаленно через браузер. На рисунке 1
представлен web-интерфейс со стороны клиента.
Рис. 1. Web – интерфейс работы устройства
При однократном нажатии на кнопку управления двигателем выполняется поворот
IP камеры на 36 градусов влево или вправо в зависимости от нажатой кнопки. Пять
нажатий - поворот на 180 градусов в одну сторону(800 шагов). Шестое нажатие на ту же
кнопку вернет камеру в исходное состояние. Таким образом, камера должна обеспечить
обзор на 360 градусов (180 градусов в одну сторону и 180 в другую). Использование
сервопривода вместо шагового двигателя позволяет обеспечить обзор на 180 градусов.
Нажатие на клавишу «Включить» в области управления подсветкой – включает
светодиод, установленный на камере. Кнопка «Выключить, справка» - выключает
светодиод и высвечивает краткую справку по работе устройством. При нажатии на кнопку
«Температура» активизируется температурный датчик и высвечивается текущая
температура.
2. Структура и настройка сети, в которой установлено устройство
Управление устройством должно выполняться в сети, представленной на рисунке
2. Браузер на компьютере с адресом 172.10.60.159 для управления устройством должен
подключиться к нему по адресу 172.20.60.160. На маршрутизаторе 172.20.60.160 запущен
web –сервер с html страничкой (index_cam.htm):
<html>
<head>
<meta http-equiv=Content-Type content="text/html;charset=windows-1251">
<title>FRAME</title>
</head>
<frameset cols="25%,75%">
<frame src="http://172.20.60.160:8080">
<frame src="http://172.20.60.160:8081/jview.htm">
</frameset>
</html>
После подключения на окне браузера появиться два фрейма – в первом web – страничка
микроконтроллера, во втором – ip - камеры. Router должен будет выполнить «проброс
портов», т.е. передать управление при подключении по адресу 172.20.60.160 с портами
8080 и 8081 микроконтроллеру с адресом 192.168.1.10 и портом 8080 и ip – камере с
адресом 192.168.1.20 и портом 8081. В работе использован WiFi маршрутизатор TP-LINK
TL-MR3420, в котором вместо заводской прошивки установлена прошивка OpenWRT на
внешнюю USB флеш память.
Рис.2. Схема сети
Для «проброса портов» необходимо отредактировать в OpenWRT
/etc/config/firewall таким образом, чтобы туда были добавлены команды:
config zone
option name 'lan'
option network 'lan'
файл
option input 'ACCEPT'
option forward 'REJECT'
option output 'ACCEPT'
option masq '1'
config zone
option name 'wan'
option network 'wan'
option output 'ACCEPT'
option forward 'REJECT'
option masq '1'
option input 'ACCEPT'
# Запуск NAT и проброс порта 8080 на ip 192.168.1.10
config redirect
option target 'DNAT'
option src 'wan'
option dest 'lan'
option proto 'tcp udp'
option src_dport '8080'
option dest_ip '192.168.1.10'
option dest_port '8080'
option name 'Forward'
# Запуск NAT и проброс порта 8081 на ip 192.168.1.20
config redirect
option target 'DNAT'
option src 'wan'
option dest 'lan'
option proto 'tcp udp'
option src_dport '8081'
option dest_ip '192.168.1.20'
option dest_port '8081'
option name 'Forward8081'
config forwarding
option dest 'lan'
option src 'wan'
config forwarding
option dest 'wan'
option src 'lan'
В файле /etc/config/network должны быть команды:
config interface 'lan'
option ifname 'eth0'
option type 'bridge'
option proto 'static'
option ipaddr '192.168.1.101'
option netmask '255.255.255.0'
config interface 'wan'
option ifname 'eth1'
option proto 'static'
option ipaddr '172.20.60.160'
option netmask '255.255.0.0'
А в файле /etc/config/wireless - команды:
config wifi-iface
option device 'radio0'
option network 'lan'
# Раздача WiFi идет с интерфейса lan
option mode 'ap'
option ssid 'OpenWrt'
# OpenWrt - Имя точки доступа
option encryption 'none'
option macfilter 'allow' # Включена фильтрация по MAC - адресам
list maclist 'f0:7d:68:07:1c:0b' # MAC – адрес ip - камеры
list maclist '74:2f:68:a6:0f:4e'
Для работы web – сервера на маршрутизаторе выполняем следующие действия.
Создаем каталог /www/home, где будут находиться документы web - сервера:
mkdir /www/home
и делаем изменения в файле /etc/uhttpd.
Редактируем строку
option home
/www
на
option home
/www/home
Далее перегружаем web сервер:
/etc/init.d/uhttpd restart
После этого при обращении к серверу по адресу
http://172.20.60.160
будет загружаться страничка, находящаяся в файле /www/home/index.html или
/www/home/index.htm.
Ip – камера должна быть настроена на работу по WiFi как показано на рисунке 3.
Рис.3. Настойка Ip – камеры для работы с WiFi
3. Электронные блоки, составляющие устройство и схема их подключения
Устройство управления основано на аппаратной вычислительной платформе
Arduino, основными компонентами которой являются простая плата ввода/вывода и среда
разработки на языке Processing/Wiring. Используемая здесь плата Arduino Mega и ее схема
(по ссылке) представлены на рисунке 4.
Рис.4. Фото Arduino Mega (схема)
Arduino Mega построена на микроконтроллере ATmega1280. Платформа содержит
54 цифровых входа/выходов (14 из которых могут использоваться как выходы ШИМ), 16
аналоговых входов,4 последовательных порта UART, кварцевый генератор 16 МГц,
разъем USB, силовой разъем(питание), разъем ICSP(шина SPI, RESET, питание) и кнопку
перезагрузки.
Краткие характеристи Arduino Mega
Микроконтроллер
ATmega1280
Рабочее напряжение
5В
Входное напряжение
7-12В
(рекомендуемое)
Входное напряжение (предельное) 6-20В
54 (14 из которых могут использоваться как выходы
Цифровые Входы/Выходы
ШИМ)
Аналоговые входы
16
Постоянный ток через
40 mA
вход/выход
Постоянный ток для вывода 3.3 В 50 mA
Флеш-память
128 KB (4 используются для загрузчика)
ОЗУ
8 KB
Энергонезависимая память
4 KB
Тактовая частота
16 MHz
Для работы в сети плата Arduino Mega по шине SPI подключается к плате Ethernet
Shield W5100, фото и схема которой представлены на рисунке 5.
Рис.5. Фото Ethernet Shield W5100 (схема)
Плата устанавливается с помощью разъемов на контроллере Arduino Mega. Она
основана на Ethernet – микросхеме фирмы Wiznet W5100, поддерживающая стеки TCP/IP
и UDP в IP-сети. Микросхема поддерживает до четырёх одновременных подключений к
сокетам. Для создания программ, которые подключают Arduino к сети, используется
библиотека Ethernet. Данная плата соединяется с Arduino при помощи длинных штырьков.
Это позволяет не изменять расположение выводов и устанавливать другие платы поверх
неё. Плата Ethernet Shield имеет стандартный разъём RJ-45 для подключения к кабелю
«витая пара».
Управление шаговыми двигателем в этой работе выполняется с помощью платы
Dual Step Motor Driver shield, на которой установлены две микросхемы A3967SLB,
которые могут управлять двумя двигателями независимо. На рисунке 6 представлены
расположение разъемов и электронных компонентов платы, а по ссылке - схема этой
платы. Плата в устройстве установлена не поверх Ethernet Shield W5100, а отдельно для
развязки силовой части от микроконтроллеров ATmega1280 и W5100 по питанию.
Рис. 6. Схема расположения элементов на плате (схема).
На плате для подключения одного шагового двигателя используются разъемы
YDIR – направление вращения, YStep – шаг, Y01A и Y01B - 1-я обмотка шагового
двигателя, Y02A и Y02B - вторая обмотка. Для питания микросхем подается напряжение
5В. Для питания силового выхода микросхем и обмоток двигателей – напряжение до 30В
через разъем Power supply socket.
На рисунке 7 представлена схема подключения рассмотренных выше модулей и
шагового двигателя.
Рис. 7. Схема подключения модулей и шагового двигателя
4. Программа, реализующая работу web – сервера на Ардуино
Среда разработки программ для Ардуино - это приложение на Java, включающее в
себя редактор кода, компилятор и модуль передачи прошивки в плату. Разработка
прошивок производится на специально созданном языке программирования (проект
Wiring), который напоминает Си/Си++ и, вследствие относительной простоты и наличия
большого количества библиотек, позволяет быстро создавать программы для
микроконтроллеров даже непрофессиональным программистам.
Программа с подробными описаниями, реализующая работу устройства в качестве
управляющего Web – сервера, представлена ниже.
#include <SPI.h>
//Подключаем описание библиотеки шины SPI
#include <Ethernet.h>
//Подключаем описание библиотеки Ethernet
#include <OneWire.h>
//Подключаем описание библиотеки шины OneWire
#include <DallasTemperature.h>
//Подключаем описание библиотеки для
температуры(DS18B20)
#define FORM "<FORM action=\"\" >"
#define ONE_WIRE_BUS 3
OneWire oneWire(ONE_WIRE_BUS); //Настройка шины для работы с 3-м выводом
Ардуино
DallasTemperature sensors(&oneWire); //Подключаем датчик температуры
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //Задаем MAC - адрес
IPAddress ip(192,168,1,10); //Задаем ip - адрес
IPAddress gateway(192,168,1,1); //Задаем шлюз
IPAddress subnet(255,255,255,0); //Устанавливаем маску сети
EthernetServer server(8080); //Создаем сервер, который слушает порт 8080
int dirPin = 7; //Задаем, что 7-й вывод будет работать на направление вращения двигателя
int stepperPin = 6; //Задаем, что 6-й вывод формирует шаг для двигателя
int ii=0;
int kk=0;
int pos1=0;
int pos2=0;
int freeRam () { //Функция определения свободной памяти SRAM (для отладки программы)
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
void step(boolean dir,int steps){ //Функция работы с шаговым двигателем
digitalWrite(dirPin,dir);
//boolean – направление вращения, steps – число шагов
delay(10);
for(int i=0;i<steps;i++){
digitalWrite(stepperPin, HIGH); //Запись высокого уровня в вывод 6 Ардуино
delayMicroseconds(4000); // 4000 – микросекунд, используется для формирования шага
digitalWrite(stepperPin, LOW);
delayMicroseconds(4000);
}
}
void setup()
{
sensors.begin();//Инициализация датчика температуры DS18B20
pinMode(dirPin, OUTPUT); //Установка вывода Ардуина для работы на выход
pinMode(stepperPin, OUTPUT);
pinMode(5, OUTPUT); //Установка вывода на выход, на котором подключена подсветка
камеры
Serial.begin(9600); //Инициализация UART (установка скорости 9600)
Ethernet.begin(mac, ip, gateway, subnet); //Инициализация Ethernet модуля
server.begin(); //Инициализация сервера – начинает ожидать соединения на порту 8080
Serial.print("server is at "); Serial.println(Ethernet.localIP());//Распечатка на UART
локального адреса устройства
}
void loop() { //Основной цикл
EthernetClient client = server.available(); //Ожидание подключения клиентов
if (client) // Если client=1, то есть подключение к серверу
{
Serial.println("new client"); //Выводим на консоль, что есть новый клиент
//Согласно протоколу HTTP клиент
// шлет серверу довольно сложный запрос (см. пример заголовков).
// Запрос заканчивается пустой строкой, т.е.
// получением символа '\n', перед которым тоже были получены '\r' и '\n'.
// Согласно описанию HTTP после каждой строки заголовка следуют символы '\r' и '\n'.
// currentLineIsBlank - это переменная-флаг. Она равна true, если
// вновь полученная от клиента строка пустая, т.е. в полученных данных
// не встретилось символов отличных от '\n' и '\r'.
// Будем выставлять переменную currentLineIsBlank в false при
// получении любого отличного от '\r' и '\n' символа.
// Однако, первоночально currentLineIsBlank = true
boolean currentLineIsBlank = true;
byte k=0;
String buffer = "";
while (client.connected()) // Если в буфере есть несчитанные данные, то
client.connected()=1
{
if (client.available()) // В client.available() хранится количество полученных символов от
клиента,
// когда тот послал заголовок. Следующая команда считывает посимвольно
данные от клиента.
// Только в этом случае client.available() уменьшается до нуля. Если команды
// c = client.read() нет, то значение client.available() не меняется!
{
char c = client.read();
Serial.write(c); //Посимвольная распечатка на консоль(UART)
if(k==0) buffer+=c; // Переменная buffer заполняется только в случае чтения первой
строки заголовка клиента
if (c == '\n' && currentLineIsBlank) // Если получен перевод строки ('\n') и
currentLineIsBlank == true,
// значит получена пустая строка, т.е. запрос клиента окончен –
// можно слать ответ (ответ сервера)
{
// Шлем стандартный HTTP заголовок:
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html; charset=utf-8");
client.println(); //Заголовок должен заканчивается пустой строкой!
if(kk==0){ // Если выполнено первое подключение к серверу или нажата кнопка
«Выключить, справка»,
// распечатывается краткая справка управления позиционированием камеры
client.print("Устройство управляет шаговым<BR>");
client.print("двигателем IP камеры, включает<BR>");
client.print("и выключает подсветку для каме-<BR>");
client.print("ры, определяет температуру в <BR>");
client.print("помещении. При однократном на-<BR>");
client.print("жатии на кнопку управления дви-<BR>");
client.print("гателем выполняется поворот IP <BR>");
client.print("камеры на 36 градусов влево или <BR>");
client.print("вправо в зависимости от нажатой <BR>");
client.print("кнопки. Пять нажатий - поворот <BR>");
client.print("на 180 градусов в одну сторону<BR>");
client.print("(800 шагов). Шестое нажатие на <BR>");
client.print("ту же кнопку вернет камеру в ис-<BR>");
client.print("ходное соcтояние.<BR>");
client.print("<hr>");
// Формирование формы «Перейти к командам»
client.print(FORM);
client.print("<INPUT type=\"HIDDEN\" name=\"h\" value=\"1\" size=2>");
client.print("<INPUT type=\"submit\" value=\"Перейти к командам\"> </FORM>");
}
if(kk==0) goto labl;
// Если подключение к серверу не первое или нажата кнопка «Перейти к командам»,
//распечатываются кнопки управления устройством
// Формирование формы «Управление двигателем»
client.print("Управление двигателем<BR>");
client.print("IP камеры:<BR>");
client.print(FORM);
client.print("<INPUT type=\"HIDDEN\" name=\"s\" value=\"0\" size=2>");
client.print("<INPUT type=\"submit\" value=\"Влево\"> </FORM>");
client.print("Число шагов вправо:");client.print(pos1);
client.print(FORM);
client.print("<INPUT type=\"HIDDEN\" name=\"s\" value=\"1\" size=2>");
client.print("<INPUT type=\"submit\" value=\"Вправо\"> </FORM>");
client.print("Число шагов влево:");client.print(pos2);
client.print("<hr>");
// Формирование формы «Управление подсветкой»
client.print("Управление подсветкой:<BR>");
client.print(FORM);
client.print("<INPUT type=\"HIDDEN\" name=\"l\" value=\"0\" size=2>");
client.print("<INPUT type=\"submit\" value=\"Выключить, справка\"> </FORM>");
client.print(FORM);
client.print("<INPUT type=\"HIDDEN\" name=\"l\" value=\"1\" size=2>");
client.print("<INPUT type=\"submit\" value=\"Включить\"> </FORM>");
if (digitalRead(5)){
client.print("Подсветка включена");client.print("<hr>");
}else{
client.print("Подсветка выключена");client.print("<hr>");
}
// Формирование формы «Температура»
client.print("Температура:<BR>");
client.print(FORM);
client.print("<INPUT type=\"HIDDEN\" name=\"t\" value=\"1\" size=2>");
client.print("<INPUT type=\"submit\" value=\"Температура\"> </FORM>");
client.print("Температура= "); // Распечатка температуры
client.print(sensors.getTempCByIndex(0));client.print(" град.<BR>");
labl:
// После передачи данных сервером можно выходить из цикла while и разрывать
// соединение с клиентом (по команде client.stop())
break;
}
if (c == '\n') {// Если получен второй раз символ перевода строки, значит началась
новая
// строка. Выставляем флаг currentLineIsBlank = true
currentLineIsBlank = true;
buffer=""; // После каждого перехода к новой строке обнуляем строковую
переменную buffer.
}
else if (c == '\r') { // Если получен символ '\r' (сразу за ним будет идти символ '\n'),
// не дожидаясь перехода к новой строке, выполняем проверку условий:
if(buffer.indexOf("GET /")>=0) k=1; // Если это первая строка заголовка запроса,
устанавливаем k=1 для того,
// чтобы строковой переменной buffer не присваивать следующие строки заголовка.
// Выборка символов, соответствующих нажатой кнопке
if(buffer.indexOf("GET /?h=1")>=0) kk=1; // При нажатой кнопке «Перейти к
командам»
// будет распечатаны кнопки управления устройством
if(buffer.indexOf("GET /?s=0")>=0) // При нажатой кнопке «влево» один раз камера
// повернется на 160 шагов вращения двигателя влево
{ pos1=pos1+160; if(pos1<960) {step(true,160);} if(pos1>=960){step(false,pos1-160);
pos1=0;} }
if(buffer.indexOf("GET /?s=1")>=0) // При нажатой кнопке «вправо» один раз камера
// повернется на 160 шагов вращения двигателя вправо
{ pos2=pos2+160; if(pos2<960) {step(false,160);} if(pos2>=960){step(true,pos2-160);
pos2=0;} }
if(buffer.indexOf("GET /?l=0")>=0) // При нажатой кнопке «Выключить, справка»
будет выключена
//подсветка камеры и выполнен переход к справке
{ digitalWrite(5,LOW); kk=0; }
if(buffer.indexOf("GET /?l=1")>=0) // При нажатой кнопке «Включить» будет
включена
// подсветка камеры
{ digitalWrite(5,HIGH); }
if(buffer.indexOf("GET /?t=1")>=0) // При нажатой кнопке «Температура» будет снято
значение
// температуры с датчика DS18B20
{ sensors.requestTemperatures(); }
}
else {
currentLineIsBlank = false;
}
}
}
//Делаем паузу, чтобы данные ушли с сервера, распечатываем свободную память SRAM,
//печатаем, что клиент отсоединился, и разрываем соединение с клиентом
delay(1);
Serial.print("mem=");
Serial.println(freeRam());
client.stop();
Serial.println("client disonnected");
}
}
Пример заголовков, формируемых браузером (клиентом)
1. Первоначальное подключение к серверу по адресу hppt://192.168.1.10:8080
GET / HTTP/1.1
Host: 192.168.1.10:8080
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:25.0) Gecko/20100101 Firefox/25.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
2. Заголовок клиента, сформированный при нажатии на кнопку «Включить» при
управлении подсветкой
GET /?l=1 HTTP/1.1
Host: 192.168.1.10:8080
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:25.0) Gecko/20100101 Firefox/25.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://192.168.1.10:8080/?h=1
Connection: keep-alive
Для второго заголовка во второй строке GET /?l=1 HTTP/1.1 появились символы /?l=1
На рисунке 8 представлено фото устройства.
Рис.8. Фото устройства
5. Задание для самостоятельной работы
1. Изменить программу так чтобы поворот камеры при однократном нажатии на кнопку
был равен 18 градусам. Обзор камеры соответствовал 360 градусам.
2. Законспектировать материал и уметь отвечать на вопросы.
3. Размесить законспектированный материал на web – сервере под своим логином.
4. Факультативное задание. Изменить программу и схему подключения модулей так,
чтобы камера вращалась в двух плоскостях. Обзор должен быть 360 на 72 градуса. Шаг
поворота – 18 градусов.
Download