Подключение Ардуино к роутеру TL-MR3020
1
Удалённое управление Arduino через Web-интерфейс...
Предполагается, что на роутере установлена OpenWrt и система перенесена на флешку. Как это сделать я подробно описал здесь.
Если OpenWrt установлена, тогда переходим к основной задаче.
Существуют два способа подключения, первый — к UART роутера, второй — через USB.
Оба варианта работают одинаково, однако первый требует разбора роутера и подпаивания контактов:
Второй вариант проще, но придётся ипользовать usb-хаб.
Я опишу оба способа подключения и покажу как сделать простой веб-интерфейс для управления.
Кто будет подключать по usb, может сразу перейти сюда.
Вариант с UART
Вскрываем роутер. Крышка у него приклеена, поэтому берём что-то типа ножа и ковыряем по всему периметру. Пластик достаточно прочный, так что можно не боятся повредить.
Достаём плату и припаиваем три контакта RX, TX и GND, четвёртый контакт — это плюс (3,3V), он нам не нужен.
Теперь зальём в ардуину простенький скетч для проверки.
int led = 13;
void setup()
{
Serial.begin(57600);
pinMode(led, OUTPUT);
}
void loop()
{
if (Serial.available())
{
byte insim = Serial.read();
switch (insim)
{
case 'a':
digitalWrite(led, HIGH);
break;
case 'b':
digitalWrite(led, LOW);
break;
}
}
}
Будем посылать в ардуину символы a и b, в ответ на которые будет зажигаться и гаснуть D13.
Подключаем ардуину как на рисунке:
Ардуина TX ⇨ RX Роутера (синий)
Роутер TX ⇨ RX Ардуина (зелёный)
CND ⇨ CND
Не смотря на то, что чип роутера питается от 3,3V, а ардуина от 5V, никаких проблем не возникает, посему нет необходимости согласовывать уровни.
Подключаем сетевой кабель (или не подключаем если Вы соединяетесь по WIFI) и подаём питание на роутер и ардуину.
Заходим на роутер по ssh (на всякий случай)
Ради интереса смотрим существующие устройства:
ls /dev/tty*
В списке будет присутствовать ttyATH0, это и есть UART.
Обновляем репозиторий…
opkg update
Установим утилиту для настройки порта:
opkg install coreutils-stty
Настроим порт командой…
stty -F /dev/ttyATH0 cs8 57600 ignbrk -brkint -icrnl -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts -hupcl
Проверяем…
echo 'a' > /dev/ttyATH0
D13 загорелась.
echo 'b' > /dev/ttyATH0
D13 погасла.
Должно работать, если нет, то возвращаемся и проверяем что не так.
Доведём до ума:
Если у Вас не установлен редактор nano, то исправим ситуацию...
opkg install nano
Добавим в автозагрузку настройку порта:
nano /etc/rc.local
В конец файла (перед exit 0) добавим строчку:
stty -F /dev/ttyATH0 cs8 57600 ignbrk -brkint -icrnl -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts -hupcl
подсказка nano
Сохранить______Выйти
Сохранить______Выйти
Перегружаем роутер и проверяем…
reboot
echo 'a' > /dev/ttyATH0
echo 'b' > /dev/ttyATH0
Поскольку при загрузке (да и в процессе работы) в консоль прилетают различные символы, нам надо их отфильтровывать, а также сделать обратную связь, чтоб в ответ на команду ардуина сообщала о выполнении.
Залейте в ардуину этот скетч: Не забывайте отсоединять провода RX,TX во время прошивки.
int led = 13;
byte descript[5];
void setup()
{
Serial.begin(57600);
pinMode(led, OUTPUT);
}
void loop()
{
if (Serial.available()>4) // ждём дескриптор и нужный символ
{
if (Serial.read()=='Y') // проверяем первый символ, если это 'Y', то продолжаем принимать, если нет, то выходим из цикла чтения
{
for (byte i=0; i < 5; i++)
{
descript[i] = Serial.read();
}
if((descript[0] =='+') && (descript[1] =='=') && (descript[2] =='Z'))
{
switch (descript[3])
{
case 'a':
digitalWrite(led, HIGH);
Serial.println("OK vkl"); // ответ
break;
case 'b':
digitalWrite(led, LOW);
Serial.println("OK otkl"); // ответ
break;
}
}
else
{
for(byte i=0; i < 255; i++)
{
Serial.read();
}
}
}// конец if (Serial.read()=='Y')
} // конец чтение порта
}
Перед управляющим символом (a,b) будем отправлять четыре символа служащие дескриптором Y+=Z, благодоря этому всё что не нужно отфильтруется и не будет случайных срабатываний.
Открываем параллельно ещё одну ssh-сессию и вводим там команду:
cat /dev/ttyATH0
Здесь будет ответ ардуины.
Проверяем...
echo 'Y+=Za' > /dev/ttyATH0
echo 'Y+=Zb' > /dev/ttyATH0
И последнее, надо отвязать UART от отладочной консоли. Для этого надо в файле /etc/inittab закомментировать последнюю строчку:
nano /etc/inittab
Вот так:
::sysinit:/etc/init.d/rcS S boot
::shutdown:/etc/init.d/rcS K shutdown
#ttyATH0::askfirst:/bin/ash --login
Сохраняем, перегружаем.
Если что-то не работает, то возвращаемся к началу и проверяем что сделали не так.
С первым вариантом покончено, если подключение по usb не интересно, то переходите ниже...
Вариант с USB
Зальём в ардуину проверочный скетч:
int led = 13;
void setup()
{
Serial.begin(57600);
pinMode(led, OUTPUT);
}
void loop()
{
if (Serial.available())
{
byte insim = Serial.read();
switch (insim)
{
case 'a':
digitalWrite(led, HIGH);
break;
case 'b':
digitalWrite(led, LOW);
break;
}
}
}
Будем посылать в ардуину символы a и b в ответ на которые будет зажигаться и гаснуть D13.
Подключаем к роутеру хаб и втыкаем в него флешку и ардуину. Включаем.
Желательно чтобы хаб был с отдельным питанием. Некоторые хабы работают некорректно.
Заходим на роутер по ssh (на всякий случай)
Обновляем репозиторий…
opkg update
Установим драйвера для всех существующих ардуин и утилиту для настройки порта stty:
opkg install kmod-usb-serial-ftdi kmod-usb-acm kmod-usb-serial-pl2303 kmod-usb-serial-cp210x libftdi coreutils-stty
reboot
Можно не перегружать, по идее устройство должно появиться сразу.
Проверим… если нет, тогда перегрузите.
ls /dev/tty*
У Вас может быть /dev/ttyACM0, тогда его и используйте в дальнейших командах и настройках.
Настроим порт командой…
stty -F /dev/ttyUSB0 cs8 57600 ignbrk -brkint -icrnl -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts -hupcl
Проверяем…
echo 'a' > /dev/ttyUSB0
D13 загорелась.
echo 'b' > /dev/ttyUSB0
D13 погасла.
Если при посылке пакета ардуина перегружается (диоды моргают, но D13 не горит), тогда нужно поставить электролитический косденсатор 5-10мкФ между Reset и GND.
Не забудьте отключать его когда заливаете скетч.
Далее сделаем защиту от случайных срабатываний и обратную связь, чтоб в ответ на команду ардуина сообщала о выполнении.
Если редактор nano отсутствует, то установим...
opkg install nano
Добавим в автозагрузку настройку порта:
nano /etc/rc.local
В конец файла (перед exit 0) добавим строчку:
stty -F /dev/ttyUSB0 cs8 57600 ignbrk -brkint -icrnl -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts -hupcl
подсказка nano
Сохранить______Выйти
Сохранить______Выйти
Перегружаем…
reboot
… и проверяем…
echo 'a' > /dev/ttyUSB0
echo 'b' > /dev/ttyUSB0
Теперь выключаем роутер и прошиваем в ардуину этот скетч:
int led = 13;
byte descript[5];
void setup()
{
Serial.begin(57600);
pinMode(led, OUTPUT);
}
void loop()
{
if (Serial.available()>4) // ждём дескриптор и нужный символ
{
if (Serial.read()=='Y') // проверяем первый символ, если это 'Y', то продолжаем принимать, если нет, то выходим из цикла чтения
{
for (byte i=0; i < 5; i++)
{
descript[i] = Serial.read();
}
if((descript[0] =='+') && (descript[1] =='=') && (descript[2] =='Z'))
{
switch (descript[3])
{
case 'a':
digitalWrite(led, HIGH);
Serial.println("OK vkl"); // ответ
break;
case 'b':
digitalWrite(led, LOW);
Serial.println("OK otkl"); // ответ
break;
}
}
else
{
for(byte i=0; i < 255; i++)
{
Serial.read();
}
}
}// конец if (Serial.read()=='Y')
} // конец чтение порта
}
Перед управляющим символом (a,b) будем отправлять четыре символа служащие дескриптором Y+=Z, таким образом отфильтруется случайный мусор и не будет случайных срабатываний.
После обработки команды, ардуина будет отправлять ответ.
Возвращаем ардуину в хаб и включаем роутер.
Открываем две параллельные ssh-сессии, в первой водим команду:
cat /dev/ttyUSB0
Здесь будет ответ ардуины.
Во второй пробуем…
echo 'Y+=Za' > /dev/ttyUSB0
echo 'Y+=Zb' > /dev/ttyUSB0
Всё должно работать, если нет, то возвращаемся и внимательно проверяем.
Если всё получилось, то можно переходить к следующей части.
Интерфейс
Сделаем простой веб-интерфейс для управления двумя лампочками.
Выглядеть будет вот так… Можно понажимать.
Скачайте архив и распакуйте его в рабочую папку сервера, чтоб было так сервер/primer/.
Здесь подробная инструкция по установке сервера Lighttpd на OpenWrt.
Проверьте, чтоб в файле /etc/php.ini всё было так, как написано здесь!
Если Вы пользуете Win, то отключите всякие файрволы/антивирусы!
Установим и настроим небольшой прокси-сервер ser2net, он создаёт соединение между сокетом и устройством (/dev/ttyUSB0).
Как показала практика, через ser2net, php-файл работает лучше, нежели обращаясь к устройству напрямую.
opkg update
opkg install ser2net
Редактируем файл конфигурации:
nano /etc/ser2net.conf
Закомментируйте всё строчки в конце и сохраните.
Добавим ser2net в автозагрузку:
nano /etc/rc.local
Добавьте в конец файла вот эту строку:
ser2net -C "3002:raw:0:/dev/ttyUSB0:57600 NONE 1STOPBIT 8DATABITS -XONXOFF -LOCAL -RTSCTS"
Должно получится так:
stty -F /dev/ttyUSB0 cs8 57600 ignbrk -brkint -icrnl -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts -hupcl
ser2net -C "3002:raw:0:/dev/ttyUSB0:57600 NONE 1STOPBIT 8DATABITS -XONXOFF -LOCAL -RTSCTS"
exit 0
В примере используется устройство /dev/ttyUSB0, у Вас может быть другое! (ttyATH0 — консоль, ttyACM0 — мега)
Внимание! Строки инициализации должны быть записаны одной строкой (без переноса).
Прошейте в ардуину этот скетч:
int descript[5];
int R1 = 0; // флаг первой лампы D12
int R2 = 0; // флаг второй лампы D13
void setup()
{
Serial.begin(57600);
pinMode(12, OUTPUT);
pinMode(13, OUTPUT);
}
void loop()
{
if (Serial.available()>4) // ждём дескриптор и нужный символ
{
if (Serial.read()=='Y') // проверяем первый символ, если это 'Y', то продолжаем принимать, если нет, то выходим из цикла чтения
{
for (byte i=0; i < 5; i++)
{
descript[i] = Serial.read(); // добавляем символы в массив
}
if((descript[0] =='+') && (descript[1] =='=') && (descript[2] =='Z')) // проверяем символы
{
switch (descript[3])
{
case 'o': // обновление
glavnaia(); // отправка ответа
break;
case 'A':
digitalWrite(12, HIGH);
R1 = 1; // ставим флаг в единицу (вкл)
glavnaia();
break;
case 'a':
digitalWrite(12, LOW);
R1 = 0; // ставим флаг в ноль (откл)
glavnaia();
break;
case 'B':
digitalWrite(13, HIGH);
R2 = 1;
glavnaia();
break;
case 'b':
digitalWrite(13, LOW);
R2 = 0;
glavnaia();
break;
}
}
else
{
for(byte i=0; i < 255; i++)
{
Serial.read();
}
}
}// конец if (Serial.read()=='Y')
} // конец чтение порта
}
void glavnaia() // отправка ответа
{
Serial.print(R1); // отсылаем флаг
Serial.print(","); // запятая для парсинга строки
Serial.println(R2); // отсылаем флаг !!!последняя строчка должна быть println!!!
}
Добавлены функции для второй лампочки и обновления. (к D12 подключите светодиод через резистор 200-1000 Ом)
Включаем/перегружаем роутер и в браузере заходим по аресу ваш_роутер/primer/
Должно получится так:
Если надпись stD серая, это значит что связь с ардуиной установлена, если красная, то связи нет.
Работа заключается в следующем:
index.html раз в три секунды (интервал можно изменить) запрашивает данные у ардуины (отправляя ей символ о) с помощью функции ajax (ajax позволяет не перегружать страницу).
...
function show() /* функция обновления */
{
$.ajax({
type: "GET",
url: "box2.php?df=o",
timeout:400, /* если до роутера "длиные пинги" то этот параметр нужно увеличивать */
cache: false,
success: function(data)
{
var vars = data.split(","); /* разбор строки принятой от ардуино */
if(vars.length == dlina) /* проверка длины данных (количество блоков разделённых запятой) */
{
$('#std').html("<v2>stD</v2>"); /* если данные приняты правильно, то надпись stD будет серой */
/* lampR1 */
/* если принята единица, то рисуем жёлтую лампочку. Переменной присваевается символ, который будет отослан при следующем нажатии */
if(vars[0]==1) $('#lampR1').html('<img src="images/onlamp.png">'),(r1 = 'a');
/* если принят ноль, то рисуем серую лампочку. Переменной присваевается символ, который будет отослан при следующем нажатии */
else if(vars[0]==0) $('#lampR1').html('<img src="images/offlamp.png">'),(r1 = 'A');
/* lampR2 */
if(vars[1]==1) $('#lampR2').html('<img src="images/onlamp.png">'),(r2 = 'b');
else if(vars[1]==0) $('#lampR2').html('<img src="images/offlamp.png">'),(r2 = 'B');
}
else
{
$('#std').html("<v>stD</v>"); /* если данные приняты НЕправильно, то надпись stD будет красной */
}
}
});
}
$(document).ready(function()
{
show();
setInterval('show()',3000); /* частота обновления */
});
...
Запрос передаётся php-файлу (box2.php) находящемуся на сервере, который в свою очередь обращается к ардуине через сокет ser2net.
<?php
if($fp = fsockopen("localhost", 3002, $errno, $errstr, 1)) // открываем порт, в качестве посредника между роутером и ардуиной выступает ser2net
{
fwrite($fp, 'Y+=Z'); // отправляем в порт дескриптор Y+=Z
fwrite($fp, $_GET['df']); // отправляем в порт символ полученый от html странички
stream_set_timeout($fp, 0, 150000); // полезный таймаут, если ответа нет, то поток закроется через 150 мс
$bufft = fgets($fp); // получаем ответ от ардуины
fclose($fp); // закрываем порт
echo $bufft; // отправляем ответ клиенту
}
else
{
usleep(70000);
$fp = fsockopen("localhost", 3002, $errno, $errstr, 1);
fwrite($fp, 'Y+=Z');
fwrite($fp, $_GET['df']);
stream_set_timeout($fp, 0, 150000);
$bufft = fgets($fp);
fclose($fp);
echo $bufft;
}
?>
Ардуина получает команду, обрабатывает её и отправляет ответ, который по той же цепочке возвращается html-страничке (index.html).
...
switch (server[3]) // simvol
{
case 'o': // obnovlenie
glavnaia();
break;
...
void glavnaia() // отправка ответа
{
Serial.print(R1); // отсылаем флаг
Serial.print(","); // запятая для парсинга строки
Serial.println(R2); // отсылаем флаг !!!последняя строчка должна быть println!!!
}
Html-страничка разбирает ответ и выводит значения на экран.
...
success: function(data)
{
var vars = data.split(","); /* разбор строки принятой от ардуино */
if(vars.length == dlina) /* проверка длины данных (количество блоков разделённых запятой) */
{
$('#std').html("<v2>stD</v2>"); /* если данные приняты правильно, то надпись stD будет серой */
/* lampR1 */
/* если принята единица, то рисуем жёлтую лампочку. Переменной присваевается символ, который будет отослан при следующем нажатии */
if(vars[0]==1) $('#lampR1').html('<img src="images/onlamp.png">'),(r1 = 'a');
/* если принят ноль, то рисуем серую лампочку. Переменной присваевается символ, который будет отослан при следующем нажатии */
else if(vars[0]==0) $('#lampR1').html('<img src="images/offlamp.png">'),(r1 = 'A');
...
Если открыть ещё одну страничку (или зайти с другого устройства) и включить лампочку, то на первой страничке (в течении 3 сек.) тоже включится лампочка.
Для этого и нужно обновление.
Нажатие на лампочку работает так же как и «обновление», в ардуину отсылается символ включения или отключения (в зависимости от состояния лампочки), ардуина выполняет действие и посылает в ответ строку с флагами состояния (единица или ноль). Ответ разбирается в html-странице и в зависимости от флагов выводит картинку включённой или отключённой лампочки.
Для лучшего понимания откройте файл index.html из архива, и посмотрите комментарии.
Внимание! Если Вы редактируете файл на роутере, то удалите все комментарии, в противном случае могут возникнуть проблемы с русской кодировкой.
Если редактируете файлы на виндовс-машине, то пользуйтесь редактором Notepad++.
Если что-то не так, то возвращаемся и проверяем всё с удвоенным вниманием. Проверяем права на файлы, правильность путей и устройств.
В следующей части — «умный дом» на основе ардуино.
Вот тут можно скачать библиотеку для разгона Arduino.
Телеграм-чат istarik
- +888
- stD
55552
Поддержать автора
Комментарии (45)
ls /dev/tty*
/dev/tty /dev/ttyS10 /dev/ttyS13 /dev/ttyS2 /dev/ttyS5 /dev/ttyS8
/dev/ttyS0 /dev/ttyS11 /dev/ttyS14 /dev/ttyS3 /dev/ttyS6 /dev/ttyS9
/dev/ttyS1 /dev/ttyS12 /dev/ttyS15 /dev/ttyS4 /dev/ttyS7
PS. Роутер у меня TP-Link TL-WR842ND с OpenWrt AA 12.09 на борту.
Дайте вот такую команду
И выложете сюда вывод.
Но на ttyS0 тишина…
istarik.ru/uploads/images/00/00/01/2015/04/24/93ab06.png
Замкните на ардуине RST и GND, включите её в компьютер, откройте Serial Monitor (115200) и перегрузите роутер. Вы должны увидеть лог загрузки. Если его нет, поменяйте местами rx-tx.
Не могу понять, для чего в PHP скрипте используется условный оператор, который в обоих случаях делает то же самое, но только во втором с задержкой. Для чего?
Задержка сделана на тот случай, если в данный момент сокет занят другим клиентом.
…
Я Вам рекомендую попробовать вот это, без пхп.
После того как светодиод начал быстро моргать, выполнил команду mount_rootЮ а затем mtd -r erase rootfs_data. Что при этом восстанавливается? по крайней мере доступ по 192.168.0.254 не восстановился.
root@OpenWrt:~# opkg update
Downloading istarik.ru/packages/mr3020/packages//Packages.gz.
wget: bad address 'istarik.ru'
Collected errors:
* opkg_download: Failed to download istarik.ru/packages/mr3020/packages//Packages.gz, wget returned 1.
в чем дело?
внутри написано
src/gz attitude_adjustment istarik.ru/packages/mr3020/packages/
dest root /
dest ram /tmp
lists_dir ext /var/opkg-lists
option overlay_root /overlay
дошел до управления через веб. при этом на нажатия ws ad робот не реагирует… я думаю проблема в связи- юарт роутера-ардуино…
вот хотел проверить вашим простым примером… а тут оказывается столько всего надо сделать…
поэтому вопрос непонятно почему автор ничего такого не делал, а у него все работает…
… и то, что написано у меня.
…
Впрочем это не важно, у Вас другая прошивка и часть программ не установятся, тем более ядерные модули.
если все сделаю по вашей инструкции и с вашей прошивкой может будет работать?
Делаю всё по инструкции для usb.
После загрузки ардуины первой тестовой программой подключаю её к роутеру через активный usb-хаб
ввожу в консоль:
echo 'a' > /dev/ttyUSB0
или
echo 'b' > /dev/ttyUSB0
И на любую из этих команд ардуина реагирует сиюсекундным разовым морганием светодиода, после чего светодиод погасает.
Что можно попробовать сделать? Очень хочется разобраться. Спасибо заранее =)
Происходит это, потому-что давая команду echo 'a' > /dev/ttyUSB0 открывается устройство и ардуина перегружается (как при подключении к компьютеру). Эта проблема решалась командой stty -F /dev/ttyUSB0 cs8 57600 ... с соответствующими параметрами, но она не работает с ардуинами, у которых в качестве usb-моста используется микросхема ch34x (которая у вас скорее всего стоит).
Спасибо.