Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jog cancellation (0x85) sometimes not working #95

Closed
luben111 opened this issue Jan 17, 2017 · 69 comments
Closed

Jog cancellation (0x85) sometimes not working #95

luben111 opened this issue Jan 17, 2017 · 69 comments

Comments

@luben111
Copy link

Hi,
I'm using LabView to control GRBL v1.1 (downloaded the latest GRBL few days ago). Everything works like charm except that I spotted something which might be a glitch in the jog control. The bug is that sending 0x85 to the GRBL sometimes is not aborting the movement. Let me explain in details the circumstances when this occurs. I recorded all data sent to the COM port (char <…> is the 0x85) when the problem occurred :

G00 X-0.30 (1)
$J=G90X-558F2000 (2)
…$J=G90X-558Y-2F2000 (3)
…$J=G90X-558F2000 (4)
… (5)

  1. X+ was just pressed, send single step movement to absolute position

  2. If X+ jog key pressed for longer than 500ms the program sends jog command and instead of sending frequently jog steps I'm targeting the end of the area (x= -558). At this point the machine begins to move smoothly to the end of X axis (-558).

  3. While moving in X direction I can also press the Y- jog key , 0x85 was sent before the command to abort the current jogging movements. This works well, now the head moves simultaneously to end of X and to the beginning of Y axis.

  4. Y- key released , send 0x85 to abort current jogging and send new jog commad targeting end of X axis (x=-558)

  5. the X+ jog key released - sending 0x85 to abort the jog operations. The problem appears exactly here - in 2-5% of the cases the machine just ignores 0x85 command and continues to move.

Let me know if you find something incorrect in my jog commands which may cause the problem.

In short - sometimes 0x85 command is not aborting the currently executed jog movements.

Best regards,
Luben

@chamnit
Copy link
Contributor

chamnit commented Jan 29, 2017

@luben111 : I'll look into this when I get the time, but first could you verify that Grbl is receiving the 0x85 command when you notice it fails? Not exactly sure what would be easiest way to do this. Maybe edit the serial RX ISR code to toggle a pin whenever it reads a 0x85.

@luben111
Copy link
Author

Good point, I'll check this

@shamsiqbal
Copy link

@luben111 : you have mentioned that you are using labview would you like to share your work with me so i will be able to help/verify more/new features of grbl basically i am porting grbl to xmega avr where i am aimed to add G33 (tapping /threading ) g-code support and i need labview type application to test function integrity

@luben111
Copy link
Author

luben111 commented Feb 7, 2017

@shamsiqbal
There is LabView VI which is handling the communication over the serial COM in LV environment and in your case it doesn't bring any advantages compared to using any Serial COM terminal. This LV code is very sophisticated (state machine, position polling, etc.) and if you're not well experienced in LV it will be difficult to make it working. What you want to test for the G33 command and why you need this to be done exactly in LabView?

@shamsiqbal
Copy link

@luben111
i had worked in labview in past to develop many application for instrument interfaces and i can work on your vi too with little or no help from you
here are some key things which can be done in labview
pid tuning interface can be developed in labview (in your existing VI ) which is must thing for spindle closed loop control and it will took me lesser time with compere to develop brand new GUI i have added closed loop pid control in xmega port
after that i can integrate testing VI in existing VI for G33 function integrity/validity
its all about that i can work in labview and its easy for me instead starting from zero

i have retrofitted beaver vc5 cnc milling machine it was a mix of xmega and arduino nano but next version i am going to use only xmega128a1u
just finished porting and adding xmega hardware driver support now started working on jog keys that how to implement that function in grbl using GPIO of xmega i have added new grbl parameters for spindle pid tuning which need to be added in grbl interfacing GUI i will also alter spindle and feedrate override with potentiometer attached with xmega adc channel and show the actual override % on GUI

@luben111
Copy link
Author

luben111 commented Feb 8, 2017

@shamsiqbal
It sounds reasonable to use LV in your case. It will take me a little time to clean the code because it's a part from a large project. Let me know how I can send the files over email.

Porting to XMega128 sounds like a good idea (despite that very soon will be available port to ARM), do you have some PCB for it?

About jogging - the new GRBL v.1.1 has built in jogging control and I can say that it works really well - with the PC keyboard I can get technically the same behaviour as if using a pendant .

@shamsiqbal
Copy link

