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/vi/4-manufacturing/lessons/2-check-fruit-from-device/wio-terminal-camera.md

475 lines
21 KiB

<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "160be8c0f558687f6686dca64f10f739",
"translation_date": "2025-08-27T21:04:06+00:00",
"source_file": "4-manufacturing/lessons/2-check-fruit-from-device/wio-terminal-camera.md",
"language_code": "vi"
}
-->
# Chụp ảnh - Wio Terminal
Trong phần này của bài học, bạn sẽ thêm một camera vào Wio Terminal của mình và chụp ảnh từ nó.
## Phần cứng
Wio Terminal cần một camera.
Camera bạn sẽ sử dụng là [ArduCam Mini 2MP Plus](https://www.arducam.com/product/arducam-2mp-spi-camera-b0067-arduino/). Đây là một camera 2 megapixel dựa trên cảm biến hình ảnh OV2640. Nó giao tiếp qua giao diện SPI để chụp ảnh và sử dụng I2C để cấu hình cảm biến.
## Kết nối camera
ArduCam không có cổng Grove, thay vào đó nó kết nối với cả bus SPI và I2C thông qua các chân GPIO trên Wio Terminal.
### Nhiệm vụ - kết nối camera
Kết nối camera.
![Một cảm biến ArduCam](../../../../../translated_images/arducam.20e4e4cbb268296570b5914e20d6c349fc42ddac9ed4e1b9deba2188204eebae.vi.png)
1. Các chân ở đáy của ArduCam cần được kết nối với các chân GPIO trên Wio Terminal. Để dễ dàng tìm đúng chân, hãy gắn nhãn dán chân GPIO đi kèm với Wio Terminal xung quanh các chân:
![Wio Terminal với nhãn dán chân GPIO](../../../../../translated_images/wio-terminal-pin-sticker.b90b1535937b84bd00d853f0004aea74fac2aec04b43f14b887796b2633f855e.vi.png)
1. Sử dụng dây nhảy, thực hiện các kết nối sau:
| Chân ArduCAM | Chân Wio Terminal | Mô tả |
| ------------ | ----------------- | --------------------------------------- |
| CS | 24 (SPI_CS) | SPI Chip Select |
| MOSI | 19 (SPI_MOSI) | SPI Controller Output, Peripheral Input |
| MISO | 21 (SPI_MISO) | SPI Controller Input, Peripheral Output |
| SCK | 23 (SPI_SCLK) | SPI Serial Clock |
| GND | 6 (GND) | Ground - 0V |
| VCC | 4 (5V) | Nguồn điện 5V |
| SDA | 3 (I2C1_SDA) | I2C Serial Data |
| SCL | 5 (I2C1_SCL) | I2C Serial Clock |
![Wio Terminal được kết nối với ArduCam bằng dây nhảy](../../../../../translated_images/arducam-wio-terminal-connections.a4d5a4049bdb5ab800a2877389fc6ecf5e4ff307e6451ff56c517e6786467d0a.vi.png)
Kết nối GND và VCC cung cấp nguồn điện 5V cho ArduCam. Nó hoạt động ở 5V, không giống như các cảm biến Grove hoạt động ở 3V. Nguồn điện này được cung cấp trực tiếp từ kết nối USB-C cấp nguồn cho thiết bị.
> 💁 Đối với kết nối SPI, các nhãn chân trên ArduCam và tên chân Wio Terminal được sử dụng trong mã vẫn sử dụng quy ước đặt tên cũ. Các hướng dẫn trong bài học này sẽ sử dụng quy ước đặt tên mới, ngoại trừ khi tên chân được sử dụng trong mã.
1. Bây giờ bạn có thể kết nối Wio Terminal với máy tính của mình.
## Lập trình thiết bị để kết nối với camera
Wio Terminal bây giờ có thể được lập trình để sử dụng camera ArduCAM đã được gắn.
### Nhiệm vụ - lập trình thiết bị để kết nối với camera
1. Tạo một dự án Wio Terminal mới bằng PlatformIO. Đặt tên dự án này là `fruit-quality-detector`. Thêm mã vào hàm `setup` để cấu hình cổng nối tiếp.
1. Thêm mã để kết nối WiFi, với thông tin đăng nhập WiFi của bạn trong một tệp có tên `config.h`. Đừng quên thêm các thư viện cần thiết vào tệp `platformio.ini`.
1. Thư viện ArduCam không có sẵn dưới dạng thư viện Arduino có thể được cài đặt từ tệp `platformio.ini`. Thay vào đó, nó cần được cài đặt từ mã nguồn trên trang GitHub của họ. Bạn có thể lấy nó bằng cách:
* Clone repo từ [https://github.com/ArduCAM/Arduino.git](https://github.com/ArduCAM/Arduino.git)
* Truy cập repo trên GitHub tại [github.com/ArduCAM/Arduino](https://github.com/ArduCAM/Arduino) và tải mã dưới dạng tệp zip từ nút **Code**
1. Bạn chỉ cần thư mục `ArduCAM` từ mã này. Sao chép toàn bộ thư mục vào thư mục `lib` trong dự án của bạn.
> ⚠️ Toàn bộ thư mục phải được sao chép, vì vậy mã nằm trong `lib/ArduCam`. Đừng chỉ sao chép nội dung của thư mục `ArduCam` vào thư mục `lib`, hãy sao chép toàn bộ thư mục.
1. Mã thư viện ArduCam hoạt động cho nhiều loại camera. Loại camera bạn muốn sử dụng được cấu hình bằng các cờ trình biên dịch - điều này giúp thư viện được xây dựng nhỏ nhất có thể bằng cách loại bỏ mã cho các camera bạn không sử dụng. Để cấu hình thư viện cho camera OV2640, thêm đoạn sau vào cuối tệp `platformio.ini`:
```ini
build_flags =
-DARDUCAM_SHIELD_V2
-DOV2640_CAM
```
Điều này thiết lập 2 cờ trình biên dịch:
* `ARDUCAM_SHIELD_V2` để thông báo cho thư viện rằng camera nằm trên một bo mạch Arduino, được gọi là shield.
* `OV2640_CAM` để thông báo cho thư viện chỉ bao gồm mã cho camera OV2640.
1. Thêm một tệp tiêu đề vào thư mục `src` có tên `camera.h`. Tệp này sẽ chứa mã để giao tiếp với camera. Thêm đoạn mã sau vào tệp này:
```cpp
#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;
};
```
Đây là mã cp thp cu hình camera bng cách s dng các thư vin ArduCam và trích xut hình nh khi cn thiết bng bus SPI. Mã này rt c th cho ArduCam, vì vy bn không cn lo lng v cách nó hot động thi đim này.
1. Trong `main.cpp`, thêm đon mã sau bên dưới các câu lnh `include` khác để bao gm tp mi này và to mt th hin ca lp camera:
```cpp
#include "camera.h"
Camera camera = Camera(JPEG, OV2640_640x480);
```
Điu này to mt `Camera` lưu hình nh dưới dng JPEG vi độ phân gii 640 x 480. Mc dù các độ phân gii cao hơn được h tr (lên đến 3280x2464), b phân loi hình nh hot động trên các hình nh nh hơn nhiu (227x227) nên không cn chp và gi các hình nh ln hơn.
1. Thêm đon mã sau bên dưới để định nghĩa mt hàm thiết lp camera:
```cpp
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!");
}
}
```
Hàm `setupCamera` này bt đầu bng cách cu hình chân SPI chip select (`PIN_SPI_SS`) mc cao, làm cho Wio Terminal tr thành b điu khin SPI. Sau đó, nó khi động các bus I2C và SPI. Cui cùng, nó khi to lp camera, cu hình các cài đặt cm biến camera và đảm bo mi th được kết ni đúng cách.
1. Gi hàm này cui hàm `setup`:
```cpp
setupCamera();
```
1. Xây dng và ti mã này lên, sau đó kim tra đầu ra t màn hình ni tiếp. Nếu bn thy `Error setting up the camera!`, hãy kim tra li dây ni để đảm bo tt c các dây cáp đang kết ni đúng chân trên ArduCam vi đúng chân GPIO trên Wio Terminal, và tt c các dây nhy được cm chc chn.
## Chụp ảnh
Wio Terminal bây gi có th được lp trình để chp nh khi mt nút được nhn.
### Nhiệm vụ - chụp ảnh
1. Các vi điu khin chy mã ca bn liên tc, vì vy không d dàng để kích hot mt hành động như chp nh mà không phn ng vi mt cm biến. Wio Terminal có các nút, vì vy camera có th được thiết lp để kích hot bi mt trong các nút. Thêm đon mã sau vào cui hàm `setup` để cu hình nút C (mt trong ba nút trên cùng, nút gn công tc ngun nht).
![Nút C ở trên cùng gần công tắc nguồn](../../../../../translated_images/wio-terminal-c-button.73df3cb1c1445ea07ee98316af0e7925fcb43135df0abed58d3d4822b2589c3b.vi.png)
```cpp
pinMode(WIO_KEY_C, INPUT_PULLUP);
```
Chế độ `INPUT_PULLUP` thc cht đảo ngược mt đầu vào. Ví dụ, thông thường mt nút s gi tín hiu thp khi không được nhn và tín hiu cao khi được nhn. Khi được đặt thành `INPUT_PULLUP`, chúng gi tín hiu cao khi không được nhn và tín hiu thp khi được nhn.
1. Thêm mt hàm trng để phn hi khi nút được nhn trước hàm `loop`:
```cpp
void buttonPressed()
{
}
```
1. Gi hàm này trong phương thc `loop` khi nút được nhn:
```cpp
void loop()
{
if (digitalRead(WIO_KEY_C) == LOW)
{
buttonPressed();
delay(2000);
}
delay(200);
}
```
Đon mã này kim tra xem nút có được nhn hay không. Nếu được nhn, hàm `buttonPressed` s được gi và vòng lp s tm dng trong 2 giây. Điu này để cho phép thi gian để nút được nh ra để mt ln nhn dài không được đăng ký hai ln.
> 💁 Nút trên Wio Terminal được đặt thành `INPUT_PULLUP`, vì vậy gửi tín hiệu cao khi không được nhấn và tín hiệu thấp khi được nhấn.
1. Thêm đon mã sau vào hàm `buttonPressed`:
```cpp
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);
}
```
Đon mã này bt đầu chp nh bng cách gi `startCapture`. Phn cng camera không hot động bng cách tr v d liu khi bn yêu cu, thay vào đó bn gi mt lnh để bt đầu chp, và camera s hot động trong nn để chp nh, chuyn đổi nó thành JPEG và lưu tr trong mt b đệm cc b trên chính camera. Lnh `captureReady` sau đó kim tra xem vic chp nh đã hoàn thành hay chưa.
Khi vic chp đã hoàn thành, d liu hình nh được sao chép t b đệm trên camera vào mt b đệm cc b (mng byte) vi lnh `readImageToBuffer`. Độ dài ca b đệm sau đó được gi đến màn hình ni tiếp.
1. Xây dng và ti mã này lên, sau đó kim tra đầu ra trên màn hình ni tiếp. Mi ln bn nhn nút C, mt hình nh s được chp và bn s thy kích thước hình nh được gi đến màn hình ni tiếp.
```output
Connecting to WiFi..
Connected!
Image captured
Image read to buffer with length 9224
Image captured
Image read to buffer with length 11272
```
Các hình nh khác nhau s có kích thước khác nhau. Chúng được nén dưới dng JPEG và kích thước ca tp JPEG cho mt độ phân gii nht định ph thuc vào ni dung trong hình nh.
> 💁 Bạn có thể tìm thấy mã này trong thư mục [code-camera/wio-terminal](../../../../../4-manufacturing/lessons/2-check-fruit-from-device/code-camera/wio-terminal).
😀 Bn đã chp nh thành công vi Wio Terminal ca mình.
## Tùy chọn - xác minh hình ảnh camera bằng thẻ SD
Cách d nht để xem các hình nh được chp bi camera là ghi chúng vào th SD trong Wio Terminal và sau đó xem chúng trên máy tính ca bn. Thc hin bước này nếu bn có mt th microSD d phòng và mt khe cm th microSD trên máy tính ca bn hoc mt b chuyn đổi.
Wio Terminal ch h tr th microSD có dung lượng ti đa 16GB. Nếu bn có th SD ln hơn, nó s không hot động.
### Nhiệm vụ - xác minh hình ảnh camera bằng thẻ SD
1. Định dng mt th microSD dưới dng FAT32 hoc exFAT bng các ng dng liên quan trên máy tính ca bn (Disk Utility trên macOS, File Explorer trên Windows, hoc s dng các công c dòng lnh trên Linux).
1. Chèn th microSD vào khe cm ngay bên dưới công tc ngun. Đảm bo nó được đẩy vào hoàn toàn cho đến khi nó kêu "click" và gi nguyên v trí, bn có th cn đẩy nó bng móng tay hoc mt công c mng.
1. Thêm các câu lnh `include` sau vào đầu tp `main.cpp`:
```cpp
#include "SD/Seeed_SD.h"
#include <Seeed_FS.h>
```
1. Thêm hàm sau trước hàm `setup`:
```cpp
void setupSDCard()
{
while (!SD.begin(SDCARD_SS_PIN, SDCARD_SPI))
{
Serial.println("SD Card Error");
}
}
```
Hàm này cấu hình thẻ SD bằng bus SPI.
1. Gọi hàm này từ hàm `setup`:
```cpp
setupSDCard();
```
1. Thêm đoạn mã sau phía trên hàm `buttonPressed`:
```cpp
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);
}
```
Đoạn mã này định nghĩa một biến toàn cục cho số lượng tệp. Biến này được sử dụng cho tên tệp hình ảnh để nhiều hình ảnh có thể được chụp với các tên tệp tăng dần - `1.jpg`, `2.jpg` và cứ thế.
Sau đó, nó định nghĩa hàm `saveToSDCard` nhận một bộ đệm dữ liệu byte và độ dài của bộ đệm. Một tên tệp được tạo bằng số lượng tệp, và số lượng tệp được tăng lên sẵn sàng cho tệp tiếp theo. Dữ liệu nhị phân từ bộ đệm sau đó được ghi vào tệp.
1. Gọi hàm `saveToSDCard` từ hàm `buttonPressed`. Lệnh gọi này nên **trước** khi bộ đệm bị xóa:
```cpp
Serial.print("Image read to buffer with length ");
Serial.println(length);
saveToSDCard(buffer, length);
delete(buffer);
```
1. Xây dựng và tải mã này lên, sau đó kiểm tra đầu ra trên màn hình nối tiếp. Mỗi lần bạn nhấn nút C, một hình ảnh sẽ được chụp và lưu vào thẻ SD.
```output
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
```
1. Tắt nguồn Wio Terminal và tháo thẻ microSD bằng cách đẩy nhẹ vào và thả ra, thẻ sẽ bật ra. Bạn có thể cần sử dụng một công cụ mỏng để làm điều này. Cắm thẻ microSD vào máy tính của bạn để xem các hình ảnh.
![Hình ảnh một quả chuối được chụp bằng ArduCam](../../../../../translated_images/banana-arducam.be1b32d4267a8194b0fd042362e56faa431da9cd4af172051b37243ea9be0256.vi.jpg)
> 💁 Có thể mất vài hình ảnh để cân bằng trắng của máy ảnh tự điều chỉnh. Bạn sẽ nhận thấy điều này dựa trên màu sắc của các hình ảnh được chụp, vài hình đầu tiên có thể trông không đúng màu. Bạn luôn có thể khắc phục điều này bằng cách thay đổi mã để chụp vài hình ảnh bị bỏ qua trong hàm `setup`.
---
**Tuyên bố miễn trừ trách nhiệm**:
Tài liệu này đã được dịch bằng dịch vụ dịch thuật AI [Co-op Translator](https://github.com/Azure/co-op-translator). Mặc dù chúng tôi cố gắng đảm bảo độ chính xác, xin lưu ý rằng các bản dịch tự động có thể chứa lỗi hoặc không chính xác. Tài liệu gốc bằng ngôn ngữ bản địa nên được coi là nguồn thông tin chính thức. Đối với các thông tin quan trọng, nên sử dụng dịch vụ dịch thuật chuyên nghiệp bởi con người. Chúng tôi không chịu trách nhiệm cho bất kỳ sự hiểu lầm hoặc diễn giải sai nào phát sinh từ việc sử dụng bản dịch này.