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
相关产品推荐
相关产品推荐

