You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
IoT-For-Beginners/translations/pl/4-manufacturing/lessons/2-check-fruit-from-device/wio-terminal-camera.md

20 KiB

Zrób zdjęcie - Wio Terminal

W tej części lekcji dodasz kamerę do swojego Wio Terminal i zrobisz zdjęcia za jej pomocą.

Sprzęt

Wio Terminal potrzebuje kamery.

Kamera, której użyjesz, to ArduCam Mini 2MP Plus. Jest to kamera o rozdzielczości 2 megapikseli, oparta na czujniku obrazu OV2640. Komunikuje się za pomocą interfejsu SPI, aby przechwytywać obrazy, i używa I2C do konfiguracji czujnika.

Podłącz kamerę

ArduCam nie posiada gniazda Grove, zamiast tego łączy się z magistralami SPI i I2C za pomocą pinów GPIO na Wio Terminal.

Zadanie - podłącz kamerę

Podłącz kamerę.

Czujnik ArduCam

  1. Piny na spodzie ArduCam muszą być podłączone do pinów GPIO na Wio Terminal. Aby łatwiej było znaleźć odpowiednie piny, przyklej naklejkę z oznaczeniami pinów GPIO, która jest dołączona do Wio Terminal:

    Wio Terminal z naklejką oznaczającą piny GPIO

  2. Używając przewodów połączeniowych, wykonaj następujące połączenia:

    Pin ArduCAM Pin Wio Terminal Opis
    CS 24 (SPI_CS) Wybór układu SPI
    MOSI 19 (SPI_MOSI) Wyjście kontrolera SPI, wejście peryferyjne
    MISO 21 (SPI_MISO) Wejście kontrolera SPI, wyjście peryferyjne
    SCK 23 (SPI_SCLK) Zegar szeregowy SPI
    GND 6 (GND) Masa - 0V
    VCC 4 (5V) Zasilanie 5V
    SDA 3 (I2C1_SDA) Dane szeregowe I2C
    SCL 5 (I2C1_SCL) Zegar szeregowy I2C

    Wio Terminal podłączony do ArduCam za pomocą przewodów połączeniowych

    Połączenia GND i VCC dostarczają zasilanie 5V do ArduCam. Kamera działa na 5V, w przeciwieństwie do czujników Grove, które działają na 3V. Zasilanie pochodzi bezpośrednio z połączenia USB-C, które zasila urządzenie.

    💁 W przypadku połączenia SPI etykiety pinów na ArduCam i nazwy pinów Wio Terminal używane w kodzie nadal korzystają ze starej konwencji nazewnictwa. Instrukcje w tej lekcji będą używać nowej konwencji nazewnictwa, z wyjątkiem przypadków, gdy nazwy pinów są używane w kodzie.

  3. Teraz możesz podłączyć Wio Terminal do komputera.

Zaprogramuj urządzenie, aby połączyć się z kamerą

Wio Terminal można teraz zaprogramować, aby korzystał z podłączonej kamery ArduCAM.

