gin66 / FastAccelStepper

A high speed stepper library for Atmega 168/328p (nano), Atmega32u4, Atmega 2560, ESP32, ESP32S2, ESP32S3, ESP32C3 and Atmel SAM Due
MIT License
286 stars 67 forks source link

Bézier curve jerk control and hardware FP calculations #107

Closed contactalexliu closed 1 year ago

contactalexliu commented 2 years ago

Might there be a way to fit a Bézier curve to the trapezoidal profile of the velocity curve similar to what TinyG and Marlin do, perhaps in the RampGenerator or RampCalculator? I’m not sure how much it might help, but to visualize how the Bézier curve from this commit limits jerk, I made a demonstration using Desmos. I realize this increases the amount of computation, so compute speed might need to increase too (to that end, Marlin contributors wrote assembly sequences for ARM and even Atmel AVR).

Considering the ESP32 has a hardware single-precision floating point unit (and by the looks of this blog post, others seem to have had success with it), maybe a macro in the RampCalculator could switch the calculations to use accelerated FP routines when compiling with ESP32 as the target? Based on this benchmark, the ESP32 can do an FP multiplication operation in about 5 ns and division in 200 ns. It also seems that GCC has had hardware FPU sequences for SQRT/RECIP/RSQRT since this commit in 2016. Even if we assume terrible RSQRT performance, the ESP32 should be capable of TICKS_PER_S * RSQRT(2.0 * steps * acceleration) in less than 8 µs (which looks like the record to beat if the helpful comments in RampCalculator are up to date).

Thank you very much for all your work on this library!

gin66 commented 2 years ago

Thanks for the proposal. TinyG and Marlin are far more advanced stepper controllers, which can control several axes at the same time. Quite ingenious and especially the forward planning is just great. Wonder, why no one has extracted the code and offered this as standalone library.

Anyway, in case I find time to come up with a solution for jerk control, it will be more a (real life) compromise and not an exact solution of the Bezier curves - and most likely not a 4 or 5 grade polynomial solution. Constant acceleration has been comparable "easy" to implement. And jerk control from stand still to maximum acceleration seems to be comparable "easy", too. The difficult parts are:

So perhaps it is sufficient for jerk control from standstill only ?!

I hope, that there is a comparable "elegant" solution (applying some symmetries or a rather straightforward approach of varying the acceleration in the ramp generator), which avoids a lot of the algorithmic complexity. The concept of PoormanFloat with table driven calculation would allow even complex functions like a cosinh, log or else without being computational expensive. Just the resolution is not great, but may be acceptable.

BTW: IMHO a perfect solution is not the goal. For example starting acceleration with value = 0 does not make sense in real life, because a stepper outputs discrete steps. Similarly ending the accelerating ramp with acceleration of 0, seems too not to be reasonable. So the perfect mathematical solution would not be an engineer's implementation.

Considering, that at every step the acceleration makes a huge jump and at the beginning the distance between steps is more in the tens or even hundreds of milliseconds. It's even not so easy to calculate a reasonable speed. Actually after having read your post, perhaps I will add another pc-based test, which uses a physical model of two connected springs, thereof one is connected to an ideal stepper and the other side to a mass to be moved (movement with friction). This would help me to better understand and optimize any solution, I may come up with. Why two springs ? The first spring simulates any tension in the mechanical system (e.g. water level in the glass). The second spring would be to simulate the magnetic (holding) force of the stepper. In case of too much tension in the second spring, the system would just snap to the next full step - means one step lost. Sounds fun. Just not sure, when I have time for this.

In the moment, jerk control can only be achieved by modifying acceleration from the app and call setAcceleration() and applySpeedAcceleration() every couple ms with increasing/decreasing values. This should work, but is far from elegant. Perhaps you can give this a try.

The comments in RampCalculator are related to the performance on avr. My intention is to have as much code reuse across architectures as possible. That's why, I would try to find a solution for jerk control, which works for avr and for esp the same. So I would not look into real floating point calculations or hardware FPU. Besides I doubt, that for a stepper ramp control more than 8 bit mantissa is needed at all.

cranefist commented 1 year ago

I was about to request this also. Im working on a project, where i would need jerk control. I can get to high speeds, but only until i have beaten the initial friction. So the motor stalls if i use the high speed settings directly, but works just fine if i first do a small movement to break the initial friction first.

So i either have to use low accelerations, and this limits my overall movement speed as i only do short linear movements back & forth. Or to do some sort of initial movement to break the friction. And then the high acceleration movement.

And thanks for the suggestion about the not so elegant solution, i will be testing this out.

But if you have time, any type of crude or simple jerk control would be highly appreciated. And from standstill would be perfect for my use case at least.

gin66 commented 1 year ago

I have started a new branch log_tables, which replaces the five tables used by PoorManFloat by two tables using log2/pow2 correction values. This is in preparation of jerk control on motor start using the mechanism as laid out here. This new approach needs quadratic functions and powers of 2/3 and 3/2. Those can be calculated via log tables comparably easy.

Plan is to have a working implementation in the coming weeks.

gin66 commented 1 year ago

implementation is complete and will be released as 0.29.1