Traumflug / Teacup_Firmware

Firmware for RepRap and other 3D printers
http://forums.reprap.org/read.php?147
GNU General Public License v2.0
312 stars 199 forks source link

Stuttering at random intervals, due to sudden increase in speed for durations of less than a millisecond. #295

Open ZKing1000 opened 6 years ago

ZKing1000 commented 6 years ago

As the title says, my printer was stuttering badly when trying to move large angles. After looking through the code a little, I'm pretty confident that it is due to the function dda_create() being very inefficient. The function seems to be called every time a new gcode movement command is processed... I compiled the project to an i386 executable and profiled the function with calls to clock_gettime() and the results were interesting to say the least...

Do you guys have interest in fixing this? I plan on making some changes myself, but you guys may be able to do a better job. I'm really interested in this project, coming from marlin, but this is sort of a deal breaker...

Thanks.

Traumflug commented 6 years ago

The function seems to be called every time a new gcode movement command is processed...

That's true, and to my research it typically takes about 30'000 CPU clocks, or 2 milliseconds on an ATmega. Moving closer to maximum speed takes away some of the processing power, so it takes longer.

Measuring calculation timings is rather simple once you've set up SimulAVR for profiling. One can turn the (virtual) debug LED on and off at arbitrary code points to measure execution time between these two points.

Regarding timings in the i386 simulator I'm not too sure whether they're accurate.

If you have ideas on how to improve this, sure, go ahead. If you want write access to the repo to avoid complicated pull requests, just ask.

Wurstnase commented 6 years ago

Depending on the segment size, short one at high speed will make more trouble, it could be an issue of small jerk values.

Most configs have a default value of 300mm/min. Probably the calculation between Marlin and Teacup is quit different, the default with Marlin is 1200mm/min. On some testing in the simulator with 300 I can see a lot of deceleration in curves. This becomes less with higher jerk. Less deceleration = smoother movement.

Make a try if you see some different.

Also, when you have free RAM you could increase the buffer for the movement queue. (MOVEBUFFER_SIZE)

ZKing1000 commented 6 years ago

@Wurtnase That was actually the first thing that came to mind when trying to solve this problem... I didn't think to increase the jerk values much above 400mm/min though... I tried 1200mm/min like you said and that seems to make a positive difference though... I'm not really aware of how this firmware vs marlin calculates that type of thing... Changing movebuffer size didn't really do much to fix the problem, though. I think its just the nature of the model I'm trying to print. It has many close consecutive movements followed by large movements with sharp angles... In fact I think I'll attach the gcode file so you guys can have a look. If it's not a problem with dda_create than my assumption would be that it's a problem with how movement is calculated... Although you guys would probably be much better equipped to figure that sort of thing out than I am. Changing to ACCELERATION_REPRAP only makes the problem much worse though... And I've already spent too much time trying to configure the acceleration and jerk values. Is it possible to do that through EEPROM? That would be convenient...

@Traumflug You know... I actually tried setting up SimulAVR initially but was discouraged at the complexity of the process... I've spent some more time setting it up and now I've got it actually working... Although I had to comment out this line in Makefile-AVR: #CFLAGS += -dM -E # To list all predefined macros into the .o file. With those flags enabled, the linker was giving me this message on all of the object files: avr-gcc: warning: '(Name of .o file):' linker input file unused because linking not done

Now that I've got that set up, I can see that the function takes approximately 2ms to execute, as you said. As for how to improve it, the first things that come to mind are to expand the for loops to increase binary size as apposed to cpu time and remove some of the uneccesary if statements. Other than that, I noticed that their are a lot of slow operations effecting SRAM in that function... Those could probably be sped up by moving more state to a global context, if that's possible and maybe even using some asm() register magic to reduce instructions accessing SRAM. Glancing at the compiler options being used, I have a feeling those could be tweaked, although I probably don't really know enough about this code base to do that effectively...

I know one of your design goals was to achieve a small binary size... In that case, It would probably make sense to have these changes enabled through some type of macro like ENABLE_VERTEX_EFFICIENCY or something like that...

Does that all sound alright to you?

Also, having write access to the repo sounds really great... Although, you may have to bear with me on some things, because I don't have a lot of experience using github... At the moment I have the repository cloned on my local machine and plan on making some more changes on my local branch...

