Replies: 19 comments 4 replies
-
Let's continue with the findings of my web search. I've startet this topic in another issue: I'd just recall the fact that in grblHAL, there is already a spindle-sync feature for lathing threads in place. Albeit under different circumstances, it already implements movements waiting and synced for some external signal, thus allowing deviation from the pre-planned spacetime path beyond a mere change of speed. And there is Terje's reference to his maslow code, which - I have to admit - I have no clue yet how it fits into the whole framework. I found one thread in the "legacy" grbl area on processing linear encoder signals: There is a very basic implementation of a selfmade servo: |
Beta Was this translation helpful? Give feedback.
-
So the next challenge is to understand the inner structure of grbl(HAL):
As Terje pointed "a book had to be written". Agree on that. Until this is done, some obvious pointers. However, in the end, I found more questions risen anew than old ones solved. This is were I started to understand: After understanding the Architecture sketched and explained there, I managed
|
Beta Was this translation helpful? Give feedback.
-
Guided by this plan, we finally find the place where the magic is going on: The workhorse is
The ISR is called at 30 kHz rate - as the source comment says.
back to stepper.c:
Neither buffer update timing nor stepper rate is readily available from the source. I suspect it's depending on different driver configuration - still to be figured out. Digging deeper into the code, we learn that segments may contain things like There is a This all looks like relevant action that may be performed upon absolute position information. However, the segment buffer is not the place to compare planned with actual position, since it is some unknown time ahead of pulse output. When I got it right, the line (number 426 in current version) where a pulse is generated reads The update of internal axis counters follows this line. ... which leads us to the question how we get this position into our controller - under severe timing contsraints. Contemporary µControllers can immediately process quadrature encodings. However, asking the datasheet of STM32F4 (my favourate at the moment), there are only 4 out of 11 timers capable of this, 2 of them already configured for other purposes. Another issue is that most timers only are capable of 16 bit, which equals 0.32 meters of 5-µm intervals. |
Beta Was this translation helpful? Give feedback.
-
My early considerations included driving some PID-controlled DC-Servo or even VFD-PID-driven AC-Motors. I encountered a venerable paper with some corner values for our task at hand: In the case of servo drives, we might feed these "Reference-Word" to the PID controlling the servos. However, said paper mentions a typical corner frequency of PID controllers not far above 100 Hz. Compared to steppers running at dozens or even hundreds of kHz, we decide not pursue the servo path at the moment, as I don't see any chance to come anyway close to stepper precision in the case of normal, deterministic precision. Their are NEMA41-steppers available even in DIY sources, delivering 30 Nm torque and > 700 W of power - albeit matching drivers are close to 200 €/$ each. |
Beta Was this translation helpful? Give feedback.
-
Based on the prospective insight so far, let's try to structure a bit: Architecure and data path:
Evaluation
Events to be recognized
Actions possible
Potential for adaptive auto learning
|
Beta Was this translation helpful? Give feedback.
-
referring to @terjeio
Peeking down the rabbit hole a little bit ('till Ln 600 where the So while there is considerable chance that code plugged in here is called several times per second, there is no reliable deterministic way to ensure it is called at all, not even to say at a precise interval, correct? Not the perfect place I'd like a superviser code to live in? Do we have enough CPU time in spare to risk this? Or do we already hit the amount of complexity to be handled by a single controller? |
Beta Was this translation helpful? Give feedback.
-
I have not gone through all your comments yet, summer is here and I have plenty of other stuff to do. Nevertheless a few comments:
True. However, time critical events are taken care of by interrupts so as close to realtime as possible. And all drivers supports a interrupt driven 1 ms systick which may be used to hook time critical code into. Some drivers also supports a microsecond resolution "timer" which can be used to time events hooked into the main loop which by the way runs pretty frequently most of the time.
How precise is a precise interval? Less than 10 microsecond jitter? Sub microsecond?
This depends on the requirements, a FPU equipped MCU running at a reasonable high clock rate may work perfectly well. Tasks can be attached directly into the main loop or it can be registered with the core task manager which mainly uses the 1ms systick timer interval to check for and run tasks.
That depends on how the code is written. I like to add an immediate task on some interrupts and let the foreground process execute the code. This will add a non-deterministic delay which I have not bothered to measure - a few microseconds worst case for the most capable MCUs?
Depends on the MCU, anyway unpredicable behaviour should not be coded for...
I am not sure, driver.c might be a better place? Or a plugin? IMO the most critical part of the solution will be how to handle encoder input - it should be restricted to MCUs having a sufficient number of quadrature encoder peripherals? Doing the decoding in code might be a non starter due to high frequency inputs?
Fast MCUs like the iMXRT1062 or STM32H7xx series might handle this without breaking a sweat. And complexity will only increase if offloading... |
Beta Was this translation helpful? Give feedback.
-
referring to @terjeio
hm ... I try to find the PID implementation in that code, but I only can see parameters hold, and static coordinate transfer. Is KINEMATIC really a good place for dynamic correction?
ah, OK, I see some PID there for positions. |
Beta Was this translation helpful? Give feedback.
-
Never mind.
Ah, I was looking in vain for this figure for this systick frequency. I think 1 ms should be enough for most emergency like conditions - at least much faster than any human operator might react.
Impressive figure, indeed, but only "most of the time". Essence so far:
|
Beta Was this translation helpful? Give feedback.
-
Checking for feasibility of timing: Start at our "M3-thread-mill-challenge".
Travel 6µ in one systick of 1 ms yields a feed rate of 360 mm/min - quite a high value for such tiny threads. A common M3 thread mill bit has a diameter of 2.35mm. 6µ / 0,0019m/s = 3.2 ms - more than 3 systicks while traveling the allowed tolerance. Travelling the whole cycle of r=0.35 mm at 0.0019 m/s takes 1.16 seconds: Regarding backlash of a single axis, deviation builds up at the turning point.
Essence: sounds feasible until here |
Beta Was this translation helpful? Give feedback.
-
Next feasibility check: peripherals for quadrature capture As Terje pointed out
In the Datasheet for
In an accompanying "Table4" we read that only TIM1, TIM2, TIM3, TIM4, TIM5 are capable of up/down counting, which is a reasonable preassumption for capturing quadrature encoding. The role of TIM1 is a bit unclear:
So while not explicitly listed as quadrature capable, from this text it might be understood that TIM1 is quadrature capable as well. While the much more advanced STM32H7 counts a total of 22 timers (compared to 11 on the F411), its datasheet reads as there were only the same 4+maybe TIM1 up-down-timers capable of quadrature capture. In https://github.com/grblHAL/STM32F4xx/blob/master/Inc/driver.h we find:
So we might reluctantly hope that Timers 1,2,3 might be available for quadrature capture -
Might And what about stepper and pulse timers? I see, @terjeio , again, may be the first one to help out here? |
Beta Was this translation helpful? Give feedback.
-
Have desperately been looking for timer interfacing in the encoder code, It looks like a polling code, crafted in C for efficiency, reading two GPIO lines A,B, testing for change and updating an counter if appropriate. I know that GPIO interrupts in STM32 are a rare ressource, too. This way, we would not require any valuable timer ressources. |
Beta Was this translation helpful? Give feedback.
-
... watching some rabbits dancing in https://github.com/grblHAL/STM32F4xx/blob/master/Src/driver.c Looks like stepper timing comes down to what I'd guess as "normal" timer while quadrature stuff I'd expect to end out in the "extended" timer HAL here ... and I see that systick µs and ms are drawn from skd of core hardware and obviously do not consume any extra timer: searching the web for CMSIS, I learn that while in said core_cm3.h there is not even an FPU, in cm4 (aka Cortex4) there is both an FPU and DSP with SIMD facilities available. Back to the timers: reached the end of |
Beta Was this translation helpful? Give feedback.
-
spent quite some hours now, comparing the All grblHAL drivers I checked use the same scheme of interrupts triggered by rising and falling edge of two input lines per encoder.
There is actually a counter based encoder outside grbHAL, but within our "ecosystem": A 5µ encoder moving at (not really realistic) 10m/min generates pulses at 33 kHz, which for a 40+-MHz CPU should not pose too much stress. So for the moment, I'm inclined to implement encoder input by irq triggeres on lines and keep the timer configuration untouched. "Further action" includes at least pushing systick time and counter value to some buffer (i.e. spacetime coordinates) for further evaluation. We might instead try to put all 6 encoder lines into the realm of one single I've ordered the encoders and steppers for my mill and plan at least to implement data capture. |
Beta Was this translation helpful? Give feedback.
-
Not sure what you mean by this. If sharing an interrupt line for a given pin number across GPIO ports then that is not possible.
Only the STM32F1xx driver (for the 128K flash variants) is nearing the code limit, IRQ code should be fast so inlining is better if for high frequency handlers.
IRQ capable GPIO pins are more valuable? I prefer a 32 bit timer for the stepper interrupt, but a 16 bit one can be used by changing the prescaler to get the required range. So remapping is possible.
It is - via assembler.
The encoder interface is aimed at hand turned encoders - for menu selection and/or jogging. So not suited for positioning?
I do not know, my hunch is that it is better to read the position at regular intervals, at least PID control requires that (fixed sampling rate) and let the hardware take care of keeping track of the encoders/position. Handling of underflow/overflow would have to be by IRQ though.
This is aimed at plasma tool height control (THC) and is for moving an axis (Z) without notifying the core. The axis moved by this should not be moved by the core at the same time. This functionality could be replaced with your dynamic backlash compensation?
This keeps the position in sync with the spindle by changing the time between stepper pulses, not by adding/removing any. Backlash compensation requires additional pulses. And the current spindle sync code is based on having a constant (programmed) feed rate over the synced move. I am not sure it is suitable for rigid tapping, certainly not so if the spindle is moved by hand since the code does not detect direction. FYI I have looked into some electronic lead screw (ELS) projects for ideas for how to implement rigid tapping but have not started coding for it yet. I fear it will be quite a bit of work and will lead to a lot of broken taps... Projects exists that adds servo control to regular steppers, perhaps some ideas can be extracted from those? |
Beta Was this translation helpful? Give feedback.
-
Encouraging to watch my thinking converging towards your knowledge ;-)
Still decaes old remains of 6502 architecture in my mind.... but ... :
... although not configurable, there is a lumping of 6 pins to one interrupt as it seems. Just let's explore the alternative of using timers for encoder reading.
Nice exercise in STM32CubeIDE, at least. Next step is to acquire timestamps. I found However, it looks a bit complicated for beeing called in interrupt handlers every couple of µs. Where is the complexity coming from? Can we short this down? |
Beta Was this translation helpful? Give feedback.
-
hm... A web search for "asynchronous PID" leads me astray to AI-based PID tuning ... For the moment, my idea is to extract "features" such as slope, curves, kinks from the collected data, but haven't yet decided how. |
Beta Was this translation helpful? Give feedback.
-
I really admire your energy to face the challenge of all those different platforms. So let's continue on Blackpill. I like the approach of However, it add's loads of complexity (in terms of code lines, learning time and processing time). I think the stepper2-approach to genereate ticks on independent timers per axis is much more smooth. Although I'll not go for precise evaluation, I'd expect it injects less noise and allows smooth small amlitude feed back. Following the datasheets of STM32F411, TIM9, 10, 11 should fit the purpose. Back to the question where to interface to the existent code. And how does PID fit to Bresenham? Does it fit at all? Let's step back and reconsider what we want to achieve - in falling priority:
If we look at priorities in that list, we see that it is not time, but position that counts. |
Beta Was this translation helpful? Give feedback.
-
Two night's of sleep later, I 'd rather dismiss the idea of individual timers per axis. What if instead we have a single high tick rate - pulse generator and PID update, synced for all axes? E.g. 8 x 8 = 64 easily fits: step rate = 1 MHz / 8 = 125 kHz, microstepping = 8. A DM556 accepts up to 200 kHz with am minimum step time of 2,5 µs - so on the output side, we have a comfortable safety margin. If wee feed distance between planned and measured postion to PID, in the Differentail realm, In the Proportional realm below, speed ist adjusted to match planned speed - which may vary over a segment. The syncing of axes might require skd of common slow down (or even speed up?) proportional to all axes, as soon as one axis accrues drift. This way, other axes "wait" until the drifting one comes up. May this be another PID loop? maybe a bit slower than pulse generators? The dynamic range of axis movement might raise some extra challenge. From e.g. 1mm /min to 1000 mm/min and even more we easily may have to span 3 orders of magnitude and more. Maybe PID tuning had to be adapted? And when ordering steppers for my mill to go moving, I encountered another issue related to dynamic range: Grey is all theory. But clouded the forces of reality are as well. But isn't there a simulation driver in |
Beta Was this translation helpful? Give feedback.
-
Consider such a venerable near 4thousand pound pile of well crafted cast iron:
Can we enhance it to mill e.g. sth like a pattern of M3-threads in a 1m-plus workpiece?
Of course, we might easily put tooth belt pulleys in place of of the lead screw handles and drive them with some nema23 or larger stepper.
However, we find an Y-axis with some tenth of tactible backlash, an X-Axis equipped with a geared AC-Motor, moving some hundert punds of inertial table mass, and a Z-Axis lifting and lowering same table, yielding in a quite asymmetric load.
So we may end up in very conservative speed an acceleration settings if we go the purely deterministic way grbl is working at the moment.
There are closed loop steppers and servo motors with rotary encoders and grbl-like step/dir inputs. Both may help to shift the safety margins a little bit. We may generate skd of "motor fault" or "motor warning" signal, so at least we could stop a job and avoid further damage, if we pressed too hard.
Threre is skd of a deterministic backlash compensation already provided in grblHAL core (no clue how mature it is).
Any way, it requires precise precalculation of backlash and does not handle cases where the table is pressed by tool force to one or the other end of the backlash interval - or maybe even sticks somewhere inbetween.
We might consider to replace the old trapezoid lead screws by contemporary no-lash SFU-type ball screws. Quite expensive, if we come to the 30mm-plus size. And not easily fit mechanically into the existing cast blocks.
There is another option:
There are linear glass scale encoders. Readily available to the DIY-market. They cost ~70 €/$ each for 5 µm resolution and are available in packages with DRO display units, too. They deliver 90°-phase-shifted-AB-Signals at ttl-level - similiar as rotary encoders do. Easy to mount, cheaper than strong ball screws. But best of all: They are not subject to forces or backslash of the kinematic slide chain. So, they tell us where our table really is (well, let's ignore tilt....)
Now, we could feed the linear encoding signal back to a closed loop stepper or servo motor.
grbl - still unchanged - delivers step/dir signals and independent servo-controllers for each axis perform the fine tuning.
This way, at least we might eliminate backlash - in the end of a movement.
However, during correction of backlash by an independent servo driver, we may be a bit off the planned path, since other axes are not aware of the correction taking place in the lagging axis.
This may be no problem if we just pocket out some large square areas. Maybe, the corners show tiny artefacts.
However, our 3 mm thread presumably might not succed this way.
For this end, compensation has to be kept in sync for all axes. If Y travels through backlash, X and Z have to wait and only then coordinated move may start again.
In terms of spacetime coordinates, we may allow deviation in speed/time, but X-Y-Z lateral space has to be kept in tight control to each other.
Anticipating my findings in trying to understand grbl, I think this ends up in heavy modifications of the stepper code.
In my current vision of the implementation, the planner might still generate the same deterministic spacetime-path.
But when it comes to send signals out to real world, it is the stepper which has to check whether the path is still on track by processing the linear encoder's position signals. And if deviation like backlash, mechanical or inertial lagging or even stalling of a motor occurs in one axis, the whole movement has to slow down. This is similiar to feed rate correction, which is injected between planner and stepper in the current code already. So only the lagging axis is moved at higher speed until on path again, and only then the other non-lagging axes may catch up as well.
I have no clue if somebody in the FOSS world has done such a thing already. Maybe there is a fork of grbl lingering around, being capable of that adaptive operation? What about LinuxCNC, Mach, Estlcam and bretheren?
Anyway, I'd bet my a(...rbitrary part of body to be filled in) that heavy commercial machines work skd of such way.
Are we, as a community, prepared to pick up this challenge?
Beta Was this translation helpful? Give feedback.
All reactions