Jetson & 머신러닝

(작성중) 어르신 말벗 위한, AI와 대화 가능한 음성 챗봇 만들기( ESP32 활용: 약 5만원? )

아크리엑터 2026. 9. 22. 18:28
반응형

1. 준비할 부품

Seeed Studio XIAO ESP32-S3

Seeed Studio XIAO ESP32S3 leverages 240MHz Xtensa 32-bit LX7 dual-core processor, supporting both WiFi and BLE 5.0 wireless connectivities and a 2.4GHz Rod antenna. Ideal for the Internet of Things, Smart Homes, Wireless wearable devices, Robotics, etc.

www.seeedstudio.com

1-10PCS 고정밀 MEMS 마이크 MS3625 - I2S 인터페이스, INMP441 및 ESP32 (전방향) 와 호환 가능 - AliExpress 502

Smarter Shopping, Better Living! Aliexpress.com

ko.aliexpress.com

1-20PCS MAX98357 I2S 3W Class D Amplifier Breakout Interface DAC Decoder Module Filterless Audio Board For Raspberry Pi ESP32 -

Smarter Shopping, Better Living! Aliexpress.com

www.aliexpress.com

2030 4Ω 3W 8Ω 2W Speaker Module for Notebook

Smarter Shopping, Better Living! Aliexpress.com

www.aliexpress.com

 
 
 

  • 또는, 위의 camera, mic를 같이 포함하는 제품으로, Seeed Studio XIAO ESP32-S3 Sense(ESP32-S3 8M PSRAM, Digital Microphone, OV3660 camera sensor, SD카드)를 사용할 수 있다.(아래의 설명은 이 제품으로 진행한다) : 13.9 달러

 
 

Seeed Studio XIAO ESP32-S3 Sense

Seeed Studio XIAO ESP32-S3 leverages dual-core ESP32-S3 chip, supporting both Wi-Fi and BLE wireless connectivities, which allows battery charge. It integrates built-in camera sensor, digital microphone. It offers 8MB PSRAM, 8MB FLASH, and external SD card

www.seeedstudio.com

 

Round Display for Seeed Studio XIAO

This compact expansion board is designed for the Seeed Studio XIAO ESP32 series and features a 1.28-inch fully covered round touch display in a 39 mm disc form factor. It integrates an RTC holder, charging circuit, and TF card slot, making it well suited f

www.seeedstudio.com

 
 

2. 프로그램 준비할 것들

     가. 아두이노 설정

  • Arduino 메뉴 : File > Preferences의  "Additional Boards Manager URLs"에 아래의 URL을 추가한다.
  • https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json  

 

  • Windows화면
  • 맥OS 화면
  • 보드 설치/선택
  • Tools > Board > Boards Manager 메뉴 선택 후, "esp32" 검색하여 "esp32 by Espressif Systems" 설치

나. ESP32-S3의 포트가 인식되지 않거나 작동하지 않을 때.

  • 1단계: ESP32-S3의 Boot 버튼을 누른 상태를 유지한다. (B버튼)
  • 2단계: Boot버튼이 눌려진 상태에서 USB 케이블을 컴퓨터에 연결한다. 
  • 3단계: USB케이블이 연결된 상태(전원 인가)에서 눌려진 Boot버튼을 떼어낸다.
  • 4단계: 기본예제인 Blink 예제를 업로드하여 정상 작동 여부를 확인한다.

다. 라이브러리 설치

GitHub - Seeed-Studio/Seeed_Arduino_RoundDisplay: An Arduino graphics library based on LVGL, specifically designed for Round Dis

An Arduino graphics library based on LVGL, specifically designed for Round Display for XIAO - Seeed-Studio/Seeed_Arduino_RoundDisplay

github.com

GitHub - Seeed-Studio/Seeed_GFX: Arduino and PlatformIO IDE compatible TFT library optimised for the Seeed XIAO that supports di

Arduino and PlatformIO IDE compatible TFT library optimised for the Seeed XIAO that supports different driver chips - Seeed-Studio/Seeed_GFX

github.com

 

  • 위의 Zip파일을 다운로드 받아서, 아두이노IDE > Sketch > Include Library > Add .ZIP Library 에서 해당 파일을 선택하여 설치한다. 
    •  lvgl by kisvegabor, TFT_eSPI by Bodmer 라이브러리를 추가로 설치한다.
    • 설치 방법
      • 1단계: Tool > 라이브러리 관리 선택
      • 2단계: TFT_eSPI 검색 (lvgl 등)
      • 3단계: 해당 라이브러리를 선택하여 설치한다.

 

