Here I’d like to start a discussion whether or not software xon/xoff flow control should be integrated into grbl’s serial interface. There are both benefits and drawbacks in terms of use, and it is easy to implement.
The primary and greatest benefit is that any standard serial terminal program supports xon/xoff software flow control. This really simplifies streaming g-code to grbl, as a user can just send/upload the file and grbl should execute it to the end of file. A second important benefit is that grbl can access the next g-code block command immediately from the serial read buffer without having to perform the ‘ok’ handshake and wait for a response. This really speeds things up and prevents planner starvation.
The primary drawback is that it limits the streaming interface and can limit control, since the serial port is the only software connection to grbl. In the status report discussion, the question was raised: how do would you send run-time commands, like feed holds and abort, while streaming the g-code program at the same time? If the XOFF flag is sent from grbl when its receive buffer is full, this effectively blocks transmit communication to grbl, unless a special streaming interface is designed to force transmit run-time command characters. At this point, a specialized streaming interface negates the simplicity benefit.
Right now, the stream.py script does a pseudo-XON/XOFF flow control by counting and tracking the sent characters to grbl’s buffer. Not exactly clean and simple, but effective.
So I guess my question is: where do you all see the primary interface of grbl going? Does it make sense to keep the ‘ok’ and ‘error:’ response interface or should we begin to look into efficient alternatives for replacement or enhancement? This should all come with a consideration of not dropping current user support and messing with their interfaces without good reason.
评论 (30)
#2 – sacidu93 于 2012-01-25
I personally used the XON / OFF method to control the flow on the serial port, but immediately I had this problem, when the buffer is full and the XOFF occur, I was unable to send run-time command characters as feedhold, Reset and Status Report, so I gave up and I returned to the starting point, I just checked the return of the ‘ok’ before sending the next gcode line. I think it would be interesting to include in the Satus Report a flag that indicates the end of the process and that the buffer is empty, since the end of streaming the code does not mean the end of moves, I can’t check if the process is really finished, especially when the last lines of gcode are axis long moves. Here is a small video showing a simple application used to control both GRBL and Tinyg. http://www.youtube.com/watch?v=li7HwmOskMM
#3 – aldenhart 于 2012-01-25
I’ve experienced the same issues with character insertion with XON/XOFF on TInyG, but it does have its uses. It’s a useful way to simply stream files to the unit. I’ve been running TinyG w/FTDI chip with Coolterm (Mac) this way for some time and it’s very reliable (I’d say completely reliable, but somehow I’d be proven wrong!). However, if you want to inject real-time commands you really need to either gate the sender to sending only one Gcode block per transmission, or – as Simen suggests – have an advance buffer that’s “unlimited” (like an SD card that’s bigger than any practical Gcode file). I don’t think you can have it both ways. My preference is to agree on a single sync character that can be easily scanned in the response line (like a >, for example).
#4 – chamnit 于 2012-01-25
A couple more drawbacks to add.. Software flow control is limited to character transmission only and no binary data can be sent, since there is always a chance the binary data sends the XON/XOFF bit sequence. This prevents a fast, efficient binary mode status report, unless encoded in base32 or base 64 ascii strings. The same could be said about still using a ‘ok\n’ response. There is a chance that binary data could trigger this as well, even though its a remote possibility.
Secondly, I have read that some terminal emulators do not honor the XOFF command immediately and can cause buffer overflows unless the serial buffer is very large and can handle the delay. How flow control is handled may vary between terminals. Alden’s use of Coolterm maybe an exception while Simen’s ‘socat’ and piping are not. Although I could be wrong about this as well.
So, it seems that there are two options: implementing the XON/XOFF with all its drawbacks or update and continue with the application-level flow control scheme (‘ok\n’) that we have been using.
– For XON/XOFF, binary data is not possible, so data compression into base32 or base64 ascii characters are likely the easiest thing to do for fast and efficient status reporting with some CPU overhead. Testing may be needed to ensure XON/XOFF works reliably with most terminal emulators and grbl doesn’t have problems with buffer overflows. And there still needs to be a way to force transmit run-time control characters to grbl that is not part of the standard flow protocol, but users can users can use any terminal to use grbl sans the run-time control. (Still useful).
– With our application-level ‘ok\n’ flow control, we may have to further develop and mandate a protocol of some sort. If so, I’m in the camp of still using the ‘ok\n’ response, as it is non-cryptic to new users. Binary data can be sent by creating a header for an interface, indicating that a binary data packet is being sent of a fixed size. This type of protocol is pretty simple and easy for users to work with, you send and wait until an ‘ok\n’, but has latency problems and the serial read buffer is usually always empty. If we keep using this protocol, we will need to make it easy for users to keep the serial read buffer full, like with the XON/XOFF protocol, which can be a challenge for some people.
What do you all think? As Alden states, we can’t have it both ways. Or maybe we can?
simen: An SD card would definitely solve all these problems. All you would have to do is upload the file to grbl, then hit run. Simple as that. I’d really like to see this happen at some point. This issues with this would be having to free up digital pins 10-13 for SD card shields, which are occupied by the limit switches(could we reduce this to one pin?) and spindle control pins, and making sure we have enough RAM and flash memory to install it (I’ve heard that the FAT16 library is huge).
sacidu93: Very nice interface! I like seeing that people are able to program their own without too much trouble. Including the buffer status in the status reports is currently under discussion and will likely make its way into grbl soon.
#5 – aldenhart 于 2012-01-25
A preferred way to implement XON/XOFF is to use a high-water-mark / low-water-mark scheme. The XOFF is issued when the buffer is (say) 90% full, and XON is issued when it’s (say) 5% full (while draining). This allows for lag in the system and keeps the system from thrashing by introducing hysteresis. This is how it’s implemented in TinyG.
If we go the SD card route I’ll design it onto grblshield so you don’t need multiple shields. We should also work out the preferred pinouts for homing switches and any other HW requirements.
#6 – chamnit 于 2012-01-26
I’ve read about the high and low water mark scheme, but didn’t know what it was for. That makes sense. Thanks Alden.
Let’s suppose we do both. Keep the standard ‘ok\n’ responses to indicate that block/line was received and parsed. Is there a way to auto-configure the XON/XOFF protocol upon connection? If so, a user or interface can elect to use either.
A grblshield SD would be awesome. Still if SD card support is made, this would need to be compatible with anything in production, which I think use digital pins 10-13. Simen what do you think? Bit the bullet and instigate a pin assignment change?
#7 – aldenhart 于 2012-01-26
This is a lot of competition for the upper bits. If you assume to keep the lower port the same as the 0.6 pinouts – to not break support for RX/TX, 3 step and 3 dir bits – then the upper port bits need to be allocated either for the SD card or for 3 limit / homing switches and 2 spindle control (as per the 0.6 pinout). So you get one or the other but not both. I guess that’s the tradeoff.
#8 – jgeisler0303 于 2012-01-26
I would go with the XON/XOFF (high-water-mark / low-water-mark scheme) protocol. If the client honours it, that’s good: we give users with many different terminals the ability to stream the gcode as fast as possible. If the user application ignores the protocol, well, nothing is lost then.
It should also be possible to ignore XON/XOFF and use streaming scripts that use the “ok\n” protocol or count the characters sent.
Also, run time commands can still be sent with an arbitrary terminal as long as the gcode is sent line by line (this would also be required when no flow control is used).
A streaming script could still inject run time commands if it tells the serial driver to use no flow-control.
This is actually the way I would implement any client: use a no-flow-control driver and handle XON/XOFF in the program code (beware the client side buffer though). Then, the program could still send run time commands while the gcode streaming is XOFFed/halted.
The only drawback I really see with XON/XOFF is the incompatibility with binary data. But binary data could still be sent in the range 128…255 (bit 7 set) which would also clearly mark it as binary.
@chamnit: we need separate limit switches for each axis to know which axis is already finished when homing x and y at the same time.
@chamnit and alden: are you sure that any atmega has enough flash for grbl and the FAT library. maybe we need to think about a piggy-backed second arduino that does the SD-card handling and user interface serial communication (and maybe counting steps or reading position feedback). I think I saw a setup like that on youtube. Also, it would be nice to keep some pins for hardware jogging and feed-hold input.
@sacidu93: is the source code of your application publicly available?
#9 – aldenhart 于 2012-01-26
I’m not sure why you want to go binary. I know there’s some efficiency there, but it it really worth the hassle and complexity? I’d rather see some analysis of transmit times and cycle budgets before taking that step. The pack/unpack processing will go up, the code size will go up, while the number of characters and transmit time will go down (which may also reduce cycles somewhat). You might find that there’s actually plenty of time and bandwidth without it and you can avoid the complexity.
It’s also worth looking at using 115,200 as the default baud rate. When I looked at this it was a no-brainer, and the xmega is actually only 2x as fast as the 328’s. Not that much, actually.
#10 – simen 于 2012-01-26
I agree totally. Plain text protocols are practically self documenting. With binary people will have to deal with endianness and whatnot. I also agree regarding the baud rate. There is not problem running grbl at that rate – I have done it many times. The only reason I have stayed at 9600 for the distro is that it I believe it is the default rate on many systems. It will commonly work for most people without digging into their man-files.
#11 – aldenhart 于 2012-01-26
Sticking with 9600 is cool (and it avoids a step in the setup of Coolterm, for one). I’d see if 9600 supports the data update rates anticipated by the status report. A 100 character line (excessive, I’m sure) would take roughly 100ms to transmit, setting the maximum achievable update rate at 10 Hz. This may be enough.
That said: you might want to bump this if you ever want to dump a file onto an SD card. 115,200 starts to look pretty good.
#12 – simen 于 2012-01-26
Agreed. What I really wanted to make but never have gotten around to was auto-detecting baud rate on startup by employing the interrupt capability of the RX pin and then require the client to hit a few enter-characters to “wake” grbl. That would be seriously 0-conf.
#13 – aldenhart 于 2012-01-26
Riley did something like that in a console he wrote. It works with both TinyG and grbl. It hits the board until it gets a response then configures accordingly. On-board autobaud would be cool. There has to be some atmega example code out there.
#14 – jgeisler0303 于 2012-01-26
Agreed too. A pure ascii protocol that serves terminals and GUIs alike should be the preferred solution. I was just tying to settle concerns against XON/XOFF.
#15 – chamnit 于 2012-01-26
Yikes! Lots of comments to reply to..
Alden: First, I’m not an expert at pin assignments, but is there any reason why we can’t start using the analog pins as digital pins? I understand from the Arduino IDE that this is pretty easy. Not sure how or what it entails for development in C.
For microprocessors, twice as fast is significant. There isn’t much overhead on these CPUs and you generally get nearly twice as fast execution. From my experiences with developing grbl, the 328p performance limit is real and I’ve bumped up against it several times. It would be awesome to get some extra cycles.
simen and alden: Well, I have to admit I don’t know what it exactly entails for transmitting binary. I assumed that it meant that all you had to do is sent 8 bit char portions of each variable in a set order and size that is known and expected by the receiver. (Or use the 7 bit binary packing for ascii chars > 127 like Jens states, which basically solves this xon/xoff problem with binary.) If so, this can be done very fast and efficiently.
On the other hand, I’ve been recently going through the print.c source file. To print an integer value, you have to modulo AND divide for each base digit. So for a number 94857 in base10, you have 5 modulos and 5 divides. Adding this all up, say that you have about 10 integer/float values with 5 digits each you need to send at a rate of 20Hz, grbl will have to compute 1000 modulos and 1000 divides a second to print these at the rate required. This adds up really really quickly. If we can significantly optimize the print function, then I would be completely ok with not including the capability (not necessarily integrate) of binary transmission. Just to re-iterate, binary transmission would only really be needed for status reporting at high rates, not for anything else.
As for increasing baud rate, I’ve used grbl at higher baud rates as well with no problems. I’ve read, but not experienced that the only thing to watch out for is missing data bits at the highest baud rates, if other interrupts delay the serial interrupt from executing on-time. At 115200 baud, each pulse is about 8.5 usec and the stepper interrupt handling takes up about minimum of 3 usec.
Jens: The pins are beginning to get into short supply, especially if SD card support is included (not sure if it will fit in grbl) and if cycle start, feed hold, and abort control is used as pins. Bringing down the limit switch pins down to one would free up two. The homing cycle could feasibly be re-written to move one axis at a time to flip each limit switch to locate home.
Not sure what you mean by your XON/XOFF protocol ignoring the characters. Would it be better to make this a user EEPROM setting to enable/disable XON/XOFF flow control? This would be straight forward and easy to do. A user wouldn’t then have to make their interface script ignore these characters.
#16 – jgeisler0303 于 2012-01-26
Ohhh, really good point, I totally forgot about the divs and mods. There are special functions that do div and mod at the same time because mod always is a by-product of div. But for floats that’s still some processor load.
There are other methods for float to ascii conversion. One can use stored numbers 10000, 1000, 100, 10, 1, 0.1 etc. and then subtract them from the number to convert, counting the subtractions it takes to make the result negative this is then the decimal value of the corresponding decimal place (I can try to re-find the example source code if needed). But that’s still nested loops and maybe you’re right about the necessity of binary transmission.
By ‘ignoring’ I meant to filter XON/XOFF characters from the input stream but otherwise not react to them … But that requires some changes in the streaming script. Originally I thought the occasional XON/XOFF characters could be printed to the console like any other grbl response, but that might break the “ok\n” protocol … I was thinking too fast.
I already use analog pins as digital IO no problem, same procedure, analog doesn’t even have to be disabled or anything.
#17 – aldenhart 于 2012-01-26
I wrote some efficient character queue handlers for TinyG just to see how far I could push it. Turns out if you load the queue from the top to the bottom you can test on zero to do the wrap operation, which then just becomes a pointer or index load. This is the most efficient way to do it (I think) because the decrement to zero sets the Z status bit and so the branch comes “for free” with no other operation. THis is in keeping with the philosophy of “use the C complier as a robot to write the assembler you would have written if you weren’t so lazy”. You can find the code in the xio modules if you want.
Good news on the analog IO. I had not seen that. Looks like all functions can be supported if the switches and spindle are moved to the analog side of the board.
#18 – chamnit 于 2012-01-27
First, I have to say that this is a great brainstorming session. Awesome.
It’s looking like integrating an XON/XOFF scheme might a good thing to do, but perhaps as an advanced setting that any user can toggle. (This leads to my next question on how the structure of settings should look like, but this should start on another thread.) Anyhow, we seem to have a few options on how to transfer binary with XON/OFF, i.e. 7 bit upper ascii characters that Jens suggested (great idea by the way). This will greatly simplify streaming g-code to grbl for users that will not need run time commands or move these controls to pins. And, anyone should be able to write their own specific streaming interface if they need run-time commands through software. In addition, if we allow this toggling, this doesn’t leave current users in the dust and they can still use their standard and simple “ok\n” call and response protocol.
If anyone needs to look at some example code on how XON/XOFF is implemented, I believe Jens has a start in his fork, edge branch, serial.c.
Alden: The modulo and divides come from the conversion of a binary number to character format. It looks like TinyG uses a standard library for printing and converting characters. Simen installed his own stripped down version of this same printing scheme in print.c, mainly for minimizing flash size, but I believe that this operates in the same way as the standard library.
That’s good news on the analog IO pins. Does anyone have any objection for moving the spindle enable and speed pins to analog 0 and 1, while reducing the limit switch pins to one on pin 9? It would also be possible to support cycle_start, feed hold, about, and jogging (toggle on/off) on analog pins 2,3,4, and 5. This would use up all pins except digital IO 10-13, which would be reserved for i2c, sd cards, ethernet interfaces or addition user allocated pins.
#19 – aldenhart 于 2012-01-27
The print semantics are different but the end result is the same. TinyG uses the AVRGCC stdio libraries for serial and takes the hit on including the float lib so it can support formatted print strings (“J Offset = %8.3f\n” and that sort of thing). This is too much code bloat for the 328s, so its not really an option on the Arduino hardware.
I’m still uneasy about going the binary route unless it’s absolutely necessary. I think a little testing with the print routines are in order. It would be nice not to have to deal with binary on the receiving end.
One small correction from earlier – a USART running at 115,200 interrupts roughly every 86 microseconds, not every 8.6 microseconds as the interrupts occur once per received character (typically 8 bits, 1 start bit, 1 stop bit) so it’s not quite as bad as it seems.
#20 – chamnit 于 2012-01-27
Alden. I don’t have the intention of installing a binary reporting scheme
unless needed. This was an exercise of planning ahead and making sure we’re
not painting ourselves into a corner, so to speak. I guessing that for most
people character-based reporting will be just fine. For people who want
very rapid and real-time reporting, binary is likely the way to go, at
least on a 328p processor.
The 115,200 baud timing is still correct. Each bit is sent every 8.6
microseconds of that 10 bit character sequence per USART interrupt.
On Thu, Jan 26, 2012 at 6:53 PM, Alden Hart < reply@reply.github.com
> wrote:
>
> The print semantics are different but the end result is the same. TinyG
> uses the AVRGCC stdio libraries for serial and takes the hit on including
> the float lib so it can support formatted print strings (“J Offset =
> %8.3f\n” and that sort of thing). This is too much code bloat for the 328s,
> so its not really an option on the Arduino hardware.
>
> I’m still uneasy about going the binary route unless it’s absolutely
> necessary. I think a little testing with the print routines are in order.
> It would be nice not to have to deal with binary on the receiving end.
>
> One small correction from earlier – a USART running at 115,200 interrupts
> roughly every 86 microseconds, not every 8.6 microseconds as the interrupts
> occur once per received character (typically 8 bits, 1 start bit, 1 stop
> bit) so it’s not quite as bad as it seems.
>
> —
>
> Reply to this email directly or view it on GitHub:
> https://github.com/grbl/grbl/issues/50#issuecomment-3680702
#21 – aldenhart 于 2012-01-27
Agreed on all points. Perhaps I misinterpreted the baud timing question. The processor doesn’t need to be concerned about the 8.6 uSec bit timing (which is correct) as the USART handles all that. The processor will, however, be interrupted every 86 uSec, and if a higher priority interrupt is running that takes longer than that serial characters can be lost. But that’s not a situation that should be of concern as the step timer gets in and out in way less than that. Sounds like I’m agreeing with you but arguing over details. No matter. Just me being thick headed.
#22 – chamnit 于 2012-01-28
I guess it would be a good time to make a summary on this discussion:
– Install XON/XOFF flow control as a toggle-able setting, either at compile-time or in EEPROM (to be discussed how). This will give users have a simpler interface for streaming g-code sans run-time commands. Higher level users can and should write their own advanced interfaces. ‘ok\n’ and ‘error:’ protocol will remain the same.
– Higher baud rates are available as a compile-time setting and would likely need to be faster than 9600 baud for fast status reports. This could be available as an EEPROM setting as well (will start a new discussion on settings). If we can do this as auto-config instead, this would be even better.
– Data flow back to the user, i.e. status reports, will be in ascii form only. Binary data, which will not be officially supported for now, may be packed into the higher ascii character set to avoid flow control problems.
If anyone has any objections to these points, let everyone know. Otherwise, we’ll solidify these points as goals and move on. Other things that still need to be ironed out on other threads is pin-reallocation for future uses and developments and how advanced settings are going to be handled.
#23 – nm156 于 2012-01-28
Hi all. I’m new here, but have been lurking GRBL for a long time. I have been playing around with some ideas myself. Not to hijack the thread, but I already have a boatload of ATMega32s, so I have been using that with some minor changes. (Basically a new #include to config.h that maps the registers so no grbl core changes are needed) I can post it if anyone is interested.
Back on the subject, I built this http://sensi.org/~svo/motori/ with a Mega32 some time ago. (I am not the author/designer) It also used RTS/CTS handshaking and the code is available.
My preference would be to have hardware handshaking.
#24 – chamnit 于 2012-01-28
Hi nm156. No problem with hijacking. Grbl is a community, open-source effort, so comment and ideas are accepted with open arms. That’s great that were able to create a simple config file to port to an atmega32. At least for me, I’m not looking to begin porting to other hardware platforms/CPUs until the grbl codebase has solidified a bit. But, I’m always keeping an ear out for things that will make it easier for people when the time comes.
Hardware handshaking would be nice, but as far as I understand, the Arduino Uno USB port does not have this capability, where only software flow control is possible. It would be feasible to just pin out the RX/TX and use other digital pins for hardware control, but I think this is outside the realm of the current development path.
#25 – jgeisler0303 于 2012-01-28
Chamnit is right: on the arduinos RTS and CTS are not properly wired. One reason for this is that RTS is used to reset the atmega for ISP via USB without any further user interaction. This is a nice feature of the arduinos and imho one of the reasons for there success even among avrgcc programmers. Of course that doesn’t mean that grbl should be an arduino only project, on the contrary! But the arduino will probably always remain grbls ‘home base’. So, in due time we will have to start to figure out how we can setup a customization/porting framework, probably preprocessor driven, just like mm156 did for the atmeag32.
BTW, really nice plotter.
#26 – nm156 于 2012-01-29
Sorry guys, I should have checked out the Arduino first. I’ve been using AVRs and WinAVR for quite a while, but have never used the Arduino stuff. I totally agree with you on this, having a broad standardized base is very important part of the project.
#27 – chamnit 于 2012-02-14
Over the last few days, I’ve been playing with XON/XOFF flow control in grbl. I have to say that I’ve had nothing but problems with it, perhaps similar luck that Simen initially had with it. (Could be related to using Macs but I also tried a Windows XP virtual machine). Tried several programs(screen,CoolTerm,PuTTY) and old Mac computers, all with varying results, after sending it a curve-heavy and rapid g-code program. Most of the time, the terminal program did not pause the transmit and overflowed grbl’s buffers. PuTTY on the XP virtual machine performed the “best” but still failed on occasion.
As for high-low watermarks, the settings I’ve used are 96bytes HIGH and 32 LOW with a 128 byte buffer. I’ve also tried 256 bytes. I know that Alden, stephanix, and Jens haven’t had any problems with this, but I can’t seem to figure out why I’ve not had any success. The XON/XOFF serial.c source from Jens’ and stephanix, among others, has been used, but all have the same problems. Can anyone shed any light on this?
#28 – jgeisler0303 于 2012-02-14
I’m sure the problem is on the client side. Serial programming is tricky and quick google trawl showed that apparently even “good” programs have their weak spots.
I know java rxtx is a bit buggy too. But maybe it helps to do some low level debugging. You can use java code in MATLAB and thus have low level command line control of the serial port. Or you use the python api, but I’m not sure how much access it gives you to the low level settings (e.g. send buffer size).
Good luck
#29 – chamnit 于 2012-02-14
I was beginning to come to this conclusion too. But, earlier in the conversation, it sounded like any terminal program should be able to transfer just fine. I guess not. A couple of days ago, I was digging into CoolTerm’s save file. It turned out to have a TX block size hidden parameter that is defaulted at 256bytes. Changing this to 1 byte improved but did not fix the file transfer problems. This seems to support this argument.
So, if not all standard terminal programs can use flow control with grbl well, is there a point of including it? It sounds like it really does require a special low-level interface to really take advantage of it. If we do include it, do we even need to have a way to turn it on and off? What I mean by this, if a user just communicates with grbl by a simple call-and-response and the high water mark (say 96 characters) of the XON/XOFF flow control is set larger than the length of any single line of g-code, they should never see the XOFF character sent back, nor an XON.
#30 – chamnit 于 2012-02-21
Here’s a status update on XON/XOFF. I have not been able to successfully get XON/XOFF flow control to work reliably with standard terminal programs, mainly due to having no control over how they work internally between system and programs. But, I have been able to get a very robust Python streaming script that works solidly for just about anything that I throw at it, especially at high feedrates. It handles the low-level serial communication without using the built-in pySerial flow control.
I’ve also set the low-water (XON flag) mark to 80 characters and high-water mark to 110. The 80 character mark is there so the conventional call and response still works without flow control characters, but I can change this.
So, my question is: Does anyone have any reason for me not to include this? Should I include this as a compile-time option for high-level user testing only? I’m having trouble deciding on what to do with this, as this changes things quite a bit and I’m still unsure if this is the right way to go.
#1 – simen 于 2012-01-25
Initially I wanted to just use xon/xoff or rts/cts flow control. My plan was to just
and off it goes. But my experiments yielded nothing. As far as I can tell either the serial adapters I use (FTDI mostly) or Mac OS X do not support flow control which kind of moots the whole ordeal on my part. I would love to be told I am wrong about this. Personally I think better buffering is the way to go. If we supported swift buffering to SD cards or something similarly convenient we might not need flow control at all because we would always be able to gobble up the input.