串口控制Galvo Scanner高速运行时数值异常的技术求助
咱们先梳理下你遇到的核心困境:Python端加time.sleep(1)时系统能正常跑,但提速后振镜的Y坐标会随机跳变(变成200、20、1这类值),而你预期的是Y固定在2000,X从0到4095扫描一条直线。结合你贴的代码,我找到几个关键问题点,逐个修复应该就能解决:
1. Arduino变量初始化的低级错误
你看Arduino代码里的这段:
int integerFromPC = "";
这是严重错误!int类型变量不能赋值字符串字面量,这会让变量内存里存的是随机垃圾值,后续解析串口数据时必然会逻辑混乱,甚至直接导致数据错位。
修复方法:把这个变量初始化为0:
int integerFromPC = 0;
2. 串口数据格式不匹配,解析完全错位
你的Python发送代码生成的字符串格式是 <ON,,1,xxx,2000>(ON后面有两个连续逗号),但Arduino的parseData()是按逗号顺序分割:
- 第1段:
messageFromPC(取ON) - 第2段:
integerFromPC(取两个逗号之间的空字符串,atoi("")返回0) - 第3段:
integerFromPC2(取1) - 第4段:
integerFromPC3(取xxx,也就是你要的X坐标)
完全和你预期的integerFromPC2=X、integerFromPC3=Y错位了!
修复方法:调整Python发送的格式,去掉多余的逗号,改成和解析逻辑匹配的结构:
ard.write(('<').encode()) ard.write(('ON,').encode()) # 状态字符串 ard.write(setVal1.encode()) # 状态数字(1) ard.write((',').encode()) ard.write(setVal2.encode()) # X坐标 ard.write((',').encode()) ard.write(setVal3.encode()) # Y坐标 ard.write(('>').encode())
现在发送的格式是 <ON,1,xxx,2000>,和Arduino的解析逻辑完全对应,不会再出现数据错位。
3. SerToLaser()被重复调用,逻辑冲突
你的Arduinoloop()里已经调用了SerToLaser(),但在showParsedData()里又调用了一次。这意味着同一组串口数据会被处理两次,当发送速度变快时,很容易导致状态和坐标混乱,出现随机值。
修复方法:删掉showParsedData()里的SerToLaser();调用,只保留loop()里的一次即可。
4. OLED刷新优先于串口处理,导致数据堆积
你的loop()开头先执行OLED的刷新循环:
u8g.firstPage(); do { draw(); } while( u8g.nextPage() );
这个过程会占用不少时间,当Python发送速度加快时,串口缓冲区的数据会堆积甚至溢出,后续解析的数据就会错位或丢失,表现为Y坐标随机跳变。
优化方法:调整loop()的执行顺序,先处理串口数据,再刷新OLED:
void loop() { // 先处理串口数据 recvWithStartEndMarkers(); if (newData == true) { strcpy(tempChars, receivedChars); parseData(); showParsedData(); newData = false; } SerToLaser(); // 最后刷新OLED,根据状态选择显示内容 u8g.firstPage(); do { if (integerFromPC != 0) { draw2(); } else { draw(); } } while( u8g.nextPage() ); }
这样能优先处理串口数据,避免缓冲区堆积。
5. 波特率瓶颈
当前用的9600波特率可能不足以支撑高速数据传输,你可以尝试把波特率提高到115200:
- Arduino端修改:
Serial.begin(115200); - Python端修改:
ard = serial.Serial('com6',115200,timeout=5)
测试建议
修改完以上几点后,先把Python的time.sleep(1)改成time.sleep(0.01)或者更小的值测试,观察Y坐标是否稳定在2000。如果还有问题,可以在Arduino的recvWithStartEndMarkers()里加缓冲区溢出处理,比如当ndx >= numChars时重置接收状态,避免错误数据累积。
内容的提问来源于stack exchange,提问作者Gr5

