the*_*G27 6 java serial-port serial-communication 3d-printing
我必须编写一个java程序,通过网络接收G-Code命令,并通过串行通信将它们发送到3D打印机.原则上一切似乎都没问题,只要打印机需要超过300毫秒来执行命令.如果执行时间短于此时间,则打印机接收下一个命令需要花费太多时间,并且导致命令执行之间的延迟(打印机喷嘴静止约100-200ms).这可能会成为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;
}
Run Code Online (Sandbox Code Playgroud)
这是printer.serialWrite :( Arduino Java Lib的"Inspired")
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();
}
Run Code Online (Sandbox Code Playgroud)
printer是一个Printer实现 的类的Objectcom.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));
}
}
Run Code Online (Sandbox Code Playgroud)
Printer.bufferAvailable声明是volatile我也尝试在另一个线程中阻塞jserialcomm的函数,结果相同.我的瓶颈在哪里?我的代码中是否存在瓶颈或者jserialcomm是否会产生过多的开销?
对于那些没有3D打印经验的人:当打印机收到有效命令时,它会将该命令放入内部缓冲区以最大限度地减少延迟.只要内部缓冲区中有可用空间,它就会回复ok.当缓冲区已满时,ok会延迟,直到再次有空闲空间.所以基本上你只需要发送命令,等待确定,立即发送另一个命令.
@Override
public void serialEvent(SerialPortEvent serialPortEvent) {
byte[] newData = new byte[comPort.bytesAvailable()];
int numRead = comPort.readBytes(newData, newData.length);
handleData(new String(newData));
}
Run Code Online (Sandbox Code Playgroud)
这部分是有问题的,该事件可能在读取整行之前就已触发,因此可能只读取了一半ok,因此可能只收到了在尝试将其解析为完整消息之前,您需要先缓冲(针对多个事件)并重新组装成消息。
最坏的情况,这可能会导致温度读数完全丢失或ok消息完全丢失,因为它们被撕成两半。
请参阅InputStream 示例并将其包装在 a 中BufferedReader以访问BufferedReader::readLine(). 就位后BufferedReader,您可以使用它直接在主线程中轮询并同步处理响应。
try{Thread.sleep(5);} catch(Exception e){}
sleep(1);
Run Code Online (Sandbox Code Playgroud)
你不想睡觉。根据您的系统环境(我强烈假设这不是在 x86 上的 Windows 上运行,而是在嵌入式平台上的 Linux 上运行), asleep可能比预期长得多。最多 30 毫秒或 100 毫秒,具体取决于内核配置。
首先,写入之前的睡眠没有多大意义,您知道串行端口已准备好写入,因为您已经收到了ok先前发送的命令的确认接收。
使用 时,接收期间的睡眠变得毫无意义BufferedReader。
comPort.setComPortTimeouts(SerialPort.TIMEOUT_SCANNER, 0, 500);
Run Code Online (Sandbox Code Playgroud)
这实际上导致了你的问题。SerialPort.TIMEOUT_SCANNER激活读取等待期。收到第一个字节后,它将至少再等待 100 毫秒,看看它是否会成为消息的一部分。因此,在它看到之后,ok它会在操作系统端内部等待 100 毫秒,然后才认为这就是全部了。
您需要SerialPort.TIMEOUT_READ_SEMI_BLOCKING低延迟,但是除非进行缓冲,否则第一段中预测的问题将会发生。
重复设置还会带来另一个问题,因为内部有200ms的睡眠Serialport::setComPortTimeouts。每个串行连接设置一次,仅此而已。
| 归档时间: |
|
| 查看次数: |
508 次 |
| 最近记录: |