-
Notifications
You must be signed in to change notification settings - Fork 32
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
lots of jitter on step movements #4
Comments
Is there any specific reason why it's doing all that work between the rising and falling edge of a short pulse? Maybe move the HIGH/LOW to be back to back, and process when waiting anyway? It looks like the DeterminePerdiodOfNextSlep is a bit heavy -- maybe include the clocks taken to process that in the delay for more stable frequency? But that's a guess. |
Thank you @3ricj for the effort you put into analyzing the signals and your inputs on this topic. Your change moves the update task on core 1, but as far as I know this is also the core where the standard arduino function setup and loop are running. So when you move it there, it might interfere with some heavy work on core 1 from your loop(). You should also try to disable the ESP Flexy Stepper service which will avoid the opening of a separate task completely and solely run in the main loop. Of Course then you cannot have other logic in the main loop that might cause jitter. Can you please post your complete program you used while measuring the jitter? As for your question of the pulse duration: The pulse duration (or even a variation of the length) should not matter to drivers that are triggered on the rising edge of the pulse. As for the logic to set the Pins high and low: you are right this might be quicker, but the jitter is not caused by using the Arduino digitalWrite functions. These functions need the same time with every call, they do not need sometimes longer and sometimes shorter (unless interrupted by some wifi / rf stack logic on the same core, which of course is more likely the longer the function runs). |
@3ricj can you provide feedback on the above comment? |
I also encounter an exteme and constant amount of jitter... sometimes it stops for half a second in the middle of a move. Moves fine using other libraries. Any thoughts? |
@Humanoidx please provide some more details on your setup and code. |
ESP32-Wroom-32D Nema 34 12nm Closed Loop Stepper Here is a video if it working smoothly with FastAccelStepper Library And here is the jittery ESP-FlexyStepper Library Both Videos are 400 steps per revolution 16,000 steps per second max speed Depending on the settings sometimes it just stops all together even at low speed,s |
@Humanoidx thx for the hardware details, yet I was more referring to the software code and setup of esp FlexyStepper though :-) |
:)
|
@pkerspe |
Did you try running the FlexyStepper stepper as a service as in example 5? I know it works with the other library, but we need to narrow down the cause of the problem. |
Just tried it with the less aggressive values, and it is still jerky Tried example 5 and it is still jerky (particularly when it accelerates or decelerates). But it seemed smooth when it reached the maximum speed. |
Thanks for the feedback. |
Also one important question: did you connect to the ESP32 with a serial monitor to check if it crashes and performs a reboot/reset? This would explain the very long pauses you experienced before. |
I did some first tests with alternative methods of generating a square wave signal for step output using some of the build in modules from the ESP32. This way I can create a pretty exact amount (not 100% sure about exact number though, still fine-tuning needed) of pulses with a static frequency up to several kHz (didn't really test the limit, only tested up to 20kHz so far, but according to the documentation a frequency of up to 40MHz should be possible with 50% duty cycle). Downsides:
Find below a quick and dirty copy&paste programm used for tests with PWM and Pulse Counter (you can test with your setup and modify the variable So what does this program do? It initialized the PWM module on channel 0 and outputs a pwm signal (square wave with 50% duty cycle) with 20 kHz on Pin 4, this is where the stepper driver would be connected for the step signal. So once you connected the stepper, it will start directly to spin for (in this case 55555 steps with 20kHz) and then stop.
|
Another option to address the step signal generation issue would be to use the Remote Control (RMT) module (https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/rmt.html), using this approach the Step signal frequency could be set by setting the carrier signal frequency (I did not find details in the documentation about the maximum frequency, but since it is a unsigned 32 bit integer (https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/rmt.html#_CPPv4N15rmt_tx_config_t15carrier_freq_hzE) it should easily support some 100 kHz if not even several Mhz (possibly up to CPU frequency which by default would be 80 Mhz). I did not perform any tests. Benefits of this solution would be, that you do not need any additional pins for a pulse counter, since basically the data transmitted via the RMT module would define the actual amount of pulses. While I did not yet implement a POC this approach would face the same issue with acceleration and deceleration, which would need to be implemented by changing the carrierfrequency gradually. Example script for generating square wave signal with the RMT module:
So this program basically configured the RMT to use a carrier frequency of 10kHz and then sends "message" which consists of a low signal for 1000 ticks. Due to the configuration of the clock divider ticks are generated at 1 Mhz, so a tick is equal to 0.001 ms. when sending a signal with a duration of 1000 ticks, it means sending the carrier signal for 1ms, which with a given frequency of 10kHz results in 10 Step signals (but since then the signal level of the RMT returns to high, thus, it would issue an 11th step signal to the stepper driver. So for 10 step signals 900 ticks would nees to be used. The example program runs in an endless loop if issuing some step pulses and waiting 10 seconds. |
so all this POC code is basically to show that there are other ways to generate pulses than the current approach which is basically bit-banging. But it requires quite some reworking to implement the acceleration / deceleration, and I currently do not have the time to do so. So any help would be highly appreciated. |
I wish i could help but mannnn this is over my head |
I will investigate a bit further in the near future, but it is a time consuming change, but certainly a good one in regards to stability and much cleaner signal generation. But as often the devil is in the details :-) So I don't expect this to be an easy one. |
@Humanoidx did you try the changes suggested by 3ricj in his opening post? So basically you can edit the lines 96 and following (the body of the
You can even try if it gets better with a priority value of 2 instead of 1 |
I have struggled with this issue before, researched the ESP32 docs and lots and lots of forums. It turns out core 1 does not go much faster dan a 1000 cycles per second, no wonder I had so much jitter. Just try to schedule your program well on core 0 and the steppermotor runs very smooth! @pkerspe I would just advice to stop using core 1 for the stepper motor, core 1 should only be used for tasks which do not need the speed core 0 offers... |
@xander-m2k thank you for your input. But I honestly doubt that it will be only good for 1000 "cyles"/sec (or in other words a net clock speed of 1kHz). The CPU runs (depending on your settings) with up to 240 MHz (that is 240,000 kHz), I doubt that the WiFi stack consumes 99.99% of the CPU time. Can you please provide a link to the source where you found this "1000 cycles per second" figure? But indeed the jitter seems to be caused by the fact that other tasks from the OS / WiFi Stack are running on the same core and obviously with a higher priority. By the way, according to some random tutorial (https://randomnerdtutorials.com/esp32-dual-core-arduino-ide/) the Arduino functions (so the setup and loop) function are running on core 1 of the ESP32, so according to your number, all code in a default Arduino project would be limited to the mentioned 1000 clock cycles/Second... |
@pkerspe I'm sorry, I was confused, it has been a while since I used the ESP32. So Core 1 is indeed the main core for your main Arduino/ESP program. So to elaborate on how this works; in FreeRTOS you're only able to utilize core 0 by starting a task, with xTaskCreatePinnedToCore(). These tasks are ran by a with called 'tickrate' and currently the SDK only supports a tickrate of about a 1000Hz. This is because they are limited by vTaskDelay (unvisible to the user), where 1 ms is the minimum. This is to create space for Bluetooth, Wifi and other tasks like that which are handled by Core 0. I could not find any official documentation about this, but people are talking about it on the esp32 forum: Hope this informs you well :) |
@xander-m2k thanks for the update about the ticks, I checked the documentation of FreeRTOS (https://www.freertos.org/implementation/a00011.html) to better understand this task management routine. I read it a bit differently than your explanation, since in my understanding a task does not get 1000 CPU cycles or "1000hz", but a maximum continuous processing time before a task might be suspended by the OS to allow another task to run. I recommend not to put any code in the loop() function if using ESP Flexy Stepper as a service. Rather use interrupt-driven design patterns for the code. In general, a refactoring of the ESP flexy stepper code to an interrupt-driven or hardware module-based (e.g. hardware PWM, LEDC or the RMT module) solution as described earlier (#4 (comment) / #4 (comment)) might be the best solution for a more stable / jitter-free signal generation, but this is a bigger task and affects quite some parts of the library. |
@pkerspe you're very complete in your answers sir, loving it. I was using the Wifi capability while experiencing this jitter indeed, and was reaching about a 1000 cycles per second in my case, I don't remember how I measured it but it was about that amount. Anyway, I think it is good to mention in the README that when using Wifi/Bluetooth/BLE it is not advised to use core 0. |
@xander-m2k as suggested I updated the README file with some content on the jitter topic |
@pkerspe did you concider using the mcpwm feature of the ESP32? |
@hnnswldschtz thanks for the link, this is an interesting piece of information and might be useful in the future. The comments regarding the mcpwm modules are very interesting though.
Still, I appreciate the input a lot! |
Compatibility is an issue, you are right. |
I started experimenting a bit again on this topic, the MCPWM peripheral seems not to be present in the ESP32-C3 and ESP32-S2 variants, thus I am not fancying this approach. I figured the LED Control (LEDC) module is present in all variants (S2, S3, C3) according to the documentation of Espressif (https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/search.html).
|
Hey @pkerspe I'm working currently on an art project and indented to use your library because it looks very clean and structured and has all functions to work effectively out of the box. It looks like I'm running into the same issues as your discussing here. I've tried to create a Task isolated to core 0 for my main loop and setup but still do experience some light jitter when running the stepper service on core 1. Do you know if it matters if I initialize the stepper class on core 0 and run the service on core 1? Will there be some additional locking variables delay or something like that? Since you were working towards the more robust hardware implementation of this solution, I was wondering if you've found some more time to work on implementing acceleration and deacceleration? Kind Regards |
Hi @FlipEngineering How many stepper motors do you need to control and do you need the features to change speeds and directions all the time with smooth acceleration? |
Thanks for your reply @pkerspe. Unfortunately I will need the wifi module to be active. The goal is to send position targets over wifi and have two individual stepper + esp32 systems run synchronized without any wired connections between them. I've done now as well some fast testing with the Fastaccelstepper library which uses the hardware timers, and was able to have no issues with the jitter. But your library provides a very nice usability framework. Do you think it would be a big task to implement the hardware timing solutions from the fastaccelstepper lib into yours? Perhaps I would give it a go. But I'm by no means as experienced as you are, so I would trust your judgment if you'd say it's not that easy |
As for the sync between two ESP32 i I would probably not use WiFi but the ESP-Now protocol. It will work without an existing WiFi Access point and also should be more efficient and maybe also result in less "traffic" on the WiFI stack. As for the Fastaccelstepper: the library uses multiple hardware modules to achieve running up to 14 stepper motors (on ESP32, less on ESP32-S2/S3), that is quite some logic to interface all the different hardware modules on the different ESP32 models (on ESP32: mcpwm, rmt, on ESP32-S2: rmt, on ESP32-S3: mcpwm). The current versin of this very libary (flexystepper) uses a software only approach with the benefit of working on all ESP32 models (hpoefully), but the problem of limited step frequency and jitter. If you would like to have a go, feel free to submit a Pull Request with suggested changes and I will review them. |
The esp now looks like a great idea thanks for that! I'll do my best to work cleanly and if it's presentable will submit a pull request. Thank you a lot for the advice! |
I just wanted to follow up on this bug as I filed it a few years ago. I changed directions with my projects -- I finally accepted that I would not get the stable performance I need on an ESP based software solution -- despite this library being completely awesome: the hardware + low level software support isn't there yet if you need low jitter and high performance. I've been using the TIC controllers from Pololu - they are in charge of all of the pulses to the drivers and let you focus on driving at a speed or direction. Extremely nice drivers with great documentation. Of course, this comes at a cost, however, the i2c buses and support are just awesome -- so now my ESP chips can focus on other things. I keep hoping I can find an open source version of this product that works just as well -- but have not found it yet. In theory, we could hook the correct hardware features on an ESP chip and get stable performance, but it may limit what chips are support (eg: s2) |
|
Interesting I wasn't aware of that, they could have been a good alternative. In a previous project we were as well successful with a teensy 3.6 to run 4 steppers over dmx/artnet. I'm trying to use the current project for building a base of wireless real time control of a single stepper, because this would be very handy in future projects. From my experience with the teensy I know that the hardware timer solution can provide a very accurate and reliable system. But I really would like to transit to the esp. Let's see where it brings us haha. Appreciate all of your input guys. Thanks a lot again. |
Hi! I have been studying your library and it brings awesome function. I hard coded the control of two stepper motors for Arduino in the past and now I'm searching for a library like this with ESP. We are trying to control 5 steppers motor for a robotic arm and there is a lot of jitter with the simplest code. Code: ` // IO pin assignments // Speed settings // create the stepper motor object int previousDirection1 = -1; void setup() // connect and configure the stepper motor to its IO pins // Not start the stepper instance as a service in the "background" as a separate task } void loop() if (stepper1.getDistanceToTargetSigned() == 0) // Notice that you can now do whatever you want in the loop function without the need to call processMovement(). Video: https://youtu.be/he3V48hPz28?si=DYzSet-NDicG8P1o I would prefer this library because it bring nice function and documentations. Thank you very much. |
@Lammpo which ESP model are you using? Is it a dual core version? |
It is an ESP Wroom-32 and the only code I'm using is what I posted. I tried microstepping and the behaviour was better but the controller and the nema17 were really hot. I think that when I tried to control 2 steppers the behaviour was worst which doesn't make sense if the tasks are independent. Thank for the quick response. Tomorrow I will add more info and test. |
You should check your wiring if the steppers are getting hot. You might still get movement sometimes if you wired the steppers incorrectly but with problems like temperature and jitter. |
I forgot to check the ref values of drv and the current was too high so that's why the temperature was high. The jitter is reduced now but I got a strange acceleration. First it accelerates just fine and it jumps to the final spped. Same when it has to deccelerate. Code: `// *********************************************************************** #include <ESP_FlexyStepper.h> // IO pin assignments // IO pin assignments // create the stepper motor object int previousDirection = 1; void setup() // Not start the stepper instance as a service in the "background" as a separate task pinMode(MOTOR_ENABLE_PIN, OUTPUT); // Second motor stepper2.connectToPins(MOTOR_STEP_PIN2, MOTOR_DIRECTION_PIN2); // Not start the stepper instance as a service in the "background" as a separate task // pinMode(MOTOR_ENABLE_PIN2, OUTPUT); } void loop()
{ // Notice that you can now do whatever you want in the loop function without the need to call processMovement(). |
Hi there,
I was having problems running this as a service at 6khz pulses. There was breaks in the pulses nearly 20ms (6-10ms typical) long! That made for very rough movement of the stage at times... it would jitter and chatter.. not to mention cause vibration.
I've started to try and optimize this a bit. It's much better now -- pretty stable pulses. I'm still seeing some minor bugaboos (slow fall times?) randomly seeing 1ms pulse lengths on the step line. But much much better now.
Before:
https://www.dropbox.com/s/arb881iok61ibbv/stock.png?dl=0
https://www.dropbox.com/s/1k708hg0hwj6nsq/stock2.png?dl=0
After:
https://www.dropbox.com/s/5knigkzt73tjq9a/changes.png?dl=0
Here's what I changed:
This forces the step processing onto core1 -- it seems pretty happy there. This may have other bad side effects -- not sure.
Finally, there are some faster digital pin options on the ESP32 -- bitmask style. here's some info on that:
https://www.instructables.com/Faster-ESP32/
It may help drive things even faster.
Best I can tell the library is doing a bunch of stuff between the rising and falling edge of the pulse. Something in here may be causing the existing jitter, but I'm not sure how to best find it.
Here you can see the 1m pause between rising and falling:
https://www.dropbox.com/s/n9lzfshqx4ar0r1/screenshot.png?dl=0
Thanks for the library, it's awesome.
Best,
-3ric Johanson
The text was updated successfully, but these errors were encountered: