Overextrusion at Start and End of Corners in 5-Axis Rotating Convex-Cylindrical Bed Printer: Is Custom Klipper Kinematics the Solution?

Basic Information:

Printer Model: Creality Ender 5
MCU / Printerboard: bigtreetech skr mini e3 v3.0 32 bit mainboard & Creality 3D silent mainboard V4.2.7
Host / SBC: RPI4
klippy.log: klippy.log (1.6 MB)

Hey All,

I’m currently in the process of building a custom printer, and I need help with getting the kinematics right. The setup is as follows:

The System

The system consists of a 5-axis printer (XYZBA) with a rotating convex cylindrical bed: X B and Z are linear movements, where B is generally passive as its only purpose is to keep the nozzle on the center of the spinning bed (it’s the original Y linear axis). Y rotates the print bed, and A rotates the hotend so that its perpendicular to the print surface. Stepper B and A are both manually added steppers. The print bed, or substrate, is actually printed with a polymer as well, so the final print is a product of the substrate and the pattern that is printed on top. I’m printing single line patterns (in vase mode style) on top of the substrate, with a high flow rate (1mm nozzle, approximately 2mm layer thickness).

Up to this point, I have been using cartesian kinematics in my printer config, and basically wrote my own python script to write the gcode in such a way that makes it suitable for the setup of the printer. Here is a quick summary of the current workflow:

  1. A Rhino Grasshopper script that does two things:
    a. Generate pattern and export list array of x,y,z coordinates
    b. Generate an array of radii of the substrate (the radius of each layer height (0.2mm))
  2. The data is then imported into a python script, which does the following things:
    a. Generating Gcode: Iterate through the pattern coordinates and convert data into gcode suitable for printing on top of the substrate. The Z coordinates are calculated using the values from the radii array. Additionally, the angle between the different radii is calculated to define the value for A, retrieving a value that ensures that the extruder will always be perpendicular to the current layer.
    b. Linear to Angular Velocity and Extrusion mapping: To account for the differences in linear and angular velocity, the program calculates the correct feedrate by looking at the translation of x and y and then calculates the actual movement lenghts across y by using the current radius (and additional z height), using the formula:
    actual_y = delta_y * (current_circumference / rotation_distance)
    This value is then used to adjust the speed, by comparing the real distance of XY, and commanded distance of XY, and changing the feedrate and exrusion value accordingly. The rotation_distance corresponds to the stepper_Y rotation_distance in the printer configuration, which is set to 40.
    The Problem

So far I’ve made good progress in getting the system to work, but I’m currently stuck on a problem that I have trouble resolving. During printing, there is a imperfection that keeps reoccurring in my print. When I try to print rounded corners, the printer keeps over extruding material at the beginning of the corner, and it also tends to over extrude at the end of the corner (see image). I suspect it has to do with the fact that the printer has to slow down before initiating the corner, even though I’m already “manually” trying to accomplish this using the previously mentioned linear to angular velocity logic.

So, here are some things I have tried to resolve the issue:

  • Ensure that acceleration and velocity of all axis are the same to reduce dwelling of the nozzle. I reasoned that when the printer initiated the rounded corner, both X and Z axis start to move and their acceleration could cause a delay in the printers path, causing filament to ooze out. But tweaking these settings led to no succes.
  • I tried tweaking Pressure Advance ¶ which did influence the imperfection. A high PA value resulted in underextrusion, and a low PA value resulted in overextrusion. However, there was no golden ratio where the imperfection would cease to exist. I also hypothesized later that PA should be turned of anyway, because when gradually converting angular motion to linear motion (or vise versa), and changing the feedrate acordingly, the actual print speed on the surface remains the same (therefore, PA can be turned of right..?).
  • I also tried tweaking the square corner velocity. I reasoned this could be the problem, because the domain of the initial G-code height is limited to Y = 0 to Y = 40, which corresponds to the rotation distance of 40. In reality, the gcode Y coordinates are being stretched out on the substrate. So, the initial rounded corner might be small, but is actually bigger when printed. Therefore, I tried tweaking the square corner velocity, suspecting that when it’s the same as the normal velocity there would be no acceleration to deceleration before the corners. In parallel, I also tried different values for the min. cruise ratio, but both inquiries led to no succes.

My Question

My hypothesis is that the problem that I’m currently facing is due to the function mentioned in 2b: Linear to Angular Velocity and Extrusion mapping. Because what I’m essentially doing here is applying the desired kinematics in higher level code, as a workaround for the printers generic cartesian kinematics, and this might be causing some conflicts. The system thinks its slowing down and the extrusion suddenly changes, which I can imagine could be confusing for the underlying machine settings.

Therefore, I think it would probably be sensible to consider making my own kinematics.py file, where I define the correct kinematics in lower level code. However, I’m starting to realize I don’t know enough about kinematics and Klipper’s low-level Python code, which makes this a challenging task. My initial idea was to maybe rewrite parts of the polar.py kinematics, because my system shares some similarities with this configuration. Or maybe I could consider building a kinematics file that uses a cylindrical coordinate system?

I’m hoping that someone can give me some advice on how to tackle this issue. Here are some specific questions that I need help with:

  1. More general: Is it likely to assume that the current problem I’m facing is due to the aforementioned reason, mainly the mismatch between kinematic/general configuration of the klipper configuration and my own code, and could you elaborate on why and where this problem actually occurs? Or do you think the problem lies elsewhere?
  2. Could there be another work around that might be worth considering, that could lead to good print results without the need for rewriting low level code?
  3. If you think writing my own kinematics file is a sensible direction, how should I approach creating this custom configuration? Does it make sense to tweak the polar.py kinematics file, like rewriting it into cylindrical coordinates? And what are elements of the klipper code that would require tweaking? (e.g. elements of kinematics.py / stepper / toolhead.py)?

I’m hoping someone can give me some guidance / advice on this problem. I hope that I’ve shared enough information about the system, but, if needed, I can provide more information.

1 Like

Wow, I didn’t realize that my analysis and question became so long :sweat_smile:. Props for anyone actually reading through that.

After some further digging I realized that I totally misunderstood the rotation_distance setting. I didn’t realize it affected steps/mm, and therefore affecting the feedrate as well. In my case it would be ideal to change the rotation_distance on the fly, but as far as I know that’s not possible (Something similar to Marlin's M92 command - #17 by dmbutyugin). But I think I can manage with just using a rotation_distance that corresponds with the average circumference, and post process my gcode to compensate for the different angular distances and velocity.

Next step is to actually implement this system on an ender 3 with a z belt drive modification. Because I realize now that the current z-axis, consisting of a lead screw and a rotation distance of 4, really is not up to the task of non planar printing. Aside from the erroneous rotation ditance on the y-axis, the z axis is most likely a major bottleneck as well, as the steps/mm on this axis is huge, ausing the printer to slow down when a z movement is initiated (which is ususally right before the corners…)

Interesting machine. Congrats on your build and the successful prints you’ve had so far!

For what it is worth, it looks like you have a pretty unusual machine and I suspect you’ll know more about what is needed then we do. Some of the questions you’ve asked are just the kind of questions I would have asked you. That said, I do have a few comments and questions.

If I understand your hardware correctly, you have a traditional cartesian style printer with XYZ axes with motors that we could call hw_x, hw_y, and hw_z for discussion purposes. It seems you have also added a motor that alters the nozzle position by angling it relative to a line parallel to hw_y, that we could call hw_b for discussion purposes. And you also have a motor that can spin a “cylinder like bed” around a line parallel to hw_x, that we could call hw_a for discussion purposes. Did I understand that correctly?

In the klippy.log file that you uploaded, it looks like you were using kinamtics: polar but in the above text you mentioned using cartesian kinematics. Where does “polar” kinematics come into this setup? If it does, how do you intend to map the “hw_?” motors to stepper_bed, stepper_arm, and stepper_z?

What is the preferred gcode coordinate system for your project? That is, if you could write out the gcode in a way that made sense for the objects you plan to print, what would the G28 X, Y, Z, ... axes represent?

It sounds like you are trying to generate gcode that directly encodes motor positions in it. For what it is worth, I suspect it will be challenging to do that while getting good results from Klipper’s lookahead system. That system is designed to process standard linear cartesian coordinate systems that wont map well to arbitrary motor movements.

FYI, Klipper also has a “gcode move transform” system that is capable of translating coordinates prior to processing. It’s used by tools like bed_mesh. I have also used this system to implement a kind of “tool center point control” system for 3d printers with XYZAB kinematics. If you are curious you can find that experimental code in the pivot_coord module at GitHub - KevinOConnor/klipper-dev at work-pivotcoord-20250604 . That module doesn’t directly translate to your use case (the module is for a traditional flat bed that can be rotated around a point perpendicular to Y and Z). However, maybe it can give you some ideas.

As a suggestion, if I had a similar requirement, I would look at defining a gcode coordinate system that made sense for the prints, then use a “gcode transform” to convert that to XYZ+AB coordinates internally, and then try to use existing internal kinematics for stepper generation. The goal would be to try to reuse the existing lookahead system (which only considers XYZ movement - post “gcode transform”).

Maybe that helps a little,
-Kevin