- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我必须编写一个 java 程序,通过网络接收 G 代码命令,并通过串行通信将它们发送到 3D 打印机。原则上一切似乎都没有问题,只要打印机需要超过 300ms 来执行一条命令。如果执行时间短于此,则打印机接收下一条命令需要花费太多时间,导致命令执行之间存在延迟(打印机喷嘴静止约 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
会延迟,直到再次有可用空间。所以基本上你只需要发送一个命令,等待确定,立即发送另一个命令。
最佳答案
@Override
public void serialEvent(SerialPortEvent serialPortEvent) {
byte[] newData = new byte[comPort.bytesAvailable()];
int numRead = comPort.readBytes(newData, newData.length);
handleData(new String(newData));
}
这部分有问题,事件可能在读取整行之前被触发,因此可能只收到了一半的ok
。在尝试将其解析为完整消息之前,您需要先缓冲(通过多个事件)并重新组合成消息。
最坏的情况是,这可能导致温度读数完全丢失或 ok
消息被撕成两半。
参见 InputStream example并将其包装在 BufferedReader
中以访问 BufferedReader::readLine()
。有了 BufferedReader
,您就可以直接在主线程中使用它来轮询并同步处理响应。
try{Thread.sleep(5);} catch(Exception e){}
sleep(1);
你不想 sleep 。根据您的系统环境(我强烈假设这不是在 x86 上的 Windows 上运行,而是在嵌入式平台上的 Linux 上运行),sleep
可能比预期的要长得多。最多 30 毫秒或 100 毫秒,具体取决于内核配置。
写入前的 sleep 首先没有多大意义,您知道串行端口已准备好写入,因为您已经收到确认接收到先前发送的命令的 ok
。
当使用 BufferedReader
时,接收期间的 hibernate 变得毫无意义。
comPort.setComPortTimeouts(SerialPort.TIMEOUT_SCANNER, 0, 500);
这实际上导致了您的问题。 SerialPort.TIMEOUT_SCANNER
激活读取等待时间。在接收到第一个字节后,它将至少再等待 100 毫秒以查看它是否会成为消息的一部分。因此,在它看到 ok
之后,它会在操作系统端内部等待 100 毫秒,然后才会认为这就是全部。
您需要 SerialPort.TIMEOUT_READ_SEMI_BLOCKING
以实现低延迟,但除非进行缓冲,否则会出现第一段中预测的问题。
重复设置还会导致又一个问题,因为在Serialport::setComPortTimeouts
内部有一个200ms 的 hibernate 。每个串行连接设置一次,仅此而已。
关于java - 如何与3D打印机正确通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49720214/
我有一个代理类,它接收请求并将请求发送到另一台服务器,获取响应并将其定向回原始请求者。我使用套接字连接到服务器并使用 Printwriter 对其进行写入。像这样的事情 private Pri
我想使用 Java Swing 为医疗商店开发一个独立的应用程序。强制要求在没有打印对话框的情况下单击一下即可打印小尺寸(219 毫米至 140 毫米)的纸张。他们需要间歇性地将报告从不同的打印机打印
我是一名学生,需要创建一个 silten 打印功能,希望能够打印 PDF。这个需要基于Java。 我在 Google 上搜索并找到了一个无需对话框即可打印的代码。但如果源是 .txt 文件,它就会正确
我正在寻找 POS 打印的解决方案。 场景是: 一家餐厅目前有一个 POS 系统启动并运行,他们从店内的 iPad 上接受订单,并有一个网络设置来处理订单并在厨房的热敏打印机上自动打印出来(很酷,对吧
尝试使用以下代码示例,它在 WinForm 应用程序中运行良好,但在 VSTO 中运行不佳。是否有某种允许访问的权限? 可以设置默认打印机,但不能获取或设置打印机设置。 从插件中获取以下异常: Sys
我必须通过蓝牙将字体文件发送到我的打印机 Zebra RW420。我正在使用 Zebra Windows Mobile SDK,但无法找到任何方式将其发送和存储在打印机上。我可以通过 Label Vi
我需要创建一个“粉碎”的虚拟打印机 基本上这是我的问题。我有一个软件程序需要在保存文件之前“打印”文件。我希望能够打印到我的碎纸机,以便它保存文档,但实际上我不想打印文档。所以我需要打印到一个程序,该
我在吃 Argox 标签打印机时遇到了麻烦,只是仍然无法向她发送任何内容。型号为 Argox OS214 tt,ANPP,接受 PPLB。 使用通用类连接串行设备,我将她用于多个财务打印机和秤,附后。
我正在编写一些在 org.eclipse.swt.printing.Printer 上打印的代码。所以第一步是看看我如何测试它,但似乎架构不允许我定义自己的打印机,因为 PrinterData 和 P
我有一个标签列表,数据如下。 ['id', 'Version', 'chip_name', 'xversion', 'device', 'opt_param', 'place_effort'][1,
我正在开发一个应用程序,在该应用程序中,我通过 IP 地址和端口号从我的手机向 WiFi 打印机发送文件,这些文件是 .txt、.png、.jpg、.doc。它们应该从打印机打印出来。我尝试了以下代码
我正在尝试使用以下代码打印图像,但文档只是停留在打印作业队列中,拒绝打印。在 (windows) 打印作业队列中,我得到: DocumentName: Printing an image Status
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: Print preview ZPL II commands using .NET WinForm befor
我有什么 我目前正在编写一个程序,它接受一个指定的文件并对其执行一些操作。目前它打开它,和/或将它附加到电子邮件并将其邮寄到指定地址。 文件可以是以下格式:Excel、Excel Report、Wor
我将这台 Zebra ZM400 打印机连接到网络 (192.168.1.50)。我正在尝试直接从 PHP 将内容推送到这台打印机。 这就是我的想法,但我无法做到这一点。我尝试了 file_put_c
我想显示一个列表,其中包含设备可通过 AirPrint 访问的所有打印机。 我使用 UIPrinterPickerController 让它工作。 是否有以自定义方式显示此 PickerControl
我想将任何办公文件传输到 Wi-ifi 打印机。我完全不知道如何开始。 发现没有用于无线打印的公共(public) API。 谁能分享一些意见? 提前致谢! 最佳答案 您可以首先扫描 WiFi 设备并
有什么方法可以让我在蓝牙热敏打印机上打印收据,因为我真的很难在 flutter 上找到解决方案?任何事情都有帮助,我真的很感激这些答案 最佳答案 我试过 esc_pos_bluetooth 包,但它不
为了在我的 mac 上模拟 ZPL 打印机,我在互联网上搜索了几天。最后,我有一个解决方案可以在这里发布,这样其他用户可能会发现它有帮助。我想在这里发布我的解决方案 Emulate Zebra pri
是否有 ZPL 命令来简单地重启 Zebra 打印机?到目前为止,我只能找到 ~JR 命令,这对我来说看起来不像我正在寻找的东西。我只需要一种方法来重新启动打印机,而无需重置其任何配置。 最佳答案 以
我是一名优秀的程序员,十分优秀!