Status reporting is a new feature just being built into the grbl/edge v0.8a branch. I’d like to start a discussion on how the status reporting should look like, what should be included, how it works, and answer some other questions like its flexibility in the future or for users that want to hack it. Here are a few things I’ve been thinking about:
1. For portability and hackability, I’m considering re-organizing and placing the status reporting feature into its own report.c source file, instead of its current location as a function in protocol.c. Here it should be clear what this source file is, what it’s function is, and a place for user to freely hack at it for their own nefarious needs. The required data for reporting would likely need to be re-organized a bit as well, so a user will have direct access to everything they will need.
2. Perhaps the biggest question is what will users need in the status report? Here’s a list of things that are minimally required/needed on CNC mill and lathes, but some of these features are not necessarily needed for other machines/robots. To keep with the spirit of grbl, what needs to be there and what doesn’t to maintain simplicity? Everything listed here are items that cannot be done off-board by an interface.
– Current XYZ position – This is the real-time position in the work coordinate system (G92) or aka part zero. This is the most important information a user would need and could be supplied in terms of mm, inches, or steps.
– Machine XYZ position/coordinate offset – This differs from the work position as being the absolute real-time position/offset from the machine home position. This needs to be retained so grbl knows where home is and may be used to establish the absolute travel limits of a machine without using physical limit switches. There are not many cases that this information would be needed in real-time, but can be very useful.
– Buffer state/size – The planner buffer state or how many blocks are stored and ready to go in the buffer. This is a great indicator of how grbl is doing when under heavy load or showing if grbl is having buffer starvation problems. Again, not needed for all users, but extremely handy and relatively easy to implement.
– Feed rate (& spindle speed) – The realtime feedrate may used to monitor feed rates through complex curves and acceleration profiles. This would be based on the trapezoidadjustedrate value in the stepper module.
– Line number in-process – The problem is what defines the line number. Is it the g-code ‘N’ line command (not required or consistent) or simply based on an internal count of incoming lines? The latter would be simpler and more accurate. The line number being processed would help a user to directly correlate where a problem is in a g-code program and compute distance to go off-board. Could be fairly easy to implement, but require some memory to track these.
– States – Reports the stepper module state, i.e. cycle start, feed hold, and possibly feed rate override (when integrated).
3. The next question is what should a status report look like? In general, the status report should be kept at a relative minimum to reduce the amount of cycles for each status report, especially for setups that need reporting 10-20 times a second. It should be straight forward and human readable. There is also the consideration that a non-human readable binary format could be included to keep the cycle budget to an absolute minimum, but would need to be used with an external interface to interpret the binary data. The need for a binary format may be debated, but here is an idea for a human readable format.
– Grbl:Running,Ln:203,Buf:15,Rate:300.0,MPos:[0.00,10.02,4.34],WPos:[-10.00,2.22,5.00]
– Grbl: Lists the current [Running, Hold, Idle] states
– Ln: Line number in-process. Reset to zero when buffer empties.
– Buf: Number of blocks left in planner buffer
– Rate: Real-time feedrate
– MPos:[x,y,z] Real-time machine position in mm/inch/steps (or maybe in terms of coordinate offsets?)
– WPos:[x,y,z] Real-time work position in mm/inch/steps
– Also, if needed, the reports could be tailored, where certain items in the report can be toggled on or off via some EEPROM settings or bitmask. For example, if the line number, buffer state, and machine position aren’t needed, a user can set the EEPROM settings to show instead: Grbl:Running,Rate:300.0,WPos:[-10.00,2.22,5.00]
4. The last critical question is how should it work? First, the current implementation allows for some flexibility in how to do this. All that needs to be done is to set a bitmask in a system byte to print the report. This could be done in a number of ways, via the current ‘?’ character, an internal timer, or even some external signal on an I/O pin.
– Right now, when a ‘?’ character is sent to the serial receive buffer, the run-time execution routine will reply nearly instantanously with the status report, regardless of what grbl is doing. For an interface, this would mean that it would need to send ‘?’ characters at some periodic rate. (‘?’ may be changed to whatever special character, like control characters or extended ascii.) So is this good enough?
– The main problem I can see with the current implementation is how it complicates the grbl streaming interface. If a user is streaming a file, their interface would need to send the ‘?’ command whenever they need a report and then read and process the report in their serial buffer. At some point, I’d like to install XON/XOFF flow control into the serial module to make streaming g-code less of a hassle. Improving/changing the way grbl streams is a whole other conversation, and the way status reporting works should be a consideration with this.
Anyhow, I think most of these functionalities should be integrated into grbl by design, but they do not necessarily have to be implemented. In other words, it should be very simple for a user to ‘turn on’ these features or whatever they may need without much fuss. Most of the stated report data is already stored in a global struct ‘sys’, and the others could simply be moved into this.
Simen, Alden, Jens, or anyone else.. What do you think about this?
评论 (11)
#2 – jgeisler0303 于 2012-01-23
Great summary from me too.
Many choices are probably very personal, depending on the environment and and task at hand. So the question really is: how much flexibility vs bloated code can we afford (e.g. ‘?’ turns periodic reporting on, ‘!’ turns it off, ‘#’ gives a one shot report etc.); and how do we accommodate hackability for those who still feel the need for something different.
Further, a lot of these questions are strongly connected to the interface design. I would suggest a crawl-walk-run approach, i.e. start with something that can be used with a simple streaming script or terminal and then see what might be added for the needs of a GUI (e.g. binary data format for faster update cycles). Let’s see how many ftoa()’s we can squeeze into the idle time ![]()
One thing to consider though: how do the status reports mix with the parser status when a report is triggered while commands are still being processed?
Regarding line numbers, I totally agree with Simen: they should come from the g-code ‘N’-commands. (If not defined they could default to zero).
So much for now.
#3 – aldenhart 于 2012-01-23
I’ve thought about many of these issues and here’s what I’ve implemented so far (and am in the process of implementing) for TinyG. This is still evolving, and I’m also happy to adjust as these things get hammered out. I’m also happy to contribute whatever code people might want.
1. report.c. Good idea.
2. What to report? All the reportable items are selectable because asking for them all is a big flood. Items are:
– xyz & abc work position. These are identified by tokens xwp, ywp,… perhaps should add machine position as well: xmp, ymp… I first did the positions as as arrays (as you suggest), but my collaborators complained that they wanted them as independent variables because it’s easier to parse. So I changed it. But they were doing JSON, not command line, and I think the arrays are easier to read. It also conveniently keeps things flat in the accessor code.
– line number (ln). If the N words are present it reports them as line number. If not it reports counted lines. This takes about 4 bytes of RAM (double), and extracting the N word falls out of the grbl parser very naturally. The count is still useful in identifying problems as you can find the right line by the line counter in most text editors. Preprocessed G-code? maybe not.
– machine state (ms). States are reset, run, stop, feedhold. This is VERY useful for releasing the streaming program when the gcode is actually complete.
– feedrate. yes. I have this as velocity (vel) because it’s delivered for feeds and traveses, and technically there is no feedrate for traverses. Semantics.
– motion mode and gcode block. I’m thinking of adding this. This will allow EZ readouts and colored drawings from console programs (feeds are one color, traverses another).
– since everything is configurable you may also want to optionally include:
\ firmware version
\ gcode units mode (G20, G21)
\ absolute mode (G90, G91)
\ plane selection (G17, G18, G19)
\ offsets (IJK)
… and a whole host of other parameters too numerous to list. I have this working both as command-line mode and JSON, so in either you can just query the variable (get) the get the return (i.e. the name with a null value). So perhaps the non-realtime variables are not needed in the status report itself. (more on the evolving JSON spec can be found below. comments welcome.) http://www.synthetos.com/wiki/index.php?title=Projects:TinyG-JSON
3. I like the look. Basically it’s JSON without the curlies and quotes. To tailor reports I’ve been playing with just sending in the tokens you want in the report with ‘true’ values (for the SET semantic). The system remembers this and returns the report according to spec.
4. How should it work? Here are the methods TinyG implements:
– ad-hoc query. There is a “statusreport” object (friendlyname “statusreport”, token “sr”). If you ask for sr you get the status report as specified. I’ve been implementing this as ?sr and {“sr”:null} (the friendlyname forms also work: ?statusreport and {“statusreport”:null} )
– status_interval (si). If you set the si token to non-zero you get a report every N milliseconds while the machine is moving. And you always get one at the end of travel. The minimum ms value is about 100ms, and there may be a max as well. If you don’t want this behavior just set si to zero.
– additionally there is the SET method mentioned in (2) above.
Let me know what you think.
Alden
#4 – chamnit 于 2012-01-23
Simen:
Good point on both notes. The g-code line numbering would be the most direct and simple to understand for reporting. But since g-code line numbering isn’t exactly consistent from user to user and CAM to CAM software, there needs to be another way to know what block is in-process. As Alden suggests, he uses both, but I think mixing both would make for some confusion. Hard to say what to do. Are there any other ideas on how to track the block in-process?
Your comment on the polling leads to another question. For the feed hold, resume, and abort features to work, there needs to be an interface to allow these commands to interrupt grbl’s main program to immediately execute. For a software/USB based setup, this means the only way to send commands to grbl is through the serial rx/tx interface, piggy-backed on the g-code streaming. To do this, an external interface must be able to inject these special characters into the stream so the serial read function picks them off to set the runtime execution flags. Status reports were added here mainly because it was easy to do.
So if we decide to include XON/XOFF flow control, how do we still send these runtime commands through this without requiring a specialized streaming interface? One answer would be: don’t send them and move this functionality to physical buttons on the spare I/O pins. But at the cost of having a software interface. There might be a nice solution to this streaming problem. I just haven’t thought of one yet.
As for periodic reporting, do we have an available timer to handle this? As far as I understand, we have Timer1 and Timer2 used by the stepper module and I’ve read that Timer0 is generally a don’t touch timer. If a timer is available, I agree that this would be the best way to send the reporting. Also, as Alden has in his code, does it make sense to allow both timer based and ad-hoc reporting?
Jens:
The g-code parser should be independent of the real-time status reporting, as they are reporting what the steppers are doing and executing. As of now, there isn’t a way to prevent overwriting variables by the stepper module when a report is triggered, but when overwriting occurs, it’s rare and doesn’t seem to cause to many problems. You just have to make sure that the variables are being written only by the stepper module to prevent two simultaneous writes.
With the customization and fear of bloat, I think using a toggle scheme in the settings should help with preventing bloat. This would also provide a clear blueprint for users to modify the report.c source file to their needs. But, I think I would still have to draft one up to see how it would really look.
Alden:
Good catch on the g-code modes. This is whole other realm of reports that may need to be reported, but likely at a much slower rate. This could be a separate reporting scheme.. perhaps call it ‘modal report’ or something like this. It would likely need to be sent ad-hoc and no faster than every second or so, not the 10-20Hz like with the stepper position.
As for TinyG’s implementations, it seems that we have a general agreement on what needs to be there. The JSON formatting probably can be integrated by users by just modifying the report.c source file. I would prefer to keep things nicely human readable and short, mainly not to confuse new users. The way I see it, if we do make a report.c source file, people could just write and distribute their own to be compiled by users or forks. Plug and play hopefully.
#5 – aldenhart 于 2012-01-23
A finer point on line numbers – if the N’s are present I prefer to use them. I only count lines if the N’s are not there.
Timers: Doesn’t the 328 have an RTC? That’s what I use.
The need for other reports is why I haven’t attached the status report directly to the ?, but use ?sr. It comes in through the normal command line interface, not the “signals” traps used by ! (feedhold) and ~ (cycle start) and ^x (abort)
I agree on the JSON. It’s a special thing I’m doing for some console writers who want to work directly to dictionaries / hashmaps. I think I’ve managed to integrate it in so it’s “modeless” – it just starts if you send a line beginning with a curly and stops when you send a line beginning with a $. I like the idea of a separate report.c
#6 – realRandomWalk 于 2012-05-30
I have been working on a GUI for jogging my CNC, written in Processing. The difficulty is that when a button is pressed, let’s say “+x”, to jog the CNC along the X-axis in the positive direction, GRBL responds with a serial “Ok” message, but it does so immediately, not when the operation is finished. To be clear I am running GRBL 0.7d, I’m not sure if this behavior is different in the “edge” branch. So ideally I would like to be able to “poll” GRBL for whether the operation is finished or for GRBL to send something like “done”. It sounded like that might be possible with the planned status reporting feature which the wiki said is on the roadmap. The behavior I’m trying to avoid is that repeated presses of a jogging button don’t continue to send additional movement gcode lines, until the previous line is executed. I will try to upload the Processing program to my fork of GRBL, still figuring out github and git. The code is very alpha, functional though, and I’m not a programmer by trade, so it might be kinda hack, open to feedback.
#7 – jgeisler0303 于 2012-05-30
the “ok” message indicates that the g-code line was parsed all right. It is also an indicator that the space that the line occupied in the buffer is free again. In this function the “ok” message is already being used by programs, like the stream.py script, that feed grbl as fast as possible.
One way to indicate when exactly a g-code line is started to be run can be achieved by using g-code line number reporting (I will provide the code for this soon). But if your line is the only and last line to be run that still doesn’t give you the “g-code line finished” report. The finish of the last g-code command could be read from the number of blocks in the command buffer. When this becomes zero then your command has finished running.
The way I do it right now in my https://github.com/jgeisler0303/grblUI is to compare 3 consecutive position reports (polling at 100ms). If there is no change then that means that movement has stopped and the command has finished.
#8 – stwspoon 于 2012-07-06
A simple ‘Done’ worked for me (see issue 12) as I needed to know that the motion had stopped. I added a “Done” print statement when the command buffer is empty. I also added a ‘Done’ in the planner because sometimes the movement was optimized out. I was using 74576a8, but it probably can be added to the newer branches.
#9 – aldenhart 于 2012-07-06
In TinyG I added a synthetic state variable like so:
enum cmCombinedState {
COMBINED_RESET = 0, // machine has been reset or aborted
COMBINED_CYCLE, // machine is running (cycling)
COMBINEDPROGRAMSTOP, // program stop or no more blocks
COMBINEDPROGRAMEND, // program end
COMBINED_RUN, // motion is running
COMBINED_HOLD, // motion is holding
COMBINED_HOMING, // homing cycle active
COMBINED_PROBE, // probe cycle active
COMBINED_JOG // jogging is treated as a cycle
};
The state is one of the parameters you can request to be reported in a status report (token is “stat”). So when the system is running the value “Run” is returned in the status report. On the last status report the value “Stop” is returned, assuming there are no more blocks queued to run. Note: Even though “Cycle” is in there this isn’t exposed to the interface.
-Alden
#10 – yurkomik 于 2013-02-10
Can anyone help me with getting “done” status? I write a small program for my bot in python and only way to know that we have reached final destination is to check change of MPos after initialising of the new gcode. I am sure that’s possible to get reply like “done” or “buffer clear” in special mode. For example “*G00 x100” could give reply after execution of this code was complete. “G00 x200” can give only “ok” reply as usual. Thanks for any help.
#11 – miltonvilela 于 2013-03-16
Hello, void TestEdle(){ Comments are welcome,
To know that a command was executed gcode sending through the serial port:
Serial.print(“?\n\r”);
then check sometimes if the return of the first five characters equals “
while( stateGcode() != “
Milton Vilela
São Paulo – Brasil
#1 – simen 于 2012-01-23
Great writeup, and much to consider. I just wanted to say something about line numbers: I think dead reckonning line numbers by counting input is hard to use as a client often may preprocess the file and even delete lines from the input. Personally I would prefer that we used the line-numbering standard from g-code and have line number reports be an optional feature that you “turned on” by actually numbering your lines. A preprocessing client that wanted to show current line in its interface would tag each line as it streamed it to grbl.
When it comes to reporting, maybe rather than polling, ? could turn on periodic reporting (e.g. every second) and ! would turn it back off. In a typical streaming setting the uplink would be pure gcode and downstream pure status. Just a thought.