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 ); }
问题分析与修复方案
核心问题点
- Enter键触发失效:ControlP5的
ACTION_ENTER回调存在触发不稳定的情况,且发送的发射码未添加换行符,Arduino端用readStringUntil('\n')读取,无法识别完整指令。 - 随机发送问题:未对串口连接状态做校验,可能在未连接时误触发发送;同时温湿度数据解析逻辑有漏洞,可能导致串口缓存混乱引发误触发。
修复后的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
相关产品推荐
相关产品推荐

