Łączenie Arduino z OpenWrt

Od jakiegoś czasu „bawię się” Arduino, a swoje doświadczenia staram się tu opisywać. Pisałem też kiedyś o mojej koncepcji inteligentnego domu (lub jak kto woli domowej automatyki) w oparciu o OpenWRT. Do rozpoczęcia przygody z Arduino skłoniła mnie właśnie chęć rozbudowy tego systemu.

OpenWRT zainstalowany w routerze jest świetny, elastyczny, linuksowy, jednak trochę brakuje mu możliwości z realnym światem. Problem w dużej części rozwiązał zakup karty przekaźnikowej wyposażonej dodatkowo w wejścia, jednak cały czas mi czegoś brakowało.

Oczywiście mogłem też pójść w kierunku wykorzystania portów GPIO w routerach, ale dla mnie to mało eleganckie rozwiązanie. Trzeba rozbierać router, lutować, itp. Zaletą jest niewątpliwie, że wszystko jest obsługiwane w jednym miejscu – w routerze. Ale co jeśli router się popsuje – trzeba kupić nowy i znowu kombinować z rozkręcaniem, lutowaniem. A co jeśli taki model nie będzie już dostępny? Poza tym linii GPIO zdatnych do użytku nie ma zwykle wiele i nie nadają się do niektórych zastosowań.

Dlatego zainteresowałem się Arduino. Jest standardowe – jak się uszkodzi, to kupię nowe (albo nawet wezmę z szuflady zapasowe), wgram program i podmienię to, które się zepsuło. Do tego daje mi sporą ilość wejść/wyjść cyfrowych i wejścia analogowe. Ponieważ jest programowalne i może działać autonomicznie – gdy restartuję router może nadal sterować automatyką, nie otrzymując tylko dodatkowych danych z routera. Jeżeli się okaże, że muszę zainstalować je trochę dalej od routera, to dołożę port ethernet i podłączę je w innym miejscu domu. Do tego nie będę musiał obciążać routera analizą danych wejściowych – przykładowo Arduino samo zliczy ilość zużywanego węgla i routerowi udostępni odpowiedni licznik. Router pobierze te dane, kiedy będzie potrzebował.

Trzeba jednak jakoś połączyć te dwa elementy. Najprostszym (i najtańszym) rozwiązaniem jest podłączenie Arduino do routera kablem USB. Dodatkowym plusem takiego rozwiązania jest fakt, że zasilanie będzie pobierane z routera (w moim przypadku aktywnego huba usb).

Po podłączeniu mojego Arduino Uno do routera TP-Link TL-WR1043ND z automatu w systemie nie pojawił się nowy port. Konieczne było doinstalowanie modułu kmod-usb-acm (przez okpg update, a następnie opkg install kmod-usb-acm). Gdy instalacja się zakończyła dmesg pokazało informację o nowym urządzeniu (/dev/ttyACM0):

usbcore: registered new interface driver cdc_acm
cdc_acm: v0.26:USB Abstract Control Model driver for USB modems and ISDN adapters
usb 1-1.4.4: new full speed USB device using ar71xx-ehci and address 7
usb 1-1.4.4: configuration #1 chosen from 1 choice
cdc_acm 1-1.4.4:1.0: ttyACM0: USB ACM device

Warto w tym miejscu zaznaczyć, że to działanie jest właściwe dla Arduino Uno. Wcześniejsze wersje płytki, z tego co wiem, posiadały na pokładzie chip FT232RL od FTDI, więc spodziewam się, że do ich obsługi właściwy będzie moduł kmod-usb-serial-ftdi, jednak tego nie miałem okazji przetestować. W Uno za obsługę USB odpowiada atmega8u2, dzięki czemu port stał się bardziej uniwersalny (umożliwia pracę w różnych trybach).

Gdy port jest już widoczny w Arduino, można się do niego łączyć. Nie miałoby to jednak żadnego sensu, gdyby w Arduino nie było programu, który podjąłby komunikację. Wgywamy więc wcześniej prosty program:

// progam zaczyna liczyć od zera w górę
// wynik wysyła przez port szeregowy

long counter=0;

void setup() {
  // inicjalizacja portu na starcie
  Serial.begin(9600);
}

void loop() {
  Serial.println(counter); // wypisujemy licznik i przechodzimy do nowej linii
  counter++; // zwiększamy licznik
  delay(500); // czekamy pół sekundy
}

Teraz już można się połączyć. Jak? Można to zrobić na różne sposoby, ja preferuję php z wykorzystaniem doświadczeń (i bibliotek) zdobytych przy okazji obsługi karty przekaźnikowej. Mój program w php łączący się z Arduino wygląda tak:

<?php
include "php_serial.class.php";

$port="/dev/ttyACM0";

$serial = new phpSerial;
$serial->deviceClose($port);
$serial->deviceSet($port);
$serial->confBaudRate(9600);
$serial->confParity(none); //Set the Parity
$serial->confCharacterLength(8);//Set the word length
$serial->confStopBits(1); //Set Stop Bit
$serial->confFlowControl(none);

if( !$serial->deviceOpen("a+b") ) { echo "Nie mozna otworzyc portu"; exit; }

while(1)
{
$read = $serial->readPort();
echo $read;
sleep(1);
}

$serial->deviceClose();
?>

Po jego uruchomieniu (przez php-cli -f nazwapliku.php) na ekranie co sekundę pokazują się 2 liczby. Dlaczego co sekundę? Bo odczyty robimy w pętli co sekundę, a Arduino zwiększa licznik co pół sekundy. Co charakterystyczne po uruchomieniu programu licznik zawsze zaczyna od zera. Dlaczego? Bo Arduino Uno przy każdym przychodzącym połączeniu szeregowym resetuje się i oczekuje na program. Funkcjonalność ma ułatwić obsługę, żeby za każdym programowaniem nie było potrzeby wciskania przycisku „reset”. W moim przypadku jednak to przeszkadzało.

Jak wyłączyć auto-reset w Arduino Uno? Poza barbarzyńską metodą przecięcia jednej ze ścieżek na płytce, można podłączyć 10µF kondensator między złącza reset i masę. Jeżeli kondensator jest elektrolityczny (a jest), trzeba przy tym pamiętać, że ważna jest polaryzacja, więc do GND ma trafić nóżka oznaczona jako minus (zwykle białym paskiem na obudowie).


Po wykonaniu tej czynności, kolejne połączenia do Arduino nie powodują restartu urządzenia, dzięki czemu licznik zwiększa się nieprzerwanie. Testowo zostawiłem uruchomione Arduino na nieco ponad trzy tygodnie, łącząc się z nim od czasu do czasu w celu sprawdzenia stanu licznika. Nic nieprzewidzianego się nie wydarzyło, wszystko działało jak należy.

Na zakończenie dziękuję firmie Nettigo za bezpłatne udostępnienie urządzeń do testów.

Advertisements

7 Responses to Łączenie Arduino z OpenWrt

  1. fpaliuc says:

    Great trick for stopping the reset!!!

  2. fpaliuc says:

    Do you think PHP can be used to both read and write the Arduino?

    I’m thinking about something like displaying the status of the digital pins in a php webpage and also giving the possibility, in the same webpage (through a few submit buttons) to change the pin’s status.

  3. Paweł says:

    Również próbuję oprogramować Arduino i nie rozumiem jednej rzeczy podanej w Twoim przykładzie. Mianowicie wykonujesz po stronie PHP petlę while(1) – czyli do póki wartość równa się 1. Nie bardzo rozumiem tylko czego wartość ma wynosić 1?

    Przy takim rozwiązaniu jakie proponujesz otrzymuję błąd podczas wykonywania sktyptu CGI. Dostaję timeout.

  4. piernik says:

    Ostatnio też się trochę bawie arduino i ostatnio
    doszedłem do momentu w którym nie bardzo wiem co zrobić.
    Otóż posiadam router z wgranym openWrt, do routera poprzez USB podpięte jest Arduino UNO r3. Postawiłem na routerze serwer i wgrałem na niego stronkę. Chciałbym teraz oskryptować jeden przycisk aby po wciśnięciu wysyłał on „1” do arduino który jest podłączone przez USB do routera.
    Program który jest na arduino ma po odebraniu „1” zapalić diodę która jest na płytce.

    Po połączeniu się przez ssh i wejściem przez telnet na arduino wszystko działa i po wpisaniu „1” i akceptacji enterem zapala mi sie dioda. Ale jak to zrobić w phpie?
    Proszę o pomoc!

    Arduino jest zamontowane poleceniem:
    ser2net -C „3001:raw:600:/dev/usb/acm/0:9600 NONE 1STOPBIT 8DATABITS -XONXOFF -LOCAL -RTSCTS”

    na acm bo na tty nie było widziane …

    • darek says:

      Tez mam problemy z komunikacja openwrt – arduino.
      Owszem działa to pod php ale niestabilnie. Przynajmniej w moim przypadku, stawiam na biblioteke php że czegoś jej brakuje

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Log Out / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Log Out / Zmień )

Facebook photo

Komentujesz korzystając z konta Facebook. Log Out / Zmień )

Google+ photo

Komentujesz korzystając z konta Google+. Log Out / Zmień )

Connecting to %s

%d bloggers like this: