R包serial因EOL字符截断导致串口数据乱码的技术问询
解决R包serial中EOL截断导致的串口数据粘连问题
问题背景
R包serial提供跨系统串口通信接口,但其read.serialConnection函数会根据translation设置截断换行符(\n/\r),引发数据粘连异常。例如接收Arduino发送的系统毫秒数时,会出现"157615831589"这类多个数值粘连的情况,经确认是EOL字符截断导致,而非数据流本身问题。
涉及代码
Arduino发送脚本
void setup() { Serial.begin(9600); } void loop() { Serial.println(millis()); }
原R接收脚本
library(serial) device = "ttyACM0" # 根据系统修改设备名 speed=9600 connection <- serialConnection("arduino", device, mode=paste0(speed,",n,8,1"), translation = "auto") # 备选值"crlf" open(connection) start_time <- as.numeric(Sys.time())*1000 while (as.numeric(Sys.time())*1000 < start_time+2500) { tmp <- read.serialConnection(connection) if (tmp != "") { print(tmp) } } close(connection)
解决方案
方法1:禁用自动翻译,手动处理行结束符
将translation设为"raw",让函数不截断任何字符,自行在R中维护缓冲区并分割完整行:
library(serial) device = "ttyACM0" speed=9600 # 设置translation为raw,不处理任何字符 connection <- serialConnection("arduino", device, mode=paste0(speed,",n,8,1"), translation = "raw") open(connection) start_time <- as.numeric(Sys.time())*1000 buffer <- "" # 定义缓冲区存储未处理的原始数据 while (as.numeric(Sys.time())*1000 < start_time+2500) { tmp <- read.serialConnection(connection) if (tmp != "") { buffer <- paste0(buffer, tmp) # 按换行符分割缓冲区中的数据 lines <- strsplit(buffer, "\r\n|\n|\r")[[1]] # 最后一个元素可能是未完成的行,重新存入缓冲区 buffer <- lines[length(lines)] # 输出所有完整的行 for (line in lines[-length(lines)]) { if (line != "") print(line) } } } close(connection)
方法2:明确指定匹配Arduino的行结束符
Arduino的Serial.println()默认发送\r\n(CRLF)作为行结束符,将translation设为"crlf",让函数正确识别并分割行,避免截断导致的粘连:
library(serial) device = "ttyACM0" speed=9600 # 指定translation为crlf,匹配Arduino的行结束符 connection <- serialConnection("arduino", device, mode=paste0(speed,",n,8,1"), translation = "crlf") open(connection) start_time <- as.numeric(Sys.time())*1000 while (as.numeric(Sys.time())*1000 < start_time+2500) { tmp <- read.serialConnection(connection) if (tmp != "") { print(tmp) } } close(connection)
方法3:使用固定长度读取(适用于已知数据长度场景)
如果能确定发送数据的固定长度(比如millis()在一段时间内是固定位数),可以指定read.serialConnection的n参数读取固定长度,再拼接处理:
library(serial) device = "ttyACM0" speed=9600 connection <- serialConnection("arduino", device, mode=paste0(speed,",n,8,1"), translation = "raw") open(connection) start_time <- as.numeric(Sys.time())*1000 while (as.numeric(Sys.time())*1000 < start_time+2500) { # 假设每次发送的数值+换行符共7位(比如4位数字+\r\n),根据实际调整 tmp <- read.serialConnection(connection, n=7) if (tmp != "") { # 提取数值部分,去掉换行符 value <- gsub("\r\n|\n|\r", "", tmp) print(value) } } close(connection)
内容的提问来源于stack exchange,提问作者Søren ONeill
相关产品推荐
相关产品推荐

