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

Experimental kinematics #1023

Merged
merged 3 commits into from
Dec 24, 2018
Merged

Experimental kinematics #1023

merged 3 commits into from
Dec 24, 2018

Conversation

KevinOConnor
Copy link
Collaborator

Klipper has had experimental "polar" and "cable winch" kinematics on development branches for some time. I plan to commit these experimental kinematics to the master branch - although they are not complete, I think they are sufficiently modular that they will not adversely impact the main cartesian/corexy/delta users.

-Kevin

This was referenced Dec 20, 2018
@yschroeder
Copy link
Contributor

Based on my experiments over the last few days I figured out, that it would be really handy to configure the attachment points of the winches at the toolhead separately. We discussed this in #180 and while it is working to offset the winches by the offset of the attachment points, it is error prone to change something.

The anchor positions should be the exact values measured from the (arbitrarily chosen) (0, 0, 0) location. When changing the toolhead (when experimenting with different designs) it gets complicated to add and subtract the offsets (subtract the old offsets, add the new ones). Klipper could do this automatically.

So my suggestion would be to add three optional config parameters per winch: offset_x, offset_y, offset_z. These parameters define offsets relative to the toolhead (nozzle) for the cable attachment points.

@KevinOConnor
Copy link
Collaborator Author

@yschroeder - that makes sense. I don't feel I'm in a good position to make those types of changes though, as I don't have the hardware to test it. If you'd like to get the code and docs into a better shape, that would be great.

Let me know if you think I should hold-off on merging "winch" kinematics, or if you think merging and extending later is okay.

-Kevin

@yschroeder
Copy link
Contributor

I think you can merge this as the basic functionality is there (and I believe it is working correctly apart from my setup being badly calibrated).

Homing (SET_KINEMATIC_POSITION) and configuration (toolhead offsets) are a bit rough but can be improved later.

I will copy my above idea into an issue and might work on it myself. Can't promise it though and it would only happen after holidays are over...

@tobbelobb
Copy link

Can you elaborate on why anchor positions should be measured from the origin?

What would be the end points of the offset measurements, and how does the simplified anchor calibration procedure look, step by step?

When changing tools heads using Marlin and RepRapFirmware, I've just added a z-offset in Slic3r. Later, when we have tool changing, I've imagined adding a z offset, relative to a point on the holder bracket on the mover, per tool.

@tobbelobb
Copy link

Just for reference: In current Marlin and RepRapFirmware, the offsets from nozzle tip to line entry point on the mover are not mentioned in the firmware at all. Anchor positions are measured from line entry point on the mover, to the line entry point on the anchor. (You only measure along one line, even if several lines go in the same direction.)

So the static offsets are subtracted at time of measurement, not firmware compilation time or run time.

@yschroeder
Copy link
Contributor

I am not sure what exactly you mean with "simplified anchor calibration". To be honest, I haven't looked yet at how anchors are calibrated for a Hangprinter, so there might be better ways to do this. Let me explain what we did until now:

Remember we have this setup:

img_20181218_144219

  1. We built up the cubicle walls (later this would be some other existing wall) roughly square (based on the floor tiles)
  2. We put up the winches at the corners without paying any attention where they are exactly
  3. We marked the (0,0,0) at the front left corner below the D winch. We used a makeshift plumb bob (ball bearing on a string) to get right underneath the D winch. However, later we decided that the attachment point at the winch is actually somewhere else, so the 0 location is just roughly at the D winch. We decided on the front left corner to be in line with other 3D printers.
  4. We measured X, Y and Z locations of all anchors directly with a laser rangefinder and/or a yardstick. These measurements are likely not very accurate, hence our accuracy is not very good right now.
  5. We put the measured values into the Klipper config and subtracted the offsets of the attachment points from the toolhead. In our case, the toolhead is a small moving platform (I am going to change this) where the center point is the "nozzle" and the cables are attached on a square around it with each edge being 100mm long. This means, that the attachment points for the cable are 50mm off in X and Y direction. Further, the attachment points are 35mm above the "nozzle". We did the math as pointed out by Kevin here: Cable winch kinematics #180 (comment)
  6. We marked and measured a position right (roughly) in the center of the whole area as our calibration point (on the floor, Z=0)
  7. We moved the toolhead by hand to that location (motors off) and held it in place
  8. We wound up the cable on the spools until tight by hand (I want auto-tightening with TMC2130 here)
  9. We set the current location of the toolhead via SET_KINEMATIC_POSITION
  10. Done, you can now move the toolhead via G1 as you like (or you move 0 via G92 to this center location)

