如何使用writerow将Arduino传入PsychoPy的带时间戳整数流写入CSV?
解决Arduino整数流无法写入PsychoPy CSV的问题
嘿,我来帮你搞定这个困扰!你说print(port.readline())能正常收到Arduino的整数,但CSV里只有时间戳,大概率是数据读取后的处理环节或者CSV写入逻辑出了小疏漏,咱们一步步拆解解决:
核心问题分析
port.readline()返回的是bytes类型的数据(比如b'123\r\n'),如果直接转整数或者写入CSV,要么会报错,要么写入的是无法识别的字节内容,最终导致整数没被正确记录。另外,Arduino输出的内容通常会带换行符(\r\n),需要先清理掉才能转成有效的整数。
分步解决方案
1. 正确处理Arduino的输入数据
首先要把读取到的字节数据解码成字符串,去掉多余的换行/空格,再转成整数,还要处理可能的异常(比如Arduino输出了调试信息而非整数):
raw_data = port.readline() if raw_data: # 确保不是空数据 # 解码字节为字符串,清理首尾空白(包括换行符) clean_data = raw_data.decode('utf-8').strip() try: arduino_num = int(clean_data) # 转成整数 except ValueError: # 处理非整数数据,比如Arduino的串口调试信息 print(f"收到无效数据: {clean_data}") arduino_num = "无效数据" # 或者跳过写入
2. 确保CSV写入包含时间戳和整数
要保证每次写入CSV时,同时传入时间戳和处理后的整数,并且文件操作要规范(比如用csv.writer的writerow方法传入列表):
import csv from psychopy import clock # 初始化CSV文件(建议在实验开始前打开) with open('arduino_record.csv', 'w', newline='') as csv_file: writer = csv.writer(csv_file) # 先写入表头 writer.writerow(['timestamp', 'arduino_integer']) # 实验循环中持续读取和写入 while True: # 获取PsychoPy同步的时间戳(比系统时间更准确) current_time = clock.getTime() # 读取并处理Arduino数据(用上面的代码) raw_data = port.readline() arduino_num = None if raw_data: clean_data = raw_data.decode('utf-8').strip() try: arduino_num = int(clean_data) except ValueError: arduino_num = f"无效: {clean_data}" # 写入CSV:同时传入时间戳和整数 if arduino_num is not None: writer.writerow([current_time, arduino_num]) # 实验退出条件(比如按ESC键) # if event.getKeys(keyList=['escape']): # break
3. 串口初始化的关键细节
- 一定要加
timeout参数:serial.Serial('COMx', 9600, timeout=1),避免readline()阻塞整个实验流程 - 给Arduino留启动时间:初始化串口后加
core.wait(2),让Arduino完成重启后的初始化
完整示例代码
把上面的逻辑整合到PsychoPy的实验框架里,完整代码如下:
import serial import csv from psychopy import core, clock, event # 配置串口(替换成你的串口名称和波特率) port = serial.Serial('COM3', 9600, timeout=1) core.wait(2) # 等待Arduino启动 # 创建并打开CSV文件 with open('arduino_data.csv', 'w', newline='', encoding='utf-8') as f: csv_writer = csv.writer(f) csv_writer.writerow(['timestamp', 'arduino_integer']) # 写入表头 print("开始记录数据,按ESC退出...") while True: # 获取时间戳 timestamp = clock.getTime() # 读取Arduino数据 raw_input = port.readline() if raw_input: try: # 解码、清理、转整数 arduino_value = int(raw_input.decode('utf-8').strip()) # 写入CSV csv_writer.writerow([timestamp, arduino_value]) print(f"已记录: 时间戳={round(timestamp, 3)}, 整数={arduino_value}") except ValueError: # 记录无效数据 invalid_data = raw_input.decode('utf-8').strip() csv_writer.writerow([timestamp, f"无效数据: {invalid_data}"]) print(f"无效数据: {invalid_data}") # 检查退出按键 if event.getKeys(keyList=['escape']): print("停止记录,关闭串口...") break # 关闭串口 port.close() core.quit()
额外排查点
- 检查Arduino代码:确保用
Serial.println()输出整数(带换行符,让readline()能正确读取),而不是Serial.print() - 验证数据转换:在写入CSV前,用
print(type(arduino_num))确认是整数类型,而不是bytes或字符串 - 查看CSV文件:如果用Excel打开显示异常,试试用记事本打开,确认是否有隐藏的字节内容
内容的提问来源于stack exchange,提问作者Shravan Thaploo




