基于Arduino与Python的串口读写故障排查求助
问题分析与解决方案
核心问题
- 波特率不匹配:Python脚本设置的波特率是
38400,但Arduino代码里是9600,串口通信必须两端波特率完全一致,否则会出现通信乱码或阻塞。 - Arduino未处理控制指令:Python发送的
s(开始)和e(停止)指令,Arduino代码完全没有对应的处理逻辑,导致指令无效。 - Python文件写入未刷新缓冲区:默认情况下文件写入是缓冲的,若不手动刷新,数据可能不会实时写入文件,甚至程序异常退出时丢失数据。
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
相关产品推荐
相关产品推荐

