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

基于p5.js与Arduino的蚀刻素描项目故障求助

p5.js + Arduino 蚀刻素描(Etch-a-Sketch)故障修复方案

问题背景

使用p5.js与Arduino制作蚀刻素描装置,硬件包含2个电位器(控制XY轴绘图)和1个按钮(清除画布)。已完成Node.js及串口库安装,Arduino可读取电位器值并在IDE、p5.js中正常显示,但存在两个核心问题:

  • 按钮按下无清除画布反应
  • p5.js运行后初始绘图点几秒后飞出画布边界

故障排查与修复

1. 按钮无响应问题

核心原因

  • 按钮未做消抖处理,导致串口发送的状态信号不稳定
  • Arduino与p5.js之间的串口数据格式不统一,前端无法正确解析按钮状态
  • 按钮接线未使用上拉/下拉电阻,信号存在干扰

修复后的Arduino代码(含消抖+统一数据格式)

const int potXPin = A0;
const int potYPin = A1;
const int clearBtnPin = 2;

int lastBtnState = HIGH;
int currentBtnState;
unsigned long debounceTimer = 0;
const unsigned long debounceDelay = 50; // 50ms消抖延迟

void setup() {
  Serial.begin(9600);
  pinMode(clearBtnPin, INPUT_PULLUP); // 启用内部上拉电阻,无需外接电阻
}

void loop() {
  // 读取并映射电位器值到画布尺寸范围(0-400)
  int xValue = map(analogRead(potXPin), 0, 1023, 0, 400);
  int yValue = map(analogRead(potYPin), 0, 1023, 0, 400);

  // 按钮消抖逻辑
  currentBtnState = digitalRead(clearBtnPin);
  if (currentBtnState != lastBtnState) {
    debounceTimer = millis();
  }
  if ((millis() - debounceTimer) > debounceDelay) {
    if (currentBtnState != lastBtnState) {
      lastBtnState = currentBtnState;
    }
  }

  // 统一发送格式:x坐标,y坐标,按钮状态(1=按下,0=未按下)
  Serial.print(xValue);
  Serial.print(",");
  Serial.print(yValue);
  Serial.print(",");
  Serial.println(lastBtnState == LOW ? 1 : 0);

  delay(10); // 降低串口发送频率,避免数据堆积
}

2. 绘图点飞出画布问题

核心原因

  • p5.js初始化时未设置有效初始坐标,串口未稳定时读取到异常值
  • 未对读取到的坐标值做边界限制,导致超出画布范围

修复后的p5.js代码(初始坐标设置+边界校验)

let serial;
const portPath = '/dev/tty.usbmodem14101'; // 替换为你的Arduino串口端口
let currentX, currentY;
let prevX, prevY;
let shouldClear = false;

function setup() {
  createCanvas(400, 400);
  background(255);
  
  // 初始化坐标为画布中心,避免初始异常
  currentX = width / 2;
  currentY = height / 2;
  prevX = currentX;
  prevY = currentY;

  // 初始化串口连接
  serial = new p5.SerialPort();
  serial.open(portPath);
  serial.on('data', handleSerialData);
  serial.on('error', err => console.error('串口错误:', err));
}

function draw() {
  // 处理画布清除
  if (shouldClear) {
    background(255);
    shouldClear = false;
    // 清除后重置坐标到中心
    currentX = width / 2;
    currentY = height / 2;
    prevX = currentX;
    prevY = currentY;
  }

  // 仅在坐标变化时绘制线条,减少冗余绘制
  if (currentX !== prevX || currentY !== prevY) {
    stroke(0);
    strokeWeight(2);
    line(prevX, prevY, currentX, currentY);
    prevX = currentX;
    prevY = currentY;
  }
}

function handleSerialData() {
  const rawData = serial.readStringUntil('\n');
  if (!rawData) return;
  
  const cleanData = trim(rawData);
  const dataArray = cleanData.split(',');
  
  // 校验数据格式,确保是3个有效数值
  if (dataArray.length !== 3) return;
  
  // 解析并限制坐标在画布范围内
  currentX = constrain(parseInt(dataArray[0]), 0, width);
  currentY = constrain(parseInt(dataArray[1]), 0, height);
  
  // 触发画布清除
  if (parseInt(dataArray[2]) === 1) {
    shouldClear = true;
  }
}

硬件接线确认

  • 电位器:一端接5V,一端接GND,中间信号引脚分别接A0(X轴)、A1(Y轴)
  • 按钮:一端接GND,另一端接数字引脚2(依赖Arduino内部上拉电阻,无需额外外接电阻)

内容的提问来源于stack exchange,提问作者K-PopCorn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 07:04:52