Eliminating ringing by modeling a spring-damper system

83 views
Skip to first unread message

Oskar Linde

unread,
Dec 17, 2020, 5:03:34 PM12/17/20
to 3DP Ideas
I've read this group over the years as a source of inspiration and though it's time to share something in return.

I recently got a chance to prototype and test an idea I've had for a while – could we model a 3D printer motion dynamics as a spring-damper and apply model based control to eliminate (or significantly suppress) ringing phenomenon?

I did a quick write-up of the concept and did including some simulations: https://www.digitalvision.blog/spring-damper-control/

And here's a short video of the method running live: https://youtu.be/3ze9RwqkLqU

The method looks promising, but to make this work there are two things that need to change:

1. This is fundamentally incompatible with instantaneous velocity change / "jerk". We need to develop another method to smooth out tessellated geometry. I can think of several reasonable options
2. Fundamentally, for this to work you ideally want s-curve acceleration profiles (to get a continuous second derivative) as the method would otherwise need instantaneous set-point changes. It's possible that we can approximate this by just approximating this by moving fast (the simulation seems to indicate this), but I don't know how well that would work in practice.

Thoughts?

Joseph Chiu (Toybuilder)

unread,
Dec 18, 2020, 10:07:40 AM12/18/20
to Oskar Linde, 3DP Ideas
There is currently a Kickstarter, i believe, for a cloud service to perform some kind of motion modeling to improve speed and output quality. https://3dprint.com/193133/algorithm-speeds-3d-printing/

I don't know the technical details beyond what is briefly described in the article, but it sounds maybe like some of the smoothing functions that were in skeinforge.

--
You received this message because you are subscribed to the Google Groups "3DP Ideas" group.
To unsubscribe from this group and stop receiving emails from it, send an email to 3dp-ideas+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/3dp-ideas/2efeac98-ab8c-433a-8e1a-a6cb1d9d0881n%40googlegroups.com.

Joseph Chiu (Toybuilder)

unread,
Dec 25, 2020, 2:53:05 PM12/25/20
to Joseph Chiu, Oskar Linde, 3DP Ideas

Oskar Linde

unread,
Dec 25, 2020, 3:41:07 PM12/25/20
to joe...@joechiu.com, 3DP Ideas
That's very interesting, that paper on "Command Shaping" http://code.eng.buffalo.edu/tdf/papers/acc_tut.pdf is actually not the same approach I'm proposing. My approach effectively solves for a new set of control setpoints to cause the end-effector to perfectly follow a desired target profile. The command shaping approach instead applies a correction signal to the end of a move to eliminate the residual ringing. That approach may be more suited to run on limited compute controllers, but I think there are a number of advantages to doing perfect continuous control.


The two modes of ringing were actually pretty enlightening to me: https://forum.duet3d.com/post/200564


Ryan Carlyle

unread,
Jan 12, 2021, 12:48:58 PM1/12/21
to 3DP Ideas
I love that people are actually implementing this stuff in a feasible way now. I read the Duet forums thread a few days ago and it's good stuff. The Klipper input shaping work is also good stuff. What I do want to see is application tests in more diverse print geometry. The results on rectangular shapes oriented with printer axes are AWESOME, but does it make organic shapes worse? Does it have wacky behaviors if you rotate the test print 45 degrees or 31 degrees?

Some of us printer-control nerds have been kicking around feed-forward ringing compensation ideas for years, but it really wasn't feasible to implement back in, say, 2015. Certainly 8bit Sailfish/Marlin/Repetier weren't powerful enough to do it, and Smoothieware's motion control coding was too rigid to accommodate stuff like this (or even linear advance) without a major refactor that the devs didn't want to tackle at that time. There was a university team (can't remember which one or find the paper) that made an input-shaping demonstration printer a number of years ago and achieved pretty ludicrous speeds on factory hardware, but that was some pretty janky custom coding/toolchain. Being able to implement it as a hobbyist-tunable firmware mode is very much necessary for the approach to go anywhere. Getting more powerful controller platforms with broader dev support like Klipper and Duet/RRF seems to be putting it in reach now. 

The constant "rediscovery" in this space is always frustrating to me, and I wish we could spend a lot more time documenting things better than forum/group posts. Like the "two ringing modes" thing (decel ringing causing transverse errors and accel ringing causing extrusion width errors) was discussed in some detail on the Duet forums a couple years ago. Likewise the resonant frequencies varying with nozzle position within the build volume, belt elasticity being dominated by the length of the shorter leg of the loop, and the dominant resonant modes varying by machine architecture. All "already known" to SOMEBODY, but it isn't obvious nor well-documented. (A few of these things are in my Volume 2 which hopefully I will finish and publish someday...) The ~2018 S-curve ringing reduction discussion was when David Crocker figured out (with a lot of input from the hive mind) that there are accel/jerk combos that can partially self-cancel ringing, and S-curve is worse than trapezoid in some situations. 

In terms of eliminating corner jerk / junction deviation (velocity jumps) one corner-smoothing approach is fairly well-proven by MachineKit. They establish a per-axis acceleration limit, and a maximum allowable error, and the trajectory planner creates a smooth curve trajectory that satisfies all individual axis accel limits and the maximum off-path error at the highest attainable speed. This is really favorable for milling because you can do a high-velocity roughing pass with a wide tolerance and then come back for a low-velocity finish pass with a tight tolerance. But that's fairly similar to how we do perimeters slower than infill. That MachineKit trajectory planner mode is also only implemented for 3-axis XYZ motion, it doesn't support E-axis extruders, so there's a 3d printing workaround based on a wire-laying approach (slaving extruder speed to XYZ speed) which is viable... but makes life a lot harder for modern slicer features like variable extrusion width or layer height slicing. 

So, the challenge for me is, how do you make a ringing cancellation approach that is flexible enough to work on different machine types, but simple enough to be usable by anyone other than a few power-users? Like...
  • Delta ringing can be dominated by drivetrain elasticities or by frame sway. (Plastic corner vertices or undersized columns --> frame flex.) Frame sway gets worse as Z height increases, but whether belt elasticity gets better or worse with Z height depends on whether motors are at top or bottom. So you can have a U-shaped elasticity curve with Z height. And since you have three drivetrains with "gear ratios" that vary with nozzle distance from that tower, you could have one dominant drivetrain resonance frequency that splits into 2-3 different frequencies near the edges of the bed.
  • CoreXY has diagonal resonance axes in the drivetrain via belts/motors, and separate X axis and bridge-torsion resonance modes from rod/rail flex.
  • Ender3 / i3 printer elasticities are dominated by belt stretch (particularly cheap printers with cheap belts) which is fairly linear with motion stage position. Y axis ringing should be relatively constant with Z height, while X axis ringing can increase with Z height. 
All of these things depend on motor selection, belt selection, frame design, etc. Which means you can pick 10 random printers and find there is 7 different elasticity curve shapes to accommodate in the tuning parameters. 

So, folks like me are pretty caught up in "admiring the problem" and maybe are making it look too complex to solve. Yet there is definitely a large subset of users (say anybody with an i3 or XY gantry Cartesian machine) that would benefit greatly from a minimum-viable-product type user-tuned approach with a few parameters. And maybe we don't care too much at the end of the day whether high Z heights or printing at delta bed-edge decreases print quality, because let's be honest, that's already true today, and most people do most printing at bed-center and low Z height.

I do think an automated accelerometer-based tuning approach is going to be the most fruitful at the end of the day. David Crocker's delta bed leveling code absolutely transformed the viability of deltas as production printers, and that's the model I would personally prefer moving towards for ringing as well. You can do a resonance frequency/magnitude/orientation scan of the build volume, and just map out a matrix of compensation factors like mesh leveling. Heck, you could roll backlash compensation and bed leveling into one accelerometer scan routine if you wanted. Building this into a Smart Effector or bolt-on MEMS dongle puts all the complexity into the up-front design/coding and then would be fairly painless for users. 

Maybe a more practical question, is there an intermediate step we can do with RRF that puts some input shaping work into the code base that can be extended for an accelerometer approach later?

Oskar Linde

unread,
Jan 12, 2021, 3:09:00 PM1/12/21
to Ryan Carlyle, 3DP Ideas
Ryan, thanks for the detailed response. I'll give some quick comments/thoughts below.

On Tue, Jan 12, 2021 at 9:49 AM Ryan Carlyle <temp...@gmail.com> wrote:
I love that people are actually implementing this stuff in a feasible way now. I read the Duet forums thread a few days ago and it's good stuff. The Klipper input shaping work is also good stuff. What I do want to see is application tests in more diverse print geometry. The results on rectangular shapes oriented with printer axes are AWESOME, but does it make organic shapes worse? Does it have wacky behaviors if you rotate the test print 45 degrees or 31 degrees?

Thanks. Let me do some more test non-axis aligned paths on a CoreXY when I hopefully get a bit of time over the weekend. Organic shapes are still not possible with my simple setup though, as I haven't solved for path smoothing yet. The fact that I got good results on a delta printer gives me some confidence though.
 
Being able to implement it as a hobbyist-tunable firmware mode is very much necessary for the approach to go anywhere. Getting more powerful controller platforms with broader dev support like Klipper and Duet/RRF seems to be putting it in reach now. 

Yeah, S-curve control is now on the roadmap for the next major RRF version, and that will unblock one of the biggest hurdles (path smoothing being the other one).
 
The constant "rediscovery" in this space is always frustrating to me, and I wish we could spend a lot more time documenting things better than forum/group posts.

I agree that the ephemerality of forum posts is a problem and one should probably take the time to do some better write-ups of things once they are in a more conclusive state. I don't know of a good repository that's aggregating this type of information though – any suggestions?
  
In terms of eliminating corner jerk / junction deviation (velocity jumps) one corner-smoothing approach is fairly well-proven by MachineKit. They establish a per-axis acceleration limit, and a maximum allowable error, and the trajectory planner creates a smooth curve trajectory that satisfies all individual axis accel limits and the maximum off-path error at the highest attainable speed. This is really favorable for milling because you can do a high-velocity roughing pass with a wide tolerance and then come back for a low-velocity finish pass with a tight tolerance. But that's fairly similar to how we do perimeters slower than infill.

Yes, this is pretty much what I've been thinking. The acceleration limits will impose a maximum curvature limit, which together with a maximum "cordial error" as specified by the user will bracket the trajectory. For most segmented geometry you can even reconstruct the underlying generating conic curve (e.g. arcs) with no loss in actual precision.
 
So, the challenge for me is, how do you make a ringing cancellation approach that is flexible enough to work on different machine types, but simple enough to be usable by anyone other than a few power-users? Like...
  • Delta ringing can be dominated by drivetrain elasticities or by frame sway. (Plastic corner vertices or undersized columns --> frame flex.) Frame sway gets worse as Z height increases, but whether belt elasticity gets better or worse with Z height depends on whether motors are at top or bottom. So you can have a U-shaped elasticity curve with Z height. And since you have three drivetrains with "gear ratios" that vary with nozzle distance from that tower, you could have one dominant drivetrain resonance frequency that splits into 2-3 different frequencies near the edges of the bed.
  • CoreXY has diagonal resonance axes in the drivetrain via belts/motors, and separate X axis and bridge-torsion resonance modes from rod/rail flex.
  • Ender3 / i3 printer elasticities are dominated by belt stretch (particularly cheap printers with cheap belts) which is fairly linear with motion stage position. Y axis ringing should be relatively constant with Z height, while X axis ringing can increase with Z height. 
All of these things depend on motor selection, belt selection, frame design, etc. Which means you can pick 10 random printers and find there is 7 different elasticity curve shapes to accommodate in the tuning parameters. 

I agree that there are a lot of parameters (at least in theory), but I think most printer geometries will fall within one of a fairly small set of models, and for each model there is a stack ranking of the parameters with the first few being able to model most of the characteristics. A compounding problem though is that some parameters have the potential to change over time as well (e.g. belt tension for belts with a non-linear stress-strain curve).
 
So, folks like me are pretty caught up in "admiring the problem" and maybe are making it look too complex to solve. Yet there is definitely a large subset of users (say anybody with an i3 or XY gantry Cartesian machine) that would benefit greatly from a minimum-viable-product type user-tuned approach with a few parameters. And maybe we don't care too much at the end of the day whether high Z heights or printing at delta bed-edge decreases print quality, because let's be honest, that's already true today, and most people do most printing at bed-center and low Z height.

I do think an automated accelerometer-based tuning approach is going to be the most fruitful at the end of the day.

Yes, completely agree. I actually did some experiments with an accelerometer over the weekend and it seems entirely feasible and easy to do a complete characterization of the dynamic model with a cheap accelerometer. I'll share some data on this once I've had a chance to go over it a bit more systematically. I wish there was a free SPI header for high bandwidth data on the boards we use (like Duet) since with that we could potentially do closed-loop acceleration-based control with a very cheap sensor board on the hotend, but right now I'm looking at using the serial bus on the PanelDue header to at least get an easy characterization flow working. It's not inconceivable to build a fully self-characterizing model that requires close to zero user input. in theory you even have the signal to auto calibrate the correction on the fly.
 
David Crocker's delta bed leveling code absolutely transformed the viability of deltas as production printers, and that's the model I would personally prefer moving towards for ringing as well. You can do a resonance frequency/magnitude/orientation scan of the build volume, and just map out a matrix of compensation factors like mesh leveling. Heck, you could roll backlash compensation and bed leveling into one accelerometer scan routine if you wanted. Building this into a Smart Effector or bolt-on MEMS dongle puts all the complexity into the up-front design/coding and then would be fairly painless for users.

Yes, that would be awesome. You can easily build this dongle today for $40 worth of off the shelf components (I just did), and later spinning a custom small PCB for this shouldn't be hard and would cut the cost in half.
 
Maybe a more practical question, is there an intermediate step we can do with RRF that puts some input shaping work into the code base that can be extended for an accelerometer approach later?

I think the motion control and the characterization are fairly orthogonal. S-curves plus curve smoothing are as I mentioned probably the two biggest boulders to enable the motion control side. The characterization and modeling aspect seems fairly straightforward.

Ryan Carlyle

unread,
Jan 12, 2021, 6:45:53 PM1/12/21
to 3DP Ideas
I have no suggestions on better repositories. Forums (forae?) and blogs go fallow and lose content. Social media platforms don't have any meaningful archival/documentation functionality. That's basically why I started writing books. They have a terrible lag-time from discovery/invention to documentation though, and most people don't read them, so. A wiki would probably be best if people would put the effort into maintaining them. Like, yeah, I could spend the next month sprucing up RepRap Wiki pages, and we'd have some absolutely kick-ass stepper motor pages or whatever, but the whole site needs more maintenance and traffic for that to really be worth the effort. It stopped being relevant when the 3DP community R&D center of gravity shifted away from self-replicating and we collectively shifted gears into milled metal parts and performance optimization and modding cheap Chinese printers. 

"Chordal" not "cordial" by the way. 

One thing that worries me about trying to reconstruct surface contours in firmware from the gcode path is that you've lost a lot of information along the way, and firmware then has to make decisions that might not match user intent. For example, take a cylinder shape. Was the model created as a vector/NURBS/whatever true circle cross-section and then converted to mesh? Or was it modelled as an extruded high-facet polygon? Was that polygon drawn inscribed inside or circumscribed outside the desired arc boundary? Does that behavior vary for inside holes versus outside holes? For example, if you draw a circle in Sketchup, the default behavior is a 24 sided inscribed polygon. So the mesh is non-trivially undersized relative to the desired arc shape. That's usually ok for part fit/function. If you then boolean a cylinder out to make a hole/pocket, the polygon facets extend beyond the desired arc shape, and the part is oversized, contributing to the typical hole undersizing problem we have. And then somebody who knows about hole undersizing will use the Polyhole method where they boolean out an octogon or whatever circumscribing their desired circular hole. So your modelling toolchain can have different inscribing/circumscribing behavior.  You don't necessarily know what the desired part geometry was when you see a string of gcode segments. Certainly the firmware isn't smart enough to look and say "this is a hole so I will oversize, while this is a contour surface so I will undersize." Most slicers have elected to not try to compensate for this stuff, because you can't easily do it consistently. 

Then there's prints like lithophanes and embossed text (like the back end of a Benchy) where small gcode segments may have been VERY precisely designed such that you lose resolution if you try to convert segments to arcs or whatever else. How do you accommodate stuff like that in an arc-conversion algorithm? 

But now I'm admiring the problem again... maybe there's a simple approach that covers most cases, or a one- or two-parameter model that covers the desired cases. 

Oskar Linde

unread,
Jan 12, 2021, 8:06:32 PM1/12/21
to Ryan Carlyle, 3DP Ideas
On Tue, Jan 12, 2021 at 3:45 PM Ryan Carlyle <temp...@gmail.com> wrote:
"Chordal" not "cordial" by the way. 

Thanks for pointing that out. One challenge of being a non-native speaker.

One thing that worries me about trying to reconstruct surface contours in firmware from the gcode path is that you've lost a lot of information along the way, and firmware then has to make decisions that might not match user intent. For example, take a cylinder shape. Was the model created as a vector/NURBS/whatever true circle cross-section and then converted to mesh? Or was it modelled as an extruded high-facet polygon? Was that polygon drawn inscribed inside or circumscribed outside the desired arc boundary? Does that behavior vary for inside holes versus outside holes? For example, if you draw a circle in Sketchup, the default behavior is a 24 sided inscribed polygon. So the mesh is non-trivially undersized relative to the desired arc shape. That's usually ok for part fit/function. If you then boolean a cylinder out to make a hole/pocket, the polygon facets extend beyond the desired arc shape, and the part is oversized, contributing to the typical hole undersizing problem we have. And then somebody who knows about hole undersizing will use the Polyhole method where they boolean out an octogon or whatever circumscribing their desired circular hole. So your modelling toolchain can have different inscribing/circumscribing behavior.  You don't necessarily know what the desired part geometry was when you see a string of gcode segments. Certainly the firmware isn't smart enough to look and say "this is a hole so I will oversize, while this is a contour surface so I will undersize." Most slicers have elected to not try to compensate for this stuff, because you can't easily do it consistently.

Without actually knowing or testing, I suspect most if not all CAD tessellation algorithms will (at least default to) create triangles with the vertices on the actual parametric surface and leave the triangles/line segments between unadjusted. Primarily because it's the easiest thing to do and also helps ensure that segment nodes join properly (e.g. the transition from a flat surface to a corner radius).

Making the chordal error a g-code-adjustable parameter would provide the user (or even slicer) with some deterministic control, and from a workflow perspective it would be nice to not have to think about holes vs outer contour dimensions. But simply cutting corners (literally) is probably the simplest approach and would probably also most closely match the current instantaneous velocity change behavior. The thing though is that the key reason that holes come out undersized in a naive workflow is the combination of segmentation error and the instantaneous velocity change (which further results in corner rounding). Both of these can potentially be eliminated.

Then there's prints like lithophanes and embossed text (like the back end of a Benchy) where small gcode segments may have been VERY precisely designed such that you lose resolution if you try to convert segments to arcs or whatever else. How do you accommodate stuff like that in an arc-conversion algorithm? 

I'd probably suggest as a heuristic to not convert a segment transition if it's beyond a specific angle. If you compare to the actual path a "springy" hotend with a firmware with instantaneous velocity change would follow across such small segments, we can probably come up with a parameterized algorithm that gives less absolute path-tracking error at the same average speed.
 

Ryan Carlyle

unread,
Jan 13, 2021, 9:41:20 AM1/13/21
to 3DP Ideas
I don't like naive corner-cutting arc conversion because it works great on sharp corners, but if you assume typical model meshing behavior, it makes holes MORE undersized and convex surfaces MORE undersized than the meshing and slicing processes already did. So you kind of want to round off sharp corners but circumscribe big faceted arcs outside the facets instead. Picking between different behaviors based on how the firmware interprets the gcode geometry isn't ideal.

My gut says we want to follow the path as closely as possible on average, rather than always inscribing or circumscribing. My recollection is MachineKit's corner-rounding technique requires the trajectory to touch the midpoint? of every gcode segment (after decimating out tiny segments), in addition to maintaining the specified max error.   

Comparing segment DURATION against the dominant resonant PERIOD could be fruitful for planning arc conversions. Then it's tied to machine dynamics rather than part geometry. The current worst case for faceted arc trajectories is when you have a polygon that is 1) faceted finely enough that the angle between segments is too gentle to trigger jerk / junction deviation slowdowns, and 2) faceted coarsely enough and at the right spacing for the small corner velocity jumps to hit a resonant frequency. 

Likewise, you can have multiple small turns across a series of gcode segments, which individually are trivial but collectively constitute a large turn. Like if you take a rectangle with a sharp corner and fillet off the corner at a small radius with a high facet count, that will act much like a sharp corner for machine dynamics but current firmware only sees a gentle smooth curve (because it looks solely at corners, not cumulative direction changes over a time/distance). This inability to consider cumulative velocity changes across multiple small segments is a major gap in current 3DP trajectory planners. It also doesn't show up in most people's ringing test prints due to their choice of model geometry.

I might suggest arcs that attempt to intersect each segment at a location close to the segment endpoints, say you start the corner rounding at a fractional resonant wavelength from the corner, meaning you would set the corner-rounding arc size such that it smears the corner velocity change over a distance/time that is anti-resonant. Segments too small for that would get run through a check to see if it's suitable for either arc blending or feedrate slowdown.

Just taking a stab at a sequence...
  1. After gcode parsing, load the commanded gcode into the motion planner buffer
  2. Merge arbitrarily small gcode segments (e.g. less than 1 microstep)
  3. Calculate each segment duration at commanded feedrate
  4. Flag segments longer than X resonant periods ("long segments") versus short segments, and classify corner transitions between adjacent segments
    1. Corner between two long segments: S-curve the straight lines and round off sharp corners using appropriate arcs (e.g. S-curve slowdown to cornering speed, round corner at constant low speed, then S-curve accelerate out of the corner)
    2. Corner between long and short: chop off the end of the long segment at the corner with length = adjacent short segment, so it can be evaluated for arc blend in next step. S-curve the long segment.
    3. Corner(s) between >=2 short segments: Calculate direction of first turn. Calculate direction of next (nth) turn. When consecutive turns are in the same direction, check if converting to circle arc is feasible (ie is there a solution for a circle that fits within a certain error and allowable accel/speed). Keep checking additional segments for addition to the arc until there is a direction change or no longer a suitable circle arc fit. 
    4. Corners between short segments turning in different directions: identify low constant speed that will make corner jerks anti-resonant for the segment length with trapezoid or S-curve accel through the series of small segments

Oskar Linde

unread,
Jan 14, 2021, 12:38:24 AM1/14/21
to Ryan Carlyle, 3DP Ideas
On Wed, Jan 13, 2021 at 6:41 AM Ryan Carlyle <temp...@gmail.com> wrote:
I don't like naive corner-cutting arc conversion because it works great on sharp corners, but if you assume typical model meshing behavior, it makes holes MORE undersized and convex surfaces MORE undersized than the meshing and slicing processes already did. So you kind of want to round off sharp corners but circumscribe big faceted arcs outside the facets instead.

Agreed.
 
My gut says we want to follow the path as closely as possible on average, rather than always inscribing or circumscribing. My recollection is MachineKit's corner-rounding technique requires the trajectory to touch the midpoint? of every gcode segment (after decimating out tiny segments), in addition to maintaining the specified max error.

Requiring the rounding to never round more than half the segment (touching the midpoint) is a good simple way to avoid corner cases. Note though that corner rounding of an outside corner on a CNC machine can be done without any precision loss if the introduced corner radius is less than or equal to the cutter radius. CNC machines are generally programmed with G-Code that allows them to know which side of the path the cut is happening at so they can apply wear compensation for the cutter diameter. If slicers provided the same information we could similarly often round internal corners by the nozzle radius without any rounding of the outer contour.
 
Comparing segment DURATION against the dominant resonant PERIOD could be fruitful for planning arc conversions. Then it's tied to machine dynamics rather than part geometry. The current worst case for faceted arc trajectories is when you have a polygon that is 1) faceted finely enough that the angle between segments is too gentle to trigger jerk / junction deviation slowdowns, and 2) faceted coarsely enough and at the right spacing for the small corner velocity jumps to hit a resonant frequency.

When doing spring-damper correction, I believe the resonant period becomes much less important, but it might still be a useful reference dimension.
 
Likewise, you can have multiple small turns across a series of gcode segments, which individually are trivial but collectively constitute a large turn. Like if you take a rectangle with a sharp corner and fillet off the corner at a small radius with a high facet count, that will act much like a sharp corner for machine dynamics but current firmware only sees a gentle smooth curve (because it looks solely at corners, not cumulative direction changes over a time/distance). This inability to consider cumulative velocity changes across multiple small segments is a major gap in current 3DP trajectory planners. It also doesn't show up in most people's ringing test prints due to their choice of model geometry.

Yes, the instantaneous velocity change method of path smoothing is pretty crappy. Luckily, with proper path smoothing we can retire it entirely.
 
I might suggest arcs that attempt to intersect each segment at a location close to the segment endpoints, say you start the corner rounding at a fractional resonant wavelength from the corner, meaning you would set the corner-rounding arc size such that it smears the corner velocity change over a distance/time that is anti-resonant. Segments too small for that would get run through a check to see if it's suitable for either arc blending or feedrate slowdown.

Rather than an arc we want a C2 continuous curve. A 4rth order polynomial with zero curvature at the start and end point is probably the most straightforward way to connect two long straight segments.
 
Just taking a stab at a sequence...
  1. After gcode parsing, load the commanded gcode into the motion planner buffer
  2. Merge arbitrarily small gcode segments (e.g. less than 1 microstep)
  3. Calculate each segment duration at commanded feedrate
  4. Flag segments longer than X resonant periods ("long segments") versus short segments, and classify corner transitions between adjacent segments
    1. Corner between two long segments: S-curve the straight lines and round off sharp corners using appropriate arcs (e.g. S-curve slowdown to cornering speed, round corner at constant low speed, then S-curve accelerate out of the corner)
The way to calculate the corner radius should probably be based on your max acceleration setting = centripetal acceleration = speed^2/r. If your print speed is 80 mm/s and the acceleration is 1000 mm/s^2, the min radius to avoid slowing down is 6mm. The radius error can then be calculated based on the turn angle. Only if the radius error exceeds the tolerance would we need to slow down. This allows large radius curves (with potentially relatively long segments) to be traversed at constant speed.

Maybe a minor thing, but for relatively sharp corners (e.g. ≤90°) between long segments I could see one wanting to keep them sharp i.e. a minimum radius increase vs the nozzle size while accepting more smoothing on curved parts of the geometry. Basically decelerating all the way down to zero velocity.
    1. Corner between long and short: chop off the end of the long segment at the corner with length = adjacent short segment, so it can be evaluated for arc blend in next step. S-curve the long segment.
You probably want to modify this to half the short segment length, especially if the segment after the short one is a long one again. 
    1. Corner(s) between >=2 short segments: Calculate direction of first turn. Calculate direction of next (nth) turn. When consecutive turns are in the same direction, check if converting to circle arc is feasible (ie is there a solution for a circle that fits within a certain error and allowable accel/speed). Keep checking additional segments for addition to the arc until there is a direction change or no longer a suitable circle arc fit. 
    2. Corners between short segments turning in different directions: identify low constant speed that will make corner jerks anti-resonant for the segment length with trapezoid or S-curve accel through the series of small segments
With model based control, I don't think the resonance aspect will be that crucial. I'd suggest both of these cases could ideally be handled by fitting a low-order polynomial spline with enforced G2 continuity. A NURBS model would generalize any conical curve like circular arcs and ellipses. A computationally simpler method might be to do just circular arc fitting, but then we'd need to add a separate transition curve, similar to the one above, into, out of and between arcs to preserve G2 continuity.

Since we have shown that the spring-damper model is a good dynamic model for the printer motion, it's not hard to simulate all of the above in software with good accuracy to determine the trade-offs. I've been planning to get to that once I'm through my backlog of other things.

Note, keeping the trajectory C2 continuous is important if you want to avoid instantaneous stepper motor position changes for spring-damper compensation. The math and compute for transition spirals is a bit hairy though and for more general curves directly representing C2 continuity gets practically infeasible. G2 continuity is relatively easy to achieve though, and a G2 continuous path can always be reparametrized (numerically in practice) to C2 continuity. It's not too compute heavy, but may still be too much for a M4-class microcontroller to do in realtime without some pre-processing.
 

Dushyant Ahuja

unread,
Jan 14, 2021, 9:48:18 PM1/14/21
to 3DP Ideas
Klipper has support for using ADXL345 accelerometer to measure resonances. The input shaping technique works wonders for my self-built Core-XY. I haven't tried the accelerometer yet; but that's next on the list. 

Ryan Carlyle

unread,
Feb 2, 2021, 4:44:48 PM2/2/21
to 3DP Ideas
Did y'all know this exists?
Looks like somebody went off and implemented segment-to-arc conversion without us. 

Dushyant Ahuja

unread,
Feb 3, 2021, 12:48:08 AM2/3/21
to Ryan Carlyle, 3DP Ideas
Had read about it some time back, but never used it, as Klipper's arc implementation splits arcs back into line segments - so will not make any difference (as far as I understand)
------------------
Dushyant Ahuja


You received this message because you are subscribed to a topic in the Google Groups "3DP Ideas" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/3dp-ideas/RmVGqb77yJ8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to 3dp-ideas+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/3dp-ideas/53bba733-ef0c-47b3-9650-ef8ed80d6a39n%40googlegroups.com.

Ryan Carlyle

unread,
Feb 3, 2021, 9:06:31 AM2/3/21
to Dushyant Ahuja, 3DP Ideas
I think all mainstream 3DP firmware does currently split arcs back into segments, which is why this wasn’t done years ago. For non-Klipper 8bit firmwares, it can help with pause zits by reducing the command transmission rate for USB or SD. Command parsing uses a lot of interrupt time and loop time on the old Atmegas. Not a game-changer, but interesting to try for certain people with print flaws. 

Perhaps more importantly, having contours be consistently arc’d could be a useful starting point for new acceleration techniques like centripetal acceleration control. It’s not quite continuous spline curves, but it’s a good starting point to play around with some of the rounding techniques we’ve been talking about. 

Also, if we’ve previously had a chicken or the egg problem where slicers don’t make arcs and firmwares don’t process arcs properly, maybe this will get some firmware devs thinking about true arc support. I think you should be able to use a midpoint circle algorithm for fast DDA in lieu of the old Bresenham’s approach (or just use RRF’s exact step time calcs like a delta), and apply centripetal acceleration limits, with fairly little change to the rest of the motion planning / step processing. 

Ryan Carlyle

On Feb 2, 2021, at 11:48 PM, Dushyant Ahuja <dusht...@gmail.com> wrote:


Reply all
Reply to author
Forward
0 new messages