Zadanie - zaprogramuj urządzenie, aby połączyć się z kamerą

  1. Utwórz nowy projekt Wio Terminal w PlatformIO. Nazwij ten projekt fruit-quality-detector. Dodaj kod w funkcji setup, aby skonfigurować port szeregowy.

  2. Dodaj kod do połączenia z WiFi, umieszczając dane logowania w pliku config.h. Nie zapomnij dodać wymaganych bibliotek do pliku platformio.ini.

  3. Biblioteka ArduCam nie jest dostępna jako biblioteka Arduino, którą można zainstalować z pliku platformio.ini. Zamiast tego trzeba ją zainstalować ze źródła z ich strony GitHub. Możesz to zrobić na dwa sposoby:

  4. Potrzebujesz tylko folderu ArduCAM z tego kodu. Skopiuj cały folder do folderu lib w swoim projekcie.

    ⚠️ Należy skopiować cały folder, aby kod znajdował się w lib/ArduCam. Nie kopiuj tylko zawartości folderu ArduCam do folderu lib, skopiuj cały folder.

  5. Kod biblioteki ArduCam działa dla wielu typów kamer. Typ kamery, której chcesz użyć, jest konfigurowany za pomocą flag kompilatora - dzięki temu biblioteka jest jak najmniejsza, usuwając kod dla kamer, których nie używasz. Aby skonfigurować bibliotekę dla kamery OV2640, dodaj następujący kod na końcu pliku platformio.ini:

    build_flags =
        -DARDUCAM_SHIELD_V2
        -DOV2640_CAM
    

    Ustawia to dwie flagi kompilatora:

    • ARDUCAM_SHIELD_V2, aby poinformować bibliotekę, że kamera znajduje się na płytce Arduino, znanej jako shield.
    • OV2640_CAM, aby poinformować bibliotekę, aby uwzględniała tylko kod dla kamery OV2640.
  6. Dodaj plik nagłówkowy do folderu src, nazwij go camera.h. Będzie on zawierał kod do komunikacji z kamerą. Dodaj do tego pliku następujący kod:

    #pragma once
    
    #include <ArduCAM.h>
    #include <Wire.h>
    
    class Camera
    {
    public:
        Camera(int format, int image_size) : _arducam(OV2640, PIN_SPI_SS)
        {
            _format = format;
            _image_size = image_size;
        }
    
        bool init()
        {
            // Reset the CPLD
            _arducam.write_reg(0x07, 0x80);
            delay(100);
    
            _arducam.write_reg(0x07, 0x00);
            delay(100);
    
            // Check if the ArduCAM SPI bus is OK
            _arducam.write_reg(ARDUCHIP_TEST1, 0x55);
            if (_arducam.read_reg(ARDUCHIP_TEST1) != 0x55)
            {
                return false;
            }
    
            // Change MCU mode
            _arducam.set_mode(MCU2LCD_MODE);
    
            uint8_t vid, pid;
    
            // Check if the camera module type is OV2640
            _arducam.wrSensorReg8_8(0xff, 0x01);
            _arducam.rdSensorReg8_8(OV2640_CHIPID_HIGH, &vid);
            _arducam.rdSensorReg8_8(OV2640_CHIPID_LOW, &pid);
            if ((vid != 0x26) && ((pid != 0x41) || (pid != 0x42)))
            {
                return false;
            }
    
            _arducam.set_format(_format);
            _arducam.InitCAM();
            _arducam.OV2640_set_JPEG_size(_image_size);
            _arducam.OV2640_set_Light_Mode(Auto);
            _arducam.OV2640_set_Special_effects(Normal);
            delay(1000);
    
            return true;
        }
    
        void startCapture()
        {
            _arducam.flush_fifo();
            _arducam.clear_fifo_flag();
            _arducam.start_capture();
        }
    
        bool captureReady()
        {
            return _arducam.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK);
        }
    
        bool readImageToBuffer(byte **buffer, uint32_t &buffer_length)
        {
            if (!captureReady()) return false;
    
            // Get the image file length
            uint32_t length = _arducam.read_fifo_length();
            buffer_length = length;
    
            if (length >= MAX_FIFO_SIZE)
            {
                return false;
            }
            if (length == 0)
            {
                return false;
            }
    
            // create the buffer
            byte *buf = new byte[length];
    
            uint8_t temp = 0, temp_last = 0;
            int i = 0;
            uint32_t buffer_pos = 0;
            bool is_header = false;
    
            _arducam.CS_LOW();
            _arducam.set_fifo_burst();
    
            while (length--)
            {
                temp_last = temp;
                temp = SPI.transfer(0x00);
                //Read JPEG data from FIFO
                if ((temp == 0xD9) && (temp_last == 0xFF)) //If find the end ,break while,
                {
                    buf[buffer_pos] = temp;
    
                    buffer_pos++;
                    i++;
    
                    _arducam.CS_HIGH();
                }
                if (is_header == true)
                {
                    //Write image data to buffer if not full
                    if (i < 256)
                    {
                        buf[buffer_pos] = temp;
                        buffer_pos++;
                        i++;
                    }
                    else
                    {
                        _arducam.CS_HIGH();
    
                        i = 0;
                        buf[buffer_pos] = temp;
    
                        buffer_pos++;
                        i++;
    
                        _arducam.CS_LOW();
                        _arducam.set_fifo_burst();
                    }
                }
                else if ((temp == 0xD8) & (temp_last == 0xFF))
                {
                    is_header = true;
    
                    buf[buffer_pos] = temp_last;
                    buffer_pos++;
                    i++;
    
                    buf[buffer_pos] = temp;
                    buffer_pos++;
                    i++;
                }
            }
    
            _arducam.clear_fifo_flag();
    
            _arducam.set_format(_format);
            _arducam.InitCAM();
            _arducam.OV2640_set_JPEG_size(_image_size);
    
            // return the buffer
            *buffer = buf;
        }
    
    private:
        ArduCAM _arducam;
        int _format;
        int _image_size;
    };
    

    Jest to kod niskopoziomowy, który konfiguruje kamerę za pomocą bibliotek ArduCam i pobiera obrazy w razie potrzeby za pomocą magistrali SPI. Kod ten jest bardzo specyficzny dla ArduCam, więc na tym etapie nie musisz się martwić, jak działa.

  7. W pliku main.cpp dodaj następujący kod poniżej innych instrukcji include, aby dołączyć nowy plik i utworzyć instancję klasy kamery:

    #include "camera.h"
    
    Camera camera = Camera(JPEG, OV2640_640x480);
    

    Tworzy to obiekt Camera, zapisujący obrazy jako JPEG w rozdzielczości 640x480. Chociaż obsługiwane są wyższe rozdzielczości (do 3280x2464), klasyfikator obrazu działa na znacznie mniejszych obrazach (227x227), więc nie ma potrzeby przechwytywania i przesyłania większych obrazów.

  8. Dodaj poniższy kod, aby zdefiniować funkcję konfigurującą kamerę:

    void setupCamera()
    {
        pinMode(PIN_SPI_SS, OUTPUT);
        digitalWrite(PIN_SPI_SS, HIGH);
    
        Wire.begin();
        SPI.begin();
    
        if (!camera.init())
        {
            Serial.println("Error setting up the camera!");
        }
    }
    

    Funkcja setupCamera zaczyna od skonfigurowania pinu wyboru układu SPI (PIN_SPI_SS) jako wysokiego, czyniąc Wio Terminal kontrolerem SPI. Następnie uruchamia magistrale I2C i SPI. Na końcu inicjalizuje klasę kamery, która konfiguruje ustawienia czujnika kamery i upewnia się, że wszystko jest poprawnie podłączone.

  9. Wywołaj tę funkcję na końcu funkcji setup:

    setupCamera();
    
  10. Zbuduj i wgraj ten kod, a następnie sprawdź dane wyjściowe w monitorze szeregowym. Jeśli zobaczysz komunikat Error setting up the camera!, sprawdź okablowanie, aby upewnić się, że wszystkie przewody są podłączone do odpowiednich pinów na ArduCam i Wio Terminal, a wszystkie przewody są dobrze osadzone.

