ESP8266 robi zdjęcia – ArduCam na ESP8266

ESP8266 z ArduCam
ESP8266 z ArduCam

ArduCam Mini jest dość niszowym produktem. Mała kamerka która możesz podłączyć do Arduino lub ESP8266. Dlaczego to jest możliwe? Otóż ArduCam to nie tylko układ optyczny i przetwornik. To również dedykowany układ CPLD, który zajmuje się obróbką obrazu. Dzięki temu nawet Arduino może przez SPI i I2C odebrać dane z kamery. Przetworzyć to już pewnie nie da rady, ale na kartę SD to może zapisać. ESP8266 ma nieco większe możliwości.

Gdy wpadł nam w ręce testowy układ ArduCam Mini 2 MP postanowiłem  przetestować kamerę – podłączając ją do ESP8266 i udostępniając obraz przez WWW. Dla jasności – ESP ma nieco większe możliwości niż Arduino, ale nadal za wolne i za mało pamięci by robić jakiś zaawansowany streaming. Dlatego tylko kilka zdjęć na sekundę (jeżeli będzie rozdzielczość mała).

Cały proces nie jest skomplikowany – jak już się dojdzie do finału. Ja, niestety wpadłem w dwie pułapki, które mnie kosztowały stracony czas, ale w końcu po to piszę, byście Wy mogli uniknąć takiego losu.

Nim jednak ruszymy, przyda się płytka deweloperska dla ESP. Ja wyrwałem ja z projektu, który powstał w ramach cyklu ESP8266 i IoT (to nie koniec do niego jeszcze wrócę, tylko skończmy z tą kamerą). Warto sobie taką zbudować (koszt 9-13 zł w zależności ile części typu złącza masz na stanie). Jak ją zrobić – to było opisane w części trzeciej przewodnika ESP8266 i IoT. Tam też lista elementów.

Nim zaczniemy coś programować, musimy przygotować Arduino IDE do pracy z ESP8266. Jeśli już masz to gotowe, do ściągnij i zainstaluj trzy biblioteki: ArduCAM, ESP8266_websocket oraz UTFT4ArduCAM_SPI (co za nazwa…). Możesz te biblioteki zainstalować przez manager (Sketch/Include Library/Library Manager) ale… ja osobiście nie przepadam, zainstalowałem ręcznie.

ESP8266-12 Arduino pinout
ESP8266-12 Arduino pinout

Ok, sprzęt gotowy, to zaczynamy podpinać. I tu pierwszy wilczy dół, w który wpadłem. Otóż chyba wszystkie diagramy (łącznie z oficjalną dokumentacją) wskazują pin CS/SS na GPIO15 na płytce. Przykład, który jest dołączony również w komentarzu mówi o GPIO15, choć w kodzie był 16. Dlatego, zmieniłem w kodzie GPIO na 15 i do podłączania. Po wpięciu kabelków do SPI zdziwienie – ESP2866 zaczęło zachowywać się co najmniej dziwnie.

Wgranie programu jeszcze się udało, ale potem zwis totalny, zazwyczaj reset nawet nie pomagał, trzeba było wyłączać układ. I tutaj nakłada się druga historia, w tym samym czasie robię testy innych urządzeń z ESP8266. One też korzystają z SPI i tam były pewne problemy ze stabilnością. Dlatego, pierwsze podejrzenia poszły w kierunku podobnych problemów z SPI – oscyloskop i szukanie sygnałów. Jednak w miarę szybko okazało się, że odpięcie właśnie CS przywracało po resecie ESP8266 do życia. W końcu – zmieniłem CS na pin GPIO16 i ESP zaczęło normalnie funkcjonować.

Sęk w tym, że tak się na SPI zafiksowałem, że wpadłem w drugi „wilczy dół” :) Wstyd się przyznać, ale ArduCam potrzebuje zarówno SPI jak I2C jednocześnie, a jak się okazało nie było dla mnie to dostatecznie dużymi literami napisane. Co z tego, że wszystkie schematy mówią wyraźnie, że SDA/SCL też trzeba podłączyć, gdzieś się zapisało w głowie że albo SPI albo I2C. Prawda jest taka, że po SPI jest dostęp do CPLD Altery, który dokonuje obróbki danych z czujnika kamery. Sam czujnik kamery jest dostępny po I2C i potrzeba obu by całość mogła być sterowana.

Czyli, niezależnie od doświadczenia, zawsze można zrobić głupi błąd :) który kosztować będzie Was trochę straconego czasu. Jeśli coś nie działa zupełnie (a powinno), to warto zostawić na chwilę wszystko i z otwartym umysłem podejść jeszcze raz do tematu, ale zweryfikować wszystkie swoje wstępne założenia.

Jak już CS został zmieniony na GPIO16 a piny SDA/SCL zostały podłączone (GPIO4 i GPIO5 – uwaga sprawdź dobrze, niektóre moduły ESP8266-07 i -12 miały zamienione te dwa wyprowadzenia), to wszystko zaczęło działać jak należy:

Złącze ArduCAM
Złącze ArduCAM