Step 4 is extremely cumbersome though. The easiest way to do this is via a total
station
. These devices are magic. After you tell the device where the origin point is and in which directions the axes are (by pointing its laser there), you can just point the laser at the winches, press a button and it will show X, Y, and Z coordinates on its display. The more expensive ones do not need a prism for reflection, they work on every surface like a laser rangefinder. However, these devices cost a fortune and they are certainly out of scope for a hobby project. Luckily, I am am working at a university and I know people from another insitute owning a total station and they are helping me now and then (but sadly have not measured my setup yet).

So, how would you do it @tobbelobb? I started watching the calibration part of you video with Tom, but I'd like a written document better 😃

@tobbelobb
Copy link

Ah, ok I thought you were suggesting a simplification of the current Hangprinter calibration routine.

Having the origin at the bottom left of your reachable area get you in line with Cartesian printers, but out of line with delta printers. As you say, you may define the origin to anywhere you choose. There is a practical benefit to placing your origin close to where you will actually print, and to do your calibration measurements when the nozzle is in that point. The benefit is better accuracy, because consequences (errors) due to any mis-calibration will grow (accumulate) when you move away from your well calibrated point (the origin). Some work on consequences of calibration errors here: http://vitana.se/opr3d/tbear/2018#hangprinter_project_53

I don't do manual calibration anymore, as step 4 in your description is indeed cumbersome. Manual calibration is not part of part of the HP design or intended use case, so I won't write any official documentation, but I can try to help you here. Steps to manually calibrate anchor positions of HP3:

  1. Put the nozzle at the origin. When calibrating manually, the origin must be the point where D-lines are completely vertical, and the nozzle hovers ca 0.5 mm above the print surface.
  2. Tighten ABC-lines so that the mover will be stationary during the calibration.
  3. Now focus on one of the A-lines. Measure the distance, l_a, between the point where it enters the mover and the point where it enters the anchor. We want to divide this distance into two components: The vertical one, call it anchor_A_z (a negative value), and the horizontal one, call it anchor_A_y (also a negative value). Warning: measuring the vertical part and the horizontal part separately is really tricky, but you can use Pythagoras' theorem to assure yourself that you're in the right ballpark. Your three measured lengths should satisfy:
    l_a^2 = anchor_A_y^2 + anchor_A_z^2
  4. B-line measurements are similar, but you need to also divide the horizontal length into two orthogonal components: The x one and the y one. You should end up with l_b, anchor_B_x (positive value), anchor_B_y (positive value), and anchor_B_z (negative value). They should satisfy:
    l_b^2 = anchor_B_x^2 + anchor_B_y^2 + anchor_B_z^2
  5. C-line calibration is similar to B-line calibration. The only difference is that anchor_C_x should be considered a negative value (the C anchor is to the left of the origin).
  6. D-line calibration is easier. Measure the distance between the point where one line enters the mover to the point where it enters the lineroller vertically above it. anchor_D_z is a positive value. anchor_D_x and anchor_D_y are zero.

Standard HP3 calibration is semi-automatic. The user collects data points, feeds them into a script, and the script calculates the position of the anchors. See:
https://gitlab.com/tobben/auto-calibration-simulation-for-hangprinter#how-to-collect-data-points

The semi-automatic calibration script could probably be made to work for your machine as well with some small adjustments.

@tobbelobb
Copy link

tobbelobb commented Dec 20, 2018

How does your inverse kinematic equations look like? I think your point 5 might be in error. You want to calculate line lengths (distance from the point where the line enters the mover to the point where the line enters the anchor), not the distance to the tip of the nozzle. Edit: Maybe you're not in error, since you're measuring from the origin and subtract your offsets. Works in principle, if your offsets are right.

If you're using the Tom's videos, then this page might help you navigate them since they're so long: https://reprap.org/wiki/Links_Into_Hangprinter_v3_Build_Video#Now_going_into_an_hour_of_measuring_this