Zrób zdjęcie

Wio Terminal można teraz zaprogramować tak, aby robił zdjęcie po naciśnięciu przycisku.

Zadanie - zrób zdjęcie

  1. Mikrokontrolery wykonują kod w sposób ciągły, więc trudno jest wywołać coś takiego jak zrobienie zdjęcia bez reakcji na czujnik. Wio Terminal ma przyciski, więc kamerę można skonfigurować tak, aby była wyzwalana jednym z przycisków. Dodaj poniższy kod na końcu funkcji setup, aby skonfigurować przycisk C (jeden z trzech przycisków na górze, ten najbliżej przełącznika zasilania).

    Przycisk C na górze, najbliżej przełącznika zasilania

    pinMode(WIO_KEY_C, INPUT_PULLUP);
    

    Tryb INPUT_PULLUP zasadniczo odwraca wejście. Na przykład, normalnie przycisk wysyła niski sygnał, gdy nie jest naciśnięty, i wysoki sygnał, gdy jest naciśnięty. Gdy ustawiony jest na INPUT_PULLUP, wysyła wysoki sygnał, gdy nie jest naciśnięty, i niski sygnał, gdy jest naciśnięty.

  2. Dodaj pustą funkcję reagującą na naciśnięcie przycisku przed funkcją loop:

    void buttonPressed()
    {
    
    }
    
  3. Wywołaj tę funkcję w metodzie loop, gdy przycisk jest naciśnięty:

    void loop()
    {
        if (digitalRead(WIO_KEY_C) == LOW)
        {
            buttonPressed();
            delay(2000);
        }
    
        delay(200);
    }
    

    Ten klucz sprawdza, czy przycisk jest naciśnięty. Jeśli jest naciśnięty, wywoływana jest funkcja buttonPressed, a pętla opóźnia się o 2 sekundy. Ma to na celu umożliwienie zwolnienia przycisku, aby długie naciśnięcie nie zostało zarejestrowane dwukrotnie.

    💁 Przycisk na Wio Terminal jest ustawiony na INPUT_PULLUP, więc wysyła wysoki sygnał, gdy nie jest naciśnięty, i niski sygnał, gdy jest naciśnięty.

  4. Dodaj poniższy kod do funkcji buttonPressed:

    camera.startCapture();
    
    while (!camera.captureReady())
        delay(100);
    
    Serial.println("Image captured");
    
    byte *buffer;
    uint32_t length;
    
    if (camera.readImageToBuffer(&buffer, length))
    {
        Serial.print("Image read to buffer with length ");
        Serial.println(length);
    
        delete(buffer);
    }
    

    Ten kod rozpoczyna przechwytywanie obrazu, wywołując startCapture. Sprzęt kamery nie działa w ten sposób, że zwraca dane na żądanie, zamiast tego wysyłasz instrukcję rozpoczęcia przechwytywania, a kamera działa w tle, aby przechwycić obraz, przekonwertować go na JPEG i zapisać w lokalnym buforze na samej kamerze. Wywołanie captureReady sprawdza, czy przechwytywanie obrazu zostało zakończone.

    Po zakończeniu przechwytywania dane obrazu są kopiowane z bufora na kamerze do lokalnego bufora (tablicy bajtów) za pomocą wywołania readImageToBuffer. Długość bufora jest następnie wysyłana do monitora szeregowego.

  5. Zbuduj i wgraj ten kod, a następnie sprawdź dane wyjściowe w monitorze szeregowym. Za każdym razem, gdy naciśniesz przycisk C, obraz zostanie przechwycony, a jego rozmiar zostanie wysłany do monitora szeregowego.

    Connecting to WiFi..
    Connected!
    Image captured
    Image read to buffer with length 9224
    Image captured
    Image read to buffer with length 11272
    

    Różne obrazy będą miały różne rozmiary. Są one kompresowane jako JPEG, a rozmiar pliku JPEG dla danej rozdzielczości zależy od tego, co znajduje się na obrazie.

