Hello everybody,
I have been using octoprint for a long time and i'm developing a custom app using a raspberry pi 4 and one printer with motherboard MKS Base 1.6 inspired by octoprint, but I'm struggling in one thing.
I want to create a Gcode Sender in python like octoprint's one that can send one gcode file over USB so the printer can print it.
At first I was using one I found on Github (gcodesender.py/gcodesender.py at c0572efca5950bf0cf9a8a612ee465c701c30685 · bborncr/gcodesender.py · GitHub) but I had some problems cause It seems like the script doesn't really wait and it sends more gcode lines than the motherboard can handle.
So I downloaded github files of octoprint and I think the core part of what I want is in "src/octoprint/util/comm.py". I created one test file trying to copy the methods "_do_increment_and_send_with_checksum", "_do_send_with_checksum" and "_do_send_without_checksum" from the class called "MachineCom(object)".
But I'm still getting some problems with the buffer/wait-to-send part. I expect no fails on my print so I don't need any protections/fail warnings. Just a Gcode Sender that can print one file over usb. I was wondering if someone who knows the core part of this program could help me or give me one direction I should go.
This is my first post here, I don't know if I should post this on the github site instead, sorry in advance.
The class I wrote:
import serial
import threading
import time
ser = serial.Serial("/dev/ttyUSB0", baudrate=115200)
time.sleep(1)
print("do home")
ser.write(str.encode("G28\r\n"))
time.sleep(1)
class octo_sender():
def __init__(self):
self._line_mutex = threading.RLock()
self._current_line=0
self._transmitted_lines = 0
self._max_write_passes=3
def _do_increment_and_send_with_checksum(self, cmd):
with self._line_mutex:
linenumber = self._current_line
self._current_line += 1
self._do_send_with_checksum(cmd, linenumber)
def _do_send_with_checksum(self, command, linenumber):
command_to_send = b"N" + str(linenumber).encode("ascii") + b" " + command
checksum = 0
for c in bytearray(command_to_send):
checksum ^= c
command_to_send = command_to_send + b"*" + str(checksum).encode("ascii")
self._do_send_without_checksum(command_to_send)
print(str(command_to_send))
def _do_send_without_checksum(self, cmd, log=True):
cmd += b"\n"
written = 0
passes = 0
while written < len(cmd):
to_send = cmd[written:]
old_written = written
try:
result = ser.write(to_send)
if result is None or not isinstance(result, int):
# probably some plugin not returning the written bytes, assuming all of them
written += len(cmd)
else:
written += result
except serial.SerialTimeoutException:
print("Serial timeout while writing to serial port, trying again.")
try:
result = ser.write(to_send)
if result is None or not isinstance(result, int):
# probably some plugin not returning the written bytes, assuming all of them
written += len(cmd)
else:
written += result
except Exception as ex:
print("Unexpected error while writing to serial port")
break
if old_written == written:
# nothing written this pass
passes += 1
if passes > self._max_write_passes:
# nothing written in max consecutive passes, we give up
message = "Could not write anything to the serial port in {} tries, something appears to be wrong with the printer communication".format(
self._max_write_passes
)
print(message)
break
# if we have failed to write data after an initial retry then the printer/system
# may be busy, so give things a little time before we try again. Extend this
# period each time we fail until either we write the data or run out of retry attempts.
if passes > 1:
time.sleep((passes - 1) / 10.0)
self._transmitted_lines += 1
##~~ command handlers
## gcode
def removeComment(string):
if (string.find(';') == -1):
return string
else:
return string[:string.index(';')]
def sender(file):
myThread=octo_sender()
f = open(file, "r")
# Wake up
# Hit enter a few times to wake the Printrbot
ser.write(str.encode("\r\n\r\n"))
# time.sleep(2) # Wait for Printrbot to initialize
ser.flushInput() # Flush startup text in serial input
print('Sending gcode')
for line in f:
l = removeComment(line)
l = l.strip() # Strip all EOL characters for streaming
if (l.isspace() == False and len(l) > 0):
myThread._do_increment_and_send_with_checksum(str.encode(l))
f.close()
time.sleep(1)
if __name__ == "__main__":
sender("/media/pi/0DD8-0D9F/mode1.gcode")
Btw, does someone know what the "W:?" or "W:(number)" mean in Marlin? I'm getting this messages from the console and I think they mean WAIT(they go lower value everytime) but didn't find info on the internet. For example:
T:207.03 /210.00 B:49.72 /50.00 @:0 B@:40 W:?
T:210.27 /210.00 B:49.97 /50.00 @:0 B@:19 W:5
T:209.96 /210.00 B:50.01 /50.00 @:3 B@:14 W:4
echo:busy: processing
T:209.53 /210.00 B:50.00 /50.00 @:16 B@:17 W:3
T:209.26 /210.00 B:50.01 /50.00 @:23 B@:15 W:2