@KevinOConnor
Copy link
Collaborator Author

How does your inverse kinematic equations look like?

FYI, Klipper calculates motion from a single inverse kinematics equation. For the "winch" demo kinematics, I implemented: 345b22e#diff-5407884987d0f93b6d75d59a65f94109R19

The code uses an "iterative solver" to find a precise time for each step on each stepper using this function. The anchor x/y/z values come directly from the config: 345b22e#diff-f726e7a1bb28f5dce6c9c6e7bbf4cd4cR15

The above equation may not be best - my goal was to provide a starting point.

FYI, it should be possible to change just this inverse kinematics equation (and the similar forward kinematics equation in the winch.py code) to implement more advanced calculations (eg, the effect of gravity on the cable, the effect of spooled cable impacting the drum radius).

-Kevin

@tobbelobb
Copy link

Looks perfectly reasonable. I like the clear, easy to read config file!

@yschroeder
Copy link
Contributor

Maybe this PR is derailling completely now, but I am not sure I understood the semi-automatic calibration. I understood is does the following: You input nozzle positions and line lengths into the script and it tries to figure out which anchor locations make sense for those values.

Some questions:

Or do you just need the line lengths and not the real X, Y, Z coordinates?

The Mechaduinos tell Marlin the "lost" steps when they are moved by hand and M114 S1 tells you the cable lengths of A, B, C and D?

You say you move to the position of data point collection. Where exactly is this? I guess the solver needs to know this?

In the video with Tom you did all kinds of measurements. Am I correct, that none of these are needed when using the semi-automatic calibration?

Does the solver make any assumptions on the geometry of the printer (e.g. D winch being at X=0 Y=0)?

And some more info on the kinematics:
I found this Phd thesis some time ago:
https://elib.uni-stuttgart.de/bitstream/11682/9102/1/ValentinLorenzSchmidt65.pdf
It covers all kinds of details in cable winch robots (and they use Dyneema cables, which I am using as well). Section 2.2.1 (page 12) covers the basic kinematics and the offset of the cable attachment to the end effector.

@tobbelobb
Copy link

Thanks for asking these questions. Calibration is the major bottleneck and hurdle for almost all HP users and details has been under-communicated.

Yes, M114 S1 tells you cable lengths, but not absolute cable lengths. It gets relative cable lengths compared to the line lengths you have when the nozzle is at the origin.

You input these relative line lengths into the script. The xyz-positions of data point collection may also be input into the script, but this is optional. The most common way to use the script is to drag the mover to ca 13 completely random and unknown positions of data point collection and not input any xyz-positions into the script.

No, the solver does not need to know positions of data point collection. It will solve for that as well as the anchor positions. If you do know the xyz-positions of data collection, then you need fewer points of data collection (maybe 3-4?), and may have better accuracy in the output anchor point positions.

Yes, you don't need measuring tape at all to build a HP3 :) Working on the Tom's videos made me realize that crawling on the floor with a measurement tape is really not the way forward.

Yes, the solver currently assumes D winch being at x=0 y=0.

HP3 also uses dyneema. It's awesome :)

@yschroeder
Copy link
Contributor

I had an idea for a (almost) fully automated calibration. It might not be completely thought through, so maybe this does not work at all.

