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

基于Arduino与Node.js(Serial Port)的设备连接监听方案咨询

解决Arduino与Node.js SerialPort的事件化连接监听问题

方案1:基于SerialPort本身实现事件化连接/重连(无额外依赖)

不需要定时轮询,通过主动尝试连接+事件监听来实现状态管理,断开后自动重试:

const { SerialPort } = require('serialport');

// 你的Arduino串口序列号
const TARGET_SERIAL = "YS72404M0284";
let arduinoPort = null;

async function connectArduino() {
  // 查找目标端口
  const ports = await SerialPort.list();
  const targetPort = ports.find(port => port.serialNumber === TARGET_SERIAL);

  if (!targetPort) {
    console.log("Arduino未连接,2秒后重试...");
    setTimeout(connectArduino, 2000);
    return;
  }

  // 初始化串口实例
  arduinoPort = new SerialPort({
    path: targetPort.path,
    baudRate: 9600, // 匹配你的Arduino波特率
    autoOpen: false
  });

  // 监听连接成功事件
  arduinoPort.on('open', () => {
    console.log("Arduino已连接,开始读取编码器数据");
    // 这里添加编码器数据处理逻辑
    arduinoPort.on('data', (data) => {
      console.log("收到编码器脉冲:", data.toString().trim());
    });
  });

  // 监听断开事件
  arduinoPort.on('close', () => {
    console.log("Arduino断开连接,重新尝试连接");
    arduinoPort = null;
    connectArduino();
  });

  // 监听错误事件
  arduinoPort.on('error', (err) => {
    console.error("串口错误:", err.message);
    if (arduinoPort) arduinoPort.close();
    setTimeout(connectArduino, 2000);
  });

  // 尝试打开串口
  try {
    await arduinoPort.open();
  } catch (err) {
    console.error("打开串口失败:", err.message);
    setTimeout(connectArduino, 2000);
  }
}

// 启动连接流程
connectArduino();

方案2:基于USB硬件事件触发检查(低资源占用)

通过监听系统USB设备的插拔事件,仅当硬件状态变化时才检查目标串口,避免无效查询:

首先安装依赖:

npm install usb-detection

代码示例:

const { SerialPort } = require('serialport');
const usbDetect = require('usb-detection');

const TARGET_SERIAL = "YS72404M0284";
let arduinoPort = null;

// 检查并维护Arduino连接状态
async function syncArduinoConnection() {
  const ports = await SerialPort.list();
  const targetPort = ports.find(port => port.serialNumber === TARGET_SERIAL);

  // 设备已连接且未建立串口
  if (targetPort && !arduinoPort) {
    arduinoPort = new SerialPort({
      path: targetPort.path,
      baudRate: 9600
    });

    arduinoPort.on('open', () => {
      console.log("Arduino连接成功");
      arduinoPort.on('data', (data) => {
        console.log("编码器数据:", data.toString().trim());
      });
    });

    arduinoPort.on('close', () => {
      console.log("Arduino断开");
      arduinoPort = null;
    });

    arduinoPort.on('error', (err) => {
      console.error("串口异常:", err.message);
      arduinoPort = null;
    });
  } 
  // 设备已断开但串口仍存在
  else if (!targetPort && arduinoPort) {
    arduinoPort.close();
  }
}

// 启动USB监听
usbDetect.startMonitoring();

// 监听设备插入
usbDetect.on('add', async () => {
  console.log("检测到USB设备插入,检查目标Arduino");
  await syncArduinoConnection();
});

// 监听设备移除
usbDetect.on('remove', async () => {
  console.log("检测到USB设备移除,检查目标Arduino");
  await syncArduinoConnection();
});

// 程序启动时初始化检查
syncArduinoConnection();

// 程序退出时清理资源
process.on('exit', () => {
  usbDetect.stopMonitoring();
  if (arduinoPort) arduinoPort.close();
});

方案对比

  • 方案1:无需额外依赖,逻辑简洁,适合大多数场景,通过退避重试避免频繁查询,比定时轮询高效。
  • 方案2:利用系统硬件事件触发检查,资源占用极低,适合对性能敏感的场景,但需要安装第三方依赖。

核心思路是用事件驱动替代定时轮询,只有当连接状态发生变化时才执行对应逻辑,彻底解决轮询的实用性问题。

内容的提问来源于stack exchange,提问作者user19574730

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 11:17:48