Hello Folks,
Hope everyone is keeping well. Im making some progress with a raspberry Pi python GRBL sender. Right now,
It picks a random G-Code file from a folder
Streams the file accross the serial to the GRBL
Closes everything - It completes one pattern and then stops.
Im looking for a little assistance if possible
Scheduling: Id like to be able to run the machine on certain days and time. It sounds like Crontab is used for this. Is it better to use a python library like datetime and control the stuff in the actual program OR use crontab to schedule to when to run the program. Can I have a while loop that keeps on running the patterns if using crontab does anyone know?
Plotting the G-Code: Iâd like to have a little screen that plots the X,Y co-ordinates so students could appreciate that the sand pattern is controlled by the raspberry pi. Does anyone know of a simple python library that opens up a little window and prints out the plot.
Any chance someone more experienced in programming and python could look over the code and give me some feedback - is there any error checking we could add - any other suggestions?
Big thanks for all the help so far - If your ever in Maryland - ill buy you a pint ,
Tim
import serial
import time
import os, random
# Open grbl serial port
s = serial.Serial('/dev/ttyUSB0',115200)
# Opens up a random G-Code File
random_file = random.choice(os.listdir("/home/timcallinan/GCODE/"))
file_path = os.path.join("/home/timcallinan/GCODE/", random_file)
print(file_path)
f = open(file_path,'r');
# Wake up grbl
s.write("\r\n\r\n".encode())
time.sleep(2) # Wait for grbl to initialize
s.flushInput() # Flush startup text in serial input
# Stream g-code to grbl
for line in f:
l = line.strip() # Strip all EOL characters for streaming
print('Sending: ' + l,)
s.write((l + '\n').encode()) # Send g-code block to grbl
grbl_out = s.readline() # Wait for grbl response with carriage return
grbl_out_str=str(grbl_out)
print(' : ' + grbl_out_str)
# Close file and serial port
f.close()
s.close()
Iâm working on something similar for my sand table but im at about the same point as you are with totally different setup⌠grbl and esp32 for a polar machine
It will be fun to see how you tackle it. I suspect that the buffering bit may be a bit of a pain to deal with but not sure yet.
May we toast each otherâs victories as Iâm also in maryland.
Running your program forever, with a while loop, is fine. The suggestion for crontab was a little different. I imagined sandypi running forever, with no changes. Crontab would send a command at 8am to say, âplayâ and at 8 to say, âstopâ pr âpauseâ.
With a while loop, you could just ad something like this:
if hour < 8 or hour > 20:
print("sleeping")
time.sleep(60)
continue
Inside a while loop.
Your code looks fine. I have a couple of suggestions:
Use with to open the serial port and the file. It makes errors easier to handle and closes then automatically.
Use a log. Whenever you get this running. And you want to see why it stopped, youâll want to look at the text log. Youâre doing a decent job of printing frequently. Just be sure you record the output of the app so you can see the log later, after an error.
If you want this to be more generally useful, make the serial port and the gcode folder parameters.
How are you going to run this? You could run it from cron with @restart. You could configure systemd. You could use docker with restart=unless stopped. Youâll have to look into each of these options. There are many choices.
About error handling. I imagine the ways this is going to fail is that there will be a loose connection on the USB, or a command will get lost and youâll be waiting for a new line. If you lose the serial port, then things like send will raise an exception. I would recommend just not handling that for now. But make sure you have a good log to see where it is falling before it fails. The log can also help you detect a stalled scenario. But remember that output can be cached. Eventually, if that becomes a significant problem, you can make a watchdog that you feed when things are working, and if you havenât fed the WD in 10 minutes, then it will flush the serial port and start over, or whatever.
Hello Jeff & Co,
I hope everyone is doing well. Sorry I havent been able to respond in a long time. The start of my semester is always chaos. Anyway Ive been playing with the sand plotter and been making some slow progress with the Python Pi GCode Sender. Ive enclosed a photo of the machine as well as the code Im using.
I was able to figure out the whole timing - which day/hours I want the machine to run. This is in the check_program_window function. It seems to work quite well. I was also able to figure out the program picking a random G-Code file and the parsing of each line.
Where I could use some advice is the serial buffering of the G-Code sentences - I dont know if âbufferingâ is the correct term. My program sends the next command once it gets a carriage return back from the controller. The program seems to keep sending the G-Code out. Is there a better way of doing this. Bart Drings CNC controller does kick back some data. Here is an example of it . Maybe I could check this GRBL response before we move to the next line of G-Code? Hopefully my ramblings make some sense. Any advice is appreciated. Thank you
Tim
#START OF CODE
from datetime import datetime
import time
import serial
import os, random
INTERVAL = 5 # seconds between loops
VALID_DAYS = [0,1,2,3,4] # days of week to run program MONDAY TO FRIDAY
VALID_HOURS = (9, 19) # (start, stop) hours 24 hour time
def GRBL_Sender():
# Open grbl serial port
s = serial.Serial('/dev/ttyUSB0',115200)
# Opens up a random G-Code File
random_file = random.choice(os.listdir("/home/timcallinan/GCODE/"))
file_path = os.path.join("/home/timcallinan/GCODE/", random_file)
print(file_path)
f = open(file_path,'r');
# Wake up grbl
s.write("\r\n\r\n".encode())
time.sleep(2) # Wait for grbl to initialize
s.flushInput() # Flush startup text in serial input
# Stream g-code to grbl
for line in f:
l = line.strip() # Strip all EOL characters for streaming
print('Sending: ' + l,)
s.write((l + '\n').encode()) # Send g-code block to grbl
grbl_out = s.readline() # Wait for grbl response with carriage return
grbl_out_str=str(grbl_out)
print(' : ' + grbl_out_str)
# Close file and serial port
f.close()
s.close()
def run_program():
#stuff to run 9am-7pm Mon-Sat
print("sand pltter is running")
GRBL_Sender()
pass
def check_program_window() -> bool:
dt = datetime.now()
print(dt.weekday())
if dt.weekday() not in VALID_DAYS:
return False # not a valid day
if VALID_HOURS[0] <= dt.hour and dt.hour <= VALID_HOURS[1]:
return True
else:
return False
def start() -> None:
while True: # keep program looping
if check_program_window():
run_program()
time.sleep(INTERVAL)
#This just starts the program
if __name__ == "__main__":
start()
That seems fine to me. I would look at other senders, like the cncjs , ugs, or octoprint to see how they manage that buffering. But what you have looks fine to me.
You could add in a huge timeout (longer than any possible move) to make sure it will break free if it ever stalls.
This makes me want to make a micropython/circuitpython board to do this on a little microcontroller.