@luben111
well arm port doesn't solve any problems >-----------> will it gonna have G33 g-code support
about arm port i knew it since v0.9 its no use at all for me
if there is going to support for S-curve motion planning in grbl i can say 16 MIPS processing power is sufficient to control 6 axis closed loop dc servo control with virtually no speed limit on motion control thing its gonna be only limited by servo motor speed
i choose xmega because it have three hardware quadrature encoder counting option have double the processing power of avr mega and it can be used generate more steps then mega avr

about xmega pcb i have built breakout board using photosensitive film method you can build one using toner transfer method its a simple smd to dip breakout board once i am done with porting i will build complete pcb using my own built cnc milling machine

you can email me files on shams@bosonelec.com

i am using v1.0 not v1.1 for grbl port because i have found some issues in v1.1 where my newly added parameters wont get saved properly

@chamnit : good job to getting juices from arduino uno but plz admit this thing  that its almost end of arduino uno available resources due to flash memory limit so plz dont make grbl mega difficult where adding new function will become difficult i dont want to add a new issue stated above because i can understand that i wont be getting any helping answer from you 

i think its not important to port grbl on ARM but to go for S-curve motion planing . you have chosen lpc17xx arm port but it will be good choice if you had chosen stm32 nucleo board due economical price and on board debugging option available on it plz have look on stm32 nucloe boards available from st. cortex m3 vs cortex m4 and fpu is big difference i have 3k kintes mkv3 series cortex m4 mcu's in my stock but i still prefer stm32f4 family where standalone grbl based cnc controller is possible on stm32f429i discovery board in my opinion i will suggest you to plz consider stm32 family boards for grbl arm port

@chamnit
Copy link
Contributor

chamnit commented Feb 8, 2017

@shamsiqbal : Before you go and start saying things that you have no clue about, please try reading the other issues threads. In particular, the thread about moving on to ARM. There is a lengthy conversation there about this topic. Also the LPC port was done by a user and is not my primary choice, as you'll see if had you read the topic. And for everyone that is demanding to use this ARM chip or that ARM chip or even FPGA, I'm done talking about this. It's getting ridiculous.

@tbfleming
Copy link

@shamsiqbal : my brother and I ported grbl to the lpc17xx because there's a very large number of CNC boards sold which use it, but running a different firmware. As far as I know, grbl-lpc has faster step rates and block rates than any other grbl port. Will M4 perform better? Maybe. We'll see when you or someone else port to it.

@shamsiqbal
Copy link

@chamnit :
it looks like that if i open issue then you will be helping me on issue
"i am using v1.0 not v1.1 for grbl port because i have found some issues in v1.1 where my newly added parameters wont get saved properly"

further these are your comments on https://github.com/gnea/grbl-Mega/issues/17 thread
Grbl is being ported to 32-bit ARM
never mentioned that its your port or someone else port i do remember that there are similar comment from you on different issue thread that you are busy with arm port but i still apologies for my comments about arm port

in this thread i have pointed three things
i) G33 (tapping/threading) g-code support
ii) remain it compatible with other older version for everyone and add new function with minimal change for every user / developer v1.0 to v1.1 total revise for every GUI developer
iii) S-CURVE motion planning
dear @chamnit :
plz let me know if these were out of the scope of grbl
for G33 i have started work on it
for remain it compatible i have also faced issues
for S-curve motion planing i will be working on it after complete port of xmega

i have been reading grbl code since v0.8 i have less experience on grbl then you have and if i am not able to perform any additional function its obvious thing to ask help from experts its not how things works but its all about code compatibility with existing function in grbl

@tbfleming 👍
good job and great approach to help community i do have three lpc17xx embed boards but still i am not going to use these boards you have mentioned speed performance its obvious thing that 16Mhz vs 100Mz thats the speed difference in mcu you are using but here is my main question do you think that a common stepper motor and stepper motor driver going to to accept high step rate and going to perform well
higher step rate and rpm poor torque curve for stepper motors and loss of actual position
when i am done with xmega port i will going to upload a video on youtube that how my system works

@chamnit
Copy link
Contributor

chamnit commented Feb 8, 2017

never mentioned that its your port or someone else port

Please stop contradicting yourself. You stated this in your last post.

you have chosen lpc17xx arm port but it will be good choice if you had chosen stm32 nucleo board due economical price and on board debugging option available on it plz have look on stm32 nucloe boards available from st.

Please understand that answering questions on these issues threads takes time and energy. It's for determining if there are bugs or discussing important issues.

