Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cable winch kinematics #180

Closed
JonasForssell opened this issue Feb 17, 2018 · 46 comments
Closed

Cable winch kinematics #180

JonasForssell opened this issue Feb 17, 2018 · 46 comments

Comments

@JonasForssell
Copy link

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

@KevinOConnor
Copy link
Collaborator

KevinOConnor commented Feb 17, 2018 via email

@JonasForssell
Copy link
Author

JonasForssell commented Feb 17, 2018 via email

@JonasForssell
Copy link
Author

JonasForssell commented Feb 18, 2018

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?

@KevinOConnor
Copy link
Collaborator

KevinOConnor commented Feb 19, 2018 via email

@JonasForssell
Copy link
Author

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.

@KevinOConnor
Copy link
Collaborator

KevinOConnor commented Feb 20, 2018 via email

@JonasForssell
Copy link
Author

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

@KevinOConnor
Copy link
Collaborator

KevinOConnor commented Feb 22, 2018 via email

@lenne0815
Copy link

@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.

@JonasForssell
Copy link
Author

@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.

@lenne0815
Copy link

Yes, or use one of these springs commonly used in vacuum cleaners to spool it up neatly.

@JonasForssell
Copy link
Author

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

@JonasForssell
Copy link
Author

JonasForssell commented Feb 25, 2018

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

@KevinOConnor
Copy link
Collaborator

KevinOConnor commented Feb 25, 2018 via email

@KevinOConnor
Copy link
Collaborator

Any update on your development?

@JonasForssell
Copy link
Author

JonasForssell commented Apr 1, 2018 via email

@yschroeder
Copy link
Contributor

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?

@KevinOConnor
Copy link
Collaborator

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

@yschroeder
Copy link
Contributor

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.

@KevinOConnor
Copy link
Collaborator

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

@KevinOConnor
Copy link
Collaborator

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

@JonasForssell
Copy link
Author

JonasForssell commented Jul 13, 2018 via email

@yschroeder
Copy link
Contributor

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.

@yschroeder
Copy link
Contributor

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...).

@KevinOConnor
Copy link
Collaborator

KevinOConnor commented Jul 13, 2018 via email

@programmerq
Copy link

I would love to test out hangprinter support and provide feedback!

@tobbelobb
Copy link

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:

  • Frameless (static anchors are mounted directly on existing structures)
  • Cable driven
  • Redundantly constrained (more than 3 movement axes used for translation in 3d space)
  • Probably Cable-driven Parallel (I haven't found the exact definition of this term, but it is similar enough to ROBOCRANE, "the first cable-driven parallel robot" that I dare use it.)
  • Line-on-spool

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.

@KevinOConnor
Copy link
Collaborator

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

@KevinOConnor
Copy link
Collaborator

@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

@tobbelobb
Copy link

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.

@KevinOConnor
Copy link
Collaborator

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

@tobbelobb
Copy link

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.

@tobbelobb
Copy link

@programmerq Has the Klipper cable winch support been tested on a Hangprinter yet?

@KevinOConnor
Copy link
Collaborator

Any updates on this?

@KevinOConnor
Copy link
Collaborator

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

@KevinOConnor KevinOConnor added the inactive Not currently being worked on label Sep 9, 2018
@yschroeder
Copy link
Contributor

yschroeder commented Dec 14, 2018

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:

  1. Set the motor drivers to low hold current to be able to drag the end effector
  2. Pull the end effector to a known position (or move there via unregistered moves)
  3. Fix the end effector there (by holding tight or clamping down)
  4. Issue a G28. This pulls all cables tight, then the motor drivers register motor stalls and stop the homing procedure.
  5. Set the new machine position via G92 to the known position from step 2.
  6. Set motor driver currents back to normal

@yschroeder
Copy link
Contributor

I just cherry-picked 17300f4 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.

@tobbelobb
Copy link

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.

@yschroeder
Copy link
Contributor

yschroeder commented Dec 19, 2018

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):

img_20181218_144219
img_20181218_144014
img_20181218_144050
img_20181218_144118
img_20181218_144134
img_20181218_144140

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?

@KevinOConnor KevinOConnor reopened this Dec 19, 2018
@KevinOConnor KevinOConnor removed the inactive Not currently being worked on label Dec 20, 2018
@KevinOConnor
Copy link
Collaborator

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

@KevinOConnor KevinOConnor changed the title Feature Request: Support for Tetra printer Cable winch kinematics Dec 24, 2018
@KevinOConnor
Copy link
Collaborator

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

@KevinOConnor
Copy link
Collaborator

Any further updates on this? If not, I'm inclined to mark this as inactive again.

-Kevin

@yschroeder
Copy link
Contributor

@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...

@til-k
Copy link

til-k commented Mar 15, 2019

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

@KevinOConnor
Copy link
Collaborator

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

@KevinOConnor
Copy link
Collaborator

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

@github-actions github-actions bot locked and limited conversation to collaborators Dec 15, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants