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

基于Arduino与Python的串口读写故障排查求助

问题分析与解决方案

核心问题

  1. 波特率不匹配:Python脚本设置的波特率是38400,但Arduino代码里是9600,串口通信必须两端波特率完全一致,否则会出现通信乱码或阻塞。
  2. Arduino未处理控制指令:Python发送的s(开始)和e(停止)指令,Arduino代码完全没有对应的处理逻辑,导致指令无效。
  3. Python文件写入未刷新缓冲区:默认情况下文件写入是缓冲的,若不手动刷新,数据可能不会实时写入文件,甚至程序异常退出时丢失数据。
  4. out_dir未赋值:Python代码中out_dir = # some generic path是无效语句,需要指定实际输出目录。

修正后的Python代码

# -----------------------------------------------------------------------------
# Import Standard Libraries
# -----------------------------------------------------------------------------
import numpy as np
import serial
import time
import os

# -----------------------------------------------------------------------------
# Definition of Directories
# -----------------------------------------------------------------------------
out_dir = "./imu_data"  # 替换为你的实际输出目录,不存在则自动创建
os.makedirs(out_dir, exist_ok=True)

# -----------------------------------------------------------------------------
# Definition of Parameters
# -----------------------------------------------------------------------------
# Serial Port
port = 'COM4'          # Arduino Serial Port
b_rate = 9600          # 和Arduino保持一致的波特率

# Test
T = 5                  # Test Time (s)
test_id = 'A_0456_001' # Test ID

# -----------------------------------------------------------------------------
# Open Serial Port
# -----------------------------------------------------------------------------
ard = serial.Serial(port, b_rate, timeout=1)  # 添加timeout避免readline无限阻塞
time.sleep(2)  # 延长等待时间,给Arduino重启和初始化留足时间

# -----------------------------------------------------------------------------
# Acquire Data
# -----------------------------------------------------------------------------
# Create Output Text File
out_path = os.path.join(out_dir, test_id + '.txt')
if os.path.exists(out_path):
    os.remove(out_path)

# 使用with语句自动管理文件,无需手动close
with open(out_path, 'w') as out_file:
    # 发送开始指令
    ard.write(b's')  # 直接用bytes字面量更简洁
    print('Data acquisition started...')
    time.sleep(1)

    t_0 = time.time_ns()
    t_c = t_0
    p_count = 0

    while t_c < t_0 + T * 10**9:
        # Write Header
        if p_count == 0:
            header = 'System Time, Type, ard_time, x, y, z'
            out_file.write(header + '\n')
            out_file.flush()  # 立即写入文件

        # Read Serial
        s_line = ard.readline().decode('utf-8').strip()  # 解码为字符串并去除首尾空白
        if not s_line:  # 如果读取为空(超时),跳过本次循环
            t_c = time.time_ns()
            continue

        t_c = time.time_ns()  # High precision time

        # 解析Arduino输出的"ard_time\tX\tY\tZ"格式
        data_parts = s_line.split('\t')
        if len(data_parts) == 4:
            data_line = f"{t_c},ACC,{data_parts[0]},{data_parts[1]},{data_parts[2]},{data_parts[3]}"
            out_file.write(data_line + '\n')
            out_file.flush()  # 立即写入文件

        p_count += 1

    print('Data acquisition ended.')

# Send stop command and close serial
ard.write(b'e')
ard.close()

修正后的Arduino代码

添加控制指令处理逻辑,同时输出Arduino本地时间用于同步:

#include <Arduino_LSM6DS3.h>

bool isRunning = false;  // 控制数据输出的标志位
unsigned long startTime;

void setup() {
  Serial.begin(9600);
  while (!Serial);

  if (!IMU.begin()) {
    Serial.println("Failed to initialize IMU!");
    while (1);
  }

  Serial.print("Accelerometer sample rate = ");
  Serial.print(IMU.accelerationSampleRate());
  Serial.println(" Hz");
  Serial.println();
  Serial.println("Acceleration in G's");
  Serial.println("X\tY\tZ");
}

void loop() {
  // 处理串口指令
  if (Serial.available() > 0) {
    char cmd = Serial.read();
    if (cmd == 's') {
      isRunning = true;
      startTime = millis();  // 记录开始时间
    } else if (cmd == 'e') {
      isRunning = false;
    }
  }

  // 仅在允许输出时发送数据
  if (isRunning && IMU.accelerationAvailable()) {
    float x, y, z;
    IMU.readAcceleration(x, y, z);

    // 输出格式:本地相对时间(ms)\tX\tY\tZ
    Serial.print(millis() - startTime);
    Serial.print('\t');
    Serial.print(x, 5);
    Serial.print('\t');
    Serial.print(y, 5);
    Serial.print('\t');
    Serial.println(z, 5);
  }
}

额外注意事项

  • 确保Arduino上传代码后,先关闭串口监视器再运行Python脚本,避免串口被占用。
  • Python的serial库需要提前安装:pip install pyserial。
  • 如果仍出现阻塞问题,可以尝试调整串口的timeout参数,或增加time.sleep()的等待时长。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 11:24:58