ESP32 카메라 모듈로 무선통신 스트리밍 서버만들기
IoT 관련하여 프로젝트를 만들다 보니 다양한 기기에 대한 호기심이 생겨 하나씩 만들어 보고 있습니다
마이크로컨트롤러에선 원래 다량의 데이터를 주고받는 게 아니라 제어와 관련된 역할을 주로 담당하는데 저렴하게 카메라테스트를 해볼 수 있는 정도선에서 구현이 가능하여 테스트를 해보았습니다
1. 카메라 모델 및 핀 설정하기
#define CAMERA_MODEL_AI_THINKER
#include "camera_pins.h"
CAMERA_MODEL_AI_THINKER를 미리 정의하면 camera_pins.h 내부에서 AI Thinker 보드에 맞는 GPIO 번호들이 매크로로 설정됩니다.
2. 필수 라이브러리 포함하기
#include <WiFi.h>
#include "esp_camera.h"
#include "esp_http_server.h"
WiFi.h: ESP32의 무선 LAN 연결
esp_camera.h: 카메라 모듈 초기화·제어
esp_http_server.h: HTTP 서버(라우팅·스트리밍) 기능
3. 네트워크 자격 증명
const char* ssid = "와이파이 이름";
const char* password = "패스워드";
ESP32가 접속할 Wi-Fi SSID와 비밀번호를 지정 이후만들 setup()에서 WiFi.begin(ssid, password)로 부팅 시 자동으로 연결 시도
4. setup() 함수
void setup() {
Serial.begin(115200); //시리얼 통신 디버깅 메세지 115200 baud로 출력하도록
Serial.setDebugOutput(false);
WiFi.begin(ssid, password); // 와이파이 접속시도
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected"); // 와파 연결
Serial.println(WiFi.localIP()); // 아이피 출력
// 카메라 설정
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
if (psramFound()) {
config.frame_size = FRAMESIZE_QVGA; // 해상도
config.jpeg_quality = 10; //화질
config.fb_count = 2; //버퍼
} else {
config.frame_size = FRAMESIZE_QVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
startCameraServer(); // 스트리밍 서버 함수 호출
}
5. startCameraServer() 함수
void startCameraServer() {
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.server_port = 80;
httpd_handle_t server = NULL; // 서버 핸들러
httpd_uri_t index_uri = {
.uri = "/",
.method = HTTP_GET,
.handler = [](httpd_req_t *req) {
const char* html = R"rawliteral(
<html>
<head><title>간이 cctv 만들기</title></head>
<body>
<h2>ESP32-CAM</h2>
<img src="/stream" />
</body>
</html>
)rawliteral";
httpd_resp_send(req, html, HTTPD_RESP_USE_STRLEN);
return ESP_OK;
}
};
httpd_uri_t stream_uri = {
.uri = "/stream",
.method = HTTP_GET,
.handler = [](httpd_req_t *req) {
camera_fb_t * fb = NULL;
esp_err_t res = ESP_OK;
char * part_buf[64];
res = httpd_resp_set_type(req, "multipart/x-mixed-replace; boundary=frame");
if (res != ESP_OK) return res;
while (true) {
fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Camera capture failed");
continue;
}
snprintf((char *)part_buf, 64, "--frame\r\nContent-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n", fb->len);
res = httpd_resp_send_chunk(req, (const char *)part_buf, strlen((char *)part_buf));
if (res == ESP_OK) res = httpd_resp_send_chunk(req, (const char *)fb->buf, fb->len);
if (res == ESP_OK) res = httpd_resp_send_chunk(req, "\r\n", 2);
esp_camera_fb_return(fb);
if (res != ESP_OK) break;
delay(50);
}
return res;
}
};
if (httpd_start(&server, &config) == ESP_OK) { // server 사용
httpd_register_uri_handler(server, &index_uri);
httpd_register_uri_handler(server, &stream_uri);
Serial.println("Camera stream ready at /stream");
} else {
Serial.println( Failed to start web server");
}
}
간단히 말하자면 jpg로 사진을 연속촬영해서 연속된 사진을 계속 교체하여 넘기면서 보여주는 방식으로 보여주게됩니다
이렇게 간단하게 간이 CCTV를 만들어보았는데 ESP 성능이 좋지않기 때문에 테스트 및 학습용도로 적합합니다 아무리 최적화를 잘한다 하여도 주기적으로 재부팅되거나 멈추는 경우가 잦기때문에 테스트 용도로만 권장드립니다 물론 재부팅되면 자동으로 와이파이와 서버구동이 되기때문에 지속성에선 큰 문제가 되지않습니다😊
다음엔 고성능 프로세서를 이용해 찐 CCTV를 만들어볼 예정입니다