Sorry for taking so long to respond... I get nervous around new people some times........................ lol... gcode.zip

ZKing1000 commented 6 years ago

Ah, wait a second... That's not the right gcode file... Here it is: tens.gco.zip

Traumflug commented 6 years ago

I know one of your design goals was to achieve a small binary size... In that case, It would probably make sense to have these changes enabled through some type of macro like ENABLE_VERTEX_EFFICIENCY or something like that...

In 9 of 10 cases, a smaller binary is more efficient. That's why targeting a small binary also made Teacup so fast.

ZKing1000 commented 6 years ago

I was mainly just considering the extra overhead asssociated with the jmp/rjmp instructions likely generated by those for loops associated with the 4 axes's, although that type of thing may depend on compiler flags... Anyways, talking about it probably isn't going to do much. I'll just try making some changes and see what the results are.

ZKing1000 commented 6 years ago

Well good news! I just made some of the changes I talked about and the execution time of that function was reduced by a factor of 16! I haven't even done any of the assembler magic I talked about yet... We'll see if thats even necessary. ;)

ZKing1000 commented 6 years ago

Oh, wait that might have been a false alarm.... Lol...

ZKing1000 commented 6 years ago

You know to be honest, it sounds like you guys have taken care in optimizing this function. Is that right? In the case that it's not a problem with this function how do you suppose I fix this?

ZKing1000 commented 6 years ago

Yeah and you guys are also stepping the thing in the interrupt context and have a move buffer, so I'm not totally sure whats going on...

ZKing1000 commented 6 years ago

Oh, wait a minute... I think I just found something interesting... I ran the attached gcode file and generated the attached .vcd file. I modified the short_moves.gcode file to make it repeat itself over and over a few times. The whole thing runs at a constant feed rate of 12000mm/min, which should mean that X_STEP_PIN should be called at a constant interval throughout the print, accept for the beginning and do to accel and deccel. Try monitoring these two pins: (PORTA2 and PORTC5). PORTA2 is the x step pin and PORTC5 is DEBUG_LED_PIN. The I modified the code to WRITE(DEBUG_LED_PIN, 1) at the beginning of dda_create() and to WRITE(DEBUG_LED_PIN, 0) at the end of dda_create().

Now in gtkwave, skip to these points in time: 752ms, 942ms, 1394ms, 1404ms, 2304ms. That would definitely explain the stuttering... And there is a weird correlation between the two pins.

How am I the only one that is having this problem? I've tried using all different versions of this firmware, right now I'm using the experimental branch. For this example the acceleration was set to 500mm/min, and x/y jerk to 1200. testcases.zip

ZKing1000 commented 6 years ago

Theres got to be a way to see what point the processor is at in the code at any given time... That would help to solve this.

ZKing1000 commented 6 years ago

I fixed it!!!!!!!!!!!!! This is definitely a hack, but it works! In the file dda.c (around line 939.), I modified this: ATOMIC_START if (current_id == dda->id) // This happens only when !recalc_speed, meaning we are cruising, not // accelerating or decelerating. So it pegs our dda->c at c_min if it // never made it as far as c_min. dda->c = dda->c_min; ATOMIC_END

So that instead, it looks like this:

` ATOMIC_START; if (current_id == dda->id); // This happens only when !recalc_speed, meaning we are cruising, not; // accelerating or decelerating. So it pegs our dda->c at c_min if it; // never made it as far as c_min. ; dda->c = dda->c_min;

      if( dda->c < 3000 )
      {
          dda->c *= 7;
          }
    ATOMIC_END;

`

For some reason, at basically random points in time, dda->c_min was being set to a value that was about 7 times smaller than it should have been, for durations of less than a millisecond. Essentially ramping the thing up to insane speeds for durations of less than a millisecond at random intervals. Don't ask me why, I have absolutely no idea. I was about to give up before I figured this out, but its working now! I assume this won't cause any step loss right? Since, steps seem to be tracked in other parts of the code. Had you guys' never noticed this before? It could have been a difference in our printers abilities to respond to fine movements like that... Tomorrow, I'll do a test print, with some actual plastic being extruded and see what the quality is like. (It's late for me now)

Well that formatting kinda messed up... I'll attach the file. Can I make a pull request, or is that really necessary? You guys' may want to figure out why this is happening in the first place...

Here's the file: dda.zip

Wurstnase commented 6 years ago

Please check the latest experimental. Probably it is a similar issue I've fixed with the latest commit. On Sat 17. Feb 2018 at 10:36, ZKing1000 notifications@github.com wrote:

I fixed it!!!!!!!!!!!!! This is definitely a hack, but it works! In the file dda.c (around line 939.), I modified this: ATOMIC_START if (current_id == dda->id) // This happens only when !recalc_speed, meaning we are cruising, not // accelerating or decelerating. So it pegs our dda->c at c_min if it // never made it as far as c_min. dda->c = dda->c_min; ATOMIC_END

So that instead, it looks like this: `ATOMIC_START if (current_id == dda->id) // This happens only when !recalc_speed, meaning we are cruising, not // accelerating or decelerating. So it pegs our dda->c at c_min if it // never made it as far as c_min. dda->c = dda->c_min;

if( dda->c < 3000 ) { dda->c *= 7; }

ATOMIC_END`

For some reason, at basically random points in time, dda->c_min was being set to a value that was about 7 times smaller than it should have been, for durations of less than a millisecond. Essentially ramping the thing up to insane speeds for durations of less than a millisecond at random intervals. Don't ask me why, I have absolutely no idea. I was about to give up before I figured this out, but its working now! I assume this won't cause any step loss right? Since, steps seem to be tracked in other parts of the code. Had you guys' never noticed this before? It could have been a difference in our printers abilities to respond to fine movements like that... Tomorrow, I'll do a test print, with some actual plastic being extruded and see what the quality is like. (It's late for me now)

— You are receiving this because you commented.

Reply to this email directly, view it on GitHub https://github.com/Traumflug/Teacup_Firmware/issues/295#issuecomment-366429472, or mute the thread https://github.com/notifications/unsubscribe-auth/AITlJ_QVMCyjvpEws_9aqZhA3JsDgrGEks5tVp2vgaJpZM4SF0RA .

ZKing1000 commented 6 years ago

@Wurstnase Oh, I see you already fixed it, cool. I just did a test print with your changes and the results were pretty incredible.... It did a 0.1mm tolerance with room to spare! It definitely couldn't do that before, I'm pretty sure. Great job you guys'.

I noticed looking over the code some, that most of the math and logic for movement in this code was pretty advanced. (Like hacker level 9000 or something). I'd like to learn more about that, but I couldn't really understand it all well just by looking at the code. Although, there were links to www.embedded.com in regard to stepper motor speed profiles, which is kinda nice. Do you guys' explain your design anywhere in more detail? I'm genuinely interested.

Also, I definitely plan on implementing some EEPROM functionality, because I still have some jerk and acceleration tuning to do and I don't want to spend another second flashing the board. I saw that @ryannining has his own branch that seems to implement EEPROM configuration storage... Have you guys' considered implementing that functionality in the master or experimental branches? If it's a problem with flash size, then it could just be a configuration option.

I may also add some support for my 3d printer's lcd display. I haven't gotten that to work, so I'm not sure if it's supported or not. My printer is a Tevo Tarantula, with an mks gen v1.4 mother board (essentially RAMPS).

Thanks.

ryannining commented 6 years ago

hello zking, can you please share your print result , i am interesting in printing this using your machine, i do have my own teacup machine, but perhaps, my machine was not good quality also still use old teacup code

https://www.thingiverse.com/thing:1587568/#files

test the hipopotamo phone stand. layer 0.2, thx

Thx

Traumflug commented 6 years ago

I definitely plan on implementing some EEPROM functionality

You can do this, of course. But you might well end up with a Marlin clone, with all its disadvantages. Having things like acceleration fixed allows a lot of optimizations at compile time, which leads to Teacups good efficiency. That's why Teacup implemented Configtool in favor of EEPROM settings.

ZKing1000 commented 6 years ago

Update: With the right printer and slicer settings, I achieved a beautiful 0.05mm tolerance!!!! The thing actually spins...

@ryannining Sure, I don't see why not. Although, I think I'll have to get back to you on that tomorrow. I spent all day today just calibrating the thing. I'll probably make a video or something. One thing to keep in mind, though is that the Tevo Tarantula needs some basic upgrades to work well out of the box. (Kinda like an Anet, but better) If you end up getting it, you'll want to order a couple of fans, like these for example: https://www.gearbest.com/3d-printer-parts/pp_540285.html?wid=21&lkid=10394192. All of the other upgrades can be printed, except for nuts and bolts (Although I have had it do that. They just aren't that strong).

@Traumflug I see... I noticed in the code that the variable c0_P (from dda.c) and acc_ramp_div_P (from dda_maths.c) were both declared with the modifier PROGMEM, keeping them explicitly hardcoded in flash and those variables are the only real entry point of the macro ACCELERATION into the program state, except for in home.c, I'm pretty sure... I had to move those variables to SRAM to implement some more eeprom functionality. ( Which I've actually done now. ). I don't know the entirety of your code base, but for that example, I don't really thing you'd expect to see any performance loss, would you? I don't think it takes longer to load a value from SRAM into a register, than it does to load a value from flash to a register...

Edit: Ok, I just looked it up and apparently the LDS instruction takes two cycles to execute which probably means it would actually be slower... Still, I think it would make sense as a macro option and there are some other optimizations I could think of to compensate for it.

Anyways don't get me wrong, I think the Configtool is really great (much better than the alternatives), but If you look at it from the perspective of someone who's in the process of trying to tune in a new printer, with a flash size of 256KB, at least having a macro that would allow you to configure some basic machine settings, like jerk, acceleration, x_max y_max ..., through eeprom is a really nice feature.

Also, I have another idea that I plan on trying to implement, that I wan't your guys's opinion on. So, I assume it would be optimal to have a small jerk and high acceleration overall if you can achieve it right? I don't really know how that's calculated in this code, but I think the basic idea is that less jerk=more overall precision and that higher acceleration can compensate for less jerk. Well, I noticed that I could achieve really good results on curves with an accel of 4000 and x/y jerk of 300, but as soon as the printer tried to do a a travel move at 100mm/s there was step loss. The rest of the print was 20-30mm/s. It'd probably be nice to have a dynamic acceleration feature, where you can set a max and min acceleration and the actual acceleration is calculated in real time based essentially on the inverse of speed (feedrate), so a 0mm/s move would accelerate at max acceleration and a move at max speed would accelerate at min acceleration. Does that sound like a good idea? It would probably be pretty easy to implement.

ryannining commented 6 years ago

zking, if the Acceleration is dynamic and change while moving, then it will be hard to calculate how many steps ramping up/down.

but if its change based on entry speed, that can be done i think.

the problem of 3D printer, i think is the swelling when the acceleration is low + jerk low, and ringing if acceleration is high/jerk is high. because the filament still have a compressed energy while decelerate. thats why new firmware have advance extrusion algorigthm (need to be tuned)

image

ZKing1000 commented 6 years ago

@ryannining Yeah, that's what I meant entry speed. You would probably just need to change those two variables I mentioned earlier. It sounds like you guys are trying to account for this problem with an advanced extrusion algorithm, Would having a dynamic acceleration conflict with that? Having both features may be even better...

ryannining commented 6 years ago

Corner limit using repetier style, JERK 15, ACCEL 300 image

Using teacup algorithm, JERK 15, ACCEL 300 image ACCELL 4000 image

Using GRBL centripetal corner max speed, DEVIATE 0.3, ACCEL 300 image

Backplanner Enabled: image

Ideally, all motion must be on cruise, without acceleration or deceleration for total smooth/stable extrusion, but thats imposible because there is mechanical limit on motor. So thats why there is corner limit.

You need to use high accell and small jerk to smoothing curve move right ?

Wurstnase commented 6 years ago

No. You need high jerk for such moves.

Which tool are you using for the pictures?

ryannining commented 6 years ago

yes, sorry high jerk.

ryannining commented 6 years ago

Its a gcode simulator, but for ramping use F squared incremented by acceleration.

the file is phone stand keychain hipopotamo from thingiverse, its high segment count image

to get good deceleration on low acceleration value you have to implement backplanner

ZKing1000 commented 6 years ago

I think I should clarify that right now I'm using x and y jerk values of 600 and an acceleration of 2000 and curves are turning out beautifully (That's how I did a 0.05mm tolerance). I'm just worried that a jerk of 600 may interfere with the rest of the print... Am I justified in that assumption? I tried lowering the jerk to 300 and increasing the acceleration to 4000 in order to compensate, but the higher acceleration became a problem on non-printing moves (ie. travel moves). And also, I'm using a translucent filament so I can easily see where there is plastic build up, based on the coloration of the print... (The print gets darker in the vertex corners of the cylinder when the jerk and accel are too low) I imagine that an acceleration of 4000 is pretty big, since it would take I think 5ms to accelerate to 20mm/s. It seems to work fine on curves, but accelerating from less than 20mm/s to 100mm/s in the span of less than 20ms isn't feasible for my machine without stuttering and step loss. I want fast travel moves, though to fight oozing, which my machine is easily capable of at lower accelerations. So that's where the idea for dynamic acceleration comes in.

@ryannining Nice pictures, but I'm not sure I completely understand them... Are the white segments times of accel/deccel and the red segments cruising? Also what do you mean by a backplanner?... Are the bottom graphs speed? If so it looks kinda unstable at 4000 accel... Or are they graphs of ideal extrusion amount or something associated with an extrusion algorithm... If so, I could imagine that high accelerations could maybe mess with an extrusion algorithm, because I bet it would be hard to lower the pressure in the nozzle at really specific spots like that... Also, I printed what you asked me to print today with a couple different filament types, but I don't have my phone on me right now (its complicated), which I would optimally need to take a some pictures and it's dark out so the lighting would probably be bad... And, I'm getting pretty anxious, which happens sometimes sadly... Sorry about that.... But I'll probably be able to do it tomorrow.

Edit: Is it ok that we are getting kinda off topic or should I move this stuff to some type of pull request? Since, I may end up making one of those anyways... I guess the actual issue has been fixed.

ryannining commented 6 years ago

Wow jerk 600 is just like no corner slow down at all. And your machine can do thats mean yout machine is like a dream machine.

The color is just a palette, which i set low speed as white. Its mean the corner limit algorithm success detect

Thr last pic i use different palette to show each color is a segment in the gcode.

Have you print the hipopotamo phone stand keychain from thingiverse?

