gnea / grbl-Mega

An open source, embedded, high performance g-code-parser and CNC milling controller written in optimized C that will run on an Arduino Mega2560
https://github.com/gnea/grbl/wiki
Other
495 stars 230 forks source link

Lathe pulse input for threading (feature request) #26

Open tklus opened 7 years ago

tklus commented 7 years ago

Hey guys, Just wanted to get this on the list for grbl mega. Not sure how this would be done but it would be nice to have the capability to do threading with a grbl controlled lathe.

If this should be with grbl arm I can move it. Not sure what the difference is between arm and mega.

Thanks! Tim

fschill commented 6 years ago

@shooter64738 actually, after reading your thoughts, I guess the clean way for feed hold on mill as well as lathe is: stop the spindle, and wind down all other axes in sync with the spindle slowing down. On a purpose-built machine (Fadal, etc.) this can be guaranteed, but with GRBL everyone does it differently, and on some machines the spindle switch might not be controlled by GRBL (my machine, for example). So the issue remains, that we can't assume that the spindle will stop, and feed hold has to work at all times. There is also the issue of completely stopping motion when the spindle is stopped - as GRBL requires a minimum feed, it never stops completely. I tried to insert a feed hold automatically if the spindle speed is zero, but I think it didn't work (need to check again, can't remember what the current state is).

Regarding behaviour between mill and lathe: rigid tapping is a different GCode to threading, so it could be implemented next to each other. As was said above, I think hitting feed hold accidentally during threading/rigid tapping will break the tool and ruin the work, but not much more in almost all cases (unless cutting some really big threads, maybe). So the users that don't heed the warnings ("DON'T push feed hold during those cycles"), re-education will happen automatically... ;) who hasn't broken a tap...

109JB commented 6 years ago

All the GRBL realtime commands should always be active, and for consistency always do the same thing.

I agree, but am not opposed to alternative behavior if it makes sense. As noted, not everyone implements Grbl on their machines the same way, and some, myself included have written their own GUIs to fit their own needs on that end. For this reason, perhaps an override to feed hold during G95 or other synced motion as @terjeio suggested should be implemented but as a define that can be set in the config.h file like so many other things in there. However, I would still vote to have the default setting for this to be feed hold working all the time.

On a normal cnc lathe feed hold while threading retracts in X out of the threads then returns to thread start point in Z. When start is hit again it will recut the last thread.

I too think this is the absolute best option for lathe threading but don't see it as absolutely necessary. It also seems like this would all have to happen within Grbl, and would have to be tied to a G76 command rather than G95, since the parameters included in G76 would be necessary to define which direction to retract in X (internal/external threads), how far to retract, etc. I suppose the Mega has plenty of space to define a G76 canned cycle but the cycle would need definition as well as the alternate feed hold behavior. Just thinking out loud here.

terjeio commented 6 years ago

@109JB : sorry for my comment about grbl entering alarm when a reset is issued. It is due a modification I did a year ago to my branch - I have to revisit that. Perhaps I will add another input signal for eStop that triggers a reset and then enter alarm state. As it stands now grbl has no way of knowing whether eStop is active as far as I can tell. Is currently the best practice to pull the MCU reset pin low when eStop is active, thus halting the processor? Going back to the master code I see there is a configuration for whether grbl enters alarm state at boot-up, I think that should always happen if the reset signal (or eStop) is active.

As for disabling feed hold then this can be implemented by a M-code, as per linuxcnc spec: M53 Adding support for M49 - M51 could also be useful?

As I understands it grbl tries to implement functionality in a similar vein as linuxcnc, perhaps it should be checked how the complexities around threading are handled there?

109JB commented 6 years ago

@terjeio - The config.h settings that force Grbl into an alarm state only does so for a hard reset or a power cycle. It does not place Grbl into an alarm state during a soft reset resulting from invoking a ctrl-X command.

In regard to how LinuxCNC handles things, I use LinuxCNC as well as Grbl and have a virtual machine with LinuxCNC. I can report the following regarding how LinuxCNC implements a few things based on running the LinuxCNC simulator in the virtual machine.

G95 using LinuxCNC - Both feed hold and program stop work immediately during the synced moves while in G95

G33 using LinuxCNC - Feed hold is delayed until the end of the G33 move, but program stop works immediately stopping the spindle stops and all axes.

G76 using LinuxCNC - Feed hold is delayed until the end of that cutting pass but program stop works immediately, stopping the spindle and all axes. This makes sense since G76 is essentially a bunch of G33's

Based on this, LinuxCNC does delay a feed hold during G33 or G76 presumably to not ruin the thread, However, since what @fschill has only implemented a G95 thus far, it seems that leaving feed hold alone at this point fits what LinuxCNC does regarding feed hold during G95 moves.

If G33 or G76 are implemented, then it may be prudent to follow LinuxCNC convention and have feed hold wait until the end of either a G33 or G76 move. I really don't see an issue with leaving feed hold to immediately pause. I'd just personally remember to not hit it during the threading cuts. If others really want this though I am not opposed. However, since this would potentially break a bunch of GUIs and how program stop is implemented in them I would vote to leave the existing feed hold as is for existing GUIs, and create a new feed hold that waits until the end of the move for use in new GUIs that want to use this behavior.

terjeio commented 6 years ago

@109JB : Many thanks for the info about how linuxcnc works, useful for me as I am trying to implement G33. I am making good progress on the pendant GUI so hopefully I will soon be back at the lathe for real life testing.

As for the reset I have added a new signal (input pin) for eStop so I can boot the system and provide feedback to the user. I do belive the way I implemented this will not break exsisting GUIs, and it should be safe provided that a active eStop signal also cuts power to the motors. To be tested...

I find it a bit strange that a active reset signal is ignored at boot up, IMO this indicates that there is a fault condition that should be addressed.

109JB commented 6 years ago

I find it a bit strange that a active reset signal is ignored at boot up, IMO this indicates that there is a fault condition that should be addressed.

I'm not sure I completely understand what you mean above. If you are referring to the soft-reset behavior vs. the hard reset/power cycle behavior, it seems the difference in behavior was by design. It has been the recommended practice for flushing the buffers for many years. Here is one post where the developer recommends this procedure for buffer flushing

https://github.com/grbl/grbl/issues/195

I find it a bit strange that a active reset signal is ignored at boot up,

If you mean to imply that Grbl will ignore a reset signal on the Grbl reset pin, then I would have to say that I have not tried this but would think this would place Grbl into a reset loop until the pin is cleared.

What I was referring to is a reset that occurs from invoking a ctrl-X command. On the subsequent boot there will be no active reset condition.

As for disabling feed hold then this can be implemented by a M-code, as per linuxcnc spec: M53 Adding support for M49 - M51 could also be useful?

The above is from your previous post. I re-read and realized that I had wanted to reply but didn't.

M49-M50 and M53 - Although there is are LinuxCNC specifications for these, there are not RS274-NGC specifications. Also consider that these command can have different meanings on different machines. For example, on an Okuma mill, M53 specifies the retract plane for canned cycles. Looking at an Okuma list, there doesn't appear to be a command to disable feed hold. Personally, when working as a CNC machinist for several years, which included quite a bit of hand programming (I'm getting old), I never remember an occasion where I placed a M49-50 or M53 in any program I wrote in this context and I don't ever remember encountering this in any program I ever ran. I can't really think of a good reason to place this in a program except for not trusting an operator to use feed hold or override appropriately. In that case the operator is probably not qualified to be at the machine. In any case these are not commonly used commands.

