jes notes Index Gallery . 4th axis Anniversary Clocks Blog ideas Micro-machining CNC milling machine Paint colours CNC Router Shaft passers Snap issues Software ideas Stepper motor clock Toy ideas Watchmaking Wildflowers

2024-01-31

Last modified: 2024-01-31 20:27:42

< 2024-01-29 2024-02-03 >

G-code sender

Plan is to make a first pass at opening a G-code file and running it.

First observation is that the serial buffer keeps filling up while a job is sending, is this because $G\n keeps getting added to the buffer? Yes. Fixed by only sending $G\n if it's not already pending a response to one. (But can that mean after a soft-reset flushes the buffer it will never send another?)

I'm using the simple "send a line and wait for the response" technique for sending G-code, and so far it seems to be doing a fine job of keeping the planner buffer full, because Grbl replies "ok" as soon as the command goes into the planner, and then I send the next command, which waits in the serial buffer until Grbl is ready. Obviously it would be better to put a few more commands in the serial buffer, but I expect it's only a small improvement, at least on the workload I'm testing with (the Klingon Dagger finishing pass generated by pngcam). So I may leave it as it is. I certainly don't need to make it use the character-counting mode yet.

A line of G-code can be in one of 5 states:

I want to be able to distinguish all of these states in the G-code view in the program. In particular, if I stop a program part-way through, I want to know what is the line that was actually executing at the point that it was stopped, to let the user resume in sync. Although, on second thoughts, maybe it's not necessary: you just need to make sure you resume at a point that had already been cut, and re-cutting it isn't a massive deal.

But for sake of argument, how would we tell?

At startup, all lines are not yet sent. When you first send a line, you know it goes into the serial buffer. You know it is accepted into the planner buffer when you get "ok" (but, some lines could conceivably apply immediately, or have no effect, so not go into the planner buffer). But how do you know when it is currently executing? How do you know when it has been completed? Maybe you just know that the planner buffer stores 15 lines, so the first 15 lines that have not been completed must be in the planner buffer, and the first one of those is the one that's currently executing?

ChatGPT said:

// Send each line and update its state accordingly.
for i, line := range gcode {
    updateState(i, InSerialBuffer)
    a.CommandWait(line)
    updateState(i, InPlannerBuffer)

    // Infer that a line 15 steps earlier has been executed, if it exists.
    if i >= plannerBufferCapacity {
        updateState(i-plannerBufferCapacity, Executed)
    }
}

I need to make it warn you (or correct the configuration automatically? or offer to do so?) if Grbl is not configured to report the buffer states in the status reports. Needs $10=2.

Next up I want to make it draw the loaded G-code in a scrollable view, with the last-sent line highlighted (and actually, we don't need to track the state of each line individually, because everything is a function of the last line that was sent: last line sent is in serial buffer, the 15 before that are in the planner buffer, the one before that is currently executing, and all before that are completed). That works fine until the very end of the program, where the planner buffer drains without us realising, but let's get to that later.

For now I just draw a grey background on the lines that have already been sent.

< 2024-01-29 2024-02-03 >