Wurstnase commented 6 years ago

Jerk are values which can make the printer instantly. https://github.com/Traumflug/Teacup_Firmware/blob/master/dda_lookahead.c#L89-L109

e.g. Marlin standard is 20mm/s (1200mm/min). So 600 is not very high.

Backplanner I made some tries a year ago. But without any success so far, because of missing time and no good ideas.

@ryannining Do you have any source for your simulator?

ZKing1000 commented 6 years ago

@Wurstnase Oh, I wasn't sure how marlin calculates lookahead vs this. Are they any different? In the config tool I noticed the sane values were recommended as 0-400mm/min... I take it having a dynamic acceleration may not be necessary at all? I'm really just interested in achieving maximum quality because I'm planning on printing some gear boxes for my cnc that need to be as precise as possible.

@ryannining Yes I have. Tomorrow I will take some pictures. Then I will show you... It was a pretty good quality.

ryannining commented 6 years ago

Ahhh i see, so teacup save the f values as per minute not per second. I am not familiar with marlin, only repetier. Repetier jerk value normally 25 for xy and 3 for z

We can see the repetier jerk code at motion.cpp teacup at dda_lookahead.c and grbl at planner.c

The code i use i put on github/karyacontroller and compiled/run using quincy cpp ide with winbgi

triffid commented 6 years ago

Isn't jerk supposed to be distance/time³, ie rate of change of acceleration?

On 20 February 2018 at 15:55, ryannining notifications@github.com wrote:

Ahhh i see, so teacup save the f values as per minute not per second. I am not familiar with marlin, only repetier. Repetier jerk value normally 25 for xy and 3 for z

We can see the repetier jerk code at motion.cpp teacup at dda_lookahead.c and grbl at planner.c

