spindle at speed active at zero speed

More
16 Dec 2019 21:19 #152767 by billykid
how strange! I cleaned the file hal and now it works well ... I had done some tests and maybe something was wrong.
my vfd is a huan yang connected via rs485, the only lines hal are in these two files nothing else in ini or main hal
Attachments:

Please Log in or Create an account to join the conversation.

More
17 Dec 2019 06:23 #152779 by macsddau@linuxcnc

I have a spindle with the hy_vfd

I have an HY vfd too. I don’t remember what are the setup on vfd. I don’t have time for the moment but I will give it to you so we can compare it.

Please Log in or Create an account to join the conversation.

More
18 Mar 2022 20:18 - 26 Mar 2022 16:06 #237669 by airbrontosaurus
This post is from a long time ago, but I ran into the same issue recently, and I kept running into this post.  I was able to fix it, and I wanted to post this in case someone in the future finds this.

The Problem
In LinuxCNC, the program will hold motion until the spindle.X.at-speed is true.  This way, the machine won't start cutting until the spindle is up to speed, but the machine can run G0s and other processes to 'get ready', and then wait right before the first cut for the spindle to achieve its commanded speed.

However, there are times where the machine starts cutting before the spindle has reached its commanded speed.  This can cause damage to the workpiece as well as the spindle and cutter.

The Cause

