You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESP32串口发Base64图片,Python仅读取到b''故障求助

串口传输ESP32摄像头视频流问题排查

尝试通过串口而非WiFi传输ESP32摄像头视频流:ESP32将采集的图片编码为Base64后通过串口发送,Python逐行读取并解码为图片,再用OpenCV实现视频流。目前Arduino串口监视器可正常读取Base64编码内容,但Python端仅读取到b'',已确认串口端口与波特率无误,请求协助排查问题。

ESP32代码

/////////////////////////////////////////////////////////////////

/*

  ESP32CAM | Android(Flutter App) Wired Communication - Base64 Encoding/Decoding [2/2]

  Created by Eric N. (ThatProject)

*/

/////////////////////////////////////////////////////////////////

#include "esp_camera.h"
#include <base64.h>
#define CAMERA_MODEL_AI_THINKER


#define BAUD_RATE 2000000
#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM      0
#define SIOD_GPIO_NUM     26
#define SIOC_GPIO_NUM     27

#define Y9_GPIO_NUM       35
#define Y8_GPIO_NUM       34
#define Y7_GPIO_NUM       39
#define Y6_GPIO_NUM       36
#define Y5_GPIO_NUM       21
#define Y4_GPIO_NUM       19
#define Y3_GPIO_NUM       18
#define Y2_GPIO_NUM        5
#define VSYNC_GPIO_NUM    25
#define HREF_GPIO_NUM     23
#define PCLK_GPIO_NUM     22

void setup() {
    Serial.begin(BAUD_RATE);
    cameraInit();
}

void loop() {
    grabImage();
}

void cameraInit() {
    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 = 10000000;
    config.pixel_format = PIXFORMAT_JPEG;
    config.frame_size = FRAMESIZE_QVGA; //320x240
    config.jpeg_quality = 10;
    config.fb_count = 2;

    esp_err_t err = esp_camera_init(&config);
    if (err != ESP_OK) {
      return;
    }

    sensor_t * s = esp_camera_sensor_get();
    s->set_hmirror(s, 1);   
    s->set_vflip(s, 1);   
}

void grabImage() {
    camera_fb_t* fb = esp_camera_fb_get();
    if (!fb || fb->format != PIXFORMAT_JPEG) {
    } else {
        delay(40);
        String enter = "\n";
        String encoded = base64::encode(fb->buf, fb->len);
        encoded = encoded + enter;
        Serial.write(encoded.c_str(), encoded.length());
        // Serial.println();
    }
    esp_camera_fb_return(fb);
}

Python代码

cam = serial.Serial(
    port='COM7',
    baudrate=2000000,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS,
    timeout=0
)

cam.close()

cam.setDTR(False)
cam.setRTS(False)
cam.open()

for _ in range(5):
    # cam.close()
    # cam.open()
    print(cam.readline())

排查建议

  • 调整串口超时设置:当前timeout=0为非阻塞模式,会立即返回空值。建议改为timeout=2或更大值,给串口足够时间接收完整数据行。
  • 修正串口初始化流程:先设置DTR/RTS参数,再打开串口,避免重复开关导致状态异常。
  • 增加读取次数:原代码仅循环读取5次,可能还未接收到数据就结束。改为持续循环读取,或增加循环次数。
  • 明确关闭硬件流控:在Python串口初始化中添加xonxoff=False、rtscts=False、dsrdtr=False,确保硬件流控完全关闭。
  • 校验换行符一致性:ESP32发送的换行符为\n,Python的readline()默认以此为分隔符,若传输中出现丢失,可尝试读取所有字节后手动按\n分割。

调整后的Python示例代码

import serial

cam = serial.Serial(
    port='COM7',
    baudrate=2000000,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS,
    timeout=2,
    xonxoff=False,
    rtscts=False,
    dsrdtr=False
)

cam.setDTR(False)
cam.setRTS(False)

if not cam.is_open:
    cam.open()

try:
    while True:
        line = cam.readline()
        if line:
            print(line)
finally:
    cam.close()

内容的提问来源于stack exchange,提问作者shin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 02:06:35