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

Processing中cP5文本框发射码无法按Enter发送至Arduino问题求助

地下发射井项目Processing串口控制问题求助

我和朋友正在开发带内置火箭的地下发射井项目,计划用Processing程序从PC端控制发射。Arduino代码运行完全正常,但Processing代码存在两个问题:

  • 按下Enter键时无法将文本框中的发射码发送至Arduino
  • 发射码会出现无规律的随机发送情况

当前Processing代码

import processing.serial.*;
import controlP5.*;

Serial arduinoPort;
ControlP5 cp5;
int textFieldWidth = 200;
int buttonWidth = 100;
String launchCode = "7tRfKp9Z";

void setup() {
  size(300, 400);
  cp5 = new ControlP5(this);
  
  // Add temperature and humidity displays
  cp5.addTextlabel("tempLabel")
     .setText("Temperature: ")
     .setPosition(50, 50)
     .setColorValue(0);
  
  cp5.addTextlabel("humidityLabel")
     .setText("Humidity: ")
     .setPosition(50, 70)
     .setColorValue(0);
  
  cp5.addTextfield("launchCode")
     .setPosition(50, 100)
     .setSize(textFieldWidth, 20)
     .addCallback(event -> {
        if (event.getAction() == ControlP5.ACTION_ENTER) {
          sendCode();
        }
      });
  
  cp5.addButton("launchButton")
     .setPosition(50, 130)
     .setSize(buttonWidth, 20)
     .setLabel("Launch")
     .setColorBackground(color(0, 255, 0));
  
  cp5.addButton("closeButton")
     .setPosition(50 + buttonWidth + 10, 130)
     .setSize(buttonWidth, 20)
     .setLabel("Close")
     .setColorBackground(color(255, 0, 0));
  
  // Add port selection dropdown
  DropdownList portList = cp5.addDropdownList("portList")
     .setPosition(50, 170)
     .setSize(textFieldWidth, 100);
  for (String port : Serial.list()) {
    portList.addItem(port, port);
  }
  
  // Connect to the selected port
  portList.addCallback(event -> {
    if (event.getAction() == ControlP5.ACTION_BROADCAST) {
      String portName = cp5.get(DropdownList.class, "portList").getItem((int)event.getController().getValue()).get("name").toString();
      if (arduinoPort != null) {
        arduinoPort.stop();
      }
      arduinoPort = new Serial(this, portName, 9600);
    }
  });

}

void draw() {
  background(255);
  // Update temperature and humidity displays
  if (arduinoPort != null && arduinoPort.available() > 0) {
    String input = arduinoPort.readStringUntil('\n');
    if (input != null) {
      input = input.trim();
      if (input.startsWith("T = ")) {
        float temp = parseFloat(input.substring(4));
        cp5.get(Textlabel.class, "tempLabel").setText(String.format("Temperature: %.1f", temp));
      } else if (input.startsWith("H = ")) {
        float humidity = parseFloat(input.substring(4));
        cp5.get(Textlabel.class, "humidityLabel").setText(String.format("Humidity: %.1f", humidity));
      }
    }
  }
}

void sendCode() {
  String codeInput = cp5.get(Textfield.class, "launchCode").getText().trim();
  println(codeInput);
  arduinoPort.write(codeInput);
}


void launchButton() {
  arduinoPort.write("launch\n");
}

void closeButton() {
  arduinoPort.write("close\n");
}

可用的Arduino参考代码

#include <Servo.h>
#include <dht_nonblocking.h>

#define DHT_SENSOR_TYPE DHT_TYPE_11

static const int DHT_SENSOR_PIN = 2;
DHT_nonblocking dht_sensor( DHT_SENSOR_PIN, DHT_SENSOR_TYPE );

#define IGNITION_PIN 7
#define NUM_HATCHES 1
#define HATCH_PINS {3}
#define HATCH_OPEN_ANGLE 90
#define HATCH_CLOSE_ANGLE 0
#define HATCH_SPEED 90

const String CODE = "7tRfKp9Z";
const String CLOSE_COMMAND = "close";
const String LAUNCH_COMMAND = "launch";

Servo hatches[NUM_HATCHES];
int hatchPins[NUM_HATCHES] = HATCH_PINS;

bool codeCorrect = false;

void setup() {
  Serial.begin(9600);
  pinMode(IGNITION_PIN, OUTPUT);
  for (int i = 0; i < NUM_HATCHES; i++) {
    hatches[i].attach(hatchPins[i]);
    pinMode(hatchPins[i], OUTPUT);
  }
}

void loop() {
  float temperature;
  float humidity;

  if( measure_environment( &temperature, &humidity ) == true ) {
    if (Serial.available() > 0) {
      Serial.print( "T = " );
      Serial.print( temperature, 1 );
      Serial.print( ", H = " );
      Serial.print( humidity, 1 );
    }
  }

  if (Serial.available() > 0) {
    String input = Serial.readStringUntil('\n');
    if (input == CODE) {
      openHatches();
    } else if (input == CLOSE_COMMAND) {
      closeHatches();
      digitalWrite(IGNITION_PIN, LOW);
    } else if (input == LAUNCH_COMMAND) {
      digitalWrite(IGNITION_PIN, HIGH);
      delay(3000);
      digitalWrite(IGNITION_PIN, LOW);
    }
  }
}

void openHatches() {
  for (int h = HATCH_CLOSE_ANGLE; h < HATCH_OPEN_ANGLE; h++){
    for (int i = 0; i < NUM_HATCHES; i++) {
      hatches[i].write(h);
    }
    int speed = map(HATCH_SPEED, 0, 100, 1000, 0);
    delay(speed);
  }
}