라. 라이브러리 수정

이렇게 설치한 상태에서 관련 예제를 사용해보니, ESP32가 Crash나면서 무한 Dump가 반복된다. 여러 곳을 검색하다가 아래의 해결책을 찾았다. 

  • 1단계: 아두이노가 설치된 또는 문서함의 Arduino 폴더 > libraries > TFT-eSPI > Processors 로 이동한다.
  • 2단계: 텍스트 편집기로 TFT_eSPI_ESP32_S3.h 를 열어서, 아래의 내용을 수정한다.
    • #ifndef REG_SPI_BASE 및 쌍이 되는 endif 삭제
    • #undef REG_SPI_BASE 추가
  //#ifndef REG_SPI_BASE //HSPI                 FSPI/VSPI
    #undef REG_SPI_BASE
    #define REG_SPI_BASE(i) (((i)>1) ? ( DR_REG_SPI3_BASE) : (DR_REG_SPI2_BASE))
  //#endif

 

  • 3단계: libraries/TFT_eSPI/User_Setup_Select.h 파일을 열어서, 다음 내용을 수정한다.
  • 4단계: 27라인과 93라인 즈음에 있는 아래 내용을 주석을 추가하고, 뒤의 것은 주석을 제거한다. 
//#include <User_Setup.h>           // Default setup is root library folder

.....

#include <User_Setups/Setup66_Seeed_XIAO_Round.h>     // Setup file for Seeed XIAO with GC9A01 240x240


.....

 

3. 예제 프로그램을 실행해보자

가. Round Display

  • Arduino IDE > File > Examples > Seeed_GFX > Round Display > Arduino_Life 를 선택
  • driver.h 파일이 같이 열림: 아래 내용으로 되어있는지 확인 필요
    • #define BOARD_SCREEN_COMBO 501 // Round Display for Seeed Studio XIAO (GC9A01)" 
  • 컴파일 할 때는 "PSRAM : OPI PSRAM"이 선택되도록 해야 한다. (다른 것도 동일)    
  • 컴파일 및 업로드 수행한다.  업로드가 완료되면, 아래의 화면이 표시된다.                                                                             

 




나. TFT Clock
 

  • Arduino IDE > File > Examples > Seeed_GFX > Round Display > TFT_Clock 을 선택
  • driver.h 파일이 같이 열림: 아래 내용으로 되어있는지 확인 필요
    • #define BOARD_SCREEN_COMBO 501 // Round Display for Seeed Studio XIAO (GC9A01)" 
  • 컴파일 및 업로드 수행한다.  업로드가 완료되면, 아래의 화면이 표시된다.                                                                                                                                                                                                             

 

 

4. 마이크 인식

 
 
 

5. 스피커 연결(앰프 포함)

앰프 모듈 핀XIAO 보드 핀역할

Round Display와 XIAO ESP32-S3 모듈의 소켓을 연결하고 나면, 위의 핀을 연결할 수 없다. Round Display의 소켓의 발에서 선을 뽑아오는 방법을 사용할 수 있다. 내 경우에는, 중간에 꽂는 소켓을 하나 만들어서 앰프 연결할 수 있는 핀을 뽑아내게 만들었다.
 

 
 

6. 카메라 연결

카메라에서 촬영한 동영상을 Round Display에 표시하는 프로그램이다. 
driver.h 파일은 위에서 설명한 것과 동일하게 같은 폴더에 저장한다. 그리고, Round Display에 있는 SD슬롯은 비활성화시킨다. SD슬롯 2개가 동시에 인식될 수는 없다.
메모리를 많이 사용하는 프로그램이기 때문에, PSRAM 설정은 꼭 필요하다. 

 

#include "esp_camera.h"
#include <TFT_eSPI.h>
#include <SPI.h>

// XIAO ESP32S3 Sense 카메라 핀 배열 (고정값)
#define PWDN_GPIO_NUM     -1
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM     10
#define SIOD_GPIO_NUM     40
#define SIOC_GPIO_NUM     39
#define Y9_GPIO_NUM       48
#define Y8_GPIO_NUM       11
#define Y7_GPIO_NUM       12
#define Y6_GPIO_NUM       14
#define Y5_GPIO_NUM       16
#define Y4_GPIO_NUM       18
#define Y3_GPIO_NUM       17
#define Y2_GPIO_NUM       15
#define VSYNC_GPIO_NUM    38
#define HREF_GPIO_NUM     47
#define PCLK_GPIO_NUM     13