Na zdjęciu jest złącze ArduCAM. Łączymy z ESP8266-12:

  • CS -> GPIO16
  • MOSI -> GPIO13
  • MISO -> GPIO12
  • SCK -> GPIO14
  • GND -> GND
  • VCC -> VCC
  • SDA -> GPIO4
  • SCL -> GPIO5

Do działania potrzebny nam jest szkic, na początek nie wybiegniemy poza przykład dostępny z ArduCam. W menu File/Examples/ArduCAM/ESP8266/ArduCAM_Mini_OV2640_websocket_server jest tym czego szukamy. Otwieramy przykład, odnajdujemy miejsce w którym jest ustawiane SSID i hasło sieci WiFi (u mnie są to linie 42 i 43 szkicu – jeśli nie masz jeszcze to włącz sobie numerowanie linii w IDE – Ctrl+, i opcja Display line numbers), wpisz właściwe SSID i hasło do Twojej sieci WiFi.

Wgraj szkic na ESP (pamiętaj o zwarciu do GND pinu GPIO0), korzystając z jakiegoś konwertera USB/Serial. Zajrzyj na konsolę, by zobaczyć jaki adres IP otrzymało ESP. Teraz, co robi ten szkic? Otóż udostępnia tak zwany WebSocket – jest to standard zapewniający komunikację w dwie strony przez jeden kanał TCP i jest zaimplementowany przez współczesne przeglądarki. Jako taki nadaje się świetnie do transmisji danych z kamery. Po nawiązaniu połączenia, przeglądarka w każdej chwili może wysłać do ESP komendę capture, która spowoduje zrobienie zdjęcia i odesłanie go przez kanał WebSocket.

Do tego potrzebny jest HTML – aby już nie kombinować z równoległa obsługą WebSocket i HTML na ESP, dla wygody skorzystamy z lokalnego HTML. Do szkicu jest dołączony katalog html (tam gdzie jest przykład). Możesz dogrzebać się do niego na swoim dysku, albo po prosty ściągnij ArduCAM websocket HTML – archiwum ZIP będące jego kopią.

ArduCAM HTML
ArduCAM HTML

Rozpakuj zip i otwórz plik html w przeglądarce. Otworzy się taka strona ze zdjęciem przygotowanym przez autora ArduCAM.

W polu Location wpiszcie adres IP waszego ESP (zachowując ws:// z przodu) i kliknijcie Connect. Po chwili powinien wyskoczyć pop-up z informacją o nawiązaniu połączenia.

Wtedy można wysłać komendę capture by otrzymać zdjęcie. Tutaj zobaczyć możecie jak dziś rano widok za oknem się prezentował. Może niezbyt pięknie, ale heh, taka rzeczywistość :)

Widok z okna
Widok z okna

Klikając kolejny raz Send możecie uaktualnić zdjęcie. Ale na takim gotowcu nie poprzestaniemy. Jak działa ten szkic?

W pętli loop znajdziecie kod:

  WiFiClient client = server.available();
  if (webSocketServer.handshake(client)) {
    while (client.connected() ) {
      //KOD
    }

 Zmienna client zostanie „wypełniona” jeżeli przyjdzie połączenie z przeglądarki. Następnie, jeżeli połączenie jest zidentyfikowane jako poprawna komunikacja w ramach WebSocket (sprawdza to  webSocketServer.handshake) to następuje obsługa połączenia. Po odebraniu danych od przeglądarki, są one umieszczane w łańcuchu znakowym i przekazywane do funkcji handleClientData. I tam, jeśli został odebrany łańcuch capture zostaje uruchomiona kamera.

Co można poprawić? Na szybko – może dodamy obsługę  różnych rozdzielczości. W tym celu modyfikujemy funkcję handleClientData dając dwa ify, a przed wywołaniem start_capture ustawiamy wybraną rozdzielczość. Całość wygląda tak:

void handleClientData(String &dataString)
{
  if (dataString.startsWith("capture1"))
  {
    myCAM.OV2640_set_JPEG_size(OV2640_640x480);
    Serial.println(dataString);
    start_capture();
  }
  if (dataString.startsWith("capture2"))
  {
    myCAM.OV2640_set_JPEG_size(OV2640_320x240);
    Serial.println(dataString);
    start_capture();
  }
}

Prawda, że proste? Od teraz w zależności czy wyślecie tekst capture1 czy capture2 to otrzymacie zdjęcie w różnej rozdzielczości.

Przy produkcji wpisu ucierpiały (albo i nie) następujące części:

Co dalej z ArduCAM?

Jak na wstępie napisałem, ArduCAM jest w mojej opinii produktem niszowym. Jego niewątpliwą zaletą jest stosunkowy niewielki rozmiar.

Gdy myślisz o obróbce obrazu czy bardziej o video streamingu to raczej Twoje myśli powinny kierować się w stronę rozwiązania opartego o jakieś Rasbperry Pi i kamer dedykowanych do Raspberry lub nawet zwykłe kamerki na USB.

Jeśli chcesz zrobić coś użytecznego z tą kamerą, to na myśl przychodzi mi scenariusz w którym chcesz robić zdjęcie po jakimś zdarzeniu. Czy to będzie wyzwolenie z czujnika PIR czy może odczyt karty RFID (kontrola wejść) to już nie ma znaczenia.

Czy chcielibyście tutaj zobaczyć taki gotowy projekt?