It requires automatic cable tensioning (as possible with the Mechaduinos and hopefully via the Stallguard of the TMC2130 as well. With the encoder output of Mechaduinos it might become even easier.

The automated calibration would work like this:

  1. Move the mover to 0 location and hold it in place
  2. Auto-tension all cables (the mover does not move, as it is held in place)
  3. Wind up a known length of cable on 3 winches (e.g. 10 cm), the mover will move and one cable hangs lose
  4. Auto-tension the fourth cable that was lose and record the amount of cable that was needed to tension the cable

After step 4 we know all 4 cable lengths that are needed for your calibration script. Repeat steps 3 and 4 until enough points are sampled, maybe choose different winches each time for the lose cable. It might also be advisable to return to the 0 location in between to check if all cables are still tensioned correctly.

If you are using Mechaduinos, the fourth motor could be in torque mode and you could read out its encoder movement directly instead of auto-tension it afterwards. I'm interested in the auto-tension solution, as this would work with my TMC2130.

@tobbelobb
Copy link

I think your idea would work well if StallGuard2 gave a fine-resolution measurement of line tension. But StallGuard2 has some limitations that would make the data collection procedure you describe less good (I think maybe not work at all) in practice.

After a StallGuard2 detection, you only know the motor shaft position to an accuracy of +-4 full steps. So you would need to return to the origin an re-calibrate between collected data point.

StallGuard2 actually doesn't measure force, it forces back emf, which depends on many things, like motor speed. Back emf does not easily translate to cable tension. But you could record for example the line lengths at the origin, if you ram the mover into prepared landing brackets at the anchors.

Before reaching for the Mechaduinos (and later SmartSteppers and ODrives, I don't recommend Mechaduinos anymore), I tried using force sensing resistors. Some details here: http://vitana.se/opr3d/tbear/2017#hangprinter_project_48

I think auto calibration based on force sensing resistors (or better; well calibrated load cells) could be made to work well.

If you just want to test the script, you could use forced moves to get into 13 different valid positions (positions where all lines are tight).

@yschroeder
Copy link
Contributor

I understand that is an abuse of stallguard to do tensioning. The accuracy can be down to 1 full step, which is actually not that much I believe. For my setup one full step is 0.36mm. I don't think I can tension the cable to that accuracy by hand... (remember, my machine is not fully constrained, so overtensioning one cable results in movement of the nozzle).

Further, Stallguard does not only allow stall detection but you could read SG_RESULT during a move to see the current load. It might be problematic, that this only works for faster moves (whatever fast means exactly).

I'd love to try your script, however, FORCE_MOVE needs to be fixed for this (see #1012) and there needs to be a way to get the current cable lengths. G28 should reset the cable lengths to 0 and all moves (both, kinematic moves and forced moves) need to considered for the current cable length. Then I have everything at hand for calibrating via your script.

@yschroeder
Copy link
Contributor

yschroeder commented Dec 21, 2018

@KevinOConnor: I found a bug with this PR (back on topic):

You are using mathutil in winch.py without import. This becomes obvious when issuing a GET_POSITION command:

Traceback (most recent call last):
  File "/home/pi/klipper/klippy/gcode.py", line 188, in process_commands
    handler(params)
  File "/home/pi/klipper/klippy/gcode.py", line 69, in <lambda>
    func = lambda params: origfunc(self.get_extended_params(params))
  File "/home/pi/klipper/klippy/gcode.py", line 652, in cmd_GET_POSITION
    for a, v in zip("XYZE", kin.calc_position())])
  File "/home/pi/klipper/klippy/kinematics/hangprinter.py", line 36, in calc_position
    return mathutil.trilateration(self.anchors[:3], [sp*sp for sp in spos])
NameError: global name 'mathutil' is not defined
Internal error on command:"GET_POSITION"

Yes, I'm still using the old version, but the bug is still valid.

Add a dummy kinematics class for development testing.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
@KevinOConnor KevinOConnor force-pushed the work-kinematics-20181219 branch from 345b22e to 7c6d145 Compare December 21, 2018 17:14
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
@KevinOConnor KevinOConnor force-pushed the work-kinematics-20181219 branch from 7c6d145 to 4957695 Compare December 21, 2018 17:20
@KevinOConnor
Copy link
Collaborator Author

You are using mathutil in winch.py without import.

Thanks, should be fixed now.

-Kevin

@KevinOConnor KevinOConnor merged commit 5dc74f3 into master Dec 24, 2018
@KevinOConnor KevinOConnor deleted the work-kinematics-20181219 branch December 24, 2018 16:39
@Kenzu
Copy link

Kenzu commented Oct 19, 2019

Hello
I have a sculpto printer. It has custom electronics, based on an linkit smart7688 wifi module with openwrt and an LPC1768 (smoothie based). They talk via uart.
The machine is not normal Polar, but more like bipolar (like an old LP player). I have a smoothie and marlin port working on the machine, but would like to try out klipper.
How to get started?

https://sculpto.dk

sculpto

@Kenzu Kenzu mentioned this pull request Oct 20, 2019
@github-actions github-actions bot locked and limited conversation to collaborators Oct 22, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants