First of all thank you for this fantastic program. It has done wonders for my little 28byj-48 steppers and enabled my project.
I am trying to add support for a new type of printer to Klipper.
I call it Tetra - a type of hangprinter (see Tetra 3D printer group on facebook). The effector is suspended in three anchors with a stepper driven spool at each anchor.
This means that the stepper position is effectively equal to the arm length of each wire.
I have made a fork with the hope to provide a pull request in the future here, and have managed to adjust most of the Delta class code but I am now stuck.
I need hints on how to adjust the code in the move method. The step_delta code runs deep into Klipper through stepper and mcu classes and I am unsure if I should use this or perhaps step_const instead. I do not understand why there are two ways to drive the steppers when the kinematics already have been done.
A little help would go a long way.
I hope posting this request here is not a problem. If so, please feel free to delete it.
Best Regards
/Jonas
On Sat, Feb 17, 2018 at 04:22:45PM +0000, JonasForssell wrote:
First of all thank you for this fantastic program. It has done wonders for my little 28byj-48 steppers and enabled my project.
I am trying to add support for a new type of printer to Klipper.
I call it Tetra - a type of hangprinter (see Tetra 3D printer group on facebook). The effector is suspended in three anchors with a stepper driven spool at each anchor.This means that the stepper position is effectively equal to the arm length of each wire.
I have made a fork with the hope to provide a pull request in the future here, and have managed to adjust most of the Delta class code but I am now stuck.
I need hints on how to adjust the code in the move method. The step_delta code runs deep into Klipper through stepper and mcu classes and I am unsure if I should use this or perhaps step_const instead. I do not understand why there are two ways to drive the steppers when the kinematics already have been done.
Hi Jonas,
I added some tips to the code overview document:
https://github.com/KevinOConnor/klipper/blob/master/docs/Code_Overview.md#adding-new-kinematics
Let me know if that helps.
Separately, just out of curiosity, do your steppers have different
effective step sizes when more wire is wound around the spool? That
is, when the head is closer to the stepper (and thus more wire is
wound around the spool) does the diameter of the spool change and thus
cause more wire to be moved on each step?
-Kevin
Hello Kevin,
Thanks for the added description. i`ll do my best to implement it.
Yes, you are correct. As the wire winds up on the spool, the diameter will increase.The Hangprinter has a compensation algoritm for this but I will try to solve it mechanically if I get Klipper working.The spool will have a slight axial movement as it turns to prevent buildup.Â
/Jonas
Skickat från Yahoo Mail för iPad
Den lördag, februari 17, 2018, 7:58 em, skrev KevinOConnor notifications@github.com:
On Sat, Feb 17, 2018 at 04:22:45PM +0000, JonasForssell wrote:
First of all thank you for this fantastic program. It has done wonders for my little 28byj-48 steppers and enabled my project.
I am trying to add support for a new type of printer to Klipper.
I call it Tetra - a type of hangprinter (see Tetra 3D printer group on facebook). The effector is suspended in three anchors with a stepper driven spool at each anchor.This means that the stepper position is effectively equal to the arm length of each wire.
I have made a fork with the hope to provide a pull request in the future here, and have managed to adjust most of the Delta class code but I am now stuck.
I need hints on how to adjust the code in the move method. The step_delta code runs deep into Klipper through stepper and mcu classes and I am unsure if I should use this or perhaps step_const instead. I do not understand why there are two ways to drive the steppers when the kinematics already have been done.
Hi Jonas,
I added some tips to the code overview document:
https://github.com/KevinOConnor/klipper/blob/master/docs/Code_Overview.md#adding-new-kinematics
Let me know if that helps.
Separately, just out of curiosity, do your steppers have different
effective step sizes when more wire is wound around the spool? That
is, when the head is closer to the stepper (and thus more wire is
wound around the spool) does the diameter of the spool change and thus
cause more wire to be moved on each step?
-Kevin
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub, or mute the thread.
Alright,
I have read your manual now a couple of times and looked at your older version of Klipper for inspiration on how to write the move() method in a clear but non-optimized way.
This is my take on it:
Calculate the line of movement for the effector by using start and endpoints from the move object
For each stepper (anchor) do:
..Calculate how many steps the line length is for the stepper (total stepper movement / step_dist)
..For each step on the stepper
....Solve the position for the effector on the line of movement (using some kind of algebra)
....Determine the time this position represent based on if it is
......an acceleration
......continuous move
......or deceleration
....call the stepper.step() method with the time to put this step in a que for the controller
Did I understand correctly?
On Sun, Feb 18, 2018 at 05:22:19AM -0800, JonasForssell wrote:
This is my take on it:
Calculate the line of movement for the effector
For each stepper (anchor) do:
Calculate how many steps the line is for the stepper by dividing the line length with step_dist
The calculation for number of steps is unlikely to be move_distance /
step_distance. For example, a move that is far away from the stepper
and going parallel to it is likely going to require fewer steps than a
move this is closer and moving towards the stepper.
Also, be aware that your kinematics may require some cartesian moves
to result in a stepper retracting cable at the start of the move and
releasing cable at the end.
You may be able to use the "virtual tower" trick to help with this -
for a given move it may be possible to imagine an anchor that is
directly above the line of movement that can still produce the same
step movements. If so, this "virtual anchor" might make the
calculations simpler.
For each step on the stepper
Solve the position for the effector on the line of movement
Determine the time this position represent based on if it is
an acceleration
continuous move
or deceleration
call the stepper.step() method with the time to put this step in a que for the controllerDid I understand correctly?
Sounds good.
-Kevin
Great feedback!
I was wondering, how exakt must the time estimation be?
If there are some allowance for tolerances, I think I can develop a very simple and fast algoritm to determine the times by stepping along the line and using the errors from the previous step to get the next one more accurate.
On Mon, Feb 19, 2018 at 06:59:18PM +0000, JonasForssell wrote:
Great feedback!
I was wondering, how exakt must the time estimation be?
If there are some allowance for tolerances, I think I can develop a very simple and fast algoritm to determine the times by stepping along the line and using the errors from the previous step to get the next one more accurate.
You need to make sure all the step times are between print_time and
print_time+move.accel_t+move.cruise_t+move.decel_t.
Other than that, you should be able to use whatever step times you
want.
-Kevin
Hello again Kevin,
I am making good progress but have a challenge. There are cases when the stepper actually will have to change direction as the effector moves along the line of movement.
How do you handle this case? I have built up an algorithm which turns each stepper until the end of movement is reached but it cannot handle the above mentioned case.
Thanks
/Jonas
On Thu, Feb 22, 2018 at 09:04:46AM -0800, JonasForssell wrote:
Hello again Kevin,
I am making good progress but have a challenge. There are cases when the stepper actually will have to change direction as the effector moves along the line of movement.
How do you handle this case? I have built up an algorithm which turns each stepper until the end of movement is reached but it cannot handle the above mentioned case.
The delta code has a similar requirement. At a high level, the delta
code determines where along the line of movement this reversal point
will be, and it then breaks the move into two moves - one from the
start to the reverse point and one from the reverse point to the end.
The code is in stepcompress.c:stepcompress_push_delta().
-Kevin
@JonasForssell totally off topic but thats a question burning on my mind since quite some time: why dont you just use a "filament" type gear system to grab the wire directly and spool the excess passively ? Ive seen multiple winch systems now and they all go convoluted lengths to account for changing diameters / uneven windings etc etc etc without ever really succeeding.
@lenne0815 This is clever thinking! Would be a great solution for larger versions when the wire length is significant. the excess wire can hang down with a counterweight to avoid the use of extra spools.
Yes, or use one of these springs commonly used in vacuum cleaners to spool it up neatly.
Alright,
I am about to start testing the special version for Tetra.
The new kinematics are written in this file
I would greatly appreciate any proof reading so that it fits the Klipper template.
Thanks
/Jonas
Sorry to bother you again, but I am curious how you debug and develop with Klipper.
Since the service runs as a deamon in the background it is not just to run the program and look at errors that occur.
I have spent some time now copying in small snippets of the program into the parser. Setting variabels by hand and see the outcome has allowed me to check the math and find loads of bugs.
Now, however I need to start running the program as it should including reading data from the configuration file.
What is your way of working from this point? Do you use the M112 command and docs.log or where does the error messages end up?
Thanks
/Jonas
On Sun, Feb 25, 2018 at 04:53:34PM +0000, JonasForssell wrote:
Sorry to bother you again, but I am curious how you debug and develop with Klipper.
Since the service runs as a deamon in the background it is not just to run the program and look at errors that occur.
See docs/Debugging.md. I run the program with a gcode file as input
and have it produce the mcu commands as an output file.
-Kevin
Any update on your development?
Hello Kevin!
I have used a version of Marlin (hangprinter) to get Tetra running. It actually works!! It is lkely the worlds lowest cost 3D printer and it can build large things!
The Klipper code is almost there but I am stuck with debugging and it is getting harder for me.It accepts a few commands until I get somekind of timeout and need to reboot the firmware in Arduino and host.
I really need some help to get through and have asked around but noone has time at the moment to help me.
When I get the time back I will try to solve it. I mean it is just a simpler version of Delta so how hard can it be?
The code is available on github if you know anyone who would be interested.JonasForssell/klipperÂ
|
|
|
| | |
|
|
|
| |
JonasForssell/klipper
klipper - Klipper is a 3d-printer firmware
| |
|
|
Branch: Tetra
/Jonas
Skickat från Yahoo Mail för iPad
Den söndag, april 1, 2018, 6:11 fm, skrev KevinOConnor notifications@github.com:
Any update on your development?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
I am planning to build something similar. Not for 3D printing though. We have a big empty space 4 floors high in the middle of our building where I want to move a cable robot around. However, I am planning to use 4 wires so the 'build volume' would be rectangular (as the space is).
I have no experience with kinematics though, but quite a bit of knowledge of MCU and Python programming.
On the problem with the spool build up: I think it is feasible to make a threaded spool that only winds up a single layer. With thin wire you can get a considerable amount of length onto even rather small spools. But idea with the extruder-style mechanic is also interesting.
Maybe we can join forces on this project?
FYI, it should be much easier to support new kinematics with the upcoming "iterative solver" code. This code (still in a development state) is available on the work-itersolve-20180609 branch. With this code, it is no longer necessary to implement the complex move() method - instead, Klipper can figure it out from just a cartesian_coordinate->stepper_position function. See the updated klippy/delta.py and klippy/chelper/kin_delta.c files for an example. The code on this branch is in active development, but I hope to get it integrated into the main branch within a couple of weeks.
-Kevin
That sounds great! I will take a look at that.
My plan would be then, to focus on my hardware first and implement the kinematics once your work on the iterative solver is (mostly) done.
FYI, the iterative solver changes have now been committed to the master branch. I've made some updates to the documentation as well - see: https://github.com/KevinOConnor/klipper/blob/master/docs/Code_Overview.md#adding-new-kinematics
-Kevin
FYI, I added a new work-hangprinter-20180713 branch with some experimental support for cable winch driven printers.
cd ~/klipper ; git fetch ; git checkout origin/work-hangprinter-20180713 ; sudo service klipper restart
-Kevin
Thanks Kevin!This would allow me to start testing my Tetra printer. I am currently using a hangprinter firmware but with special configuration.
/Jonas
Skickat från Yahoo Mail för iPad
Den fredag, juli 13, 2018, 3:21 em, skrev KevinOConnor notifications@github.com:
FYI, I added a new work-hangprinter-20180713 branch with some experimental support for cable winch driven printers.
cd ~/klipper ; git fetch ; git checkout origin/work-hangprinter-20180713 ; sudo service klipper restart
-Kevin
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
Awesome!
One remark though: The cables will most likely not be attached in a single location on the tool head/extruder. They will be attached at the corners of it to prevent twisting. So in the configuration it should also be possible to define the attachment points of the cables relative to the nozzle position.
One other thing: As I see it, your kinematics called "hangprinter" resemble something like this:
https://www.marginallyclever.com/2015/02/code-inverse-kinematics-spidercam-skycam/
This is exactly what I want to build, so I appreciate your advances here very much :-)
However, the Hangprinter project seems to have quite different kinematics (all winches at the top). To avoid confusion, you should rename your kinematics maybe to "suspended-cable" or something (it could also be the case that I am completely wrong here, as I am no expert on kinematics...).
On Fri, Jul 13, 2018 at 12:20:23PM -0700, Yannic Schröder wrote:
One remark though: The cables will most likely not be attached in a single location on the tool head/extruder. They will be attached at the corners of it to prevent twisting. So in the configuration it should also be possible to define the attachment points of the cables relative to the nozzle position.
My general understanding is that any static offset to an attachment
point can simply be subtracted from the anchor xyz coordinate. For
example, if the actual pulley is at 1000,1000,1000 and the attachment
point has a 10mm x offset from the toolhead, then one can use an
anchor coordinate of 990,1000,1000.
On Fri, Jul 13, 2018 at 07:40:12PM +0000, Yannic Schröder wrote:
One other thing: As I see it, your kinematics called "hangprinter" resemble something like this:
https://www.marginallyclever.com/2015/02/code-inverse-kinematics-spidercam-skycam/This is exactly what I want to build, so I appreciate your advances here very much :-)
However, the Hangprinter project seems to have quite different kinematics (all winches at the top). To avoid confusion, you should rename your kinematics maybe to "suspended-cable" or something (it could also be the case that I am completely wrong here, as I am no expert on kinematics...).
I'm open to different naming.
As far as I understand it, although the hangprinter has all the
winches at the top, three of the winches have cables that route
through totally different anchor points. So, in practice, the winches
can be thought of as at different locations.
-Kevin
I would love to test out hangprinter support and provide feedback!
I have a comment on the naming. I suggest using Hangprinter only when we refer to the machine that is designed by and used by the Hangprinter community. Other terms that can be more useful for naming Hangprinter-like machines or features:
More on redundandly constrained: Hangprinter is a _completely restrained positioning mechanism_ (CPRM), aka _kinematically redundant_ or _redundantly constrained_, since it doesn't require additional forces for acceleration or stabilization. For example the Tetra would be called an incompletely restrained positioning mechanism (IPRM).
For more nice and correct terms, see this book.
I have a comment on the naming. I suggest using Hangprinter only when we refer to the machine that is designed by and used by the Hangprinter community.
Okay - I'll rename the demo code next time I make a change. (I'm thinking of calling it "cable winch" kinematics.)
Hangprinter is a completely restrained positioning mechanism (CPRM)
Yes - and that's very interesting. It doesn't look like it impacts the kinematic formulas though. FYI, I coded up the demo code to automatically support between 3 and 26 cable winches (stepper_a to stepper_z).
-Kevin
@programmerq wrote:
I would love to test out hangprinter support and provide feedback!
Great! First step would be to make sure you can get Klipper installed on a Raspberry Pi and on the micro-controller. Then grab the "hangprinter" branch (cd ~/klipper ; git fetch ; git checkout origin/work-hangprinter-20180713 ; sudo service klipper restart), make sure all the motors can turn, and attach the resulting /tmp/klippy.log file to this issue.
What type of motor drivers are you using - stepsticks or mechaduinos? There isn't currently support for the mechaduinos, but it's not clear to me how important that is for basic functionality checks.
I think the basic kinematics themselves are okay, but I suspect getting the "mover" to position 0,0,0 is going to be a challenge. Can you describe the process that one would use to get the printer "homed" so that movement commands make sense?
-Kevin
Cable winch sounds good!
I coded up the demo code to automatically support between 3 and 26 cable winches (stepper_a to stepper_z).
Awesome! :)
You can get nice prints out without Mechaduinos, it just requires more time and knowledge from the user to get right.
I suspect getting the "mover" to position 0,0,0 is going to be a challenge.
Yes, automatic homing is still to be done. With Mechaduinos, it's quite straightforward: you mark a point roughly vertically below your D-anchor, and place the nozzle there before calibration and before every print. The Mechaduinos' torque mode (G95) makes it easy to drag the mover in place by hand, with the right tightness in all the strings.
If you don't have Mechaduinos, your mark must be exactly vertically below the D anchor. The D-lines must be dead vertical when the printer is at home. With the nozzle at the home position, tighten ABC-motors with "direct" aka "unregistered" moves. On Marlin, the I've used G6 for this. RepRapFirmware uses G1 S2 or G1 S1. Example:
G6 A-10 F1000 ; Tightens A-line by 10 mm at 1000 mm/min
G6 is like babystepping, just more powerful.
Yes, automatic homing is still to be done. With Mechaduinos, it's quite straightforward: you mark a point roughly vertically below your D-anchor, and place the nozzle there before calibration and before every print. The Mechaduinos' torque mode (G95) makes it easy to drag the mover in place by hand, with the right tightness in all the strings.
Okay - I don't think it would be too difficult to send basic i2c commands via the micro-controller. It does require implementing a "twi" driver on the atmega chips though.
Separately, it's likely possible to port Klipper directly to the Mechaduino's SAMD21 chip, and then drive the stepper directly from the RPi using the Mechaduino's USB port and Klipper's multi-mcu support - that would be a bit of software development work though.
G6 is like babystepping, just more powerful.
Okay, I've added support for a FORCE_MOVE command (enable with a new [force_move] config section - see config/example-extras.cfg for details). This should allow these types of "unregistered" moves.
Separately, just out of curiosity, if one is using the Mechaduino, is it necessary to drive the D motor via the regular kinematic equations, or could one just leave it in a constant torque mode?
-Kevin
Nice, FORCE_MOVE sounds good. Connecting the Mechaduinos through USB also sounds nice. It would remove the requirement for separate i2c and step/dir cables and make wiring much easier.
One could just leave the D-motor in constant torque mode, it would just work slightly less good.
The D-acceleration would be limited, but it accelerates slowly most of the time anyways, so not a deal breaker.
Usable print volume would be reduced. The ABC motors will have to pull the effector downwards to fight the constant force in the D-lines. In some positions the ABC motors will have very bad working angles. For example positions where D lines are vertical and ABC lines are all horizontal or near horizontal doesn't work with a torque mode/spring loaded D-axis. But many positions would work, so still not a deal breaker.
If there's a bump in one of the gears, or if the nozzle crashes into something so that D-line gets pulled out, then the D-motor won't use it's full force to overcome the obstacle. So we would have a higher risk of getting artifacts. With belt drive and well tuned machine this might not be a big issue.
The biggest reason why I've never spring loaded one axis is that it would make the effects of mis-calibration harder to see. With constantly tight lines we would have to measure the effector movement to see if it's correct or not. With 4 motors trying to set the correct line lengths we immediately get slack or over tight lines if something is up with the calibration.
Since you're asking about a torque mode Mechaduino on the D-axis, and not a simple spring, we could of course use the Mechaduino to read the motor angle, and calculate an observed D line length. If that line length is not what firmware would expect, we could flash a LED to force the effect of mis-calibration to be visible anyways.
@programmerq Has the Klipper cable winch support been tested on a Hangprinter yet?
Any updates on this?
I'm going to close this as it doesn't look like it is currently being worked on. I'll reopen if there is future interest.
-Kevin
FYI: I continued my work on this.
And I had an idea about the homing: I am currently using TMC2130 stepper drivers and one could use the virtual end stops for homing. It would go like this:
G28. This pulls all cables tight, then the motor drivers register motor stalls and stop the homing procedure.G92 to the known position from step 2.I just cherry-picked 17300f4120a66130a34e9432708e3e266e2126b6 onto the current master without problems.
My setup has 4 winches (A to D) connected to 4 different MCUs and all the motors are turning. The winches are not assembled yet though, so I cannot check if it positions correctly.
I will update once the winches are set up.
Awesome!
If you go for auto tightening and similar with TMC2130, be aware that StallGuard2 only works at specific speeds and loads, and you must fine tune it for every model of stepper motor for it to work well. I've experimentet with it, but then I wanted more control, and went ahead with Mechaduinos instead.
I'm very interested in HP related work on Klipper! I like the idea of a thin 3D printer firmware. It would set the scene for more flexible usage.
So, I got it working!
I was caught off-guard by G92 not doing what I was expecting. I figured I have to use SET_KINEMATIC_POSITION for homing. So the kinematics look to be working correctly.
It now moves mostly as expected. The accuracy is not great (yet). There is an error of a few millimeters or so.
Now I really want the auto-tightening of the cables, it is quite cumbersome to do this by hand (you basically need two people for it). So we should try to implement optional (virtual) end stops for the cable robot kinematic.
Here are some pictures of the setup (2x3x1.5 meter):






A few words on the hardware (if you are interested):
The control board features a FT4232, to get 4 UARTs from a single USB device. These UARTs are converted to full duplex RS485 with four MAX3490. I use Ethernet cables for simplicity. 4 wires are RS485, the other 4 wires are for power (passive PoE "standard").
The control boards have a MAX3490 again to get back to UART, that goes into a blue pill module which drives a TMC2130. There is an extra power supply and connector for a servo motor which should be used as a holding brake for the winches when the steppers are not powered.
Once this setup works nicely, I want to move it to a big open space in our institute. That will need 30m of cable for each winch.
@KevinOConnor: Would you mind to reopen this issue? Maybe we can get the kinematic into Klipper 0.8?
That's great!
Based on previous feedback, I've renamed the kinematics from "hangprinter" to "winch". I think it makes sense to commit this to the master branch - even in its experimental state. See PR #1023.
-Kevin
FYI, I've been working on adding "Mechaduino" (and similar) support to Klipper. (The Klipper micro-controller code runs directly on the Mechaduino and all actions are scheduled via the USB bus.) See PR #1038 for details.
-Kevin
Any further updates on this? If not, I'm inclined to mark this as inactive again.
-Kevin
@til-k is currently working on the auto-tightening and calibration of winch positions based on the python solver by @tobbelobb.
So this is not strictly inactive...
Hi,
as @yschroeder mentioned, I continued working on the auto-tightening with the TMC2130.
One small issue I ran into:
Using virtual endstops for winch kinematics throws an error, because endstop-initialization happens in the PrinterRail class, which is not used by WinchKinematics.
I fixed it by adding the following lines to the stepper-initialization in winch.py, line 23:
printer = config.get_printer()
ppins = printer.lookup_object('pins')
mcu_endstop = ppins.setup_pin('endstop', stepper_config.get('endstop_pin'))
s.add_to_endstop(mcu_endstop)
Not sure if thats the correct way to handle it, but it fixed the issue for me.
In case anyone is interested in details about auto-tightening:
The idea is to setup the virtual endstop and choose a SGT value so that stallGuard2 will trigger as soon as there is a slight amount of force.
I implemented a custom G-command (called 'TIGHTEN_WINCH') that initializes the endstop-homing for one stepper, then uses force_move to retract the cable and wait for the endstop-trigger. This routine doesn't work perfectly (e.g., it sometimes causes a flush_handler exception when I try to issue a regular move afterwards, I'm probably not using force_move correctly), but its enough to evaluate different parameters.
So far i have tried various SGT, IRUN and force_move velocity values for our 4 different steppers.
It seems that the stallGuard2 really differs quite a lot between the steppers (one may detect a stall with a SGT=5, another one with SGT=62), so proper fine tuning is not as simple as i thought. I also haven't really tested if the temperature of the stepper significantly influences the stallGuard, but they seem to get quite warm after a while.
I'll update if i can get it to work. We'll then also see if we can use the automatic calibration script by @tobbelobb.
Regards,
Til
Interesting. Thanks.
At a high-level, the PrinterRail is intended for steppers that have an endstop, and PrinterStepper for steppers that do not have an endstop. So, that's why you see the difference. I don't see any harm in manually adding an endstop like you've described above.
FYI, if you're running into issue while homing with force_move, then you may wish to take a look at how klippy/manual_stepper.py implements homing.
-Kevin
It looks like general "cable winch kinematics" work as expected. There's still lots to do for the hangprinter and other cable based printers. However, I don't think we need to keep this issue open to track it. As issues come up, I think we can open individual tickets on each particular issue.
-Kevin