What is not for is teaching every random person how to code for Grbl. The code is well-commented for this reason. Nor does it make any sense to try to help you on an older version of Grbl, when everything is moving forward with v1.1. What you want would be a complete waste of time for myself and others here.

Also, all of the improvements you have suggested has been previously discussed in numerous locations and are already planned. Please try using Google and do some homework before posting here. It'll save everyone the precious time that they volunteer to help out. Time that should be spent on development or making something.

@tbfleming
Copy link

do you think that a common stepper motor and stepper motor driver going to to accept high step rate and going to perform well higher step rate and rpm poor torque curve for stepper motors and loss of actual position

ClearPath servos.

@tbfleming
Copy link

Also, steppers on current-generation hobby lasers run close to 100 kHz. Future hobby lasers may need higher rates.

@luben111
Copy link
Author

luben111 commented Feb 10, 2017

About jog cancellation problem (I'm sorry for the thread contaminated by other posts):

In grbl.c (lines 91..) was added the following code:

@-------------------------------------------------------------------------------------------------
// Determine if the line is a jogging motion or a normal g-code block.
if (line[0] == '$') { // NOTE: $J= already parsed when passed to this function.
// Set G1 and G94 enforced modes to ensure accurate error checks.

// 10/02/2017 modification done to detect if the JOG command was accepted. Scope should be attached to pin 4 of ISP header (MOSI - PORTB_Bit3)
// check with scope do you get the pulses when the jog command failed (was not accepted)
SPINDLE_ENABLE_PORT ^= (1<< 3); // toggle pin 11 on Uno when new jog command was accepted**
gc_parser_flags |= GC_PARSER_JOG_MOTION;
gc_block.modal.motion = MOTION_MODE_LINEAR;
gc_block.modal.feed_rate = FEED_RATE_MODE_UNITS_PER_MIN;
#ifdef USE_LINE_NUMBERS
gc_block.values.n = JOG_LINE_NUMBER; // Initialize default line number reported during jog.
#endif
}
@-------------------------------------------------------------------------------------------------

The code changes the state of PB3 (pin 4 of ISP header) each time a new jog command accepted. What I see is that each time I send a jog command it was accepted correctly. The sequence I used is similar to the sequence listed initially:
$J=G90X-558F2000 (2)
$J=G90X-558Y-2F2000 (3)
$J=G90X-558F2000 (4)
the scope snapshot is below - you can see exactly 3 changes of the signal:
scrn0027

So receiving the jog command is correct, what should be wrong is the cancellation of the running jogging. Now will add some another pin change to show the jog cancellations in time as second trace on scope.

@luben111
Copy link
Author

luben111 commented Feb 10, 2017

I made the following modifications into serial.c (line 161) in order to show the 0x85 cancellation in action - each time 0x85 is cancelling something PB5 will toggle (visible on pin 3 of ISP).

@------------------------------------------------------------------------------------------------
if (sys.state & STATE_JOG) { // Block all other states from invoking motion cancel.
system_set_exec_state_flag(EXEC_MOTION_CANCEL);
SPINDLE_ENABLE_PORT ^= (1<< 5); // toggle PB5 pin (pin 3 on ISP)
}
@------------------------------------------------------------------------------------------------

Here are the timings from the scope:
failure
ok

It seems there is really some problem and it occurs in the following conditions

  1. Send a jog command
  2. Send 0x85 command (to cancel the effect of previous command 1)
  3. Send new jog command before the head movement of command (1) stopped
  4. Short time after you send (3) and while the head is still moving from 1 send new 0x85 to cancel all jog commands.

The misbehaviour is - if 0x85 was sent before command 1 head movement stopped, command 2 will be executed, i.e. 0x85 is not affecting jog commands which were accepted and waiting to be executed while previous command was cancelled but head is still moving.

My explanation is:

  • After you send 0x85 (2) the machine begins to decelerate - cancellation of (1)
  • you send new jog command (3) immediately after (2). Notice that head is still moving.
  • if you send new command 0x85 (4) before command (1) was completed (head stopped) it will be accepted but command (3) will not be cancelled (it's hanging probably in some other buffer).

@chamnit
Copy link
Contributor

chamnit commented Feb 10, 2017

@luben111 : Thanks for digging into this. It's possible there may be some bug in the state machine. I didn't vet it as much as I have in the past prior to releasing v1.1. But, first:

  • With sending (3) immediately after (2), what exactly does Grbl do? Does it start to slow down and then accelerate again? Does it stop and then go? Or does it continue moving like nothing has happened?
  • If it starts slowing down and accelerates again, It's possible that Grbl is doing what it is supposed to by stopping the machine. However, when you send the next command, it may have gotten queued somewhere between the serial buffer and the planner and executed immediately after the cancel completes.
  • Regarding (4), sending another 0x85 jog cancel will be ignored, if the current one hasn't been executed and cleared yet.

I suppose the question would be, what is the situation that you are sending a jog cancel and then still are sending jog commands? Does Grbl operate ok if you stop sending jog commands until it stops and then resume streaming jog commands?

If so, perhaps I need to add a [Jog End] message for GUIs to know when the jog motion ends.

@luben111
Copy link
Author

@chamnit
With sending (3) immediately after (2) - I can't distinguish what's exactly happening, for sure after sending (2) the machine begins to decelerate (there is a hiccup, not sure if it stops completely). It will be very difficult to get this data without some debugging tool.

I suppose the question would be, what is the situation that you are sending a jog cancel and then still are sending jog commands?

The situation is very simple and this is how my implementation of jogging is working on LabView:

  1. In order to avoid constant sending of jog commands to the serial port I send single jog command which is targeting the end of the X or Y area. For example moving in X direction against one end (let's say it's X=300.00) I could send simply $J=-X299F2000 and everything will be all right. With this approach I get two benefits:
    a) I'm sending only a single command to the jog control (no need to resend commands)
    b) it's guaranteed that the jog will not exceed the working area of the machine (no need to check working coordinates)

  2. If the jog button was released - I just send 0x85 and movement is cancelled (this is working well)

  3. The problem appeas if you use for jogging two or more buttons. If I press second button while the fist was kept pressed (to move simultaneously on XY) I send 0x85 to cancel the previous command and then I send the new command - for example $J=-X299Y-199F2000 . The machine makes a small hiccup and continues to the new positions, now moving on X and Y simultaneously.

  4. The problematic moment is when the keys were released - when I release the two pressed buttons normally there is some delay between two events (releasing the first and releasing the second button). In this time gap the bad events occur - for example when I release the Y button first I send 0x85 to cancel the movement on XY ( $J=-X299Y-199F2000) and then I send a new command $J=-X299F2000 to continue moving on X. On this stage everything works fine.

  5. A short time after (4) the second button was also released and I send a new 0x85 to cancel all movements (this is the end of jog movement). And here the misbehaviour occurs - this 0x85 somehow doesn't clear the last jog command in the buffer.