💁 Kod ten znajdziesz w folderze code-camera/wio-terminal.

😀 Udało Ci się przechwycić obrazy za pomocą Wio Terminal.

Opcjonalne - zweryfikuj obrazy z kamery za pomocą karty SD

Najłatwiejszym sposobem zobaczenia obrazów przechwyconych przez kamerę jest zapisanie ich na karcie SD w Wio Terminal, a następnie obejrzenie ich na komputerze. Wykonaj ten krok, jeśli masz wolną kartę microSD i gniazdo microSD w komputerze lub adapter.

Wio Terminal obsługuje tylko karty microSD o pojemności do 16 GB. Jeśli masz większą kartę SD, nie będzie działać.

Zadanie - zweryfikuj obrazy z kamery za pomocą karty SD

  1. Sformatuj kartę microSD jako FAT32 lub exFAT za pomocą odpowiednich aplikacji na komputerze (Disk Utility na macOS, File Explorer na Windows lub narzędzi wiersza poleceń w Linux).

  2. Włóż kartę microSD do gniazda tuż poniżej przełącznika zasilania. Upewnij się, że jest całkowicie wsunięta, aż kliknie i pozostanie na miejscu. Może być konieczne użycie paznokcia lub cienkiego narzędzia.

  3. Dodaj następujące instrukcje include na początku pliku main.cpp:

    #include "SD/Seeed_SD.h"
    #include <Seeed_FS.h>
    
  4. Dodaj następującą funkcję przed funkcją setup:

    void setupSDCard()
    {
        while (!SD.begin(SDCARD_SS_PIN, SDCARD_SPI))
        {
            Serial.println("SD Card Error");
        }
    }
    

    Funkcja ta konfiguruje kartę SD za pomocą magistrali SPI.

  5. Wywołaj tę funkcję z funkcji setup:

    setupSDCard();
    
  6. Dodaj poniższy kod powyżej funkcji buttonPressed:

    int fileNum = 1;
    
    void saveToSDCard(byte *buffer, uint32_t length)
    {
        char buff[16];
        sprintf(buff, "%d.jpg", fileNum);
        fileNum++;
    
        File outFile = SD.open(buff, FILE_WRITE );
        outFile.write(buffer, length);
        outFile.close();
    
        Serial.print("Image written to file ");
        Serial.println(buff);
    }
    

    Definiuje to globalną zmienną dla licznika plików. Jest ona używana do nazw plików obrazów, aby można było przechwycić wiele obrazów z rosnącymi nazwami plików - 1.jpg, 2.jpg i tak dalej.

    Następnie definiuje funkcję saveToSDCard, która przyjmuje bufor danych bajtowych i długość bufora. Tworzona jest nazwa pliku przy użyciu licznika plików, a licznik plików jest zwiększany, aby przygotować się na kolejny plik. Dane binarne z bufora są następnie zapisywane do pliku.

  7. Wywołaj funkcję saveToSDCard z funkcji buttonPressed. Wywołanie powinno być przed usunięciem bufora:

    Serial.print("Image read to buffer with length ");
    Serial.println(length);
    
    saveToSDCard(buffer, length);
    
    delete(buffer);
    
  8. Zbuduj i wgraj ten kod, a następnie sprawdź dane wyjściowe w monitorze szeregowym. Za każdym razem, gdy naciśniesz przycisk C, obraz zostanie przechwycony i zapisany na karcie SD.

    Connecting to WiFi..
    Connected!
    Image captured
    Image read to buffer with length 16392
    Image written to file 1.jpg
    Image captured
    Image read to buffer with length 14344
    Image written to file 2.jpg
    
  9. Wyłącz zasilanie karty microSD i wysuń ją, delikatnie wciskając i zwalniając, a karta wyskoczy. Może być konieczne użycie cienkiego narzędzia, aby to zrobić. Podłącz kartę microSD do komputera, aby obejrzeć obrazy.

    Zdjęcie banana wykonane za pomocą ArduCam 💁 Może zająć kilka zdjęć, zanim balans bieli aparatu dostosuje się. Zauważysz to na podstawie kolorów uchwyconych zdjęć, pierwsze kilka może wyglądać na nieprawidłowe. Zawsze możesz obejść ten problem, zmieniając kod tak, aby uchwycić kilka zdjęć, które są ignorowane w funkcji setup.

Zastrzeżenie:
Ten dokument został przetłumaczony za pomocą usługi tłumaczenia AI Co-op Translator. Chociaż dokładamy wszelkich starań, aby tłumaczenie było precyzyjne, prosimy pamiętać, że automatyczne tłumaczenia mogą zawierać błędy lub nieścisłości. Oryginalny dokument w jego rodzimym języku powinien być uznawany za autorytatywne źródło. W przypadku informacji o kluczowym znaczeniu zaleca się skorzystanie z profesjonalnego tłumaczenia przez człowieka. Nie ponosimy odpowiedzialności za jakiekolwiek nieporozumienia lub błędne interpretacje wynikające z użycia tego tłumaczenia.