【发布时间】:2018-04-08 16:40:33
【问题描述】:
我必须编写一个 java 程序,通过网络接收 G-Code 命令并通过串行通信将它们发送到 3D 打印机。原则上一切似乎都很好,只要打印机需要超过 300 毫秒来执行命令。如果执行时间比这短,打印机接收下一个命令需要太多时间,导致命令执行之间出现延迟(打印机喷嘴静止约 100-200 毫秒)。这可能会成为 3D 打印的问题,因此我必须消除这种延迟。
为了比较:像 Repetier Host 或 Cura 这样的软件可以通过 seial 发送相同的命令,在命令执行之间没有任何延迟,所以它必须以某种方式成为可能。
我使用jSerialComm 库进行串行通信。
这是向打印机发送命令的线程:
@Override
public void run() {
if(printer == null) return;
log("Printer Thread started!");
//wait just in case
Main.sleep(3000);
long last = 0;
while(true) {
String cmd = printer.cmdQueue.poll();
if (cmd != null && !cmd.equals("") && !cmd.equals("\n")) {
log(cmd+" last: "+(System.currentTimeMillis()-last)+"ms");
last = System.currentTimeMillis();
send(cmd + "\n", 0);
}
}
}
private void send(String cmd, int timeout) {
printer.serialWrite(cmd);
waitForBuffer(timeout);
}
private void waitForBuffer(int timeout) {
if(!blockForOK(timeout))
log("OK Timeout ("+timeout+"ms)");
}
public boolean blockForOK(int timeoutMillis) {
long millis = System.currentTimeMillis();
while(!printer.bufferAvailable) {
if(timeoutMillis != 0)
if(millis + timeoutMillis < System.currentTimeMillis()) return false;
try {
sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
printer.bufferAvailable = false;
return true;
}
这是printer.serialWrite:(Arduino Java Lib 的“灵感”)
public void serialWrite(String s){
comPort.setComPortTimeouts(SerialPort.TIMEOUT_SCANNER, 0, 500);
try{Thread.sleep(5);} catch(Exception e){}
PrintWriter pout = new PrintWriter(comPort.getOutputStream());
pout.print(s);
pout.flush();
}
printer 是类 Printer 的对象,它实现了 com.fazecast.jSerialComm.SerialPortDataListener
打印机相关功能
@Override
public int getListeningEvents() {
return SerialPort.LISTENING_EVENT_DATA_AVAILABLE;
}
@Override
public void serialEvent(SerialPortEvent serialPortEvent) {
byte[] newData = new byte[comPort.bytesAvailable()];
int numRead = comPort.readBytes(newData, newData.length);
handleData(new String(newData));
}
private void handleData(String line) {
//log("RX: "+line);
if(line.contains("ok")) {
bufferAvailable = true;
}
if(line.contains("T:")) {
printerThread.printer.temperature[0] = Utils.readFloat(line.substring(line.indexOf("T:")+2));
}
if(line.contains("T0:")) {
printerThread.printer.temperature[0] = Utils.readFloat(line.substring(line.indexOf("T0:")+3));
}
if(line.contains("T1:")) {
printerThread.printer.temperature[1] = Utils.readFloat(line.substring(line.indexOf("T1:")+3));
}
if(line.contains("T2:")) {
printerThread.printer.temperature[2] = Utils.readFloat(line.substring(line.indexOf("T2:")+3));
}
}
Printer.bufferAvailable 被声明为 volatile
我还尝试在另一个线程中阻塞 jserialcomm 的函数,结果相同。
我的瓶颈在哪里?我的代码是否存在瓶颈,或者 jserialcomm 是否会产生太多开销?
对于那些没有 3D 打印经验的人:
当打印机接收到有效命令时,它将将该命令放入内部缓冲区以最大限度地减少延迟。只要内部缓冲区中有可用空间,它就会回复ok。当缓冲区已满时,ok 会延迟,直到再次有空闲空间。
所以基本上你只需要发送一个命令,等待ok,立即发送另一个。
【问题讨论】:
-
“我的瓶颈在哪里?” -- 我不懂 Java,但我在 blockForOK() 中看到了
sleep(1)常规。这意味着您的代码不是事件驱动的,而是轮询(以一秒的速度?),因此它不会非常敏感。最坏的情况是等待条件测试为真,但在测试后立即变为假,因此在最终识别出继续条件之前已经过了完整的延迟间隔(1000 毫秒?)。您的平均响应延迟为 500 毫秒? -
sleep(1)会导致 1 毫秒 的延迟,而不是 1000 毫秒。另外,我尝试过事件驱动的代码,它不能消除延迟。 -
哇,我的学位也遇到了同样的问题,我从没想过其他人也会遇到这个问题……但对我来说,事件驱动的解决方案运行良好。你能包括你的代码吗?
-
感谢您的意见!业务逻辑到底是什么意思?如果您的意思是调用发送的部分(目前在“打印机线程”的“运行”中),我认为可以给我更多的延迟,因为仅在从打印机收到命令时才调用 handleData()。但另一方面,我真的应该尝试一下。
标签: java serial-port serial-communication 3d-printing