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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 03:22:21