void closeHatches() {
  for (int h = HATCH_OPEN_ANGLE; h > HATCH_CLOSE_ANGLE; h--){
    for (int i = 0; i < NUM_HATCHES; i++) {
      hatches[i].write(h);
    }
    if (h > 30/100.0 * HATCH_OPEN_ANGLE) {
    } 
    else {
      int speed = map(HATCH_SPEED, 0, 100, 500, 0);
      delay(speed);
    }
  }
}

static bool measure_environment( float *temperature, float *humidity ) {
  static unsigned long measurement_timestamp = millis( );

  /* Measure once every four seconds. */
  if( millis( ) - measurement_timestamp > 3000ul ) {
    if( dht_sensor.measure( temperature, humidity ) == true ) {
      measurement_timestamp = millis( );
      return( true );
    }
  }

  return( false );
}

问题分析与修复方案

核心问题点

  1. Enter键触发失效:ControlP5的ACTION_ENTER回调存在触发不稳定的情况,且发送的发射码未添加换行符,Arduino端用readStringUntil('\n')读取,无法识别完整指令。
  2. 随机发送问题:未对串口连接状态做校验,可能在未连接时误触发发送;同时温湿度数据解析逻辑有漏洞,可能导致串口缓存混乱引发误触发。

修复后的Processing代码

import processing.serial.*;
import controlP5.*;

Serial arduinoPort;
ControlP5 cp5;
int textFieldWidth = 200;
int buttonWidth = 100;
String launchCode = "7tRfKp9Z";

void setup() {
  size(300, 400);
  cp5 = new ControlP5(this);
  
  // 温湿度显示标签
  cp5.addTextlabel("tempLabel")
     .setText("Temperature: ")
     .setPosition(50, 50)
     .setColorValue(0);
  
  cp5.addTextlabel("humidityLabel")
     .setText("Humidity: ")
     .setPosition(50, 70)
     .setColorValue(0);
  
  // 发射码输入框
  cp5.addTextfield("launchCode")
     .setPosition(50, 100)
     .setSize(textFieldWidth, 20)
     .setAutoClear(false);
  
  // 发射按钮
  cp5.addButton("launchButton")
     .setPosition(50, 130)
     .setSize(buttonWidth, 20)
     .setLabel("Launch")
     .setColorBackground(color(0, 255, 0));
  
  // 关闭按钮
  cp5.addButton("closeButton")
     .setPosition(50 + buttonWidth + 10, 130)
     .setSize(buttonWidth, 20)
     .setLabel("Close")
     .setColorBackground(color(255, 0, 0));
  
  // 串口选择下拉列表
  DropdownList portList = cp5.addDropdownList("portList")
     .setPosition(50, 170)
     .setSize(textFieldWidth, 100);
  for (String port : Serial.list()) {
    portList.addItem(port, port);
  }
  
  // 串口连接回调
  portList.addCallback(event -> {
    if (event.getAction() == ControlP5.ACTION_BROADCAST) {
      int selectedIndex = (int)event.getController().getValue();
      String portName = portList.getItem(selectedIndex).get("name").toString();
      if (arduinoPort != null) {
        arduinoPort.stop();
      }
      arduinoPort = new Serial(this, portName, 9600);
      delay(1000); // 延迟确保串口连接稳定
    }
  });

}

void draw() {
  background(255);
  // 更新温湿度显示
  if (arduinoPort != null && arduinoPort.available() > 0) {
    String input = arduinoPort.readStringUntil('\n');
    if (input != null) {
      input = input.trim();
      // 正确拆分Arduino发送的合并数据
      if (input.contains("T = ") && input.contains("H = ")) {
        String[] parts = input.split(", ");
        if (parts.length == 2) {
          float temp = parseFloat(parts[0].substring(4));
          cp5.get(Textlabel.class, "tempLabel").setText(String.format("Temperature: %.1f", temp));
          float humidity = parseFloat(parts[1].substring(4));
          cp5.get(Textlabel.class, "humidityLabel").setText(String.format("Humidity: %.1f", humidity));
        }
      }
    }
  }
}

// 全局键盘监听,处理Enter键发送
void keyPressed() {
  if (key == ENTER && cp5.get(Textfield.class, "launchCode").isFocus()) {
    sendCode();
  }
}

void sendCode() {
  if (arduinoPort == null) {
    println("请先连接串口");
    return;
  }
  String codeInput = cp5.get(Textfield.class, "launchCode").getText().trim();
  println("发送发射码: " + codeInput);
  arduinoPort.write(codeInput + "\n"); // 添加换行符匹配Arduino读取逻辑
}

void launchButton() {
  if (arduinoPort == null) {
    println("请先连接串口");
    return;
  }
  arduinoPort.write("launch\n");
}

void closeButton() {
  if (arduinoPort == null) {
    println("请先连接串口");
    return;
  }
  arduinoPort.write("close\n");
}

关键修复说明

  • 改用全局keyPressed()事件处理Enter键,确保输入框聚焦时才触发发送,稳定性更强
  • 所有串口发送的指令都添加\n,与Arduino端的readStringUntil('\n')逻辑匹配
  • 增加串口连接状态校验,避免未连接时触发发送导致错误
  • 优化温湿度数据解析逻辑,适配Arduino发送的合并格式,避免串口缓存混乱
  • 添加串口连接延迟,确保通信链路稳定

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 22:30:02