TFT_eSPI tft = TFT_eSPI();

void setup() {
  Serial.begin(115200);

  // 1. 하드웨어 충돌 방지: Round Display의 SD 카드 비활성화 
  // (스피커 연결용 D8, D9, D10 핀을 온전히 확보하기 위함)
  pinMode(D3, OUTPUT);
  digitalWrite(D3, HIGH);

  // 2. 디스플레이 초기화
  tft.init();
  tft.setRotation(0); // 화면 방향 (0~3으로 조절하여 위아래를 맞추세요)
  tft.fillScreen(TFT_BLACK);
  
  // 카메라의 RGB565 데이터와 디스플레이의 색상 바이트 순서가 반대이므로 맞춰줍니다.
  // 이 설정을 안 하면 빨간색과 파란색이 뒤집혀서(스머프처럼) 나옵니다.
  tft.setSwapBytes(true); 

  // 3. 카메라 설정
  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_sccb_sda = SIOD_GPIO_NUM;
  config.pin_sccb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  
  // 압축(JPEG)을 하지 않고 디스플레이에 픽셀을 그대로 쏘기 위한 포맷
  config.pixel_format = PIXFORMAT_RGB565; 
  
  // Round Display 해상도(240x240)에 완벽하게 일치하는 카메라 해상도
  config.frame_size = FRAMESIZE_240X240; 
  
  config.jpeg_quality = 10;
  config.fb_count = 2; // 화면 끊김을 없애기 위한 더블 버퍼링 (PSRAM 필수)
  config.fb_location = CAMERA_FB_IN_PSRAM;

  // 4. 카메라 초기화 실행
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("카메라 초기화 실패! 에러 코드: 0x%x", err);
    tft.setTextColor(TFT_RED);
    tft.drawCentreString("Camera Error", 120, 110, 2);
    return;
  }
  
  // 만약 카메라 조립 방향 때문에 화면이 거꾸로 나온다면 아래 두 줄의 주석(//)을 해제하세요.
  // sensor_t * s = esp_camera_sensor_get();
  // s->set_vflip(s, 1);   // 상하 반전
  // s->set_hmirror(s, 1); // 좌우 반전
}

void loop() {
  // 카메라에서 1장의 프레임 캡처
  camera_fb_t * fb = esp_camera_fb_get();
  
  if (!fb) {
    Serial.println("프레임 캡처 실패");
    return;
  }

  // 캡처된 프레임 메모리(fb->buf)를 디스플레이(0, 0 위치부터 240x240 크기로)에 바로 밀어 넣습니다.
  tft.pushImage(0, 0, 240, 240, (uint16_t *)fb->buf);

  // 다 쓴 프레임 메모리를 반환하여 다음 사진을 찍을 수 있게 합니다. (매우 중요)
  esp_camera_fb_return(fb);
}

💡 프로그램 핵심 포인트

  1. FRAMESIZE_240X240: 카메라 해상도를 Round Display의 픽셀 수에 1:1로 정확히 맞췄기 때문에, 화면이 찌그러지거나 잘리지 않고 예쁜 원형으로 꽉 차게 나온다.
  2. PIXFORMAT_RGB565 & pushImage(): 흔히 쓰는 JPEG 방식이 아닌, 화면의 픽셀 색상값(RGB565) 자체를 뽑아내서 디스플레이 하드웨어로 즉시 전송하기 때문에 영상이 끊기지 않고 아주 부드럽게(실시간 스트리밍) 재생된다.
  3. 화면 방향 조절: 모듈을 결합한 각도에 따라 화면이 눕혀져 보이거나 뒤집혀 보일 수 있다. 이 경우 tft.setRotation(0);의 숫자 0을 1, 2, 3 중 하나로 바꿔서 방향을 맞추거나, setup() 마지막 부분에 있는 상하좌우 반전 코드를 활용할 수 있다.

 
밤에 찍은 것이라 전체 모습은 안보이고 화면 출력된 것만 보인다.


 
 

7. 실시간 음성 대화 챗봇 만들기

 
 
 

반응형