M53 specifically - Implementing it without other changes would still cause problems with existing GUIs because feed hold is commonly used in GUI implementation of program stop. I guess what I am trying to stress is that any change to how feed hold works can affect other things that other users or GUI creators, etc, have implemented, including, but not limited to program stop.

I realize that it may seem like I am just putting down your ideas, but that isn't my intention. I actually would like to see some times when feed-hold doesn't happen immediately, like during a cutting move in a G33 or G76 cycle. but only if it doesn't break existing functions. In that vein, I think I may have a proposed solution.

I suppose that possibly the easiest path to implementing this could be to use the existing "!" feed hold character as it currently is and always active. Then a new realtime character could be implemented which could be used to trigger the same feed-hold routine but only when appropriate based on M53, G33, G76, etc. That may be the cleanest solution as it doesn't change the existing feed-hold function at all but adds a new one that can be implemented however a user sees fit. This would guarantee that the current feed hold doesn't change and therefore any GUI using it doesn't have to change their operation, but a new GUI can choose to use the new one, or the old one, depending on what the particular need is.

109JB commented 6 years ago

@fschill - So I decided to get a pseudo-lathe going the quick way so I can try out your code. I plan to outfit my mill spindle with some optical switches to act as a spindle encoder and mount an R8 lathe chuck to try things out. I plan to do something similar to this http://7xcnc.com/hardware/encoder/ but can alter the number of slots that are in the disk. I plan to use 2 optical switches with one for index in case it can be used later. This brings up a couple questions:

  1. Does your code always keep track of the encoder pulses even when not in G95?

  2. I seem to remember your setup had 4 ppr and I am wondering if the ppr count will affect overall system performance. I guess this is tied to question 1

  3. If ppr count does affect system performance, have you done any experiments or testing to see what those affects are?

  4. I can make a disk for testing now and always change it if needed, but wondered if you had a recommendation on how many slots in the disk I should start with?

Thanks,

John Brannen

fschill commented 6 years ago

Hi,

  1. yes, at the moment the interrupt is always on. I have not noticed any problems so far, and I did use the CNC lathe a few times since in non-threading operations.
  2. &
  3. I haven't done any tests regarding performance and maximum pulse frequency. The maximum on my lathe is 1200 RPM *4 ppr, and I haven't noticed any problems for now.
  4. As the counter for encoder ticks can overflow, I would recommend a power of 2 ticks per rev, until this is addressed (so that it's still a full revolution even if it does overflow). I think, given my experience, a low number of ticks should be enough. You could even try with just one, then the spindle position will always be absolute. A larger number of ticks will improve the adaptation if the spindle speed changes, so if your lathe is very steady you need less, if it slows down a lot under load then maybe more (I think 16-32 should be plenty).
109JB commented 6 years ago

@fschill Thanks for the reply. I've ordered the optical encoders and will likely try it out with 4 ppr as you have done. Unfortunately it will still probably be a month to get things all sorted out due to family commitments, but will still be loads faster than doing a complete lathe conversion. I'll let everyone know how it goes.

Muscles commented 6 years ago

@fschill I was trying to use your grbl for a lathe, where should I put the rpm sensor?

fschill commented 6 years ago

The RPM sensor typically goes on the main shaft for the spindle/chuck. My lathe actually already had an encoder for the RPM display. In this case, it's a ring clamped on the shaft on the gear side of the spindle bearing, with 4 little magnets embedded. A hall sensor reads the magnets and generates a pulse sequence (pulses are low in my setup, so at the moment my version of GRBL reacts to falling edges). Note that this is still experimental - it works for me, but I recommend that you test it carefully. Things may go wrong...

Muscles commented 6 years ago

@fschill I get that, I meant which mega pin

fschill commented 6 years ago

@Muscles oops, sorry :) Currently it is using hardware interrupt INT4, which is on "digital pin 2" on the mega board.

Muscles commented 6 years ago

Now we are talking, thanks!

shooter64738 commented 6 years ago

Hello all! I was toying around with some changes this weekend trying to resolve my rigid tapping/lathe threading issues and came up with this idea, which seems to work pretty decently!

Using @fschill 's changes, I was having pretty good luck getting spindle synch with a 100ppr encoder. Ideally I think a 64 ppr encoder would be better, but what I needed was an index pulse. I had several 600 ppr encoders I ordered for closed loop feedback and decided I would mod one.

Using a quadrature encoder I removed the small disc and 'painted' half of each slot over with black nail polish. You can cover either edge, but not both. You will then get a pulse on either the A channel or the B channel (depending on which side of the slot you covered half of) but leave one slot completely open. I get the 600ppr on channel A, but since channel B has been painted over (except for one slot) I get an index pulse on B after 1 complete rev. You could of course get an encoder with a Z pulse, but since I had a bunch of these already I didnt wanna spend the money and these were crazy cheap anyway.

Also, I didnt notice too much of a problem running the 600 ppr encoder (obviously NOT as a quadrature though) I still think a lower res encoder would be better, but thought I would toss this out there for anyone that wants the index pulse and has some of these cheaper encoders. I did make some changes to handle the over flow in @fschill 's code for my testing, but it handles higher res pretty well so far.

rokag3 commented 6 years ago

I have made a little program that make a divider for encoder it take a "too big" encoder and divide it by whatever https://www.tinkercad.com/things/ipSM028xFth-encoder-quadratic-divider/editel The switch are not implemented anymore in the software

this program is very short but a bit long to explain If is usefull to limit the number of interuptions of your program if you use a hacked encoder from a printer originally I did it for a frienf to divide by 2 a linear encoder so he can see the real value on his DRO for a lathe (1 mm= 2mm of metal out) I use spool of course no need to use a costly interrupt here (cost 70 cycles)

I also have a attiny 45 version this is divide by 2 If you want to do diide bt anything (of course slower ) You must use replace the line if (!(encoder0Pos&1))//if divisor is 2 no need to make a costly modulo by if (!(encoder0Pos%Divisor)){//if the position of fast encoder can be divided by divisor

/vB1.0
//rokag3 2/21/2017
//diviseur par 2 d'encodeur en quadrature
//attiny 84 20mhz
//if you use it say it's from me
// ********************************************************************************************
//Arduino IDE & Pin Mapping 
// add  2 capacitor 22picof ground to PB0 and PB1 where is the crystal 20mhz
// add a capa 1000 microf between 5V an gnd
// ATMEL ATTINY84 / ARDUINO
//
//                                  +-\/-+
//  red              VCC 5V 1|    |14  GND                         black
// quartz1 (D 10)  PB0  2|    |13  AREF (D  0)
//  quartz2 (D  9)  PB1  3|    |12  PA1  (D  1) 
//  reset                PB3  4|    |11  PA2  (D  2)           outA1 green to DRO 
//  PWM  INT0 (D8)PB25|    |10  PA3  (D  3)           outB1 yelow to DRO
//  PWM    (D  7)  PA7  6|    |9   PA4  (D  4)            in1 A green from encoder
//  PWM    (D  6)  PA6  7|    |8   PA5  (D  5)            PWM   in2 B yelow from encoder
//                                 +----+
#include <avr/io.h>

long int encoder0Pos,encoder0Divide = 0;//position of the encoder since power up.  it can be a simple int provided that the modulo of the higest number possible for encoder0 with Divisor must be 0 
const char direction [16] =   {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0}; //up or down table
const char   slowEncoder [9] = {4,12,0,8,0,4,12,0,8,};//table of sequence of the encoder A+B+ bits 2 and 3

#define in1   0 //PA4
#define in2   1 //PA5
#define outA1 2 //PA2
#define outB2 3 //PA3
#define Divisor 2 //here it must be 2 if you want more you must use the modulo test line
byte New,Nnew, Old; 
char testerr,faults,sign=0;
byte  diviseNew;

void setup() {
 pinMode(in1, INPUT);
 pinMode(in2, INPUT);
 pinMode(outA1 , OUTPUT);
 pinMode(outB2 , OUTPUT);
 }

void loop() {

 Nnew=PINA & 3;  // Only one read to keep the coherence of the time same as Nnew=PINA &48/16 if I read 32 then divided by 16 Nnew = 2
   if(New != Nnew){  //any change on the encoder ? if yes routine to determine increment or decrement
                   Old = New; 
                   New = Nnew;// I take here the value I read before the test to keep the coherence of the time
                   sign = direction [Old * 4 + New];//I take the value in my table 
                   if (sign){ //in C if the argument is not equal to zero it is TRUE so -1 is true like 1
                           encoder0Pos+= sign; //I increment or decrement the position with sign who can be -1 or 1
                           if (!(encoder0Pos&1))//if divisor is 2 4 8 16 no need to make a costly modulo 
                              {
                                diviseNew=slowEncoder[4+sign+(((PINA &12)>>2)*sign)];//
                                if ((encoder0Divide*Divisor)!=encoder0Pos)
                                   {
                                    encoder0Divide+= sign;
                                    PORTA |= (diviseNew);//equivalent to PORTA = PORTA or divisenew
                                    PORTA &=(diviseNew); //equivalent to PORTA = PORTA and divisenew
                                   }                  
                               }
                             }
                    }
              } 

/*
Old = New; 
New = (PINB &3 );
encoder0Pos+= QEM [Old * 4 + New];
 if (!(encoder0Pos%Divisor)){//if the position of fast encoder can be divided by divisor
     sign= QEM [Old * 4 + New];
     diviseNew=slowEncoder [4+sign+(((PINB &12)>>2)*sign)];
     PORTB |= (diviseNew);
     PORTB &=(diviseNew)
*/               
   //explanation not complete let say that 
   //const int slowEncoder [9] = {8,0,12,4,0,8,0,12,4};//table of sequence of the encoder A+B+ bits 2 and 3
   // sign=testerr  diviseNew=slowEncoder [4+sign+(((PINB &12)>>2)*sign)];
   // value to write is at the position 4(+1 or-1)so 5 or 3 9here we are going to take -1 for sign so we have 3
   //+ the bits in +A+B shifted to obtain the value on 2 bits here 12=8+4 so position 3 and 4 lets shift 2 time
   // if the value was 4 >>2 and it become 1
   //so (((4)>>2)*-1)=-1 so 4+sign+(((PINB &12)>>2)*sign=>3+-1=2
   // I will write the value in slowEncoder[2]so 12 in portB bit 3 will be 1 and bit 4 will be 1 job done
   // If I want to write A B in portB bit 4 and 5
   //const int slowEncoder [9] = {16,48,0,32,0,16,48,0,32};//table of sequence of the encoder A+B+ bits 4 and 5
   // sign=testerr  diviseNew=slowEncoder [4+sign+(((PINB &48)>>4)*sign)]
Abdurahman85 commented 5 years ago
* timekeeper.c

timekeeper.c - no such file in grbl-mega repository, as well as support G95...

codemakeshare commented 5 years ago

@Abdurahman85 The lathe add-ons are not yet in the GRBL repositories - you can find them in my fork: https://github.com/fschill/grbl-Mega (spindle_sync branch). Be aware that it's still experimental code - I didn't have much time to continue working on it.

Kukuzca commented 5 years ago

Sorry if this is the wrong place but I cannot find the info in any other place. I'm a noob both in arduino world than in mechanical working. I've an Emco Unimat mini lathe and I want to be able to thread with it. If I install your fork on a mega I have to wire the encoder output to mega digital pin 2/ground and using a Ramps 1.4 and a stepper driver drive a stepper motor (sorry for the pun) for z axis? It is correct? Have you got some schematics on how to wire it all? Thanks!

codemakeshare commented 5 years ago

Hi, This is unfortunately still very early and rough code, very much "work in progress"... I don't have a schematic for the wiring either, sorry. Regarding stepper drivers, I would not recommend using the tiny drivers on the Ramps 1.4 board, I don't think they're powerful enough. For a lathe, you'd want a NEMA23 motor with a suitable driver. You are of course very welcome to try it out, I just wanted to warn you to not expect it to work perfectly, and it might need some adaptation work. In principle you only need one encoder input, and you'll have to adjust the number of ticks per revolution in the code. For threading you would also want a stepper drive on the X-axis as well, to retract at the end of the thread. It might be possible to do without, if you first cut a relief groove to land in, but it would be a bit fiddly (although, not more fiddly than manual threading...).

Abdurahman85 commented 5 years ago

Thanks for the answer. About drives: I will use an alternative option, namely my homemade drives - with DC-motors and optical disks. (I would put it on github, but I don’t know how yet :D) Next, the code you have is yes, it is slightly not optimized, but there is already support for "thread cutting" - this is a big increase in the possibility of the machine .. I'm going to port it to the architecture of stm32 ... I hope that will work .. later I uploading..

Abdurahman85 commented 5 years ago

I'm sorry, but I can't say anything about atmeg. not rebuffed. I work with smt32. (blupill specifically, and newer versions) 16.07.2009, 20:26, "Kukuzca" notifications@github.com:Sorry if this is the wrong place but I cannot find the info in any other place. I'm a noob both in arduino world than in mechanical working. I've an Emco Unimat mini lathe and I want to be able to thread with it. If I install your fork on a mega I have to wire the encoder output to mega digital pin 2/ground and using a Ramps 1.4 and a stepper driver drive a stepper motor (sorry for the pun) for z axis? It is correct? Have you got some schematics on how to wire it all? Thanks!—You are receiving this because you were mentioned.Reply to this email directly, view it on GitHub, or mute the thread.

terjeio commented 5 years ago

@Abdurahman85 : I have recently added a HAL driver for the bluepill board that might be of interest. However, I do not believe the bluepill is suitable for driving a lathe with spindle synced motion - IMO not enough free timers.

Abdurahman85 commented 5 years ago

Thank you very much for your work! I will definitely look at your project.Yes you are right, bluepill is not good for the lathe. But in my version I use 2 bluepill connected to SPI. Works tolerably well... Yet the project is in the process of revision. 16.07.2009, 22:54, "Terje Io" notifications@github.com:@Abdurahman85 : I have recently added a HAL driver for the bluepill board that might be of interest. However, I do not believe the bluepill is suitable for driving a lathe with spindle synced motion - IMO not enough free timers.—You are receiving this because you were mentioned.Reply to this email directly, view it on GitHub, or mute the thread.

Kukuzca commented 5 years ago

@codemakeshare thank you for the answer. Maybe I was not clear: my approach will be like the Abdurahman solution: I will use the original lathe motor spindle adding on it an high res encoder. From one of yours previous answer I've understood that the output of the encoder have to be wired to mega digital pin 2. When I'll send a G33 command how can I specify to Arduino to send pulses to one of the axis in particular? In other word: using the default configuration the spindle pulses from the encoder which axis will "drive" through Ramps/stepper driver electronics? I've tried to understand port and pin configuration in cpu_map.h but it's too difficult for me...

fschill commented 5 years ago

@Kukuzca Yes, on my lathe I also use the original spindle motor. I do not have a high-res encoder, I just used the existing sensor of the RPM display, which generates 4 pulses/revolution. My software synchronises a timer to those pulses, and then interpolates the speed and angle. More pulses are of course better, but it works quite well even with just 4 pulses/rev. What I haven't tested yet is what maximum pulse rate the Arduino can cope with - at 4 p/rev and 1200 RPM it's no problem, but that's all I know. Regarding the drive of the steppers: I think I know what you mean now. I have not implemented G33 yet (some more explanation in this comment above: https://github.com/gnea/grbl-Mega/issues/26#issuecomment-401905428) I foremost use GRBL to run my lathe as a CNC machine, the treading is a little add-on that I'm still working on (but don't have much time for right now). I didn't want to bypass GRBL's motion planning system, as that would make it difficult to maintain coordinate frames, ensure acceleration ramps, etc., so all motion still goes through the regular motion planning. I tapped into the feedrate control, similar to the feedrate override, to achieve spindle-synchronised feed.

What I have implemented is explained here: https://github.com/gnea/grbl-Mega/issues/26#issuecomment-400067745 Essentially, it's just a G95 (feedrate per revolution mode), which means that the speed of movement is relative to the spindle speed. F 1.0 in G95 means 1mm movement for each revolution. It can also be used for regular turning - you're directly programming the chip thickness, basically. For threading this is not enough, unless you only do one pass. To have a simple solution for the start, I just modified the G4 command - if in G95 mode, it will wait the given delay, and then also wait for the spindle to cross zero degrees. This makes it possible to do repeat passes that line up in the same groove. Note that it is not perfect, as it only controls the feedrate, and does not "lock" absolute position to spindle rotation (still needs to be done). But I've cut some threads with it, and it works as long as you don't change the spindle speed or anything. More recently I also added a non-standard "R" parameter to G4, to wait for arbitrary angles (e.g. G4 P1 R90 should wait until the spindle reaches 90 degrees). I haven't tested this mode very much yet - seems to work, but not sure how precise it is. On my machine (and most lathes afaik), the z axis is the one along the bed (parallel to axis of rotation), and the x axis is the cross slide. The G95 mode applies to total feedrate along any axis, so you could also turn a "spiral" along the X axis with it, or conical threads (but be aware that the pitch along Z is not the same as the pitch along the direction of movement...). I hope this helps. If you try it out, I recommend testing with a sharpie first...

Kukuzca commented 5 years ago

Yes, I made a mistake when I wrote G33, I was meaning G95. Thanks for the answer

HuubBuis commented 5 years ago

I have implemented a G33 spindle synchronization for threading in the GRBL-Mega version. The code is based on the @fschill G95 spindle sync version https://github.com/fschill/grbl-Mega/tree/spindle_sync except:

By shifting the start position, multi start threads can be made (Shift 1/2 pitch for a 2 start thread). By calculating the pitch over the tool path (Z:X) tapered threads can be made.

There is a Wiki with an explanation for the users and an explanation of the threading code for those who want to adapt their grbl (mega) fork.

I am working on a version for the Arduino Uno. I think, if I strip all not lathe related code, it will just fit. This Arduino Uno release is targeted for October 2019

see Grbl-L-Mega

HuubBuis commented 5 years ago

I have implemented the G33 spindle synced threading in the GRBL-L version. There is still some room left for changes. @chamnit If you want to add this to the grbl version, let me know then I will adjust the code so it can be turned on using a compiler define and make a pull request.

Sketch uses 31846 bytes (98%) of program storage space. Maximum is 32256 bytes. Global variables use 1592 bytes (77%) of dynamic memory, leaving 456 bytes for local variables. Maximum is 2048 bytes.

See Grbl-L

Bi7Wis3 commented 4 years ago

Hi all, and thanks for all the efforts so far.

I'm also very interested for adding threading to my lathe. I have a ring with 4 magnets and one hal sensor mounted on the lathe.

Tried both versions ( the one from fschill and the one from HuubBuis). Couldn't get HuubBuis version get to work. ( no spindle speed ). @HuubBuis : you mention to use Y-Limit pin, but on the Mega you have 2 ( Min and Max). tried both, but didn't get any spindle speed.

The version from fschill, i could get to work for a single pass. but can't get any sequential passes to line up.

HuubBuis commented 4 years ago

@crashguard,

The GRBL mega only has one limit pin so I assume you have a shield op top of the Mega. Did you set the compiler options in the config.h to compile for this shield?

I use the Mega and Uno version without a shield and that works very well.

Bi7Wis3 commented 4 years ago

@HuubBuis

I use a mega and have it configured for the ramps board. got a few of those laying around. When i look at cpu_map.h i see 2 limit pins in the config:

define MIN_LIMIT_BIT_1 1 // Y Limit Min - Pin D14

define MAX_LIMIT_BIT_1 0 // Y Limit Max - Pin D15

Which one to use ? tried both without succes .. Also tried INT4 ( D2 ), works on the version from fschill > spindle_sync..

Did you assign D11 from the CPU_MAP_2560_INITIAL definition?

HuubBuis commented 4 years ago

I used the grbl mega default D11 configuration:

define Y_LIMIT_BIT 5 // MEGA2560 Digital Pin 11

I had a quick look at the Ramps configuration in config.h. Default there is a setting // Disable the hardware limits

define DISABLE_HW_LIMITS

If hardware limits are disabled, index, sync pulses and probably limit switches are not detected.

Homing however will work because it is done by polling the limit switches!

I guess, didn't analyze the code, that if hardware limits are enabled, both pins D14 and D15 should/could hopefully work.

I have a ramps board on my rotary table but have to take it apart and mount it on a lathe to test it. Not something that can be done easily at the moment!

HuubBuis commented 4 years ago

I took a closer look at the Mega Ramps configuration and found the following code fragment in limits.c:

ifdef DEFAULTS_RAMPS_BOARD

ifndef DISABLE_HW_LIMITS

#error "HW limits are not implemented"

endif

else

When i compile the code, I also get the error "HW limits are not implemented" It seems like hardware limits are not supported on the ramps board running grbl. I also couldn't find a probe signal pin on the shield.

fra589 commented 4 years ago

Hi @HuubBuis,
Hardware limits can't be implemented on the RAMPS board version, since it use hardware interrupt and the port used by the limit switch on the RAMPS board are not compatible with interrupt. On the Mega 2560 CPU, not all the IO ports support interrupt.

HuubBuis commented 4 years ago

@fra589 Thanks for this information, it save's me a lot of time. A solution would be to use pins on the ramps board that support hardware interrupts. That could lead to confusion for those who don't read the complete documentation.

Bi7Wis3 commented 4 years ago

The probe pin is A15 on the Ramps board. Using it with my xyz probe. Works good.

Op zo 19 apr. 2020 17:58 schreef Huub Buis notifications@github.com:

I took a closer look at the Mega Ramps configuration and found the following code fragment in limits.c:

ifdef DEFAULTS_RAMPS_BOARD

ifndef DISABLE_HW_LIMITS

error "HW limits are not implemented"

endif

else

When i compile the code, I also get the error "HW limits are not implemented" It seems like hardware limits are not supported on the ramps board running grbl. I also couldn't find a probe signal pin on the shield.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/gnea/grbl-Mega/issues/26#issuecomment-616169336, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABA5S3NE3KGGQ3WLMFI6AP3RNMNSFANCNFSM4DOV3TDQ .

HuubBuis commented 4 years ago

@crashguard The A15 pin is connected to the therm2 pin on the Ramps Shield. I could change the code to see the synchronization pulse as an index pulse if the number of synchronization pulses = 1. You then will be able to do threading. I can't test the change before half of Mai but if you would test it, i will make the code change a.s.p. ultimately before the end of next week. Beware, this change could effect the probing cycle so take care not to destroy your probe.

Bi7Wis3 commented 4 years ago

@HuubBuis

In cpu_maps.h : // Define probe switch input pin.

define PROBE_DDR DDRK

define PROBE_PIN PINK

define PROBE_PORT PORTK

define PROBE_BIT 7 // MEGA2560 Analog Pin 15

define PROBE_MASK (1<<PROBE_BIT)

P.S. .. I have it configured as a ramps board, but took it off and using big stepper drivers now..

HuubBuis commented 4 years ago

@crashguard

I have plans for making a tool changer based on a rotary table setup. The Ramps board seemed a good solution for this because it has a 4e axis and many IO pins together with GND and 5V. I would also use external drivers. No hardware interrupts on the limit switches is a no go for me. Remapping pins will lead to confusion. I have checked for other shields but didn't find an appropriate one. So at the moment I am not sure what to do (for my own project). Never the less, I think with a small code change, Ramps users could do threading with the limitation of just one index pulse. For spindles who's speed is regulated by gears, I expect it will work fine.

I want to change system.c to set the "CONTROL_PIN_INDEX_SPINDLE_SYNC" as a response to the receive of a index or sync pulse when the number of sync pulses = 1. Then the sync pulse could be on the Index or Sync pin. The time penalty for the extra check would be a few micro seconds or less. My plan is to do the code change and check the code for the impact. Recompile the Mega version and test this on my lathe. Recompile the Ramps version and simulate this on my Mega + Ramps board (will set a pulse generator on the sync pin). If it works I will fit the ramps board on may lathe and test it (scheduled half of Mai). If this test is OK, I will make a new release and update the WiKi.

P.S. I have some cheap ebay adapter cables that fit on the stepstick header to connect my external TB6600 drivers (JST connector).

The old code in systemc:



// Pin change interrupt for pin-out commands, i.e. cycle start, feed hold, and reset. Sets
// only the realtime command execute variable to have the main program execute these when
// its ready. This works exactly like the character-based realtime commands when picked off
// directly from the incoming serial data stream.
ISR(CONTROL_INT_vect)
{
  uint8_t pin = system_control_get_state();
  if (pin) {
    if (bit_istrue(pin,CONTROL_PIN_INDEX_RESET)) {
      mc_reset();
    } else if (bit_istrue(pin,CONTROL_PIN_INDEX_CYCLE_START)) {
      bit_true(sys_rt_exec_state, EXEC_CYCLE_START);
    } else if (bit_istrue(pin,CONTROL_PIN_INDEX_FEED_HOLD)) {
      bit_true(sys_rt_exec_state, EXEC_FEED_HOLD); 
    } else if (bit_istrue(pin,CONTROL_PIN_INDEX_SAFETY_DOOR)) {
      bit_true(sys_rt_exec_state, EXEC_SAFETY_DOOR);
    } else if (bit_istrue(pin,CONTROL_PIN_INDEX_SPINDLE_SYNC)) {            // Detected a G33 spindle synchronization pulse. Beware, this is not the spindle index pulse
      if (settings.sync_pulses_per_revolution>1) {                          // If G33 is configured for synchronization pulses
      bit_true(threading_exec_flags,EXEC_PLANNER_SYNC_PULSE);               // Signal the detection of a synchronization pulse.
      }
    }
  }
}

The new code

    } else if (bit_istrue(pin,CONTROL_PIN_INDEX_SPINDLE_SYNC)) {            // Detected a G33 spindle synchronization pulse. Beware, this is not the spindle index pulse
      if (settings.sync_pulses_per_revolution==1) {                         // If G33 is configured for 1 synchronization pulses
        bit_true(threading_exec_flags,EXEC_SPINDLE_INDEX_PULSE);}           // Signal the detection of a index pulse 
      else if (settings.sync_pulses_per_revolution>1) {                     // If G33 is configured for more than 1 synchronization pulse
      bit_true(threading_exec_flags,EXEC_PLANNER_SYNC_PULSE);               // Signal the detection of a synchronization pulse.
      }
    }
Bi7Wis3 commented 4 years ago

@HuubBuis

Sounds, good.

I also could test it on my lathe.

You said: Recompile the Ramps version and simulate this on my Mega + Ramps board (will set a pulse generator on the sync pin).

Which pin do you mean on the ramps, the probe pin (A15)?

define CONTROL_SPINDLE_SYNC_BIT 7 // MEGA2560 Analog Pin 15, same as probe pin

And also how to set the number of pulses per rev?

HuubBuis commented 4 years ago

Which pin do you mean on the ramps, the probe pin (A15)?

define CONTROL_SPINDLE_SYNC_BIT 7 // MEGA2560 Analog Pin 15, same as probe pin

I would first try to use the sync pulse as an index pulse because for that, no pins need to be remapped, only a change in the ISR logic.

Which pin do you mean on the ramps, the probe pin (A15)?

The Probe pin (A15) is connected on the Ramps board to THERM2

And also how to set the number of pulses per rev?

If there is only an index pulse, the number of sync pulses (pulses per rev) should be set to 1.

If the logic change works it means the other pins still support Interrupts using the current RAMPS code. Than there maybe is a solution for the missing index interrupt.

HuubBuis commented 4 years ago

And also how to set the number of pulses per rev?

The number of sync pulses is set in the arduino config $40, should be 1 if there is just an index pulse.

I have done a small test, the safety door pin interrupt is working on the ramps board after enabling it in config.h. Because the synchronization pin is setup the same way, I expect this pin to work also.

Bi7Wis3 commented 4 years ago

I have tried the above code. Connected the Sync_pulse to A15. But when i try running :

G0 X0 Z0 F25; go to start position
G0 X-0.1 ; go to cutting depth, clear of workpiece
G90 G33 Z-5 K1 ; Threading pass at a pitch of 1 unit per revolution
G0X0.4 ; retract at end of move
Z0 ; end of pass

I get Error 18 ...

HuubBuis commented 4 years ago

Error 18: you find the errors in the file error_codes_en_US.csv inthe doc directory "18","Index pulse timeout","G33 No index pulse received within 6 sec"

I have done the same, came to the same error. The reason is than on the RAMPS board this pin has a 4k7 pullup connected to a 10 uF capacitor. Your pulse has to be wide enough to charge the capacitor. I tested using a 2 ms high pulse at a rate of 6 Hz (360 RPM) and GRBL showed a very high speed. The slow rising flank (charging the capacitor) or the spikes when discharging this large capacitor probably causes a lot of false triggers. I had a second problem. As soon as I started the index pulse simulator, I wasn't able to run a G92 command. To be short, the quick fix won't work. I reserved the next 2 days to see if I can get the RAMPS board Index signal working on another pin. For now I am going to use the DOOR pin. After that I will decide what to do.

HuubBuis commented 4 years ago

Part of the problems came from my Index pulse simulator. It had a positive pulse (NC sensor). I changed it to a 2 ms negative pulse(NO censor). Now the grbl speed is measured ok and I can sent a G92 code without problems. To avoid problems due to the large capacitor on the THERM inputs I used the safety door pin for the index pulse.

I have made a quick and dirty change to the code. It is tested on the ramps board using a spindle index pulse simulator running at 120 RPM (2 ms low pulse) connected to A12, Pin 9 on the AUX2 connector, the former safety door pin. It is not the final version but it should/could get you started. Use it carefully GRBL-L-Mega-Ramps.zip I will consider the options for a final version and will make the final version half of Mai when I can free up a lathe for testing.

Bi7Wis3 commented 4 years ago

OK thnx, I'll check it later.. I'm using NO sensors too, but to make the pulse longer, i used 2 magnets next to each other on the timing ring. ( using 4 pulses per rev, so 8 magnets ). i can get rpm readings up to 3500 rpm without any problems with the firmware from fschill..( Pulses on Pin D2 , alse getting rpm readings in UGS.)

HuubBuis commented 4 years ago

I'm using NO sensors too, but to make the pulse longer, i used 2 magnets next to each other on the timing ring. ( using 4 pulses per rev, so 8 magnets ). I needed the long timing pulses to get the index pulses on the RAMPS Probe input (TERM2 with 4u7 capacitor) working. On the door input there is no capacitor so the pulses can be a lot shorter. I use 4 mm diameter magnets on the small lathe and 12 mm diameter magnets on the "large" lathe.

The small lathe gets to it's max (2500 RPM) the larger lathe is limited to 1200 RPM due to a optocoupler input that is not adjusted for higher speeds (at the moment).

Beware, sync pulses are not supported in this version, only an index pulse.

D2 and D3 are connected to an dedicated interrupt capable pin (INT0/INT1). I will consider using D2 and D3 for index and sync pulses.

Bi7Wis3 commented 4 years ago

fun fact: According to specs, my small lathe should do 2500rpm, but in reality when i cranck it up, it goes over 4000 rpm ... REALY SCARY!! LOL ..

HuubBuis commented 4 years ago

Scary thing: Be careful, the chuck may break apart (explode) if you run faster than it's max RPM.