The root cause of this is the default LinuxCNC behavior that when a spindle is at 0 RPMs (because it has not been commanded to spin up), spindle.X.at-speed is TRUE.  This can cause problematic behavior depending on how your GCODE is setup.  In my case (and I suspect the OP's case too), the spindle speed GCODE was sent directly before the G0 positioning move, and then the first G1 cutting move was below that.  In most cases, there was no problem. The logic would look like this:

Linux CNC is powered on
Spindle RPMs = 0, Commanded RPMs = 0, spindle.0.at-speed = TRUE
GCODE is started
Spindle RPMs = 0, Commanded RPMs = 0, spindle.0.at-speed = TRUE
GCODE sets the spindle RPMs and calls a G0 movement to position spindle
Spindle rapidly moves to the starting position 
Spindle RPMs = 0, Commanded RPMs = something_other_than_zero, spindle.0.at-speed = FALSE
LinuxCNC waits
Spindle RPMs = commanded_speed, Commanded RPMs = commanded_speed, spindle.0.at-speed = TRUE
LinuxCNC now starts the first G1 cutting move

However, if the spindle is close to the starting point when the GCODE is started, this race-condition-sorta-thing can happen

Linux CNC is powered on
Spindle RPMs = 0, Commanded RPMs = 0, spindle.0.at-speed = TRUE
GCODE is started
Spindle RPMs = 0, Commanded RPMs = 0, spindle.0.at-speed = TRUE
GCODE sends the spindle RPM signal to the VFD and calls a G0 movement to position spindle 
The spindle gets to the G0 position very quickly
Spindle RPMs = 0, Commanded RPMs = still zero, because the VFD has not yet had time to accept and process the spindle RPM command, spindle.0.at-speed = TRUE
The VFD finally recognizes the M3 spindle speed command, but at this point it's too late. LinuxCNC has already checked to see if spindle.0.at-speed is TRUE for the first G1 move (and it is, because it's currently at 0 and the VFD hasn't processed the new speed yet. LinuxCNC thinks everything is fine and begins commanding the cut moves, even though the spindle has only just begun spinning up.
The machine will now start cutting even as the spindle is still accelerating (usually when it's still very low in the RPM range) which can causes broken bits or damaged work pieces.


The Solution


UPDATE:

I have built a new function that works much better, it is available here:
forum.linuxcnc.org/38-general-linuxcnc-q...peed?start=20#238404
I'm leaving the original solution up in case someone wants it, but I think you should use the solution at the link above


I built some logic that checks to make sure the spindle speed is above a certain threshold, and only then will spindle.X.at-speed be TRUE.  So at rest, when the commanded speed is 0 and the actual speed is 0, spindle.X.at-speed is FALSE.  It remains false until it gets to a certain RPM, and only then will it begin to check is the RPMs reported by the VFD match the commanded RPMs.

My code is here (you'll obviously need to change this for your setup:

#first, load the COMP function so we can compare the spindle speed vs the min (1,000 RPMs)
loadrt comp names=spindle-speed-not-zero

#add this to the servo thread
addf spindle-speed-not-zero servo-thread

#create our AND.  Our end goal is to only show spindle.0.at-speed when the spindle is at speed AND the spindle is over 1,000 RPMs
addf and2.6 servo-thread


#set minimum RPM to 1000 as COMP argument 1, below this the spindle is considered NOT at speed, even if the speed is 0 and the spindle is at 0
setp spindle-speed-not-zero.in0 1000

# hijack the spindle speed out pin from CL, and pipe it to our signal, as well as pipe it to COMP argument 2
net spindle-hijacked-speed <= classicladder.0.floatout-00 => spindle-speed-not-zero.in1

#Now, COMP will only return true if the spindle currently, according to the VFD, spinning faster than 1,000 RPMs
#Great, the last thing we need to do is to verify our spindle is currently AT-SPEED, which is reported via MODBUS
#from our VFD.  The pin is classicladder.0.out-01

#The first input to our AND function is the output of the COMP function above.  This will ONLY be true when
#the spindle's ACTUAL reported RPM from the VFD is greater than 1,000 RPMS, AND the spindle is currently
#at full speed according to the VFD

#This prevents the issue of the spindle being at-speed at 0 RPMs
#This command creates a signal called is-spindle-speed-over-zero and then
#takes the output of our comparator and inserts it into and2.6.in0
net is-spindle-speed-over-zero and2.6.in0 spindle-speed-not-zero.out

#Finally, we put the output of our VFD saying the spindle is at full RPMs
#and we pass that into and2.6.in1
net is-spindle-at-speed and2.6.in1 classicladder.0.out-01 

# FINALLY FINALLY, we take the output of our and2.6, and we pipe
#that into spindle.0.at-speed.  Now spindle.0.at-speed will only be true
#when the spindle is at the commanded speed, AND it is at a speed greater
than 1,000 RPMs.  At rest (0 RPMs), spindle.0.at-speed will always read FALSE
net spindle-ready <= and2.6.out => spindle.0.at-speed

Hopefully, this will help someone googling this in the future.
Last edit: 26 Mar 2022 16:06 by airbrontosaurus. Reason: Updating to show the new, better fix link
The following user(s) said Thank You: billykid

Please Log in or Create an account to join the conversation.

More
22 Mar 2022 23:55 #238053 by andypugh
I think that this is a problem inherent in the fact that most of the VFD control HAL modules operate in userspace. If they were realtime modules then I don't think that this would happen.

Unfortunately in most cases they can't be.

I am not sure that there needs to be a separate HAL component (You have one, keep it, this is advice for later readers)
In the realtime layer I would look at masking spindle-at-speed from the VFD when an edge was seen in spindle-on.

linuxcnc.org/docs/html/man/man9/edge.9.html

Will produce a fixed-length pulse when spindle-on transitions from on-to-off.
Use the out-invert and

linuxcnc.org/docs/html/man/man9/and2.9.html

So that spindle-at-speed is ignored for "long enough" after the edge.
The following user(s) said Thank You: airbrontosaurus

Please Log in or Create an account to join the conversation.

More
23 Mar 2022 01:26 #238067 by cmorley
Also it only waits at specific times:

before the first feed move after each spindle start or speed change;
before the start of every chain of spindle-synchronized moves;
and if in CSS mode, at every rapid to feed transition.

Please Log in or Create an account to join the conversation.

More
25 Mar 2022 19:28 #238362 by airbrontosaurus

I think that this is a problem inherent in the fact that most of the VFD control HAL modules operate in userspace. If they were realtime modules then I don't think that this would happen.

Unfortunately in most cases they can't be.

I am not sure that there needs to be a separate HAL component (You have one, keep it, this is advice for later readers)
In the realtime layer I would look at masking spindle-at-speed from the VFD when an edge was seen in spindle-on.

linuxcnc.org/docs/html/man/man9/edge.9.html

Will produce a fixed-length pulse when spindle-on transitions from on-to-off.
Use the out-invert and

linuxcnc.org/docs/html/man/man9/and2.9.html
 


That solution sounds a lot more elegant than what I came up with, and it also fixes the issue of LinuxCNC expecting spindle.0.at-speed to be true at 0-RPMs.  If it's not clear from my first post, I'm not really sure what I'm doing with LinuxCNC.  Would you take a look at this pseudocode and let me know if this is on the right track?  I'm sure the syntax is wrong and I might need to pick different pins, I just want to make sure I have the right general idea
#create our and2
loadrt and2

#create our edge thing here
loadrt edge

#add to servo threads
addf and2.0 servo-thread
addf edge.0 servo-thread


#create a signal that reflects the spindle.0.speed-out, which is what LCNC sets when it commands a spindle speed.  This speed will be set #immediately on the GCODE call and will NOT be delayed by the VFD.  Then pipe this data into our edge function.
net lcnc-spindle-speed <= spindle.0.speed-out => edge.0.in

#now, edge_inverted is going to be outputting TRUE at idle, but when we command the spindle speed to be something other than 0 we
#want it to output a signal for a certain amount of time to block off the spindle.0.at-speed pin

#set the output pulse to 2 seconds, so when the edge is detected it will output FALSE for 2 seconds before outputting true.  this way we still get #spindle.0.at-speed = TRUE at 0 RPMs (which I think is good for any GCODE macros that use G1 commands)
sets spindle-signal-edge.0.out-width-ns 2000000

#pipe both of these into input 1 of our and2 function
net edge-detect and2.0.in <= edge.0.out-invert

#now pipe spindle.0.at-speed into input 2 of our and2 function
net spindle-speed-achieved and2.1.in <= spindle.0.at-speed

#finally, take that value and pipe it into our spindle.0.at-speed function
net spindle-ready <= and2.0.out => spindle.0.at-speed

Please Log in or Create an account to join the conversation.

More
26 Mar 2022 00:11 #238388 by andypugh
You can't use spindlle-speed (floating point) as the input to the edge detector (bit). so use spindle.0.on (bit) instead.

Please Log in or Create an account to join the conversation.

More
26 Mar 2022 15:51 #238404 by airbrontosaurus

You can't use spindlle-speed (floating point) as the input to the edge detector (bit). so use spindle.0.on (bit) instead.
 


Thanks!  I took a swing at this.  I was unable to get the EDGE function to work, specifically the timer.  I was following the docs, but no matter what I set the out-width-ns to, when I looked at that pin in HALMETER it was just oscillating around 250ms.  All the other pins worked, but I couldn't figure that one out.  I even opened it up on HALSCOPE and it looked like random noise, it was very strange.

However, I found another function called oneshot that seems to do what I want.  I incorporated it into my final function, and it works exactly like I want it to.  At rest, spindle.0.at-speed reads TRUE (which is great for any macro or automated process that uses GCODES for setup, and uses G1s for movement).  The instant I command a different spindle speed via the M3 command, I can watch my variables and see that my VFD takes about 500ms to register the new speed, however since the oneshot is triggered instantly, my spindle.0.at-speed reads FALSE until the spindle actually gets up to speed.  Then, when I turn the spindle off, spindle.0.at-speed reads true again once the spindle has spun down to zero.

I tested this with a bunch of situations where, before this fix, the spindle would have started cutting before it got to speed.  In every single case, it paused and waited for the full spindle speed to be achieved before it started cutting.

Thanks again for all your help andypugh!

Here's my final code (as above, you'll obviously need to change pins around for whatever pins you're using on your end):
#Create our oneshot thing here
loadrt oneshot

#Add to servo threads (I already am using a bunch of and2s so I had to start at and2.6)
addf and2.6 servo-thread
addf oneshot.0 servo-thread

#Create a signal that reflects the spindle.0.speed-out, which is what LCNC sets when it commands a spindle speed.  
#This speed will be set immediately on the GCODE call and will NOT be delayed by the VFD.  Then pipe this data into our oneshot function.
net lcnc-spindle-speed <= spindle.0.on => oneshot.0.in

#Now, oneshot.out-not is going to be outputting TRUE at idle, but when we command the spindle speed to be something other than 0 we
#want it to output FALSE for a certain amount of time to block off the spindle.0.at-speed pin, otherwise it can cause a race
#condition where the spindle is still TRUE because the VFD hasn't had time to process
#the spindle speed command


#This is where we set the output pulse length.  You can set this to whatever you want, but in my case I set it to 2 seconds
#because I did a bunch of tests on my VFD and it never took more than 500ms to recognize the input signal, so I multiplied that
#by 4x for safety.  If your VFD is slower, then you may need to lengthen this.

#The logic of this function is that the absolute instant a newly-commanded spindle speed is detected, this signal will output FALSE for 
#2 seconds before outputting true.  this way we still get  spindle.0.at-speed = TRUE at 0 RPMs
#(which I think is good for any GCODE macros that use G1 commands)
setp oneshot.0.width 2

#pipe this signal into input 1 of our and2 function
net oneshot-detect and2.6.in0 <= oneshot.0.out-not 

#now pipe the VFD spindle-at-speed output pin into input 2 of our and2 function
#This is my CL pin, if you use a different pin or something like VFDMod you'll need to 
#update this to use your pin
net vfd-says-spindle-speed-achieved and2.6.in1 classicladder.0.out-01 

#finally, take the output value of our and2 function, and pipe it into our spindle.0.at-speed function
net spindle-ready <= and2.6.out => spindle.0.at-speed

Please Log in or Create an account to join the conversation.

More
29 Mar 2022 20:56 #238654 by andypugh
I had forgotten "oneshot". That's actually a better choice than "edge" for this task.

Please Log in or Create an account to join the conversation.

More
13 Sep 2022 21:04 - 13 Sep 2022 21:10 #251847 by macsddau@linuxcnc
Today I have made some improvement on spindle configuration :
  • connecting vfd speed feddback to spindle feedback bar in GEMOCCAPY
  • connecting vfd enable to machine turn on/off
Currently, the LCNC PC is not connected to hardware so i cannot test this configuration. using HALShow I was able to check that it will probably work fine.
Unfortunately, without the hardware connected i have no feedback of the @speed so that programs wait infinitely the spindle.

The custom.hal file contains these lines :
loadusr -Wn vfd hy_vfd -n vfd -t 1 -d /dev/ttyUSB0 -p none -r 9600
net spindle-speed-cmd spindle.0.speed-out-abs => vfd.speed-command
net spindle-fwd spindle.0.forward => vfd.spindle-forward
net spindle-rev spindle.0.reverse => vfd.spindle-reverse
net spindle-on spindle.0.on => vfd.spindle-on
net spindle-at-speed spindle.0.at-speed <= vfd.spindle-at-speed
net spindle-speed-fb spindle.0.speed-in <= vfd.spindle-speed-fb


the custom_postgui.hal contains these lines :
net spindle-speed-fb gmoccapy.spindle_feedback_bar => vfd.spindle-speed-fb
net spindle-at-speed gmoccapy.spindle_at_speed_led => vfd.spindle-at-speed
net xenable => vfd.enable
Last edit: 13 Sep 2022 21:10 by macsddau@linuxcnc.

Please Log in or Create an account to join the conversation.

Time to create page: 0.105 seconds
Powered by Kunena Forum