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

Arduino经Python Socket传空文件致Matplotlib绘图崩溃问题排查

解决Arduino-Socket传输空文件导致Matplotlib崩溃的问题

我之前做类似的Arduino-PC数据传输项目时,也碰到过空文件导致绘图崩溃的问题,咱们从几个维度来排查和解决:

一、先堵上Socket传输的漏洞

空文件的核心原因要么是Arduino没发数据/发了空数据,要么是Python接收端没做校验直接写入,先从这两块入手:

1. Python接收端加数据校验

不要直接把接收到的内容写入文件,先判断数据是否有效,空数据直接跳过,甚至记录错误日志:

import socket

HOST = "你的PC IP"
PORT = 12345  # 自定义端口

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind((HOST, PORT))
    s.listen()
    conn, addr = s.accept()
    with conn:
        print(f"已连接 {addr}")
        data = conn.recv(1024).decode('utf-8').strip()
        # 核心校验:数据为空就跳过写入
        if not data:
            print(f"从{addr}接收到空数据,跳过写入")
            conn.sendall(b"FAIL")  # 告诉Arduino发送失败
            return
        # 写入日志文件
        with open("sensor_log.txt", "a", encoding="utf-8") as f:
            f.write(data + "\n")
        conn.sendall(b"OK")  # 发送确认信号给Arduino

2. Arduino端加发送确认机制

让Arduino知道数据确实被PC接收了,避免重复发送或者发送空内容:

#include <WiFi.h>  // 用WiFi模块的话,Ethernet模块类似

const char* ssid = "你的WiFi名";
const char* password = "WiFi密码";
const char* serverIP = "你的PC IP";
const uint16_t serverPort = 12345;

WiFiClient client;

void setup() {
    Serial.begin(115200);
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("\nWiFi连接成功");
}

void loop() {
    // 如果没连接上PC,先重连
    if (!client.connected()) {
        Serial.println("尝试连接PC...");
        if (client.connect(serverIP, serverPort)) {
            Serial.println("连接PC成功");
        } else {
            delay(2000);
            return;
        }
    }

    // 准备要发送的数据(替换成你的实际数据)
    String sensorData = String(millis()) + "," + String(analogRead(A0));
    client.println(sensorData);

    // 等待PC的确认信号,超时就重连
    unsigned long timeout = millis();
    while (!client.available()) {
        if (millis() - timeout > 3000) {
            Serial.println("等待确认超时,断开重连");
            client.stop();
            delay(1000);
            return;
        }
    }

    // 读取确认信号
    String ack = client.readStringUntil('\n');
    if (ack.trim() == "OK") {
        Serial.println("数据发送成功");
    } else {
        Serial.println("数据发送失败,重试");
    }

    delay(1000);  // 调整发送间隔
}

二、修复批处理循环的隐患

批处理循环运行Python脚本时,容易出现前一个Socket进程没完全关闭,新进程端口被占用的问题,导致连接异常:

修改你的批处理脚本,先清理旧进程再启动:

@echo off
set "PY_SCRIPT=your_socket_receiver.py"  # 替换成你的Python脚本名

:LOOP
:: 杀掉之前的Python进程(避免端口占用)
taskkill /f /im python.exe >nul 2>&1
:: 等待2秒确保进程完全退出
timeout /t 2 /nobreak >nul
:: 启动接收脚本
python "%PY_SCRIPT%"
:: 脚本退出后循环重启
goto LOOP

三、给Matplotlib加“防崩”逻辑

就算前面的步骤都做了,还是可能有漏网的空日志,直接在绘图前做校验:

import matplotlib.pyplot as plt

def load_log_data(file_path):
    valid_data = []
    with open(file_path, "r", encoding="utf-8") as f:
        for line_num, line in enumerate(f, 1):
            line = line.strip()
            if not line:
                print(f"第{line_num}行为空,跳过")
                continue
            # 根据你的日志格式解析,比如CSV格式拆分
            try:
                timestamp, value = line.split(",")
                valid_data.append(float(value))
            except Exception as e:
                print(f"第{line_num}行数据无效:{e},跳过")
    return valid_data

# 加载数据并绘图
log_data = load_log_data("sensor_log.txt")
if not log_data:
    print("日志中无有效数据,不绘图")
else:
    plt.plot(log_data)
    plt.title("Sensor Data Log")
    plt.xlabel("Sample Index")
    plt.ylabel("Value")
    plt.show()

四、额外排查点

  • 检查Arduino的网络稳定性:如果用WiFi,看看信号强度(WiFi.RSSI()),信号弱容易丢包;
  • 给Python Socket加超时:在s.listen()后加s.settimeout(10),避免进程一直卡在等待连接的状态;
  • 查看Serial Monitor:Arduino端的串口日志能帮你快速定位是连接失败还是发送失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:33:05