The code i use i put on github/karyacontroller and compiled/run using quincy cpp ide with winbgi

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/Traumflug/Teacup_Firmware/issues/295#issuecomment-366894169, or mute the thread https://github.com/notifications/unsubscribe-auth/AAKBGnoGRAuJsEFcK5-YxhGUG3cojg6Nks5tWnpcgaJpZM4SF0RA .

Wurstnase commented 6 years ago

Isn't jerk supposed to be distance/time³, ie rate of change of acceleration?

Normally yes. But 3D printer use the name 'jerk' for a bit different solution. The problem is when you have short segments in curves. There you could have deceleration to zero. This is where jerk comes into play.

ryannining commented 6 years ago

Yea, in grbl, klipper no "jerk" there they use acceleration and deviate then calculate the sinus from current and previous vector to calculate max allowable F

ZKing1000 commented 6 years ago

@Wurtnase Based off of what you linked to it sounds like jerk is simply being calculated based off of difference In the component axes's target speed and scaled in-between to compensate for large discrepancies. Which is pretty much how I would expect it to work......

I guess I should just try implementing what I suggested and see how well it works. Like I said it's a pretty easy hack.

ZKing1000 commented 6 years ago

@Wurstnase In that case a jerk of 600mm/min would equate to an instant change of 10mm/s. Which I guess isn't that huge, but still the smaller the better I guess... Or maybe not... This stuff is kinda complicated and it does play into your extrusion algorithm... Is there actually any attempt being made right now in this firmware to modulate the pressure in the nozzle based off of the current speed in real time? Or is that just a planned feature.

Wurstnase commented 6 years ago

I'm not a fan of advanced extruder algorithm. The problem of such things is, that you need to tune your extruder first. Then enable the advance algorithm and tune again. This tuning is very special and will make more problems then it solves.

Probably new algorithm are doing a better job. My acknowledge about this is >2 years old.

Pressure values are based on speed, acceleration, material, temperature... A lot of dependencies...

ZKing1000 commented 6 years ago

Yeah I could definitely imagine... That would also probably depend on your particular extruder... You may be able to narrow it down to just a couple or few values that need to be configured though... Kinda like PID tunning. It's probably possible. Have you seen those multicolor setups that melt the plastic into a continues filament line in real time and give really precise multicolor prints. If that's possible this is probably possible too... Anyways I think I got my answer. I'll try implementing that feature when I get the energy... I may need to take a break soon though.

ryannining commented 6 years ago

advance extrusion, should be just move the stepping time extruder motor, before the axis motor right ? should be just 1 variable, extrudedelay value is in microseconds

right ?? :smiley:

ZKing1000 commented 6 years ago

@ryannining Maybe it is... I wouldn't really know. You can always try implementing it and see what results you get. I just worry that there may be some more complicated physics involved or something, but like I said I really wouldn't be one to know. Although if you are going to try implementing that I think I just had a somewhat interesting idea... How about you try implementing small little retractions of the filament at points of deccel in the print. So on the vertices of a cylinder there are small little retractions to combat oozing. Have you guys' thought of that?

ZKing1000 commented 6 years ago

The retraction I think would have the effect of relieving pressure in the nozzle (in real time, no delay) and the speed at which you can do that would probably only be limited by your max E feedrate. Doing things that way would probably play much better with dynamic acceleration and yield really good results overall. Not to mention it would be relatively simple to implement.

ZKing1000 commented 6 years ago

Ok, here are the pictures you wanted... I used cura to slice the model. All we're printed at 20mm/s with 3d concentric infill 20%, wall width 0.8, nozzle diameter 0.4.

Stock PLA, came with the printer:

side top

Tianse 1.75 PLA: The filament got caught so there was some z distortion and I still need to upgrade the z axis...: https://www.amazon.com/dp/B01NCRVSF6/ref=cm_sw_r_cp_apa_IrmJAb3B43ASK

head back side

And for the hell of it I did one at 0.1mm layer heights: light

Look at how the layers lines turned out under a lense: 0.2mm layers 0.1mm layer height closer up

That looks like some serious precision. The layer lines all came out pretty much exact. Can't wait to see how it fairs with a 0.2mm nozzle.

I'll do another tolerance test once I've tuned in my printer some more...

ryannining commented 6 years ago

Great!!

ZKing1000 commented 6 years ago

@ryannining Anyways, what do you think of the retraction idea?