ESP32-CAM開發板(一):簡介與燒錄程式

ESP32-CAM是安信可科技研發的ESP32開發板,搭載200萬像素的攝影鏡頭,具備拍照、串流視訊以及人臉辨識功能。ESP32-CAM開發板的外觀如下,詳細的參數規格與電路圖(原理圖),請參閱安信可科技的ESP32-CAM攝像頭開發板說明文件(簡體中文)。

ESP32-CAM開發板正面

板子上的ESP32模組具有IPEX外接天線插座,外接2.4GHz天線可延長Wi-Fi無線傳輸距離。然而,外接天線和PCB天線只能擇一使用,採用外接天線之前,你要自行改焊右上圖的電阻。

從電路圖可看出,LED1的陰極接在GPIO 33,所以當GPIO 33設成低電位時,LED1將被點亮。

ESP32-CAM開發板LED接腳

開發板右下角有個用於暫存影像資料的4MB PSRAM,PSRAM全稱 “pseudo static RAM”(虛擬靜態隨機存取記憶體),根據華邦電子PSRAM產品介紹網頁的說明:PSRAM是由一個DRAM主體核心與傳統SRAM介面所組成 。晶片上的刷新電路,可省略使用者需要記憶體刷新的考量。相對於傳統的CMOS SRAM,PSRAM具有更高容量,高速度,更小的晶片尺寸,以及與DRAM相容的優勢。

ESP32-CAM有附帶一個200萬像素(1600×1200像素)的OV2640攝影模組(攝像頭)。這一面PCB標示的VCC引腳,預設輸出電壓是3.3V。若要輸出5V,必須把標示3.3V的電阻改焊到5V接點,但這樣顯然太麻煩了,直接從5V輸入腳焊接一個引線,或者從外部電源模組取得5V比較方便。

ESP32-CAM開發板反面

請先把相機模組安裝到ESP32-CAM開發板:

ESP32-CAM開發板安裝相機模組

燒錄ESP32-CAM程式的UART序列腳接線

ESP32-CAM開發板沒有內建USB轉TTL序列訊號的IC,也沒有USB介面,所以燒錄程式碼需要外接USB轉TTL序列訊號模組,此外,ESP32-CAM板子的GPIO 0腳必須接地,ESP32才會進入燒錄模式。

也有商家販售「帶下載器」的模組,也就是適用於ESP32-CAM開發板的電源供應及USB轉序列介面的底座(商品關鍵字 “ESP32-CAM-MB”),直接插上開發板就能燒錄程式。

USB轉TTL序列訊號模組與ESP32-CAM板的接線示範如下,強烈建議採用具備3.3V邏輯電位的序列訊號轉換模組:

ESP32-CAM開發板連接USB轉TTL訊號介面

如果手邊有Arduino UNO板或其他具備USB轉TTL序列介面的開發板,可以利用它的USB轉TTL序列介面IC來銜接ESP32-CAM。把Arduino UNO的RESET腳接地,UNO板子上的ATmega328微控器將停止運作,所以進出UNO板的序列資料都不會傳入ATmega328,而是直接通過板子上的TX和RX腳。

使用Arduino UNO充當USB轉TTL訊號介面

UNO板的邏輯電位是5V,所以TX(傳送)腳最好串接一個1KΩ~2KΩ電阻,避免損壞ESP32。

許多ESP32和ESP8266開發板都有內建USB轉TTL序列訊號IC,但我手邊的這些開發板,序列訊號IC的RESET腳和處理器的RESET相連,所以板子的RESET接地,USB轉TTL訊號IC也無法運作。

燒錄CameraWebServer(相機網站伺服器)範例程式

從Arduino IDE的「工具」主功能表,選擇“Ai Thinker ESP32-CAM”開發板:

選擇“Ai Thinker ESP32-CAM”開發板

「序列埠」選擇你的USB序列模組的埠號。

選擇ESP32範例中的CameraWebServer(相機網站伺服器)。

CameraWebServer(相機網站伺服器)範例

這個範例程式適用多種ESP32開發板與相機模組,請修改程式開頭的相機模組定義,並且填入你的Wi-Fi網路名稱和密碼:

修改程式碼

最後,編譯並上傳程式碼到ESP32-CAM開發板。

執行CameraWebServer(相機網站伺服器)範例

程式上傳完畢後,先拆掉連接GPIO 0和GND的接線。然後開啟序列埠監控視窗,再按一下ESP32-CAM的RST(重置鍵),它將開始連線到指定的Wi-Fi網路並顯示此開發板的網址(此例為192.168.0.117)。

CameraWebServer(相機網站伺服器)畫面

在瀏覽器輸入ESP32-CAM的IP位址、按下Start Stream(開始串流)鈕,即可看見ESP32-CAM的串流視訊。

Posts created 483

32 thoughts on “ESP32-CAM開發板(一):簡介與燒錄程式

  1. 老師您好:
    請問cam有方法能回復至原廠設定,可能是串流時錯誤中斷造成無法讀取(未知的USB裝置),有試著安裝驅動程式,但似乎無效,謝謝。

    1. ESP32CAM並不具備USB轉序列埠晶片,所以出問題的應該是USB轉序列埠的板子。

    2. 感謝老師。之前燒錄esp01s,與這篇esp32 cam的燒錄,都是使用arduino uno去轉的,因為我個人失敗率出奇的高,想請問您的經驗,是不是這種做法蠻不穩的。

    3. 我只有在驗證用Uno燒錄可行時測試過一次,其餘都是用3.3V邏輯準位的USB轉TTL序列線燒錄。

  2. 老師您好:
    請問能讓這組程式隔著固定時間拍照並上傳到google drive嗎
    我們有試著在程式間插入指定路徑但似乎沒用

    1. 我採用Google官方的API,上傳檔案到Google Drive雲端硬碟。底下的程式改自之前的《使用Python Flask建置影像圖檔上傳網站服務》範例,日後再補上說明。

      你需要在Flask網站伺服器程式專案的根資料夾存入Google的憑證檔(我將它重新命名成client_secrets.json)。

      這個程式需要事先安裝這些Python套件:

      pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
      

      伺服器端的Python程式碼(app.py檔)如下:

      import datetime
      import os
      import filetype
      from flask import Flask, flash, request, redirect, url_for, render_template
      import io  # 需要暫時存檔
      from google.auth.transport.requests import Request
      from google.oauth2.credentials import Credentials
      from google_auth_oauthlib.flow import InstalledAppFlow
      from googleapiclient.discovery import build
      from googleapiclient.http import MediaIoBaseUpload
      
      
      CLIENT_SECRET_FILE = 'client_secrets.json'  # 憑證檔案
      UPLOAD_FOLDER = 'Google雲端硬碟的資料夾ID'   # 請自行修改ID
      SCOPES = ['https://www.googleapis.com/auth/drive']
      ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
      
      app = Flask(__name__)
      app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'     # 請自行修改密鑰
      app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
      app.config['MAX_CONTENT_LENGTH'] = 3 * 1024 * 1024
      
      # 存取Google憑證檔案,取自Google官方範例:
      # https://developers.google.com/drive/api/quickstart/python
      creds = None
      
      if os.path.exists('token.json'):
          creds = Credentials.from_authorized_user_file('token.json', SCOPES)
      
      if not creds or not creds.valid:
          if creds and creds.expired and creds.refresh_token:
              creds.refresh(Request())
          else:
              flow = InstalledAppFlow.from_client_secrets_file(
                  CLIENT_SECRET_FILE, SCOPES)
              creds = flow.run_local_server(port=0)
      
          with open('token.json', 'w') as token:
              token.write(creds.to_json())
      
      service = build('drive', 'v3', credentials=creds)
      
      @app.route('/')
      def index():
          return render_template('index.html')
      
      @app.route('/', methods=['POST'])
      def upload_file():
          res = handle_file(request)
      
          if res['msg'] == 'ok':
              flash('影像上傳完畢!')
              return render_template('index.html', filename=res['filename'])
          elif res['msg'] == 'type_error':
              flash('僅允許上傳png, jpg, jpeg和gif影像檔')
          elif res['msg'] == 'empty':
              flash('請選擇要上傳的影像')
          elif res['msg'] == 'no_file':
              flash('沒有上傳檔案')
      
          return redirect(url_for('index'))  # 令瀏覽器跳回首頁
      
      @app.route('/esp32cam', methods=['POST'])
      def esp32cam():
          res = handle_file(request)
          return res['msg']
      
      def handle_file(request):
          if 'filename' not in request.files:
              return {"msg": 'no_file'}
      
          file = request.files['filename']  # 取得上傳檔
      
          if file.filename == '':
              return {"msg": 'empty'}       # 傳回代表"空白"的訊息
      
          if file:
              file_type = filetype.guess_extension(file)  # 判斷上傳檔的類型
              MIME = file.content_type
      
              if file_type in ALLOWED_EXTENSIONS:
                  file.stream.seek(0)
                  # 重新設定檔名
                  filename = str(datetime.datetime.now()).replace(
                      ':', '_') + '.' + file_type
      
                  buffer = io.BytesIO()
                  buffer.name = file.filename
                  file.save(buffer)  # 暫存檔案
      
                  print("上傳到Google Drive...")
                  media = MediaIoBaseUpload(buffer, mimetype=MIME,
                                            chunksize=1024*1024, resumable=True)
                  body = {'name': filename, 'parents': [UPLOAD_FOLDER]}
      
                  file_id = service.files().create(
                      body=body, media_body=media).execute()
      
                  print('雲端檔名: ' + str(body['name']))
                  print('雲端檔案ID:' + str(file_id['id']))
      
                  return {"msg": 'ok', "filename": filename}
              else:
                  return {"msg": 'type_error'}  # 傳回代表「檔案類型錯誤」的訊息
      
      @app.route('/img/')
      def display_image(filename):
          return redirect(url_for('static', filename='uploads/' + filename))
      
      if __name__ == "__main__":
          app.run(host='0.0.0.0', port=80)
      
    1. 如果當作燒錄器的ESP32板子的UART介面的Reset電路和ESP32晶片是分開來的,可以,但多數ESP32板子都不這樣的。

  3. 手上的esp32 cam使用序列串按照上面的接線圖會發現無法上傳程式碼,必須把GND接5V那一側.
    且使用3.3V無法連線wifi,必須使用5V.
    不知何故?

    1. 仔細看我的esp32 cam 3.3V那一側的GND,標示為GND/R,使用三用電錶量看起來與其他的GND不是短路.
      查看網路上的文章https://blog.makehub.tw/post/hands-on-esp32-cam-mb/,看來這是副廠的設計,用來與上傳底板結合使用的RST腳.
      謝謝老師的回覆.

  4. 您好!

    我用了老師 Arduino UNO的接法,結果出現
    A fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header

    請問要怎麼處理

    1. 我發現arduino的TX要接UOT, RX要接UOR
      這樣就會看到畫面也可以燒CODE了
      老師的圖可能不小心畫反了…

  5. 老師您好,我用的 ESP32-Cam 是副廠也就是有標示GND/R那種,購買的時候我有一起購買所謂的下載板ESP32 CAM MB (CH340),要上傳程式碼的時候已確認過進入下載模式,但出現錯誤「Download mode successfully detected, but getting no sync reply: The serial TX path seems to be down.」

    我原本以為是板子壞了,但交換了幾片皆是如此,後來我用Arduino UNO做USB-TTL連到ESP32 Cam,試驗幾次後發現,只有TX RX輸出5V才能成功上傳,其他不管什麼方式低電壓於5V都會失敗(包含您範例會串接1K歐姆電阻),我後來再次量測所謂下載板的TX RX腳位,以及LDO Vout皆穩壓在3.3V,我推測電壓不足導致失敗。

    請問老師有這方面的經驗為什麼會這樣嗎,還是說這是廠商隨便批的代工低價品的關係?雖然可以用UNO上傳但是挺不方便的,我看CH340 data sheet是可以輸入5V電源但須要接一顆0.1uF電容,若其他不改動僅拿掉LDO,直接一條線加電容將5V從USB提供給CH340這樣改造下載板再利用的想法是否可行,謝謝。

    1. CH340晶片電源接0.1uF電容是為了濾波(穩定電源供給),跟燒錄韌體沒有直接關聯,USB轉TTL板子上的晶片一定有接這個電容(有些甚至會並聯多個不同數值的電容)。

      以前自製Arduino板子時,USB轉TTL的DTR接腳和ATMega晶片的Reset接腳之間,有串連一個0.1uF,目的是在燒錄之前自動重置Arduino板,像這篇貼文:

      採用PL-2303晶片的USB轉TTL序列板的小小改造
      https://swf.com.tw/?p=637

      ESP32和ESP8266一樣,在Reset時,GPIO 0腳必須處於低電位,晶片才會進入燒錄模式,這篇貼文有提到自動切換燒錄模式的電路:

      使用ESP8266 ESP-01模組的USB轉接板燒錄Arduino程式或MicroPython韌體
      https://swf.com.tw/?p=1260

      至於ESP32燒錄時出現 “Download mode successfully detected, but getting no sync reply: The serial TX path seems to be down.” 錯誤訊息…我沒遇過,但樂鑫原廠文件的這個連結提到,這個訊息代表ESP32已進入燒錄模式,但是一直沒有收到來自燒錄程式(esptool)的回應,請檢查燒錄器的TX接線是否正常。

  6. 謝謝老師的回應與參考資料,樂鑫原廠文件與其他網路上的資料查到此錯誤都是檢查燒錄器的TX接線,我自己在排除錯誤的時候有做幾組測試,皆處於燒錄模式下:ESP32 cam 接 (1) 下載板(CH340),(2) UNO板做USB轉TTL,TX腳位串接1K、1.5K歐姆電阻,(3) UNO板做USB轉TTL,TX腳位直接相連ESP32 cam,只有 (3) TX腳位直接相連 (無任何電阻) 可以成功,其他兩種都會出現以上錯誤;因為我看老師的文章有寫過「UNO板的邏輯電位是5V,所以TX(傳送)腳最好串接一個1KΩ~2KΩ電阻,避免損壞ESP32」,因此很疑惑是不是電壓問題。

  7. 老師你好,我編譯上傳完後要在串口序列阜找網址up,但找不到卻出現
    E (911) camera: Camera probe failed with error 0x105(ESP_ERR_NOT_FOUND)
    Camera init failed with error 0x105
    要怎麼解決

  8. 請問在串口序列阜找網址IP時,一直出現很多點在無限的跑(像這樣:…………),是哪裡錯誤呢

  9. 老師你好,我上傳完後打開監控視窗顯示以下這些
    E (206) psram: PSRAM ID read error: 0xffffffff

    E (267) camera: Camera probe failed with error 0x105(ESP_ERR_NOT_FOUND)
    Camera init failed with error 0x105
    選用的模組也是正確的
    我使用的板子是ESP32-S
    請問要怎麼解決

      • 請用穩定的5V供電
      • D0腳不要接其他元件
      • 拔掉再插回攝像頭模組試試
      • PSRAM晶片可能壞了
      • 嘗試這個老外的測試,上傳程式之前,Flash mode(快閃記憶體模式)設為”DIO”,Partition Scheme(分區)設成”Huge APP (3Mb…)”。

      補充說明,ESP32-CAM是安信可科技(AI-Thinker)研發的開源板子,所以其他公司也可以自由生產,但某些相容板採用次級零件,導致運作不穩定或出錯。

  10. Arduino UNO R4 已經上市,不知何時可以看到老師的新作。感覺可玩的東西更多了

    1. 我會買一片Arduino UNO R4 WiFi來玩玩,但現階段的主力仍是ESP32和UNO R3板,因為ESP32微控制板的功能和接腳數量對我來說,非常好用而且價格低廉,所以目前進行中的書籍案例,還是採用ESP32開發板。

      UNO R4 WiFi開發板搭載兩個32位元微控器:Renesas RA4M1(執行Arduino程式)和ESP32-S3(負責WiFi和藍牙通訊),主因有軟、硬體相容性的考量。

      在硬體方面,R4開發板的I/O腳的布局和電位,都和R3板相容,因此可沿用既有的擴展板(Shield)。RA4M1微控器的I/O腳支援5V,數量也遠多於R3使用的ATMega328,但受限於UNO開發板的布局,很多接腳不能直接使用,有點可惜。

      ESP32的I/O腳不支援5V,所以不相容於某些擴展板和模組。

      在軟體方面,因為處理器架構不同,某些Arduino程式庫不相容於ESP32,像處理PWM輸出的程式敘述,就跟Arduino UNO R3不一樣。

      但只要有Arduino的軟硬體實作經驗(只把硬體當成積木模組拼接,完全不知道電路運作方式的人除外),這些都是小問題,Arduino UNO R4 WiFi能做的,現有的ESP32開發板也可以,電容觸控輸入、多組UART序列埠、內建USB介面、高解析度取樣、I2S, DAC, CAN匯流排…等功能,ESP32系列微控器也有,而且很多感測器和控制IC都支援3.3V低電壓。

      Arduino官方也有推出ESP32開發板(Arduino Nano ESP32),只是20美金的定價,有點嬌貴,再加上ESP32 Arduino開發程式以及MicroPython語言的開源專案,都不是由Arduino官方主導,從這個角度來看,Arduino官方的ESP32開發板對我的吸引力不大(我有贊助購買micropython.org的開發板)。

  11. 老師您好,我發現您介紹的 Arduino 官方程式​​碼是最穩定的,它使用了原始的esp_httpd函數庫。
    我已經使用 ESP32 的 AP 模式和 Client 模式 進行了嘗試,並獲得了穩定的視訊幀。

    為了使用 ESP32 Web伺服器與網頁建立雙向通信, 我嘗試了很多 websocket 視訊串流程式碼,最穩定的表現是將 esp32 作為 AP 模式,當我使用相同的 wifi 路由器配置並使用 ESP32 作為客戶端時,視訊有很多延遲和幀丟失。我在任何網站中都沒有找到在AP mode 和 Client mode下工作良好的 ESP32 Websocket 程式碼,這非常令人困惑和沮喪。

    所以,我回到了官方的範例程式碼,希望能夠找到僅使用 esp_httpd library + webserver.h 作雙向通訊。 我發現有一種方法可以使用ajax和 ESP32 Web伺服器 ( webserver.h ) 來刷新網頁,但是,它們似乎跟視訊串流彼此不匹配 (crash)。 那麼如何在使用相機串流媒體的同時從 esp32 模組接收資料呢?

  12. 老師您好打擾了:
    我想詢問以下兩行是esp32cam出現問題嗎?
    若我使用公用網路之電腦會有影響嗎?
    [E][camera.c:1049] camera_probe(): Detected camera not supported.
    [E][camera.c:1249] esp_camera_init(): Camera probe failed with error 0x20004

    1. 那兩個錯誤訊息分別代表「不支援偵測到的相機模組」以及「相機偵測錯誤」,通常是你的程式選錯相機模組,例如,根據我的開發板,應該取消這一行註解:

      #define CAMERA_MODEL_AI_THINKER

      然後將其他相機模組的巨集定義設成註解。

      另外,也有可能是排線接觸不良、電源不穩定或者相機模組故障。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

Related Posts

Begin typing your search term above and press enter to search. Press ESC to cancel.

Back To Top