Maybe adding [Jog End] message will not improve things because now we have to hang around the serial to see if it's accepting or not the 0x85 commands and if not to resend it. The best approach is if we can locate where this happen and to fix the logic.

@chamnit
Copy link
Contributor

chamnit commented Feb 10, 2017

@luben111 :

  • Regarding seeing if Grbl stops, you can send a status report when the jog cancel completes in protocol.c's cycle stop code. This should show you the current velocity, which should be zero.
  • Grbl's jog cancel was designed to expect the cancel to complete before send new commands. I was not expecting more commands to be sent during this time. Jog cancel is there to cancel long motions, not very quick ones. I can make this more robust, but this is how it was intended to work.
  • In your case, send only a short time segment of motions, as outlined in the jogging document. Keep the planner just full enough to attain the programmed speed. Anytime there is a direction change, just send the new direction commands and let what's in the queue complete. Don't send a jog cancel. If done right, it'll actually run better this way because the planner can account for small direction changes, decelerate when it needs to, and keep the speed optimal.

@luben111
Copy link
Author

@chamnit

  • sending status report and getting the data on PC is very slow process - on USB it may take up to 30ms to complete, i.e. using the status report to take quick actions is not the best approach for PC programs (but it might be OK for controllers which communicate directly with the Atmega328)

Grbl's jog cancel was designed to expect the cancel to complete before send new command
Is there some event to show that jog cancellation was completed?

If this was the way how the jog cancellation was designed I can make a patch and delay the 0x85 command to the GRBL so it will take effect. Another option is to send it several times by hoping that one of the commands will come in the right time.

  • I agree that sending short segments will make the jog movement extremely smooth (no hiccups) but on the price of excessive communication

@chamnit
Copy link
Contributor

chamnit commented Feb 10, 2017

@luben111 :

  • I meant to compile in a status report call directly in the source code. Not from a PC. So it generates one automatically when it reaches that point. Similar to how you set the pins.

  • It's best to fix the jog cancel issue so that it doesn't miss a cancel command, rather than send multiple cancels. I'll probably take a look this weekend, but can't guarantee anything. My workload is full right now.

  • Yes, sending short segments will have a lot of comm traffic, but Grbl can handle it. If there is a stream interruption, Grbl will just slow down to a stop until there are more motions.

@luben111
Copy link
Author

@chamnit

It's best to fix the jog cancel issue so that it doesn't miss a cancel command

yes, this is the best approach - keeping some misbehaviour in the code and explaining to everybody how it should be avoided is not great. There is something else - very often behind a bug stays some other problem which is invisible.

BTW, the GRBL code is really a masterpiece, I really appreciate all your efforts to support such sophisticated and well working engine.

@terjeio
Copy link

terjeio commented Mar 1, 2017

I have a similar problem but then I am trying to execute jogging by calling code directly, not via serial comm, so I am possibly on very thin ice. IMO the problem could be related to the EXEC_MOTION_CANCEL flag beeing reset before the cancel is completed, if a new cancel command is received before completion it will set EXEC_MOTION_CANCEL flag again and thus possibly cause all kinds of problems later? I am going to try to avoid this problem by not allowing the EXEC_MOTION_CANCEL flag to be set until the cancel is completed, not sure if this could work:

case CMD_JOG_CANCEL: if ((sys.state & STATE_JOG) && !(sys.suspend & SUSPEND_JOG_CANCEL)) { // Block all other states from invoking motion cancel. system_set_exec_state_flag(EXEC_MOTION_CANCEL); } break;

If not I will have to dig deeper...

@luben111
Copy link
Author

luben111 commented Mar 2, 2017

@terjeio The movement cancellation is actually working - whenever you send jog cancellation it will always stop the head. What is not working is purging the buffers of new incoming jog commands. So the scenario when you'll get jog misbehaviour is when you send the following sequence in short time:

  1. send jog command
  2. send jog cancellation
  3. send new jog command
  4. send jog cancellation
    You'll find very often that 3 is not cancelled but 1 is always cancelled.

In my case instead of sending multiple small segment jog movements I'm sending single jog command targeting the end of the working area (left, right, top or bottom). When doing horizontal and vertical movement simultaneously (pressed for example left plus bottom arrows of keyboard) and when releasing both buttons almost simultaneously the described above sequence may occur. For example if moving left + up and releasing buttons I may get the following picture:

  • head is moving left + up (there is active jog command)
  • released up key:
    a) sending jog cancellation
    b) sending new jog movement to the left side
  • released left key
    c) send jog cancellation. NOTICE - this cancellation is not affecting the b) command

@terjeio
Copy link

terjeio commented Mar 2, 2017

@luben111 : "purging the buffers" is the clue, since jog cancellation is picked off the input stream in real time the jog command to be cancelled may still (partly) be in the serial input buffer? I''ll check what happens if I flush the buffer on a jog cancel but I suspect it will not be a 100% foolproof solution.

@terjeio
Copy link

terjeio commented Mar 2, 2017

@luben111 : Thinking about this some more before I commence testing: flushing the serial buffer, inserting a CAN (ctrl-X) into the buffer and use that to flush the line buffer in protocol.c may be even better.

@terjeio
Copy link

terjeio commented Mar 2, 2017

@luben111 : my solution above seem to work, I think you should try it. There may be a edge case related to the time window from the job command is queued for execution to sys.state = STATE_JOG; is set (in jog.c), if the cancel arrives in that window it will be missed. This is what I did:

protocol.c

   while((c = serial_read()) != SERIAL_NO_DATA) {

      if(c == CMD_RESET)
    	  char_counter = 0;

      else if ((c == '\n') || (c == '\r')) { // End of line reached

serial.c

case CMD_JOG_CANCEL:
     serial_cancel_read_buffer();
     if (sys.state & STATE_JOG) { // Block all other states from invoking motion cancel.
        system_set_exec_state_flag(EXEC_MOTION_CANCEL);
    }

added (NB! ARM code in my port)

void serial_cancel_read_buffer(void) {

	rx_head = 1;
	rx_tail = 0;

	rxbuf[0] = CMD_RESET;

	GPIOPinWrite(RTS_PORT, RTS_PIN, rts_state = 0);
}

Disclaimer: I am still trying to get to grips with the innards of Grbl so bear over with me if I am messing things up.

@luben111
Copy link
Author

luben111 commented Mar 2, 2017

@terjeio - where are these vars:
rx_head
rx_tail
rxbuf[0]

I can't get them in GRBL 1.1 for Arduino UNO

@luben111
Copy link
Author

luben111 commented Mar 2, 2017

@terjeio
Adding only the code
if(c == CMD_RESET)
char_counter = 0;
into protocol.c doesn't fix the problem

@terjeio
Copy link

terjeio commented Mar 2, 2017

For the original code I guess it would be something like this:

void serial_cancel_read_buffer()
{
  serial_rx_buffer_tail = 0;
  serial_rx_buffer_head = 1;
  serial_rx_buffer[0] = CMD_RESET;
}

Adding your code above does nothing, you need to have the serial_cancel_read_buffer in place also.

Edit: for clarity...

@luben111
Copy link
Author

luben111 commented Mar 2, 2017

@terjeio
I added the code as you suggested. There is substantial improvement - the problem is very difficult to be reproduced now. From ~100 attempts I got only once the misbehaviour (where before I was able to get almost every second jog to misbehave). It's so rare that I did the experiments again to ensure it's not some glitch, unfortunately if you're persistent and if you try to release the keys with some specific timing you can see it again.

The main challenge is that we need to cancel the current movement but we can't just stop the head, it will take some time to complete the task and during this time window something bad can happen. It's something about buffers / queues.

@chamnit
Copy link
Contributor

chamnit commented Mar 9, 2017

Ok fellas. I've had a bit of time to review what you have been up to and looked at the source code to isolate the issue. Based on @luben111's descriptions, this is my evaluation:

  • Suppose Grbl is executing a jog cancel and is actively decelerating(1), but has not completed the cancel. Grbl receives a new jog command during this time(2), which is placed in the serial RX buffer. If Grbl receives another jog cancel command (3) while (1) is still decelerating, it'll ignore it because it is already executing a cancel. (3) will not and can not cancel (2) in the serial RX buffer, because Grbl does not know what kind of information is in it or if it is a complete transmission. You have to wait until the first cancel (1) completes to find out. By design, (3) is correctly thrown away as a repeated cancel command.

  • Suppose Grbl completes the first jog cancel (1) and has started to parse/plan (3) next jog command inside the serial RX buffer. In the few milliseconds prior to executing (3), Grbl receives another jog cancel command (4). Grbl will ignore this jog cancel (4), because it is technically still IDLE and there is nothing to cancel. Grbl can do a better job with this particular scenario, but I'm not convinced that this is a bug. During this time, Grbl may have received more data inside of its serial RX buffer. It could be another jog command, or something else. If you cancel (3) now, do you cancel whatever else is in the serial RX buffer? When do you stop purging? Which do you purge, if there are non-jogging commands mixed in there? That isn't immediately clear.

  • Suppose (3) is now executing and yet another jog cancel command (5) is received, this will correctly terminate the active jog (3) and come to a stop.

To me, this is still a non-issue, if the GUI implements the jog cancel as intended. If you cease sending jogging commands after sending a jog cancel 0x84 command and only resume once the jog cancel is complete, then there is no problem. To me, the matter is the GUI knowing when the jog cancel is complete. And as I stated before, Grbl can issue a quick message, like [Jog End] to facilitate that without having to use status reports to see if the state is IDLE. This is the simplest solution without having to hack the state machine and risk breaking stability.

@luben111
Copy link
Author

luben111 commented Mar 9, 2017

@chamnit
I agree - your proposed jogging control algorithm should not have issues with the existing GRBL. As I see fixing the jog cancellations may require deep changes so probably it's worth to try your approach.

@luben111
Copy link
Author

@chamnit
There is one possible patch for the problem when using my algorithm for jogging (sending single jog commands targeting the end of the working area) which should work with the original unmodified GRBL v1.1. The idea is quite simple:

  1. Send jog command to the point which is the end of the working area (if moving simultaneously on 2 or 3 axis - send a jog command to the end points of all active axis). This works pretty well and also doesn't require any communications with GRBL during the move, the head will stop automatically on the end of the working area.

  2. If the user wants to stop the jog movement and we have the worst case - from two axis movement to no movement we just need to keep for 0.2s a history of the previous state and if case detected we send with delay an additional jog cancellation command. In short - if the control program detects the case when the jog cancellation will be ignored it should send with delay an additional jog cancellation.

@chamnit
Copy link
Contributor

chamnit commented Mar 10, 2017

@luben111 : There is an old trick that I forgot about to know when something is in sync. If you send a G4P0 command, this will return an ok when Grbl is IDLE. So, if you are streaming a lot of jog commands and issue a jog cancel, just send a G4P0 and wait for its ok to return before resuming more jog commands. The latency of this is minimal. Much faster than 0.2s.

@luben111
Copy link
Author

@chamnit Thanks - it's very useful !

@chamnit
Copy link
Contributor

chamnit commented Mar 11, 2017

Closing this issue as it seems to be resolved. @luben111 feel free to open a new issue if you run into problems with the proposed solution.

@arkypita
Copy link

arkypita commented Apr 29, 2019

Hi all, same problem here.

I send:

$J=G91X1.0Y1.0F10\n
$J=G91X1.0Y1.0F10\n
$J=G91X1.0Y1.0F10\n
(many of them)
0x85
(no more jogging command)

But jogging continue even after sending Jog Cancel immediate command.
Here is a video: https://youtu.be/34LQxzKqU3w
Any hint?

@zeevy
Copy link

zeevy commented Apr 29, 2019

I think this is what jog cancel command will do

  1. Clears the planner buffer, tries to stop the machine.
  2. Jog commands which are in rx buffer at this time will be added to planner buffer.
  3. And jog continues.

I also observed no matter how many jog commands are there in the rx buffer after jog cancel, only one gets through planner buffer

@zeevy
Copy link

zeevy commented Apr 29, 2019

My work arround is, dont fill the planner buffer completly. If it is filled then jog commands will get queued in rx buffer which can not be cleared with jog cancel.

In my app i do like

if(PlannerBuffer > 5) then only send jog command.
This will make sure my jog commands wont sit in rx buffer.

Even with this approch i still gets this problem, but that is very very rare

@arkypita
Copy link

This is what I am doing with button:

  1. On mouse down I set a variable called "jog_direction" with required jog direction, and I send a first jog command.
  2. In the thread that read the com port, when I receive an "ok" i check if jog_direction is not null, in that case I put a new jog command (so I put a new jog command every time the previous command receive its own "ok" reply).
  3. On mouse up I set jog_direction to null (so any ok does not longer send any new jog command) and I send 0x85.

@arkypita
Copy link

arkypita commented Apr 29, 2019

My work arround is, dont fill the planner buffer completly. If it is filled then jog commands will get queued in rx buffer which can not be cleared with jog cancel.

I am not sure to have real time and affordable knowledge of planner buffer.
I mean, they are reported by "Bf:15,128" in realtime status report, but look like that they could be disabled https://github.com/gnea/grbl/wiki/Grbl-v1.1-Configuration#10---status-report-mask

However I get a try

@zeevy
Copy link

zeevy commented Apr 29, 2019

Ya they can be disabled, in my app i check for that and re enables it.

You can use G4P0 to sync the buffer after each jog command, this will also solves the problem.

@arkypita
Copy link

if(PlannerBuffer > 5) then only send jog command.
This will make sure my jog commands wont sit in rx buffer.

Thanks for the hint, it works.
how did you size the value of 5?

@zeevy
Copy link

zeevy commented Apr 29, 2019

Its trail and error method, I updates the status report for every 150ms, based on that i found 5 is most suited value.
keeping the value to 5 with 150ms, always leaves enough room in planner buffer. (even this fails if you try to fill the rx buffer at high interval let say 30ms = 150/5)

@arkypita
Copy link

I have also tried to remove sending of 0x85 directly from MouseButtonUp (that could happen at any time with some command unprocessed in grbl rx buffer) and moves it to rx thread.

In MouseButtonUp I "schedule" jog cancel by setting a variable. In the rx thread I send the 0x85 only when I know that no pending commands (all previously sent command have received the ok/error response). This is same test I do to decide to enqueue a new jog command when I want to continue jog.

This works too (seem add a little delay) but neither this solution or checking PlannerBuffer does satisfies my aesthetic sense :-)

Sending a single jog command to the point which is the end of the working area as suggested by @luben111 seems to be the better way to do that, and since I don't need to runtime change the speed (not a joystick) the more effective. I'll do some test in this direction too.

@zeevy
Copy link

zeevy commented Apr 29, 2019

Waiting for "Ok" before sending any new jog command does not prevent the error. Grbl sends ok as soon as it get the jog command. If you are waiting for ok before sending any new jog commands, then you may not have a pending jog commands at your end but grbl still may have few commands left in its RX buffer. It may or may not even finished its first jog command.

Delaying the jog cancel could be danger (may be not for laser mills), as machine will not stop at the expected location.

@abdset
Copy link

abdset commented Feb 16, 2020

How to you guys send 0x85 to grbl, i mean what it the command line for that ?
Sorry but i'm beginer and i tryed :
Serial.println("0x85")
and even
Serial.println(85)
but i got error that the command wrong.

i'm interfacing esp32 between arduino uno and grbl sender using bluetooth serial com, everything is working just fine (even sending job file is perfect) and i wana add jog button to my controller box by programing the esp32 to listen to the pushed buttons and send to arduino the jog commands, all is good but can'nt stop the jog when i release the button because i don'nt know the right command for that.
I apreciate any help.

@langwadt
Copy link

I haven't really used Arduino but I'd expect something like Serial.write(0x85)

@abdset
Copy link

abdset commented Feb 16, 2020

Thank you langwadt, i finaly figured out some different aproach without using cancel command and here is my code put into ESP32 to send jog commands to arduino uno and it turns working just fine:
`#include "BluetoothSerial.h"

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run make menuconfig to and enable it
#endif

BluetoothSerial SerialBT;

uint8_t serialValue = 0;
bool pressed = false;
uint8_t buttonPinNumber = 0;
char *pinsListStep [6][2] = {{"25", "X0.5"}, {"26", "X-0.5"}, {"27", "Y0.5"}, {"14", "Y-0.5"}, {"32", "Z0.5"}, {"33", "Z-0.5"}};
String jogStep = "";

// Buttons pins setup
// ==================
const int xButtonPlus = 25; // Jog +X
const int xButtonMinus = 26; // Jog -X
const int yButtonPlus = 27; // Jog +Z
const int yButtonMinus = 14; // Jog +Z
const int zButtonPlus = 32; // Jog +Z
const int zButtonMinus = 33; // Jog -Z

void setup() {

// Serial and BT setup
// ===================
Serial.begin(115200);
SerialBT.begin("ESP32_CNC"); //Bluetooth device name

// Buttons pins mode setup
// =======================
pinMode(xButtonPlus, INPUT_PULLUP);
pinMode(xButtonMinus, INPUT_PULLUP);
pinMode(yButtonPlus, INPUT_PULLUP);
pinMode(yButtonMinus, INPUT_PULLUP);
pinMode(zButtonPlus, INPUT_PULLUP);
pinMode(zButtonMinus, INPUT_PULLUP);
}

void loop() {

// BT <-> COM data flow
// ====================
if (Serial.available() > 0) {
serialValue = Serial.read(); // Added this for further status read needs
SerialBT.write(serialValue);
}
if (SerialBT.available() > 0) {
Serial.write(SerialBT.read());
}

// Joging
// ======

// Reading which button has been pressed and take its axis move
// ------------------------------------------------------------
for (int i = 0; i < 5; i++) {
if (digitalRead(atoi(pinsListStep[i][0]) == LOW)) {
buttonPinNumber = atoi(pinsListStep[i][0]);
jogStep = pinsListStep[i][1];
i = 6; // Just to stop the loop
}
}

// Moving according to the pressed button
// --------------------------------------
if (digitalRead(buttonPinNumber) == LOW && pressed == false) {
pressed = true;
Serial.println("$J=G91 G21 " + jogStep + " F7200");

delay(350);
// After 350 mSec the button still pushed, user keeps holding it, lets keep sending till he release it.
while (digitalRead(buttonPinNumber) == LOW) {
  Serial.println("$J=G91 G21 " + jogStep + " F7200");
  delay (15); // Don'nt overload the buffer.
}

} else {
if (digitalRead(xButtonPlus) == HIGH && pressed == true) {
pressed = false;
}
}

// Lets put some latency to remove button electrical noise
// -------------------------------------------------------
// Still working on this (not ready yet)

}

`

@abdset
Copy link

abdset commented Feb 16, 2020

I dont know why some lines of code look different shape but they are all one piece.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants