Compare commits
934 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bee179eab4 | ||
|
|
039bb9f10f | ||
|
|
b0b4bc8958 | ||
|
|
a6553538e6 | ||
|
|
019666a6f6 | ||
|
|
7579b9671b | ||
|
|
99f3c99238 | ||
|
|
aba04bf3bd | ||
|
|
f5c67baac2 | ||
|
|
973ef97143 | ||
|
|
310cdf88cc | ||
|
|
5c05a24947 | ||
|
|
c93dad8eba | ||
|
|
fb3065cfa7 | ||
|
|
e3f9ff6701 | ||
|
|
c95cc3fb66 | ||
|
|
1dda4628a0 | ||
|
|
36612fd544 | ||
|
|
ef8c464d97 | ||
|
|
66eefa1da8 | ||
|
|
e78377eebd | ||
|
|
451f7d5672 | ||
|
|
ef820d98f6 | ||
|
|
9dfe612516 | ||
|
|
830cfc5414 | ||
|
|
45afa04578 | ||
|
|
9bc4239e9c | ||
|
|
3a1cdc7d70 | ||
|
|
3a75748762 | ||
|
|
e336c24665 | ||
|
|
849f4ed25f | ||
|
|
57d342b455 | ||
|
|
5208fc38ed | ||
|
|
b549c3927e | ||
|
|
e53a589ac3 | ||
|
|
4d48c111d8 | ||
|
|
6c1e1dcc8d | ||
|
|
ddcf9a7ff7 | ||
|
|
05ec7ca7ff | ||
|
|
ef0c80af51 | ||
|
|
d997821e58 | ||
|
|
385e6b67d9 | ||
|
|
04602b2470 | ||
|
|
923954772f | ||
|
|
5a16863465 | ||
|
|
08a5f8a5ff | ||
|
|
43ac56766e | ||
|
|
afc9bcf27b | ||
|
|
9140f36d99 | ||
|
|
fa07be9346 | ||
|
|
7290ed5f73 | ||
|
|
fc60bda4d1 | ||
|
|
82a65e9f4a | ||
|
|
b139a8561f | ||
|
|
8518da9824 | ||
|
|
656cb2c417 | ||
|
|
239c1ad5c9 | ||
|
|
7733e1d832 | ||
|
|
99b4122901 | ||
|
|
28d70eaf0c | ||
|
|
5d635c5252 | ||
|
|
22d7e48aa2 | ||
|
|
a6b0649cb1 | ||
|
|
58dd6d9106 | ||
|
|
d139389267 | ||
|
|
e99c0f53f8 | ||
|
|
02ae2ab984 | ||
|
|
97f7735c6a | ||
|
|
69486e45c1 | ||
|
|
5e8aaed41f | ||
|
|
c128a9dfd5 | ||
|
|
6dc623b35d | ||
|
|
8fc3487a8a | ||
|
|
82db072151 | ||
|
|
41f73d0c8c | ||
|
|
08a1183a01 | ||
|
|
f77e1b67f6 | ||
|
|
11c7c110a1 | ||
|
|
5abea041b4 | ||
|
|
268d1cb27c | ||
|
|
561c84dd93 | ||
|
|
955d940b60 | ||
|
|
6ea36de9f2 | ||
|
|
e0cedfb853 | ||
|
|
0a5b07f9da | ||
|
|
08874b9c91 | ||
|
|
8121a4a29f | ||
|
|
d1c209c689 | ||
|
|
f4bfce260a | ||
|
|
7e3adde542 | ||
|
|
33bdc2fc32 | ||
|
|
0b76864453 | ||
|
|
56bfb3280a | ||
|
|
3ddbd34a7c | ||
|
|
67f9c4948d | ||
|
|
7d3600f918 | ||
|
|
21df21b7af | ||
|
|
b7b216af7f | ||
|
|
077a56c2ca | ||
|
|
a67306c76b | ||
|
|
6eefbe5e30 | ||
|
|
650d55d7b2 | ||
|
|
03bcae8a98 | ||
|
|
1a67902858 | ||
|
|
01bb4b291e | ||
|
|
e38c7df064 | ||
|
|
3001a089c0 | ||
|
|
39d62556b1 | ||
|
|
434341d074 | ||
|
|
ce9db609ad | ||
|
|
6c252d30f5 | ||
|
|
978777f09f | ||
|
|
5db84779c6 | ||
|
|
1e3a03fbee | ||
|
|
01a89b951a | ||
|
|
d166d1f692 | ||
|
|
9399911490 | ||
|
|
d3665699f1 | ||
|
|
81013ba5c8 | ||
|
|
f0a754e496 | ||
|
|
51e1085dbc | ||
|
|
47bb8b7cc2 | ||
|
|
33893ece1d | ||
|
|
1b3ef8a8fb | ||
|
|
09eec3710d | ||
|
|
6fa95e12ea | ||
|
|
7a11b78fd4 | ||
|
|
3d26bf6635 | ||
|
|
08444a8b89 | ||
|
|
84c623e705 | ||
|
|
72074078f9 | ||
|
|
1d11c4e74d | ||
|
|
f8bb383e9a | ||
|
|
8e5d228555 | ||
|
|
6770aa96c9 | ||
|
|
896c31fd05 | ||
|
|
054cbbe094 | ||
|
|
0d8ddcadbb | ||
|
|
d3eda337a9 | ||
|
|
138f3c2646 | ||
|
|
f1222565b8 | ||
|
|
5caff594c5 | ||
|
|
5a68c636da | ||
|
|
02b141ac43 | ||
|
|
47e458210e | ||
|
|
3833669c3a | ||
|
|
df6528715e | ||
|
|
265b9097d5 | ||
|
|
a6025686b6 | ||
|
|
ed80b92b59 | ||
|
|
45e65580f7 | ||
|
|
f6f174ab36 | ||
|
|
0cf06ee69a | ||
|
|
ed9dee4602 | ||
|
|
f183871e28 | ||
|
|
d891baa860 | ||
|
|
f6cd51bfb7 | ||
|
|
83e9e92b9a | ||
|
|
9e4eb050f9 | ||
|
|
5a86391f78 | ||
|
|
29c83cec22 | ||
|
|
db927bd822 | ||
|
|
cb969527bc | ||
|
|
3ab9a8d26c | ||
|
|
5db4886c9c | ||
|
|
b22a81cd34 | ||
|
|
9fc5506c83 | ||
|
|
bba22ab7f0 | ||
|
|
a0b4cdb5c4 | ||
|
|
e4129a7e53 | ||
|
|
00ea3934ee | ||
|
|
cf4c31cb88 | ||
|
|
f10bd5726d | ||
|
|
7db6fa7bfc | ||
|
|
b05eb1e8e3 | ||
|
|
1bdebeaebf | ||
|
|
479772ca00 | ||
|
|
1d276d160f | ||
|
|
9313e58123 | ||
|
|
d778ae1846 | ||
|
|
522093ef00 | ||
|
|
d303e556ad | ||
|
|
1d21bf66c6 | ||
|
|
1b07505973 | ||
|
|
3c5649219f | ||
|
|
68d03e4a3e | ||
|
|
e6e0a21b06 | ||
|
|
0e0780a460 | ||
|
|
9a4425c85a | ||
|
|
57c27f75ae | ||
|
|
8d62318c5f | ||
|
|
add528532e | ||
|
|
8944e2104d | ||
|
|
319221ee23 | ||
|
|
4a5801bb2e | ||
|
|
f8acf0f54f | ||
|
|
bc5d900e61 | ||
|
|
efb4a5daa1 | ||
|
|
e0c947e188 | ||
|
|
3ffab763c0 | ||
|
|
ef09ac5a7f | ||
|
|
f6d4284d5c | ||
|
|
8d9ca6f2dd | ||
|
|
1d6af72de5 | ||
|
|
2a8dd5c51f | ||
|
|
c78f66b8e8 | ||
|
|
b340fdcc4a | ||
|
|
7785d3a87d | ||
|
|
31db4cc772 | ||
|
|
7932de11a7 | ||
|
|
bc9cbc8133 | ||
|
|
b5a41d0dd1 | ||
|
|
64a091fb98 | ||
|
|
80f23441dd | ||
|
|
3a2d16abb3 | ||
|
|
c70cc8fadb | ||
|
|
10e11950ae | ||
|
|
37788c1e55 | ||
|
|
6d6638826c | ||
|
|
6930a7de8d | ||
|
|
6bbb84326d | ||
|
|
8c2fa2e2d6 | ||
|
|
38643f52c9 | ||
|
|
eecf3b6ea8 | ||
|
|
fc1d690d75 | ||
|
|
d10380e73f | ||
|
|
aaeda540b6 | ||
|
|
fda988889b | ||
|
|
b58a897b70 | ||
|
|
84d8cf9b7e | ||
|
|
8463a83324 | ||
|
|
fc0e016a6d | ||
|
|
f5c0148665 | ||
|
|
3d78a99758 | ||
|
|
03e97c2d95 | ||
|
|
eaacb928fc | ||
|
|
75ba375b8a | ||
|
|
cbd06f1433 | ||
|
|
1c59a0d30a | ||
|
|
d222ec1024 | ||
|
|
674f584190 | ||
|
|
77fea562c4 | ||
|
|
e0f275cddf | ||
|
|
07a69df62f | ||
|
|
f8750b142f | ||
|
|
3033b03789 | ||
|
|
3506d1e994 | ||
|
|
3c4d14bfa9 | ||
|
|
db97f36631 | ||
|
|
d03cf2b83f | ||
|
|
744c6d114e | ||
|
|
3b9b4e4d6f | ||
|
|
78ba7064a7 | ||
|
|
cc7c99a4a4 | ||
|
|
d3eb148cfa | ||
|
|
00d541b767 | ||
|
|
ecf2596469 | ||
|
|
6a2eaeae40 | ||
|
|
ce7cc798dc | ||
|
|
0ec7eda11b | ||
|
|
fb0f344346 | ||
|
|
afac81c161 | ||
|
|
5c982c90f3 | ||
|
|
381304aa6f | ||
|
|
ce9523fb90 | ||
|
|
06420b0ddf | ||
|
|
c2e1c53356 | ||
|
|
eaeb831107 | ||
|
|
459695e9d7 | ||
|
|
ece1f71c64 | ||
|
|
776d8f9f79 | ||
|
|
61ee63f358 | ||
|
|
6f65ba9214 | ||
|
|
ba837c2641 | ||
|
|
1518032606 | ||
|
|
6469cce2bc | ||
|
|
4c40b50fb5 | ||
|
|
a0f0911a95 | ||
|
|
f658819862 | ||
|
|
8d5a9143bb | ||
|
|
8f8951b4c1 | ||
|
|
6e5bcc69bc | ||
|
|
8d04d3d8fd | ||
|
|
f37fc775e5 | ||
|
|
ead99cf647 | ||
|
|
3982b5030e | ||
|
|
d9fe4b6944 | ||
|
|
387cab27bd | ||
|
|
6dcc44ce2d | ||
|
|
3b4088c23f | ||
|
|
5a85c1667a | ||
|
|
16d2ec3a90 | ||
|
|
4d60567bc6 | ||
|
|
73a1c9d249 | ||
|
|
d851882278 | ||
|
|
3ccecc568d | ||
|
|
cee200e509 | ||
|
|
f1b315e04f | ||
|
|
94bcd9735a | ||
|
|
f662445766 | ||
|
|
008be18f41 | ||
|
|
13812aa1c9 | ||
|
|
2089f19670 | ||
|
|
593741919f | ||
|
|
9d0fcca8a9 | ||
|
|
857eb01bfa | ||
|
|
a100f174f9 | ||
|
|
5dfe4e1eb9 | ||
|
|
b9586bad18 | ||
|
|
f1c2f789b6 | ||
|
|
123719bf92 | ||
|
|
14810d7e80 | ||
|
|
52156d2c41 | ||
|
|
2a6a9eb52f | ||
|
|
bf85c61b48 | ||
|
|
dba488f30a | ||
|
|
d618affd63 | ||
|
|
121c747cc8 | ||
|
|
91b9634198 | ||
|
|
7d17002b33 | ||
|
|
477b3941a6 | ||
|
|
36dd7e7609 | ||
|
|
167a65d826 | ||
|
|
c9cd8cea66 | ||
|
|
dfdcbece53 | ||
|
|
5b62f15c6d | ||
|
|
09e32d1b84 | ||
|
|
68fc6abf74 | ||
|
|
ff56c0fb74 | ||
|
|
36de6118c1 | ||
|
|
7083a33ecd | ||
|
|
7b7f57e01c | ||
|
|
8d0ef49e8f | ||
|
|
7a81bfc4a4 | ||
|
|
0d13834293 | ||
|
|
ac53806e04 | ||
|
|
026b9c336c | ||
|
|
60c77fff06 | ||
|
|
588ecbe868 | ||
|
|
e05c635489 | ||
|
|
f5cc355044 | ||
|
|
78f4c25a14 | ||
|
|
002dc0dfaf | ||
|
|
68d6788413 | ||
|
|
c7c551369f | ||
|
|
0c2919b534 | ||
|
|
d8c75fc608 | ||
|
|
a42cb4fecf | ||
|
|
68ba3d5106 | ||
|
|
80dc1dfcc1 | ||
|
|
931811ab59 | ||
|
|
9d75c3b0ca | ||
|
|
6ab8567d51 | ||
|
|
c727ed3592 | ||
|
|
c72ca983ba | ||
|
|
ec7990796a | ||
|
|
268834e4ae | ||
|
|
b80c488d36 | ||
|
|
f25cb33367 | ||
|
|
4b5f3bec4b | ||
|
|
1f4c6443ef | ||
|
|
0adea120cd | ||
|
|
71bb7acb8e | ||
|
|
4b5109c1b9 | ||
|
|
085817d332 | ||
|
|
f8bd8b97be | ||
|
|
f3da473285 | ||
|
|
f0f4ab7abe | ||
|
|
d8225642fa | ||
|
|
8ebba6d27a | ||
|
|
1051a52755 | ||
|
|
5583b050a0 | ||
|
|
a38082016d | ||
|
|
156e9b7556 | ||
|
|
5e6acf7dbc | ||
|
|
58811b5c44 | ||
|
|
86a762b2b7 | ||
|
|
f886212b44 | ||
|
|
2c272f99a3 | ||
|
|
a9982beacf | ||
|
|
e9d2ec7c41 | ||
|
|
78982ebb51 | ||
|
|
6a63c27542 | ||
|
|
62f77f6bc5 | ||
|
|
88a10fb31c | ||
|
|
e12527b895 | ||
|
|
114c8c5b6d | ||
|
|
d50f4e23e0 | ||
|
|
dca0fc91ea | ||
|
|
981c53682f | ||
|
|
143b7cccf4 | ||
|
|
8ce042bf04 | ||
|
|
85a1e1118f | ||
|
|
51baeb3c2c | ||
|
|
959a20888c | ||
|
|
7bf0ec2fe7 | ||
|
|
c6231a16e3 | ||
|
|
a619aacfc6 | ||
|
|
d469db84ee | ||
|
|
4655a6bfef | ||
|
|
61325c0a14 | ||
|
|
7faa5fe233 | ||
|
|
19090bdd5b | ||
|
|
4a6254fac3 | ||
|
|
649d26e093 | ||
|
|
2ee42997e4 | ||
|
|
17a3e25036 | ||
|
|
c4b8d3ea8b | ||
|
|
118fd21cb8 | ||
|
|
969485c754 | ||
|
|
519e81d0fa | ||
|
|
12ca45a264 | ||
|
|
3ac60b31a2 | ||
|
|
c105ff1c51 | ||
|
|
ae9bc93ccc | ||
|
|
afc665d7c8 | ||
|
|
2d173f51b1 | ||
|
|
b32ba3727b | ||
|
|
5793271308 | ||
|
|
09140a51d5 | ||
|
|
cf662b842b | ||
|
|
0ac518040b | ||
|
|
067fac05a8 | ||
|
|
c7d0358c41 | ||
|
|
c957e4ba86 | ||
|
|
c8dca0a56c | ||
|
|
da3569c490 | ||
|
|
e8356afa26 | ||
|
|
c1bd628ce5 | ||
|
|
849096d5f3 | ||
|
|
e681369a1a | ||
|
|
faa29c8062 | ||
|
|
44f2a2a952 | ||
|
|
292453d306 | ||
|
|
1ae78d08e9 | ||
|
|
1c3cbe9456 | ||
|
|
88f4c38dca | ||
|
|
b7b368a1ed | ||
|
|
d2fafbdd9e | ||
|
|
d981973096 | ||
|
|
b310501970 | ||
|
|
e92ce565dd | ||
|
|
da4f2c5ea0 | ||
|
|
bd48c3a083 | ||
|
|
ba58e0446d | ||
|
|
c03b4921c3 | ||
|
|
c60e4aceed | ||
|
|
156de2e4c2 | ||
|
|
959509496a | ||
|
|
8419e152bb | ||
|
|
1bc3e0a678 | ||
|
|
d093200966 | ||
|
|
72dc21fb1a | ||
|
|
24b8f4ebc1 | ||
|
|
136dccbcdf | ||
|
|
d0e6a0928b | ||
|
|
46846d4297 | ||
|
|
01ee9e16c5 | ||
|
|
38411fd2e7 | ||
|
|
b8094de129 | ||
|
|
73207a12ba | ||
|
|
3af87e1c42 | ||
|
|
d2547ce6b0 | ||
|
|
7e3d7e071f | ||
|
|
d4bed025ed | ||
|
|
a82e949c00 | ||
|
|
ca9756413f | ||
|
|
b9940f0e0d | ||
|
|
f91a49c65d | ||
|
|
4b8ad3fc03 | ||
|
|
e8aabbb40b | ||
|
|
02a5fa2c79 | ||
|
|
944c121a00 | ||
|
|
c9b6662138 | ||
|
|
b85755c0ff | ||
|
|
b6f24e78ac | ||
|
|
fc24aa041b | ||
|
|
c9b44b5bb6 | ||
|
|
2255176228 | ||
|
|
ccaa25eaa5 | ||
|
|
969ee4c8f9 | ||
|
|
c35278e217 | ||
|
|
039d3f0523 | ||
|
|
d56f8407a5 | ||
|
|
142b92b883 | ||
|
|
c292006421 | ||
|
|
5c4cc0d646 | ||
|
|
a361b92184 | ||
|
|
37572bc217 | ||
|
|
233adfe660 | ||
|
|
450c14b286 | ||
|
|
33dfc386c9 | ||
|
|
f331936969 | ||
|
|
8f1d0c2a7c | ||
|
|
02549c9299 | ||
|
|
98f2adbcb5 | ||
|
|
c9d21574d8 | ||
|
|
253517096e | ||
|
|
0fa35254c6 | ||
|
|
fc9fb7473c | ||
|
|
31ca2331d2 | ||
|
|
b5062a07d1 | ||
|
|
4112007314 | ||
|
|
a3162b17d9 | ||
|
|
e177d4f70d | ||
|
|
631b0e6c37 | ||
|
|
a7f339ad1c | ||
|
|
c1c0b2dd38 | ||
|
|
d7a1111955 | ||
|
|
d73340474b | ||
|
|
4f7237de44 | ||
|
|
4096745a58 | ||
|
|
a97e074022 | ||
|
|
917c6aa94a | ||
|
|
05bd6fda7e | ||
|
|
7c78de989d | ||
|
|
35a6d9ba87 | ||
|
|
c63754fc32 | ||
|
|
ccb93068fe | ||
|
|
a6fe355801 | ||
|
|
fe11c3e348 | ||
|
|
56d4422d31 | ||
|
|
e507848a8f | ||
|
|
70599667cb | ||
|
|
1878da228d | ||
|
|
37865d69a2 | ||
|
|
83eba902a3 | ||
|
|
ec805aee2e | ||
|
|
167b18b58f | ||
|
|
4b1a530330 | ||
|
|
19ffaa9ff0 | ||
|
|
0f5167a407 | ||
|
|
563ab5caa5 | ||
|
|
db5b5f121c | ||
|
|
1f417a8441 | ||
|
|
b74b09ea7a | ||
|
|
2cce67ad84 | ||
|
|
2cb935c300 | ||
|
|
b9623c1128 | ||
|
|
7a386cff7d | ||
|
|
839725e3c5 | ||
|
|
8920479f85 | ||
|
|
4c25eae9b4 | ||
|
|
a3a45b5037 | ||
|
|
dc645d76b4 | ||
|
|
daff83ee9a | ||
|
|
9f9e3e61d6 | ||
|
|
1592395036 | ||
|
|
8491b1f86a | ||
|
|
a7b4d70cc6 | ||
|
|
fa193e9618 | ||
|
|
050008f3c8 | ||
|
|
70e53cb080 | ||
|
|
7b03b04c78 | ||
|
|
7a7b98cc31 | ||
|
|
15d5837322 | ||
|
|
f9ebb8b23e | ||
|
|
77b94451de | ||
|
|
ca6245e974 | ||
|
|
1cdddeec30 | ||
|
|
657c908f88 | ||
|
|
d7a0e22d59 | ||
|
|
33b809714f | ||
|
|
b915a2ad7d | ||
|
|
85ed5cef7f | ||
|
|
df42b0d1ac | ||
|
|
98add22891 | ||
|
|
1d81bf5596 | ||
|
|
e4153a536f | ||
|
|
79f31238b0 | ||
|
|
8c712d959d | ||
|
|
c4b1a79db2 | ||
|
|
47f12f107d | ||
|
|
bfad970e4d | ||
|
|
49bdc6fbd1 | ||
|
|
57f279677f | ||
|
|
fff73c7735 | ||
|
|
e44678ceba | ||
|
|
85c0e9c574 | ||
|
|
0c3ec7f9a5 | ||
|
|
74e15b2eb5 | ||
|
|
565861f680 | ||
|
|
7c991399ac | ||
|
|
384c853a39 | ||
|
|
c0380d0280 | ||
|
|
a1c61563a0 | ||
|
|
aa0f1aaeb2 | ||
|
|
03ddd64b93 | ||
|
|
7fc9ba7d3a | ||
|
|
63b6bab5c3 | ||
|
|
eb4eeb6f73 | ||
|
|
6988507998 | ||
|
|
65be6d5146 | ||
|
|
6d05dd07f5 | ||
|
|
7436ec093a | ||
|
|
2b735daae5 | ||
|
|
f8b0c884b0 | ||
|
|
18f4d343f5 | ||
|
|
31e78c90e2 | ||
|
|
3238256b79 | ||
|
|
59b71d5d05 | ||
|
|
4dfa6c6ee4 | ||
|
|
60e488eb17 | ||
|
|
14340ac4df | ||
|
|
efbfc2b1ab | ||
|
|
d4f09bc20d | ||
|
|
d67f962a38 | ||
|
|
6de85d02ae | ||
|
|
f28eb902df | ||
|
|
9702d522a4 | ||
|
|
4f710b0470 | ||
|
|
5f29787dc7 | ||
|
|
1fbb36fa87 | ||
|
|
3cafcc2bc7 | ||
|
|
8d92c898ee | ||
|
|
9bf73cd72d | ||
|
|
f97cf5c3b6 | ||
|
|
5ff2d5aee6 | ||
|
|
1f474742eb | ||
|
|
0041a0079d | ||
|
|
9bb8b0c622 | ||
|
|
df6d3107f2 | ||
|
|
cbdc54843d | ||
|
|
d2027cb4a9 | ||
|
|
e60779bfe1 | ||
|
|
f66b1ac450 | ||
|
|
ff6a96665a | ||
|
|
4388a294a4 | ||
|
|
d21b9280f0 | ||
|
|
92649332ce | ||
|
|
be91c1229f | ||
|
|
168cb95bd5 | ||
|
|
1d796a4e24 | ||
|
|
8e6d5efdac | ||
|
|
0f2478b62f | ||
|
|
e5d7e593ec | ||
|
|
69b927bfe9 | ||
|
|
944d176856 | ||
|
|
cdd5a772e8 | ||
|
|
0a3c23bcf6 | ||
|
|
cb286ede9d | ||
|
|
16e3dbb18c | ||
|
|
a38437f378 | ||
|
|
8d6ecd9af8 | ||
|
|
342a7096ea | ||
|
|
60a4bda9d4 | ||
|
|
d5fc594317 | ||
|
|
64407dc5d2 | ||
|
|
b0329465ec | ||
|
|
0f70b420f2 | ||
|
|
21c4dea0e6 | ||
|
|
bcaf818c0e | ||
|
|
37bac916e7 | ||
|
|
affdbbf9ca | ||
|
|
4fcf0ff2ac | ||
|
|
c19af4fb2b | ||
|
|
f53897758d | ||
|
|
54002c4391 | ||
|
|
6a53eaefc0 | ||
|
|
4bc114336c | ||
|
|
47f1d377f5 | ||
|
|
566699f68a | ||
|
|
29ba92a551 | ||
|
|
38e9484f9f | ||
|
|
fec12030a9 | ||
|
|
bdfdf7ef55 | ||
|
|
9f65ae72c3 | ||
|
|
3434ea540c | ||
|
|
29131c873a | ||
|
|
ab1eb70d1c | ||
|
|
71256f9456 | ||
|
|
6179839215 | ||
|
|
0ca96e543c | ||
|
|
acb0b8f599 | ||
|
|
20d0936fa2 | ||
|
|
c24b7a7ef9 | ||
|
|
074495a13a | ||
|
|
e14d86d8b8 | ||
|
|
528c29c01c | ||
|
|
1bb7a22115 | ||
|
|
19ed67331d | ||
|
|
667b72870f | ||
|
|
4194ebf9df | ||
|
|
5beceaae5c | ||
|
|
9c1bf1387c | ||
|
|
fc6a31eac8 | ||
|
|
064e8bdd84 | ||
|
|
262ccbcf30 | ||
|
|
7567885115 | ||
|
|
ed715ec437 | ||
|
|
9a44a20a9d | ||
|
|
f335045273 | ||
|
|
4ea091339e | ||
|
|
8378b7345b | ||
|
|
4a71c7a2bd | ||
|
|
b2885a53cb | ||
|
|
46b6b4037d | ||
|
|
93d3a6e1d1 | ||
|
|
eebaeeff96 | ||
|
|
3a7a77d49e | ||
|
|
c87c090264 | ||
|
|
b26922978a | ||
|
|
5a5bd2596a | ||
|
|
38ca051381 | ||
|
|
91056809dd | ||
|
|
f75430e95f | ||
|
|
8e797e6830 | ||
|
|
73c4be3fd3 | ||
|
|
c552ba06b4 | ||
|
|
6bd5f4e44e | ||
|
|
6138d18f4b | ||
|
|
d028f42e99 | ||
|
|
860fc3e91d | ||
|
|
2e03d84755 | ||
|
|
f2b406fc5e | ||
|
|
f46bc0ef04 | ||
|
|
800d53db6a | ||
|
|
a9444d3399 | ||
|
|
4a16053c00 | ||
|
|
d0c61f0f76 | ||
|
|
451ffd567d | ||
|
|
f3a49604f1 | ||
|
|
3576dd6e87 | ||
|
|
3b668c9baf | ||
|
|
618fe0e6fb | ||
|
|
872b08601a | ||
|
|
fe95ea221b | ||
|
|
4e8674d5df | ||
|
|
9894348e12 | ||
|
|
189ac86b06 | ||
|
|
6f3bbafbbd | ||
|
|
3a478adeaa | ||
|
|
29aa6ef6c7 | ||
|
|
219796ef4e | ||
|
|
4f087c331c | ||
|
|
18456f71f8 | ||
|
|
1d841eeb87 | ||
|
|
19d1f83d97 | ||
|
|
6efadf44d0 | ||
|
|
e4c4a4628b | ||
|
|
a217c0f394 | ||
|
|
1dbd11446c | ||
|
|
74fa8a3907 | ||
|
|
cad1e0b985 | ||
|
|
b099851a8b | ||
|
|
f25ead109c | ||
|
|
edd7dfe1c8 | ||
|
|
89f5452ddb | ||
|
|
a6de1db94d | ||
|
|
ed9d7e4fae | ||
|
|
e169f70bfb | ||
|
|
35428f2e04 | ||
|
|
0718a1bd1f | ||
|
|
83f7d702e7 | ||
|
|
12d4888321 | ||
|
|
4565a73e91 | ||
|
|
9c932ad514 | ||
|
|
5458f3cbd2 | ||
|
|
611e1d239b | ||
|
|
d2abbd8f5d | ||
|
|
00b40b720f | ||
|
|
71b4923208 | ||
|
|
c49d3fdb17 | ||
|
|
fcaf359e89 | ||
|
|
9a31c068c4 | ||
|
|
babc9e7a1e | ||
|
|
d2ecc9d80c | ||
|
|
fbd7cc243b | ||
|
|
a6055ce069 | ||
|
|
35719e665c | ||
|
|
bc80ed4e88 | ||
|
|
5ebe8ce025 | ||
|
|
17dcb42752 | ||
|
|
2f97b2d7c2 | ||
|
|
57244de37d | ||
|
|
3806ed882a | ||
|
|
ce7e7c4048 | ||
|
|
524e0290bc | ||
|
|
dbdf1e137e | ||
|
|
6ebb1a68cb | ||
|
|
7e7e607e3f | ||
|
|
4eb21a71ae | ||
|
|
4f07ee4d92 | ||
|
|
b14db404b5 | ||
|
|
7cb71df02c | ||
|
|
55fc11ff02 | ||
|
|
0d43d269ed | ||
|
|
a0829c63de | ||
|
|
535c7b99b4 | ||
|
|
5d805ba550 | ||
|
|
bafe796eeb | ||
|
|
ceb60ffcc6 | ||
|
|
72c4f353e6 | ||
|
|
4d6830a373 | ||
|
|
f547cab710 | ||
|
|
7835f50722 | ||
|
|
d161d66741 | ||
|
|
9755182adf | ||
|
|
a5637bb9d4 | ||
|
|
1e1364c3d4 | ||
|
|
7cf914537b | ||
|
|
ab1972d1cf | ||
|
|
e0aa067cc9 | ||
|
|
4f30dce64f | ||
|
|
2b5b899d35 | ||
|
|
781cf608d7 | ||
|
|
9e1059afb4 | ||
|
|
7ef8c0442a | ||
|
|
6ab269ceb7 | ||
|
|
fd7cb99f47 | ||
|
|
5a1ec817d4 | ||
|
|
9ad8153d33 | ||
|
|
941427554a | ||
|
|
7554c7f694 | ||
|
|
79da35d023 | ||
|
|
1dee1ba64e | ||
|
|
afecf7ce36 | ||
|
|
5e6127869a | ||
|
|
3b5b895a10 | ||
|
|
345fc41482 | ||
|
|
93dd310add | ||
|
|
a201385008 | ||
|
|
9d7aa1e155 | ||
|
|
6285cc6f66 | ||
|
|
8e165fecc0 | ||
|
|
7c8addc5c5 | ||
|
|
5419c456ac | ||
|
|
2b7ab290b8 | ||
|
|
508a934d62 | ||
|
|
8025921fc8 | ||
|
|
ff6fef927a | ||
|
|
77d486f8d2 | ||
|
|
233a90ce8b | ||
|
|
41ef0bd98c | ||
|
|
f58d93c0bf | ||
|
|
8f331f08d2 | ||
|
|
f0cefebff7 | ||
|
|
2904a0bbac | ||
|
|
6a96e83ea9 | ||
|
|
306db9a851 | ||
|
|
93bd19a8c2 | ||
|
|
98ce7dc465 | ||
|
|
9edf60ffc6 | ||
|
|
884cee27eb | ||
|
|
0f87493487 | ||
|
|
8be8cb7a91 | ||
|
|
977aabe038 | ||
|
|
da7d8dbcac | ||
|
|
3809e4c055 | ||
|
|
7f8a94ff48 | ||
|
|
ee56b14faa | ||
|
|
ab54fcd443 | ||
|
|
9fa0a62c8a | ||
|
|
9faa0fbd25 | ||
|
|
3167e8ddbe | ||
|
|
b53da365a1 | ||
|
|
275b386856 | ||
|
|
e9505697fb | ||
|
|
47f303317b | ||
|
|
0685802cb8 | ||
|
|
c8ff439722 | ||
|
|
a7b81dc05c | ||
|
|
0824d32319 | ||
|
|
9ff5600421 | ||
|
|
94272ed072 | ||
|
|
7b2f6f89f0 | ||
|
|
06dbc40f53 | ||
|
|
1bbcb51066 | ||
|
|
33a48d926c | ||
|
|
c5f50e73c2 | ||
|
|
7276c7085a | ||
|
|
e52113a319 | ||
|
|
11ecac626d | ||
|
|
5a24ab06d8 | ||
|
|
654546e338 | ||
|
|
170389ef14 | ||
|
|
a17229a4c1 | ||
|
|
92f81d51f4 | ||
|
|
e9c03f2e4a | ||
|
|
dc37a07a8e | ||
|
|
c847606311 | ||
|
|
589017a3d6 | ||
|
|
d3c27c514f | ||
|
|
777a0b817b | ||
|
|
4988ba9a71 | ||
|
|
3fa7da804d | ||
|
|
af99ab1645 | ||
|
|
4a527a46ce | ||
|
|
5829aa8bd7 | ||
|
|
9bb1ae079f | ||
|
|
e0a9a1b800 | ||
|
|
861f5a5387 | ||
|
|
20ae4e5d98 | ||
|
|
b3e8b430e5 | ||
|
|
ae8d57e650 | ||
|
|
b0b2e9c4aa | ||
|
|
409904c61c | ||
|
|
afb1839b6b | ||
|
|
cc62a3dbf3 | ||
|
|
31c04261c1 | ||
|
|
6220cdda92 | ||
|
|
da305e6b61 | ||
|
|
343de9c454 | ||
|
|
e59951c8ae | ||
|
|
ea5f825a91 | ||
|
|
b3e4ff7ef0 | ||
|
|
b0524947e5 | ||
|
|
fa85094cbb | ||
|
|
9dd101c26f | ||
|
|
4fcf5a31f5 | ||
|
|
c20f993747 | ||
|
|
71947d6bea | ||
|
|
220a1e4197 | ||
|
|
4dd3478fc1 | ||
|
|
8e1c0941b0 | ||
|
|
62f96f0911 | ||
|
|
73f3b0636a | ||
|
|
9f8817a47e | ||
|
|
9971f999b3 | ||
|
|
ff789058df | ||
|
|
bd07cd1193 | ||
|
|
a6de2184ba | ||
|
|
bb3b881e21 | ||
|
|
e4859d2e9a | ||
|
|
91e7807af6 | ||
|
|
38f1d78e1b | ||
|
|
b52b65624b | ||
|
|
2a17d9457a | ||
|
|
7531d0c678 | ||
|
|
3eafc83458 | ||
|
|
4326a3adce | ||
|
|
ed103822f5 | ||
|
|
d68cb264c4 | ||
|
|
45ba03efa3 |
13
.travis.yml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# This is a travis-ci.org continuous integration configuration file.
|
||||||
|
language: c
|
||||||
|
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- gcc-avr
|
||||||
|
- avr-libc
|
||||||
|
- wget
|
||||||
|
|
||||||
|
install: ./scripts/travis-install.sh
|
||||||
|
|
||||||
|
script: ./scripts/travis-build.sh
|
||||||
45
Makefile
@@ -1,6 +1,6 @@
|
|||||||
# Klipper build system
|
# Klipper build system
|
||||||
#
|
#
|
||||||
# Copyright (C) 2016 Kevin O'Connor <kevin@koconnor.net>
|
# Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||||
#
|
#
|
||||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
|
||||||
@@ -22,27 +22,24 @@ OBJCOPY=$(CROSS_PREFIX)objcopy
|
|||||||
OBJDUMP=$(CROSS_PREFIX)objdump
|
OBJDUMP=$(CROSS_PREFIX)objdump
|
||||||
STRIP=$(CROSS_PREFIX)strip
|
STRIP=$(CROSS_PREFIX)strip
|
||||||
CPP=cpp
|
CPP=cpp
|
||||||
PYTHON=python
|
PYTHON=python2
|
||||||
|
|
||||||
# Source files
|
# Source files
|
||||||
src-y=sched.c command.c stepper.c basecmd.c gpiocmds.c spicmds.c endstop.c
|
src-y =
|
||||||
DIRS=src src/avr src/simulator
|
dirs-y = src
|
||||||
|
|
||||||
# Default compiler flags
|
# Default compiler flags
|
||||||
cc-option=$(shell if test -z "`$(1) $(2) -S -o /dev/null -xc /dev/null 2>&1`" \
|
cc-option=$(shell if test -z "`$(1) $(2) -S -o /dev/null -xc /dev/null 2>&1`" \
|
||||||
; then echo "$(2)"; else echo "$(3)"; fi ;)
|
; then echo "$(2)"; else echo "$(3)"; fi ;)
|
||||||
|
|
||||||
CFLAGS-y := -I$(OUT) -Isrc -Os -MD -g \
|
CFLAGS := -I$(OUT) -Isrc -I$(OUT)board-generic/ -O2 -MD -g \
|
||||||
-Wall -Wold-style-definition $(call cc-option,$(CC),-Wtype-limits,) \
|
-Wall -Wold-style-definition $(call cc-option,$(CC),-Wtype-limits,) \
|
||||||
-ffunction-sections -fdata-sections
|
-ffunction-sections -fdata-sections
|
||||||
CFLAGS-y += -flto -fwhole-program
|
CFLAGS += -flto -fwhole-program -fno-use-linker-plugin
|
||||||
|
|
||||||
LDFLAGS-y := -Wl,--gc-sections
|
CFLAGS_klipper.elf = $(CFLAGS) -Wl,--gc-sections
|
||||||
|
|
||||||
CPPFLAGS = -P -MD -MT $@
|
CPPFLAGS = -I$(OUT) -P -MD -MT $@
|
||||||
|
|
||||||
CFLAGS = $(CFLAGS-y)
|
|
||||||
LDFLAGS = $(LDFLAGS-y)
|
|
||||||
|
|
||||||
# Default targets
|
# Default targets
|
||||||
target-y := $(OUT)klipper.elf
|
target-y := $(OUT)klipper.elf
|
||||||
@@ -58,6 +55,7 @@ MAKEFLAGS += --no-print-directory
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
# Include board specific makefile
|
# Include board specific makefile
|
||||||
|
include src/Makefile
|
||||||
-include src/$(patsubst "%",%,$(CONFIG_BOARD_DIRECTORY))/Makefile
|
-include src/$(patsubst "%",%,$(CONFIG_BOARD_DIRECTORY))/Makefile
|
||||||
|
|
||||||
################ Common build rules
|
################ Common build rules
|
||||||
@@ -70,33 +68,30 @@ $(OUT)%.o: %.c $(OUT)autoconf.h $(OUT)board-link
|
|||||||
|
|
||||||
$(OUT)board-link: $(KCONFIG_CONFIG)
|
$(OUT)board-link: $(KCONFIG_CONFIG)
|
||||||
@echo " Creating symbolic link $(OUT)board"
|
@echo " Creating symbolic link $(OUT)board"
|
||||||
|
$(Q)mkdir -p $(addprefix $(OUT), $(dirs-y))
|
||||||
$(Q)touch $@
|
$(Q)touch $@
|
||||||
$(Q)ln -Tsf $(PWD)/src/$(CONFIG_BOARD_DIRECTORY) $(OUT)board
|
$(Q)ln -Tsf $(PWD)/src/$(CONFIG_BOARD_DIRECTORY) $(OUT)board
|
||||||
|
$(Q)mkdir -p $(OUT)board-generic
|
||||||
|
$(Q)ln -Tsf $(PWD)/src/generic $(OUT)board-generic/board
|
||||||
|
|
||||||
$(OUT)declfunc.lds: src/declfunc.lds.S
|
$(OUT)%.o.ctr: $(OUT)%.o
|
||||||
@echo " Precompiling $@"
|
$(Q)$(OBJCOPY) -j '.compile_time_request' -O binary $^ $@
|
||||||
$(Q)$(CPP) $(CPPFLAGS) -D__ASSEMBLY__ $< -o $@
|
|
||||||
|
|
||||||
$(OUT)klipper.o: $(patsubst %.c, $(OUT)src/%.o,$(src-y)) $(OUT)declfunc.lds
|
$(OUT)compile_time_request.o: $(patsubst %.c, $(OUT)src/%.o.ctr,$(src-y)) ./scripts/buildcommands.py
|
||||||
@echo " Linking $@"
|
|
||||||
$(Q)$(CC) $(CFLAGS) -Wl,-r -Wl,-T,$(OUT)declfunc.lds -nostdlib $(patsubst %.c, $(OUT)src/%.o,$(src-y)) -o $@
|
|
||||||
|
|
||||||
$(OUT)compile_time_request.o: $(OUT)klipper.o ./scripts/buildcommands.py
|
|
||||||
@echo " Building $@"
|
@echo " Building $@"
|
||||||
$(Q)$(OBJCOPY) -j '.compile_time_request' -O binary $< $(OUT)klipper.o.compile_time_request
|
$(Q)cat $(patsubst %.c, $(OUT)src/%.o.ctr,$(src-y)) > $(OUT)klipper.compile_time_request
|
||||||
$(Q)$(PYTHON) ./scripts/buildcommands.py $(OUT)klipper.o.compile_time_request $(OUT)autoconf.h $(OUT)compile_time_request.c
|
$(Q)$(PYTHON) ./scripts/buildcommands.py -d $(OUT)klipper.dict -t "$(CC);$(AS);$(LD);$(OBJCOPY);$(OBJDUMP);$(STRIP)" $(OUT)klipper.compile_time_request $(OUT)compile_time_request.c
|
||||||
$(Q)$(CC) $(CFLAGS) -c $(OUT)compile_time_request.c -o $@
|
$(Q)$(CC) $(CFLAGS) -c $(OUT)compile_time_request.c -o $@
|
||||||
|
|
||||||
$(OUT)klipper.elf: $(OUT)klipper.o $(OUT)compile_time_request.o
|
$(OUT)klipper.elf: $(patsubst %.c, $(OUT)src/%.o,$(src-y)) $(OUT)compile_time_request.o
|
||||||
@echo " Linking $@"
|
@echo " Linking $@"
|
||||||
$(Q)$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@
|
$(Q)$(CC) $^ $(CFLAGS_klipper.elf) -o $@
|
||||||
|
|
||||||
################ Kconfig rules
|
################ Kconfig rules
|
||||||
|
|
||||||
define do-kconfig
|
define do-kconfig
|
||||||
$(Q)mkdir -p $(OUT)/scripts/kconfig/lxdialog
|
$(Q)mkdir -p $(OUT)/scripts/kconfig/lxdialog
|
||||||
$(Q)mkdir -p $(OUT)/include/config
|
$(Q)mkdir -p $(OUT)/include/config
|
||||||
$(Q)mkdir -p $(addprefix $(OUT), $(DIRS))
|
|
||||||
$(Q)$(MAKE) -C $(OUT) -f $(CURDIR)/scripts/kconfig/Makefile srctree=$(CURDIR) src=scripts/kconfig obj=scripts/kconfig Q=$(Q) Kconfig=$(CURDIR)/src/Kconfig $1
|
$(Q)$(MAKE) -C $(OUT) -f $(CURDIR)/scripts/kconfig/Makefile srctree=$(CURDIR) src=scripts/kconfig obj=scripts/kconfig Q=$(Q) Kconfig=$(CURDIR)/src/Kconfig $1
|
||||||
endef
|
endef
|
||||||
|
|
||||||
@@ -120,4 +115,4 @@ clean:
|
|||||||
distclean: clean
|
distclean: clean
|
||||||
$(Q)rm -f .config .config.old
|
$(Q)rm -f .config .config.old
|
||||||
|
|
||||||
-include $(patsubst %,$(OUT)%/*.d,$(DIRS))
|
-include $(OUT)*.d $(patsubst %,$(OUT)%/*.d,$(dirs-y))
|
||||||
|
|||||||
@@ -6,8 +6,11 @@ runs on a host machine. The host software does the work to build a
|
|||||||
schedule of events, while the micro-controller software does the work
|
schedule of events, while the micro-controller software does the work
|
||||||
to execute the provided schedule at the specified times.
|
to execute the provided schedule at the specified times.
|
||||||
|
|
||||||
Please see the [documentation](docs/Overview.md) for more information
|
See the [features](docs/Features.md) document to find out why you
|
||||||
on running and working with Klipper.
|
should use Klipper. To begin using Klipper start by
|
||||||
|
[installing](docs/Installation.md) it.
|
||||||
|
|
||||||
|
There is also [developer documentation](docs/Overview.md) available.
|
||||||
|
|
||||||
License
|
License
|
||||||
=======
|
=======
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Support for internal testing with the "simulavr" program. To use
|
# Support for internal testing with the "simulavr" program. To use
|
||||||
# this config, compile the firmware for an AVR atmega644p, disable the
|
# this config, compile the firmware for an AVR atmega644p, disable the
|
||||||
# AVR watchdog timer, set the MCU frequency to 20000000, and set the
|
# AVR watchdog timer, set the MCU frequency to 20000000, and set the
|
||||||
# serial baud rate to 115200.
|
# serial baud rate to 250000.
|
||||||
|
|
||||||
[stepper_x]
|
[stepper_x]
|
||||||
# Pins: PA5, PA4, PA1
|
# Pins: PA5, PA4, PA1
|
||||||
@@ -9,9 +9,7 @@ step_pin: ar29
|
|||||||
dir_pin: ar28
|
dir_pin: ar28
|
||||||
enable_pin: ar25
|
enable_pin: ar25
|
||||||
step_distance: .0225
|
step_distance: .0225
|
||||||
max_velocity: 500
|
endstop_pin: ^ar0
|
||||||
max_accel: 3000
|
|
||||||
endstop_pin: ^!ar0
|
|
||||||
position_min: -0.25
|
position_min: -0.25
|
||||||
position_endstop: 0
|
position_endstop: 0
|
||||||
position_max: 200
|
position_max: 200
|
||||||
@@ -22,9 +20,7 @@ step_pin: ar27
|
|||||||
dir_pin: ar26
|
dir_pin: ar26
|
||||||
enable_pin: ar25
|
enable_pin: ar25
|
||||||
step_distance: .0225
|
step_distance: .0225
|
||||||
max_velocity: 500
|
endstop_pin: ^ar1
|
||||||
max_accel: 3000
|
|
||||||
endstop_pin: ^!ar1
|
|
||||||
position_min: -0.25
|
position_min: -0.25
|
||||||
position_endstop: 0
|
position_endstop: 0
|
||||||
position_max: 200
|
position_max: 200
|
||||||
@@ -35,49 +31,48 @@ step_pin: ar23
|
|||||||
dir_pin: ar22
|
dir_pin: ar22
|
||||||
enable_pin: ar25
|
enable_pin: ar25
|
||||||
step_distance: .005
|
step_distance: .005
|
||||||
max_velocity: 250
|
endstop_pin: ^ar2
|
||||||
max_accel: 30
|
|
||||||
endstop_pin: ^!ar2
|
|
||||||
position_min: 0.1
|
position_min: 0.1
|
||||||
position_endstop: 0.5
|
position_endstop: 0.5
|
||||||
position_max: 200
|
position_max: 200
|
||||||
|
|
||||||
[stepper_e]
|
[extruder]
|
||||||
# Pins: PC3, PC2
|
# Pins: PC3, PC2
|
||||||
step_pin: ar19
|
step_pin: ar19
|
||||||
dir_pin: ar18
|
dir_pin: ar18
|
||||||
enable_pin: ar25
|
enable_pin: ar25
|
||||||
step_distance: .004242
|
step_distance: .004242
|
||||||
max_velocity: 200000
|
nozzle_diameter: 0.500
|
||||||
max_accel: 3000
|
filament_diameter: 3.500
|
||||||
|
|
||||||
[heater_nozzle]
|
|
||||||
heater_pin: ar4
|
heater_pin: ar4
|
||||||
thermistor_pin: analog1
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
thermistor_type: EPCOS 100K B57560G104F
|
sensor_pin: analog7
|
||||||
control: pid
|
control: pid
|
||||||
pid_Kp: 22.2
|
pid_Kp: 22.2
|
||||||
pid_Ki: 1.08
|
pid_Ki: 1.08
|
||||||
pid_Kd: 114
|
pid_Kd: 114
|
||||||
min_temp: 0
|
min_temp: 0
|
||||||
|
min_extrude_temp: 0
|
||||||
max_temp: 210
|
max_temp: 210
|
||||||
|
|
||||||
[heater_bed]
|
[heater_bed]
|
||||||
heater_pin: ar3
|
heater_pin: ar3
|
||||||
thermistor_pin: analog0
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
thermistor_type: EPCOS 100K B57560G104F
|
sensor_pin: analog0
|
||||||
control: watermark
|
control: watermark
|
||||||
min_temp: 0
|
min_temp: 0
|
||||||
max_temp: 110
|
max_temp: 110
|
||||||
|
|
||||||
[fan]
|
[fan]
|
||||||
pin: ar14
|
pin: ar14
|
||||||
hard_pwm: 1
|
|
||||||
|
|
||||||
[mcu]
|
[mcu]
|
||||||
serial: /tmp/pseudoserial
|
serial: /tmp/pseudoserial
|
||||||
baud: 115200
|
|
||||||
pin_map: arduino
|
pin_map: arduino
|
||||||
|
|
||||||
[printer]
|
[printer]
|
||||||
kinematics: cartesian
|
kinematics: cartesian
|
||||||
|
max_velocity: 500
|
||||||
|
max_accel: 3000
|
||||||
|
max_z_velocity: 250
|
||||||
|
max_z_accel: 30
|
||||||
|
|||||||
81
config/example-corexy.cfg
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
# This file serves as documentation for config parameters of corexy
|
||||||
|
# style printers. One may copy and edit this file to configure a new
|
||||||
|
# corexy printer. Only parameters unique to corexy printers are
|
||||||
|
# described here - see the "example.cfg" file for description of
|
||||||
|
# common config parameters.
|
||||||
|
|
||||||
|
# DO NOT COPY THIS FILE WITHOUT CAREFULLY READING AND UPDATING IT
|
||||||
|
# FIRST. Incorrectly configured parameters may cause damage.
|
||||||
|
|
||||||
|
# The stepper_x section is used to describe the X axis as well as the
|
||||||
|
# stepper controlling the X+Y movement.
|
||||||
|
[stepper_x]
|
||||||
|
step_pin: ar54
|
||||||
|
dir_pin: ar55
|
||||||
|
enable_pin: !ar38
|
||||||
|
step_distance: .01
|
||||||
|
endstop_pin: ^ar3
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 200
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
# The stepper_y section is used to describe the Y axis as well as the
|
||||||
|
# stepper controlling the X-Y movement.
|
||||||
|
[stepper_y]
|
||||||
|
step_pin: ar60
|
||||||
|
dir_pin: ar61
|
||||||
|
enable_pin: !ar56
|
||||||
|
step_distance: .01
|
||||||
|
endstop_pin: ^ar14
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 200
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_z]
|
||||||
|
step_pin: ar46
|
||||||
|
dir_pin: ar48
|
||||||
|
enable_pin: !ar62
|
||||||
|
step_distance: .0025
|
||||||
|
endstop_pin: ^ar18
|
||||||
|
position_endstop: 0.5
|
||||||
|
position_max: 200
|
||||||
|
|
||||||
|
[extruder]
|
||||||
|
step_pin: ar26
|
||||||
|
dir_pin: ar28
|
||||||
|
enable_pin: !ar24
|
||||||
|
step_distance: .0022
|
||||||
|
nozzle_diameter: 0.400
|
||||||
|
filament_diameter: 1.750
|
||||||
|
heater_pin: ar10
|
||||||
|
sensor_type: ATC Semitec 104GT-2
|
||||||
|
sensor_pin: analog13
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 22.2
|
||||||
|
pid_Ki: 1.08
|
||||||
|
pid_Kd: 114
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 250
|
||||||
|
|
||||||
|
[heater_bed]
|
||||||
|
heater_pin: ar8
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: analog14
|
||||||
|
control: watermark
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 130
|
||||||
|
|
||||||
|
[fan]
|
||||||
|
pin: ar9
|
||||||
|
|
||||||
|
[mcu]
|
||||||
|
serial: /dev/ttyACM0
|
||||||
|
pin_map: arduino
|
||||||
|
|
||||||
|
[printer]
|
||||||
|
kinematics: corexy
|
||||||
|
# This option must be "corexy" for corexy printers.
|
||||||
|
max_velocity: 300
|
||||||
|
max_accel: 3000
|
||||||
|
max_z_velocity: 25
|
||||||
|
max_z_accel: 30
|
||||||
131
config/example-delta.cfg
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
# This file serves as documentation for config parameters of delta
|
||||||
|
# style printers. One may copy and edit this file to configure a new
|
||||||
|
# delta printer. Only parameters unique to delta printers are
|
||||||
|
# described here - see the "example.cfg" file for description of
|
||||||
|
# common config parameters.
|
||||||
|
|
||||||
|
# DO NOT COPY THIS FILE WITHOUT CAREFULLY READING AND UPDATING IT
|
||||||
|
# FIRST. Incorrectly configured parameters may cause damage.
|
||||||
|
|
||||||
|
# The stepper_a section describes the stepper controlling the front
|
||||||
|
# left tower (at 210 degrees). This section also controls the homing
|
||||||
|
# parameters (homing_speed, homing_retract_dist) for all towers.
|
||||||
|
[stepper_a]
|
||||||
|
step_pin: ar54
|
||||||
|
dir_pin: ar55
|
||||||
|
enable_pin: !ar38
|
||||||
|
step_distance: .01
|
||||||
|
endstop_pin: ^ar2
|
||||||
|
homing_speed: 50
|
||||||
|
position_endstop: 297.05
|
||||||
|
# Distance (in mm) between the nozzle and the bed when the nozzle is
|
||||||
|
# in the center of the build area and the endstop triggers. This
|
||||||
|
# parameter must be provided for stepper_a; for stepper_b and
|
||||||
|
# stepper_c this parameter defaults to the value specified for
|
||||||
|
# stepper_a.
|
||||||
|
arm_length: 333.0
|
||||||
|
# Length (in mm) of the diagonal rod that connects this tower to the
|
||||||
|
# print head. This parameter must be provided for stepper_a; for
|
||||||
|
# stepper_b and stepper_c this parameter defaults to the value
|
||||||
|
# specified for stepper_a.
|
||||||
|
#angle:
|
||||||
|
# This option specifies the angle (in degrees) that the tower is
|
||||||
|
# at. The default is 210 for stepper_a, 330 for stepper_b, and 90
|
||||||
|
# for stepper_c.
|
||||||
|
|
||||||
|
# The stepper_b section describes the stepper controlling the front
|
||||||
|
# right tower (at 330 degrees).
|
||||||
|
[stepper_b]
|
||||||
|
step_pin: ar60
|
||||||
|
dir_pin: ar61
|
||||||
|
enable_pin: !ar56
|
||||||
|
step_distance: .01
|
||||||
|
endstop_pin: ^ar15
|
||||||
|
|
||||||
|
# The stepper_c section describes the stepper controlling the rear
|
||||||
|
# tower (at 90 degrees).
|
||||||
|
[stepper_c]
|
||||||
|
step_pin: ar46
|
||||||
|
dir_pin: ar48
|
||||||
|
enable_pin: !ar62
|
||||||
|
step_distance: .01
|
||||||
|
endstop_pin: ^ar19
|
||||||
|
|
||||||
|
[extruder]
|
||||||
|
step_pin: ar26
|
||||||
|
dir_pin: ar28
|
||||||
|
enable_pin: !ar24
|
||||||
|
step_distance: .0022
|
||||||
|
nozzle_diameter: 0.400
|
||||||
|
filament_diameter: 1.750
|
||||||
|
heater_pin: ar10
|
||||||
|
sensor_type: ATC Semitec 104GT-2
|
||||||
|
sensor_pin: analog13
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 22.2
|
||||||
|
pid_Ki: 1.08
|
||||||
|
pid_Kd: 114
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 250
|
||||||
|
|
||||||
|
[heater_bed]
|
||||||
|
heater_pin: ar8
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: analog14
|
||||||
|
control: watermark
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 130
|
||||||
|
|
||||||
|
# Print cooling fan (omit section if fan not present).
|
||||||
|
#[fan]
|
||||||
|
#pin: ar9
|
||||||
|
|
||||||
|
[mcu]
|
||||||
|
serial: /dev/ttyACM0
|
||||||
|
pin_map: arduino
|
||||||
|
|
||||||
|
[printer]
|
||||||
|
kinematics: delta
|
||||||
|
# This option must be "delta" for linear delta printers.
|
||||||
|
max_velocity: 300
|
||||||
|
# Maximum velocity (in mm/s) of the toolhead relative to the
|
||||||
|
# print. This parameter must be specified.
|
||||||
|
max_accel: 3000
|
||||||
|
# Maximum acceleration (in mm/s^2) of the toolhead relative to the
|
||||||
|
# print. This parameter must be specified.
|
||||||
|
max_z_velocity: 150
|
||||||
|
# For delta printers this limits the maximum velocity (in mm/s) of
|
||||||
|
# moves with z axis movement. This setting can be used to reduce the
|
||||||
|
# maximum speed of up/down moves (which require a higher step rate
|
||||||
|
# than other moves on a delta printer). The default is to use
|
||||||
|
# max_velocity for max_z_velocity.
|
||||||
|
#minimum_z_position: 0
|
||||||
|
# The minimum Z position that the user may command the head to move
|
||||||
|
# to. The default is 0.
|
||||||
|
delta_radius: 174.75
|
||||||
|
# Radius (in mm) of the horizontal circle formed by the three linear
|
||||||
|
# axis towers. This parameter may also be calculated as:
|
||||||
|
# delta_radius = smooth_rod_offset - effector_offset - carriage_offset
|
||||||
|
# This parameter must be provided.
|
||||||
|
|
||||||
|
# The delta_calibrate section enables a DELTA_CALIBRATE extended
|
||||||
|
# g-code command that can calibrate the tower endstop positions and
|
||||||
|
# angles.
|
||||||
|
[delta_calibrate]
|
||||||
|
radius: 50
|
||||||
|
# Radius (in mm) of the area that may be probed. This is typically
|
||||||
|
# the size of the printer bed. This parameter must be provided.
|
||||||
|
#speed: 50
|
||||||
|
# The speed (in mm/s) of non-probing moves during the
|
||||||
|
# calibration. The default is 50.
|
||||||
|
#horizontal_move_z: 5
|
||||||
|
# The height (in mm) that the head should be commanded to move to
|
||||||
|
# just prior to starting a probe operation. The default is 5.
|
||||||
|
#manual_probe:
|
||||||
|
# If true, then DELTA_CALIBRATE will perform manual probing. If
|
||||||
|
# false, then a PROBE command will be run at each probe
|
||||||
|
# point. Manual probing is accomplished by manually jogging the Z
|
||||||
|
# position of the print head at each probe point and then issuing a
|
||||||
|
# NEXT extended g-code command to record the position at that
|
||||||
|
# point. The default is false if a [probe] config section is present
|
||||||
|
# and true otherwise.
|
||||||
400
config/example-extras.cfg
Normal file
@@ -0,0 +1,400 @@
|
|||||||
|
# This file serves as documentation for config parameters of
|
||||||
|
# additional devices that may be configured on a printer. The snippets
|
||||||
|
# in this file may be copied into the main printer.cfg file. See the
|
||||||
|
# "example.cfg" file for description of common config parameters.
|
||||||
|
#
|
||||||
|
# Note, where an extra config section creates additional pins, the
|
||||||
|
# section defining the pins must be listed in the config file before
|
||||||
|
# any sections using those pins.
|
||||||
|
|
||||||
|
|
||||||
|
# Z height probe. One may define this section to enable Z height
|
||||||
|
# probing hardware. When this section is enabled, PROBE and
|
||||||
|
# QUERY_PROBE extended g-code commands become available. The probe
|
||||||
|
# section also creates a virtual probe:z_virtual_endstop pin. One may
|
||||||
|
# set the stepper_z endstop_pin to this virtual pin on cartesian style
|
||||||
|
# printers that use the probe in place of a z endstop.
|
||||||
|
#[probe]
|
||||||
|
#pin: ar15
|
||||||
|
# Probe detection pin. This parameter must be provided.
|
||||||
|
#z_offset:
|
||||||
|
# The distance (in mm) between the bed and the nozzle when the probe
|
||||||
|
# triggers. This parameter must be provided.
|
||||||
|
#speed: 5.0
|
||||||
|
# Speed (in mm/s) of the Z axis when probing. The default is 5mm/s.
|
||||||
|
#activate_gcode:
|
||||||
|
# A list of G-Code commands (one per line) to execute prior to each
|
||||||
|
# probe attempt. This may be useful if the probe needs to be
|
||||||
|
# activated in some way. The default is to not run any special
|
||||||
|
# G-Code commands on activation.
|
||||||
|
#deactivate_gcode:
|
||||||
|
# A list of G-Code commands (one per line) to execute after each
|
||||||
|
# probe attempt completes. The default is to not run any special
|
||||||
|
# G-Code commands on deactivation.
|
||||||
|
|
||||||
|
|
||||||
|
# Bed tilt compensation. One may define a [bed_tilt] config section to
|
||||||
|
# enable move transformations that account for a tilted bed.
|
||||||
|
#[bed_tilt]
|
||||||
|
#x_adjust: 0
|
||||||
|
# The amount to add to each move's Z height for each mm on the X
|
||||||
|
# axis. The default is 0.
|
||||||
|
#y_adjust: 0
|
||||||
|
# The amount to add to each move's Z height for each mm on the Y
|
||||||
|
# axis. The default is 0.
|
||||||
|
# The remaining parameters control a BED_TILT_CALIBRATE extended
|
||||||
|
# g-code command that may be used to calibrate appropriate x and y
|
||||||
|
# adjustment parameters.
|
||||||
|
#points:
|
||||||
|
# A newline separated list of X,Y points that should be probed
|
||||||
|
# during a BED_TILT_CALIBRATE command. The default is to not enable
|
||||||
|
# the command.
|
||||||
|
#speed: 50
|
||||||
|
# The speed (in mm/s) of non-probing moves during the
|
||||||
|
# calibration. The default is 50.
|
||||||
|
#horizontal_move_z: 5
|
||||||
|
# The height (in mm) that the head should be commanded to move to
|
||||||
|
# just prior to starting a probe operation. The default is 5.
|
||||||
|
#manual_probe:
|
||||||
|
# If true, then BED_TILT_CALIBRATE will perform manual probing. If
|
||||||
|
# false, then a PROBE command will be run at each probe
|
||||||
|
# point. Manual probing is accomplished by manually jogging the Z
|
||||||
|
# position of the print head at each probe point and then issuing a
|
||||||
|
# NEXT extended g-code command to record the position at that
|
||||||
|
# point. The default is false if a [probe] config section is present
|
||||||
|
# and true otherwise.
|
||||||
|
|
||||||
|
|
||||||
|
# In a multi-extruder printer add an additional extruder section for
|
||||||
|
# each additional extruder. The additional extruder sections should be
|
||||||
|
# named "extruder1", "extruder2", "extruder3", and so on. See the
|
||||||
|
# "extruder" section in example.cfg for a description of available
|
||||||
|
# parameters.
|
||||||
|
#[extruder1]
|
||||||
|
#step_pin: ar36
|
||||||
|
#dir_pin: ar34
|
||||||
|
#...
|
||||||
|
#shared_heater:
|
||||||
|
# If this extruder uses the same heater already defined for another
|
||||||
|
# extruder then place the name of that extruder here. For example,
|
||||||
|
# should extruder3 and extruder4 share a heater then the extruder3
|
||||||
|
# config section should define the heater and the extruder4 section
|
||||||
|
# should specify "shared_heater: extruder3". The default is to not
|
||||||
|
# reuse an existing heater.
|
||||||
|
#deactivate_gcode:
|
||||||
|
# A list of G-Code commands (one per line) to execute on a G-Code
|
||||||
|
# tool change command (eg, "T1") that deactivates this extruder and
|
||||||
|
# activates some other extruder. It only makes sense to define this
|
||||||
|
# section on multi-extruder printers. The default is to not run any
|
||||||
|
# special G-Code commands on deactivation.
|
||||||
|
#activate_gcode:
|
||||||
|
# A list of G-Code commands (one per line) to execute on a G-Code
|
||||||
|
# tool change command (eg, "T0") that activates this extruder. It
|
||||||
|
# only makes sense to define this section on multi-extruder
|
||||||
|
# printers. The default is to not run any special G-Code commands on
|
||||||
|
# activation.
|
||||||
|
|
||||||
|
|
||||||
|
# Support for cartesian printers with dual carriages on a single
|
||||||
|
# axis. The active carriage is set via the SET_DUAL_CARRIAGE extended
|
||||||
|
# g-code command. The "SET_DUAL_CARRIAGE CARRIAGE=1" command will
|
||||||
|
# activate the carriage defined in this section (CARRIAGE=0 will
|
||||||
|
# return activation to the primary carriage). Dual carriage support is
|
||||||
|
# typically combined with extra extruders - use the SET_DUAL_CARRIAGE
|
||||||
|
# command in the activate_gcode / deactivate_gcode section of the
|
||||||
|
# appropriate extruder. Be sure to also use that mechanism to park the
|
||||||
|
# carriages during deactivation.
|
||||||
|
#[dual_carriage]
|
||||||
|
#axis:
|
||||||
|
# The axis this extra carriage is on (either x or y). This parameter
|
||||||
|
# must be provided.
|
||||||
|
#step_pin:
|
||||||
|
#dir_pin:
|
||||||
|
#enable_pin:
|
||||||
|
#step_distance:
|
||||||
|
#endstop_pin:
|
||||||
|
#position_endstop:
|
||||||
|
#position_min:
|
||||||
|
#position_max:
|
||||||
|
# See the example.cfg for the definition of the above parameters.
|
||||||
|
|
||||||
|
|
||||||
|
# Heater and temperature sensor verification. Heater verification is
|
||||||
|
# automatically enabled for each heater that is configured on the
|
||||||
|
# printer. Use verify_heater sections to change the default settings.
|
||||||
|
#[verify_heater heater_config_name]
|
||||||
|
#heating_gain: 2
|
||||||
|
# The minimum temperature (in Celsius) that the heater must increase
|
||||||
|
# by when approaching a new target temperature. The default is 2.
|
||||||
|
#check_gain_time:
|
||||||
|
# The amount of time (in seconds) that the heating_gain must be met
|
||||||
|
# in before an error is raised. The default is 20 seconds for
|
||||||
|
# extruders and 60 seconds for heater_bed.
|
||||||
|
#hysteresis: 5
|
||||||
|
# The difference between the target temperature and the current
|
||||||
|
# temperature for the heater to be considered within range of the
|
||||||
|
# target temperature. The default is 5.
|
||||||
|
#max_error: 120
|
||||||
|
# The maximum temperature difference a heater that falls outside the
|
||||||
|
# target temperature range may accumulate before an error is
|
||||||
|
# raised. For example, if the target temperature is 200, the
|
||||||
|
# hysteresis is 5, the max_error is 120, and the temperature is
|
||||||
|
# reported at 185 degrees for 12 seconds then an error would be
|
||||||
|
# raised (or 24 seconds at 190, or 120 seconds at 194, etc.). The
|
||||||
|
# default is 120.
|
||||||
|
|
||||||
|
|
||||||
|
# Multi-stepper axes. On a cartesian style printer, the stepper
|
||||||
|
# controlling a given axis may have additional config blocks defining
|
||||||
|
# steppers that should be stepped in concert with the primary
|
||||||
|
# stepper. One may define any number of sections with a numeric suffix
|
||||||
|
# starting at 1 (for example, "stepper_z1", "stepper_z2", etc.).
|
||||||
|
#[stepper_z1]
|
||||||
|
#step_pin: ar36
|
||||||
|
#dir_pin: ar34
|
||||||
|
#enable_pin: !ar30
|
||||||
|
#step_distance: .005
|
||||||
|
# See the example.cfg for the definition of the above parameters.
|
||||||
|
#endstop_pin: ^ar19
|
||||||
|
# If an endstop_pin is defined for the additional stepper then the
|
||||||
|
# stepper will home until the endstop is triggered. Otherwise, the
|
||||||
|
# endstop will home until the endstop on the primary stepper for the
|
||||||
|
# axis is triggered.
|
||||||
|
|
||||||
|
|
||||||
|
# Stepper phase adjusted endstops. The following additional parameters
|
||||||
|
# may be added to a stepper axis definition to improve the accuracy of
|
||||||
|
# endstop switches.
|
||||||
|
#[stepper_z]
|
||||||
|
#homing_stepper_phases:
|
||||||
|
# One may set this to the number of phases of the stepper motor
|
||||||
|
# driver (which is the number of micro-steps multiplied by
|
||||||
|
# four). This parameter must be provided if using stepper phase
|
||||||
|
# adjustments.
|
||||||
|
#homing_endstop_accuracy: 0.200
|
||||||
|
# Sets the expected accuracy (in mm) of the endstop. This represents
|
||||||
|
# the maximum error distance the endstop may trigger (eg, if an
|
||||||
|
# endstop may occasionally trigger 100um early or up to 100um late
|
||||||
|
# then set this to 0.200 for 200um). The default is
|
||||||
|
# homing_stepper_phases*step_distance.
|
||||||
|
#homing_endstop_phase:
|
||||||
|
# This specifies the phase of the stepper motor driver to expect
|
||||||
|
# when hitting the endstop. Only set this value if one is sure the
|
||||||
|
# stepper motor driver is reset every time the mcu is reset. If this
|
||||||
|
# is not set, then the stepper phase will be detected on the first
|
||||||
|
# home and that phase will be used on all subsequent homes.
|
||||||
|
#homing_endstop_align_zero: False
|
||||||
|
# If true then the code will arrange for the zero position on the
|
||||||
|
# axis to occur at a full step on the stepper motor. (If used on the
|
||||||
|
# Z axis and the print layer height is a multiple of a full step
|
||||||
|
# distance then every layer will occur on a full step.) The default
|
||||||
|
# is False.
|
||||||
|
|
||||||
|
|
||||||
|
# Heater cooling fans (one may define any number of sections with a
|
||||||
|
# "heater_fan" prefix). A "heater fan" is a fan that will be enabled
|
||||||
|
# whenever its associated heater is active. In the event of an MCU
|
||||||
|
# software error the heater_fan will be set to its max_power.
|
||||||
|
#[heater_fan my_nozzle_fan]
|
||||||
|
# See the "fan" section for fan configuration parameters.
|
||||||
|
#pin: ar4
|
||||||
|
# The remaining variables are specific to heater_fan.
|
||||||
|
#heater: extruder
|
||||||
|
# Name of the config section defining the heater that this fan is
|
||||||
|
# associated with. The default is "extruder".
|
||||||
|
#heater_temp: 50.0
|
||||||
|
# A temperature (in Celsius) that the heater must drop below before
|
||||||
|
# the fan is disabled. The default is 50 Celsius.
|
||||||
|
#fan_speed:
|
||||||
|
# The fan speed (expressed as a value from 0.0 to 1.0) that the fan
|
||||||
|
# will be set to when its associated heater is enabled. The default
|
||||||
|
# is max_power.
|
||||||
|
|
||||||
|
|
||||||
|
# Additional micro-controllers (one may define any number of sections
|
||||||
|
# with an "mcu" prefix). Additional micro-controllers introduce
|
||||||
|
# additional pins that may be configured as heaters, steppers, fans,
|
||||||
|
# etc.. For example, if an "[mcu extra_mcu]" section is introduced,
|
||||||
|
# then pins such as "extra_mcu:ar9" may then be used elsewhere in the
|
||||||
|
# config (where "ar9" is a hardware pin name or alias name on the
|
||||||
|
# given mcu).
|
||||||
|
#[mcu my_extra_mcu]
|
||||||
|
# See the "mcu" section in example.cfg for configuration parameters.
|
||||||
|
|
||||||
|
|
||||||
|
# Servos (one may define any number of sections with a "servo"
|
||||||
|
# prefix). The servos may be controlled using the SET_SERVO g-code
|
||||||
|
# command. For example: SET_SERVO SERVO=my_servo ANGLE=180
|
||||||
|
#[servo my_servo]
|
||||||
|
#pin: ar7
|
||||||
|
# PWM output pin controlling the servo. This parameter must be
|
||||||
|
# provided.
|
||||||
|
#maximum_servo_angle: 180
|
||||||
|
# The maximum angle (in degrees) that this servo can be set to. The
|
||||||
|
# default is 180 degrees.
|
||||||
|
#minimum_pulse_width: 0.001
|
||||||
|
# The minimum pulse width time (in seconds). This should correspond
|
||||||
|
# with an angle of 0 degrees. The default is 0.001 seconds.
|
||||||
|
#maximum_pulse_width: 0.002
|
||||||
|
# The maximum pulse width time (in seconds). This should correspond
|
||||||
|
# with an angle of maximum_servo_angle. The default is 0.002
|
||||||
|
# seconds.
|
||||||
|
|
||||||
|
|
||||||
|
# Statically configured digital output pins (one may define any number
|
||||||
|
# of sections with a "static_digital_output" prefix). Pins configured
|
||||||
|
# here will be setup as a GPIO output during MCU configuration. They
|
||||||
|
# can not be changed at run-time.
|
||||||
|
#[static_digital_output my_output_pins]
|
||||||
|
#pins:
|
||||||
|
# A comma separated list of pins to be set as GPIO output pins. The
|
||||||
|
# pin will be set to a high level unless the pin name is prefaced
|
||||||
|
# with "!". This parameter must be provided.
|
||||||
|
|
||||||
|
|
||||||
|
# Run-time configurable output pins (one may define any number of
|
||||||
|
# sections with an "output_pin" prefix). Pins configured here will be
|
||||||
|
# setup as output pins and one may modify them at run-time using the
|
||||||
|
# "SET_PIN PIN=my_pin VALUE=.1" extended g-code command.
|
||||||
|
#[output_pin my_pin]
|
||||||
|
#pin:
|
||||||
|
# The pin to configure as an output. This parameter must be
|
||||||
|
# provided.
|
||||||
|
#pwm: False
|
||||||
|
# Set if the output pin should be capable of
|
||||||
|
# pulse-width-modulation. If this is true, the value fields should
|
||||||
|
# be between 0 and 1; if it is false the value fields should be
|
||||||
|
# either 0 or 1. The default is False.
|
||||||
|
#static_value:
|
||||||
|
# If this is set, then the pin is assigned to this value at startup
|
||||||
|
# and the pin can not be changed during runtime. A static pin uses
|
||||||
|
# slightly less ram in the micro-controller. The default is to use
|
||||||
|
# runtime configuration of pins.
|
||||||
|
#value:
|
||||||
|
# The value to initially set the pin to during MCU
|
||||||
|
# configuration. The default is 0 (for low voltage).
|
||||||
|
#shutdown_value:
|
||||||
|
# The value to set the pin to on an MCU shutdown event. The default
|
||||||
|
# is 0 (for low voltage).
|
||||||
|
#cycle_time: 0.100
|
||||||
|
# The amount of time (in seconds) per PWM cycle. It is recommended
|
||||||
|
# this be 10 milliseconds or greater when using software based
|
||||||
|
# PWM. The default is 0.100 seconds for pwm pins.
|
||||||
|
#hardware_pwm: False
|
||||||
|
# Enable this to use hardware PWM instead of software PWM. The
|
||||||
|
# default is False.
|
||||||
|
#scale:
|
||||||
|
# This parameter can be used to alter how the 'value' and
|
||||||
|
# 'shutdown_value' parameters are interpreted for pwm pins. If
|
||||||
|
# provided, then the 'value' parameter should be between 0.0 and
|
||||||
|
# 'scale'. This may be useful when configuring a PWM pin that
|
||||||
|
# controls a stepper voltage reference. The 'scale' can be set to
|
||||||
|
# the equivalent stepper amperage if the PWM were fully enabled, and
|
||||||
|
# then the 'value' parameter can be specified using the desired
|
||||||
|
# amperage for the stepper. The default is to not scale the 'value'
|
||||||
|
# parameter.
|
||||||
|
|
||||||
|
|
||||||
|
# Multiple pin outputs (one may define any number of sections with a
|
||||||
|
# "multi_pin" prefix). A multi_pin output creates an internal pin
|
||||||
|
# alias that can modify multiple output pins each time the alias pin
|
||||||
|
# is set. For example, one could define a "[multi_pin my_fan]" object
|
||||||
|
# containing two pins and then set "pin=multi_pin:my_fan" in the
|
||||||
|
# "[fan]" section - on each fan change both output pins would be
|
||||||
|
# updated. These aliases may not be used with stepper motor pins.
|
||||||
|
#[multi_pin my_multi_pin]
|
||||||
|
#pins:
|
||||||
|
# A comma separated list of pins associated with this alias. This
|
||||||
|
# parameter must be provided.
|
||||||
|
|
||||||
|
|
||||||
|
# Statically configured AD5206 digipots connected via SPI bus (one may
|
||||||
|
# define any number of sections with an "ad5206" prefix).
|
||||||
|
#[ad5206 my_digipot]
|
||||||
|
#enable_pin:
|
||||||
|
# The pin corresponding to the AD5206 chip select line. This pin
|
||||||
|
# will be set to low at the start of SPI messages and raised to high
|
||||||
|
# after the message completes. This parameter must be provided.
|
||||||
|
#channel_1:
|
||||||
|
#channel_2:
|
||||||
|
#channel_3:
|
||||||
|
#channel_4:
|
||||||
|
#channel_5:
|
||||||
|
#channel_6:
|
||||||
|
# The value to statically set the given AD5206 channel to. This is
|
||||||
|
# typically set to a number between 0.0 and 1.0 with 1.0 being the
|
||||||
|
# highest resistance and 0.0 being the lowest resistance. However,
|
||||||
|
# the range may be changed with the 'scale' parameter (see
|
||||||
|
# below). If a channel is not specified then it is left
|
||||||
|
# unconfigured.
|
||||||
|
#scale:
|
||||||
|
# This parameter can be used to alter how the 'channel_x' parameters
|
||||||
|
# are interpreted. If provided, then the 'channel_x' parameters
|
||||||
|
# should be between 0.0 and 'scale'. This may be useful when the
|
||||||
|
# AD5206 is used to set stepper voltage references. The 'scale' can
|
||||||
|
# be set to the equivalent stepper amperage if the AD5206 were at
|
||||||
|
# its highest resistance, and then the 'channel_x' parameters can be
|
||||||
|
# specified using the desired amperage value for the stepper. The
|
||||||
|
# default is to not scale the 'channel_x' parameters.
|
||||||
|
|
||||||
|
|
||||||
|
# Homing override. One may use this mechanism to run a series of
|
||||||
|
# g-code commands in place of a G28 found in the normal g-code input.
|
||||||
|
# This may be useful on printers that require a specific procedure to
|
||||||
|
# home the machine.
|
||||||
|
#[homing_override]
|
||||||
|
#gcode:
|
||||||
|
# A list of G-Code commands (one per line) to execute in place of
|
||||||
|
# all G28 commands found in the normal g-code input. If a G28 is
|
||||||
|
# contained in this list of commands then it will invoke the normal
|
||||||
|
# homing procedure for the printer. The commands listed here must
|
||||||
|
# home all axes. This parameter must be provided.
|
||||||
|
#set_position_x:
|
||||||
|
#set_position_y:
|
||||||
|
#set_position_z:
|
||||||
|
# If specified, the printer will assume the axis is at the specified
|
||||||
|
# position prior to running the above g-code commands. Setting this
|
||||||
|
# disables homing checks for that axis. This may be useful if the
|
||||||
|
# head must move prior to invoking the normal G28 mechanism for an
|
||||||
|
# axis. The default is to not force a position for an axis.
|
||||||
|
|
||||||
|
|
||||||
|
# A virtual sdcard may be useful if the host machine is not fast
|
||||||
|
# enough to run OctoPrint well. It allows the Klipper host software to
|
||||||
|
# directly print gcode files stored in a directory on the host using
|
||||||
|
# standard sdcard G-Code commands (eg, M24).
|
||||||
|
#[virtual_sdcard]
|
||||||
|
#path: ~/.octoprint/uploads/
|
||||||
|
# The path of the local directory on the host machine to look for
|
||||||
|
# g-code files. This is a read-only directory (sdcard file writes
|
||||||
|
# are not supported). One may point this to OctoPrint's upload
|
||||||
|
# directory (generally ~/.octoprint/uploads/ ). This parameter must
|
||||||
|
# be provided.
|
||||||
|
|
||||||
|
|
||||||
|
# Support for a display attached to the micro-controller.
|
||||||
|
#[display]
|
||||||
|
#lcd_type:
|
||||||
|
# The type of LCD chip in use. This may be either "hd44780" (which
|
||||||
|
# is used in "RepRapDiscount 2004 Smart Controller" type displays)
|
||||||
|
# or "st7920" (which is used in "RepRapDiscount 12864 Full Graphic
|
||||||
|
# Smart Controller" type displays). This parameter must be
|
||||||
|
# provided.
|
||||||
|
#rs_pin:
|
||||||
|
#e_pin:
|
||||||
|
#d4_pin:
|
||||||
|
#d5_pin:
|
||||||
|
#d6_pin:
|
||||||
|
#d7_pin:
|
||||||
|
# The pins connected to an hd44780 type lcd. These parameters must
|
||||||
|
# be provided when using an hd44780 display.
|
||||||
|
#cs_pin:
|
||||||
|
#sclk_pin:
|
||||||
|
#sid_pin:
|
||||||
|
# The pins connected to an st7920 type lcd. These parameters must
|
||||||
|
# be provided when using an st7920 display.
|
||||||
|
|
||||||
|
|
||||||
|
# Replicape support - see the generic-replicape.cfg file for further
|
||||||
|
# details.
|
||||||
|
#[replicape]
|
||||||
87
config/example-multi-mcu.cfg
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
# This file contains an example configuration with three
|
||||||
|
# micro-controllers simultaneously controlling a single printer.
|
||||||
|
|
||||||
|
# See both the example.cfg and example-extras.cfg file for a
|
||||||
|
# description of available parameters.
|
||||||
|
|
||||||
|
|
||||||
|
# The main micro-controller is used as the timing source for all the
|
||||||
|
# micro-controllers on the printer. Typically, both the X and Y axes
|
||||||
|
# are connected to the main micro-controller.
|
||||||
|
[mcu]
|
||||||
|
serial: /dev/ttyACM0
|
||||||
|
pin_map: arduino
|
||||||
|
|
||||||
|
# The "zboard" micro-controller will be used to control the Z axis.
|
||||||
|
[mcu zboard]
|
||||||
|
serial: /dev/ttyACM1
|
||||||
|
pin_map: arduino
|
||||||
|
|
||||||
|
# The "auxboard" micro-controller will be used to control the heaters.
|
||||||
|
[mcu auxboard]
|
||||||
|
serial: /dev/ttyACM2
|
||||||
|
pin_map: arduino
|
||||||
|
|
||||||
|
[stepper_x]
|
||||||
|
step_pin: ar54
|
||||||
|
dir_pin: ar55
|
||||||
|
enable_pin: !ar38
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^ar3
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 200
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_y]
|
||||||
|
step_pin: ar60
|
||||||
|
dir_pin: !ar61
|
||||||
|
enable_pin: !ar56
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^ar14
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 200
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_z]
|
||||||
|
step_pin: zboard:ar46
|
||||||
|
dir_pin: zboard:ar48
|
||||||
|
enable_pin: !zboard:ar62
|
||||||
|
step_distance: .0025
|
||||||
|
endstop_pin: ^zboard:ar18
|
||||||
|
position_endstop: 0.5
|
||||||
|
position_max: 200
|
||||||
|
|
||||||
|
[extruder]
|
||||||
|
step_pin: auxboard:ar26
|
||||||
|
dir_pin: auxboard:ar28
|
||||||
|
enable_pin: !auxboard:ar24
|
||||||
|
step_distance: .002
|
||||||
|
nozzle_diameter: 0.400
|
||||||
|
filament_diameter: 1.750
|
||||||
|
heater_pin: auxboard:ar10
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: auxboard:analog13
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 22.2
|
||||||
|
pid_Ki: 1.08
|
||||||
|
pid_Kd: 114
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 250
|
||||||
|
|
||||||
|
[heater_bed]
|
||||||
|
heater_pin: auxboard:ar8
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: auxboard:analog14
|
||||||
|
control: watermark
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 130
|
||||||
|
|
||||||
|
[fan]
|
||||||
|
pin: auxboard:ar9
|
||||||
|
|
||||||
|
[printer]
|
||||||
|
kinematics: cartesian
|
||||||
|
max_velocity: 300
|
||||||
|
max_accel: 3000
|
||||||
|
max_z_velocity: 5
|
||||||
|
max_z_accel: 100
|
||||||
@@ -1,173 +1,294 @@
|
|||||||
# This file serves as documentation for config parameters. One may
|
# This file serves as documentation for config parameters. One may
|
||||||
# copy and edit this file to configure a new printer.
|
# copy and edit this file to configure a new cartesian style
|
||||||
|
# printer. For delta style printers, see the "example-delta.cfg"
|
||||||
|
# file. For corexy/h-bot style printers, see the "example-corexy.cfg"
|
||||||
|
# file. Only common config sections are described here - see the
|
||||||
|
# "example-extras.cfg" file for configuring less common devices.
|
||||||
|
|
||||||
# DO NOT COPY THIS FILE WITHOUT CAREFULLY READING AND UPDATING IT
|
# DO NOT COPY THIS FILE WITHOUT CAREFULLY READING AND UPDATING IT
|
||||||
# FIRST. Incorrectly configured parameters may cause damage.
|
# FIRST. Incorrectly configured parameters may cause damage.
|
||||||
|
|
||||||
# A note on pin names: pins may be configured with a hardware name
|
# A note on pin names: pins may be configured with a hardware name
|
||||||
# (such as PA4) or with a board name (such as ar29). In order to use a
|
# (such as "PA4") or with an Arduino alias name (such as "ar29" or
|
||||||
# board name, the pin_map variable in the mcu section must specify
|
# "analog3"). In order to use Arduino names, the pin_map variable in
|
||||||
# which board definition to use. (See the klippy/pins.py file for the
|
# the mcu section must be present and have a value of "arduino".
|
||||||
# available pin and board names.)
|
|
||||||
# Pin names may be preceded by an '!' to indicate that a reverse
|
# Pin names may be preceded by an '!' to indicate that a reverse
|
||||||
# polarity should be used (eg, trigger on low instead of high). Input
|
# polarity should be used (eg, trigger on low instead of high). Input
|
||||||
# pins may be prceded by an '^' to indicate that a hardware pull-up
|
# pins may be preceded by a '^' to indicate that a hardware pull-up
|
||||||
# resistor should be enabled for the pin.
|
# resistor should be enabled for the pin.
|
||||||
|
|
||||||
|
|
||||||
# The stepper_x section is used to describe the stepper controlling
|
# The stepper_x section is used to describe the stepper controlling
|
||||||
# the X axis in a cartesian robot
|
# the X axis in a cartesian robot.
|
||||||
[stepper_x]
|
[stepper_x]
|
||||||
step_pin: ar29
|
step_pin: ar54
|
||||||
# Step GPIO pin (triggered high)
|
# Step GPIO pin (triggered high). This parameter must be provided.
|
||||||
dir_pin: ar28
|
dir_pin: ar55
|
||||||
# Direction GPIO pin (low indicates positive direction)
|
# Direction GPIO pin (high indicates positive direction). This
|
||||||
enable_pin: !ar25
|
# parameter must be provided.
|
||||||
# Enable pin (default is enable high; use ! to indicate enable low)
|
enable_pin: !ar38
|
||||||
|
# Enable pin (default is enable high; use ! to indicate enable
|
||||||
|
# low). If this parameter is not provided then the stepper motor
|
||||||
|
# driver must always be enabled.
|
||||||
step_distance: .0225
|
step_distance: .0225
|
||||||
# Distance in mm that each step causes the axis to travel
|
# Distance in mm that each step causes the axis to travel. This
|
||||||
max_velocity: 500
|
# parameter must be provided.
|
||||||
# Maximum velocity (in mm/s) of the stepper
|
endstop_pin: ^ar3
|
||||||
max_accel: 3000
|
# Endstop switch detection pin. This parameter must be provided for
|
||||||
# Maximum acceleration (in mm/s^2) of the stepper
|
# the X, Y, and Z steppers on cartesian style printers.
|
||||||
endstop_pin: ^ar0
|
#position_min: 0
|
||||||
# Endstop switch detection pin
|
|
||||||
homing_speed: 50.0
|
|
||||||
# Maximum velocity (in mm/s) of the stepper when homing
|
|
||||||
homing_retract_dist: 5.0
|
|
||||||
# Distance to backoff (in mm) before homing a second time during homing
|
|
||||||
homing_positive_dir: False
|
|
||||||
# If true, homes in a positive direction (away from zero)
|
|
||||||
position_min: -0.25
|
|
||||||
# Minimum valid distance (in mm) the user may command the stepper to
|
# Minimum valid distance (in mm) the user may command the stepper to
|
||||||
# move to (not currently enforced)
|
# move to. The default is 0mm.
|
||||||
position_endstop: 0
|
position_endstop: 0
|
||||||
# Location of the endstop (in mm)
|
# Location of the endstop (in mm). This parameter must be provided
|
||||||
|
# for the X, Y, and Z steppers on cartesian style printers.
|
||||||
position_max: 200
|
position_max: 200
|
||||||
# Maximum valid distance (in mm) the user may command the stepper to
|
# Maximum valid distance (in mm) the user may command the stepper to
|
||||||
# move to (not currently enforced)
|
# move to. This parameter must be provided for the X, Y, and Z
|
||||||
|
# steppers on cartesian style printers.
|
||||||
|
#homing_speed: 5.0
|
||||||
|
# Maximum velocity (in mm/s) of the stepper when homing. The default
|
||||||
|
# is 5mm/s.
|
||||||
|
#homing_retract_dist: 5.0
|
||||||
|
# Distance to backoff (in mm) before homing a second time during
|
||||||
|
# homing. The default is 5mm.
|
||||||
|
#homing_positive_dir:
|
||||||
|
# If true, homing will cause the stepper to move in a positive
|
||||||
|
# direction (away from zero); if false, home towards zero. The
|
||||||
|
# default is true if position_endstop is near position_max and false
|
||||||
|
# if near position_min.
|
||||||
|
|
||||||
# The stepper_y section is used to describe the stepper controlling
|
# The stepper_y section is used to describe the stepper controlling
|
||||||
# the Y axis in a cartesian robot. It has the same settings as the
|
# the Y axis in a cartesian robot. It has the same settings as the
|
||||||
# stepper_x section
|
# stepper_x section.
|
||||||
[stepper_y]
|
[stepper_y]
|
||||||
step_pin: ar27
|
step_pin: ar60
|
||||||
dir_pin: ar26
|
dir_pin: !ar61
|
||||||
enable_pin: !ar25
|
enable_pin: !ar56
|
||||||
step_distance: .0225
|
step_distance: .0225
|
||||||
max_velocity: 500
|
endstop_pin: ^ar14
|
||||||
max_accel: 3000
|
|
||||||
endstop_pin: ^ar1
|
|
||||||
position_min: -0.25
|
|
||||||
position_endstop: 0
|
position_endstop: 0
|
||||||
position_max: 200
|
position_max: 200
|
||||||
|
|
||||||
# The stepper_z section is used to describe the stepper controlling
|
# The stepper_z section is used to describe the stepper controlling
|
||||||
# the Z axis in a cartesian robot. It has the same settings as the
|
# the Z axis in a cartesian robot. It has the same settings as the
|
||||||
# stepper_x section
|
# stepper_x section.
|
||||||
[stepper_z]
|
[stepper_z]
|
||||||
step_pin: ar23
|
step_pin: ar46
|
||||||
dir_pin: ar22
|
dir_pin: ar48
|
||||||
enable_pin: !ar25
|
enable_pin: !ar62
|
||||||
step_distance: .005
|
step_distance: .005
|
||||||
max_velocity: 250
|
endstop_pin: ^ar18
|
||||||
max_accel: 30
|
|
||||||
endstop_pin: ^ar2
|
|
||||||
position_min: 0.1
|
|
||||||
position_endstop: 0.5
|
position_endstop: 0.5
|
||||||
position_max: 200
|
position_max: 200
|
||||||
|
|
||||||
# The stepper_e section is used to describe the stepper controlling
|
# The extruder section is used to describe both the stepper
|
||||||
# the printer extruder. It has the same settings as the stepper_x
|
# controlling the printer extruder and the heater parameters for the
|
||||||
# section
|
# nozzle. The stepper configuration has the same settings as the
|
||||||
[stepper_e]
|
# stepper_x section and the heater configuration has the same settings
|
||||||
step_pin: ar19
|
# as the heater_bed section (described below).
|
||||||
dir_pin: ar18
|
[extruder]
|
||||||
enable_pin: !ar25
|
step_pin: ar26
|
||||||
|
dir_pin: ar28
|
||||||
|
enable_pin: !ar24
|
||||||
step_distance: .004242
|
step_distance: .004242
|
||||||
max_velocity: 200000
|
nozzle_diameter: 0.500
|
||||||
max_accel: 3000
|
# Diameter of the nozzle orifice (in mm). This parameter must be
|
||||||
|
# provided.
|
||||||
# The heater_nozzle section describes the extruder and extruder heater
|
filament_diameter: 3.500
|
||||||
[heater_nozzle]
|
# Diameter of the raw filament (in mm) as it enters the
|
||||||
heater_pin: ar4
|
# extruder. This parameter must be provided.
|
||||||
# PWM output pin controlling the heater
|
#max_extrude_cross_section:
|
||||||
thermistor_pin: analog1
|
# Maximum area of the cross section of an extrusion line (in
|
||||||
# Analog input pin connected to thermistor
|
# mm^2). This setting prevents excessive amounts of extrusion during
|
||||||
thermistor_type: EPCOS 100K B57560G104F
|
# relatively small XY moves. If a move requests an extrusion rate
|
||||||
# Type of thermistor (see klippy/heater.py for available types)
|
# that would exceed this value it will cause an error to be
|
||||||
pullup_resistor: 4700
|
# returned. The default is: 4.0 * nozzle_diameter^2
|
||||||
# The resistance (in ohms) of the pullup attached to the thermistor
|
#max_extrude_only_distance: 50.0
|
||||||
|
# Maximum length (in mm of raw filament) that an extrude only move
|
||||||
|
# may be. If an extrude only move requests a distance greater than
|
||||||
|
# this value it will cause an error to be returned. The default is
|
||||||
|
# 50mm.
|
||||||
|
#max_extrude_only_velocity:
|
||||||
|
# Maximum velocity (in mm/s) of the extruder motor for extrude only
|
||||||
|
# moves. If this is not specified then it is calculated to match the
|
||||||
|
# limit an XY printing move with a max_extrude_cross_section
|
||||||
|
# extrusion would have.
|
||||||
|
#max_extrude_only_accel:
|
||||||
|
# Maximum acceleration (in mm/s^2) of the extruder motor for extrude
|
||||||
|
# only moves. If this is not specified then it is calculated to
|
||||||
|
# match the limit an XY printing move with a
|
||||||
|
# max_extrude_cross_section extrusion would have.
|
||||||
|
#pressure_advance: 0.0
|
||||||
|
# The amount of raw filament to push into the extruder during
|
||||||
|
# extruder acceleration. An equal amount of filament is retracted
|
||||||
|
# during deceleration. It is measured in millimeters per
|
||||||
|
# millimeter/second. The default is 0, which disables pressure
|
||||||
|
# advance.
|
||||||
|
#pressure_advance_lookahead_time: 0.010
|
||||||
|
# A time (in seconds) to "look ahead" at future extrusion moves when
|
||||||
|
# calculating pressure advance. This is used to reduce the
|
||||||
|
# application of pressure advance during cornering moves that would
|
||||||
|
# otherwise cause retraction followed immediately by pressure
|
||||||
|
# buildup. This setting only applies if pressure_advance is
|
||||||
|
# non-zero. The default is 0.010 (10 milliseconds).
|
||||||
|
#
|
||||||
|
# The remaining variables describe the extruder heater.
|
||||||
|
heater_pin: ar10
|
||||||
|
# PWM output pin controlling the heater. This parameter must be
|
||||||
|
# provided.
|
||||||
|
#max_power: 1.0
|
||||||
|
# The maximum power (expressed as a value from 0.0 to 1.0) that the
|
||||||
|
# heater_pin may be set to. The value 1.0 allows the pin to be set
|
||||||
|
# fully enabled for extended periods, while a value of 0.5 would
|
||||||
|
# allow the pin to be enabled for no more than half the time. This
|
||||||
|
# setting may be used to limit the total power output (over extended
|
||||||
|
# periods) to the heater. The default is 1.0.
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
# Type of sensor - this may be "EPCOS 100K B57560G104F", "ATC
|
||||||
|
# Semitec 104GT-2", "NTC 100K beta 3950", or "AD595". This parameter
|
||||||
|
# must be provided.
|
||||||
|
sensor_pin: analog13
|
||||||
|
# Analog input pin connected to the sensor. This parameter must be
|
||||||
|
# provided.
|
||||||
|
#pullup_resistor: 4700
|
||||||
|
# The resistance (in ohms) of the pullup attached to the
|
||||||
|
# thermistor. This parameter is only valid when the sensor is a
|
||||||
|
# thermistor. The default is 4700 ohms.
|
||||||
|
#adc_voltage: 5.0
|
||||||
|
# The ADC comparison voltage. This parameter is only valid when the
|
||||||
|
# sensor is an AD595. The default is 5 volts.
|
||||||
control: pid
|
control: pid
|
||||||
# Control algorithm (either pid or watermark)
|
# Control algorithm (either pid or watermark). This parameter must
|
||||||
|
# be provided.
|
||||||
pid_Kp: 22.2
|
pid_Kp: 22.2
|
||||||
# Kp is the "proportional" constant for the pid
|
# Kp is the "proportional" constant for the pid. This parameter must
|
||||||
|
# be provided for PID heaters.
|
||||||
pid_Ki: 1.08
|
pid_Ki: 1.08
|
||||||
# Ki is the "integral" constant for the pid
|
# Ki is the "integral" constant for the pid. This parameter must be
|
||||||
|
# provided for PID heaters.
|
||||||
pid_Kd: 114
|
pid_Kd: 114
|
||||||
# Kd is the "derivative" constant for the pid
|
# Kd is the "derivative" constant for the pid. This parameter must
|
||||||
pid_deriv_time: 2.0
|
# be provided for PID heaters.
|
||||||
|
#pid_deriv_time: 2.0
|
||||||
# A time value (in seconds) over which the derivative in the pid
|
# A time value (in seconds) over which the derivative in the pid
|
||||||
# will be smoothed to reduce the impact of measurement noise
|
# will be smoothed to reduce the impact of measurement noise. The
|
||||||
pid_integral_max: 255
|
# default is 2 seconds.
|
||||||
# The maximum "windup" the integral term may accumulate
|
#pid_integral_max:
|
||||||
|
# The maximum "windup" the integral term may accumulate. The default
|
||||||
|
# is to use the same value as max_power.
|
||||||
|
#pwm_cycle_time: 0.100
|
||||||
|
# Time in seconds for each software PWM cycle of the heater. It is
|
||||||
|
# not recommended to set this unless there is an electrical
|
||||||
|
# requirement to switch the heater faster than 10 times a second.
|
||||||
|
# The default is 0.100 seconds.
|
||||||
|
#min_extrude_temp: 170
|
||||||
|
# The minimum temperature (in Celsius) at which extruder move
|
||||||
|
# commands may be issued. The default is 170 Celsius.
|
||||||
min_temp: 0
|
min_temp: 0
|
||||||
# Minimum temperature in Celsius (mcu will shutdown if not met)
|
|
||||||
max_temp: 210
|
max_temp: 210
|
||||||
# Maximum temperature (mcu will shutdown if temperature is above
|
# The maximum range of valid temperatures (in Celsius) that the
|
||||||
# this value)
|
# heater must remain within. This controls a safety feature
|
||||||
|
# implemented in the micro-controller code - should the measured
|
||||||
|
# temperature ever fall outside this range then the micro-controller
|
||||||
|
# will go into a shutdown state. This check can help detect some
|
||||||
|
# heater and sensor hardware failures. Set this range just wide
|
||||||
|
# enough so that reasonable temperatures do not result in an
|
||||||
|
# error. These parameters must be provided.
|
||||||
|
|
||||||
# The heater_bed section describes a heated bed (if present - omit
|
# The heater_bed section describes a heated bed (if present - omit
|
||||||
# section if not present). It has the same settings as the
|
# section if not present).
|
||||||
# heater_nozzle section
|
|
||||||
[heater_bed]
|
[heater_bed]
|
||||||
heater_pin: ar3
|
heater_pin: ar8
|
||||||
thermistor_pin: analog0
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
thermistor_type: EPCOS 100K B57560G104F
|
sensor_pin: analog14
|
||||||
control: watermark
|
control: watermark
|
||||||
max_delta: 2.0
|
#max_delta: 2.0
|
||||||
# The number of degrees in Celsius above the target temperature
|
# On 'watermark' controlled heaters this is the number of degrees in
|
||||||
# before disabling the heater as well as the number of degrees below
|
# Celsius above the target temperature before disabling the heater
|
||||||
# the target before re-enabling the heater.
|
# as well as the number of degrees below the target before
|
||||||
|
# re-enabling the heater. The default is 2 degrees Celsius.
|
||||||
min_temp: 0
|
min_temp: 0
|
||||||
max_temp: 110
|
max_temp: 110
|
||||||
|
|
||||||
# Extruder print fan (omit section if fan not present)
|
# Print cooling fan (omit section if fan not present).
|
||||||
[fan]
|
[fan]
|
||||||
pin: ar14
|
pin: ar9
|
||||||
# PWM output pin controlling the heater
|
# PWM output pin controlling the fan. This parameter must be
|
||||||
hard_pwm: 1
|
# provided.
|
||||||
# Set this value to force hardware PWM instead of software PWM. Set
|
#max_power: 1.0
|
||||||
# to 1 to force a hardware PWM at the fastest rate; set to a higher
|
# The maximum power (expressed as a value from 0.0 to 1.0) that the
|
||||||
# number (eg, 1024) to force hardware PWM with the given cycle time
|
# pin may be set to. The value 1.0 allows the pin to be set fully
|
||||||
# in clock ticks.
|
# enabled for extended periods, while a value of 0.5 would allow the
|
||||||
kick_start_time: 0.100
|
# pin to be enabled for no more than half the time. This setting may
|
||||||
|
# be used to limit the total power output (over extended periods) to
|
||||||
|
# the fan. The default is 1.0.
|
||||||
|
#cycle_time: 0.010
|
||||||
|
# The amount of time (in seconds) for each PWM power cycle to the
|
||||||
|
# fan. It is recommended this be 10 milliseconds or greater when
|
||||||
|
# using software based PWM. The default is 0.010 seconds.
|
||||||
|
#hardware_pwm: False
|
||||||
|
# Enable this to use hardware PWM instead of software PWM. The
|
||||||
|
# default is False.
|
||||||
|
#kick_start_time: 0.100
|
||||||
# Time (in seconds) to run the fan at full speed when first enabling
|
# Time (in seconds) to run the fan at full speed when first enabling
|
||||||
# it (helps get the fan spinning)
|
# it (helps get the fan spinning). The default is 0.100 seconds.
|
||||||
|
|
||||||
# Micro-controller information
|
# Micro-controller information.
|
||||||
[mcu]
|
[mcu]
|
||||||
serial: /dev/ttyACM0
|
serial: /dev/ttyACM0
|
||||||
# The serial port to connect to the MCU
|
# The serial port to connect to the MCU. The default is /dev/ttyS0
|
||||||
baud: 115200
|
#baud: 250000
|
||||||
# The baud rate to use
|
# The baud rate to use. The default is 250000.
|
||||||
pin_map: arduino
|
pin_map: arduino
|
||||||
# This option may be used to add board specific pin name aliases
|
# This option may be used to enable Arduino pin name aliases. The
|
||||||
custom:
|
# default is to not enable the aliases.
|
||||||
# This option may be used to specify a set of custom
|
#restart_method:
|
||||||
# micro-controller commands to be sent at the start of the
|
# This controls the mechanism the host will use to reset the
|
||||||
# connection. It may be used to configure the initial settings of
|
# micro-controller. The choices are 'arduino', 'rpi_usb', and
|
||||||
# LEDs, to configure micro-stepping pins, to configure a digipot,
|
# 'command'. The 'arduino' method (toggle DTR) is common on Arduino
|
||||||
# etc.
|
# boards and clones. The 'rpi_usb' method is useful on Raspberry Pi
|
||||||
|
# boards with micro-controllers powered over USB - it briefly
|
||||||
|
# disables power to all USB ports to accomplish a micro-controller
|
||||||
|
# reset. The 'command' method involves sending a Klipper command to
|
||||||
|
# the micro-controller so that it can reset itself. The default is
|
||||||
|
# 'arduino' if the micro-controller communicates over a serial port,
|
||||||
|
# 'command' otherwise.
|
||||||
|
|
||||||
# The printer section controls high level printer settings
|
# The printer section controls high level printer settings.
|
||||||
[printer]
|
[printer]
|
||||||
kinematics: cartesian
|
kinematics: cartesian
|
||||||
# This option must currently always be "cartesian"
|
# This option must be "cartesian" for cartesian printers.
|
||||||
motor_off_time: 60
|
max_velocity: 500
|
||||||
|
# Maximum velocity (in mm/s) of the toolhead (relative to the
|
||||||
|
# print). This parameter must be specified.
|
||||||
|
max_accel: 3000
|
||||||
|
# Maximum acceleration (in mm/s^2) of the toolhead (relative to the
|
||||||
|
# print). This parameter must be specified.
|
||||||
|
#max_accel_to_decel:
|
||||||
|
# A pseudo acceleration (in mm/s^2) controlling how fast the
|
||||||
|
# toolhead may go from acceleration to deceleration. It is used to
|
||||||
|
# reduce the top speed of short zig-zag moves (and thus reduce
|
||||||
|
# printer vibration from these moves). The default is half of
|
||||||
|
# max_accel.
|
||||||
|
max_z_velocity: 25
|
||||||
|
# For cartesian printers this sets the maximum velocity (in mm/s) of
|
||||||
|
# movement along the z axis. This setting can be used to restrict
|
||||||
|
# the maximum speed of the z stepper motor on cartesian
|
||||||
|
# printers. The default is to use max_velocity for max_z_velocity.
|
||||||
|
max_z_accel: 30
|
||||||
|
# For cartesian printers this sets the maximum acceleration (in
|
||||||
|
# mm/s^2) of movement along the z axis. It limits the acceleration
|
||||||
|
# of the z stepper motor on cartesian printers. The default is to
|
||||||
|
# use max_accel for max_z_accel.
|
||||||
|
#motor_off_time: 600
|
||||||
# Time (in seconds) of idle time before the printer will try to
|
# Time (in seconds) of idle time before the printer will try to
|
||||||
# disable active motors.
|
# disable active motors. The default is 600 seconds.
|
||||||
junction_deviation: 0.02
|
#junction_deviation: 0.02
|
||||||
# Distance (in mm) used to control the internal approximated
|
# Distance (in mm) used to control the internal approximated
|
||||||
# centripetal velocity cornering algorithm. A larger number will
|
# centripetal velocity cornering algorithm. A larger number will
|
||||||
# permit higher "cornering speeds" at the junction of two moves.
|
# permit higher "cornering speeds" at the junction of two moves. The
|
||||||
|
# default is 0.02mm.
|
||||||
|
|
||||||
|
|
||||||
|
# Looking for more options? Check the example-extras.cfg file.
|
||||||
|
|||||||
86
config/generic-cramps.cfg
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
# This file contains an example configuration for a Beaglebone PRU
|
||||||
|
# micro-controller attached to a CRAMPS board.
|
||||||
|
|
||||||
|
# THIS FILE HAS NOT BEEN TESTED - PROCEED WITH CAUTION!
|
||||||
|
|
||||||
|
# NOTE: Klipper does not alter the input/output state of the
|
||||||
|
# Beaglebone pins and it does not control their pull-up resistors. In
|
||||||
|
# order to set the pin state one must use a "device tree overlay" or
|
||||||
|
# use the config-pin program.
|
||||||
|
|
||||||
|
# See the example.cfg file for a description of available parameters.
|
||||||
|
|
||||||
|
[stepper_x]
|
||||||
|
step_pin: P8_13
|
||||||
|
dir_pin: P8_12
|
||||||
|
enable_pin: !P9_14
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^P8_8
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 200
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_y]
|
||||||
|
step_pin: P8_15
|
||||||
|
dir_pin: P8_14
|
||||||
|
enable_pin: !P9_14
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^P8_10
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 200
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_z]
|
||||||
|
step_pin: P8_19
|
||||||
|
dir_pin: P8_18
|
||||||
|
enable_pin: !P9_14
|
||||||
|
step_distance: .0025
|
||||||
|
endstop_pin: ^P9_13
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 200
|
||||||
|
|
||||||
|
[extruder]
|
||||||
|
step_pin: P9_16
|
||||||
|
dir_pin: P9_12
|
||||||
|
enable_pin: !P9_14
|
||||||
|
step_distance: .002
|
||||||
|
nozzle_diameter: 0.400
|
||||||
|
filament_diameter: 1.750
|
||||||
|
heater_pin: P9_15
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
pullup_resistor: 2000
|
||||||
|
sensor_pin: P9_36
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 22.2
|
||||||
|
pid_Ki: 1.08
|
||||||
|
pid_Kd: 114
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 250
|
||||||
|
|
||||||
|
[heater_bed]
|
||||||
|
heater_pin: P8_11
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
pullup_resistor: 2000
|
||||||
|
sensor_pin: P9_33
|
||||||
|
control: watermark
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 130
|
||||||
|
|
||||||
|
[fan]
|
||||||
|
pin: P9_41
|
||||||
|
|
||||||
|
[mcu]
|
||||||
|
serial: /dev/rpmsg_pru30
|
||||||
|
pin_map: beaglebone
|
||||||
|
|
||||||
|
[printer]
|
||||||
|
kinematics: cartesian
|
||||||
|
max_velocity: 300
|
||||||
|
max_accel: 3000
|
||||||
|
max_z_velocity: 5
|
||||||
|
max_z_accel: 100
|
||||||
|
|
||||||
|
[output_pin machine_enable]
|
||||||
|
pin: P9_23
|
||||||
|
value: 1
|
||||||
|
shutdown_value: 0
|
||||||
79
config/generic-melzi.cfg
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
# This file contains common pin mappings for Melzi v2.0 boards. To use
|
||||||
|
# this config, the firmware should be compiled for the AVR
|
||||||
|
# atmega1284p.
|
||||||
|
|
||||||
|
# Note, a number of Melzi boards are shipped without a bootloader. In
|
||||||
|
# that case, an external programmer will be needed to flash a
|
||||||
|
# bootloader to the board (for example, see
|
||||||
|
# http://www.instructables.com/id/Flashing-a-Bootloader-to-the-CR-10/
|
||||||
|
# ). Once that is done, one should be able to use the standard "make
|
||||||
|
# flash" command to flash Klipper.
|
||||||
|
|
||||||
|
# See the example.cfg file for a description of available parameters.
|
||||||
|
|
||||||
|
[stepper_x]
|
||||||
|
step_pin: PD7
|
||||||
|
dir_pin: PC5
|
||||||
|
enable_pin: !PD6
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^!PC2
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 200
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_y]
|
||||||
|
step_pin: PC6
|
||||||
|
dir_pin: PC7
|
||||||
|
enable_pin: !PD6
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^!PC3
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 200
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_z]
|
||||||
|
step_pin: PB3
|
||||||
|
dir_pin: !PB2
|
||||||
|
enable_pin: !PA5
|
||||||
|
step_distance: .0025
|
||||||
|
endstop_pin: ^!PC4
|
||||||
|
position_endstop: 0.5
|
||||||
|
position_max: 200
|
||||||
|
|
||||||
|
[extruder]
|
||||||
|
step_pin: PB1
|
||||||
|
dir_pin: PB0
|
||||||
|
enable_pin: !PD6
|
||||||
|
step_distance: .002
|
||||||
|
nozzle_diameter: 0.400
|
||||||
|
filament_diameter: 1.750
|
||||||
|
heater_pin: PD5
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: PA7
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 22.2
|
||||||
|
pid_Ki: 1.08
|
||||||
|
pid_Kd: 114
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 250
|
||||||
|
|
||||||
|
[heater_bed]
|
||||||
|
heater_pin: PD2
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: PA6
|
||||||
|
control: watermark
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 130
|
||||||
|
|
||||||
|
[fan]
|
||||||
|
pin: PB4
|
||||||
|
|
||||||
|
[mcu]
|
||||||
|
serial: /dev/ttyUSB0
|
||||||
|
|
||||||
|
[printer]
|
||||||
|
kinematics: cartesian
|
||||||
|
max_velocity: 300
|
||||||
|
max_accel: 3000
|
||||||
|
max_z_velocity: 5
|
||||||
|
max_z_accel: 100
|
||||||
109
config/generic-mini-rambo.cfg
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
# This file contains common pin mappings for Mini-RAMBo boards. To use
|
||||||
|
# this config, the firmware should be compiled for the AVR atmega2560.
|
||||||
|
|
||||||
|
# See the example.cfg file for a description of available parameters.
|
||||||
|
|
||||||
|
[stepper_x]
|
||||||
|
step_pin: PC0
|
||||||
|
dir_pin: PL1
|
||||||
|
enable_pin: !PA7
|
||||||
|
step_distance: .005
|
||||||
|
endstop_pin: ^PB6
|
||||||
|
#endstop_pin: ^PC7
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 250
|
||||||
|
|
||||||
|
[stepper_y]
|
||||||
|
step_pin: PC1
|
||||||
|
dir_pin: !PL0
|
||||||
|
enable_pin: !PA6
|
||||||
|
step_distance: .005
|
||||||
|
endstop_pin: ^PB5
|
||||||
|
#endstop_pin: ^PA2
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 210
|
||||||
|
|
||||||
|
[stepper_z]
|
||||||
|
step_pin: PC2
|
||||||
|
dir_pin: PL2
|
||||||
|
enable_pin: !PA5
|
||||||
|
step_distance: .0025
|
||||||
|
endstop_pin: ^PB4
|
||||||
|
#endstop_pin: ^PA1
|
||||||
|
position_endstop: 0.5
|
||||||
|
position_max: 200
|
||||||
|
|
||||||
|
[extruder]
|
||||||
|
step_pin: PC3
|
||||||
|
dir_pin: PL6
|
||||||
|
enable_pin: !PA4
|
||||||
|
step_distance: .002
|
||||||
|
nozzle_diameter: 0.400
|
||||||
|
filament_diameter: 1.750
|
||||||
|
heater_pin: PE5
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: PF0
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 22.2
|
||||||
|
pid_Ki: 1.08
|
||||||
|
pid_Kd: 114
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 250
|
||||||
|
|
||||||
|
[heater_bed]
|
||||||
|
heater_pin: PG5
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: PF2
|
||||||
|
control: watermark
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 130
|
||||||
|
|
||||||
|
[fan]
|
||||||
|
pin: PH5
|
||||||
|
|
||||||
|
#[heater_fan nozzle_cooling_fan]
|
||||||
|
#pin: PH3
|
||||||
|
|
||||||
|
[mcu]
|
||||||
|
serial: /dev/ttyACM0
|
||||||
|
|
||||||
|
[printer]
|
||||||
|
kinematics: cartesian
|
||||||
|
max_velocity: 300
|
||||||
|
max_accel: 3000
|
||||||
|
max_z_velocity: 5
|
||||||
|
max_z_accel: 100
|
||||||
|
|
||||||
|
[output_pin stepper_xy_current]
|
||||||
|
pin: PL3
|
||||||
|
pwm: True
|
||||||
|
scale: 2.0
|
||||||
|
cycle_time: .002
|
||||||
|
hardware_pwm: True
|
||||||
|
static_value: 1.3
|
||||||
|
|
||||||
|
[output_pin stepper_z_current]
|
||||||
|
pin: PL4
|
||||||
|
pwm: True
|
||||||
|
scale: 2.0
|
||||||
|
cycle_time: .002
|
||||||
|
hardware_pwm: True
|
||||||
|
static_value: 1.3
|
||||||
|
|
||||||
|
[output_pin stepper_e_current]
|
||||||
|
pin: PL5
|
||||||
|
pwm: True
|
||||||
|
scale: 2.0
|
||||||
|
cycle_time: .002
|
||||||
|
hardware_pwm: True
|
||||||
|
static_value: 1.25
|
||||||
|
|
||||||
|
[static_digital_output stepper_config]
|
||||||
|
pins:
|
||||||
|
PG1, PG0,
|
||||||
|
PK7, PG2,
|
||||||
|
PK6, PK5,
|
||||||
|
PK3, PK4
|
||||||
|
|
||||||
|
[static_digital_output yellow_led]
|
||||||
|
pins: !PB7
|
||||||
76
config/generic-printrboard.cfg
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
# This file contains common pin mappings for Printrboard boards (rev B
|
||||||
|
# through D). To use this config the firmware should be compiled for
|
||||||
|
# the AVR at90usb1286.
|
||||||
|
|
||||||
|
# Note that the "make flash" command is unlikely to work on the
|
||||||
|
# Printrboard. See the RepRap Printrboard wiki page for instructions
|
||||||
|
# on flashing.
|
||||||
|
|
||||||
|
# See the example.cfg file for a description of available parameters.
|
||||||
|
|
||||||
|
[stepper_x]
|
||||||
|
step_pin: PA0
|
||||||
|
dir_pin: !PA1
|
||||||
|
enable_pin: !PE7
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^PE3
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 200
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_y]
|
||||||
|
step_pin: PA2
|
||||||
|
dir_pin: PA3
|
||||||
|
enable_pin: !PE6
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^PB0
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 200
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_z]
|
||||||
|
step_pin: PA4
|
||||||
|
dir_pin: !PA5
|
||||||
|
enable_pin: !PC7
|
||||||
|
step_distance: .0025
|
||||||
|
endstop_pin: ^PE4
|
||||||
|
position_endstop: 0.5
|
||||||
|
position_max: 200
|
||||||
|
|
||||||
|
[extruder]
|
||||||
|
step_pin: PA6
|
||||||
|
dir_pin: PA7
|
||||||
|
enable_pin: !PC3
|
||||||
|
step_distance: .002
|
||||||
|
nozzle_diameter: 0.400
|
||||||
|
filament_diameter: 1.750
|
||||||
|
heater_pin: PC5
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: PF1
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 22.2
|
||||||
|
pid_Ki: 1.08
|
||||||
|
pid_Kd: 114
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 250
|
||||||
|
|
||||||
|
[heater_bed]
|
||||||
|
heater_pin: PC4
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: PF0
|
||||||
|
control: watermark
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 130
|
||||||
|
|
||||||
|
[fan]
|
||||||
|
pin: PC6
|
||||||
|
|
||||||
|
[mcu]
|
||||||
|
serial: /dev/ttyACM0
|
||||||
|
|
||||||
|
[printer]
|
||||||
|
kinematics: cartesian
|
||||||
|
max_velocity: 300
|
||||||
|
max_accel: 3000
|
||||||
|
max_z_velocity: 5
|
||||||
|
max_z_accel: 100
|
||||||
126
config/generic-rambo.cfg
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
# This file contains common pin mappings for RAMBo boards. To use this
|
||||||
|
# config, the firmware should be compiled for the AVR atmega2560.
|
||||||
|
|
||||||
|
# See the example.cfg file for a description of available parameters.
|
||||||
|
|
||||||
|
[stepper_x]
|
||||||
|
step_pin: PC0
|
||||||
|
dir_pin: PL1
|
||||||
|
enable_pin: !PA7
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^PB6
|
||||||
|
#endstop_pin: ^PA2
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 200
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_y]
|
||||||
|
step_pin: PC1
|
||||||
|
dir_pin: !PL0
|
||||||
|
enable_pin: !PA6
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^PB5
|
||||||
|
#endstop_pin: ^PA1
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 200
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_z]
|
||||||
|
step_pin: PC2
|
||||||
|
dir_pin: PL2
|
||||||
|
enable_pin: !PA5
|
||||||
|
step_distance: .0025
|
||||||
|
endstop_pin: ^PB4
|
||||||
|
#endstop_pin: ^PC7
|
||||||
|
position_endstop: 0.5
|
||||||
|
position_max: 200
|
||||||
|
|
||||||
|
[extruder]
|
||||||
|
step_pin: PC3
|
||||||
|
dir_pin: PL6
|
||||||
|
enable_pin: !PA4
|
||||||
|
step_distance: .002
|
||||||
|
nozzle_diameter: 0.400
|
||||||
|
filament_diameter: 1.750
|
||||||
|
heater_pin: PH6
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: PF0
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 22.2
|
||||||
|
pid_Ki: 1.08
|
||||||
|
pid_Kd: 114
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 250
|
||||||
|
|
||||||
|
#[extruder1]
|
||||||
|
#step_pin: PC4
|
||||||
|
#dir_pin: PL7
|
||||||
|
#enable_pin: !PA3
|
||||||
|
#heater_pin: PH4
|
||||||
|
#sensor_pin: PF1
|
||||||
|
#...
|
||||||
|
|
||||||
|
[heater_bed]
|
||||||
|
heater_pin: PE5
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: PF2
|
||||||
|
control: watermark
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 130
|
||||||
|
|
||||||
|
[fan]
|
||||||
|
pin: PH5
|
||||||
|
|
||||||
|
#[heater_fan nozzle_cooling_fan]
|
||||||
|
#pin: PH3
|
||||||
|
|
||||||
|
[mcu]
|
||||||
|
serial: /dev/ttyACM0
|
||||||
|
|
||||||
|
[printer]
|
||||||
|
kinematics: cartesian
|
||||||
|
max_velocity: 300
|
||||||
|
max_accel: 3000
|
||||||
|
max_z_velocity: 5
|
||||||
|
max_z_accel: 100
|
||||||
|
|
||||||
|
[ad5206 stepper_digipot]
|
||||||
|
enable_pin: PD7
|
||||||
|
# Scale the config so that the channel value can be specified in amps.
|
||||||
|
# (For Rambo v1.0d boards, use 1.56 instead.)
|
||||||
|
scale: 2.08
|
||||||
|
# Channel 1 is E0, 2 is E1, 3 is unused, 4 is Z, 5 is X, 6 is Y
|
||||||
|
channel_1: 1.34
|
||||||
|
channel_2: 1.0
|
||||||
|
channel_4: 1.1
|
||||||
|
channel_5: 1.1
|
||||||
|
channel_6: 1.1
|
||||||
|
|
||||||
|
# Enable 16 micro-steps on steppers X, Y, Z, E0, E1
|
||||||
|
[static_digital_output stepper_config]
|
||||||
|
pins:
|
||||||
|
PG1, PG0,
|
||||||
|
PK7, PG2,
|
||||||
|
PK6, PK5,
|
||||||
|
PK3, PK4,
|
||||||
|
PK1, PK2
|
||||||
|
|
||||||
|
[static_digital_output yellow_led]
|
||||||
|
pins: !PB7
|
||||||
|
|
||||||
|
# "RepRapDiscount 2004 Smart Controller" type displays
|
||||||
|
#[display]
|
||||||
|
#lcd_type: hd44780
|
||||||
|
#rs_pin: PG4
|
||||||
|
#e_pin: PG3
|
||||||
|
#d4_pin: PJ2
|
||||||
|
#d5_pin: PJ3
|
||||||
|
#d6_pin: PJ7
|
||||||
|
#d7_pin: PJ4
|
||||||
|
|
||||||
|
# "RepRapDiscount 128x64 Full Graphic Smart Controller" type displays
|
||||||
|
#[display]
|
||||||
|
#lcd_type: st7920
|
||||||
|
#cs_pin: PG4
|
||||||
|
#sclk_pin: PJ2
|
||||||
|
#sid_pin: PG3
|
||||||
101
config/generic-ramps.cfg
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
# This file contains common pin mappings for RAMPS (v1.3 and later)
|
||||||
|
# boards. RAMPS boards typically use a firmware compiled for the AVR
|
||||||
|
# atmega2560 (though other AVR chips are also possible).
|
||||||
|
|
||||||
|
# See the example.cfg file for a description of available parameters.
|
||||||
|
|
||||||
|
[stepper_x]
|
||||||
|
step_pin: ar54
|
||||||
|
dir_pin: ar55
|
||||||
|
enable_pin: !ar38
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^ar3
|
||||||
|
#endstop_pin: ^ar2
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 200
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_y]
|
||||||
|
step_pin: ar60
|
||||||
|
dir_pin: !ar61
|
||||||
|
enable_pin: !ar56
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^ar14
|
||||||
|
#endstop_pin: ^ar15
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 200
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_z]
|
||||||
|
step_pin: ar46
|
||||||
|
dir_pin: ar48
|
||||||
|
enable_pin: !ar62
|
||||||
|
step_distance: .0025
|
||||||
|
endstop_pin: ^ar18
|
||||||
|
#endstop_pin: ^ar19
|
||||||
|
position_endstop: 0.5
|
||||||
|
position_max: 200
|
||||||
|
|
||||||
|
[extruder]
|
||||||
|
step_pin: ar26
|
||||||
|
dir_pin: ar28
|
||||||
|
enable_pin: !ar24
|
||||||
|
step_distance: .002
|
||||||
|
nozzle_diameter: 0.400
|
||||||
|
filament_diameter: 1.750
|
||||||
|
heater_pin: ar10
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: analog13
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 22.2
|
||||||
|
pid_Ki: 1.08
|
||||||
|
pid_Kd: 114
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 250
|
||||||
|
|
||||||
|
#[extruder1]
|
||||||
|
#step_pin: ar36
|
||||||
|
#dir_pin: ar34
|
||||||
|
#enable_pin: !ar30
|
||||||
|
#heater_pin: ar9
|
||||||
|
#sensor_pin: analog15
|
||||||
|
#...
|
||||||
|
|
||||||
|
[heater_bed]
|
||||||
|
heater_pin: ar8
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: analog14
|
||||||
|
control: watermark
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 130
|
||||||
|
|
||||||
|
[fan]
|
||||||
|
pin: ar9
|
||||||
|
|
||||||
|
[mcu]
|
||||||
|
serial: /dev/ttyACM0
|
||||||
|
pin_map: arduino
|
||||||
|
|
||||||
|
[printer]
|
||||||
|
kinematics: cartesian
|
||||||
|
max_velocity: 300
|
||||||
|
max_accel: 3000
|
||||||
|
max_z_velocity: 5
|
||||||
|
max_z_accel: 100
|
||||||
|
|
||||||
|
# "RepRapDiscount 2004 Smart Controller" type displays
|
||||||
|
#[display]
|
||||||
|
#lcd_type: hd44780
|
||||||
|
#rs_pin: ar16
|
||||||
|
#e_pin: ar17
|
||||||
|
#d4_pin: ar23
|
||||||
|
#d5_pin: ar25
|
||||||
|
#d6_pin: ar27
|
||||||
|
#d7_pin: ar29
|
||||||
|
|
||||||
|
# "RepRapDiscount 128x64 Full Graphic Smart Controller" type displays
|
||||||
|
#[display]
|
||||||
|
#lcd_type: st7920
|
||||||
|
#cs_pin: ar16
|
||||||
|
#sclk_pin: ar23
|
||||||
|
#sid_pin: ar17
|
||||||
134
config/generic-replicape.cfg
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
# This file contains an example configuration for the Replicape rev B3
|
||||||
|
# board. To use this config, one must compile and install the
|
||||||
|
# micro-controller code for the "Beaglebone PRU", and then compile and
|
||||||
|
# install the micro-controller code a second time for a "Linux
|
||||||
|
# process".
|
||||||
|
|
||||||
|
# NOTE: Klipper does not alter the input/output state of the
|
||||||
|
# Beaglebone pins and it does not control their pull-up resistors.
|
||||||
|
# Typically the correct settings are automatically applied when the
|
||||||
|
# Beaglebone detects the Replicape board, but if changes are needed
|
||||||
|
# they must be specified in a "device tree overlay" or via the
|
||||||
|
# config-pin program.
|
||||||
|
|
||||||
|
# See the example.cfg file for a description of available parameters.
|
||||||
|
|
||||||
|
[mcu]
|
||||||
|
serial: /dev/rpmsg_pru30
|
||||||
|
pin_map: beaglebone
|
||||||
|
|
||||||
|
[mcu host]
|
||||||
|
serial: /tmp/klipper_host_mcu
|
||||||
|
|
||||||
|
# The "replicape" config section adds "replicape:stepper_x_enable"
|
||||||
|
# virtual stepper enable pins (for steppers x, y, z, e, and h) and
|
||||||
|
# "replicape:power_x" PWM output pins (for hotbed, e, h, fan0, fan1,
|
||||||
|
# fan2, and fan3) that may then be used elsewhere in the config file.
|
||||||
|
[replicape]
|
||||||
|
revision: B3
|
||||||
|
# The replicape hardware revision. Currently only revision "B3" is
|
||||||
|
# supported. This parameter must be provided.
|
||||||
|
#enable_pin: !P9_41
|
||||||
|
# The replicape global enable pin. The default is !P9_41.
|
||||||
|
host_mcu: host
|
||||||
|
# The name of the mcu config section that communicates with the
|
||||||
|
# Klipper "linux process" mcu instance. This parameter must be
|
||||||
|
# provided.
|
||||||
|
#standstill_power_down: False
|
||||||
|
# This parameter controls the CFG6_ENN line on all stepper
|
||||||
|
# motors. True sets the enable lines to "open". The default is
|
||||||
|
# False.
|
||||||
|
#servo0_enable: False
|
||||||
|
# This parameter controls whether end_stop_X_2 is used for endstops
|
||||||
|
# (via P9_11) or for servo_0 (via P9_14). The default is False.
|
||||||
|
#servo1_enable: False
|
||||||
|
# This parameter controls whether end_stop_Y_2 is used for endstops
|
||||||
|
# (via P9_28) or for servo_1 (via P9_16). The default is False.
|
||||||
|
stepper_x_microstep_mode: spread16
|
||||||
|
# This parameter controls the CFG1 and CFG2 pins of the given
|
||||||
|
# stepper motor driver. Available options are: disable, 1, 2,
|
||||||
|
# spread2, 4, 16, spread4, spread16, stealth4, and stealth16. The
|
||||||
|
# default is disable.
|
||||||
|
stepper_x_current: 0.5
|
||||||
|
# The configured maximum current (in Amps) of the stepper motor
|
||||||
|
# driver. This parameter must be provided if the stepper is not in a
|
||||||
|
# disable mode.
|
||||||
|
#stepper_x_chopper_off_time_high: False
|
||||||
|
# This parameter controls the CFG0 pin of the stepper motor driver
|
||||||
|
# (True sets CFG0 high, False sets it low). The default is False.
|
||||||
|
#stepper_x_chopper_hysteresis_high: False
|
||||||
|
# This parameter controls the CFG4 pin of the stepper motor driver
|
||||||
|
# (True sets CFG4 high, False sets it low). The default is False.
|
||||||
|
#stepper_x_chopper_blank_time_high: True
|
||||||
|
# This parameter controls the CFG5 pin of the stepper motor driver
|
||||||
|
# (True sets CFG5 high, False sets it low). The default is True.
|
||||||
|
stepper_y_microstep_mode: spread16
|
||||||
|
stepper_y_current: 0.5
|
||||||
|
stepper_z_microstep_mode: spread16
|
||||||
|
stepper_z_current: 0.5
|
||||||
|
stepper_e_microstep_mode: 16
|
||||||
|
stepper_e_current: 0.5
|
||||||
|
|
||||||
|
[stepper_x]
|
||||||
|
step_pin: P8_17
|
||||||
|
dir_pin: P8_26
|
||||||
|
enable_pin: replicape:stepper_x_enable
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^P9_25
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 200
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_y]
|
||||||
|
step_pin: P8_12
|
||||||
|
dir_pin: P8_19
|
||||||
|
enable_pin: replicape:stepper_y_enable
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^P9_23
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 200
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_z]
|
||||||
|
step_pin: P8_13
|
||||||
|
dir_pin: P8_14
|
||||||
|
enable_pin: replicape:stepper_z_enable
|
||||||
|
step_distance: .0025
|
||||||
|
endstop_pin: ^P9_13
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 200
|
||||||
|
|
||||||
|
[printer]
|
||||||
|
kinematics: cartesian
|
||||||
|
max_velocity: 300
|
||||||
|
max_accel: 3000
|
||||||
|
max_z_velocity: 25
|
||||||
|
max_z_accel: 30
|
||||||
|
|
||||||
|
[extruder]
|
||||||
|
step_pin: P9_12
|
||||||
|
dir_pin: P8_15
|
||||||
|
enable_pin: replicape:stepper_e_enable
|
||||||
|
step_distance: .002
|
||||||
|
nozzle_diameter: 0.400
|
||||||
|
filament_diameter: 1.750
|
||||||
|
heater_pin: replicape:power_e
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: host:analog4
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 22.2
|
||||||
|
pid_Ki: 1.08
|
||||||
|
pid_Kd: 114
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 250
|
||||||
|
|
||||||
|
[heater_bed]
|
||||||
|
heater_pin: replicape:power_hotbed
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: host:analog6
|
||||||
|
control: watermark
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 130
|
||||||
|
|
||||||
|
[fan]
|
||||||
|
pin: replicape:power_fan0
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
# Support for Makergear M2 printers circa 2012 that have the RAMBo
|
|
||||||
# v1.0d electronics. The electronics use Allegro A4984 stepper
|
|
||||||
# drivers with 1/8th micro-stepping. To use this config, the firmware
|
|
||||||
# should be compiled for the AVR atmega2560.
|
|
||||||
|
|
||||||
[stepper_x]
|
|
||||||
step_pin: PC0
|
|
||||||
dir_pin: PL1
|
|
||||||
enable_pin: !PA7
|
|
||||||
step_distance: .0225
|
|
||||||
max_velocity: 500
|
|
||||||
max_accel: 3000
|
|
||||||
endstop_pin: ^PB6
|
|
||||||
homing_speed: 50.0
|
|
||||||
position_min: -0.25
|
|
||||||
position_endstop: 0.0
|
|
||||||
position_max: 200
|
|
||||||
|
|
||||||
[stepper_y]
|
|
||||||
step_pin: PC1
|
|
||||||
dir_pin: !PL0
|
|
||||||
enable_pin: !PA6
|
|
||||||
step_distance: .0225
|
|
||||||
max_velocity: 500
|
|
||||||
max_accel: 3000
|
|
||||||
endstop_pin: ^PB5
|
|
||||||
homing_speed: 50.0
|
|
||||||
position_min: -0.25
|
|
||||||
position_endstop: 0.0
|
|
||||||
position_max: 250
|
|
||||||
|
|
||||||
[stepper_z]
|
|
||||||
step_pin: PC2
|
|
||||||
dir_pin: PL2
|
|
||||||
enable_pin: !PA5
|
|
||||||
step_distance: .005
|
|
||||||
max_velocity: 250
|
|
||||||
max_accel: 30
|
|
||||||
endstop_pin: ^PB4
|
|
||||||
homing_speed: 4.0
|
|
||||||
homing_retract_dist: 2.0
|
|
||||||
position_min: 0.1
|
|
||||||
position_endstop: 0.7
|
|
||||||
position_max: 200
|
|
||||||
|
|
||||||
[stepper_e]
|
|
||||||
step_pin: PC3
|
|
||||||
dir_pin: !PL6
|
|
||||||
enable_pin: !PA4
|
|
||||||
step_distance: .004242
|
|
||||||
max_velocity: 200000
|
|
||||||
max_accel: 3000
|
|
||||||
|
|
||||||
[heater_nozzle]
|
|
||||||
heater_pin: PH6
|
|
||||||
thermistor_pin: PF0
|
|
||||||
thermistor_type: EPCOS 100K B57560G104F
|
|
||||||
control: pid
|
|
||||||
pid_Kp: 7.0
|
|
||||||
pid_Ki: 0.1
|
|
||||||
pid_Kd: 12
|
|
||||||
min_temp: 0
|
|
||||||
max_temp: 210
|
|
||||||
|
|
||||||
[heater_bed]
|
|
||||||
heater_pin: PE5
|
|
||||||
thermistor_pin: PF2
|
|
||||||
thermistor_type: EPCOS 100K B57560G104F
|
|
||||||
control: watermark
|
|
||||||
min_temp: 0
|
|
||||||
max_temp: 100
|
|
||||||
|
|
||||||
[fan]
|
|
||||||
pin: PH5
|
|
||||||
hard_pwm: 1
|
|
||||||
|
|
||||||
[mcu]
|
|
||||||
serial: /dev/ttyACM0
|
|
||||||
baud: 250000
|
|
||||||
custom:
|
|
||||||
# Nozzle fan
|
|
||||||
set_pwm_out pin=PH3 cycle_ticks=1 value=155
|
|
||||||
# Turn off yellow led
|
|
||||||
set_digital_out pin=PB7 value=0
|
|
||||||
# Stepper micro-step pins
|
|
||||||
set_digital_out pin=PG1 value=1
|
|
||||||
set_digital_out pin=PG0 value=1
|
|
||||||
set_digital_out pin=PK7 value=1
|
|
||||||
set_digital_out pin=PG2 value=1
|
|
||||||
set_digital_out pin=PK6 value=1
|
|
||||||
set_digital_out pin=PK5 value=1
|
|
||||||
set_digital_out pin=PK3 value=1
|
|
||||||
set_digital_out pin=PK4 value=1
|
|
||||||
# Initialize digipot
|
|
||||||
send_spi_message pin=PD7 msg=0487 # X = ~0.75A
|
|
||||||
send_spi_message pin=PD7 msg=0587 # Y = ~0.75A
|
|
||||||
send_spi_message pin=PD7 msg=0387 # Z = ~0.75A
|
|
||||||
send_spi_message pin=PD7 msg=00A5 # E0
|
|
||||||
send_spi_message pin=PD7 msg=017D # E1
|
|
||||||
|
|
||||||
[printer]
|
|
||||||
kinematics: cartesian
|
|
||||||
motor_off_time: 600
|
|
||||||
79
config/printer-anet-a8-2017.cfg
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
# This file contains common pin mappings for Anet A8 printer from 2016
|
||||||
|
# and 2017. To use this config, the firmware should be compiled for
|
||||||
|
# the AVR atmega1284p.
|
||||||
|
|
||||||
|
# Note that the "make flash" command does not work with Anet boards -
|
||||||
|
# the boards are typically flashed with this command:
|
||||||
|
# avrdude -p atmega1284p -c arduino -b 57600 -P /dev/ttyUSB0 -U out/klipper.elf.hex
|
||||||
|
|
||||||
|
# See the example.cfg file for a description of available parameters.
|
||||||
|
|
||||||
|
[stepper_x]
|
||||||
|
step_pin: PD7
|
||||||
|
dir_pin: PC5
|
||||||
|
enable_pin: !PD6
|
||||||
|
step_distance: .01
|
||||||
|
endstop_pin: ^!PC2
|
||||||
|
position_endstop: -30
|
||||||
|
position_max: 220
|
||||||
|
position_min: -30
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_y]
|
||||||
|
step_pin: PC6
|
||||||
|
dir_pin: PC7
|
||||||
|
enable_pin: !PD6
|
||||||
|
step_distance: .01
|
||||||
|
endstop_pin: ^!PC3
|
||||||
|
position_endstop: -8
|
||||||
|
position_min: -8
|
||||||
|
position_max: 220
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_z]
|
||||||
|
step_pin: PB3
|
||||||
|
dir_pin: !PB2
|
||||||
|
enable_pin: !PA5
|
||||||
|
step_distance: .0025
|
||||||
|
endstop_pin: ^!PC4
|
||||||
|
position_endstop: 0.5
|
||||||
|
position_max: 240
|
||||||
|
homing_speed: 20
|
||||||
|
|
||||||
|
[extruder]
|
||||||
|
step_pin: PB1
|
||||||
|
dir_pin: PB0
|
||||||
|
enable_pin: !PD6
|
||||||
|
step_distance: .0105
|
||||||
|
nozzle_diameter: 0.400
|
||||||
|
filament_diameter: 1.750
|
||||||
|
heater_pin: PD5
|
||||||
|
sensor_type: ATC Semitec 104GT-2
|
||||||
|
sensor_pin: PA7
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 2.151492
|
||||||
|
pid_Ki: 0.633897
|
||||||
|
pid_Kd: 230.042965
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 250
|
||||||
|
|
||||||
|
[heater_bed]
|
||||||
|
heater_pin: PD4
|
||||||
|
sensor_type: ATC Semitec 104GT-2
|
||||||
|
sensor_pin: PA6
|
||||||
|
control: watermark
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 130
|
||||||
|
|
||||||
|
[fan]
|
||||||
|
pin: PB4
|
||||||
|
|
||||||
|
[mcu]
|
||||||
|
serial: /dev/ttyUSB0
|
||||||
|
|
||||||
|
[printer]
|
||||||
|
kinematics: cartesian
|
||||||
|
max_velocity: 300
|
||||||
|
max_accel: 1000
|
||||||
|
max_z_velocity: 20
|
||||||
|
max_z_accel: 100
|
||||||
93
config/printer-anycubic-i3-mega-2017.cfg
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
# This file contains pin mappings for the Anycubic i3 Mega with
|
||||||
|
# Ultrabase from 2017. (This config may work on an Anycubic i3 Mega v1
|
||||||
|
# prior to the Ultrabase if you comment out the definition of the
|
||||||
|
# endstop_pin in the stepper_z1 section.) To use this config, the
|
||||||
|
# firmware should be compiled for the AVR atmega2560.
|
||||||
|
|
||||||
|
# See the example.cfg file for a description of available parameters.
|
||||||
|
|
||||||
|
[stepper_x]
|
||||||
|
step_pin: ar54
|
||||||
|
dir_pin: !ar55
|
||||||
|
enable_pin: !ar38
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^!ar3
|
||||||
|
position_min: -5
|
||||||
|
position_endstop: -5
|
||||||
|
position_max: 210
|
||||||
|
homing_speed: 30.0
|
||||||
|
|
||||||
|
[stepper_y]
|
||||||
|
step_pin: ar60
|
||||||
|
dir_pin: ar61
|
||||||
|
enable_pin: !ar56
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^!ar42
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 210
|
||||||
|
homing_speed: 30.0
|
||||||
|
|
||||||
|
[stepper_z]
|
||||||
|
step_pin: ar46
|
||||||
|
dir_pin: ar48
|
||||||
|
enable_pin: !ar62
|
||||||
|
step_distance: .0025
|
||||||
|
endstop_pin: ^!ar18
|
||||||
|
position_endstop: 0.0
|
||||||
|
position_max: 205
|
||||||
|
homing_speed: 5.0
|
||||||
|
|
||||||
|
[stepper_z1]
|
||||||
|
step_pin: ar36
|
||||||
|
dir_pin: ar34
|
||||||
|
enable_pin: !ar30
|
||||||
|
step_distance: .0025
|
||||||
|
endstop_pin: ^!ar43
|
||||||
|
|
||||||
|
[extruder]
|
||||||
|
step_pin: ar26
|
||||||
|
dir_pin: ar28
|
||||||
|
enable_pin: !ar24
|
||||||
|
step_distance: .010799
|
||||||
|
nozzle_diameter: 0.400
|
||||||
|
filament_diameter: 1.750
|
||||||
|
heater_pin: ar10
|
||||||
|
sensor_type: ATC Semitec 104GT-2
|
||||||
|
sensor_pin: analog13
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 15.717
|
||||||
|
pid_Ki: 0.569
|
||||||
|
pid_Kd: 108.451
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 245
|
||||||
|
|
||||||
|
[heater_fan extruder_fan]
|
||||||
|
pin: ar44
|
||||||
|
|
||||||
|
[heater_bed]
|
||||||
|
heater_pin: ar8
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: analog14
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 74.883
|
||||||
|
pid_Ki: 1.809
|
||||||
|
pid_Kd: 775.038
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 110
|
||||||
|
|
||||||
|
[fan]
|
||||||
|
pin: ar9
|
||||||
|
|
||||||
|
[mcu]
|
||||||
|
serial: /dev/ttyUSB0
|
||||||
|
pin_map: arduino
|
||||||
|
|
||||||
|
[printer]
|
||||||
|
kinematics: cartesian
|
||||||
|
max_velocity: 300
|
||||||
|
max_accel: 3000
|
||||||
|
max_z_velocity: 10
|
||||||
|
max_z_accel: 60
|
||||||
|
|
||||||
|
[heater_fan stepstick_fan]
|
||||||
|
pin: ar7
|
||||||
88
config/printer-creality-cr10-2017.cfg
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
# This file contains common pin mappings for the 2017 Creality
|
||||||
|
# CR-10. To use this config, the firmware should be compiled for the
|
||||||
|
# AVR atmega1284p.
|
||||||
|
|
||||||
|
# Note, a number of Melzi boards are shipped without a bootloader. In
|
||||||
|
# that case, an external programmer will be needed to flash a
|
||||||
|
# bootloader to the board (for example, see
|
||||||
|
# http://www.instructables.com/id/Flashing-a-Bootloader-to-the-CR-10/
|
||||||
|
# ). Once that is done, one should be able to use the standard "make
|
||||||
|
# flash" command to flash Klipper.
|
||||||
|
|
||||||
|
# See the example.cfg file for a description of available parameters.
|
||||||
|
|
||||||
|
[stepper_x]
|
||||||
|
step_pin: PD7
|
||||||
|
dir_pin: !PC5
|
||||||
|
enable_pin: !PD6
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^PC2
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 300
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_y]
|
||||||
|
step_pin: PC6
|
||||||
|
dir_pin: !PC7
|
||||||
|
enable_pin: !PD6
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^PC3
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 300
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_z]
|
||||||
|
step_pin: PB3
|
||||||
|
dir_pin: PB2
|
||||||
|
enable_pin: !PA5
|
||||||
|
step_distance: .0025
|
||||||
|
endstop_pin: ^PC4
|
||||||
|
position_endstop: 0.0
|
||||||
|
position_max: 400
|
||||||
|
|
||||||
|
[extruder]
|
||||||
|
step_pin: PB1
|
||||||
|
dir_pin: !PB0
|
||||||
|
enable_pin: !PD6
|
||||||
|
step_distance: 0.010526
|
||||||
|
nozzle_diameter: 0.400
|
||||||
|
filament_diameter: 1.750
|
||||||
|
heater_pin: PD5
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: PA7
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 22.57
|
||||||
|
pid_Ki: 1.72
|
||||||
|
pid_Kd: 73.96
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 250
|
||||||
|
|
||||||
|
[heater_bed]
|
||||||
|
heater_pin: PD4
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: PA6
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 426.68
|
||||||
|
pid_Ki: 78.92
|
||||||
|
pid_Kd: 576.71
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 130
|
||||||
|
|
||||||
|
[fan]
|
||||||
|
pin: PB4
|
||||||
|
|
||||||
|
[mcu]
|
||||||
|
serial: /dev/ttyUSB0
|
||||||
|
|
||||||
|
[printer]
|
||||||
|
kinematics: cartesian
|
||||||
|
max_velocity: 300
|
||||||
|
max_accel: 3000
|
||||||
|
max_z_velocity: 5
|
||||||
|
max_z_accel: 100
|
||||||
|
|
||||||
|
[display]
|
||||||
|
lcd_type: st7920
|
||||||
|
cs_pin: PA3
|
||||||
|
sclk_pin: PA1
|
||||||
|
sid_pin: PC1
|
||||||
75
config/printer-creality-cr10s-2017.cfg
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
# This file contains pin mappings for the 2017 Creality CR-10S. To use
|
||||||
|
# this config, the firmware should be compiled for the AVR atmega2560.
|
||||||
|
|
||||||
|
# See the example.cfg file for a description of available parameters.
|
||||||
|
|
||||||
|
[stepper_x]
|
||||||
|
step_pin: ar54
|
||||||
|
dir_pin: ar55
|
||||||
|
enable_pin: !ar38
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^ar3
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 300
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_y]
|
||||||
|
step_pin: ar60
|
||||||
|
dir_pin: ar61
|
||||||
|
enable_pin: !ar56
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^ar14
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 300
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_z]
|
||||||
|
step_pin: ar46
|
||||||
|
dir_pin: !ar48
|
||||||
|
enable_pin: !ar62
|
||||||
|
step_distance: .0025
|
||||||
|
endstop_pin: ^ar18
|
||||||
|
position_endstop: 0.5
|
||||||
|
position_max: 200
|
||||||
|
|
||||||
|
[extruder]
|
||||||
|
step_pin: ar26
|
||||||
|
dir_pin: ar28
|
||||||
|
enable_pin: !ar24
|
||||||
|
step_distance: .010526
|
||||||
|
nozzle_diameter: 0.400
|
||||||
|
filament_diameter: 1.750
|
||||||
|
heater_pin: ar10
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: analog13
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 22.2
|
||||||
|
pid_Ki: 1.08
|
||||||
|
pid_Kd: 114
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 250
|
||||||
|
|
||||||
|
[heater_bed]
|
||||||
|
heater_pin: ar8
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: analog14
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 690.34
|
||||||
|
pid_Ki: 111.47
|
||||||
|
pid_Kd: 1068.83
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 130
|
||||||
|
|
||||||
|
[fan]
|
||||||
|
pin: ar9
|
||||||
|
|
||||||
|
[mcu]
|
||||||
|
serial: /dev/ttyUSB0
|
||||||
|
pin_map: arduino
|
||||||
|
|
||||||
|
[printer]
|
||||||
|
kinematics: cartesian
|
||||||
|
max_velocity: 300
|
||||||
|
max_accel: 3000
|
||||||
|
max_z_velocity: 5
|
||||||
|
max_z_accel: 100
|
||||||
116
config/printer-lulzbot-taz6-2017.cfg
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
# This file contains pin mappings for the Lulzbot TAZ 6 circa 2017. To
|
||||||
|
# use this config, the firmware should be compiled for the AVR
|
||||||
|
# atmega2560.
|
||||||
|
|
||||||
|
# See the example.cfg file for a description of available parameters.
|
||||||
|
|
||||||
|
[stepper_x]
|
||||||
|
step_pin: PC0
|
||||||
|
dir_pin: PL1
|
||||||
|
enable_pin: !PA7
|
||||||
|
step_distance: .010000
|
||||||
|
endstop_pin: ^PB6
|
||||||
|
position_endstop: -20
|
||||||
|
position_min: -20
|
||||||
|
position_max: 300
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_y]
|
||||||
|
step_pin: PC1
|
||||||
|
dir_pin: !PL0
|
||||||
|
enable_pin: !PA6
|
||||||
|
step_distance: .010000
|
||||||
|
endstop_pin: ^PA1
|
||||||
|
position_endstop: 306
|
||||||
|
position_min: -20
|
||||||
|
position_max: 306
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_z]
|
||||||
|
step_pin: PC2
|
||||||
|
dir_pin: PL2
|
||||||
|
enable_pin: !PA5
|
||||||
|
step_distance: 0.000625
|
||||||
|
endstop_pin: ^!PB4
|
||||||
|
position_endstop: -0.7
|
||||||
|
position_min: -1.5
|
||||||
|
position_max: 270
|
||||||
|
homing_speed: 1
|
||||||
|
|
||||||
|
[extruder]
|
||||||
|
step_pin: PC3
|
||||||
|
dir_pin: !PL6
|
||||||
|
enable_pin: !PA4
|
||||||
|
step_distance: 0.001182
|
||||||
|
nozzle_diameter: 0.400
|
||||||
|
filament_diameter: 2.920
|
||||||
|
heater_pin: PH6
|
||||||
|
sensor_type: ATC Semitec 104GT-2
|
||||||
|
sensor_pin: PF0
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 28.79
|
||||||
|
pid_Ki: 1.91
|
||||||
|
pid_Kd: 108.51
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 300
|
||||||
|
min_extrude_temp: 140
|
||||||
|
|
||||||
|
#[extruder1]
|
||||||
|
#step_pin: PC4
|
||||||
|
#dir_pin: PL7
|
||||||
|
#enable_pin: !PA3
|
||||||
|
#heater_pin: PH4
|
||||||
|
#sensor_pin: PF1
|
||||||
|
#...
|
||||||
|
|
||||||
|
[heater_bed]
|
||||||
|
heater_pin: PE5
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: PF2
|
||||||
|
control: watermark
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 130
|
||||||
|
|
||||||
|
[fan]
|
||||||
|
pin: PH5
|
||||||
|
|
||||||
|
[heater_fan nozzle_cooling_fan]
|
||||||
|
pin: PH3
|
||||||
|
|
||||||
|
[mcu]
|
||||||
|
serial: /dev/ttyACM0
|
||||||
|
|
||||||
|
[printer]
|
||||||
|
kinematics: cartesian
|
||||||
|
max_velocity: 300
|
||||||
|
max_accel: 3000
|
||||||
|
max_z_velocity: 2
|
||||||
|
max_z_accel: 10
|
||||||
|
|
||||||
|
[ad5206 stepper_digipot]
|
||||||
|
enable_pin: PD7
|
||||||
|
scale: 2.08
|
||||||
|
# Channel 1 is E0, 2 is E1, 3 is unused, 4 is Z, 5 is X, 6 is Y
|
||||||
|
channel_1: 1.34
|
||||||
|
channel_2: 1.0
|
||||||
|
channel_4: 1.1
|
||||||
|
channel_5: 1.1
|
||||||
|
channel_6: 1.1
|
||||||
|
|
||||||
|
# Enable 16 micro-steps on steppers X, Y, Z, E0, E1
|
||||||
|
[static_digital_output stepper_config]
|
||||||
|
pins:
|
||||||
|
PG1, PG0,
|
||||||
|
PK7, PG2,
|
||||||
|
PK6, PK5,
|
||||||
|
PK3, PK4,
|
||||||
|
PK1, PK2
|
||||||
|
|
||||||
|
[static_digital_output yellow_led]
|
||||||
|
pins: !PB7
|
||||||
|
|
||||||
|
[display]
|
||||||
|
lcd_type: st7920
|
||||||
|
cs_pin: PG4
|
||||||
|
sclk_pin: PJ2
|
||||||
|
sid_pin: PG3
|
||||||
108
config/printer-makergear-m2-2012.cfg
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
# Support for Makergear M2 printers circa 2012 that have the RAMBo
|
||||||
|
# v1.0d electronics along with the V3A extruder. The electronics use
|
||||||
|
# Allegro A4984 stepper drivers with 1/8th micro-stepping. To use
|
||||||
|
# this config, the firmware should be compiled for the AVR atmega2560.
|
||||||
|
|
||||||
|
[stepper_x]
|
||||||
|
step_pin: PC0
|
||||||
|
dir_pin: !PL1
|
||||||
|
enable_pin: !PA7
|
||||||
|
step_distance: .0225
|
||||||
|
endstop_pin: ^!PB6
|
||||||
|
position_endstop: 0.0
|
||||||
|
position_max: 200
|
||||||
|
homing_speed: 50
|
||||||
|
homing_stepper_phases: 32
|
||||||
|
homing_endstop_accuracy: .200
|
||||||
|
|
||||||
|
[stepper_y]
|
||||||
|
step_pin: PC1
|
||||||
|
dir_pin: PL0
|
||||||
|
enable_pin: !PA6
|
||||||
|
step_distance: .0225
|
||||||
|
endstop_pin: ^!PB5
|
||||||
|
position_endstop: 0.0
|
||||||
|
position_max: 250
|
||||||
|
homing_speed: 50
|
||||||
|
homing_stepper_phases: 32
|
||||||
|
homing_endstop_accuracy: .200
|
||||||
|
|
||||||
|
[stepper_z]
|
||||||
|
step_pin: PC2
|
||||||
|
dir_pin: !PL2
|
||||||
|
enable_pin: !PA5
|
||||||
|
step_distance: .005
|
||||||
|
endstop_pin: ^!PB4
|
||||||
|
position_min: 0.1
|
||||||
|
position_endstop: 0.7
|
||||||
|
position_max: 200
|
||||||
|
homing_retract_dist: 2.0
|
||||||
|
homing_stepper_phases: 32
|
||||||
|
homing_endstop_accuracy: .070
|
||||||
|
|
||||||
|
[extruder]
|
||||||
|
step_pin: PC3
|
||||||
|
dir_pin: PL6
|
||||||
|
enable_pin: !PA4
|
||||||
|
step_distance: .004242
|
||||||
|
nozzle_diameter: 0.350
|
||||||
|
filament_diameter: 1.750
|
||||||
|
pressure_advance: 0.07
|
||||||
|
heater_pin: PH6
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: PF0
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 7.0
|
||||||
|
pid_Ki: 0.1
|
||||||
|
pid_Kd: 12
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 210
|
||||||
|
|
||||||
|
[heater_bed]
|
||||||
|
heater_pin: PE5
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: PF2
|
||||||
|
control: watermark
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 100
|
||||||
|
|
||||||
|
[fan]
|
||||||
|
pin: PH5
|
||||||
|
|
||||||
|
[heater_fan nozzle_fan]
|
||||||
|
pin: PH3
|
||||||
|
max_power: 0.61
|
||||||
|
cycle_time: .000030
|
||||||
|
hardware_pwm: True
|
||||||
|
|
||||||
|
[mcu]
|
||||||
|
serial: /dev/ttyACM0
|
||||||
|
|
||||||
|
[printer]
|
||||||
|
kinematics: cartesian
|
||||||
|
max_velocity: 500
|
||||||
|
max_accel: 3000
|
||||||
|
max_z_velocity: 25
|
||||||
|
max_z_accel: 30
|
||||||
|
|
||||||
|
[ad5206 stepper_digipot]
|
||||||
|
enable_pin: PD7
|
||||||
|
# Scale the config so that the channel value can be specified in amps
|
||||||
|
scale: 1.56
|
||||||
|
# Channel 1 is E0, 2 is E1, 3 is unused, 4 is Z, 5 is X, 6 is Y
|
||||||
|
channel_1: 1.0
|
||||||
|
channel_2: 0.75
|
||||||
|
channel_4: 0.82
|
||||||
|
channel_5: 0.82
|
||||||
|
channel_6: 0.82
|
||||||
|
|
||||||
|
# Enable 8 micro-steps on steppers X, Y, Z, E0
|
||||||
|
[static_digital_output stepper_config]
|
||||||
|
pins:
|
||||||
|
PG1, PG0,
|
||||||
|
PK7, PG2,
|
||||||
|
PK6, PK5,
|
||||||
|
PK3, PK4
|
||||||
|
|
||||||
|
[static_digital_output yellow_led]
|
||||||
|
pins: !PB7
|
||||||
94
config/printer-seemecnc-rostock-max-v2-2015.cfg
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
# This file constains the pin mappings for the SeeMeCNC Rostock Max
|
||||||
|
# (version 2) delta printer from 2015. To use this config, the
|
||||||
|
# firmware should be compiled for the AVR atmega2560.
|
||||||
|
|
||||||
|
# See the example.cfg file for a description of available parameters.
|
||||||
|
|
||||||
|
[stepper_a]
|
||||||
|
step_pin: PC0
|
||||||
|
dir_pin: !PL1
|
||||||
|
enable_pin: !PA7
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^PA2
|
||||||
|
homing_speed: 50
|
||||||
|
position_endstop: 380
|
||||||
|
arm_length: 290.800
|
||||||
|
|
||||||
|
[stepper_b]
|
||||||
|
step_pin: PC1
|
||||||
|
dir_pin: PL0
|
||||||
|
enable_pin: !PA6
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^PA1
|
||||||
|
|
||||||
|
[stepper_c]
|
||||||
|
step_pin: PC2
|
||||||
|
dir_pin: !PL2
|
||||||
|
enable_pin: !PA5
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^PC7
|
||||||
|
|
||||||
|
[extruder]
|
||||||
|
step_pin: PC3
|
||||||
|
dir_pin: !PL6
|
||||||
|
enable_pin: !PA4
|
||||||
|
step_distance: .010793
|
||||||
|
nozzle_diameter: 0.500
|
||||||
|
filament_diameter: 1.750
|
||||||
|
heater_pin: PH6
|
||||||
|
sensor_type: ATC Semitec 104GT-2
|
||||||
|
sensor_pin: PF0
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 20.9700
|
||||||
|
pid_Ki: 1.3400
|
||||||
|
pid_Kd: 80.5600
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 300
|
||||||
|
|
||||||
|
[heater_bed]
|
||||||
|
heater_pin: PE5
|
||||||
|
sensor_type: ATC Semitec 104GT-2
|
||||||
|
sensor_pin: PF2
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 46.510
|
||||||
|
pid_Ki: 1.040
|
||||||
|
pid_Kd: 500.000
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 300
|
||||||
|
|
||||||
|
[fan]
|
||||||
|
pin: PH5
|
||||||
|
|
||||||
|
[heater_fan nozzle_cooling_fan]
|
||||||
|
pin: PH4
|
||||||
|
heater: extruder
|
||||||
|
|
||||||
|
[mcu]
|
||||||
|
serial: /dev/ttyACM0
|
||||||
|
|
||||||
|
[printer]
|
||||||
|
kinematics: delta
|
||||||
|
max_velocity: 300
|
||||||
|
max_accel: 3000
|
||||||
|
max_z_velocity: 150
|
||||||
|
delta_radius: 174.75
|
||||||
|
|
||||||
|
[ad5206 stepper_digipot]
|
||||||
|
enable_pin: PD7
|
||||||
|
scale: 2.08
|
||||||
|
channel_1: 1.34
|
||||||
|
channel_2: 1.0
|
||||||
|
channel_4: 1.1
|
||||||
|
channel_5: 1.1
|
||||||
|
channel_6: 1.1
|
||||||
|
|
||||||
|
[static_digital_output stepper_config]
|
||||||
|
pins:
|
||||||
|
PG1, PG0,
|
||||||
|
PK7, PG2,
|
||||||
|
PK6, PK5,
|
||||||
|
PK3, PK4,
|
||||||
|
PK1, PK2
|
||||||
|
|
||||||
|
[static_digital_output yellow_led]
|
||||||
|
pins: !PB7
|
||||||
89
config/printer-tronxy-x5s-2017.cfg
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
# This file contains pin mappings for the Tronxy X5S (circa 2017). To
|
||||||
|
# use this config, the firmware should be compiled for the AVR
|
||||||
|
# atmega1284p.
|
||||||
|
|
||||||
|
# Note, a number of Melzi boards are shipped without a bootloader. In
|
||||||
|
# that case, an external programmer will be needed to flash a
|
||||||
|
# bootloader to the board (for example, see
|
||||||
|
# http://www.instructables.com/id/Flashing-a-Bootloader-to-the-CR-10/
|
||||||
|
# ). Once that is done, one should be able to use the standard "make
|
||||||
|
# flash" command to flash Klipper.
|
||||||
|
|
||||||
|
# See the example.cfg file for a description of available parameters.
|
||||||
|
|
||||||
|
[stepper_x]
|
||||||
|
step_pin: PD7
|
||||||
|
dir_pin: !PC5
|
||||||
|
enable_pin: !PD6
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^!PC2
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 330
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_y]
|
||||||
|
step_pin: PC6
|
||||||
|
dir_pin: !PC7
|
||||||
|
enable_pin: !PD6
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^!PC3
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 310
|
||||||
|
homing_speed: 50
|
||||||
|
|
||||||
|
[stepper_z]
|
||||||
|
step_pin: PB3
|
||||||
|
dir_pin: PB2
|
||||||
|
enable_pin: !PD6
|
||||||
|
step_distance: .0025
|
||||||
|
endstop_pin: ^!PC4
|
||||||
|
position_endstop: 0.5
|
||||||
|
position_max: 400
|
||||||
|
|
||||||
|
[extruder]
|
||||||
|
step_pin: PB1
|
||||||
|
dir_pin: PB0
|
||||||
|
enable_pin: !PD6
|
||||||
|
step_distance: .0111
|
||||||
|
nozzle_diameter: 0.400
|
||||||
|
filament_diameter: 1.750
|
||||||
|
heater_pin: PD5
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: PA7
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 22.2
|
||||||
|
pid_Ki: 1.08
|
||||||
|
pid_Kd: 114
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 275
|
||||||
|
|
||||||
|
[heater_bed]
|
||||||
|
heater_pin: PD4
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: PA6
|
||||||
|
control: watermark
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 150
|
||||||
|
|
||||||
|
[fan]
|
||||||
|
pin: PB4
|
||||||
|
|
||||||
|
[mcu]
|
||||||
|
serial: /dev/ttyUSB0
|
||||||
|
|
||||||
|
[printer]
|
||||||
|
kinematics: corexy
|
||||||
|
max_velocity: 300
|
||||||
|
max_accel: 1000
|
||||||
|
max_z_velocity: 20
|
||||||
|
max_z_accel: 100
|
||||||
|
|
||||||
|
[display]
|
||||||
|
lcd_type: st7920
|
||||||
|
cs_pin: PA1
|
||||||
|
sclk_pin: PC0
|
||||||
|
sid_pin: PA3
|
||||||
|
|
||||||
|
# buttons are:
|
||||||
|
# PD2, PD3: encoder
|
||||||
|
# PA5: click
|
||||||
78
config/printer-wanhao-duplicator-i3-plus-2017.cfg
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
# This file contains pin mappings for the Wanhao Duplicator i3 Plus
|
||||||
|
# (circa 2017). To use this config, the firmware should be compiled
|
||||||
|
# for the AVR atmega2560.
|
||||||
|
# Pin numbers and other parameters were extracted from the
|
||||||
|
# official Marlin source available at:
|
||||||
|
# https://github.com/garychen99/Duplicator-i3-plus
|
||||||
|
|
||||||
|
# See the example.cfg file for a description of available parameters.
|
||||||
|
|
||||||
|
[stepper_x]
|
||||||
|
step_pin: PF7
|
||||||
|
dir_pin: !PK0
|
||||||
|
enable_pin: !PF6
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^!PF0
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 200
|
||||||
|
homing_speed: 30.0
|
||||||
|
|
||||||
|
[stepper_y]
|
||||||
|
step_pin: PK2
|
||||||
|
dir_pin: !PK3
|
||||||
|
enable_pin: !PK1
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^!PA2
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 200
|
||||||
|
homing_speed: 30.0
|
||||||
|
|
||||||
|
[stepper_z]
|
||||||
|
step_pin: PK5
|
||||||
|
dir_pin: PK7
|
||||||
|
enable_pin: !PK4
|
||||||
|
step_distance: .0025
|
||||||
|
endstop_pin: ^!PA1
|
||||||
|
position_endstop: 0.5
|
||||||
|
position_max: 180
|
||||||
|
|
||||||
|
[extruder]
|
||||||
|
step_pin: PF4
|
||||||
|
dir_pin: PF5
|
||||||
|
enable_pin: !PF3
|
||||||
|
step_distance: 0.010417
|
||||||
|
nozzle_diameter: 0.400
|
||||||
|
filament_diameter: 1.750
|
||||||
|
heater_pin: PG5
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: PF1
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 30.850721
|
||||||
|
pid_Ki: .208175
|
||||||
|
pid_Kd: 192.298728
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 260
|
||||||
|
|
||||||
|
[heater_bed]
|
||||||
|
heater_pin: PE5
|
||||||
|
sensor_type: EPCOS 100K B57560G104F
|
||||||
|
sensor_pin: PK6
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 64.095903
|
||||||
|
pid_Ki: 1.649830
|
||||||
|
pid_Kd: 622.531455
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 110
|
||||||
|
|
||||||
|
[fan]
|
||||||
|
pin: PE3
|
||||||
|
|
||||||
|
[mcu]
|
||||||
|
serial: /dev/ttyUSB0
|
||||||
|
|
||||||
|
[printer]
|
||||||
|
kinematics: cartesian
|
||||||
|
max_velocity: 300
|
||||||
|
max_accel: 800
|
||||||
|
max_z_velocity: 5
|
||||||
|
max_z_accel: 100
|
||||||
159
config/printer-wanhao-duplicator-i3-v2.1-2017.cfg
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
# This file contains pin mappings and other appropriate default parameters
|
||||||
|
# for a Wanhao Duplicator i3 v2.1 and its clones
|
||||||
|
# (Monoprice Maker Select, Cocoon Create, etc.)
|
||||||
|
# See the files example.cfg and example-extras.cfg for a description of available parameters.
|
||||||
|
#
|
||||||
|
# This will probably work on older revisions (v1.0, v2.0) of the printer
|
||||||
|
# but is untested on those versions.
|
||||||
|
#
|
||||||
|
# For best results with klipper and the Wanhao Duplicator i3, follow these
|
||||||
|
# guidelines:
|
||||||
|
#
|
||||||
|
# - Flash a bootloader to the Melzi board in the printer
|
||||||
|
# See http://www.instructables.com/id/Using-an-Arduino-to-Flash-the-Melzi-Board-Wanhao-I/
|
||||||
|
#
|
||||||
|
# - Make sure the auto-reset jumper is *enabled* on the Melzi board
|
||||||
|
# (See step 1 in the bootloader tutorial above)
|
||||||
|
#
|
||||||
|
# - Locate the USB serial port for your printer in /dev/serial/by-id/ format.
|
||||||
|
# See https://github.com/KevinOConnor/klipper/blob/master/docs/FAQ.md#wheres-my-serial-port
|
||||||
|
# It will be something like:
|
||||||
|
# /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_ABCD1234-if00-port0
|
||||||
|
#
|
||||||
|
# - Configure klipper to compile firmware for the AVR atmega1284p
|
||||||
|
#
|
||||||
|
# - At this point, "make flash FLASH_DEVICE=..." should successfully
|
||||||
|
# flash your printer board. Use the /dev/serial/by-id/ format for
|
||||||
|
# FLASH_DEVICE to ensure consistent results.
|
||||||
|
# See https://github.com/KevinOConnor/klipper/blob/master/docs/FAQ.md#the-make-flash-command-doesnt-work
|
||||||
|
# if you have problems.
|
||||||
|
#
|
||||||
|
# - Copy this sample file you are currently reading to ~/printer.cfg,
|
||||||
|
# and customize the following parameters:
|
||||||
|
# * [extruder] > step_distance
|
||||||
|
#
|
||||||
|
# This is the inverse of "E steps" (extruder steps per mm) from the stock
|
||||||
|
# Wanhao Repetier-based firmware.
|
||||||
|
# (See https://3dprinterwiki.info/extruder-steps/ )
|
||||||
|
#
|
||||||
|
# For example, if your E-steps are set to 107.0 steps per mm,
|
||||||
|
# then step_distance should be (1 / 107.0) ~= .009346
|
||||||
|
#
|
||||||
|
# * [extruder] > PID parameters (pid_Kp, pid_Ki, pid_Kd)
|
||||||
|
# * [heater_bed] > PID parameters (pid_Kp, pid_Ki, pid_Kd)
|
||||||
|
#
|
||||||
|
# PID values from stock Wanhao firmware (Repetier) do not
|
||||||
|
# translate directly to klipper. You will need to run klipper's
|
||||||
|
# PID autotune function for the extruder and bed. After getting the
|
||||||
|
# klipper firmware up and running, run the PID_CALIBRATE procedures
|
||||||
|
# by sending these commands via octoprint terminal (one per autotune):
|
||||||
|
#
|
||||||
|
# extruder: PID_CALIBRATE HEATER=extruder TARGET=<temp>
|
||||||
|
# heated bed: PID_CALIBRATE HEATER=heater_bed TARGET=<temp>
|
||||||
|
#
|
||||||
|
# After the autotune process completes, PID parameter results
|
||||||
|
# can be found in the Octoprint terminal tab (if you're quick)
|
||||||
|
# or in /tmp/klippy.log.
|
||||||
|
#
|
||||||
|
# Enter the PID parameters into the appropriate sections of ~/printer.cfg .
|
||||||
|
#
|
||||||
|
# * [extruder] > max_temp
|
||||||
|
# * [heater_bed] > max_temp
|
||||||
|
#
|
||||||
|
# The max temps included in this printer config are limited to 230 for extruder
|
||||||
|
# and 70 for heated bed. If your printer has been modified to handle higher temps
|
||||||
|
# (like an upgraded hot end or a separate MOSFET for your heated bed), you may
|
||||||
|
# want to increase these values.
|
||||||
|
#
|
||||||
|
# * [mcu] > serial
|
||||||
|
#
|
||||||
|
# Enter the USB serial port of the printer in /dev/serial/by-id/ format
|
||||||
|
# for best results.
|
||||||
|
#
|
||||||
|
# - Power cycle the Wanhao Duplicator i3
|
||||||
|
#
|
||||||
|
# - Issue the command "RESTART" via the Octoprint terminal tab (similar to
|
||||||
|
# how you would send a manual gcode command, but send the word RESTART).
|
||||||
|
# This tells klipper to reload its config file and do an internal reset.
|
||||||
|
# You should then see a status screen appear on the printer's LCD.
|
||||||
|
#
|
||||||
|
# - Be sure to follow these instructions before attempting any prints:
|
||||||
|
# https://github.com/KevinOConnor/klipper/blob/master/docs/Config_checks.md
|
||||||
|
|
||||||
|
[stepper_x]
|
||||||
|
step_pin: PD7
|
||||||
|
dir_pin: PC5
|
||||||
|
enable_pin: !PD6
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^!PC2
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 200
|
||||||
|
homing_speed: 40
|
||||||
|
|
||||||
|
[stepper_y]
|
||||||
|
step_pin: PC6
|
||||||
|
dir_pin: PC7
|
||||||
|
enable_pin: !PD6
|
||||||
|
step_distance: .0125
|
||||||
|
endstop_pin: ^!PC3
|
||||||
|
position_endstop: 0
|
||||||
|
position_max: 200
|
||||||
|
homing_speed: 40
|
||||||
|
|
||||||
|
[stepper_z]
|
||||||
|
step_pin: PB3
|
||||||
|
dir_pin: !PB2
|
||||||
|
enable_pin: !PA5
|
||||||
|
step_distance: 0.0025
|
||||||
|
endstop_pin: ^!PC4
|
||||||
|
position_endstop: 0.5
|
||||||
|
position_max: 180
|
||||||
|
homing_speed: 2
|
||||||
|
|
||||||
|
[extruder]
|
||||||
|
step_pin: PB1
|
||||||
|
dir_pin: !PB0
|
||||||
|
enable_pin: !PD6
|
||||||
|
step_distance: .009346
|
||||||
|
nozzle_diameter: 0.400
|
||||||
|
filament_diameter: 1.750
|
||||||
|
heater_pin: PD5
|
||||||
|
sensor_type: NTC 100K beta 3950
|
||||||
|
sensor_pin: PA7
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 18.214030
|
||||||
|
pid_Ki: 0.616380
|
||||||
|
pid_Kd: 134.556146
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 230
|
||||||
|
|
||||||
|
[heater_bed]
|
||||||
|
heater_pin: PD4
|
||||||
|
sensor_type: NTC 100K beta 3950
|
||||||
|
sensor_pin: PA6
|
||||||
|
control: pid
|
||||||
|
pid_Kp: 71.321
|
||||||
|
pid_Ki: 1.989
|
||||||
|
pid_Kd: 639.210
|
||||||
|
min_temp: 0
|
||||||
|
max_temp: 70
|
||||||
|
|
||||||
|
[fan]
|
||||||
|
pin: PB4
|
||||||
|
|
||||||
|
[mcu]
|
||||||
|
serial: /dev/ttyUSB0
|
||||||
|
restart_method: command
|
||||||
|
|
||||||
|
[printer]
|
||||||
|
kinematics: cartesian
|
||||||
|
max_velocity: 200
|
||||||
|
max_accel: 1000
|
||||||
|
max_z_velocity: 2
|
||||||
|
max_z_accel: 100
|
||||||
|
|
||||||
|
[display]
|
||||||
|
lcd_type: st7920
|
||||||
|
cs_pin: PC1
|
||||||
|
sclk_pin: PD3
|
||||||
|
sid_pin: PC0
|
||||||
56
config/sample-bltouch.cfg
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# This file provides example config file settings for the BLTouch
|
||||||
|
# automatic bed leveling sensor. This file is just a "snippet" of
|
||||||
|
# sections specific to the BLTouch - it must be added to a config file
|
||||||
|
# containing the configuration of the rest of the printer.
|
||||||
|
|
||||||
|
# Be sure to review and update this config with the appropriate pins
|
||||||
|
# and coordinates for your printer.
|
||||||
|
|
||||||
|
# See the "example.cfg" and "example-extras.cfg" files for a
|
||||||
|
# description of config parameters.
|
||||||
|
|
||||||
|
# Define the BLTouch servo
|
||||||
|
[servo bltouch]
|
||||||
|
pin: ar32
|
||||||
|
maximum_servo_angle: 180
|
||||||
|
minimum_pulse_width: 0.0006
|
||||||
|
maximum_pulse_width: 0.0024
|
||||||
|
|
||||||
|
# Define a probe using the BLTouch
|
||||||
|
[probe]
|
||||||
|
pin: ar30
|
||||||
|
activate_gcode:
|
||||||
|
SET_SERVO SERVO=bltouch ANGLE=10
|
||||||
|
SET_SERVO SERVO=bltouch ANGLE=60
|
||||||
|
G4 P200
|
||||||
|
deactivate_gcode:
|
||||||
|
SET_SERVO SERVO=bltouch ANGLE=90
|
||||||
|
|
||||||
|
# Example bed_tilt config section
|
||||||
|
[bed_tilt]
|
||||||
|
#x_adjust:
|
||||||
|
#y_adjust:
|
||||||
|
points:
|
||||||
|
100,100
|
||||||
|
10,10
|
||||||
|
10,100
|
||||||
|
10,190
|
||||||
|
100,10
|
||||||
|
100,190
|
||||||
|
190,10
|
||||||
|
190,100
|
||||||
|
190,190
|
||||||
|
probe_z_offset: 2.345
|
||||||
|
|
||||||
|
# If the BLTouch is used to home the Z axis, then define a
|
||||||
|
# homing_override section, use probe:z_virtual_endstop as the
|
||||||
|
# endstop_pin in the stepper_z section, and set the endstop_position
|
||||||
|
# in the stepper_z section to match the probe's probe_z_offset.
|
||||||
|
#[homing_override]
|
||||||
|
#set_position_z: 5
|
||||||
|
#gcode:
|
||||||
|
# ; G90 ; Uncomment these 2 lines to blindly lift the Z 2mm at start
|
||||||
|
# ; G1 Z7 F600
|
||||||
|
# G28 X0 Y0
|
||||||
|
# G1 X100 Y100 F3600
|
||||||
|
# G28 Z0
|
||||||
38
docs/CONTRIBUTING.md
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# Contributing to Klipper
|
||||||
|
|
||||||
|
Thank you for contributing to Klipper! Please take a moment to read
|
||||||
|
this document.
|
||||||
|
|
||||||
|
## Creating a new issue
|
||||||
|
|
||||||
|
Please see the [contact page](Contact.md) for information on creating
|
||||||
|
an issue. In particular, **we need the klippy.log file** attached to
|
||||||
|
bug reports. Also, be sure to read the [FAQ](FAQ.md) to see if a
|
||||||
|
similar issue has already been raised.
|
||||||
|
|
||||||
|
## Submitting a pull request
|
||||||
|
|
||||||
|
Contributions of Code and documentation are managed through github
|
||||||
|
pull requests. Each commit should have a commit message formatted
|
||||||
|
similar to the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
module: Capitalized, short (50 chars or less) summary
|
||||||
|
|
||||||
|
More detailed explanatory text, if necessary. Wrap it to about 75
|
||||||
|
characters or so. In some contexts, the first line is treated as the
|
||||||
|
subject of an email and the rest of the text as the body. The blank
|
||||||
|
line separating the summary from the body is critical (unless you omit
|
||||||
|
the body entirely); tools like rebase can get confused if you run the
|
||||||
|
two together.
|
||||||
|
|
||||||
|
Further paragraphs come after blank lines..
|
||||||
|
|
||||||
|
Signed-off-by: My Name <myemail@example.org>
|
||||||
|
```
|
||||||
|
|
||||||
|
It is important to have a "Signed-off-by" line on each commit - it
|
||||||
|
certifies that you agree to the
|
||||||
|
[developer certificate of origin](developer-certificate-of-origin). It
|
||||||
|
must contain your real name (sorry, no pseudonyms or anonymous
|
||||||
|
contributions) and contain a current email address.
|
||||||
@@ -6,12 +6,22 @@ Directory Layout
|
|||||||
|
|
||||||
The **src/** directory contains the C source for the micro-controller
|
The **src/** directory contains the C source for the micro-controller
|
||||||
code. The **src/avr/** directory contains specific code for Atmel
|
code. The **src/avr/** directory contains specific code for Atmel
|
||||||
ATmega micro-controllers. The **src/simulator/** contains code stubs
|
ATmega micro-controllers. The **src/sam3x8e/** directory contains code
|
||||||
that allow the micro-controller to be test compiled on other
|
specific to the Arduino Due style ARM micro-controllers. The
|
||||||
architectures.
|
**src/pru/** directory contains code specific to the Beaglebone's
|
||||||
|
on-board PRU micro-controller. The **src/simulator/** contains code
|
||||||
|
stubs that allow the micro-controller to be test compiled on other
|
||||||
|
architectures. The **src/generic/** directory contains helper code
|
||||||
|
that may be useful across different host architectures. The build
|
||||||
|
arranges for includes of "board/somefile.h" to first look in the
|
||||||
|
current architecture directory (eg, src/avr/somefile.h) and then in
|
||||||
|
the generic directory (eg, src/generic/somefile.h).
|
||||||
|
|
||||||
The **klippy/** directory contains the C and Python source for the
|
The **klippy/** directory contains the C and Python source for the
|
||||||
host part of the firmware.
|
host part of the software.
|
||||||
|
|
||||||
|
The **lib/** directory contains external 3rd-party library code that
|
||||||
|
is necessary to build some targets.
|
||||||
|
|
||||||
The **config/** directory contains example printer configuration
|
The **config/** directory contains example printer configuration
|
||||||
files.
|
files.
|
||||||
@@ -19,23 +29,29 @@ files.
|
|||||||
The **scripts/** directory contains build-time scripts useful for
|
The **scripts/** directory contains build-time scripts useful for
|
||||||
compiling the micro-controller code.
|
compiling the micro-controller code.
|
||||||
|
|
||||||
|
The **test/** directory contains automated test cases.
|
||||||
|
|
||||||
During compilation, the build may create an **out/** directory. This
|
During compilation, the build may create an **out/** directory. This
|
||||||
contains temporary build time objects. The final micro-controller
|
contains temporary build time objects. The final micro-controller
|
||||||
object that is built is in **out/klipper.elf.hex**
|
object that is built is **out/klipper.elf.hex** on AVR and
|
||||||
|
**out/klipper.bin** on ARM.
|
||||||
|
|
||||||
Micro-controller code flow
|
Micro-controller code flow
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
Execution of the micro-controller code starts in **src/avr/main.c**
|
Execution of the micro-controller code starts in architecture specific
|
||||||
which calls sched_main() located in **src/sched.c**. The sched_main()
|
code (eg, **src/avr/main.c**) which ultimately calls sched_main()
|
||||||
code starts by running all functions that have been tagged with the
|
located in **src/sched.c**. The sched_main() code starts by running
|
||||||
DECL_INIT() macro. It then goes on to repeatedly run all functions
|
all functions that have been tagged with the DECL_INIT() macro. It
|
||||||
tagged with the DECL_TASK() macro.
|
then goes on to repeatedly run all functions tagged with the
|
||||||
|
DECL_TASK() macro.
|
||||||
|
|
||||||
One of the main task functions is command_task() located in
|
One of the main task functions is command_dispatch() located in
|
||||||
**src/command.c**. This function processes incoming serial commands
|
**src/command.c**. This function is called from the board specific
|
||||||
and runs the associated command function for them. Command functions
|
input/output code (eg, **src/avr/serial.c**) and it runs the command
|
||||||
are declared using the DECL_COMMAND() macro.
|
functions associated with the commands found in the input
|
||||||
|
stream. Command functions are declared using the DECL_COMMAND() macro
|
||||||
|
(see the [protocol](Protocol.md) document for more information).
|
||||||
|
|
||||||
Task, init, and command functions always run with interrupts enabled
|
Task, init, and command functions always run with interrupts enabled
|
||||||
(however, they can temporarily disable interrupts if needed). These
|
(however, they can temporarily disable interrupts if needed). These
|
||||||
@@ -43,15 +59,16 @@ functions should never pause, delay, or do any work that lasts more
|
|||||||
than a few micro-seconds. These functions schedule work at specific
|
than a few micro-seconds. These functions schedule work at specific
|
||||||
times by scheduling timers.
|
times by scheduling timers.
|
||||||
|
|
||||||
Timer functions are scheduled by calling sched_timer() (located in
|
Timer functions are scheduled by calling sched_add_timer() (located in
|
||||||
**src/sched.c**). The scheduler code will arrange for the given
|
**src/sched.c**). The scheduler code will arrange for the given
|
||||||
function to be called at the requested clock time. Timer interrupts
|
function to be called at the requested clock time. Timer interrupts
|
||||||
are initially handled in an interrupt handler in **src/avr/timer.c**,
|
are initially handled in an architecture specific interrupt handler
|
||||||
but this just calls sched_timer_kick() located in **src/sched.c**. The
|
(eg, **src/avr/timer.c**) which calls sched_timer_dispatch() located
|
||||||
timer interrupt leads to execution of schedule timer functions. Timer
|
in **src/sched.c**. The timer interrupt leads to execution of schedule
|
||||||
functions always run with interrupts disabled. The timer functions
|
timer functions. Timer functions always run with interrupts
|
||||||
should always complete within a few micro-seconds. At completion of
|
disabled. The timer functions should always complete within a few
|
||||||
the timer event, the function may choose to reschedule itself.
|
micro-seconds. At completion of the timer event, the function may
|
||||||
|
choose to reschedule itself.
|
||||||
|
|
||||||
In the event an error is detected the code can invoke shutdown() (a
|
In the event an error is detected the code can invoke shutdown() (a
|
||||||
macro which calls sched_shutdown() located in **src/sched.c**).
|
macro which calls sched_shutdown() located in **src/sched.c**).
|
||||||
@@ -62,12 +79,12 @@ interrupts disabled.
|
|||||||
Much of the functionality of the micro-controller involves working
|
Much of the functionality of the micro-controller involves working
|
||||||
with General-Purpose Input/Output pins (GPIO). In order to abstract
|
with General-Purpose Input/Output pins (GPIO). In order to abstract
|
||||||
the low-level architecture specific code from the high-level task
|
the low-level architecture specific code from the high-level task
|
||||||
code, all GPIO events are implemented via wrappers. These wrappers are
|
code, all GPIO events are implemented in architecture specific
|
||||||
located in **src/avr/gpio.c**. The code is compiled with gcc's "-flto
|
wrappers (eg, **src/avr/gpio.c**). The code is compiled with gcc's
|
||||||
-fwhole-program" optimization which does an excellent job of inlining
|
"-flto -fwhole-program" optimization which does an excellent job of
|
||||||
functions across compilation units, so most of these tiny gpio
|
inlining functions across compilation units, so most of these tiny
|
||||||
functions are inlined into their callers, and there is no run-time
|
gpio functions are inlined into their callers, and there is no
|
||||||
cost to using them.
|
run-time cost to using them.
|
||||||
|
|
||||||
Klippy code overview
|
Klippy code overview
|
||||||
====================
|
====================
|
||||||
@@ -80,14 +97,339 @@ some functionality in C code.
|
|||||||
Initial execution starts in **klippy/klippy.py**. This reads the
|
Initial execution starts in **klippy/klippy.py**. This reads the
|
||||||
command-line arguments, opens the printer config file, instantiates
|
command-line arguments, opens the printer config file, instantiates
|
||||||
the main printer objects, and starts the serial connection. The main
|
the main printer objects, and starts the serial connection. The main
|
||||||
execution of gcode commands is in the process_commands() method in
|
execution of G-code commands is in the process_commands() method in
|
||||||
**klippy/gcode.py**. This code translates the gcode commands into
|
**klippy/gcode.py**. This code translates the G-code commands into
|
||||||
printer object calls, which frequently translate the actions to
|
printer object calls, which frequently translate the actions to
|
||||||
commands to be executed on the micro-controller (as declared via the
|
commands to be executed on the micro-controller (as declared via the
|
||||||
DECL_COMMAND macro in the micro-controller code).
|
DECL_COMMAND macro in the micro-controller code).
|
||||||
|
|
||||||
There are three threads in the Klippy host code. The main thread
|
There are four threads in the Klippy host code. The main thread
|
||||||
handles incoming gcode commands. A second thread (which resides
|
handles incoming gcode commands. A second thread (which resides
|
||||||
entirely in the **klippy/serialqueue.c** C code) handles low-level IO
|
entirely in the **klippy/serialqueue.c** C code) handles low-level IO
|
||||||
with the serial port. The third thread is used to process response
|
with the serial port. The third thread is used to process response
|
||||||
messages from the micro-controller in the Python code.
|
messages from the micro-controller in the Python code (see
|
||||||
|
**klippy/serialhdl.py**). The fourth thread writes debug messages to
|
||||||
|
the log (see **klippy/queuelogger.py**) so that the other threads
|
||||||
|
never block on log writes.
|
||||||
|
|
||||||
|
Code flow of a move command
|
||||||
|
===========================
|
||||||
|
|
||||||
|
A typical printer movement starts when a "G1" command is sent to the
|
||||||
|
Klippy host and it completes when the corresponding step pulses are
|
||||||
|
produced on the micro-controller. This section outlines the code flow
|
||||||
|
of a typical move command. The [kinematics](Kinematics.md) document
|
||||||
|
provides further information on the mechanics of moves.
|
||||||
|
|
||||||
|
* Processing for a move command starts in gcode.py. The goal of
|
||||||
|
gcode.py is to translate G-code into internal calls. Changes in
|
||||||
|
origin (eg, G92), changes in relative vs absolute positions (eg,
|
||||||
|
G90), and unit changes (eg, F6000=100mm/s) are handled here. The
|
||||||
|
code path for a move is: `process_data() -> process_commands() ->
|
||||||
|
cmd_G1()`. Ultimately the ToolHead class is invoked to execute the
|
||||||
|
actual request: `cmd_G1() -> ToolHead.move()`
|
||||||
|
|
||||||
|
* The ToolHead class (in toolhead.py) handles "look-ahead" and tracks
|
||||||
|
the timing of printing actions. The codepath for a move is:
|
||||||
|
`ToolHead.move() -> MoveQueue.add_move() -> MoveQueue.flush() ->
|
||||||
|
Move.set_junction() -> Move.move()`.
|
||||||
|
* ToolHead.move() creates a Move() object with the parameters of the
|
||||||
|
move (in cartesian space and in units of seconds and millimeters).
|
||||||
|
* MoveQueue.add_move() places the move object on the "look-ahead"
|
||||||
|
queue.
|
||||||
|
* MoveQueue.flush() determines the start and end velocities of each
|
||||||
|
move.
|
||||||
|
* Move.set_junction() implements the "trapezoid generator" on a
|
||||||
|
move. The "trapezoid generator" breaks every move into three parts:
|
||||||
|
a constant acceleration phase, followed by a constant velocity
|
||||||
|
phase, followed by a constant deceleration phase. Every move
|
||||||
|
contains these three phases in this order, but some phases may be of
|
||||||
|
zero duration.
|
||||||
|
* When Move.move() is called, everything about the move is known -
|
||||||
|
its start location, its end location, its acceleration, its
|
||||||
|
start/crusing/end velocity, and distance traveled during
|
||||||
|
acceleration/cruising/deceleration. All the information is stored in
|
||||||
|
the Move() class and is in cartesian space in units of millimeters
|
||||||
|
and seconds.
|
||||||
|
|
||||||
|
The move is then handed off to the kinematics classes: `Move.move()
|
||||||
|
-> kin.move()`
|
||||||
|
|
||||||
|
* The goal of the kinematics classes is to translate the movement in
|
||||||
|
cartesian space to movement on each stepper. The kinematics classes
|
||||||
|
are in cartesian.py, corexy.py, delta.py, and extruder.py. The
|
||||||
|
kinematic class is given a chance to audit the move
|
||||||
|
(`ToolHead.move() -> kin.check_move()`) before it goes on the
|
||||||
|
look-ahead queue, but once the move arrives in *kin*.move() the
|
||||||
|
kinematic class is required to handle the move as specified. The
|
||||||
|
kinematic classes translate the three parts of each move
|
||||||
|
(acceleration, constant "cruising" velocity, and deceleration) to
|
||||||
|
the associated movement on each stepper. Note that the extruder is
|
||||||
|
handled in its own kinematic class. Since the Move() class specifies
|
||||||
|
the exact movement time and since step pulses are sent to the
|
||||||
|
micro-controller with specific timing, stepper movements produced by
|
||||||
|
the extruder class will be in sync with head movement even though
|
||||||
|
the code is kept separate.
|
||||||
|
|
||||||
|
* For efficiency reasons, the stepper pulse times are generated in C
|
||||||
|
code. The code flow is: `kin.move() -> MCU_Stepper.step_const() ->
|
||||||
|
stepcompress_push_const()`, or for delta kinematics:
|
||||||
|
`DeltaKinematics.move() -> MCU_Stepper.step_delta() ->
|
||||||
|
stepcompress_push_delta()`. The MCU_Stepper code just performs unit
|
||||||
|
and axis transformation (millimeters to step distances), and calls
|
||||||
|
the C code. The C code calculates the stepper step times for each
|
||||||
|
movement and fills an array (struct stepcompress.queue) with the
|
||||||
|
corresponding micro-controller clock counter times for every
|
||||||
|
step. Here the "micro-controller clock counter" value directly
|
||||||
|
corresponds to the micro-controller's hardware counter - it is
|
||||||
|
relative to when the micro-controller was last powered up.
|
||||||
|
|
||||||
|
* The next major step is to compress the steps: `stepcompress_flush()
|
||||||
|
-> compress_bisect_add()` (in stepcompress.c). This code generates
|
||||||
|
and encodes a series of micro-controller "queue_step" commands that
|
||||||
|
correspond to the list of stepper step times built in the previous
|
||||||
|
stage. These "queue_step" commands are then queued, prioritized, and
|
||||||
|
sent to the micro-controller (via stepcompress.c:steppersync and
|
||||||
|
serialqueue.c:serialqueue).
|
||||||
|
|
||||||
|
* Processing of the queue_step commands on the micro-controller starts
|
||||||
|
in command.c which parses the command and calls
|
||||||
|
`command_queue_step()`. The command_queue_step() code (in stepper.c)
|
||||||
|
just appends the parameters of each queue_step command to a per
|
||||||
|
stepper queue. Under normal operation the queue_step command is
|
||||||
|
parsed and queued at least 100ms before the time of its first
|
||||||
|
step. Finally, the generation of stepper events is done in
|
||||||
|
`stepper_event()`. It's called from the hardware timer interrupt at
|
||||||
|
the scheduled time of the first step. The stepper_event() code
|
||||||
|
generates a step pulse and then reschedules itself to run at the
|
||||||
|
time of the next step pulse for the given queue_step parameters. The
|
||||||
|
parameters for each queue_step command are "interval", "count", and
|
||||||
|
"add". At a high-level, stepper_event() runs the following, 'count'
|
||||||
|
times: `do_step(); next_wake_time = last_wake_time + interval;
|
||||||
|
interval += add;`
|
||||||
|
|
||||||
|
The above may seem like a lot of complexity to execute a
|
||||||
|
movement. However, the only really interesting parts are in the
|
||||||
|
ToolHead and kinematic classes. It's this part of the code which
|
||||||
|
specifies the movements and their timings. The remaining parts of the
|
||||||
|
processing is mostly just communication and plumbing.
|
||||||
|
|
||||||
|
Adding a host module
|
||||||
|
====================
|
||||||
|
|
||||||
|
The Klippy host code has a dynamic module loading capability. If a
|
||||||
|
config section named "[my_module]" is found in the printer config file
|
||||||
|
then the software will automatically attempt to load the python module
|
||||||
|
klippy/extras/my_module.py . This module system is the preferred
|
||||||
|
method for adding new functionality to Klipper.
|
||||||
|
|
||||||
|
The easiest way to add a new module is to use an existing module as a
|
||||||
|
reference - see **klippy/extras/servo.py** as an example.
|
||||||
|
|
||||||
|
The following may also be useful:
|
||||||
|
* Execution of the module starts in the module level `load_config()`
|
||||||
|
function (for config sections of the form [my_module]) or in
|
||||||
|
`load_config_prefix()` (for config sections of the form
|
||||||
|
[my_module my_name]). This function is passed a "config" object and
|
||||||
|
it must return a new "printer object" associated with the given
|
||||||
|
config section.
|
||||||
|
* During the process of instantiating a new printer object, the config
|
||||||
|
object can be used to read parameters from the given config
|
||||||
|
section. This is done using `config.get()`, `config.getfloat()`,
|
||||||
|
`config.getint()`, etc. methods. Be sure to read all values from the
|
||||||
|
config during the construction of the printer object - if the user
|
||||||
|
specifies a config parameter that is not read during this phase then
|
||||||
|
it will be assumed it is a typo in the config and an error will be
|
||||||
|
raised.
|
||||||
|
* Use the `config.get_printer()` method to obtain a reference to the
|
||||||
|
main "printer" class. This "printer" class stores references to all
|
||||||
|
the "printer objects" that have been instantiated. Use the
|
||||||
|
`printer.lookup_object()` method to find references to other printer
|
||||||
|
objects. Almost all functionality (even core kinematic modules) are
|
||||||
|
encapsulated in one of these printer objects. Note, though, that
|
||||||
|
when a new module is instantiated, not all other printer objects
|
||||||
|
will have been instantiated. The "gcode" and "pins" modules will
|
||||||
|
always be available, but for other modules it is a good idea to
|
||||||
|
defer the lookup.
|
||||||
|
* Define a `printer_state()` method if the code needs to be called
|
||||||
|
during printer setup and/or shutdown. This method is called twice
|
||||||
|
during setup (with "connect" and then "ready") and may also be
|
||||||
|
called at run-time (with "shutdown" or "disconnect"). It is common
|
||||||
|
to perform "printer object" lookup during the "connect" and "ready"
|
||||||
|
phases.
|
||||||
|
* If there is an error in the user's config, be sure to raise it
|
||||||
|
during the `load_config()` or `printer_state("connect")` phases. Use
|
||||||
|
either `raise config.error("my error")` or `raise
|
||||||
|
printer.config_error("my error")` to report the error.
|
||||||
|
* Use the "pins" module to configure a pin on a micro-controller. This
|
||||||
|
is typically done with something similar to
|
||||||
|
`printer.lookup_object("pins").setup_pin("pwm",
|
||||||
|
config.get("my_pin"))`. The returned object can then be commanded at
|
||||||
|
run-time.
|
||||||
|
* If the module needs access to system timing or external file
|
||||||
|
descriptors then use `printer.get_reactor()` to obtain access to the
|
||||||
|
global "event reactor" class. This reactor class allows one to
|
||||||
|
schedule timers, wait for input on file descriptors, and to "sleep"
|
||||||
|
the host code.
|
||||||
|
* Do not use global variables. All state should be stored in the
|
||||||
|
printer object returned from the `load_config()` function. This is
|
||||||
|
important as otherwise the RESTART command may not perform as
|
||||||
|
expected. Also, for similar reasons, if any external files (or
|
||||||
|
sockets) are opened then be sure to close them from the
|
||||||
|
`printer_state("disconnect")` callback.
|
||||||
|
* Avoid accessing the internal member variables (or calling methods
|
||||||
|
that start with an underscore) of other printer objects. Observing
|
||||||
|
this convention makes it easier to manage future changes.
|
||||||
|
* If submitting the module for inclusion in the main Klipper code, be
|
||||||
|
sure to place a copyright notice at the top of the module. See the
|
||||||
|
existing modules for the preferred format.
|
||||||
|
|
||||||
|
Adding new kinematics
|
||||||
|
=====================
|
||||||
|
|
||||||
|
This section provides some tips on adding support to Klipper for
|
||||||
|
additional types of printer kinematics. This type of activity requires
|
||||||
|
excellent understanding of the math formulas for the target
|
||||||
|
kinematics. It also requires software development skills - though one
|
||||||
|
should only need to update the host software (which is written in
|
||||||
|
Python).
|
||||||
|
|
||||||
|
Useful steps:
|
||||||
|
1. Start by studying the [above section](#code-flow-of-a-move-command)
|
||||||
|
and the [Kinematics document](Kinematics.md).
|
||||||
|
2. Review the existing kinematic classes in cartesian.py, corexy.py,
|
||||||
|
and delta.py. The kinematic classes are tasked with converting a
|
||||||
|
move in cartesian coordinates to the movement on each stepper. One
|
||||||
|
should be able to copy one of these files as a starting point.
|
||||||
|
3. Implement the `get_postion()` method in the new kinematics
|
||||||
|
class. This method converts the current stepper position of each
|
||||||
|
stepper axis (stored in millimeters) to a position in cartesian
|
||||||
|
space (also in millimeters).
|
||||||
|
4. Implement the `set_postion()` method. This is the inverse of
|
||||||
|
get_position() - it sets each axis position (in millimeters) given
|
||||||
|
a position in cartesian coordinates.
|
||||||
|
5. Implement the `move()` method. The goal of the move() method is to
|
||||||
|
convert a move defined in cartesian space to a series of stepper
|
||||||
|
step times that implement the requested movement.
|
||||||
|
* The `move()` method is passed a "print_time" parameter (which
|
||||||
|
stores a time in seconds) and a "move" class instance that fully
|
||||||
|
defines the movement. The goal is to repeatedly invoke the
|
||||||
|
`stepper.step()` method with the time (relative to print_time)
|
||||||
|
that each stepper should step at to obtain the desired motion.
|
||||||
|
* One "trick" to help with the movement calculations is to imagine
|
||||||
|
there is a physical rail between `move.start_pos` and
|
||||||
|
`move.end_pos` that confines the print head so that it can only
|
||||||
|
move along this straight line of motion. Then, if the head is
|
||||||
|
confined to that imaginary rail, the head is at `move.start_pos`,
|
||||||
|
only one stepper is enabled (all other steppers can move freely),
|
||||||
|
and the given stepper is stepped a single step, then one can
|
||||||
|
imagine that the head will move along the line of movement some
|
||||||
|
distance. Determine the formula converting this step distance to
|
||||||
|
distance along the line of movement. Once one has the distance
|
||||||
|
along the line of movement, one can figure out the time that the
|
||||||
|
head should be at that position (using the standard formulas for
|
||||||
|
velocity and acceleration). This time is the ideal step time for
|
||||||
|
the given stepper and it can be passed to the `stepper.step()`
|
||||||
|
method.
|
||||||
|
* The `stepper.step()` method must always be called with an
|
||||||
|
increasing time for a given stepper (steps must be scheduled in
|
||||||
|
the order they are to be executed). A common error during
|
||||||
|
kinematic development is to receive an "Internal error in
|
||||||
|
stepcompress" failure - this is generally due to the step()
|
||||||
|
method being invoked with a time earlier than the last scheduled
|
||||||
|
step. For example, if the last step in move1 is scheduled at a
|
||||||
|
time greater than the first step in move2 it will generally
|
||||||
|
result in the above error.
|
||||||
|
* Fractional steps. Be aware that a move request is given in
|
||||||
|
cartesian space and it is not confined to discreet
|
||||||
|
locations. Thus a move's start and end locations may translate to
|
||||||
|
a location on a stepper axis that is between two steps (a
|
||||||
|
fractional step). The code must handle this. The preferred
|
||||||
|
approach is to schedule the next step at the time a move would
|
||||||
|
position the stepper axis at least half way towards the next
|
||||||
|
possible step location. Incorrect handling of fractional steps is
|
||||||
|
a common cause of "Internal error in stepcompress" failures.
|
||||||
|
6. Other methods. The `home()`, `check_move()`, and other methods
|
||||||
|
should also be implemented. However, at the start of development
|
||||||
|
one can use empty code here.
|
||||||
|
7. Implement test cases. Create a g-code file with a series of moves
|
||||||
|
that can test important cases for the given kinematics. Follow the
|
||||||
|
[debugging documentation](Debugging.md) to convert this g-code file
|
||||||
|
to micro-controller commands. This is useful to exercise corner
|
||||||
|
cases and to check for regressions.
|
||||||
|
8. Optimize if needed. One may notice that the existing kinematic
|
||||||
|
classes do not call `stepper.step()`. This is purely an
|
||||||
|
optimization - the inner loop of the kinematic calculations were
|
||||||
|
moved to C to reduce load on the host cpu. All of the existing
|
||||||
|
kinematic classes started development using `stepper.step()` and
|
||||||
|
then were later optimized. The g-code to mcu command translation
|
||||||
|
(described in the previous step) is a useful tool during
|
||||||
|
optimization - if a code change is purely an optimization then it
|
||||||
|
should not impact the resulting text representation of the mcu
|
||||||
|
commands (though minor changes in output due to floating point
|
||||||
|
rounding are possible). So, one can use this system to detect
|
||||||
|
regressions.
|
||||||
|
|
||||||
|
Time
|
||||||
|
====
|
||||||
|
|
||||||
|
Fundamental to the operation of Klipper is the handling of clocks,
|
||||||
|
times, and timestamps. Klipper executes actions on the printer by
|
||||||
|
scheduling events to occur in the near future. For example, to turn on
|
||||||
|
a fan, the code might schedule a change to a GPIO pin in a 100ms. It
|
||||||
|
is rare for the code to attempt to take an instantaneous action. Thus,
|
||||||
|
the handling of time within Klipper is critical to correct operation.
|
||||||
|
|
||||||
|
There are three types of times tracked internally in the Klipper host
|
||||||
|
software:
|
||||||
|
* System time. The system time uses the system's monotonic clock - it
|
||||||
|
is a floating point number stored as seconds and it is (generally)
|
||||||
|
relative to when the host computer was last started. System times
|
||||||
|
have limited use in the software - they are primarily used when
|
||||||
|
interacting with the operating system. Within the host code, system
|
||||||
|
times are frequently stored in variables named *eventtime* or
|
||||||
|
*curtime*.
|
||||||
|
* Print time. The print time is synchronized to the main
|
||||||
|
micro-controller clock (the micro-controller defined in the "[mcu]"
|
||||||
|
config section). It is a floating point number stored as seconds and
|
||||||
|
is relative to when the main mcu was last restarted. It is possible
|
||||||
|
to convert from a "print time" to the main micro-controller's
|
||||||
|
hardware clock by multiplying the print time by the mcu's statically
|
||||||
|
configured frequency rate. The high-level host code uses print times
|
||||||
|
to calculates almost all physical actions (eg, head movement, heater
|
||||||
|
changes, etc.). Within the host code, print times are generally
|
||||||
|
stored in variables named *print_time* or *move_time*.
|
||||||
|
* MCU clock. This is the hardware clock counter on each
|
||||||
|
micro-controller. It is stored as an integer and its update rate is
|
||||||
|
relative to the frequency of the given micro-controller. The host
|
||||||
|
software translates its internal times to clocks before transmission
|
||||||
|
to the mcu. The mcu code only ever tracks time in clock
|
||||||
|
ticks. Within the host code, clock values are tracked as 64bit
|
||||||
|
integers, while the mcu code uses 32bit integers. Within the host
|
||||||
|
code, clocks are generally stored in variables with names containing
|
||||||
|
*clock* or *ticks*.
|
||||||
|
|
||||||
|
Conversion between the different time formats is primarily implemented
|
||||||
|
in the **klippy/clocksync.py** code.
|
||||||
|
|
||||||
|
Some things to be aware of when reviewing the code:
|
||||||
|
* 32bit and 64bit clocks: To reduce bandwidth and to improve
|
||||||
|
micro-controller efficiency, clocks on the micro-controller are
|
||||||
|
tracked as 32bit integers. When comparing two clocks in the mcu
|
||||||
|
code, the `timer_is_before()` function must always be used to ensure
|
||||||
|
integer rollovers are handled properly. The host software converts
|
||||||
|
32bit clocks to 64bit clocks by appending the high-order bits from
|
||||||
|
the last mcu timestamp it has received - no message from the mcu is
|
||||||
|
ever more than 2^31 clock ticks in the future or past so this
|
||||||
|
conversion is never ambiguous. The host converts from 64bit clocks
|
||||||
|
to 32bit clocks by simply truncating the high-order bits. To ensure
|
||||||
|
there is no ambiguity in this conversion, the
|
||||||
|
**klippy/serialqueue.c** code will buffer messages until they are
|
||||||
|
within 2^31 clock ticks of their target time.
|
||||||
|
* Multiple micro-controllers: The host software supports using
|
||||||
|
multiple micro-controllers on a single printer. In this case, the
|
||||||
|
"MCU clock" of each micro-controller is tracked separately. The
|
||||||
|
clocksync.py code handles clock drift between micro-controllers by
|
||||||
|
modifying the way it converts from "print time" to "MCU clock". On
|
||||||
|
secondary mcus, the mcu frequency that is used in this conversion is
|
||||||
|
regularly updated to account for measured drift.
|
||||||
|
|||||||
147
docs/Config_checks.md
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
This document provides a list of steps to help confirm the pin
|
||||||
|
settings in the Klipper printer.cfg file. It is a good idea to run
|
||||||
|
through these steps after following the steps in the
|
||||||
|
[installation document](Installation.md).
|
||||||
|
|
||||||
|
During this guide, it may be necessary to make changes to the Klipper
|
||||||
|
config file. Be sure to issue a RESTART command after every change to
|
||||||
|
the config file to ensure that the change takes effect (type "restart"
|
||||||
|
in the Octoprint terminal tab and then click "Send"). It's also a good
|
||||||
|
idea to issue a STATUS command after every RESTART to verify that the
|
||||||
|
config file is successfully loaded.
|
||||||
|
|
||||||
|
### Verify temperature
|
||||||
|
|
||||||
|
Start by verifying that temperatures are being properly
|
||||||
|
reported. Navigate to the Octoprint temperature tab.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Verify that the temperature of the nozzle and bed (if applicable) are
|
||||||
|
present and not increasing. If it is increasing, remove power from the
|
||||||
|
printer. If the temperatures are not accurate, review the
|
||||||
|
"sensor_type" and "sensor_pin" settings for the nozzle and/or bed.
|
||||||
|
|
||||||
|
### Verify M112
|
||||||
|
|
||||||
|
Navigate to the Octoprint terminal tab and issue an M112 command in
|
||||||
|
the terminal box. This command requests Klipper to go into a
|
||||||
|
"shutdown" state. It will cause Octoprint to disconnect from Klipper -
|
||||||
|
navigate to the Connection area and click on "Connect" to cause
|
||||||
|
Octoprint to reconnect. Then navigate to the Octoprint temperature tab
|
||||||
|
and verify that temperatures continue to update and the temperatures
|
||||||
|
are not increasing. If temperatures are increasing, remove power from
|
||||||
|
the printer.
|
||||||
|
|
||||||
|
The M112 command causes Klipper to go into a "shutdown" state. To
|
||||||
|
clear this state, issue a FIRMWARE_RESTART command in the Octoprint
|
||||||
|
terminal tab.
|
||||||
|
|
||||||
|
### Verify heaters
|
||||||
|
|
||||||
|
Navigate to the Octoprint temperature tab and type in 50 followed by
|
||||||
|
enter in the "Tool" temperature box. The extruder temperature in the
|
||||||
|
graph should start to increase (within about 30 seconds or so). Then
|
||||||
|
go to the "Tool" temperature drop-down box and select "Off". After
|
||||||
|
several minutes the temperature should start to return to its initial
|
||||||
|
room temperature value. If the temperature does not increase then
|
||||||
|
verify the "heater_pin" setting in the config.
|
||||||
|
|
||||||
|
If the printer has a heated bed then perform the above test again with
|
||||||
|
the bed.
|
||||||
|
|
||||||
|
### Verify stepper motor enable pin
|
||||||
|
|
||||||
|
Verify that all of the printer axes can manually move freely (the
|
||||||
|
stepper motors are disabled). If not, issue an M84 command to disable
|
||||||
|
the motors. If any of the axes still can not move freely, then verify
|
||||||
|
the stepper "enable_pin" configuration for the given axis. On most
|
||||||
|
commodity stepper motor drivers, the motor enable pin is "active low"
|
||||||
|
and therefore the enable pin should have a "!" before the pin (for
|
||||||
|
example, "enable_pin: !ar38").
|
||||||
|
|
||||||
|
### Verify endstops
|
||||||
|
|
||||||
|
Manually move all the printer axes so that none of them are in contact
|
||||||
|
with an endstop. Send a QUERY_ENDSTOPS command via the Octoprint
|
||||||
|
terminal tab. It should respond with the current state of all of the
|
||||||
|
configured endstops and they should all report a state of "open". For
|
||||||
|
each of the endstops, rerun the QUERY_ENDSTOPS command while manually
|
||||||
|
triggering the endstop. The QUERY_ENDSTOPS command should report the
|
||||||
|
endstop as "TRIGGERED".
|
||||||
|
|
||||||
|
If the endstop appears inverted (it reports "open" when triggered and
|
||||||
|
vice-versa) then add a "!" to the pin definition (for example,
|
||||||
|
"endstop_pin: ^!ar3"), or remove the "!" if there is already one
|
||||||
|
present.
|
||||||
|
|
||||||
|
If the endstop does not change at all then it generally indicates that
|
||||||
|
the endstop is connected to a different pin. However, it may also
|
||||||
|
require a change to the pullup setting of the pin (the '^' at the
|
||||||
|
start of the endstop_pin name - most printers will use a pullup
|
||||||
|
resistor and the '^' should be present).
|
||||||
|
|
||||||
|
### Verify stepper motor direction
|
||||||
|
|
||||||
|
Make sure the printer.cfg file does not have "homing_speed" set for
|
||||||
|
any axis (or set it to a value of 5 or less).
|
||||||
|
|
||||||
|
On cartesian style printers, manually move the X axis to a midway
|
||||||
|
point, issue a G28X0 command, and verify that the X motor moves slowly
|
||||||
|
towards the endstop defined for that axis. If the motor moves in the
|
||||||
|
wrong direction issue an M112 command to abort the move. A wrong
|
||||||
|
direction generally indicates that the "dir_pin" for the axis needs to
|
||||||
|
be inverted. This is done by adding a '!' to the "dir_pin" in the
|
||||||
|
printer config file (or removing it if one is already there). For
|
||||||
|
example, change "dir_pin: xyz" to "dir_pin: !xyz". Then RESTART and
|
||||||
|
retest the axis. If the axis does not move at all, then verify the
|
||||||
|
"enable_pin" and "step_pin" settings for the axis. For cartesian style
|
||||||
|
printers, repeat the test for the Y and Z axis with G28Y0 and G28Z0.
|
||||||
|
|
||||||
|
For delta style printers, manually move all three carriages to a
|
||||||
|
midway point and then issue a G28 command. Verify all three motors
|
||||||
|
move simultaneously upwards. If not, issue an M112 command and follow
|
||||||
|
the troubleshooting steps in the preceding paragraph.
|
||||||
|
|
||||||
|
### Verify extruder motor
|
||||||
|
|
||||||
|
To test the extruder motor it will be necessary to heat the extruder
|
||||||
|
to a printing temperature. Navigate to the Octoprint temperature tab
|
||||||
|
and select a target temperature from the temperature drop-down box (or
|
||||||
|
manually enter an appropriate temperature). Wait for the printer to
|
||||||
|
reach the desired temperature. Then navigate to the Octoprint control
|
||||||
|
tab and click the "Extrude" button. Verify that the extruder motor
|
||||||
|
turns in the correct direction. If it does not, see the
|
||||||
|
troubleshooting tips in the previous section to confirm the
|
||||||
|
"enable_pin", "step_pin", and "dir_pin" settings for the extruder.
|
||||||
|
|
||||||
|
### Calibrate PID settings
|
||||||
|
|
||||||
|
Klipper supports
|
||||||
|
[PID control](https://en.wikipedia.org/wiki/PID_controller) for the
|
||||||
|
extruder and bed heaters. In order to use this control mechanism it is
|
||||||
|
necessary to calibrate the PID settings on each printer. (PID settings
|
||||||
|
found in other firmwares or in the example configuration files often
|
||||||
|
work poorly.)
|
||||||
|
|
||||||
|
To calibrate the extruder, navigate to the OctoPrint terminal tab and
|
||||||
|
run the PID_CALIBRATE command. For example: `PID_CALIBRATE
|
||||||
|
HEATER=extruder TARGET=170`
|
||||||
|
|
||||||
|
At the completion of the tuning test, update the printer.cfg file with
|
||||||
|
the recommended pid_Kp, pid_Ki, and pid_Kd values.
|
||||||
|
|
||||||
|
If the printer has a heated bed and it supports being driven by PWM
|
||||||
|
(Pulse Width Modulation) then it is recommended to use PID control for
|
||||||
|
the bed. (When the bed heater is controlled using the PID algorithm it
|
||||||
|
may turn on and off ten times a second, which may not be suitable for
|
||||||
|
heaters using a mechanical switch.) A typical bed PID calibration
|
||||||
|
command is: `PID_CALIBRATE HEATER=heater_bed TARGET=60`
|
||||||
|
|
||||||
|
### Next steps
|
||||||
|
|
||||||
|
This guide is intended to help with basic verification of pin settings
|
||||||
|
in the Klipper configuration file. It may be necessary to perform
|
||||||
|
detailed printer calibration - a number of guides are available online
|
||||||
|
to help with this (for example, do a web search for "3d printer
|
||||||
|
calibration").
|
||||||
51
docs/Contact.md
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
This page provides information on how to contact the Klipper
|
||||||
|
developers.
|
||||||
|
|
||||||
|
Issue reporting
|
||||||
|
===============
|
||||||
|
|
||||||
|
In order to report a problem or request a change in behavior, it is
|
||||||
|
necessary to collect the Klipper log file. The first step is to
|
||||||
|
**issue an M112 command** in the OctoPrint terminal window immediately
|
||||||
|
after the undesirable event occurs. This causes Klipper to go into a
|
||||||
|
"shutdown state" and it will cause additional debugging information to
|
||||||
|
be written to the log file.
|
||||||
|
|
||||||
|
Issue requests are submitted through Github. **All issues must
|
||||||
|
include the full /tmp/klippy.log log file from the session that
|
||||||
|
produced the error.** An "scp" and/or "sftp" utility is needed to
|
||||||
|
acquire this log file. The "scp" utility comes standard with Linux and
|
||||||
|
MacOS desktops. There are freely available scp utilities for other
|
||||||
|
desktops (eg, WinSCP).
|
||||||
|
|
||||||
|
Use the scp utility to copy the `/tmp/klippy.log` file from the host
|
||||||
|
machine to your desktop. It is a good idea to compress the klippy.log
|
||||||
|
file before posting it (eg, using zip or gzip). Open a new issue at
|
||||||
|
https://github.com/KevinOConnor/klipper/issues , provide a description
|
||||||
|
of the problem, and **attach the `klippy.log` file to the issue**:
|
||||||
|

|
||||||
|
|
||||||
|
Mailing list
|
||||||
|
============
|
||||||
|
|
||||||
|
There is a mailing list for general discussions on Klipper. In order
|
||||||
|
to send am email to the list, one must first subscribe:
|
||||||
|
https://www.freelists.org/list/klipper . Once subscribed, emails may
|
||||||
|
be sent to `klipper@freelists.org`.
|
||||||
|
|
||||||
|
Archives of the mailing list are available at:
|
||||||
|
https://www.freelists.org/archive/klipper/
|
||||||
|
|
||||||
|
IRC
|
||||||
|
===
|
||||||
|
|
||||||
|
One may join the #klipper channel on freenode.net (
|
||||||
|
irc://chat.freenode.net:6667 ).
|
||||||
|
|
||||||
|
To communicate in this IRC channel one will need an IRC
|
||||||
|
client. Configure it to connect to chat.freenode.net on port 6667 and
|
||||||
|
join the #klipper channel (`/join #klipper`).
|
||||||
|
|
||||||
|
If asking a question on IRC, be sure to ask the question and then stay
|
||||||
|
connected to the channel to receive responses. Due to timezone
|
||||||
|
differences, it may take several hours before receiving a response.
|
||||||
@@ -1,4 +1,47 @@
|
|||||||
The Klippy host code has some tools to help in debugging the firmware.
|
The Klippy host code has some tools to help in debugging.
|
||||||
|
|
||||||
|
Translating gcode files to micro-controller commands
|
||||||
|
====================================================
|
||||||
|
|
||||||
|
The Klippy host code can run in a batch mode to produce the low-level
|
||||||
|
micro-controller commands associated with a gcode file. Inspecting
|
||||||
|
these low-level commands is useful when trying to understand the
|
||||||
|
actions of the low-level hardware. It can also be useful to compare
|
||||||
|
the difference in micro-controller commands after a code change.
|
||||||
|
|
||||||
|
To run Klippy in this batch mode, there is a one time step necessary
|
||||||
|
to generate the micro-controller "data dictionary". This is done by
|
||||||
|
compiling the micro-controller code to obtain the **out/klipper.dict**
|
||||||
|
file:
|
||||||
|
|
||||||
|
```
|
||||||
|
make menuconfig
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
Once the above is done it is possible to run Klipper in batch mode
|
||||||
|
(see [installation](Installation.md) for the steps necessary to build
|
||||||
|
the python virtual environment and a printer.cfg file):
|
||||||
|
|
||||||
|
```
|
||||||
|
~/klippy-env/bin/python ./klippy/klippy.py ~/printer.cfg -i test.gcode -o test.serial -v -d out/klipper.dict
|
||||||
|
```
|
||||||
|
|
||||||
|
The above will produce a file **test.serial** with the binary serial
|
||||||
|
output. This output can be translated to readable text with:
|
||||||
|
|
||||||
|
```
|
||||||
|
~/klippy-env/bin/python ./klippy/parsedump.py out/klipper.dict test.serial > test.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
The resulting file **test.txt** contains a human readable list of
|
||||||
|
micro-controller commands.
|
||||||
|
|
||||||
|
The batch mode disables certain response / request commands in order
|
||||||
|
to function. As a result, there will be some differences between
|
||||||
|
actual commands and the above output. The generated data is useful for
|
||||||
|
testing and inspection; it is not useful for sending to a real
|
||||||
|
micro-controller.
|
||||||
|
|
||||||
Testing with simulavr
|
Testing with simulavr
|
||||||
=====================
|
=====================
|
||||||
@@ -32,26 +75,20 @@ cd /patch/to/klipper
|
|||||||
make menuconfig
|
make menuconfig
|
||||||
```
|
```
|
||||||
|
|
||||||
and compile the firmware for an AVR atmega644p, disable the AVR
|
and compile the micro-controller software for an AVR atmega644p, set
|
||||||
watchdog timer, set the MCU frequency to 20000000, and set the serial
|
the MCU frequency to 20Mhz, and select SIMULAVR software emulation
|
||||||
baud rate to 115200. Then one can compile Klipper (run `make`) and
|
support. Then one can compile Klipper (run `make`) and then start the
|
||||||
then start the simulation with:
|
simulation with:
|
||||||
|
|
||||||
```
|
```
|
||||||
PYTHONPATH=/path/to/simulavr/src/python/ ./scripts/avrsim.py -m atmega644 -s 20000000 -b 115200 out/klipper.elf
|
PYTHONPATH=/path/to/simulavr/src/python/ ./scripts/avrsim.py -m atmega644 -s 20000000 -b 250000 out/klipper.elf
|
||||||
```
|
|
||||||
|
|
||||||
It may be necessary to create a python virtual environment to run
|
|
||||||
Klippy on the target machine. To do so, run:
|
|
||||||
|
|
||||||
```
|
|
||||||
virtualenv ~/klippy-env
|
|
||||||
~/klippy-env/bin/pip install cffi==1.6.0 pyserial==2.7
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Then, with simulavr running in another window, one can run the
|
Then, with simulavr running in another window, one can run the
|
||||||
following to read gcode from a file (eg, "test.gcode"), process it
|
following to read gcode from a file (eg, "test.gcode"), process it
|
||||||
with Klippy, and send it to Klipper running in simulavr:
|
with Klippy, and send it to Klipper running in simulavr (see
|
||||||
|
[installation](Installation.md) for the steps necessary to build the
|
||||||
|
python virtual environment):
|
||||||
|
|
||||||
```
|
```
|
||||||
~/klippy-env/bin/python ./klippy/klippy.py config/avrsim.cfg -i test.gcode -v
|
~/klippy-env/bin/python ./klippy/klippy.py config/avrsim.cfg -i test.gcode -v
|
||||||
@@ -66,7 +103,7 @@ the directions above, but run avrsim.py with a command-line like the
|
|||||||
following:
|
following:
|
||||||
|
|
||||||
```
|
```
|
||||||
PYTHONPATH=/path/to/simulavr/src/python/ ./scripts/avrsim.py -m atmega644 -s 20000000 -b 115200 out/klipper.elf -t PORTA.PORT,PORTC.PORT
|
PYTHONPATH=/path/to/simulavr/src/python/ ./scripts/avrsim.py -m atmega644 -s 20000000 -b 250000 out/klipper.elf -t PORTA.PORT,PORTC.PORT
|
||||||
```
|
```
|
||||||
|
|
||||||
The above would create a file **avrsim.vcd** with information on each
|
The above would create a file **avrsim.vcd** with information on each
|
||||||
@@ -78,13 +115,59 @@ gtkwave avrsim.vcd
|
|||||||
```
|
```
|
||||||
|
|
||||||
Manually sending commands to the micro-controller
|
Manually sending commands to the micro-controller
|
||||||
-------------------------------------------------
|
=================================================
|
||||||
|
|
||||||
Normally, Klippy would be used to translate gcode commands to Klipper
|
Normally, the host klippy.py process would be used to translate gcode
|
||||||
commands. However, it's also possible to manually send Klipper
|
commands to Klipper micro-controller commands. However, it's also
|
||||||
commands (functions marked with the DECL_COMMAND() macro in the
|
possible to manually send these MCU commands (functions marked with
|
||||||
Klipper source code). To do so, run:
|
the DECL_COMMAND() macro in the Klipper source code). To do so, run:
|
||||||
|
|
||||||
```
|
```
|
||||||
~/klippy-env/bin/python ./klippy/console.py /tmp/pseudoserial 115200
|
~/klippy-env/bin/python ./klippy/console.py /tmp/pseudoserial 250000
|
||||||
```
|
```
|
||||||
|
|
||||||
|
See the "HELP" command within the tool for more information on its
|
||||||
|
functionality.
|
||||||
|
|
||||||
|
Generating load graphs
|
||||||
|
======================
|
||||||
|
|
||||||
|
The Klippy log file (/tmp/klippy.log) stores statistics on bandwidth,
|
||||||
|
micro-controller load, and host buffer load. It can be useful to graph
|
||||||
|
these statistics after a print.
|
||||||
|
|
||||||
|
To generate a graph, a one time step is necessary to install the
|
||||||
|
"matplotlib" package:
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install python-matplotlib
|
||||||
|
```
|
||||||
|
|
||||||
|
Then graphs can be produced with:
|
||||||
|
|
||||||
|
```
|
||||||
|
~/klipper/scripts/graphstats.py /tmp/klippy.log loadgraph.png
|
||||||
|
```
|
||||||
|
|
||||||
|
One can then view the resulting **loadgraph.png** file.
|
||||||
|
|
||||||
|
Extracting information from the klippy.log file
|
||||||
|
===============================================
|
||||||
|
|
||||||
|
The Klippy log file (/tmp/klippy.log) also contains debugging
|
||||||
|
information. There is a logextract.py script that may be useful when
|
||||||
|
analyzing a micro-controller shutdown or similar problem. It is
|
||||||
|
typically run with something like:
|
||||||
|
|
||||||
|
```
|
||||||
|
mkdir work_directory
|
||||||
|
cd work_directory
|
||||||
|
cp /tmp/klippy.log .
|
||||||
|
~/klipper/scripts/logextract.py ./klippy.log
|
||||||
|
```
|
||||||
|
|
||||||
|
The script will extract the printer config file and will extract MCU
|
||||||
|
shutdown information. The information dumps from an MCU shutdown (if
|
||||||
|
present) will be reordered by timestamp to assist in diagnosing cause
|
||||||
|
and effect scenarios.
|
||||||
|
|||||||
252
docs/FAQ.md
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
Frequently asked questions
|
||||||
|
==========================
|
||||||
|
|
||||||
|
1. [How can I donate to the project?](#how-can-i-donate-to-the-project)
|
||||||
|
2. [How do I calculate the step_distance parameter in the printer config file?](#how-do-i-calculate-the-step_distance-parameter-in-the-printer-config-file)
|
||||||
|
3. [Where's my serial port?](#wheres-my-serial-port)
|
||||||
|
4. [The "make flash" command doesn't work](#the-make-flash-command-doesnt-work)
|
||||||
|
5. [How do I change the serial baud rate?](#how-do-i-change-the-serial-baud-rate)
|
||||||
|
6. [Can I run Klipper on something other than a Raspberry Pi 3?](#can-i-run-klipper-on-something-other-than-a-raspberry-pi-3)
|
||||||
|
7. [Why can't I move the stepper before homing the printer?](#why-cant-i-move-the-stepper-before-homing-the-printer)
|
||||||
|
8. [Why is the Z position_endstop set to 0.5 in the default configs?](#why-is-the-z-position_endstop-set-to-05-in-the-default-configs)
|
||||||
|
9. [I converted my config from Marlin and the X/Y axes work fine, but I just get a screeching noise when homing the Z axis](#i-converted-my-config-from-marlin-and-the-xy-axes-work-fine-but-i-just-get-a-screeching-noise-when-homing-the-z-axis)
|
||||||
|
10. [When I set "restart_method=command" my AVR device just hangs on a restart](#when-i-set-restart_methodcommand-my-avr-device-just-hangs-on-a-restart)
|
||||||
|
11. [Will the heaters be left on if the Raspberry Pi crashes?](#will-the-heaters-be-left-on-if-the-raspberry-pi-crashes)
|
||||||
|
12. [How do I upgrade to the latest software?](#how-do-i-upgrade-to-the-latest-software)
|
||||||
|
|
||||||
|
### How can I donate to the project?
|
||||||
|
|
||||||
|
Thanks. Kevin has a Patreon page at: https://www.patreon.com/koconnor
|
||||||
|
|
||||||
|
### How do I calculate the step_distance parameter in the printer config file?
|
||||||
|
|
||||||
|
If you know the steps per millimeter for the axis then use a
|
||||||
|
calculator to divide 1.0 by steps_per_mm. Then round this number to
|
||||||
|
six decimal places and place it in the config (six decimal places is
|
||||||
|
nano-meter precision).
|
||||||
|
|
||||||
|
The step_distance defines the distance that the axis will travel on
|
||||||
|
each motor driver pulse. It can also be calculated from the axis
|
||||||
|
pitch, motor step angle, and driver microstepping. If unsure, do a web
|
||||||
|
search for "calculate steps per mm" to find an online calculator.
|
||||||
|
|
||||||
|
### Where's my serial port?
|
||||||
|
|
||||||
|
The general way to find a USB serial port is to run `ls -l
|
||||||
|
/dev/serial/by-id/` from an ssh terminal on the host machine. It will
|
||||||
|
likely produce output similar to the following:
|
||||||
|
```
|
||||||
|
lrwxrwxrwx 1 root root 13 Jan 3 22:15 usb-UltiMachine__ultimachine.com__RAMBo_12345678912345678912-if00 -> ../../ttyACM0
|
||||||
|
```
|
||||||
|
|
||||||
|
The name found in the above command is stable and it is possible to
|
||||||
|
use it in the config file and while flashing the micro-controller
|
||||||
|
code. For example, a flash command might look similar to:
|
||||||
|
```
|
||||||
|
sudo service klipper stop
|
||||||
|
make flash FLASH_DEVICE=/dev/serial/by-id/usb-UltiMachine__ultimachine.com__RAMBo_12345678912345678912-if00
|
||||||
|
sudo service klipper start
|
||||||
|
```
|
||||||
|
and the updated config might look like:
|
||||||
|
```
|
||||||
|
[mcu]
|
||||||
|
serial: /dev/serial/by-id/usb-UltiMachine__ultimachine.com__RAMBo_12345678912345678912-if00
|
||||||
|
```
|
||||||
|
|
||||||
|
Be sure to copy-and-paste the name from the "ls" command that you ran
|
||||||
|
above as the name will be different for each printer.
|
||||||
|
|
||||||
|
### The "make flash" command doesn't work
|
||||||
|
|
||||||
|
The code attempts to flash the device using the most common method for
|
||||||
|
each platform. Unfortunately, there is a lot of variance in flashing
|
||||||
|
methods, so the "make flash" command may not work on all boards.
|
||||||
|
|
||||||
|
If you're having an intermittent failure or you do have a standard
|
||||||
|
setup, then double check that Klipper isn't running when flashing
|
||||||
|
(sudo service klipper stop), make sure OctoPrint isn't trying to
|
||||||
|
connect directly to the device (open the Connection tab in the web
|
||||||
|
page and click Disconnect if the Serial Port is set to the device),
|
||||||
|
and make sure FLASH_DEVICE is set correctly for your board (see the
|
||||||
|
[question above](#wheres-my-serial-port)).
|
||||||
|
|
||||||
|
However, if "make flash" just doesn't work for your board, then you
|
||||||
|
will need to manually flash. See if there is a config file in the
|
||||||
|
[config directory](../config) with specific instructions for flashing
|
||||||
|
the device. Also, check the board manufacturer's documentation to see
|
||||||
|
if it describes how to flash the device. Finally, on AVR devices, it
|
||||||
|
may be possible to manually flash the device using
|
||||||
|
[avrdude](http://www.nongnu.org/avrdude/) with custom command-line
|
||||||
|
parameters - see the avrdude documentation for further information.
|
||||||
|
|
||||||
|
### How do I change the serial baud rate?
|
||||||
|
|
||||||
|
The default baud rate is 250000 in both the Klipper micro-controller
|
||||||
|
configuration and in the Klipper host software. This works on almost
|
||||||
|
all micro-controllers and it is the recommended setting. (Most online
|
||||||
|
guides that refer to a baud rate of 115200 are outdated.)
|
||||||
|
|
||||||
|
If you need to change the baud rate, then the new rate will need to be
|
||||||
|
configured in the micro-controller (during **make menuconfig**) and
|
||||||
|
that updated code will need to be flashed to the micro-controller. The
|
||||||
|
Klipper printer.cfg file will also need to be updated to match that
|
||||||
|
baud rate (see the example.cfg file for details). For example:
|
||||||
|
```
|
||||||
|
[mcu]
|
||||||
|
baud: 250000
|
||||||
|
```
|
||||||
|
|
||||||
|
The baud rate shown on the OctoPrint web page has no impact on the
|
||||||
|
internal Klipper micro-controller baud rate. Always set the OctoPrint
|
||||||
|
baud rate to 250000 when using Klipper.
|
||||||
|
|
||||||
|
### Can I run Klipper on something other than a Raspberry Pi 3?
|
||||||
|
|
||||||
|
The recommended hardware is a Raspberry Pi 2 or a Raspberry
|
||||||
|
Pi 3.
|
||||||
|
|
||||||
|
Klipper will run on a Raspberry Pi 1 and on the Raspberry Pi Zero, but
|
||||||
|
these boards don't have enough processing power to run OctoPrint
|
||||||
|
well. It's not uncommon for print stalls to occur on these slower
|
||||||
|
machines (the printer may move faster than OctoPrint can send movement
|
||||||
|
commands) when printing directly from OctoPrint. If you wish to run on
|
||||||
|
one one of these slower boards anyway, consider using the
|
||||||
|
"virtual_sdcard" feature (see
|
||||||
|
[config/example-extras.cfg](../config/example-extras.cfg) for details)
|
||||||
|
when printing.
|
||||||
|
|
||||||
|
For running on the Beaglebone, see the
|
||||||
|
[Beaglebone specific installation instructions](beaglebone.md).
|
||||||
|
|
||||||
|
Klipper has been run on other machines. The Klipper host software
|
||||||
|
only requires Python running on a Linux (or similar)
|
||||||
|
computer. However, if you wish to run it on a different machine you
|
||||||
|
will need Linux admin knowledge to install the system prerequisites
|
||||||
|
for that particular machine. See the
|
||||||
|
[install-octopi.sh](../scripts/install-octopi.sh) script for further
|
||||||
|
information on the necessary Linux admin steps.
|
||||||
|
|
||||||
|
### Why can't I move the stepper before homing the printer?
|
||||||
|
|
||||||
|
The code does this to reduce the chance of accidentally commanding the
|
||||||
|
head into the bed or a wall. Once the printer is homed the software
|
||||||
|
attempts to verify each move is within the position_min/max defined in
|
||||||
|
the config file. If the motors are disabled (via an M84 or M18
|
||||||
|
command) then the motors will need to be homed again prior to
|
||||||
|
movement.
|
||||||
|
|
||||||
|
If you want to move the head after canceling a print via OctoPrint,
|
||||||
|
consider changing the OctoPrint cancel sequence to do that for
|
||||||
|
you. It's configured in OctoPrint via a web browser under:
|
||||||
|
Settings->GCODE Scripts
|
||||||
|
|
||||||
|
If you want to move the head after a print finishes, consider adding
|
||||||
|
the desired movement to the "custom g-code" section of your slicer.
|
||||||
|
|
||||||
|
### Why is the Z position_endstop set to 0.5 in the default configs?
|
||||||
|
|
||||||
|
For cartesian style printers the Z position_endstop specifies how far
|
||||||
|
the nozzle is from the bed when the endstop triggers. If possible, it
|
||||||
|
is recommended to use a Z-max endstop and home away from the bed (as
|
||||||
|
this reduces the potential for bed collisions). However, if one must
|
||||||
|
home towards the bed then it is recommended to position the endstop so
|
||||||
|
it triggers when the nozzle is still a small distance away from the
|
||||||
|
bed. This way, when homing the axis, it will stop before the nozzle
|
||||||
|
touches the bed.
|
||||||
|
|
||||||
|
Almost all mechanical switches can still move a small distance
|
||||||
|
(eg, 0.5mm) after they are triggered. So, for example, if the
|
||||||
|
position_endstop is set to 0.5mm then one may still command the
|
||||||
|
printer to move to Z0.2. The position_min config setting (which
|
||||||
|
defaults to 0) is used to specify the minimum Z position one may
|
||||||
|
command the printer to move to.
|
||||||
|
|
||||||
|
Note, the Z position_endstop specifies the distance from the nozzle to
|
||||||
|
the bed when the nozzle and bed (if applicable) are hot. It is typical
|
||||||
|
for thermal expansion to cause nozzle expansion of around .1mm, which
|
||||||
|
is also the typical thickness of a sheet of printer paper. Thus, it is
|
||||||
|
common to use the "paper test" to confirm calibration of the Z
|
||||||
|
height - check that the bed and nozzle are at room temperature, check
|
||||||
|
that there is no plastic on the head or bed, home the printer, place a
|
||||||
|
piece of paper between the nozzle and bed, and repeatedly command the
|
||||||
|
head to move closer to the bed checking each time if you feel a small
|
||||||
|
amount of friction when sliding the paper between bed and nozzle - if
|
||||||
|
all is calibrated well a small amount of friction would be felt when
|
||||||
|
the height is at Z0.
|
||||||
|
|
||||||
|
### I converted my config from Marlin and the X/Y axes work fine, but I just get a screeching noise when homing the Z axis
|
||||||
|
|
||||||
|
Short answer: Try reducing the max_z_velocity setting in the printer
|
||||||
|
config. Also, if the Z stepper is moving in the wrong direction, try
|
||||||
|
inverting the dir_pin setting in the config (eg, "dir_pin: !xyz"
|
||||||
|
instead of "dir_pin: xyz").
|
||||||
|
|
||||||
|
Long answer: In practice Marlin can typically only step at a rate of
|
||||||
|
around 10000 steps per second. If it is requested to move at a speed
|
||||||
|
that would require a higher step rate then Marlin will generally just
|
||||||
|
step as fast as it can. Klipper is able to achieve much higher step
|
||||||
|
rates, but the stepper motor may not have sufficient torque to move at
|
||||||
|
a higher speed. So, for a Z axis with a very precise step_distance the
|
||||||
|
actual obtainable max_z_velocity may be smaller than what is
|
||||||
|
configured in Marlin.
|
||||||
|
|
||||||
|
### When I set "restart_method=command" my AVR device just hangs on a restart
|
||||||
|
|
||||||
|
Some old versions of the AVR bootloader have a known bug in watchdog
|
||||||
|
event handling. This typically manifests when the printer.cfg file has
|
||||||
|
restart_method set to "command". When the bug occurs, the AVR device
|
||||||
|
will be unresponsive until power is removed and reapplied to the
|
||||||
|
device (the power or status LEDs may also blink repeatedly until the
|
||||||
|
power is removed).
|
||||||
|
|
||||||
|
The workaround is to use a restart_method other than "command" or to
|
||||||
|
flash an updated bootloader to the AVR device. Flashing a new
|
||||||
|
bootloader is a one time step that typically requires an external
|
||||||
|
programmer - search the web to find the instructions for your
|
||||||
|
particular device.
|
||||||
|
|
||||||
|
### Will the heaters be left on if the Raspberry Pi crashes?
|
||||||
|
|
||||||
|
The software has been designed to prevent that. Once the host enables
|
||||||
|
a heater, the host software needs to confirm that enablement every 5
|
||||||
|
seconds. If the micro-controller does not receive a confirmation every
|
||||||
|
5 seconds it goes into a "shutdown" state which is designed to turn
|
||||||
|
off all heaters and stepper motors.
|
||||||
|
|
||||||
|
See the "config_digital_out" command in the
|
||||||
|
[MCU commands](MCU_Commands.md) document for further details.
|
||||||
|
|
||||||
|
### How do I upgrade to the latest software?
|
||||||
|
|
||||||
|
The general way to upgrade is to ssh into the Raspberry Pi and run:
|
||||||
|
|
||||||
|
```
|
||||||
|
cd ~/klipper
|
||||||
|
git pull
|
||||||
|
~/klipper/scripts/install-octopi.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Then one can recompile and flash the micro-controller code. For
|
||||||
|
example:
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo service klipper stop
|
||||||
|
make flash FLASH_DEVICE=/dev/ttyACM0
|
||||||
|
sudo service klipper start
|
||||||
|
```
|
||||||
|
|
||||||
|
However, it's often the case that only the host software changes. In
|
||||||
|
this case, one can update and restart just the host software with:
|
||||||
|
|
||||||
|
```
|
||||||
|
cd ~/klipper
|
||||||
|
git pull
|
||||||
|
sudo service klipper restart
|
||||||
|
```
|
||||||
|
|
||||||
|
If after using this shortcut the software warns about needing to
|
||||||
|
reflash the micro-controller or some other unusual error occurs, then
|
||||||
|
follow the full upgrade steps outlined above. Note that the RESTART
|
||||||
|
and FIRMWARE_RESTART g-code commands do not load new software - the
|
||||||
|
above "sudo service klipper restart" and "make flash" commands are
|
||||||
|
needed for a software change to take effect.
|
||||||
102
docs/Features.md
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
Klipper has several compelling features:
|
||||||
|
|
||||||
|
* High precision stepper movement. Klipper utilizes an application
|
||||||
|
processor (such as a low-cost Raspberry Pi) when calculating printer
|
||||||
|
movements. The application processor determines when to step each
|
||||||
|
stepper motor, it compresses those events, transmits them to the
|
||||||
|
micro-controller, and then the micro-controller executes each event
|
||||||
|
at the requested time. Each stepper event is scheduled with a
|
||||||
|
precision of 25 micro-seconds or better. The software does not use
|
||||||
|
kinematic estimations (such as the Bresenham algorithm) - instead it
|
||||||
|
calculates precise step times based on the physics of acceleration
|
||||||
|
and the physics of the machine kinematics. More precise stepper
|
||||||
|
movement translates to quieter and more stable printer operation.
|
||||||
|
|
||||||
|
* Best in class performance. Klipper is able to achieve high stepping
|
||||||
|
rates on both new and old micro-controllers. Even an old 8bit AVR
|
||||||
|
micro-controller can obtain rates over 175K steps per second. On
|
||||||
|
more recent micro-controllers, rates over 500K steps per second are
|
||||||
|
possible. Higher stepper rates enable higher print velocities. The
|
||||||
|
stepper event timing remains precise even at high speeds which
|
||||||
|
improves overall stability.
|
||||||
|
|
||||||
|
* Configuration via simple config file. There's no need to reflash the
|
||||||
|
micro-controller to change a setting. All of Klipper's configuration
|
||||||
|
is stored in a standard config file which can be easily edited. This
|
||||||
|
makes it easier to setup and maintain the hardware.
|
||||||
|
|
||||||
|
* Portable code. Klipper works on both ARM and AVR
|
||||||
|
micro-controllers. Existing "reprap" style printers can run Klipper
|
||||||
|
without hardware modification - just add a Raspberry Pi. Klipper's
|
||||||
|
internal code layout makes it easier to support other
|
||||||
|
micro-controller architectures as well.
|
||||||
|
|
||||||
|
* Simpler code. Klipper uses a very high level language (Python) for
|
||||||
|
most code. The kinematics algorithms, the G-code parsing, the
|
||||||
|
heating and thermistor algorithms, etc. are all written in
|
||||||
|
Python. This makes it easier to develop new functionality.
|
||||||
|
|
||||||
|
* Advanced features:
|
||||||
|
* Klipper implements the "pressure advance" algorithm for
|
||||||
|
extruders. When properly tuned, pressure advance reduces extruder
|
||||||
|
ooze.
|
||||||
|
* Klipper supports printers with multiple micro-controllers. For
|
||||||
|
example, one micro-controller could be used to control an
|
||||||
|
extruder, while another could control the printer's heaters, while
|
||||||
|
a third controls the rest of the printer. The Klipper host
|
||||||
|
software implements clock synchronization to account for clock
|
||||||
|
drift between micro-controllers. No special code is needed to
|
||||||
|
enable multiple micro-controllers - it just requires a few extra
|
||||||
|
lines in the config file.
|
||||||
|
* Klipper also implements a novel "stepper phase endstop" algorithm
|
||||||
|
that can dramatically improve the accuracy of typical endstop
|
||||||
|
switches. When properly tuned it can improve a print's first layer
|
||||||
|
bed adhesion.
|
||||||
|
* Support for limiting the top speed of short "zigzag" moves to
|
||||||
|
reduce printer vibration and noise. See the
|
||||||
|
[kinematics](Kinematics.md) document for more information.
|
||||||
|
|
||||||
|
To get started with Klipper, read the [installation](Installation.md)
|
||||||
|
guide.
|
||||||
|
|
||||||
|
Common features supported by Klipper
|
||||||
|
====================================
|
||||||
|
|
||||||
|
Klipper supports many standard 3d printer features:
|
||||||
|
|
||||||
|
* Works with Octoprint. This allows the printer to be controlled using
|
||||||
|
a regular web-browser. The same Raspberry Pi that runs Klipper can
|
||||||
|
also run Octoprint.
|
||||||
|
|
||||||
|
* Standard G-Code support. Common g-code commands that are produced by
|
||||||
|
typical "slicers" are supported. One may continue to use Slic3r,
|
||||||
|
Cura, etc. with Klipper.
|
||||||
|
|
||||||
|
* Constant speed acceleration support. All printer moves will
|
||||||
|
gradually accelerate from standstill to cruising speed and then
|
||||||
|
decelerate back to a standstill.
|
||||||
|
|
||||||
|
* "Look-ahead" support. The incoming stream of G-Code movement
|
||||||
|
commands are queued and analyzed - the acceleration between
|
||||||
|
movements in a similar direction will be optimized to reduce print
|
||||||
|
stalls and improve overall print time.
|
||||||
|
|
||||||
|
* Support for cartesian, delta, and corexy style printers.
|
||||||
|
|
||||||
|
Step Benchmarks
|
||||||
|
===============
|
||||||
|
|
||||||
|
Below are the results of stepper performance tests. The numbers shown
|
||||||
|
represent total number of steps per second on the micro-controller.
|
||||||
|
|
||||||
|
| Micro-controller | Fastest step rate | 3 steppers active |
|
||||||
|
| ----------------- | ----------------- | ----------------- |
|
||||||
|
| 20Mhz AVR | 189K | 125K |
|
||||||
|
| 16Mhz AVR | 151K | 100K |
|
||||||
|
| Arduino Due (ARM) | 382K | 337K |
|
||||||
|
| Beaglebone PRU | 689K | 689K |
|
||||||
|
|
||||||
|
On AVR platforms, the highest achievable step rate is with just one
|
||||||
|
stepper stepping. On the Due, the highest step rate is with two
|
||||||
|
simultaneous steppers stepping. On the PRU, the highest step rate is
|
||||||
|
with three simultaneous steppers.
|
||||||
131
docs/G-Codes.md
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
This document describes the commands that Klipper supports. These are
|
||||||
|
commands that one may enter into the OctoPrint terminal tab.
|
||||||
|
|
||||||
|
# G-Code commands
|
||||||
|
|
||||||
|
Klipper supports the following standard G-Code commands:
|
||||||
|
- Move (G0 or G1): `G1 [X<pos>] [Y<pos>] [Z<pos>] [E<pos>] [F<speed>]`
|
||||||
|
- Dwell: `G4 P<milliseconds>`
|
||||||
|
- Move to origin: `G28 [X] [Y] [Z]`
|
||||||
|
- Turn off motors: `M18` or `M84`
|
||||||
|
- Wait for current moves to finish: `M400`
|
||||||
|
- Select tool: `T<index>`
|
||||||
|
- Use absolute/relative distances for extrusion: `M82`, `M83`
|
||||||
|
- Use absolute/relative coordinates: `G90`, `G91`
|
||||||
|
- Set position: `G92 [X<pos>] [Y<pos>] [Z<pos>] [E<pos>]`
|
||||||
|
- Set speed factor override percentage: `M220 S<percent>`
|
||||||
|
- Set extrude factor override percentage: `M221 S<percent>`
|
||||||
|
- Get extruder temperature: `M105`
|
||||||
|
- Set extruder temperature: `M104 [T<index>] [S<temperature>]`
|
||||||
|
- Set extruder temperature and wait: `M109 [T<index>] S<temperature>`
|
||||||
|
- Set bed temperature: `M140 [S<temperature>]`
|
||||||
|
- Set bed temperature and wait: `M190 S<temperature>`
|
||||||
|
- Set fan speed: `M106 S<value>`
|
||||||
|
- Turn fan off: `M107`
|
||||||
|
- Emergency stop: `M112`
|
||||||
|
- Get current position: `M114`
|
||||||
|
- Get firmware version: `M115`
|
||||||
|
- Set home offset: `M206 [X<pos>] [Y<pos>] [Z<pos>]`
|
||||||
|
|
||||||
|
For further details on the above commands see the
|
||||||
|
[RepRap G-Code documentation](http://reprap.org/wiki/G-code).
|
||||||
|
|
||||||
|
Klipper's goal is to support the G-Code commands produced by common
|
||||||
|
3rd party software (eg, OctoPrint, Printrun, Slic3r, Cura, etc.) in
|
||||||
|
their standard configurations. It is not a goal to support every
|
||||||
|
possible G-Code command. Instead, Klipper prefers human readable
|
||||||
|
["extended G-Code commands"](#extended-g-code-commands).
|
||||||
|
|
||||||
|
## G-Code SD card commands
|
||||||
|
|
||||||
|
Klipper also supports the following standard G-Code commands if the
|
||||||
|
"virtual_sdcard" config section is enabled:
|
||||||
|
- List SD card: `M20`
|
||||||
|
- Initialize SD card: `M21`
|
||||||
|
- Select SD file: `M23 <filename>`
|
||||||
|
- Start/resume SD print: `M24`
|
||||||
|
- Pause SD print: `M25`
|
||||||
|
- Set SD position: `M26 S<offset>`
|
||||||
|
- Report SD print status: `M27`
|
||||||
|
|
||||||
|
# Extended G-Code Commands
|
||||||
|
|
||||||
|
Klipper uses "extended" G-Code commands for general configuration and
|
||||||
|
status. These extended commands all follow a similar format - they
|
||||||
|
start with a command name and may be followed by one or more
|
||||||
|
parameters. For example: `SET_SERVO SERVO=myservo ANGLE=5.3`. In this
|
||||||
|
document, the commands and parameters are shown in uppercase, however
|
||||||
|
they are not case sensitive. (So, "SET_SERVO" and "set_servo" both run
|
||||||
|
the same command.)
|
||||||
|
|
||||||
|
The following standard commands are supported:
|
||||||
|
- `QUERY_ENDSTOPS`: Probe the axis endstops and report if they are
|
||||||
|
"triggered" or in an "open" state. This command is typically used to
|
||||||
|
verify that an endstop is working correctly.
|
||||||
|
- `GET_POSITION`: Return information on the current location of the
|
||||||
|
toolhead.
|
||||||
|
- `PID_CALIBRATE HEATER=<config_name> TARGET=<temperature>
|
||||||
|
[WRITE_FILE=1]`: Perform a PID calibration test. The specified
|
||||||
|
heater will be enabled until the specified target temperature is
|
||||||
|
reached, and then the heater will be turned off and on for several
|
||||||
|
cycles. If the WRITE_FILE parameter is enabled, then the file
|
||||||
|
/tmp/heattest.txt will be created with a log of all temperature
|
||||||
|
samples taken during the test.
|
||||||
|
- `RESTART`: This will cause the host software to reload its config
|
||||||
|
and perform an internal reset. This command will not clear error
|
||||||
|
state from the micro-controller (see FIRMWARE_RESTART) nor will it
|
||||||
|
load new software (see
|
||||||
|
[the FAQ](FAQ.md#how-do-i-upgrade-to-the-latest-software)).
|
||||||
|
- `FIRMWARE_RESTART`: This is similar to a RESTART command, but it
|
||||||
|
also clears any error state from the micro-controller.
|
||||||
|
- `STATUS`: Report the Klipper host software status.
|
||||||
|
- `HELP`: Report the list of available extended G-Code commands.
|
||||||
|
|
||||||
|
## Custom Pin Commands
|
||||||
|
|
||||||
|
The following command is available when an "output_pin" config section
|
||||||
|
is enabled:
|
||||||
|
- `SET_PIN PIN=config_name VALUE=<value>`
|
||||||
|
|
||||||
|
## Servo Commands
|
||||||
|
|
||||||
|
The following commands are available when a "servo" config section is
|
||||||
|
enabled:
|
||||||
|
- `SET_SERVO SERVO=config_name WIDTH=<seconds>`
|
||||||
|
- `SET_SERVO SERVO=config_name ANGLE=<degrees>`
|
||||||
|
|
||||||
|
## Probe
|
||||||
|
|
||||||
|
The following commands are available when a "probe" config section is
|
||||||
|
enabled:
|
||||||
|
- `PROBE`: Move the nozzle downwards until the probe triggers.
|
||||||
|
- `QUERY_PROBE`: Report the current status of the probe ("triggered"
|
||||||
|
or "open").
|
||||||
|
|
||||||
|
## Delta Calibration
|
||||||
|
|
||||||
|
The following commands are available when the "delta_calibrate" config
|
||||||
|
section is enabled:
|
||||||
|
- `DELTA_CALIBRATE`: This command will probe seven points on the bed
|
||||||
|
and recommend updated endstop positions, tower angles, and radius.
|
||||||
|
- `NEXT`: If manual bed probing is enabled, then one can use this
|
||||||
|
command to move to the next probing point during a DELTA_CALIBRATE
|
||||||
|
operation.
|
||||||
|
|
||||||
|
## Bed Tilt
|
||||||
|
|
||||||
|
The following commands are available when the "bed_tilt" config
|
||||||
|
section is enabled:
|
||||||
|
- `BED_TILT_CALIBRATE`: This command will probe the points specified
|
||||||
|
in the config and then recommend updated x and y tilt adjustments.
|
||||||
|
- `NEXT`: If manual bed probing is enabled, then one can use this
|
||||||
|
command to move to the next probing point during a
|
||||||
|
BED_TILT_CALIBRATE operation.
|
||||||
|
|
||||||
|
## Dual Carriages
|
||||||
|
|
||||||
|
The following command is available when the "dual_carriage" config
|
||||||
|
section is enabled:
|
||||||
|
- `SET_DUAL_CARRIAGE CARRIAGE=[0|1]`: This command will set the active
|
||||||
|
carriage. It is typically invoked from the activate_gcode and
|
||||||
|
deactivate_gcode fields in a multiple extruder configuration.
|
||||||
@@ -1,97 +1,82 @@
|
|||||||
Klipper is currently in an experimental state. These instructions
|
These instructions assume the software will run on a Raspberry Pi
|
||||||
assume the software will run on a Raspberry Pi computer in conjunction
|
computer in conjunction with OctoPrint. It is recommended that a
|
||||||
with OctoPrint. Klipper supports only Atmel ATmega based
|
Raspberry Pi 2 or Raspberry Pi 3 computer be used as the host machine
|
||||||
micro-controllers at this time.
|
(see the
|
||||||
|
[FAQ](FAQ.md#can-i-run-klipper-on-something-other-than-a-raspberry-pi-3)
|
||||||
|
for other machines).
|
||||||
|
|
||||||
It is recommended that a Raspberry Pi 2 or Raspberry Pi 3 computer be
|
Klipper currently supports Atmel ATmega based micro-controllers,
|
||||||
used as the host. The software will run on a first generation
|
Arduino Due (Atmel SAM3x8e ARM micro-controller), and
|
||||||
Raspberry Pi, but the combined load of OctoPrint, Klipper, and a web
|
[Beaglebone PRU](beaglebone.md) based printers.
|
||||||
cam (if applicable) can overwhelm its CPU leading to print stalls.
|
|
||||||
|
|
||||||
Prepping an OS image
|
Prepping an OS image
|
||||||
====================
|
====================
|
||||||
|
|
||||||
Start by installing [OctoPi](https://github.com/guysoft/OctoPi) on the
|
Start by installing [OctoPi](https://github.com/guysoft/OctoPi) on the
|
||||||
Raspberry Pi computer. Use version 0.13.0 or later - see the
|
Raspberry Pi computer. Use OctoPi v0.14.0 or later - see the
|
||||||
[octopi releases](https://github.com/guysoft/OctoPi/releases) for
|
[octopi releases](https://github.com/guysoft/OctoPi/releases) for
|
||||||
release information. One should verify that OctoPi boots, that the
|
release information. One should verify that OctoPi boots and that the
|
||||||
OctoPrint web server works, and that one can ssh to the octopi server
|
OctoPrint web server works. After connecting to the OctoPrint web
|
||||||
(ssh pi@octopi -- password is "raspberry") before continuing.
|
page, follow the prompt to upgrade OctoPrint to v1.3.5 or later.
|
||||||
|
|
||||||
After installing OctoPi, ssh into the target machine and run the
|
After installing OctoPi and upgrading OctoPrint, it will be necessary
|
||||||
following commands:
|
to ssh into the target machine to run a handful of system commands. If
|
||||||
|
using a Linux or MacOS desktop, then the "ssh" software should already
|
||||||
```
|
be installed on the desktop. There are free ssh clients available for
|
||||||
sudo apt-get update
|
other desktops (eg,
|
||||||
sudo apt-get install avrdude gcc-avr binutils-avr avr-libc libncurses-dev
|
[PuTTY](https://www.chiark.greenend.org.uk/~sgtatham/putty/)). Use the
|
||||||
```
|
ssh utility to connect to the Raspberry Pi (ssh pi@octopi -- password
|
||||||
|
is "raspberry") and run the following commands:
|
||||||
The host software (Klippy) requires a one-time setup - run as the
|
|
||||||
regular "pi" user:
|
|
||||||
|
|
||||||
```
|
|
||||||
virtualenv ~/klippy-env
|
|
||||||
~/klippy-env/bin/pip install cffi==1.6.0 pyserial==2.7
|
|
||||||
```
|
|
||||||
|
|
||||||
Building Klipper
|
|
||||||
================
|
|
||||||
|
|
||||||
To obtain Klipper, run the following command on the target machine:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://github.com/KevinOConnor/klipper
|
git clone https://github.com/KevinOConnor/klipper
|
||||||
cd klipper/
|
./klipper/scripts/install-octopi.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
To compile the micro-controller code, start by configuring it:
|
The above will download Klipper, install some system dependencies,
|
||||||
|
setup Klipper to run at system startup, and start the Klipper host
|
||||||
|
software. It will require an internet connection and it may take a few
|
||||||
|
minutes to complete.
|
||||||
|
|
||||||
|
Building and flashing the micro-controller
|
||||||
|
==========================================
|
||||||
|
|
||||||
|
To compile the micro-controller code, start by running these commands
|
||||||
|
on the Raspberry Pi:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
cd ~/klipper/
|
||||||
make menuconfig
|
make menuconfig
|
||||||
```
|
```
|
||||||
|
|
||||||
Select the appropriate micro-controller and serial baud rate. Once
|
Select the appropriate micro-controller and review any other options
|
||||||
configured, run:
|
provided. For boards with serial ports, the default baud rate is
|
||||||
|
250000 (see the [FAQ](FAQ.md#how-do-i-change-the-serial-baud-rate) if
|
||||||
|
changing). Once configured, run:
|
||||||
|
|
||||||
```
|
```
|
||||||
make
|
make
|
||||||
```
|
```
|
||||||
|
|
||||||
Ignore any warnings you may see about "misspelled signal handler" (it
|
Finally, for common micro-controllers, the code can be flashed with:
|
||||||
is due to a bug fixed in gcc v4.8.3).
|
|
||||||
|
|
||||||
Installing Klipper on a micro-controller
|
|
||||||
----------------------------------------
|
|
||||||
|
|
||||||
The avrdude package can be used to install the micro-controller code
|
|
||||||
on an AVR ATmega chip. The exact syntax of the avrdude command is
|
|
||||||
different for each micro-controller. The following is an example
|
|
||||||
command for atmega2560 chips:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
example-only$ avrdude -C/etc/avrdude.conf -v -patmega2560 -cwiring -P/dev/ttyACM0 -b115200 -D -Uflash:w:/home/pi/klipper/out/klipper.elf.hex:i
|
sudo service klipper stop
|
||||||
|
make flash FLASH_DEVICE=/dev/ttyACM0
|
||||||
|
sudo service klipper start
|
||||||
```
|
```
|
||||||
|
|
||||||
Setting up the printer configuration
|
When flashing for the first time, make sure that OctoPrint is not
|
||||||
|
connected directly to the printer (from the OctoPrint web page, under
|
||||||
|
the "Connection" section, click "Disconnect"). The most common
|
||||||
|
communication device is **/dev/ttyACM0** - see the
|
||||||
|
[FAQ](FAQ.md#wheres-my-serial-port) for other possibilities.
|
||||||
|
|
||||||
|
Configuring OctoPrint to use Klipper
|
||||||
====================================
|
====================================
|
||||||
|
|
||||||
It is necessary to configure the printer. This is done by modifying a
|
|
||||||
configuration file that resides on the host. Start by copying an
|
|
||||||
example configuration and editing it. For example:
|
|
||||||
|
|
||||||
```
|
|
||||||
cp ~/klipper/config/example.cfg ~/printer.cfg
|
|
||||||
nano printer.cfg
|
|
||||||
```
|
|
||||||
|
|
||||||
Make sure to look at and update each setting that is appropriate for
|
|
||||||
the hardware.
|
|
||||||
|
|
||||||
Configuring OctoPrint to use Klippy
|
|
||||||
===================================
|
|
||||||
|
|
||||||
The OctoPrint web server needs to be configured to communicate with
|
The OctoPrint web server needs to be configured to communicate with
|
||||||
the Klippy host software. Using a web-browser, login to the OctoPrint
|
the Klipper host software. Using a web browser, login to the OctoPrint
|
||||||
web page, and navigate to the Settings tab. Then configure the
|
web page, and navigate to the Settings tab. Then configure the
|
||||||
following items:
|
following items:
|
||||||
|
|
||||||
@@ -99,20 +84,75 @@ Under "Serial Connection" in "Additional serial ports" add
|
|||||||
"/tmp/printer". Then click "Save".
|
"/tmp/printer". Then click "Save".
|
||||||
|
|
||||||
Enter the Settings tab again and under "Serial Connection" change the
|
Enter the Settings tab again and under "Serial Connection" change the
|
||||||
"Serial Port" setting to "/tmp/printer".
|
"Serial Port" setting to "/tmp/printer". Unselect the "Not only cancel
|
||||||
|
ongoing prints but also disconnect..." checkbox. Click "Save".
|
||||||
|
|
||||||
Under the "Features" tab, unselect "Enable SD support". Then click
|
From the main page, under the "Connection" section (at the top left of
|
||||||
"Save".
|
the page) make sure the "Serial Port" is set to "/tmp/printer" and
|
||||||
|
click "Connect". (If "/tmp/printer" is not an available selection then
|
||||||
|
try reloading the page.)
|
||||||
|
|
||||||
Running the host software
|
Once connected, navigate to the "Terminal" tab and type "status"
|
||||||
|
(without the quotes) into the command entry box and click "Send". The
|
||||||
|
terminal window will likely report there is an error opening the
|
||||||
|
config file - that means OctoPrint is successfully communicating with
|
||||||
|
Klipper. Proceed to the next section.
|
||||||
|
|
||||||
|
Configuring Klipper
|
||||||
|
===================
|
||||||
|
|
||||||
|
The Klipper configuration is stored in a text file on the Raspberry
|
||||||
|
Pi. Take a look at the example config files in the
|
||||||
|
[config directory](../config/). The
|
||||||
|
[example.cfg](../config/example.cfg) file contains documentation on
|
||||||
|
command parameters and it can also be used as an initial config file
|
||||||
|
template. However, for most printers, one of the other config files
|
||||||
|
may be a more concise starting point.
|
||||||
|
|
||||||
|
Arguably the easiest way to update the Klipper configuration file is
|
||||||
|
to use a desktop editor that supports editing files over the "scp"
|
||||||
|
and/or "sftp" protocols. There are freely available tools that support
|
||||||
|
this (eg, Notepad++, WinSCP, and Cyberduck). Use one of the example
|
||||||
|
config files as a starting point and save it as a file named
|
||||||
|
"printer.cfg" in the home directory of the pi user (ie,
|
||||||
|
/home/pi/printer.cfg).
|
||||||
|
|
||||||
|
Alternatively, one can also copy and edit the file directly on the
|
||||||
|
Raspberry Pi via ssh - for example:
|
||||||
|
|
||||||
|
```
|
||||||
|
cp ~/klipper/config/example.cfg ~/printer.cfg
|
||||||
|
nano ~/printer.cfg
|
||||||
|
```
|
||||||
|
|
||||||
|
Make sure to review and update each setting that is appropriate for
|
||||||
|
the hardware.
|
||||||
|
|
||||||
|
After creating and editing the file it will be necessary to issue a
|
||||||
|
"restart" command in the OctoPrint web terminal to load the config. A
|
||||||
|
"status" command will report the printer is ready if the Klipper
|
||||||
|
config file is successfully read and the micro-controller is
|
||||||
|
successfully found and configured. It is not unusual to have
|
||||||
|
configuration errors during the initial setup - update the printer
|
||||||
|
config file and issue "restart" until "status" reports the printer is
|
||||||
|
ready.
|
||||||
|
|
||||||
|
Klipper reports error messages via the OctoPrint terminal tab. The
|
||||||
|
"status" command can be used to re-report error messages. The default
|
||||||
|
Klipper startup script also places a log in **/tmp/klippy.log** which
|
||||||
|
provides more detailed information.
|
||||||
|
|
||||||
|
In addition to common g-code commands, Klipper supports a few extended
|
||||||
|
commands - "status" and "restart" are examples of these commands. Use
|
||||||
|
the "help" command to get a list of other extended commands.
|
||||||
|
|
||||||
|
After Klipper reports that the "printer is ready" go on to the
|
||||||
|
[config check document](Config_checks.md) to perform some basic checks
|
||||||
|
on the pin definitions in the config file.
|
||||||
|
|
||||||
|
Contacting the developers
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
The host software is executed by running the following as the regular
|
Be sure to see the [FAQ](FAQ.md) for answers to some common questions.
|
||||||
"pi" user:
|
See the [contact page](Contact.md) to report a bug or to contact the
|
||||||
|
developers.
|
||||||
```
|
|
||||||
~/klippy-env/bin/python ~/klipper/klippy/klippy.py ~/printer.cfg -l /tmp/klippy.log < /dev/null > /tmp/klippy-errors.log 2>&1 &
|
|
||||||
```
|
|
||||||
|
|
||||||
Once Klippy is running, use a web-browser and navigate to the
|
|
||||||
OctoPrint web site. Click on "Connect" under the "Connection" tab.
|
|
||||||
|
|||||||
298
docs/Kinematics.md
Normal file
@@ -0,0 +1,298 @@
|
|||||||
|
This document provides an overview of how Klipper implements robot
|
||||||
|
motion (its [kinematics](https://en.wikipedia.org/wiki/Kinematics)).
|
||||||
|
The contents may be of interest to both developers interested in
|
||||||
|
working on the Klipper software as well as users interested in better
|
||||||
|
understanding the mechanics of their machines.
|
||||||
|
|
||||||
|
Acceleration
|
||||||
|
============
|
||||||
|
|
||||||
|
Klipper implements a constant acceleration scheme whenever the print
|
||||||
|
head changes velocity - the velocity is gradually changed to the new
|
||||||
|
speed instead of suddenly jerking to it. Klipper always enforces
|
||||||
|
acceleration between the tool head and the print. The filament leaving
|
||||||
|
the extruder can be quite fragile - rapid jerks and/or extruder flow
|
||||||
|
changes lead to poor quality and poor bed adhesion. Even when not
|
||||||
|
extruding, if the print head is at the same level as the print then
|
||||||
|
rapid jerking of the head can cause disruption of recently deposited
|
||||||
|
filament. Limiting speed changes of the print head (relative to the
|
||||||
|
print) reduces risks of disrupting the print.
|
||||||
|
|
||||||
|
It is also important to limit acceleration so that the stepper motors
|
||||||
|
do not skip or put excessive stress on the machine. Klipper limits the
|
||||||
|
torque on each stepper by virtue of limiting the acceleration of the
|
||||||
|
print head. Enforcing acceleration at the print head naturally also
|
||||||
|
limits the torque of the steppers that move the print head (the
|
||||||
|
inverse is not always true).
|
||||||
|
|
||||||
|
Klipper implements constant acceleration. The key formula for constant
|
||||||
|
acceleration is:
|
||||||
|
```
|
||||||
|
velocity(time) = start_velocity + accel*time
|
||||||
|
```
|
||||||
|
|
||||||
|
Trapezoid generator
|
||||||
|
===================
|
||||||
|
|
||||||
|
Klipper uses a traditional "trapezoid generator" to model the motion
|
||||||
|
of each move - each move has a start speed, it accelerates to a
|
||||||
|
cruising speed at constant acceleration, it cruises at a constant
|
||||||
|
speed, and then decelerates to the end speed using constant
|
||||||
|
acceleration.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
It's called a "trapezoid generator" because a velocity diagram of the
|
||||||
|
move looks like a trapezoid.
|
||||||
|
|
||||||
|
The cruising speed is always greater than or equal to both the start
|
||||||
|
speed and the end speed. The acceleration phase may be of zero
|
||||||
|
duration (if the start speed is equal to the cruising speed), the
|
||||||
|
cruising phase may be of zero duration (if the move immediately starts
|
||||||
|
decelerating after acceleration), and/or the deceleration phase may be
|
||||||
|
of zero duration (if the end speed is equal to the cruising speed).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Look-ahead
|
||||||
|
==========
|
||||||
|
|
||||||
|
The "look-ahead" system is used to determine cornering speeds between
|
||||||
|
moves.
|
||||||
|
|
||||||
|
Consider the following two moves contained on an XY plane:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
In the above situation it is possible to fully decelerate after the
|
||||||
|
first move and then fully accelerate at the start of the next move,
|
||||||
|
but that is not ideal as all that acceleration and deceleration would
|
||||||
|
greatly increase the print time and the frequent changes in extruder
|
||||||
|
flow would result in poor print quality.
|
||||||
|
|
||||||
|
To solve this, the "look-ahead" mechanism queues multiple incoming
|
||||||
|
moves and analyzes the angles between moves to determine a reasonable
|
||||||
|
speed that can be obtained during the "junction" between two moves. If
|
||||||
|
the next move is nearly in the same direction then the head need only
|
||||||
|
slow down a little (if at all).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
However, if the next move forms an acute angle (the head is going to
|
||||||
|
travel in nearly a reverse direction on the next move) then only a
|
||||||
|
small junction speed is permitted.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The junction speeds are determined using "approximated centripetal
|
||||||
|
acceleration". Best
|
||||||
|
[described by the author](https://onehossshay.wordpress.com/2011/09/24/improving_grbl_cornering_algorithm/).
|
||||||
|
|
||||||
|
Klipper implements look-ahead between moves that have similar extruder
|
||||||
|
flow rates. Other moves are relatively rare and implementing
|
||||||
|
look-ahead between them is unnecessary.
|
||||||
|
|
||||||
|
Key formula for look-ahead:
|
||||||
|
```
|
||||||
|
end_velocity^2 = start_velocity^2 + 2*accel*move_distance
|
||||||
|
```
|
||||||
|
|
||||||
|
Smoothed look-ahead
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Klipper also implements a mechanism for smoothing out the motions of
|
||||||
|
short "zigzag" moves. Consider the following moves:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
In the above, the frequent changes from acceleration to deceleration
|
||||||
|
can cause the machine to vibrate which causes stress on the machine
|
||||||
|
and increases the noise. To reduce this, Klipper tracks both regular
|
||||||
|
move acceleration as well as a virtual "acceleration to deceleration"
|
||||||
|
rate. Using this system, the top speed of these short "zigzag" moves
|
||||||
|
are limited to smooth out the printer motion:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Specifically, the code calculates what the velocity of each move would
|
||||||
|
be if it were limited to this virtual "acceleration to deceleration"
|
||||||
|
rate (half the normal acceleration rate by default). In the above
|
||||||
|
picture the dashed gray lines represent this virtual acceleration rate
|
||||||
|
for the first move. If a move can not reach its full cruising speed
|
||||||
|
using this virtual acceleration rate then its top speed is reduced to
|
||||||
|
the maximum speed it could obtain at this virtual acceleration
|
||||||
|
rate. For most moves the limit will be at or above the move's existing
|
||||||
|
limits and no change in behavior is induced. For short zigzag moves,
|
||||||
|
however, this limit reduces the top speed. Note that it does not
|
||||||
|
change the actual acceleration within the move - the move continues to
|
||||||
|
use the normal acceleration scheme up to its adjusted top-speed.
|
||||||
|
|
||||||
|
Generating steps
|
||||||
|
================
|
||||||
|
|
||||||
|
Once the look-ahead process completes, the print head movement for the
|
||||||
|
given move is fully known (time, start position, end position,
|
||||||
|
velocity at each point) and it is possible to generate the step times
|
||||||
|
for the move. This process is done within "kinematic classes" in the
|
||||||
|
Klipper code. Outside of these kinematic classes, everything is
|
||||||
|
tracked in millimeters, seconds, and in cartesian coordinate space.
|
||||||
|
It's the task of the kinematic classes to convert from this generic
|
||||||
|
coordinate system to the hardware specifics of the particular printer.
|
||||||
|
|
||||||
|
In general, the code determines each step time by first calculating
|
||||||
|
where along the line of movement the head would be if a step is
|
||||||
|
taken. It then calculates what time the head should be at that
|
||||||
|
position. Determining the time along the line of movement can be done
|
||||||
|
using the formulas for constant acceleration and constant velocity:
|
||||||
|
|
||||||
|
```
|
||||||
|
time = sqrt(2*distance/accel + (start_velocity/accel)^2) - start_velocity/accel
|
||||||
|
time = distance/cruise_velocity
|
||||||
|
```
|
||||||
|
|
||||||
|
Cartesian Robots
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Generating steps for cartesian printers is the simplest case. The
|
||||||
|
movement on each axis is directly related to the movement in cartesian
|
||||||
|
space.
|
||||||
|
|
||||||
|
Delta Robots
|
||||||
|
------------
|
||||||
|
|
||||||
|
To generate step times on Delta printers it is necessary to correlate
|
||||||
|
the movement in cartesian space with the movement on each stepper
|
||||||
|
tower.
|
||||||
|
|
||||||
|
To simplify the math, for each stepper tower, the code calculates the
|
||||||
|
location of a "virtual tower" that is along the line of movement.
|
||||||
|
This virtual tower is chosen at the point where the line of movement
|
||||||
|
(extended infinitely in both directions) would be closest to the
|
||||||
|
actual tower.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
It is then possible to calculate where the head will be along the line
|
||||||
|
of movement after each step is taken on the virtual tower.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The key formula is Pythagoras's theorem:
|
||||||
|
```
|
||||||
|
distance_to_tower^2 = arm_length^2 - tower_height^2
|
||||||
|
```
|
||||||
|
|
||||||
|
One complexity is that if the print head passes the virtual tower
|
||||||
|
location then the stepper direction must be reversed. In this case
|
||||||
|
forward steps will be taken at the start of the move and reverse steps
|
||||||
|
will be taken at the end of the move.
|
||||||
|
|
||||||
|
### Delta movements beyond simple XY plane ###
|
||||||
|
|
||||||
|
Movement calculation is more complicated if a single move contains
|
||||||
|
both XY movement and Z movement. These moves are rare, but they must
|
||||||
|
still be handled correctly. A virtual tower along the line of movement
|
||||||
|
is still calculated, but in this case the tower is not at a 90 degree
|
||||||
|
angle relative to the line of movement:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The code continues to calculate step times using the same general
|
||||||
|
scheme as delta moves within an XY plane, but the slope of the tower
|
||||||
|
must also be used in the calculations.
|
||||||
|
|
||||||
|
Should the move contain only Z movement (ie, no XY movement at all)
|
||||||
|
then the same math is used - just in this case the tower is parallel
|
||||||
|
to the line of movement.
|
||||||
|
|
||||||
|
### Stepper motor acceleration limits ###
|
||||||
|
|
||||||
|
With delta kinematics it is possible for a move that is accelerating
|
||||||
|
in cartesian space to require an acceleration on a particular stepper
|
||||||
|
motor greater than the move's acceleration. This can occur when a
|
||||||
|
stepper arm is more horizontal than vertical and the line of movement
|
||||||
|
passes near that stepper's tower. Although these moves could require a
|
||||||
|
stepper motor acceleration greater than the printer's maximum
|
||||||
|
configured move acceleration, the effective mass moved by that stepper
|
||||||
|
would be smaller. Thus the higher stepper acceleration does not result
|
||||||
|
in significantly higher stepper torque and it is therefore considered
|
||||||
|
harmless.
|
||||||
|
|
||||||
|
However, to avoid extreme cases, Klipper enforces a maximum ceiling on
|
||||||
|
stepper acceleration of three times the printer's configured maximum
|
||||||
|
move acceleration. (Similarly, the maximum velocity of the stepper is
|
||||||
|
limited to three times the maximum move velocity.) In order to enforce
|
||||||
|
this limit, moves at the extreme edge of the build envelope (where a
|
||||||
|
stepper arm may be nearly horizontal) will have a lower maximum
|
||||||
|
acceleration and velocity.
|
||||||
|
|
||||||
|
Extruder kinematics
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Klipper implements extruder motion in its own kinematic class. Since
|
||||||
|
the timing and speed of each print head movement is fully known for
|
||||||
|
each move, it's possible to calculate the step times for the extruder
|
||||||
|
independently from the step time calculations of the print head
|
||||||
|
movement.
|
||||||
|
|
||||||
|
Basic extruder movement is simple to calculate. The step time
|
||||||
|
generation uses the same constant acceleration and constant velocity
|
||||||
|
formulas that cartesian robots use.
|
||||||
|
|
||||||
|
### Pressure advance ###
|
||||||
|
|
||||||
|
Experimentation has shown that it's possible to improve the modeling
|
||||||
|
of the extruder beyond the basic extruder formula. In the ideal case,
|
||||||
|
as an extrusion move progresses, the same volume of filament should be
|
||||||
|
deposited at each point along the move and there should be no volume
|
||||||
|
extruded after the move. Unfortunately, it's common to find that the
|
||||||
|
basic extrusion formulas cause too little filament to exit the
|
||||||
|
extruder at the start of extrusion moves and for excess filament to
|
||||||
|
extrude after extrusion ends. This is often referred to as "ooze".
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The "pressure advance" system attempts to account for this by using a
|
||||||
|
different model for the extruder. Instead of naively believing that
|
||||||
|
each mm^3 of filament fed into the extruder will result in that amount
|
||||||
|
of mm^3 immediately exiting the extruder, it uses a model based on
|
||||||
|
pressure. Pressure increases when filament is pushed into the extruder
|
||||||
|
(as in [Hooke's law](https://en.wikipedia.org/wiki/Hooke%27s_law)) and
|
||||||
|
the pressure necessary to extrude is dominated by the flow rate
|
||||||
|
through the nozzle orifice (as in
|
||||||
|
[Poiseuille's law](https://en.wikipedia.org/wiki/Poiseuille_law)). The
|
||||||
|
key idea is that the relationship between filament, pressure, and flow
|
||||||
|
rate can be modeled using a linear coefficient:
|
||||||
|
```
|
||||||
|
extra_filament = pressure_advance_coefficient * extruder_velocity
|
||||||
|
```
|
||||||
|
|
||||||
|
See the [pressure advance](Pressure_Advance.md) document for
|
||||||
|
information on how to find this pressure advance coefficient.
|
||||||
|
|
||||||
|
Once configured, Klipper will push in an additional amount of filament
|
||||||
|
during acceleration. The higher the desired filament flow rate, the
|
||||||
|
more filament must be pushed in during acceleration to account for
|
||||||
|
pressure. During head deceleration the extra filament is retracted
|
||||||
|
(the extruder will have a negative velocity).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
One may notice that the pressure advance algorithm can cause the
|
||||||
|
extruder motor to make sudden velocity changes. This is tolerated
|
||||||
|
based on the idea that the majority of the inertia in the system is in
|
||||||
|
changing the extruder pressure. As long as the extruder pressure does
|
||||||
|
not change rapidly the sudden changes in extruder motor velocity are
|
||||||
|
tolerated.
|
||||||
|
|
||||||
|
One area where sudden velocity changes become problematic is during
|
||||||
|
small changes in head speed due to cornering.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
To prevent this, the Klipper pressure advance code utilizes the move
|
||||||
|
look-ahead queue to detect intermittent speed changes. During a
|
||||||
|
deceleration event the code finds the maximum upcoming head speed
|
||||||
|
within a configurable time window. The pressure is then only adjusted
|
||||||
|
to this found maximum. This can greatly reduce (or even completely
|
||||||
|
eliminate) pressure changes during cornering.
|
||||||
285
docs/MCU_Commands.md
Normal file
@@ -0,0 +1,285 @@
|
|||||||
|
This document provides information on the low-level micro-controller
|
||||||
|
commands that are sent from the Klipper "host" software and processed
|
||||||
|
by the Klipper micro-controller software. This document is not an
|
||||||
|
authoritative reference for these commands, nor is it an exclusive
|
||||||
|
list of all available commands.
|
||||||
|
|
||||||
|
This document may be useful for developers interested in understanding
|
||||||
|
the low-level micro-controller commands.
|
||||||
|
|
||||||
|
See the [protocol](Protocol.md) document for more information on the
|
||||||
|
format of commands and their transmission. The commands here are
|
||||||
|
described using their "printf" style syntax - for those unfamiliar
|
||||||
|
with that format, just note that where a '%...' sequence is seen it
|
||||||
|
should be replaced with an actual integer. For example, a description
|
||||||
|
with "count=%c" could be replaced with the text "count=10".
|
||||||
|
|
||||||
|
Startup Commands
|
||||||
|
================
|
||||||
|
|
||||||
|
It may be necessary to take certain one-time actions to configure the
|
||||||
|
micro-controller and its peripherals. This section lists common
|
||||||
|
commands available for that purpose. Unlike most micro-controller
|
||||||
|
commands, these commands run as soon as they are received and they do
|
||||||
|
not require any particular setup.
|
||||||
|
|
||||||
|
Several of these commands will take a "pin=%u" parameter. The
|
||||||
|
low-level micro-controller software uses integer encodings of the
|
||||||
|
hardware pin numbers, but to make things more readable the host will
|
||||||
|
translate human readable pin names (eg, "PA3") to their equivalent
|
||||||
|
integer encodings. By convention, any parameter named "pin" or that
|
||||||
|
has a "_pin" suffix will use pin name translation by the
|
||||||
|
host.
|
||||||
|
|
||||||
|
Common startup commands:
|
||||||
|
|
||||||
|
* `set_digital_out pin=%u value=%c` : This command immediately
|
||||||
|
configures the given pin as a digital out GPIO and it sets it to
|
||||||
|
either a low level (value=0) or a high level (value=1). This command
|
||||||
|
may be useful for configuring the initial value of LEDs and for
|
||||||
|
configuring the initial value of stepper driver micro-stepping pins.
|
||||||
|
|
||||||
|
* `set_pwm_out pin=%u cycle_ticks=%u value=%hu` : This command will
|
||||||
|
immediately configure the given pin to use hardware based
|
||||||
|
pulse-width-modulation (PWM) with the given number of
|
||||||
|
cycle_ticks. The "cycle_ticks" is the number of MCU clock ticks each
|
||||||
|
power on and power off cycle should last. A cycle_ticks value of 1
|
||||||
|
can be used to request the fastest possible cycle time. The "value"
|
||||||
|
parameter is between 0 and 255 with 0 indicating a full off state
|
||||||
|
and 255 indicating a full on state. This command may be useful for
|
||||||
|
enabling CPU and nozzle cooling fans.
|
||||||
|
|
||||||
|
* `send_spi_message pin=%u msg=%*s` : This command can be used to
|
||||||
|
transmit messages to a serial-peripheral-interface (SPI) component
|
||||||
|
connected to the micro-controller. It has been used to configure the
|
||||||
|
startup settings of AD5206 digipots. The 'pin' parameter specifies
|
||||||
|
the chip select line to use during the transmission. The 'msg'
|
||||||
|
indicates the binary message to transmit to the given chip.
|
||||||
|
|
||||||
|
Low-level micro-controller configuration
|
||||||
|
========================================
|
||||||
|
|
||||||
|
Most commands in the micro-controller require an initial setup before
|
||||||
|
they can be successfully invoked. This section provides an overview of
|
||||||
|
the configuration process. This section and the following sections are
|
||||||
|
likely only of interest to developers interested in the internal
|
||||||
|
details of Klipper.
|
||||||
|
|
||||||
|
When the host first connects to the micro-controller it always starts
|
||||||
|
by obtaining a data dictionary (see [protocol](Protocol.md) for more
|
||||||
|
information). After the data dictionary is obtained the host will
|
||||||
|
check if the micro-controller is in a "configured" state and configure
|
||||||
|
it if not. Configuration involves the following phases:
|
||||||
|
|
||||||
|
* `get_config` : The host starts by checking if the micro-controller
|
||||||
|
is already configured. The micro-controller responds to this command
|
||||||
|
with a "config" response message. The micro-controller software
|
||||||
|
always starts in an unconfigured state at power-on. It remains in
|
||||||
|
this state until the host completes the configuration processes (by
|
||||||
|
issuing a finalize_config command). If the micro-controller is
|
||||||
|
already configured from a previous session (and is configured with
|
||||||
|
the desired settings) then no further action is needed by the host
|
||||||
|
and the configuration process ends successfully.
|
||||||
|
|
||||||
|
* `allocate_oids count=%c` : This command is issued to inform the
|
||||||
|
micro-controller of the maximum number of object-ids (oid) that the
|
||||||
|
host requires. It is only valid to issue this command once. An oid
|
||||||
|
is an integer identifier allocated to each stepper, each endstop,
|
||||||
|
and each schedulable gpio pin. The host determines in advance the
|
||||||
|
number of oids it will require to operate the hardware and passes
|
||||||
|
this to the micro-controller so that it may allocate sufficient
|
||||||
|
memory to store a mapping from oid to internal object.
|
||||||
|
|
||||||
|
* `config_XXX oid=%c ...` : By convention any command starting with
|
||||||
|
the "config_" prefix creates a new micro-controller object and
|
||||||
|
assigns the given oid to it. For example, the config_digital_out
|
||||||
|
command will configure the specified pin as a digital output GPIO
|
||||||
|
and create an internal object that the host can use to schedule
|
||||||
|
changes to the given GPIO. The oid parameter passed into the config
|
||||||
|
command is selected by the host and must be between zero and the
|
||||||
|
maximum count supplied in the allocate_oids command. The config
|
||||||
|
commands may only be run when the micro-controller is not in a
|
||||||
|
configured state (ie, prior to the host sending finalize_config) and
|
||||||
|
after the allocate_oids command has been sent.
|
||||||
|
|
||||||
|
* `finalize_config crc=%u` : The finalize_config command transitions
|
||||||
|
the micro-controller from an unconfigured state to a configured
|
||||||
|
state. The crc parameter passed to the micro-controller is stored
|
||||||
|
and provided back to the host in "config" response messages. By
|
||||||
|
convention, the host takes a 32bit CRC of the configuration it will
|
||||||
|
request and at the start of subsequent communication sessions it
|
||||||
|
checks that the CRC stored in the micro-controller exactly matches
|
||||||
|
its desired CRC. If the CRC does not match then the host knows the
|
||||||
|
micro-controller has not been configured in the state desired by the
|
||||||
|
host.
|
||||||
|
|
||||||
|
Common micro-controller objects
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
This section lists some commonly used config commands.
|
||||||
|
|
||||||
|
* `config_digital_out oid=%c pin=%u value=%c default_value=%c
|
||||||
|
max_duration=%u` : This command creates an internal micro-controller
|
||||||
|
object for the given GPIO 'pin'. The pin will be configured in
|
||||||
|
digital output mode and set to an initial value as specified by
|
||||||
|
'value' (0 for low, 1 for high). Creating a digital_out object
|
||||||
|
allows the host to schedule GPIO updates for the given pin at
|
||||||
|
specified times (see the schedule_digital_out command described
|
||||||
|
below). Should the micro-controller software go into shutdown mode
|
||||||
|
then all configured digital_out objects will be set to
|
||||||
|
'default_value'. The 'max_duration' parameter is used to implement a
|
||||||
|
safety check - if it is non-zero then it is the maximum number of
|
||||||
|
clock ticks that the host may set the given GPIO to a non-default
|
||||||
|
value without further updates. For example, if the default_value is
|
||||||
|
zero and the max_duration is 16000 then if the host sets the gpio to
|
||||||
|
a value of one then it must schedule another update to the gpio pin
|
||||||
|
(to either zero or one) within 16000 clock ticks. This safety
|
||||||
|
feature can be used with heater pins to ensure the host does not
|
||||||
|
enable the heater and then go off-line.
|
||||||
|
|
||||||
|
* `config_pwm_out oid=%c pin=%u cycle_ticks=%u value=%hu
|
||||||
|
default_value=%hu max_duration=%u` : This command creates an
|
||||||
|
internal object for hardware based PWM pins that the host may
|
||||||
|
schedule updates for. Its usage is analogous to config_digital_out -
|
||||||
|
see the description of the 'set_pwm_out' and 'config_digital_out'
|
||||||
|
commands for parameter description.
|
||||||
|
|
||||||
|
* `config_soft_pwm_out oid=%c pin=%u cycle_ticks=%u value=%c
|
||||||
|
default_value=%c max_duration=%u` : This command creates an internal
|
||||||
|
micro-controller object for software implemented PWM. Unlike
|
||||||
|
hardware pwm pins, a software pwm object does not require any
|
||||||
|
special hardware support (other than the ability to configure the
|
||||||
|
pin as a digital output GPIO). Because the output switching is
|
||||||
|
implemented in the micro-controller software, it is recommended that
|
||||||
|
the cycle_ticks parameter correspond to a time of 10ms or
|
||||||
|
greater. See the description of the 'set_pwm_out' and
|
||||||
|
'config_digital_out' commands for parameter description.
|
||||||
|
|
||||||
|
* `config_analog_in oid=%c pin=%u` : This command is used to configure
|
||||||
|
a pin in analog input sampling mode. Once configured, the pin can be
|
||||||
|
sampled at regular interval using the query_analog_in command (see
|
||||||
|
below).
|
||||||
|
|
||||||
|
* `config_stepper oid=%c step_pin=%c dir_pin=%c min_stop_interval=%u
|
||||||
|
invert_step=%c` : This command creates an internal stepper
|
||||||
|
object. The 'step_pin' and 'dir_pin' parameters specify the step and
|
||||||
|
direction pins respectively; this command will configure them in
|
||||||
|
digital output mode. The 'invert_step' parameter specifies whether a
|
||||||
|
step occurs on a rising edge (invert_step=0) or falling edge
|
||||||
|
(invert_step=1). The 'min_stop_interval' implements a safety
|
||||||
|
feature - it is checked when the micro-controller finishes all moves
|
||||||
|
for a stepper - if it is non-zero it specifies the minimum number of
|
||||||
|
clock ticks since the last step. It is used as a check on the
|
||||||
|
maximum stepper velocity that a stepper may have before stopping.
|
||||||
|
|
||||||
|
* `config_end_stop oid=%c pin=%c pull_up=%c stepper_count=%c` : This
|
||||||
|
command creates an internal "endstop" object. It is used to specify
|
||||||
|
the endstop pins and to enable "homing" operations (see the
|
||||||
|
end_stop_home command below). The command will configure the
|
||||||
|
specified pin in digital input mode. The 'pull_up' parameter
|
||||||
|
determines whether hardware provided pullup resistors for the pin
|
||||||
|
(if available) will be enabled. The 'stepper_count' parameter
|
||||||
|
specifies the maximum number of steppers that this endstop may need
|
||||||
|
to halt during a homing operation (see end_stop_home below).
|
||||||
|
|
||||||
|
Common commands
|
||||||
|
===============
|
||||||
|
|
||||||
|
This section lists some commonly used run-time commands. It is likely
|
||||||
|
only of interest to developers looking to gain insight into Klipper.
|
||||||
|
|
||||||
|
* `schedule_digital_out oid=%c clock=%u value=%c` : This command will
|
||||||
|
schedule a change to a digital output GPIO pin at the given clock
|
||||||
|
time. To use this command a 'config_digital_out' command with the
|
||||||
|
same 'oid' parameter must have been issued during micro-controller
|
||||||
|
configuration.
|
||||||
|
|
||||||
|
* `schedule_pwm_out oid=%c clock=%u value=%hu` : Schedules a change to
|
||||||
|
a hardware PWM output pin. See the 'schedule_digital_out' and
|
||||||
|
'config_pwm_out' commands for more info.
|
||||||
|
|
||||||
|
* `schedule_soft_pwm_out oid=%c clock=%u value=%hu` : Schedules a
|
||||||
|
change to a software PWM output pin. See the 'schedule_digital_out'
|
||||||
|
and 'config_soft_pwm_out' commands for more info.
|
||||||
|
|
||||||
|
* `query_analog_in oid=%c clock=%u sample_ticks=%u sample_count=%c
|
||||||
|
rest_ticks=%u min_value=%hu max_value=%hu` : This command sets up a
|
||||||
|
recurring schedule of analog input samples. To use this command a
|
||||||
|
'config_analog_in' command with the same 'oid' parameter must have
|
||||||
|
been issued during micro-controller configuration. The samples will
|
||||||
|
start as of 'clock' time, it will report on the obtained value every
|
||||||
|
'rest_ticks' clock ticks, it will over-sample 'sample_count' number
|
||||||
|
of times, and it will pause 'sample_ticks' number of clock ticks
|
||||||
|
between over-sample samples. The 'min_value' and 'max_value'
|
||||||
|
parameters implement a safety feature - the micro-controller
|
||||||
|
software will verify the sampled value (after any oversampling) is
|
||||||
|
always between the supplied range. This is intended for use with
|
||||||
|
pins attached to thermistors controlling heaters - it can be used to
|
||||||
|
check that a heater is within a temperature range.
|
||||||
|
|
||||||
|
* `get_status` : This command causes the micro-controller to generate
|
||||||
|
a "status" response message. The host sends this command once a
|
||||||
|
second to obtain the value of the micro-controller clock and to
|
||||||
|
estimate the drift between host and micro-controller clocks. It
|
||||||
|
enables the host to accurately estimate the micro-controller clock.
|
||||||
|
|
||||||
|
Stepper commands
|
||||||
|
----------------
|
||||||
|
|
||||||
|
* `queue_step oid=%c interval=%u count=%hu add=%hi` : This command
|
||||||
|
schedules 'count' number of steps for the given stepper, with
|
||||||
|
'interval' number of clock ticks between each step. The first step
|
||||||
|
will be 'interval' number of clock ticks since the last scheduled
|
||||||
|
step for the given stepper. If 'add' is non-zero then the interval
|
||||||
|
will be adjusted by 'add' amount after each step. This command
|
||||||
|
appends the given interval/count/add sequence to a per-stepper
|
||||||
|
queue. There may be hundreds of these sequences queued during normal
|
||||||
|
operation. New sequence are appended to the end of the queue and as
|
||||||
|
each sequence completes its 'count' number of steps it is popped
|
||||||
|
from the front of the queue. This system allows the micro-controller
|
||||||
|
to queue potentially hundreds of thousands of steps - all with
|
||||||
|
reliable and predictable schedule times.
|
||||||
|
|
||||||
|
* `set_next_step_dir oid=%c dir=%c` : This command specifies the value
|
||||||
|
of the dir_pin that the next queue_step command will use.
|
||||||
|
|
||||||
|
* `reset_step_clock oid=%c clock=%u` : Normally, step timing is
|
||||||
|
relative to the last step for a given stepper. This command resets
|
||||||
|
the clock so that the next step is relative to the supplied 'clock'
|
||||||
|
time. The host usually only sends this command at the start of a
|
||||||
|
print.
|
||||||
|
|
||||||
|
* `stepper_get_position oid=%c` : This command causes the
|
||||||
|
micro-controller to generate a "stepper_position" response message
|
||||||
|
with the stepper's current position. The position is the total
|
||||||
|
number of steps generated with dir=1 minus the total number of steps
|
||||||
|
generated with dir=0.
|
||||||
|
|
||||||
|
* `end_stop_home oid=%c clock=%u sample_ticks=%u sample_count=%c
|
||||||
|
rest_ticks=%u pin_value=%c` : This command is used during stepper
|
||||||
|
"homing" operations. To use this command a 'config_end_stop' command
|
||||||
|
with the same 'oid' parameter must have been issued during
|
||||||
|
micro-controller configuration. When this command is invoked, the
|
||||||
|
micro-controller will sample the endstop pin every 'rest_ticks'
|
||||||
|
clock ticks and check if it has a value equal to 'pin_value'. If the
|
||||||
|
value matches (and it continues to match for 'sample_count'
|
||||||
|
additional samples spread 'sample_ticks' apart) then the movement
|
||||||
|
queue for the associated stepper will be cleared and the stepper
|
||||||
|
will come to an immediate halt. The host uses this command to
|
||||||
|
implement homing - the host instructs the endstop to sample for the
|
||||||
|
endstop trigger and then it issues a series of queue_step commands
|
||||||
|
to move a stepper towards the endstop. Once the stepper hits the
|
||||||
|
endstop, the trigger will be detected, the movement halted, and the
|
||||||
|
host notified.
|
||||||
|
|
||||||
|
### Move queue
|
||||||
|
|
||||||
|
Each queue_step command utilizes an entry in the micro-controller
|
||||||
|
"move queue". This queue is allocated when it receives the
|
||||||
|
"finalize_config" command, and it reports the number of available
|
||||||
|
queue entries in "config" response messages.
|
||||||
|
|
||||||
|
It is the responsibility of the host to ensure that there is available
|
||||||
|
space in the queue before sending a queue_step command. The host does
|
||||||
|
this by calculating when each queue_step command completes and
|
||||||
|
scheduling new queue_step commands accordingly.
|
||||||
@@ -1,8 +1,43 @@
|
|||||||
See [installation](Installation.md) for information on compiling,
|
Welcome to the Klipper documentation. There are two parts to Klipper -
|
||||||
installing, and running Klipper.
|
code that runs on a micro-controller and code that runs on a "host"
|
||||||
|
machine. The host code is intended to run on a low-cost
|
||||||
|
general-purpose machine such as a Raspberry Pi, while the
|
||||||
|
micro-controller code is intended to run on commodity micro-controller
|
||||||
|
chips. Read [features](Features.md) for reasons to use Klipper. See
|
||||||
|
[installation](Installation.md) to get started with Klipper. See
|
||||||
|
[config checks](Config_checks.md) for a guide to verify basic pin
|
||||||
|
settings in the config file.
|
||||||
|
|
||||||
See [code overview](Code_Overview.md) for developer information on the
|
The Klipper configuration is stored in a simple text file on the host
|
||||||
structure and layout of the Klipper code.
|
machine. The [config/example.cfg](../config/example.cfg) file serves
|
||||||
|
as a reference for the config file. The
|
||||||
|
[Pressure Advance](Pressure_Advance.md) document contains information
|
||||||
|
on tuning the pressure advance config.
|
||||||
|
|
||||||
See [debugging](Debugging.md) for developer information on how to test
|
The [kinematics](Kinematics.md) document provides some technical
|
||||||
and debug Klipper.
|
details on how Klipper implements motion. The [FAQ](FAQ.md) answers
|
||||||
|
some common questions. The [G-Codes](G-Codes.md) document lists
|
||||||
|
currently supported run-time commands.
|
||||||
|
|
||||||
|
The history of Klipper releases is available at
|
||||||
|
[releases](Releases.md). See [contact](Contact.md) for information on
|
||||||
|
bug reporting and general communication with the developers.
|
||||||
|
|
||||||
|
Developer Documentation
|
||||||
|
=======================
|
||||||
|
|
||||||
|
There are also several documents available for developers interested
|
||||||
|
in understanding how Klipper works. Start with the
|
||||||
|
[code overview](Code_Overview.md) document - it provides information
|
||||||
|
on the structure and layout of the Klipper code. See the
|
||||||
|
[contributing](CONTRIBUTING.md) document to submit improvements to Klipper.
|
||||||
|
|
||||||
|
See [protocol](Protocol.md) for information on the low-level messaging
|
||||||
|
protocol between host and micro-controller. See also
|
||||||
|
[MCU commands](MCU_Commands.md) for a description of low-level
|
||||||
|
commands implemented in the micro-controller software.
|
||||||
|
|
||||||
|
See [debugging](Debugging.md) for information on how to test and debug
|
||||||
|
Klipper.
|
||||||
|
|
||||||
|
See [todo](Todo.md) for information on possible future code features.
|
||||||
|
|||||||
97
docs/Pressure_Advance.md
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
This document provides information on tuning the "pressure advance"
|
||||||
|
configuration variables for a particular nozzle and filament. The
|
||||||
|
pressure advance feature can be helpful in reducing ooze. For more
|
||||||
|
information on how pressure advance is implemented see the
|
||||||
|
[kinematics](Kinematics.md) document.
|
||||||
|
|
||||||
|
Prerequisites
|
||||||
|
=============
|
||||||
|
|
||||||
|
In order to tune the pressure advance setting the printer must be
|
||||||
|
configured and operational. The tuning test involves printing objects
|
||||||
|
and inspecting the differences between objects. In particular, the
|
||||||
|
extruder
|
||||||
|
[E steps](http://reprap.org/wiki/Triffid_Hunter%27s_Calibration_Guide#E_steps)
|
||||||
|
and
|
||||||
|
[nozzle temperature](http://reprap.org/wiki/Triffid_Hunter%27s_Calibration_Guide#Nozzle_Temperature)
|
||||||
|
should be tuned prior to tuning pressure advance.
|
||||||
|
|
||||||
|
Tuning pressure advance
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Pressure advance does two useful things - it reduces ooze during
|
||||||
|
non-extrude moves and it reduces blobbing during cornering. This guide
|
||||||
|
uses the second feature (reducing blobbing during cornering) as a
|
||||||
|
mechanism for measuring and tuning the pressure advance configuration.
|
||||||
|
|
||||||
|
Start by changing the extruder section of the config file so that
|
||||||
|
pressure_advance is set to 0.0. (Make sure to issue a RESTART command
|
||||||
|
after each update to the config file so that the new configuration
|
||||||
|
takes effect.) Then print at least 10 layers of a large hollow square
|
||||||
|
at high speed (eg, 100mm/s). See
|
||||||
|
[docs/prints/square.stl](prints/square.stl) file for an STL file that
|
||||||
|
one may use. While the object is printing, make a note of which
|
||||||
|
direction the head is moving during external perimeters. What many
|
||||||
|
people see here is blobbing occurring at the corners - extra filament
|
||||||
|
at the corner in the direction the head travels followed by a possible
|
||||||
|
lack of filament on the side immediately after that corner:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
This blobbing is the result of pressure in the extruder being released
|
||||||
|
as a blob when the head slows down to corner.
|
||||||
|
|
||||||
|
The next step is to set pressure_advance_lookahead_time to 0.0, slowly
|
||||||
|
increase pressure_advance (eg, start with 0.05), and reprint the test
|
||||||
|
object. (Be sure to issue RESTART between each config change.) The
|
||||||
|
goal is to attempt to eliminate the blobbing during cornering. (With
|
||||||
|
pressure advance, the extruder will retract when the head slows down,
|
||||||
|
thus countering the pressure buildup and ideally eliminate the
|
||||||
|
blobbing.)
|
||||||
|
|
||||||
|
If a test run is done with a pressure_advance setting that is too
|
||||||
|
high, one typically sees a dimple in the corner followed by possible
|
||||||
|
blobbing after the corner (too much filament is retracted during slow
|
||||||
|
down and then too much filament is extruded during the following speed
|
||||||
|
up after cornering):
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The goal is to find the smallest pressure_advance value that results
|
||||||
|
in good quality corners:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Typical pressure_advance values are between 0.05 and 0.20 (the high
|
||||||
|
end usually only with bowden extruders). If there is no significant
|
||||||
|
improvement seen after increasing pressure_advance to 0.20, then
|
||||||
|
pressure advance is unlikely to improve the quality of prints. Return
|
||||||
|
to a default configuration with pressure_advance disabled.
|
||||||
|
|
||||||
|
It is not unusual for one corner of the test print to be consistently
|
||||||
|
different than the other three corners. This typically occurs when the
|
||||||
|
slicer arranges to always change Z height at that corner. If this
|
||||||
|
occurs, then ignore that corner and tune pressure_advance using the
|
||||||
|
other three corners.
|
||||||
|
|
||||||
|
Once a good pressure_advance value is found, return
|
||||||
|
pressure_advance_lookahead_time to its default (0.010). This parameter
|
||||||
|
controls how far in advance to check if a head slow-down is
|
||||||
|
immediately followed by a speed-up - it reduces pointless pressure
|
||||||
|
changes in the head. It's possible to tune this - higher values will
|
||||||
|
decrease the number of pressure changes in the nozzle at the expense
|
||||||
|
of permitting more blobbing during cornering. (Tuning this value is
|
||||||
|
unlikely to impact ooze.) The default of 10ms should work well on most
|
||||||
|
printers.
|
||||||
|
|
||||||
|
Although this tuning exercise directly improves the quality of
|
||||||
|
corners, it's worth remembering that a good pressure advance
|
||||||
|
configuration can reduce ooze throughout the print.
|
||||||
|
|
||||||
|
Finally, once pressure_advance is tuned in Klipper, it may still be
|
||||||
|
useful to configure a small retract value in the slicer (eg, 0.75mm)
|
||||||
|
and to utilize the slicer's "wipe on retract option" if available.
|
||||||
|
These slicer settings may help counteract ooze caused by filament
|
||||||
|
cohesion (filament pulled out of the nozzle due to the stickiness of
|
||||||
|
the plastic). It is recommended to disable the slicer's "z-lift on
|
||||||
|
retract" option.
|
||||||
343
docs/Protocol.md
Normal file
@@ -0,0 +1,343 @@
|
|||||||
|
The Klipper messaging protocol is used for low-level communication
|
||||||
|
between the Klipper host software and the Klipper micro-controller
|
||||||
|
software. At a high level the protocol can be thought of as a series
|
||||||
|
of command and response strings that are compressed, transmitted, and
|
||||||
|
then processed at the receiving side. An example series of commands in
|
||||||
|
uncompressed human-readable format might look like:
|
||||||
|
|
||||||
|
```
|
||||||
|
set_digital_out pin=86 value=1
|
||||||
|
set_digital_out pin=85 value=1
|
||||||
|
schedule_digital_out oid=8 clock=4000000 value=0
|
||||||
|
queue_step oid=7 interval=7458 count=10 add=331
|
||||||
|
queue_step oid=7 interval=11717 count=4 add=1281
|
||||||
|
```
|
||||||
|
|
||||||
|
See the [mcu commands](MCU_Commands.md) document for information on
|
||||||
|
available commands. See the [debugging](Debugging.md) document for
|
||||||
|
information on how to translate a G-Code file into its corresponding
|
||||||
|
human-readable micro-controller commands.
|
||||||
|
|
||||||
|
This page provides a high-level description of the Klipper messaging
|
||||||
|
protocol itself. It describes how messages are declared, encoded in
|
||||||
|
binary format (the "compression" scheme), and transmitted.
|
||||||
|
|
||||||
|
The goal of the protocol is to enable an error-free communication
|
||||||
|
channel between the host and micro-controller that is low-latency,
|
||||||
|
low-bandwidth, and low-complexity for the micro-controller.
|
||||||
|
|
||||||
|
Micro-controller Interface
|
||||||
|
==========================
|
||||||
|
|
||||||
|
The Klipper transmission protocol can be thought of as a
|
||||||
|
[RPC](https://en.wikipedia.org/wiki/Remote_procedure_call) mechanism
|
||||||
|
between micro-controller and host. The micro-controller software
|
||||||
|
declares the commands that the host may invoke along with the response
|
||||||
|
messages that it can generate. The host uses that information to
|
||||||
|
command the micro-controller to perform actions and to interpret the
|
||||||
|
results.
|
||||||
|
|
||||||
|
Declaring commands
|
||||||
|
------------------
|
||||||
|
|
||||||
|
The micro-controller software declares a "command" by using the
|
||||||
|
DECL_COMMAND() macro in the C code. For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
DECL_COMMAND(command_set_digital_out, "set_digital_out pin=%u value=%c");
|
||||||
|
```
|
||||||
|
|
||||||
|
The above declares a command named "set_digital_out". This allows the
|
||||||
|
host to "invoke" this command which would cause the
|
||||||
|
command_set_digital_out() C function to be executed in the
|
||||||
|
micro-controller. The above also indicates that the command takes two
|
||||||
|
integer parameters. When the command_set_digital_out() C code is
|
||||||
|
executed, it will be passed an array containing these two integers -
|
||||||
|
the first corresponding to the 'pin' and the second corresponding to
|
||||||
|
the 'value'.
|
||||||
|
|
||||||
|
In general, the parameters are described with printf() style syntax
|
||||||
|
(eg, "%u"). The formatting directly corresponds to the human-readable
|
||||||
|
view of commands (eg, "set_digital_out pin=86 value=1"). In the above
|
||||||
|
example, "value=" is a parameter name and "%c" indicates the parameter
|
||||||
|
is an integer. Internally, the parameter name is only used as
|
||||||
|
documentation. In this example, the "%c" is also used as documentation
|
||||||
|
to indicate the expected integer is 1 byte in size (the declared
|
||||||
|
integer size does not impact the parsing or encoding).
|
||||||
|
|
||||||
|
The micro-controller build will collect all commands declared with
|
||||||
|
DECL_COMMAND(), determine their parameters, and arrange for them to be
|
||||||
|
callable.
|
||||||
|
|
||||||
|
Declaring responses
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
To send information from the micro-controller to the host a "response"
|
||||||
|
is generated. These are both declared and transmitted using the
|
||||||
|
sendf() C macro. For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
sendf("status clock=%u status=%c", sched_read_time(), sched_is_shutdown());
|
||||||
|
```
|
||||||
|
|
||||||
|
The above transmits a "status" response message that contains two
|
||||||
|
integer parameters ("clock" and "status"). The micro-controller build
|
||||||
|
automatically finds all sendf() calls and generates encoders for
|
||||||
|
them. The first parameter of the sendf() function describes the
|
||||||
|
response and it is in the same format as command declarations.
|
||||||
|
|
||||||
|
The host can arrange to register a callback function for each
|
||||||
|
response. So, in effect, commands allow the host to invoke C functions
|
||||||
|
in the micro-controller and responses allow the micro-controller
|
||||||
|
software to invoke code in the host.
|
||||||
|
|
||||||
|
The sendf() macro should only be invoked from command or task
|
||||||
|
handlers, and it should not be invoked from interrupts or timers. The
|
||||||
|
code does not need to issue a sendf() in response to a received
|
||||||
|
command, it is not limited in the number of times sendf() may be
|
||||||
|
invoked, and it may invoke sendf() at any time from a task handler.
|
||||||
|
|
||||||
|
### Output responses
|
||||||
|
|
||||||
|
To simplify debugging, there is also has an output() C function. For
|
||||||
|
example:
|
||||||
|
|
||||||
|
```
|
||||||
|
output("The value of %u is %s with size %u.", x, buf, buf_len);
|
||||||
|
```
|
||||||
|
|
||||||
|
The output() function is similar in usage to printf() - it is intended
|
||||||
|
to generate and format arbitrary messages for human consumption.
|
||||||
|
|
||||||
|
Declaring constants
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Constants can also be exported. For example, the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
DECL_CONSTANT(SERIAL_BAUD, 250000);
|
||||||
|
```
|
||||||
|
|
||||||
|
would export a constant named "SERIAL_BAUD" with a value of 250000
|
||||||
|
from the micro-controller to the host.
|
||||||
|
|
||||||
|
Low-level message encoding
|
||||||
|
==========================
|
||||||
|
|
||||||
|
To accomplish the above RPC mechanism, each command and response is
|
||||||
|
encoded into a binary format for transmission. This section describes
|
||||||
|
the transmission system.
|
||||||
|
|
||||||
|
Message Blocks
|
||||||
|
--------------
|
||||||
|
|
||||||
|
All data sent from host to micro-controller and vice-versa are
|
||||||
|
contained in "message blocks". A message block has a two byte header
|
||||||
|
and a three byte trailer. The format of a message block is:
|
||||||
|
|
||||||
|
```
|
||||||
|
<1 byte length><1 byte sequence><n-byte content><2 byte crc><1 byte sync>
|
||||||
|
```
|
||||||
|
|
||||||
|
The length byte contains the number of bytes in the message block
|
||||||
|
including the header and trailer bytes (thus the minimum message
|
||||||
|
length is 5 bytes). The maximum message block length is currently 64
|
||||||
|
bytes. The sequence byte contains a 4 bit sequence number in the
|
||||||
|
low-order bits and the high-order bits always contain 0x10 (the
|
||||||
|
high-order bits are reserved for future use). The content bytes
|
||||||
|
contain arbitrary data and its format is described in the following
|
||||||
|
section. The crc bytes contain a 16bit CCITT
|
||||||
|
[CRC](https://en.wikipedia.org/wiki/Cyclic_redundancy_check) of the
|
||||||
|
message block including the header bytes but excluding the trailer
|
||||||
|
bytes. The sync byte is 0x7e.
|
||||||
|
|
||||||
|
The format of the message block is inspired by
|
||||||
|
[HDLC](https://en.wikipedia.org/wiki/High-Level_Data_Link_Control)
|
||||||
|
message frames. Like in HDLC, the message block may optionally contain
|
||||||
|
an additional sync character at the start of the block. Unlike in
|
||||||
|
HDLC, a sync character is not exclusive to the framing and may be
|
||||||
|
present in the message block content.
|
||||||
|
|
||||||
|
Message Block Contents
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Each message block sent from host to micro-controller contains a
|
||||||
|
series of zero or more message commands in its contents. Each command
|
||||||
|
starts with a [Variable Length Quantity](#variable-length-quantities)
|
||||||
|
(VLQ) encoded integer command-id followed by zero or more VLQ
|
||||||
|
parameters for the given command.
|
||||||
|
|
||||||
|
As an example, the following four commands might be placed in a single
|
||||||
|
message block:
|
||||||
|
|
||||||
|
```
|
||||||
|
set_digital_out pin=86 value=1
|
||||||
|
set_digital_out pin=85 value=0
|
||||||
|
get_config
|
||||||
|
get_status
|
||||||
|
```
|
||||||
|
|
||||||
|
and encoded into the following eight VLQ integers:
|
||||||
|
|
||||||
|
```
|
||||||
|
<id_set_digital_out><86><1><id_set_digital_out><85><0><id_get_config><id_get_status>
|
||||||
|
```
|
||||||
|
|
||||||
|
In order to encode and parse the message contents, both the host and
|
||||||
|
micro-controller must agree on the command ids and the number of
|
||||||
|
parameters each command has. So, in the above example, both the host
|
||||||
|
and micro-controller would know that "id_set_digital_out" is always
|
||||||
|
followed by two parameters, and "id_get_config" and "id_get_status"
|
||||||
|
have zero parameters. The host and micro-controller share a "data
|
||||||
|
dictionary" that maps the command descriptions (eg, "set_digital_out
|
||||||
|
pin=%u value=%c") to their integer command-ids. When processing the
|
||||||
|
data, the parser will know to expect a specific number of VLQ encoded
|
||||||
|
parameters following a given command id.
|
||||||
|
|
||||||
|
The message contents for blocks sent from micro-controller to host
|
||||||
|
follow the same format. The identifiers in these messages are
|
||||||
|
"response ids", but they serve the same purpose and follow the same
|
||||||
|
encoding rules. In practice, message blocks sent from the
|
||||||
|
micro-controller to the host never contain more than one response in
|
||||||
|
the message block contents.
|
||||||
|
|
||||||
|
### Variable Length Quantities
|
||||||
|
|
||||||
|
See the [wikipedia article](https://en.wikipedia.org/wiki/Variable-length_quantity)
|
||||||
|
for more information on the general format of VLQ encoded
|
||||||
|
integers. Klipper uses an encoding scheme that supports both positive
|
||||||
|
and negative integers. Integers close to zero use less bytes to encode
|
||||||
|
and positive integers typically encode using less bytes than negative
|
||||||
|
integers. The following table shows the number of bytes each integer
|
||||||
|
takes to encode:
|
||||||
|
|
||||||
|
| Integer | Encoded size |
|
||||||
|
|---------------------------|--------------|
|
||||||
|
| -32 .. 95 | 1 |
|
||||||
|
| -4096 .. 12287 | 2 |
|
||||||
|
| -524288 .. 1572863 | 3 |
|
||||||
|
| -67108864 .. 201326591 | 4 |
|
||||||
|
| -2147483648 .. 4294967295 | 5 |
|
||||||
|
|
||||||
|
### Variable length strings
|
||||||
|
|
||||||
|
As an exception to the above encoding rules, if a parameter to a
|
||||||
|
command or response is a dynamic string then the parameter is not
|
||||||
|
encoded as a simple VLQ integer. Instead it is encoded by transmitting
|
||||||
|
the length as a VLQ encoded integer followed by the contents itself:
|
||||||
|
|
||||||
|
```
|
||||||
|
<VLQ encoded length><n-byte contents>
|
||||||
|
```
|
||||||
|
|
||||||
|
The command descriptions found in the data dictionary allow both the
|
||||||
|
host and micro-controller to know which command parameters use simple
|
||||||
|
VLQ encoding and which parameters use string encoding.
|
||||||
|
|
||||||
|
Data Dictionary
|
||||||
|
===============
|
||||||
|
|
||||||
|
In order for meaningful communications to be established between
|
||||||
|
micro-controller and host, both sides must agree on a "data
|
||||||
|
dictionary". This data dictionary contains the integer identifiers for
|
||||||
|
commands and responses along with their descriptions.
|
||||||
|
|
||||||
|
The micro-controller build uses the contents of DECL_COMMAND() and
|
||||||
|
sendf() macros to generate the data dictionary. The build
|
||||||
|
automatically assigns unique identifiers to each command and
|
||||||
|
response. This system allows both the host and micro-controller code
|
||||||
|
to seamlessly use descriptive human-readable names while still using
|
||||||
|
minimal bandwidth.
|
||||||
|
|
||||||
|
The host queries the data dictionary when it first connects to the
|
||||||
|
micro-controller. Once the host downloads the data dictionary from the
|
||||||
|
micro-controller, it uses that data dictionary to encode all commands
|
||||||
|
and to parse all responses from the micro-controller. The host must
|
||||||
|
therefore handle a dynamic data dictionary. However, to keep the
|
||||||
|
micro-controller software simple, the micro-controller always uses its
|
||||||
|
static (compiled in) data dictionary.
|
||||||
|
|
||||||
|
The data dictionary is queried by sending "identify" commands to the
|
||||||
|
micro-controller. The micro-controller will respond to each identify
|
||||||
|
command with an "identify_response" message. Since these two commands
|
||||||
|
are needed prior to obtaining the data dictionary, their integer ids
|
||||||
|
and parameter types are hard-coded in both the micro-controller and
|
||||||
|
the host. The "identify_response" response id is 0, the "identify"
|
||||||
|
command id is 1. Other than having hard-coded ids the identify command
|
||||||
|
and its response are declared and transmitted the same way as other
|
||||||
|
commands and responses. No other command or response is hard-coded.
|
||||||
|
|
||||||
|
The format of the transmitted data dictionary itself is a zlib
|
||||||
|
compressed JSON string. The micro-controller build process generates
|
||||||
|
the string, compresses it, and stores it in the text section of the
|
||||||
|
micro-controller flash. The data dictionary can be much larger than
|
||||||
|
the maximum message block size - the host downloads it by sending
|
||||||
|
multiple identify commands requesting progressive chunks of the data
|
||||||
|
dictionary. Once all chunks are obtained the host will assemble the
|
||||||
|
chunks, uncompress the data, and parse the contents.
|
||||||
|
|
||||||
|
In addition to information on the communication protocol, the data
|
||||||
|
dictionary also contains the software version, constants (as defined
|
||||||
|
by DECL_CONSTANT), and static strings.
|
||||||
|
|
||||||
|
Static Strings
|
||||||
|
--------------
|
||||||
|
|
||||||
|
To reduce bandwidth the data dictionary also contains a set of static
|
||||||
|
strings known to the micro-controller. This is useful when sending
|
||||||
|
messages from micro-controller to host. For example, if the
|
||||||
|
micro-controller were to run:
|
||||||
|
|
||||||
|
```
|
||||||
|
shutdown("Unable to handle command");
|
||||||
|
```
|
||||||
|
|
||||||
|
The error message would be encoded and sent using a single VLQ. The
|
||||||
|
host uses the data dictionary to resolve VLQ encoded static string ids
|
||||||
|
to their associated human-readable strings.
|
||||||
|
|
||||||
|
Message flow
|
||||||
|
============
|
||||||
|
|
||||||
|
Message commands sent from host to micro-controller are intended to be
|
||||||
|
error-free. The micro-controller will check the CRC and sequence
|
||||||
|
numbers in each message block to ensure the commands are accurate and
|
||||||
|
in-order. The micro-controller always processes message blocks
|
||||||
|
in-order - should it receive a block out-of-order it will discard it
|
||||||
|
and any other out-of-order blocks until it receives blocks with the
|
||||||
|
correct sequencing.
|
||||||
|
|
||||||
|
The low-level host code implements an automatic retransmission system
|
||||||
|
for lost and corrupt message blocks sent to the micro-controller. To
|
||||||
|
facilitate this, the micro-controller transmits an "ack message block"
|
||||||
|
after each successfully received message block. The host schedules a
|
||||||
|
timeout after sending each block and it will retransmit should the
|
||||||
|
timeout expire without receiving a corresponding "ack". In addition,
|
||||||
|
if the micro-controller detects a corrupt or out-of-order block it may
|
||||||
|
transmit a "nak message block" to facilitate fast retransmission.
|
||||||
|
|
||||||
|
An "ack" is a message block with empty content (ie, a 5 byte message
|
||||||
|
block) and a sequence number greater than the last received host
|
||||||
|
sequence number. A "nak" is a message block with empty content and a
|
||||||
|
sequence number less than the last received host sequence number.
|
||||||
|
|
||||||
|
The protocol facilitates a "window" transmission system so that the
|
||||||
|
host can have many outstanding message blocks in-flight at a
|
||||||
|
time. (This is in addition to the many commands that may be present in
|
||||||
|
a given message block.) This allows maximum bandwidth utilization even
|
||||||
|
in the event of transmission latency. The timeout, retransmit,
|
||||||
|
windowing, and ack mechanism are inspired by similar mechanisms in
|
||||||
|
[TCP](https://en.wikipedia.org/wiki/Transmission_Control_Protocol).
|
||||||
|
|
||||||
|
In the other direction, message blocks sent from micro-controller to
|
||||||
|
host are designed to be error-free, but they do not have assured
|
||||||
|
transmission. (Responses should not be corrupt, but they may go
|
||||||
|
missing.) This is done to keep the implementation in the
|
||||||
|
micro-controller simple. There is no automatic retransmission system
|
||||||
|
for responses - the high-level code is expected to be capable of
|
||||||
|
handling an occasional missing response (usually by re-requesting the
|
||||||
|
content or setting up a recurring schedule of response
|
||||||
|
transmission). The sequence number field in message blocks sent to the
|
||||||
|
host is always one greater than the last received sequence number of
|
||||||
|
message blocks received from the host. It is not used to track
|
||||||
|
sequences of response message blocks.
|
||||||
2
docs/README.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Welcome to the Klipper documentation. The
|
||||||
|
[overview document](Overview.md) is a good starting point.
|
||||||
109
docs/Releases.md
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
History of Klipper releases. Please see
|
||||||
|
[installation](Installation.md) for information on installing Klipper.
|
||||||
|
|
||||||
|
Klipper 0.6.0
|
||||||
|
=============
|
||||||
|
|
||||||
|
Available on 20180331. Major changes in this release:
|
||||||
|
* Enhanced heater and thermistor hardware failure checks
|
||||||
|
* Support for Z probes
|
||||||
|
* Initial support for automatic parameter calibration on deltas (via a
|
||||||
|
new delta_calibrate command)
|
||||||
|
* Initial support for bed tilt compensation (via bed_tilt_calibrate
|
||||||
|
command)
|
||||||
|
* Initial support for "safe homing" and homing overrides
|
||||||
|
* Initial support for displaying status on RepRapDiscount style 2004
|
||||||
|
and 12864 displays
|
||||||
|
* New multi-extruder improvements:
|
||||||
|
* Support for shared heaters
|
||||||
|
* Initial support for dual carriages
|
||||||
|
* Support for configuring multiple steppers per axis (eg, dual Z)
|
||||||
|
* Support for custom digital and pwm output pins (with a new SET_PIN command)
|
||||||
|
* Initial support for a "virtual sdcard" that allows printing directly
|
||||||
|
from Klipper (helps on machines too slow to run OctoPrint well)
|
||||||
|
* Support for setting different arm lengths on each tower of a delta
|
||||||
|
* Support for G-Code M220/M221 commands (speed factor override /
|
||||||
|
extrude factor override)
|
||||||
|
* Several documentation updates:
|
||||||
|
* Many new example config files for common off-the-shelf printers
|
||||||
|
* New multiple MCU config example
|
||||||
|
* New bltouch sensor config example
|
||||||
|
* New FAQ, config check, and G-Code documents
|
||||||
|
* Initial support for continuous integration testing on all github commits
|
||||||
|
* Several bug fixes and code cleanups
|
||||||
|
|
||||||
|
Klipper 0.5.0
|
||||||
|
=============
|
||||||
|
|
||||||
|
Available on 20171025. Major changes in this release:
|
||||||
|
|
||||||
|
* Support for printers with multiple extruders.
|
||||||
|
* Initial support for running on the Beaglebone PRU. Initial support
|
||||||
|
for the Replicape board.
|
||||||
|
* Initial support for running the micro-controller code in a real-time
|
||||||
|
Linux process.
|
||||||
|
* Support for multiple micro-controllers. (For example, one could
|
||||||
|
control an extruder with one micro-controller and the rest of the
|
||||||
|
printer with another.) Software clock synchronization is implemented
|
||||||
|
to coordinate actions between micro-controllers.
|
||||||
|
* Stepper performance improvements (20Mhz AVRs up to 189K steps per
|
||||||
|
second).
|
||||||
|
* Support for controlling servos and support for defining nozzle
|
||||||
|
cooling fans.
|
||||||
|
* Several bug fixes and code cleanups
|
||||||
|
|
||||||
|
Klipper 0.4.0
|
||||||
|
=============
|
||||||
|
|
||||||
|
Available on 20170503. Major changes in this release:
|
||||||
|
|
||||||
|
* Improved installation on Raspberry Pi machines. Most of the install
|
||||||
|
is now scripted.
|
||||||
|
* Support for corexy kinematics
|
||||||
|
* Documentation updates: New Kinematics document, new Pressure Advance
|
||||||
|
tuning guide, new example config files, and more
|
||||||
|
* Stepper performance improvements (20Mhz AVRs over 175K steps per
|
||||||
|
second, Arduino Due over 460K)
|
||||||
|
* Support for automatic micro-controller resets. Support for resets
|
||||||
|
via toggling USB power on Raspberry Pi.
|
||||||
|
* The pressure advance algorithm now works with look-ahead to reduce
|
||||||
|
pressure changes during cornering.
|
||||||
|
* Support for limiting the top speed of short zigzag moves
|
||||||
|
* Support for AD595 sensors
|
||||||
|
* Several bug fixes and code cleanups
|
||||||
|
|
||||||
|
Klipper 0.3.0
|
||||||
|
=============
|
||||||
|
|
||||||
|
Available on 20161223. Major changes in this release:
|
||||||
|
|
||||||
|
* Improved documentation
|
||||||
|
* Support for robots with delta kinematics
|
||||||
|
* Support for Arduino Due micro-controller (ARM cortex-M3)
|
||||||
|
* Support for USB based AVR micro-controllers
|
||||||
|
* Support for "pressure advance" algorithm - it reduces ooze during
|
||||||
|
prints.
|
||||||
|
* New "stepper phased based endstop" feature - enables higher
|
||||||
|
precision on endstop homing.
|
||||||
|
* Support for "extended g-code" commands such as "help", "restart",
|
||||||
|
and "status".
|
||||||
|
* Support for reloading the Klipper config and restarting the host
|
||||||
|
software by issuing a "restart" command from the terminal.
|
||||||
|
* Stepper performance improvements (20Mhz AVRs up to 158K steps per
|
||||||
|
second).
|
||||||
|
* Improved error reporting. Most errors now shown via the terminal
|
||||||
|
along with help on how to resolve.
|
||||||
|
* Several bug fixes and code cleanups
|
||||||
|
|
||||||
|
Klipper 0.2.0
|
||||||
|
=============
|
||||||
|
|
||||||
|
Initial release of Klipper. Available on 20160525. Major features
|
||||||
|
available in the initial release include:
|
||||||
|
|
||||||
|
* Basic support for cartesian printers (steppers, extruder, heated
|
||||||
|
bed, cooling fan).
|
||||||
|
* Support for common g-code commands. Support for interfacing with
|
||||||
|
OctoPrint.
|
||||||
|
* Acceleration and lookahead handling
|
||||||
|
* Support for AVR micro-controllers via standard serial ports
|
||||||
84
docs/Todo.md
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
There are several features still to be implemented in Klipper. In no
|
||||||
|
particular order:
|
||||||
|
|
||||||
|
Host user interaction
|
||||||
|
=====================
|
||||||
|
|
||||||
|
* See if there is a better way to report errors. Octoprint sometimes
|
||||||
|
doesn't highlight an error (one has to look in the terminal tab to
|
||||||
|
find the error) and errors written to the log can be non-obvious to
|
||||||
|
a user.
|
||||||
|
|
||||||
|
* Improve gcode interface:
|
||||||
|
|
||||||
|
* Provide a better way to handle print nozzle z offsets. The M206
|
||||||
|
command is cryptic to use and it is too easy to set the value
|
||||||
|
incorrectly or to forget to set it.
|
||||||
|
|
||||||
|
* Provide a way to temporarily disable endstop checks so that a user
|
||||||
|
can issue commands that potentially move the head past
|
||||||
|
position_min/position_max.
|
||||||
|
|
||||||
|
* Improve logging:
|
||||||
|
|
||||||
|
* Possibly collate and report the statistics messages in the log in a
|
||||||
|
more friendly way.
|
||||||
|
|
||||||
|
* Possibly support a mechanism for the host to limit maximum velocity
|
||||||
|
so that the mcu is never requested to step at a higher rate than it
|
||||||
|
can support.
|
||||||
|
|
||||||
|
Safety features
|
||||||
|
===============
|
||||||
|
|
||||||
|
* Support loading a valid step range into the micro-controller
|
||||||
|
software after homing. This would provide a sanity check in the
|
||||||
|
micro-controller that would reduce the risk of the host commanding a
|
||||||
|
stepper motor past its valid step range. To maintain high
|
||||||
|
efficiency, the micro-controller would only need to check
|
||||||
|
periodically (eg, every 100ms) that the stepper is in range.
|
||||||
|
|
||||||
|
* Possibly support periodically querying the endstop switches and use
|
||||||
|
multiple step ranges depending on the switch state. This would
|
||||||
|
enable runtime endstop detection. (However, it's unclear if runtime
|
||||||
|
endstop detection is a good idea because of spurious signals caused
|
||||||
|
by electrical noise.)
|
||||||
|
|
||||||
|
Testing features
|
||||||
|
================
|
||||||
|
|
||||||
|
* Complete the host based simulator. It's possible to compile the
|
||||||
|
micro-controller for a "host simulator", but that simulator doesn't
|
||||||
|
do anything currently. It would be useful to expand the code to
|
||||||
|
support more error checks, kinematic simulations, and improved
|
||||||
|
logging.
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
=============
|
||||||
|
|
||||||
|
* Add documentation describing how to perform bed-leveling accurately
|
||||||
|
in Klipper. Improve description of stepper phase based bed leveling.
|
||||||
|
|
||||||
|
Hardware features
|
||||||
|
=================
|
||||||
|
|
||||||
|
* Port to additional micro-controller architectures:
|
||||||
|
* Smoothieboard / NXP LPC1769 (ARM cortex-M3)
|
||||||
|
|
||||||
|
* Support for additional kinematics: scara, etc.
|
||||||
|
|
||||||
|
* Possible support for touch panels attached to the micro-controller.
|
||||||
|
(In general, it would be preferable to attach touch panels to the
|
||||||
|
host system and have octoprint interact with the panel directly, but
|
||||||
|
it would also be useful to handle panels already hardwired to the
|
||||||
|
micro-controller.)
|
||||||
|
|
||||||
|
Misc features
|
||||||
|
=============
|
||||||
|
|
||||||
|
* Possibly support a "feed forward PID" that takes into account the
|
||||||
|
amount of plastic being extruded. If the extrude rate changes
|
||||||
|
significantly during a print it can cause heating bumps that the PID
|
||||||
|
overcompensates for. The temperature change due to the extrusion
|
||||||
|
rate could be modeled to eliminate these bumps and make the
|
||||||
|
extrusion temperature more consistent.
|
||||||
103
docs/beaglebone.md
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
This document describes the process of running Klipper on a Beaglebone
|
||||||
|
PRU.
|
||||||
|
|
||||||
|
Building an OS image
|
||||||
|
====================
|
||||||
|
|
||||||
|
Start by installing the
|
||||||
|
[latest Jessie IoT](https://beagleboard.org/latest-images) image
|
||||||
|
(2017-03-19 or later). One may run the image from either a micro-SD
|
||||||
|
card or from builtin eMMC. If using the eMMC, install it to eMMC now
|
||||||
|
by following the instructions from the above link.
|
||||||
|
|
||||||
|
Then ssh into the beaglebone machine (ssh debian@beaglebone --
|
||||||
|
password is "temppwd") and install Klipper by running the following
|
||||||
|
commands:
|
||||||
|
```
|
||||||
|
git clone https://github.com/KevinOConnor/klipper
|
||||||
|
./klipper/scripts/install-beaglebone.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Install Octoprint
|
||||||
|
=================
|
||||||
|
|
||||||
|
One may then install Octoprint:
|
||||||
|
```
|
||||||
|
git clone https://github.com/foosel/OctoPrint.git
|
||||||
|
cd OctoPrint/
|
||||||
|
virtualenv venv
|
||||||
|
./venv/bin/python setup.py install
|
||||||
|
```
|
||||||
|
|
||||||
|
And setup OctoPrint to start at bootup:
|
||||||
|
```
|
||||||
|
sudo cp ~/OctoPrint/scripts/octoprint.init /etc/init.d/octoprint
|
||||||
|
sudo chmod +x /etc/init.d/octoprint
|
||||||
|
sudo cp ~/OctoPrint/scripts/octoprint.default /etc/default/octoprint
|
||||||
|
sudo update-rc.d octoprint defaults
|
||||||
|
```
|
||||||
|
|
||||||
|
It is necessary to modify OctoPrint's **/etc/default/octoprint**
|
||||||
|
configuration file. One must change the OCTOPRINT_USER user to
|
||||||
|
"debian", change NICELEVEL to 0, uncomment the BASEDIR, CONFIGFILE,
|
||||||
|
and DAEMON settings and change the references from "/home/pi/" to
|
||||||
|
"/home/debian/":
|
||||||
|
```
|
||||||
|
sudo nano /etc/default/octoprint
|
||||||
|
```
|
||||||
|
|
||||||
|
Then start the Octoprint service:
|
||||||
|
```
|
||||||
|
sudo systemctl start octoprint
|
||||||
|
```
|
||||||
|
|
||||||
|
Make sure the octoprint web server is accessible - it should be at:
|
||||||
|
[http://beaglebone:5000/](http://beaglebone:5000/)
|
||||||
|
|
||||||
|
Building the micro-controller code
|
||||||
|
==================================
|
||||||
|
|
||||||
|
To compile the Klipper micro-controller code, start by configuring it
|
||||||
|
for the "Beaglebone PRU":
|
||||||
|
```
|
||||||
|
cd ~/klipper/
|
||||||
|
make menuconfig
|
||||||
|
```
|
||||||
|
|
||||||
|
To build and install the new micro-controller code, run:
|
||||||
|
```
|
||||||
|
sudo service klipper stop
|
||||||
|
make flash
|
||||||
|
sudo service klipper start
|
||||||
|
```
|
||||||
|
|
||||||
|
For the Replicape, it is also necessary to compile and install the
|
||||||
|
micro-controller code for a Linux host process. Run "make menuconfig"
|
||||||
|
a second time and configure it for a "Linux process":
|
||||||
|
```
|
||||||
|
make menuconfig
|
||||||
|
```
|
||||||
|
|
||||||
|
Then install this micro-controller code as well:
|
||||||
|
```
|
||||||
|
sudo service klipper stop
|
||||||
|
make flash
|
||||||
|
sudo service klipper start
|
||||||
|
```
|
||||||
|
|
||||||
|
Remaining configuration
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Complete the installation by configuring Klipper and Octoprint
|
||||||
|
following the instructions in
|
||||||
|
[the main installation document](Installation.md#configuring-klipper).
|
||||||
|
|
||||||
|
Printing on the Beaglebone
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Unfortunately, the Beaglebone processor can sometimes struggle to run
|
||||||
|
OctoPrint well. Print stalls have been known to occur on complex
|
||||||
|
prints (the printer may move faster than OctoPrint can send movement
|
||||||
|
commands). If this occurs, consider using the "virtual_sdcard" feature
|
||||||
|
(see [config/example-extras.cfg](../config/example-extras.cfg) for
|
||||||
|
details) to print directly from Klipper.
|
||||||
37
docs/developer-certificate-of-origin
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
Developer Certificate of Origin
|
||||||
|
Version 1.1
|
||||||
|
|
||||||
|
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
|
||||||
|
1 Letterman Drive
|
||||||
|
Suite D4700
|
||||||
|
San Francisco, CA, 94129
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies of this
|
||||||
|
license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
|
||||||
|
Developer's Certificate of Origin 1.1
|
||||||
|
|
||||||
|
By making a contribution to this project, I certify that:
|
||||||
|
|
||||||
|
(a) The contribution was created in whole or in part by me and I
|
||||||
|
have the right to submit it under the open source license
|
||||||
|
indicated in the file; or
|
||||||
|
|
||||||
|
(b) The contribution is based upon previous work that, to the best
|
||||||
|
of my knowledge, is covered under an appropriate open source
|
||||||
|
license and I have the right under that license to submit that
|
||||||
|
work with modifications, whether created in whole or in part
|
||||||
|
by me, under the same open source license (unless I am
|
||||||
|
permitted to submit under a different license), as indicated
|
||||||
|
in the file; or
|
||||||
|
|
||||||
|
(c) The contribution was provided directly to me by some other
|
||||||
|
person who certified (a), (b) or (c) and I have not modified
|
||||||
|
it.
|
||||||
|
|
||||||
|
(d) I understand and agree that this project and the contribution
|
||||||
|
are public and that a record of the contribution (including all
|
||||||
|
personal information I submit with it, including my sign-off) is
|
||||||
|
maintained indefinitely and may be redistributed consistent with
|
||||||
|
this project or the open source license(s) involved.
|
||||||
BIN
docs/img/attach-issue.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
docs/img/corner-blob.jpg
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
docs/img/corner-dimple.jpg
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
docs/img/corner-good.jpg
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
184
docs/img/corner.svg
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="54.904114mm"
|
||||||
|
height="6.0860338mm"
|
||||||
|
viewBox="0 0 194.54213 21.564687"
|
||||||
|
id="svg3506"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="corner.svg">
|
||||||
|
<defs
|
||||||
|
id="defs3508">
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="DiamondL"
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="DiamondL"
|
||||||
|
style="overflow:visible"
|
||||||
|
inkscape:isstock="true">
|
||||||
|
<path
|
||||||
|
id="path4399"
|
||||||
|
d="M 0,-7.0710768 -7.0710894,0 0,7.0710589 7.0710462,0 0,-7.0710768 Z"
|
||||||
|
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||||
|
transform="scale(0.8,0.8)"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="Arrow2Lend"
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="Arrow2Lend"
|
||||||
|
style="overflow:visible"
|
||||||
|
inkscape:isstock="true">
|
||||||
|
<path
|
||||||
|
id="path4341"
|
||||||
|
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
|
||||||
|
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
|
||||||
|
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="Arrow1Mend"
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="marker4596"
|
||||||
|
style="overflow:visible"
|
||||||
|
inkscape:isstock="true">
|
||||||
|
<path
|
||||||
|
id="path4598"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||||
|
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||||
|
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="Arrow1Mend"
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="Arrow1Mend"
|
||||||
|
style="overflow:visible"
|
||||||
|
inkscape:isstock="true">
|
||||||
|
<path
|
||||||
|
id="path4329"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||||
|
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||||
|
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="Arrow1Mend"
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="Arrow1Mend-1"
|
||||||
|
style="overflow:visible"
|
||||||
|
inkscape:isstock="true">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4329-1"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||||
|
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||||
|
transform="matrix(-0.4,0,0,-0.4,-4,0)" />
|
||||||
|
</marker>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="2.49"
|
||||||
|
inkscape:cx="95.030833"
|
||||||
|
inkscape:cy="-0.17370789"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
showborder="false"
|
||||||
|
inkscape:window-width="1068"
|
||||||
|
inkscape:window-height="478"
|
||||||
|
inkscape:window-x="378"
|
||||||
|
inkscape:window-y="113"
|
||||||
|
inkscape:window-maximized="0">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid6021"
|
||||||
|
spacingx="9.9999997"
|
||||||
|
spacingy="10.000001"
|
||||||
|
originx="0.89299989"
|
||||||
|
originy="-30.954583" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata3511">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-253.40821,-436.43703)">
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Mend)"
|
||||||
|
d="m 345.38554,440.31401 96.88541,12.96764"
|
||||||
|
id="path3514"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Mend-1)"
|
||||||
|
d="m 253.63788,454.62572 89.78715,-13.91164"
|
||||||
|
id="path3514-5"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="189.09824"
|
||||||
|
y="482.48389"
|
||||||
|
id="text12656-9"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="matrix(0.98759291,-0.15703579,0.15703579,0.98759291,0,0)"
|
||||||
|
inkscape:transform-center-x="1.3563414"
|
||||||
|
inkscape:transform-center-y="-5.7099754"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan5552"
|
||||||
|
x="189.09824"
|
||||||
|
y="482.48389">move 1</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="427.95532"
|
||||||
|
y="379.5321"
|
||||||
|
id="text12656-9-8"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="matrix(0.98949457,0.14457001,-0.14457001,0.98949457,0,0)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan5554"
|
||||||
|
x="427.95532"
|
||||||
|
y="379.5321">move 2</tspan></text>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 6.7 KiB |
BIN
docs/img/corner.svg.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
273
docs/img/delta-tower.svg
Normal file
@@ -0,0 +1,273 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="97.22496mm"
|
||||||
|
height="32.550285mm"
|
||||||
|
viewBox="0 0 344.49789 115.33566"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="delta-tower.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4">
|
||||||
|
<marker
|
||||||
|
inkscape:isstock="true"
|
||||||
|
style="overflow:visible"
|
||||||
|
id="marker6618"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto"
|
||||||
|
inkscape:stockid="Arrow1Mend">
|
||||||
|
<path
|
||||||
|
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||||
|
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||||
|
id="path6620"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="Arrow1Mend"
|
||||||
|
orient="auto"
|
||||||
|
refY="0.0"
|
||||||
|
refX="0.0"
|
||||||
|
id="marker6500"
|
||||||
|
style="overflow:visible;"
|
||||||
|
inkscape:isstock="true">
|
||||||
|
<path
|
||||||
|
id="path6502"
|
||||||
|
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||||
|
style="fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1;fill:#4b4b4b;fill-opacity:1"
|
||||||
|
transform="scale(0.4) rotate(180) translate(10,0)" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:isstock="true"
|
||||||
|
style="overflow:visible;"
|
||||||
|
id="marker6082"
|
||||||
|
refX="0.0"
|
||||||
|
refY="0.0"
|
||||||
|
orient="auto"
|
||||||
|
inkscape:stockid="Arrow1Mend"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<path
|
||||||
|
transform="scale(0.4) rotate(180) translate(10,0)"
|
||||||
|
style="fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1;fill:#4b4b4b;fill-opacity:1"
|
||||||
|
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||||
|
id="path6084" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="Arrow1Mend"
|
||||||
|
orient="auto"
|
||||||
|
refY="0.0"
|
||||||
|
refX="0.0"
|
||||||
|
id="Arrow1Mend"
|
||||||
|
style="overflow:visible;"
|
||||||
|
inkscape:isstock="true"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<path
|
||||||
|
id="path5747"
|
||||||
|
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||||
|
style="fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1;fill:#4b4b4b;fill-opacity:1"
|
||||||
|
transform="scale(0.4) rotate(180) translate(10,0)" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="Arrow1Mstart"
|
||||||
|
orient="auto"
|
||||||
|
refY="0.0"
|
||||||
|
refX="0.0"
|
||||||
|
id="Arrow1Mstart"
|
||||||
|
style="overflow:visible"
|
||||||
|
inkscape:isstock="true">
|
||||||
|
<path
|
||||||
|
id="path5744"
|
||||||
|
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||||
|
style="fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1;fill:#4b4b4b;fill-opacity:1"
|
||||||
|
transform="scale(0.4) translate(10,0)" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="Arrow1Mend"
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="Arrow1Mend-1"
|
||||||
|
style="overflow:visible"
|
||||||
|
inkscape:isstock="true"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4329-1"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||||
|
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||||
|
transform="matrix(-0.4,0,0,-0.4,-4,0)" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:isstock="true"
|
||||||
|
style="overflow:visible"
|
||||||
|
id="marker6082-9"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto"
|
||||||
|
inkscape:stockid="Arrow1Mend"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||||
|
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||||
|
id="path6084-2" />
|
||||||
|
</marker>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="1.75"
|
||||||
|
inkscape:cx="172.24895"
|
||||||
|
inkscape:cy="45.708959"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="928"
|
||||||
|
inkscape:window-height="628"
|
||||||
|
inkscape:window-x="162"
|
||||||
|
inkscape:window-y="50"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
showborder="false"
|
||||||
|
inkscape:snap-global="false"
|
||||||
|
showguides="false">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid3436" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-135.22429,-249.96955)">
|
||||||
|
<ellipse
|
||||||
|
style="fill:#4d4d4d;stroke:#4b4b4b;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:2, 1, 0.5, 1;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
id="path4255"
|
||||||
|
cx="353.79568"
|
||||||
|
cy="327.87662"
|
||||||
|
rx="4.2857141"
|
||||||
|
ry="4.8571429" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1.00000006;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;marker-start:url(#Arrow1Mstart);marker-end:url(#Arrow1Mend)"
|
||||||
|
d="M 181.50998,381.87664 359.22427,275.01949"
|
||||||
|
id="path5510"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.00000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="371.22427"
|
||||||
|
y="354.44806"
|
||||||
|
id="text6058"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan6060"
|
||||||
|
x="371.22427"
|
||||||
|
y="354.44806">stepper</tspan><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
x="371.22427"
|
||||||
|
y="366.94806"
|
||||||
|
id="tspan9337">tower</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.00000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="166.65283"
|
||||||
|
y="304.16235"
|
||||||
|
id="text6062"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan6064"
|
||||||
|
x="166.65283"
|
||||||
|
y="304.16235">line of movement</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:10.0000006px;line-height:125%;font-family:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;-inkscape-font-specification:'DejaVu Sans, Normal';font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;"
|
||||||
|
x="252.93855"
|
||||||
|
y="384.16235"
|
||||||
|
id="text6066"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan6068"
|
||||||
|
x="252.93855"
|
||||||
|
y="384.16235">move</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1.00000006;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;marker-end:url(#marker6618)"
|
||||||
|
d="m 382.65284,344.73378 c -0.19273,-13.52091 -9.87887,-14.83602 -20.57143,-14.85715"
|
||||||
|
id="path6070"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker6500)"
|
||||||
|
d="m 254.65284,374.44806 c 3.39239,-12.86009 -2.06023,-20.09154 -15.42857,-22.28571"
|
||||||
|
id="path6072"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker6082)"
|
||||||
|
d="m 257.50997,296.16234 c 31.05376,-3.13332 32.38959,-1.23784 42.28572,10.28572"
|
||||||
|
id="path6074"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Mend-1)"
|
||||||
|
d="m 219.61431,358.80126 57.78715,-34.48307"
|
||||||
|
id="path3514-5"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:0.50000003;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
d="m 351.22427,323.59092 -20.57143,-32"
|
||||||
|
id="path3358"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.00000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="244.36713"
|
||||||
|
y="257.30521"
|
||||||
|
id="text4460"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan4462"
|
||||||
|
x="244.36713"
|
||||||
|
y="257.30521">virtual tower</tspan><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
x="244.36713"
|
||||||
|
y="269.80521"
|
||||||
|
id="tspan5867">location</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker6082-9)"
|
||||||
|
d="m 310.90661,257.14111 c 21.29088,8.40268 18.35244,16.28958 20.57143,29.7143"
|
||||||
|
id="path6074-6"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 11 KiB |
BIN
docs/img/delta-tower.svg.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
208
docs/img/lookahead-slow.svg
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="97.22496mm"
|
||||||
|
height="32.550285mm"
|
||||||
|
viewBox="0 0 344.49789 115.33566"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="lookahead-slow.svg"
|
||||||
|
inkscape:export-filename="/home/kevin/src/reprap/firmware/klipper/docs/img/lookahead-slow.svg.png"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-ydpi="90">
|
||||||
|
<defs
|
||||||
|
id="defs4">
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="Arrow1Mend"
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="Arrow1Mend-1"
|
||||||
|
style="overflow:visible"
|
||||||
|
inkscape:isstock="true">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4329-1"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||||
|
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||||
|
transform="matrix(-0.4,0,0,-0.4,-4,0)" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="Arrow1Mend"
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="Arrow1Mend"
|
||||||
|
style="overflow:visible"
|
||||||
|
inkscape:isstock="true">
|
||||||
|
<path
|
||||||
|
id="path4329"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||||
|
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||||
|
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</marker>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="1.15"
|
||||||
|
inkscape:cx="3.4198125"
|
||||||
|
inkscape:cy="101.26451"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1091"
|
||||||
|
inkscape:window-height="588"
|
||||||
|
inkscape:window-x="149"
|
||||||
|
inkscape:window-y="422"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
showborder="false"
|
||||||
|
inkscape:snap-global="false"
|
||||||
|
showguides="false">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid3436" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-135.22429,-249.96955)">
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 150,250.23455 1.06383,102.12765 327.12765,-0.53192 -7.97871,5.85107"
|
||||||
|
id="path3347"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:100%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="434.04257"
|
||||||
|
y="365.1282"
|
||||||
|
id="text3349"
|
||||||
|
sodipodi:linespacing="100%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan3351"
|
||||||
|
x="434.04257"
|
||||||
|
y="365.1282">time</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="-313.86618"
|
||||||
|
y="140.27856"
|
||||||
|
id="text3353"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan3355"
|
||||||
|
x="-313.86618"
|
||||||
|
y="140.27856">velocity</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 150,250.23455 -5.31915,8.51063"
|
||||||
|
id="path3359"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.62366331px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 179.63013,351.45141 16.05677,-60.94328 43.25999,0 16.53759,47.11348"
|
||||||
|
id="path3361"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.7558428px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 254.72406,337.27551 22.65101,-77.77178 43.89917,0 24.69858,91.73948"
|
||||||
|
id="path3361-7"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="195.45749"
|
||||||
|
y="286.52051"
|
||||||
|
id="text12656-9"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan7078"
|
||||||
|
x="195.45749"
|
||||||
|
y="286.52051">move A</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="280.5639"
|
||||||
|
y="254.60564"
|
||||||
|
id="text12656-9-3"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan7080"
|
||||||
|
x="280.5639"
|
||||||
|
y="254.60564">move B</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Mend)"
|
||||||
|
d="m 74.333855,283.02668 -147.83244,52.19984"
|
||||||
|
id="path3514"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Mend-1)"
|
||||||
|
d="m -79.633985,251.6122 154.13499,31.81455"
|
||||||
|
id="path3514-5"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="36.7374"
|
||||||
|
y="252.31848"
|
||||||
|
id="text12656-9-1"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="matrix(0.96753827,0.25272454,-0.25272454,0.96753827,0,0)"
|
||||||
|
inkscape:transform-center-x="-0.91382951"
|
||||||
|
inkscape:transform-center-y="-4.9145266"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan7074"
|
||||||
|
x="36.7374"
|
||||||
|
y="252.31848">move A</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="-126.26086"
|
||||||
|
y="304.35226"
|
||||||
|
id="text12656-9-8"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="matrix(0.93839918,-0.34555314,0.34555314,0.93839918,0,0)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan7076"
|
||||||
|
x="-126.26086"
|
||||||
|
y="304.35226">move B</tspan></text>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 9.2 KiB |
BIN
docs/img/lookahead-slow.svg.png
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
136
docs/img/lookahead.svg
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="97.22496mm"
|
||||||
|
height="32.550285mm"
|
||||||
|
viewBox="0 0 344.49789 115.33566"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="lookahead.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="0.94"
|
||||||
|
inkscape:cx="116.54041"
|
||||||
|
inkscape:cy="45.708959"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1091"
|
||||||
|
inkscape:window-height="588"
|
||||||
|
inkscape:window-x="149"
|
||||||
|
inkscape:window-y="422"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
showborder="false"
|
||||||
|
inkscape:snap-global="false"
|
||||||
|
showguides="false">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid3436" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-135.22429,-249.96955)">
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 150,250.23455 1.06383,102.12765 327.12765,-0.53192 -7.97871,5.85107"
|
||||||
|
id="path3347"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:100%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="434.04257"
|
||||||
|
y="365.1282"
|
||||||
|
id="text3349"
|
||||||
|
sodipodi:linespacing="100%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan3351"
|
||||||
|
x="434.04257"
|
||||||
|
y="365.1282">time</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="-313.86618"
|
||||||
|
y="140.27856"
|
||||||
|
id="text3353"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan3355"
|
||||||
|
x="-313.86618"
|
||||||
|
y="140.27856">velocity</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 150,250.23455 -5.31915,8.51063"
|
||||||
|
id="path3359"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.62366331px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 179.63013,351.45141 16.05677,-60.94328 61.3451,0 4.83546,8.81561"
|
||||||
|
id="path3361"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.7558428px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 261.70791,300.17937 13.5395,-40.67564 59.85662,0 24.69858,91.73948"
|
||||||
|
id="path3361-7"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="200.77664"
|
||||||
|
y="286.52051"
|
||||||
|
id="text12656-9"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan5532"
|
||||||
|
x="200.77664"
|
||||||
|
y="286.52051">move 1</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="280.5639"
|
||||||
|
y="255.66946"
|
||||||
|
id="text12656-9-3"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan5534"
|
||||||
|
x="280.5639"
|
||||||
|
y="255.66946">move 2</tspan></text>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 5.8 KiB |
BIN
docs/img/lookahead.svg.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
docs/img/octoprint-temperature.png
Normal file
|
After Width: | Height: | Size: 40 KiB |
207
docs/img/ooze.svg
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="98.140816mm"
|
||||||
|
height="63.537022mm"
|
||||||
|
viewBox="0 0 347.74305 225.13119"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="ooze.svg"
|
||||||
|
inkscape:export-filename="/home/kevin/src/reprap/firmware/klipper/docs/img/ooze.svg.png"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-ydpi="90">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="0.94"
|
||||||
|
inkscape:cx="199.68782"
|
||||||
|
inkscape:cy="58.510649"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1091"
|
||||||
|
inkscape:window-height="588"
|
||||||
|
inkscape:window-x="266"
|
||||||
|
inkscape:window-y="106"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
showborder="false"
|
||||||
|
inkscape:snap-global="false"
|
||||||
|
showguides="false">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid3436"
|
||||||
|
originx="-1.5695746e-05"
|
||||||
|
originy="109.79552" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-135.22431,-249.96955)">
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 150,250.23455 1.06383,102.12765 327.12765,-0.53192 -7.97871,5.85107"
|
||||||
|
id="path3347"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.50000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="-346.84067"
|
||||||
|
y="139.75046"
|
||||||
|
id="text3353"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan12733"
|
||||||
|
x="-346.84067"
|
||||||
|
y="139.75046">head velocity</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 150,250.23455 -5.31915,8.51063"
|
||||||
|
id="path3359"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 179.63013,351.45141 16.05677,-60.94328 120.91957,-1.06383 16.53759,62.00711"
|
||||||
|
id="path3361"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.78742969px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 332.99641,351.24986 16.72764,-63.00287 133.24331,0"
|
||||||
|
id="path3361-7"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="200.11789"
|
||||||
|
y="284.45413"
|
||||||
|
id="text12656"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan12658"
|
||||||
|
x="200.11789"
|
||||||
|
y="284.45413">extrude move</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="356.50089"
|
||||||
|
y="283.39032"
|
||||||
|
id="text12660"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan12662"
|
||||||
|
x="356.50089"
|
||||||
|
y="283.39032">non-extrude move</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 152.72419,471.73218 1.06383,102.12766 327.12768,-0.53192 -7.97872,5.85107"
|
||||||
|
id="path3347-0"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:100%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="436.76678"
|
||||||
|
y="586.62585"
|
||||||
|
id="text3349-3"
|
||||||
|
sodipodi:linespacing="100%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan3351-4"
|
||||||
|
x="436.76678"
|
||||||
|
y="586.62585">time</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.50000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="-551.11292"
|
||||||
|
y="125.37186"
|
||||||
|
id="text3353-0"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan4197"
|
||||||
|
x="-551.11292"
|
||||||
|
y="125.37186">actual</tspan><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan4199"
|
||||||
|
x="-551.11292"
|
||||||
|
y="140.99686">filament</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 152.72419,471.73218 -5.31915,8.51063"
|
||||||
|
id="path3359-9"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 182.35432,572.94905 c 17.46262,-43.80215 52.67413,-56.54375 92.65253,-60.94329 l 48.57915,-1.06383 c 24.916,55.4715 110.00504,59.23318 151.64398,62.00712"
|
||||||
|
id="path3361-1"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 150.87843,360.66993 1.06383,102.12766 327.12768,-0.53192 -7.97872,5.85107"
|
||||||
|
id="path3347-8"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.50000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="-444.27307"
|
||||||
|
y="124.17301"
|
||||||
|
id="text3353-6"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan4193"
|
||||||
|
x="-444.27307"
|
||||||
|
y="124.17301">desired</tspan><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan4195"
|
||||||
|
x="-444.27307"
|
||||||
|
y="139.79802">filament</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 150.87843,360.66993 -5.31915,8.51063"
|
||||||
|
id="path3359-8"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 180.50856,461.8868 16.05678,-60.94329 120.91958,-1.06383 16.53759,62.00712"
|
||||||
|
id="path3361-4"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 9.8 KiB |
BIN
docs/img/ooze.svg.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
207
docs/img/pressure-advance.svg
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="102.61139mm"
|
||||||
|
height="99.266594mm"
|
||||||
|
viewBox="0 0 363.58366 351.73204"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="pressure-advance.svg"
|
||||||
|
inkscape:export-filename="/home/kevin/src/reprap/firmware/klipper/docs/img/pressure-advance.svg.png"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-ydpi="90">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="0.97968464"
|
||||||
|
inkscape:cx="147.06528"
|
||||||
|
inkscape:cy="169.55487"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1091"
|
||||||
|
inkscape:window-height="588"
|
||||||
|
inkscape:window-x="419"
|
||||||
|
inkscape:window-y="273"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
showborder="false"
|
||||||
|
inkscape:snap-global="false"
|
||||||
|
showguides="false">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid3436"
|
||||||
|
originx="17.089787"
|
||||||
|
originy="126.61899" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-118.13451,-140.19216)">
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 150.47693,249.82417 0.58688,123.9666 m 0,-21.42857 327.12765,-0.53192 -7.97871,5.85107"
|
||||||
|
id="path3347"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.50000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="-334.86746"
|
||||||
|
y="122.91875"
|
||||||
|
id="text3353"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan12816"
|
||||||
|
x="-334.86746"
|
||||||
|
y="122.91875">extruder</tspan><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan12818"
|
||||||
|
x="-334.86746"
|
||||||
|
y="138.54375">velocity</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 150,250.23455 -5.31915,8.51063"
|
||||||
|
id="path3359"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 316.60647,311.78473 16.53759,62.00711 m -154.57776,-52.12767 16.05677,-60.94328 1.06383,29.78724 m 0,0 120.91957,-1.06383 0,22.34043"
|
||||||
|
id="path3361"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 148.75077,140.45716 1.06383,102.12766 327.12769,-0.53192 -7.97872,5.85107"
|
||||||
|
id="path3347-6"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.50000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="-237.05733"
|
||||||
|
y="140.25932"
|
||||||
|
id="text3353-2"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan12733-6"
|
||||||
|
x="-237.05733"
|
||||||
|
y="140.25932">head velocity</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 148.75077,140.45716 -5.31915,8.51063"
|
||||||
|
id="path3359-7"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 178.3809,241.67403 16.05679,-60.94329 120.91958,-1.06383 16.53759,62.00712"
|
||||||
|
id="path3361-5"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.78742969px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 331.74721,241.47248 16.72764,-63.00288 133.24332,0"
|
||||||
|
id="path3361-7-6"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="198.86868"
|
||||||
|
y="174.67674"
|
||||||
|
id="text12656-9"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan12658-8"
|
||||||
|
x="198.86868"
|
||||||
|
y="174.67674">extrude move</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="355.25165"
|
||||||
|
y="173.61293"
|
||||||
|
id="text12660-7"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan12662-2"
|
||||||
|
x="355.25165"
|
||||||
|
y="173.61293">non-extrude move</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 151.94226,384.0742 1.06383,102.12766 327.12769,-0.53192 -7.97872,5.85107"
|
||||||
|
id="path3347-2"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.50000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="-467.65732"
|
||||||
|
y="122.73453"
|
||||||
|
id="text3353-1"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan12868"
|
||||||
|
x="-467.65732"
|
||||||
|
y="122.73453">extruder</tspan><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan12870"
|
||||||
|
x="-467.65732"
|
||||||
|
y="138.35953">pressure</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 151.94226,384.0742 -5.31915,8.51063"
|
||||||
|
id="path3359-5"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 181.57239,485.29107 16.05679,-60.94329 120.91958,-1.06383 16.53759,62.00712"
|
||||||
|
id="path3361-9"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:100%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="438.03586"
|
||||||
|
y="499.53384"
|
||||||
|
id="text3349"
|
||||||
|
sodipodi:linespacing="100%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan3351"
|
||||||
|
x="438.03586"
|
||||||
|
y="499.53384">time</tspan></text>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 9.8 KiB |
BIN
docs/img/pressure-advance.svg.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
180
docs/img/pressure-cornering.svg
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="102.04809mm"
|
||||||
|
height="61.494076mm"
|
||||||
|
viewBox="0 0 361.58771 217.8924"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="pressure-cornering.svg"
|
||||||
|
inkscape:export-filename="/home/kevin/src/reprap/firmware/klipper/docs/img/pressure-cornering.svg.png"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-ydpi="90">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="0.98"
|
||||||
|
inkscape:cx="110.74341"
|
||||||
|
inkscape:cy="35.715236"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1091"
|
||||||
|
inkscape:window-height="588"
|
||||||
|
inkscape:window-x="656"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
showborder="false"
|
||||||
|
inkscape:snap-global="false"
|
||||||
|
showguides="false">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid3436"
|
||||||
|
originx="17.089805"
|
||||||
|
originy="-7.2206491" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-118.13449,-140.19216)">
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 150,250.23455 1.06383,102.12765 327.12765,-0.53192 -7.97871,5.85107"
|
||||||
|
id="path3347"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.50000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="-334.86746"
|
||||||
|
y="122.91875"
|
||||||
|
id="text3353"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan12816"
|
||||||
|
x="-334.86746"
|
||||||
|
y="122.91875">extruder</tspan><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan12818"
|
||||||
|
x="-334.86746"
|
||||||
|
y="138.54375">velocity</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 150,250.23455 -5.31915,8.51063"
|
||||||
|
id="path3359"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 178.5663,321.66417 16.05677,-60.94328 1.06383,29.78724 m 0,0 117.21969,-0.77616 5.99519,7.3871 5.9952,-6.89861 131.50541,-0.77616"
|
||||||
|
id="path3361"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccccccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 148.75077,140.45716 1.06383,102.12766 327.12769,-0.53192 -7.97872,5.85107"
|
||||||
|
id="path3347-6"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.50000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="-237.05733"
|
||||||
|
y="140.25932"
|
||||||
|
id="text3353-2"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan12733-6"
|
||||||
|
x="-237.05733"
|
||||||
|
y="140.25932">head velocity</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 148.75077,140.45716 -5.31915,8.51063"
|
||||||
|
id="path3359-7"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 178.3809,241.67403 16.05679,-60.94329 120.91958,-1.06383 4.29269,10.98671"
|
||||||
|
id="path3361-5"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 319.50231,193.5133 4.48274,-15.0437 133.24332,0"
|
||||||
|
id="path3361-7-6"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="198.86868"
|
||||||
|
y="174.67674"
|
||||||
|
id="text12656-9"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan12891"
|
||||||
|
x="198.86868"
|
||||||
|
y="174.67674">first extrude</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.25px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="355.25165"
|
||||||
|
y="173.61293"
|
||||||
|
id="text12660-7"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan12893"
|
||||||
|
x="355.25165"
|
||||||
|
y="173.61293">second extrude</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4, 2, 1, 2;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="m 314.05288,288.86296 0,17.34694 5.10204,17.34694 -1.02041,-48.97959 7.14286,-17.34694 0,31.63265"
|
||||||
|
id="path12895"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccccc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:100%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="435.80841"
|
||||||
|
y="366.8262"
|
||||||
|
id="text3349"
|
||||||
|
sodipodi:linespacing="100%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan3351"
|
||||||
|
x="435.80841"
|
||||||
|
y="366.8262">time</tspan></text>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 8.4 KiB |
BIN
docs/img/pressure-cornering.svg.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
132
docs/img/smoothed.svg
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="97.22496mm"
|
||||||
|
height="32.550285mm"
|
||||||
|
viewBox="0 0 344.49789 115.33566"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="smoothed.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="1.75"
|
||||||
|
inkscape:cx="167.32577"
|
||||||
|
inkscape:cy="45.708959"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="840"
|
||||||
|
inkscape:window-height="628"
|
||||||
|
inkscape:window-x="162"
|
||||||
|
inkscape:window-y="50"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
showborder="false"
|
||||||
|
inkscape:snap-global="false"
|
||||||
|
showguides="false">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid3436" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-135.22429,-249.96955)">
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 150,250.23455 1.06383,102.12765 327.12765,-0.53192 -7.97871,5.85107"
|
||||||
|
id="path3347"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:100%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="434.04257"
|
||||||
|
y="365.1282"
|
||||||
|
id="text3349"
|
||||||
|
sodipodi:linespacing="100%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan3351"
|
||||||
|
x="434.04257"
|
||||||
|
y="365.1282">time</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="-313.86618"
|
||||||
|
y="140.27856"
|
||||||
|
id="text3353"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan3355"
|
||||||
|
x="-313.86618"
|
||||||
|
y="140.27856">velocity</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 150,250.23455 -5.31915,8.51063"
|
||||||
|
id="path3359"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 165.50998,351.59092 15.42857,-35.42857 35.71428,0 11.71429,36.57143"
|
||||||
|
id="path3362"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.07142997px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 227.83578,352.85633 15.76217,-47.37239 22.00135,0 5.58242,17.6933"
|
||||||
|
id="path3362-3"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.21482575px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 271.35434,323.73296 11.15454,-30.54076 19.27119,-0.11152 8.73883,29.51288"
|
||||||
|
id="path3362-6"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.01949775px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 311.26144,322.49329 11.63197,-21.06975 15.33656,0 13.51652,50.22357"
|
||||||
|
id="path3362-7"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:2.00000012, 1.00000006, 0.50000003, 1.00000006;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="m 165.50999,351.59092 33.14285,-34.28571 29.14286,34.28571"
|
||||||
|
id="path3426"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 5.5 KiB |
BIN
docs/img/smoothed.svg.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
102
docs/img/trapezoid.svg
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="97.22496mm"
|
||||||
|
height="32.550285mm"
|
||||||
|
viewBox="0 0 344.49789 115.33566"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="trapezoid.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="0.94"
|
||||||
|
inkscape:cx="294.7319"
|
||||||
|
inkscape:cy="45.708959"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1091"
|
||||||
|
inkscape:window-height="588"
|
||||||
|
inkscape:window-x="113"
|
||||||
|
inkscape:window-y="31"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
showborder="false" />
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-135.22429,-249.96955)">
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 150,250.23455 1.06383,102.12765 327.12765,-0.53192 -7.97871,5.85107"
|
||||||
|
id="path3347"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:100%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="434.04257"
|
||||||
|
y="365.1282"
|
||||||
|
id="text3349"
|
||||||
|
sodipodi:linespacing="100%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan3351"
|
||||||
|
x="434.04257"
|
||||||
|
y="365.1282">time</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="-313.86618"
|
||||||
|
y="140.27856"
|
||||||
|
id="text3353"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan3355"
|
||||||
|
x="-313.86618"
|
||||||
|
y="140.27856">velocity</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 150,250.23455 -5.31915,8.51063"
|
||||||
|
id="path3359"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 179.78723,351.29837 41.48937,-60.63829 158.51063,0 37.23405,60.63829"
|
||||||
|
id="path3361"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.0 KiB |
BIN
docs/img/trapezoid.svg.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
182
docs/img/trapezoids.svg
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="97.22496mm"
|
||||||
|
height="32.550285mm"
|
||||||
|
viewBox="0 0 344.49789 115.33566"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="trapezoids.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="2.67"
|
||||||
|
inkscape:cx="164.48301"
|
||||||
|
inkscape:cy="76.011989"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1091"
|
||||||
|
inkscape:window-height="588"
|
||||||
|
inkscape:window-x="113"
|
||||||
|
inkscape:window-y="31"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
showborder="false"
|
||||||
|
inkscape:snap-global="false"
|
||||||
|
showguides="false">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid3436" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-135.22429,-249.96955)">
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 150,250.23455 1.06383,102.12765 327.12765,-0.53192 -7.97871,5.85107"
|
||||||
|
id="path3347"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:100%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="434.04257"
|
||||||
|
y="365.1282"
|
||||||
|
id="text3349"
|
||||||
|
sodipodi:linespacing="100%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan3351"
|
||||||
|
x="434.04257"
|
||||||
|
y="365.1282">time</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="-313.86618"
|
||||||
|
y="140.27856"
|
||||||
|
id="text3353"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan3355"
|
||||||
|
x="-313.86618"
|
||||||
|
y="140.27856">velocity</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 150,250.23455 -5.31915,8.51063"
|
||||||
|
id="path3359"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.62366331px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 179.63013,351.45141 16.05677,-60.94328 61.3451,0 6.96312,32.21987"
|
||||||
|
id="path3361"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.7558428px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 263.83557,321.45597 11.41184,-61.95224 59.85662,0 9.80496,29.88826"
|
||||||
|
id="path3361-7"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.7558428px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 344.93248,289.80297 59.85663,0 15.12411,61.95225"
|
||||||
|
id="path3361-7-7"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 263.86975,321.69491 0.37453,30.52957"
|
||||||
|
id="path3412"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 345.25947,289.31929 0.14909,62.46104"
|
||||||
|
id="path3414"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 222.45831,289.77329 -0.0598,62.07666"
|
||||||
|
id="path3416"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:20.00000119px;line-height:125%;font-family:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;-inkscape-font-specification:'DejaVu Sans, Normal';font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;"
|
||||||
|
x="193.73491"
|
||||||
|
y="338.70944"
|
||||||
|
id="text3418"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan3420"
|
||||||
|
x="193.73491"
|
||||||
|
y="338.70944">1</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20.00000191px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="236.28812"
|
||||||
|
y="338.70947"
|
||||||
|
id="text3422"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan3434"
|
||||||
|
x="236.28812"
|
||||||
|
y="338.70947">2</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20.00000191px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="294.79874"
|
||||||
|
y="335.51794"
|
||||||
|
id="text3426"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan3428"
|
||||||
|
x="294.79874"
|
||||||
|
y="335.51794">3</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:20.00000119px;line-height:125%;font-family:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;-inkscape-font-specification:'DejaVu Sans, Normal';font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;"
|
||||||
|
x="367.13916"
|
||||||
|
y="337.6456"
|
||||||
|
id="text3430"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan3432"
|
||||||
|
x="367.13916"
|
||||||
|
y="337.6456">4</tspan></text>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 8.3 KiB |
BIN
docs/img/trapezoids.svg.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
241
docs/img/virtual-tower.svg
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="64.619751mm"
|
||||||
|
height="27.45583mm"
|
||||||
|
viewBox="0 0 228.96762 97.284438"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="virtual-tower.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4">
|
||||||
|
<marker
|
||||||
|
inkscape:isstock="true"
|
||||||
|
style="overflow:visible"
|
||||||
|
id="marker6618"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto"
|
||||||
|
inkscape:stockid="Arrow1Mend">
|
||||||
|
<path
|
||||||
|
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||||
|
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||||
|
id="path6620"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="Arrow1Mend"
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="marker6500"
|
||||||
|
style="overflow:visible"
|
||||||
|
inkscape:isstock="true">
|
||||||
|
<path
|
||||||
|
id="path6502"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||||
|
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||||
|
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="Arrow1Mend"
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="Arrow1Mend"
|
||||||
|
style="overflow:visible"
|
||||||
|
inkscape:isstock="true"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<path
|
||||||
|
id="path5747"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||||
|
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||||
|
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="Arrow1Mstart"
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="Arrow1Mstart"
|
||||||
|
style="overflow:visible"
|
||||||
|
inkscape:isstock="true">
|
||||||
|
<path
|
||||||
|
id="path5744"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||||
|
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||||
|
transform="matrix(0.4,0,0,0.4,4,0)"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="Arrow1Mend"
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="Arrow1Mend-1"
|
||||||
|
style="overflow:visible"
|
||||||
|
inkscape:isstock="true"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4329-1"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||||
|
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||||
|
transform="matrix(-0.4,0,0,-0.4,-4,0)" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:isstock="true"
|
||||||
|
style="overflow:visible"
|
||||||
|
id="marker6082"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto"
|
||||||
|
inkscape:stockid="Arrow1Mend"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||||
|
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||||
|
id="path6084" />
|
||||||
|
</marker>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="1.75"
|
||||||
|
inkscape:cx="169.7719"
|
||||||
|
inkscape:cy="-4.0565054"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="922"
|
||||||
|
inkscape:window-height="628"
|
||||||
|
inkscape:window-x="162"
|
||||||
|
inkscape:window-y="50"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
showborder="false"
|
||||||
|
inkscape:snap-global="false"
|
||||||
|
showguides="false">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid3436"
|
||||||
|
originx="-14.085234"
|
||||||
|
originy="-95.286988" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-149.30952,-172.73378)">
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#Arrow1Mstart);marker-end:url(#Arrow1Mend)"
|
||||||
|
d="m 176.36712,256.16235 200.00001,-0.57143"
|
||||||
|
id="path5510"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.00000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="-254.01012"
|
||||||
|
y="369.20834"
|
||||||
|
id="text6058"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="matrix(-0.01833576,-0.99983189,0.99983189,-0.01833576,0,0)"
|
||||||
|
inkscape:transform-center-x="-8.0000002"
|
||||||
|
inkscape:transform-center-y="12.571429"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan10365"
|
||||||
|
x="-254.01012"
|
||||||
|
y="369.20834">virtual tower</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.00000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="148.36713"
|
||||||
|
y="269.87662"
|
||||||
|
id="text6062"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan6064"
|
||||||
|
x="148.36713"
|
||||||
|
y="269.87662">line of movement</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.00000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="237.50998"
|
||||||
|
y="251.01949"
|
||||||
|
id="text6066"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan6068"
|
||||||
|
x="237.50998"
|
||||||
|
y="251.01949">move</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:7.00000048;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 358.08141,255.01949 0,-82.28571"
|
||||||
|
id="path10351"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 220.36713,255.01949 357.50998,173.30521"
|
||||||
|
id="path10373"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.00000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="200.36713"
|
||||||
|
y="187.59093"
|
||||||
|
id="text10375"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan10377"
|
||||||
|
x="200.36713"
|
||||||
|
y="187.59093">virtual arm</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker6082)"
|
||||||
|
d="m 261.76375,182.85539 c 22.73118,-0.70136 26.45506,3.7437 40.00001,18.28573"
|
||||||
|
id="path6074"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Mend-1)"
|
||||||
|
d="m 219.61431,255.37268 70.93001,0.37408"
|
||||||
|
id="path3514-5"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 9.5 KiB |
BIN
docs/img/virtual-tower.svg.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
241
docs/img/xy+z-tower.svg
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="64.619751mm"
|
||||||
|
height="27.45583mm"
|
||||||
|
viewBox="0 0 228.96762 97.284438"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="xy+z-tower.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4">
|
||||||
|
<marker
|
||||||
|
inkscape:isstock="true"
|
||||||
|
style="overflow:visible"
|
||||||
|
id="marker6618"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto"
|
||||||
|
inkscape:stockid="Arrow1Mend">
|
||||||
|
<path
|
||||||
|
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||||
|
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||||
|
id="path6620"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="Arrow1Mend"
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="marker6500"
|
||||||
|
style="overflow:visible"
|
||||||
|
inkscape:isstock="true">
|
||||||
|
<path
|
||||||
|
id="path6502"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||||
|
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||||
|
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="Arrow1Mend"
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="Arrow1Mend"
|
||||||
|
style="overflow:visible"
|
||||||
|
inkscape:isstock="true"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<path
|
||||||
|
id="path5747"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||||
|
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||||
|
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="Arrow1Mstart"
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="Arrow1Mstart"
|
||||||
|
style="overflow:visible"
|
||||||
|
inkscape:isstock="true">
|
||||||
|
<path
|
||||||
|
id="path5744"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||||
|
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||||
|
transform="matrix(0.4,0,0,0.4,4,0)"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="Arrow1Mend"
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="Arrow1Mend-1"
|
||||||
|
style="overflow:visible"
|
||||||
|
inkscape:isstock="true"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4329-1"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||||
|
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
|
||||||
|
transform="matrix(-0.4,0,0,-0.4,-4,0)" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:isstock="true"
|
||||||
|
style="overflow:visible"
|
||||||
|
id="marker6082"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto"
|
||||||
|
inkscape:stockid="Arrow1Mend"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||||
|
style="fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1pt;stroke-opacity:1"
|
||||||
|
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
|
||||||
|
id="path6084" />
|
||||||
|
</marker>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="1.75"
|
||||||
|
inkscape:cx="169.7719"
|
||||||
|
inkscape:cy="-4.0565054"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="922"
|
||||||
|
inkscape:window-height="628"
|
||||||
|
inkscape:window-x="162"
|
||||||
|
inkscape:window-y="50"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
showborder="false"
|
||||||
|
inkscape:snap-global="false"
|
||||||
|
showguides="false">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid3436"
|
||||||
|
originx="-14.085234"
|
||||||
|
originy="-95.286988" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-149.30952,-172.73378)">
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#Arrow1Mstart);marker-end:url(#Arrow1Mend)"
|
||||||
|
d="m 176.36712,256.16235 200.00001,-0.57143"
|
||||||
|
id="path5510"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.00000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="-119.27526"
|
||||||
|
y="434.37329"
|
||||||
|
id="text6058"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="matrix(0.32454206,-0.94587127,0.94587127,0.32454206,0,0)"
|
||||||
|
inkscape:transform-center-x="-3.9400734"
|
||||||
|
inkscape:transform-center-y="14.789029"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan10365"
|
||||||
|
x="-119.27526"
|
||||||
|
y="434.37329">virtual tower</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.00000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="148.36713"
|
||||||
|
y="269.87662"
|
||||||
|
id="text6062"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan6064"
|
||||||
|
x="148.36713"
|
||||||
|
y="269.87662">line of movement</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.00000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="237.50998"
|
||||||
|
y="251.01949"
|
||||||
|
id="text6066"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan6068"
|
||||||
|
x="237.50998"
|
||||||
|
y="251.01949">move</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:7.00000048;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 354.70239,255.76769 28.12779,-77.32895"
|
||||||
|
id="path10351"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 220.36713,255.01949 380.93855,178.44807"
|
||||||
|
id="path10373"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.00000095px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="200.36713"
|
||||||
|
y="187.59093"
|
||||||
|
id="text10375"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan10377"
|
||||||
|
x="200.36713"
|
||||||
|
y="187.59093">virtual arm</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker6082)"
|
||||||
|
d="m 261.76375,182.85539 c 22.73118,-0.70136 26.45506,3.7437 40.00001,18.28573"
|
||||||
|
id="path6074"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Mend-1)"
|
||||||
|
d="m 219.61431,255.37268 70.93001,0.37408"
|
||||||
|
id="path3514-5"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 9.5 KiB |
BIN
docs/img/xy+z-tower.svg.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
126
docs/img/zigzag.svg
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="97.22496mm"
|
||||||
|
height="32.550285mm"
|
||||||
|
viewBox="0 0 344.49789 115.33566"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="zigzag.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="1.75"
|
||||||
|
inkscape:cx="167.32577"
|
||||||
|
inkscape:cy="45.708959"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="840"
|
||||||
|
inkscape:window-height="628"
|
||||||
|
inkscape:window-x="160"
|
||||||
|
inkscape:window-y="35"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
showborder="false"
|
||||||
|
inkscape:snap-global="false"
|
||||||
|
showguides="false">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid3436" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-135.22429,-249.96955)">
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 150,250.23455 1.06383,102.12765 327.12765,-0.53192 -7.97871,5.85107"
|
||||||
|
id="path3347"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:100%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="434.04257"
|
||||||
|
y="365.1282"
|
||||||
|
id="text3349"
|
||||||
|
sodipodi:linespacing="100%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan3351"
|
||||||
|
x="434.04257"
|
||||||
|
y="365.1282">time</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.5px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="-313.86618"
|
||||||
|
y="140.27856"
|
||||||
|
id="text3353"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="matrix(-0.01601372,-0.99987177,0.99987177,-0.01601372,0,0)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan3355"
|
||||||
|
x="-313.86618"
|
||||||
|
y="140.27856">velocity</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 150,250.23455 -5.31915,8.51063"
|
||||||
|
id="path3359"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 165.50998,351.59092 24.57143,-73.14286 23.42857,73.14286"
|
||||||
|
id="path3362"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 214.08032,352.31321 24.57144,-73.14287 13.14286,43.42858"
|
||||||
|
id="path3362-3"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.09757805px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 252.42963,323.78006 17.64919,-60.34771 14.22362,59.20485"
|
||||||
|
id="path3362-6"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 284.36604,322.59892 14.85715,-44.00001 3.71429,0 16.85715,73.14287"
|
||||||
|
id="path3362-7"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 5.1 KiB |
BIN
docs/img/zigzag.svg.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
2
docs/issue_template.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
<!-- Klipper do something undesirable? YOU MUST ATTACH THE KLIPPER LOG FILE.
|
||||||
|
See: https://github.com/KevinOConnor/klipper/blob/master/docs/Contact.md -->
|
||||||
45
docs/prints/square.scad
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
// Test square
|
||||||
|
//
|
||||||
|
// Generate STL using OpenSCAD:
|
||||||
|
// openscad square.scad -o square.stl
|
||||||
|
|
||||||
|
square_width = 5;
|
||||||
|
square_size = 60;
|
||||||
|
square_height = 5;
|
||||||
|
|
||||||
|
module hollow_square() {
|
||||||
|
difference() {
|
||||||
|
cube([square_size, square_size, square_height]);
|
||||||
|
translate([square_width, square_width, -1])
|
||||||
|
cube([square_size-2*square_width, square_size-2*square_width,
|
||||||
|
square_height+2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module notch() {
|
||||||
|
CUT = 0.01;
|
||||||
|
depth = .5;
|
||||||
|
width = 1;
|
||||||
|
translate([-depth, -width, -CUT])
|
||||||
|
cube([2*depth, 2*width, square_height + 2*CUT]);
|
||||||
|
}
|
||||||
|
|
||||||
|
module square_with_notches() {
|
||||||
|
difference() {
|
||||||
|
// Start with initial square
|
||||||
|
hollow_square();
|
||||||
|
// Remove four notches on inside perimeter
|
||||||
|
translate([square_width, square_size/2 - 4, 0])
|
||||||
|
notch();
|
||||||
|
translate([square_size/2, square_size - square_width, 0])
|
||||||
|
rotate([0, 0, 90])
|
||||||
|
notch();
|
||||||
|
translate([square_size - square_width, square_size/2, 0])
|
||||||
|
notch();
|
||||||
|
translate([square_size/2, square_width, 0])
|
||||||
|
rotate([0, 0, 90])
|
||||||
|
notch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
square_with_notches();
|
||||||
674
docs/prints/square.stl
Normal file
@@ -0,0 +1,674 @@
|
|||||||
|
solid OpenSCAD_Model
|
||||||
|
facet normal -1 0 0
|
||||||
|
outer loop
|
||||||
|
vertex 0 0 0
|
||||||
|
vertex 0 60 5
|
||||||
|
vertex 0 60 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -1 -0 0
|
||||||
|
outer loop
|
||||||
|
vertex 0 60 5
|
||||||
|
vertex 0 0 0
|
||||||
|
vertex 0 0 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 5 25 5
|
||||||
|
vertex 4.5 25 5
|
||||||
|
vertex 5 5 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 29 5 5
|
||||||
|
vertex 5 5 5
|
||||||
|
vertex 29 4.5 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 60 60 5
|
||||||
|
vertex 55.5 31 5
|
||||||
|
vertex 60 0 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 60 60 5
|
||||||
|
vertex 55 55 5
|
||||||
|
vertex 55.5 31 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 60 60 5
|
||||||
|
vertex 31 55.5 5
|
||||||
|
vertex 55 55 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 60 60 5
|
||||||
|
vertex 29 55.5 5
|
||||||
|
vertex 31 55.5 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 29 55.5 5
|
||||||
|
vertex 5 55 5
|
||||||
|
vertex 29 55 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 0 60 5
|
||||||
|
vertex 29 55.5 5
|
||||||
|
vertex 60 60 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 5 55 5
|
||||||
|
vertex 4.5 27 5
|
||||||
|
vertex 5 27 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 0 0 5
|
||||||
|
vertex 4.5 27 5
|
||||||
|
vertex 0 60 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 5 55 5
|
||||||
|
vertex 0 60 5
|
||||||
|
vertex 4.5 27 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 29 55.5 5
|
||||||
|
vertex 0 60 5
|
||||||
|
vertex 5 55 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 55.5 29 5
|
||||||
|
vertex 60 0 5
|
||||||
|
vertex 55.5 31 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 55 5 5
|
||||||
|
vertex 55.5 29 5
|
||||||
|
vertex 55 29 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 55.5 29 5
|
||||||
|
vertex 55 5 5
|
||||||
|
vertex 60 0 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 31 4.5 5
|
||||||
|
vertex 55 5 5
|
||||||
|
vertex 31 5 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 55 5 5
|
||||||
|
vertex 31 4.5 5
|
||||||
|
vertex 60 0 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 29 4.5 5
|
||||||
|
vertex 60 0 5
|
||||||
|
vertex 31 4.5 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 0 0 5
|
||||||
|
vertex 29 4.5 5
|
||||||
|
vertex 5 5 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 4.5 27 5
|
||||||
|
vertex 0 0 5
|
||||||
|
vertex 4.5 25 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 29 4.5 5
|
||||||
|
vertex 0 0 5
|
||||||
|
vertex 60 0 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 4.5 25 5
|
||||||
|
vertex 0 0 5
|
||||||
|
vertex 5 5 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 55.5 31 5
|
||||||
|
vertex 55 55 5
|
||||||
|
vertex 55 31 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 1
|
||||||
|
outer loop
|
||||||
|
vertex 55 55 5
|
||||||
|
vertex 31 55.5 5
|
||||||
|
vertex 31 55 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 1 -0 0
|
||||||
|
outer loop
|
||||||
|
vertex 60 0 5
|
||||||
|
vertex 60 60 0
|
||||||
|
vertex 60 60 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 1 0 0
|
||||||
|
outer loop
|
||||||
|
vertex 60 60 0
|
||||||
|
vertex 60 0 5
|
||||||
|
vertex 60 0 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 1 -0
|
||||||
|
outer loop
|
||||||
|
vertex 60 60 0
|
||||||
|
vertex 0 60 5
|
||||||
|
vertex 60 60 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 1 0
|
||||||
|
outer loop
|
||||||
|
vertex 0 60 5
|
||||||
|
vertex 60 60 0
|
||||||
|
vertex 0 60 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 5 27 0
|
||||||
|
vertex 4.5 27 0
|
||||||
|
vertex 5 55 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 29 55 0
|
||||||
|
vertex 5 55 0
|
||||||
|
vertex 29 55.5 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 60 0 0
|
||||||
|
vertex 55.5 29 0
|
||||||
|
vertex 60 60 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 60 0 0
|
||||||
|
vertex 55 5 0
|
||||||
|
vertex 55.5 29 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 60 0 0
|
||||||
|
vertex 31 4.5 0
|
||||||
|
vertex 55 5 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 60 0 0
|
||||||
|
vertex 29 4.5 0
|
||||||
|
vertex 31 4.5 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 29 4.5 0
|
||||||
|
vertex 5 5 0
|
||||||
|
vertex 29 5 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 0 0 0
|
||||||
|
vertex 29 4.5 0
|
||||||
|
vertex 60 0 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 5 5 0
|
||||||
|
vertex 4.5 25 0
|
||||||
|
vertex 5 25 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 4.5 25 0
|
||||||
|
vertex 0 0 0
|
||||||
|
vertex 4.5 27 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 5 5 0
|
||||||
|
vertex 0 0 0
|
||||||
|
vertex 4.5 25 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 29 4.5 0
|
||||||
|
vertex 0 0 0
|
||||||
|
vertex 5 5 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 55.5 31 0
|
||||||
|
vertex 60 60 0
|
||||||
|
vertex 55.5 29 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 55 55 0
|
||||||
|
vertex 55.5 31 0
|
||||||
|
vertex 55 31 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 55.5 31 0
|
||||||
|
vertex 55 55 0
|
||||||
|
vertex 60 60 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 31 55.5 0
|
||||||
|
vertex 55 55 0
|
||||||
|
vertex 31 55 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 55 55 0
|
||||||
|
vertex 31 55.5 0
|
||||||
|
vertex 60 60 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 29 55.5 0
|
||||||
|
vertex 60 60 0
|
||||||
|
vertex 31 55.5 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 0 60 0
|
||||||
|
vertex 29 55.5 0
|
||||||
|
vertex 5 55 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 0 60 0
|
||||||
|
vertex 4.5 27 0
|
||||||
|
vertex 0 0 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 29 55.5 0
|
||||||
|
vertex 0 60 0
|
||||||
|
vertex 60 60 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 4.5 27 0
|
||||||
|
vertex 0 60 0
|
||||||
|
vertex 5 55 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 55.5 29 0
|
||||||
|
vertex 55 5 0
|
||||||
|
vertex 55 29 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -0 0 -1
|
||||||
|
outer loop
|
||||||
|
vertex 55 5 0
|
||||||
|
vertex 31 4.5 0
|
||||||
|
vertex 31 5 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 -1 0
|
||||||
|
outer loop
|
||||||
|
vertex 0 0 0
|
||||||
|
vertex 60 0 5
|
||||||
|
vertex 0 0 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 -1 -0
|
||||||
|
outer loop
|
||||||
|
vertex 60 0 5
|
||||||
|
vertex 0 0 0
|
||||||
|
vertex 60 0 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 1 -0 0
|
||||||
|
outer loop
|
||||||
|
vertex 5 5 5
|
||||||
|
vertex 5 25 0
|
||||||
|
vertex 5 25 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 1 0 0
|
||||||
|
outer loop
|
||||||
|
vertex 5 25 0
|
||||||
|
vertex 5 5 5
|
||||||
|
vertex 5 5 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 1 -0 0
|
||||||
|
outer loop
|
||||||
|
vertex 5 27 5
|
||||||
|
vertex 5 55 0
|
||||||
|
vertex 5 55 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 1 0 0
|
||||||
|
outer loop
|
||||||
|
vertex 5 55 0
|
||||||
|
vertex 5 27 5
|
||||||
|
vertex 5 27 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -1 0 0
|
||||||
|
outer loop
|
||||||
|
vertex 55 5 0
|
||||||
|
vertex 55 29 5
|
||||||
|
vertex 55 29 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -1 -0 0
|
||||||
|
outer loop
|
||||||
|
vertex 55 29 5
|
||||||
|
vertex 55 5 0
|
||||||
|
vertex 55 5 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -1 0 0
|
||||||
|
outer loop
|
||||||
|
vertex 55 31 0
|
||||||
|
vertex 55 55 5
|
||||||
|
vertex 55 55 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -1 -0 0
|
||||||
|
outer loop
|
||||||
|
vertex 55 55 5
|
||||||
|
vertex 55 31 0
|
||||||
|
vertex 55 31 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 1 -0
|
||||||
|
outer loop
|
||||||
|
vertex 29 5 0
|
||||||
|
vertex 5 5 5
|
||||||
|
vertex 29 5 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 1 0
|
||||||
|
outer loop
|
||||||
|
vertex 5 5 5
|
||||||
|
vertex 29 5 0
|
||||||
|
vertex 5 5 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 1 -0
|
||||||
|
outer loop
|
||||||
|
vertex 55 5 0
|
||||||
|
vertex 31 5 5
|
||||||
|
vertex 55 5 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 1 0
|
||||||
|
outer loop
|
||||||
|
vertex 31 5 5
|
||||||
|
vertex 55 5 0
|
||||||
|
vertex 31 5 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 -1 0
|
||||||
|
outer loop
|
||||||
|
vertex 5 55 0
|
||||||
|
vertex 29 55 5
|
||||||
|
vertex 5 55 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 -1 -0
|
||||||
|
outer loop
|
||||||
|
vertex 29 55 5
|
||||||
|
vertex 5 55 0
|
||||||
|
vertex 29 55 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 -1 0
|
||||||
|
outer loop
|
||||||
|
vertex 31 55 0
|
||||||
|
vertex 55 55 5
|
||||||
|
vertex 31 55 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 -1 -0
|
||||||
|
outer loop
|
||||||
|
vertex 55 55 5
|
||||||
|
vertex 31 55 0
|
||||||
|
vertex 55 55 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 1 -0 0
|
||||||
|
outer loop
|
||||||
|
vertex 4.5 25 5
|
||||||
|
vertex 4.5 27 0
|
||||||
|
vertex 4.5 27 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 1 0 0
|
||||||
|
outer loop
|
||||||
|
vertex 4.5 27 0
|
||||||
|
vertex 4.5 25 5
|
||||||
|
vertex 4.5 25 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 -1 0
|
||||||
|
outer loop
|
||||||
|
vertex 4.5 27 0
|
||||||
|
vertex 5 27 5
|
||||||
|
vertex 4.5 27 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 -1 -0
|
||||||
|
outer loop
|
||||||
|
vertex 5 27 5
|
||||||
|
vertex 4.5 27 0
|
||||||
|
vertex 5 27 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 1 -0
|
||||||
|
outer loop
|
||||||
|
vertex 5 25 0
|
||||||
|
vertex 4.5 25 5
|
||||||
|
vertex 5 25 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 1 0
|
||||||
|
outer loop
|
||||||
|
vertex 4.5 25 5
|
||||||
|
vertex 5 25 0
|
||||||
|
vertex 4.5 25 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 -1 0
|
||||||
|
outer loop
|
||||||
|
vertex 29 55.5 0
|
||||||
|
vertex 31 55.5 5
|
||||||
|
vertex 29 55.5 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 -1 -0
|
||||||
|
outer loop
|
||||||
|
vertex 31 55.5 5
|
||||||
|
vertex 29 55.5 0
|
||||||
|
vertex 31 55.5 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 1 -0 0
|
||||||
|
outer loop
|
||||||
|
vertex 29 55 5
|
||||||
|
vertex 29 55.5 0
|
||||||
|
vertex 29 55.5 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 1 0 0
|
||||||
|
outer loop
|
||||||
|
vertex 29 55.5 0
|
||||||
|
vertex 29 55 5
|
||||||
|
vertex 29 55 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -1 0 0
|
||||||
|
outer loop
|
||||||
|
vertex 31 55 0
|
||||||
|
vertex 31 55.5 5
|
||||||
|
vertex 31 55.5 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -1 -0 0
|
||||||
|
outer loop
|
||||||
|
vertex 31 55.5 5
|
||||||
|
vertex 31 55 0
|
||||||
|
vertex 31 55 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -1 0 0
|
||||||
|
outer loop
|
||||||
|
vertex 55.5 29 0
|
||||||
|
vertex 55.5 31 5
|
||||||
|
vertex 55.5 31 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -1 -0 0
|
||||||
|
outer loop
|
||||||
|
vertex 55.5 31 5
|
||||||
|
vertex 55.5 29 0
|
||||||
|
vertex 55.5 29 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 -1 0
|
||||||
|
outer loop
|
||||||
|
vertex 55 31 0
|
||||||
|
vertex 55.5 31 5
|
||||||
|
vertex 55 31 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 -1 -0
|
||||||
|
outer loop
|
||||||
|
vertex 55.5 31 5
|
||||||
|
vertex 55 31 0
|
||||||
|
vertex 55.5 31 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 1 -0
|
||||||
|
outer loop
|
||||||
|
vertex 55.5 29 0
|
||||||
|
vertex 55 29 5
|
||||||
|
vertex 55.5 29 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 1 0
|
||||||
|
outer loop
|
||||||
|
vertex 55 29 5
|
||||||
|
vertex 55.5 29 0
|
||||||
|
vertex 55 29 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 1 -0
|
||||||
|
outer loop
|
||||||
|
vertex 31 4.5 0
|
||||||
|
vertex 29 4.5 5
|
||||||
|
vertex 31 4.5 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 0 1 0
|
||||||
|
outer loop
|
||||||
|
vertex 29 4.5 5
|
||||||
|
vertex 31 4.5 0
|
||||||
|
vertex 29 4.5 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -1 0 0
|
||||||
|
outer loop
|
||||||
|
vertex 31 4.5 0
|
||||||
|
vertex 31 5 5
|
||||||
|
vertex 31 5 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal -1 -0 0
|
||||||
|
outer loop
|
||||||
|
vertex 31 5 5
|
||||||
|
vertex 31 4.5 0
|
||||||
|
vertex 31 4.5 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 1 -0 0
|
||||||
|
outer loop
|
||||||
|
vertex 29 4.5 5
|
||||||
|
vertex 29 5 0
|
||||||
|
vertex 29 5 5
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
facet normal 1 0 0
|
||||||
|
outer loop
|
||||||
|
vertex 29 5 0
|
||||||
|
vertex 29 4.5 5
|
||||||
|
vertex 29 4.5 0
|
||||||
|
endloop
|
||||||
|
endfacet
|
||||||
|
endsolid OpenSCAD_Model
|
||||||
@@ -1,252 +1,190 @@
|
|||||||
# Code for handling cartesian (standard x, y, z planes) moves
|
# Code for handling the kinematics of cartesian robots
|
||||||
#
|
#
|
||||||
# Copyright (C) 2016 Kevin O'Connor <kevin@koconnor.net>
|
# Copyright (C) 2016 Kevin O'Connor <kevin@koconnor.net>
|
||||||
#
|
#
|
||||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
import math, logging, time
|
import logging
|
||||||
import lookahead, stepper, homing
|
import stepper, homing
|
||||||
|
|
||||||
# Common suffixes: _d is distance (in mm), _v is velocity (in
|
StepList = (0, 1, 2)
|
||||||
# mm/second), _t is time (in seconds), _r is ratio (scalar between
|
|
||||||
# 0.0 and 1.0)
|
|
||||||
|
|
||||||
StepList = (0, 1, 2, 3)
|
|
||||||
|
|
||||||
class Move:
|
|
||||||
def __init__(self, kin, relsteps, speed):
|
|
||||||
self.kin = kin
|
|
||||||
self.relsteps = relsteps
|
|
||||||
self.junction_max = self.junction_start_max = self.junction_delta = 0.
|
|
||||||
# Calculate requested distance to travel (in mm)
|
|
||||||
steppers = self.kin.steppers
|
|
||||||
absrelsteps = [abs(relsteps[i]) for i in StepList]
|
|
||||||
stepper_d = [absrelsteps[i] * steppers[i].step_dist
|
|
||||||
for i in StepList]
|
|
||||||
self.move_d = math.sqrt(sum([d*d for d in stepper_d[:3]]))
|
|
||||||
if not self.move_d:
|
|
||||||
self.move_d = stepper_d[3]
|
|
||||||
if not self.move_d:
|
|
||||||
return
|
|
||||||
# Limit velocity to max for each stepper
|
|
||||||
velocity_factor = min([steppers[i].max_step_velocity / absrelsteps[i]
|
|
||||||
for i in StepList if absrelsteps[i]])
|
|
||||||
move_v = min(speed, velocity_factor * self.move_d)
|
|
||||||
self.junction_max = move_v**2
|
|
||||||
# Find max acceleration factor
|
|
||||||
accel_factor = min([steppers[i].max_step_accel / absrelsteps[i]
|
|
||||||
for i in StepList if absrelsteps[i]])
|
|
||||||
accel = min(self.kin.max_accel, accel_factor * self.move_d)
|
|
||||||
self.junction_delta = 2.0 * self.move_d * accel
|
|
||||||
def calc_junction(self, prev_move):
|
|
||||||
# Find max start junction velocity using approximated
|
|
||||||
# centripetal velocity as described at:
|
|
||||||
# https://onehossshay.wordpress.com/2011/09/24/improving_grbl_cornering_algorithm/
|
|
||||||
if not prev_move.move_d or self.relsteps[2] or prev_move.relsteps[2]:
|
|
||||||
return
|
|
||||||
steppers = self.kin.steppers
|
|
||||||
junction_cos_theta = -sum([
|
|
||||||
self.relsteps[i] * prev_move.relsteps[i] * steppers[i].step_dist**2
|
|
||||||
for i in range(2)]) / (self.move_d * prev_move.move_d)
|
|
||||||
if junction_cos_theta > 0.999999:
|
|
||||||
return
|
|
||||||
junction_cos_theta = max(junction_cos_theta, -0.999999)
|
|
||||||
sin_theta_d2 = math.sqrt(0.5*(1.0-junction_cos_theta));
|
|
||||||
R = self.kin.junction_deviation * sin_theta_d2 / (1.0 - sin_theta_d2)
|
|
||||||
accel = self.junction_delta / (2.0 * self.move_d)
|
|
||||||
self.junction_start_max = min(
|
|
||||||
accel * R, self.junction_max, prev_move.junction_max)
|
|
||||||
def process(self, junction_start, junction_end):
|
|
||||||
# Determine accel, cruise, and decel portions of the move
|
|
||||||
junction_cruise = self.junction_max
|
|
||||||
inv_junction_delta = 1. / self.junction_delta
|
|
||||||
accel_r = (junction_cruise-junction_start) * inv_junction_delta
|
|
||||||
decel_r = (junction_cruise-junction_end) * inv_junction_delta
|
|
||||||
cruise_r = 1. - accel_r - decel_r
|
|
||||||
if cruise_r < 0.:
|
|
||||||
accel_r += 0.5 * cruise_r
|
|
||||||
decel_r = 1.0 - accel_r
|
|
||||||
cruise_r = 0.
|
|
||||||
junction_cruise = junction_start + accel_r*self.junction_delta
|
|
||||||
# Determine the move velocities and time spent in each portion
|
|
||||||
start_v = math.sqrt(junction_start)
|
|
||||||
cruise_v = math.sqrt(junction_cruise)
|
|
||||||
end_v = math.sqrt(junction_end)
|
|
||||||
inv_cruise_v = 1. / cruise_v
|
|
||||||
inv_accel = 2.0 * self.move_d * inv_junction_delta
|
|
||||||
accel_t = 2.0 * self.move_d * accel_r / (start_v+cruise_v)
|
|
||||||
cruise_t = self.move_d * cruise_r * inv_cruise_v
|
|
||||||
decel_t = 2.0 * self.move_d * decel_r / (end_v+cruise_v)
|
|
||||||
|
|
||||||
#logging.debug("Move: %s v=%.2f/%.2f/%.2f mt=%.3f st=%.3f %.3f %.3f" % (
|
|
||||||
# self.relsteps, start_v, cruise_v, end_v, move_t
|
|
||||||
# , next_move_time, accel_r, cruise_r))
|
|
||||||
|
|
||||||
# Calculate step times for the move
|
|
||||||
next_move_time = self.kin.get_next_move_time()
|
|
||||||
for i in StepList:
|
|
||||||
steps = self.relsteps[i]
|
|
||||||
if not steps:
|
|
||||||
continue
|
|
||||||
sdir = 0
|
|
||||||
if steps < 0:
|
|
||||||
sdir = 1
|
|
||||||
steps = -steps
|
|
||||||
clock_offset, clock_freq, so = self.kin.steppers[i].prep_move(
|
|
||||||
sdir, next_move_time)
|
|
||||||
|
|
||||||
step_dist = self.move_d / steps
|
|
||||||
step_offset = 0.5
|
|
||||||
|
|
||||||
# Acceleration steps
|
|
||||||
#t = sqrt(2*pos/accel + (start_v/accel)**2) - start_v/accel
|
|
||||||
accel_clock_offset = start_v * inv_accel * clock_freq
|
|
||||||
accel_sqrt_offset = accel_clock_offset**2
|
|
||||||
accel_multiplier = 2.0 * step_dist * inv_accel * clock_freq**2
|
|
||||||
accel_steps = accel_r * steps
|
|
||||||
step_offset = so.step_sqrt(
|
|
||||||
accel_steps, step_offset, clock_offset - accel_clock_offset
|
|
||||||
, accel_sqrt_offset, accel_multiplier)
|
|
||||||
clock_offset += accel_t * clock_freq
|
|
||||||
# Cruising steps
|
|
||||||
#t = pos/cruise_v
|
|
||||||
cruise_multiplier = step_dist * inv_cruise_v * clock_freq
|
|
||||||
cruise_steps = cruise_r * steps
|
|
||||||
step_offset = so.step_factor(
|
|
||||||
cruise_steps, step_offset, clock_offset, cruise_multiplier)
|
|
||||||
clock_offset += cruise_t * clock_freq
|
|
||||||
# Deceleration steps
|
|
||||||
#t = cruise_v/accel - sqrt((cruise_v/accel)**2 - 2*pos/accel)
|
|
||||||
decel_clock_offset = cruise_v * inv_accel * clock_freq
|
|
||||||
decel_sqrt_offset = decel_clock_offset**2
|
|
||||||
decel_steps = decel_r * steps
|
|
||||||
so.step_sqrt(
|
|
||||||
decel_steps, step_offset, clock_offset + decel_clock_offset
|
|
||||||
, decel_sqrt_offset, -accel_multiplier)
|
|
||||||
self.kin.update_move_time(accel_t + cruise_t + decel_t)
|
|
||||||
|
|
||||||
STALL_TIME = 0.100
|
|
||||||
|
|
||||||
class CartKinematics:
|
class CartKinematics:
|
||||||
def __init__(self, printer, config):
|
def __init__(self, toolhead, printer, config):
|
||||||
self.printer = printer
|
self.printer = printer
|
||||||
self.reactor = printer.reactor
|
self.steppers = [stepper.LookupMultiHomingStepper(
|
||||||
steppers = ['stepper_x', 'stepper_y', 'stepper_z', 'stepper_e']
|
printer, config.getsection('stepper_' + n))
|
||||||
self.steppers = [stepper.PrinterStepper(printer, config.getsection(n))
|
for n in ['x', 'y', 'z']]
|
||||||
for n in steppers]
|
max_velocity, max_accel = toolhead.get_max_velocity()
|
||||||
self.max_accel = min(s.max_step_accel*s.step_dist
|
self.max_z_velocity = config.getfloat(
|
||||||
for s in self.steppers[:2]) # XXX
|
'max_z_velocity', max_velocity, above=0., maxval=max_velocity)
|
||||||
dummy_move = Move(self, [0]*len(self.steppers), 0.)
|
self.max_z_accel = config.getfloat(
|
||||||
dummy_move.junction_max = 0.
|
'max_z_accel', max_accel, above=0., maxval=max_accel)
|
||||||
self.junction_deviation = config.getfloat('junction_deviation', 0.02)
|
self.need_motor_enable = True
|
||||||
self.move_queue = lookahead.MoveQueue(dummy_move)
|
self.limits = [(1.0, -1.0)] * 3
|
||||||
self.pos = [0, 0, 0, 0]
|
# Setup stepper max halt velocity
|
||||||
# Print time tracking
|
max_halt_velocity = toolhead.get_max_axis_halt()
|
||||||
self.buffer_time_high = config.getfloat('buffer_time_high', 5.000)
|
self.steppers[0].set_max_jerk(max_halt_velocity, max_accel)
|
||||||
self.buffer_time_low = config.getfloat('buffer_time_low', 0.150)
|
self.steppers[1].set_max_jerk(max_halt_velocity, max_accel)
|
||||||
self.move_flush_time = config.getfloat('move_flush_time', 0.050)
|
self.steppers[2].set_max_jerk(
|
||||||
self.motor_off_delay = config.getfloat('motor_off_time', 60.000)
|
min(max_halt_velocity, self.max_z_velocity), max_accel)
|
||||||
self.print_time = 0.
|
# Check for dual carriage support
|
||||||
self.print_time_stall = 0
|
self.dual_carriage_axis = None
|
||||||
self.motor_off_time = self.reactor.NEVER
|
self.dual_carriage_steppers = []
|
||||||
self.flush_timer = self.reactor.register_timer(self.flush_handler)
|
if config.has_section('dual_carriage'):
|
||||||
def build_config(self):
|
dc_config = config.getsection('dual_carriage')
|
||||||
for stepper in self.steppers:
|
self.dual_carriage_axis = dc_config.getchoice(
|
||||||
stepper.build_config()
|
'axis', {'x': 0, 'y': 1})
|
||||||
# Print time tracking
|
dc_stepper = stepper.LookupMultiHomingStepper(printer, dc_config)
|
||||||
def update_move_time(self, movetime):
|
dc_stepper.set_max_jerk(max_halt_velocity, max_accel)
|
||||||
self.print_time += movetime
|
self.dual_carriage_steppers = [
|
||||||
flush_to_time = self.print_time - self.move_flush_time
|
self.steppers[self.dual_carriage_axis], dc_stepper]
|
||||||
self.printer.mcu.flush_moves(flush_to_time)
|
printer.lookup_object('gcode').register_command(
|
||||||
def get_next_move_time(self):
|
'SET_DUAL_CARRIAGE', self.cmd_SET_DUAL_CARRIAGE,
|
||||||
if not self.print_time:
|
desc=self.cmd_SET_DUAL_CARRIAGE_help)
|
||||||
self.print_time = self.buffer_time_low + STALL_TIME
|
def get_steppers(self, flags=""):
|
||||||
curtime = time.time()
|
if flags == "Z":
|
||||||
self.printer.mcu.set_print_start_time(curtime)
|
return [self.steppers[2]]
|
||||||
self.reactor.update_timer(self.flush_timer, self.reactor.NOW)
|
return list(self.steppers)
|
||||||
return self.print_time
|
|
||||||
def get_last_move_time(self):
|
|
||||||
self.move_queue.flush()
|
|
||||||
return self.get_next_move_time()
|
|
||||||
def reset_motor_off_time(self, eventtime):
|
|
||||||
self.motor_off_time = eventtime + self.motor_off_delay
|
|
||||||
def reset_print_time(self):
|
|
||||||
self.move_queue.flush()
|
|
||||||
self.printer.mcu.flush_moves(self.print_time)
|
|
||||||
self.print_time = 0.
|
|
||||||
self.reset_motor_off_time(time.time())
|
|
||||||
self.reactor.update_timer(self.flush_timer, self.motor_off_time)
|
|
||||||
def check_busy(self, eventtime):
|
|
||||||
if not self.print_time:
|
|
||||||
# XXX - find better way to flush initial move_queue items
|
|
||||||
if self.move_queue.queue:
|
|
||||||
self.reactor.update_timer(self.flush_timer, eventtime + 0.100)
|
|
||||||
return False
|
|
||||||
buffer_time = self.printer.mcu.get_print_buffer_time(
|
|
||||||
eventtime, self.print_time)
|
|
||||||
return buffer_time > self.buffer_time_high
|
|
||||||
def flush_handler(self, eventtime):
|
|
||||||
if not self.print_time:
|
|
||||||
self.move_queue.flush()
|
|
||||||
if not self.print_time:
|
|
||||||
if eventtime >= self.motor_off_time:
|
|
||||||
self.motor_off()
|
|
||||||
self.reset_print_time()
|
|
||||||
self.motor_off_time = self.reactor.NEVER
|
|
||||||
return self.motor_off_time
|
|
||||||
print_time = self.print_time
|
|
||||||
buffer_time = self.printer.mcu.get_print_buffer_time(
|
|
||||||
eventtime, print_time)
|
|
||||||
if buffer_time > self.buffer_time_low:
|
|
||||||
return eventtime + buffer_time - self.buffer_time_low
|
|
||||||
self.move_queue.flush()
|
|
||||||
if print_time != self.print_time:
|
|
||||||
self.print_time_stall += 1
|
|
||||||
self.dwell(self.buffer_time_low + STALL_TIME)
|
|
||||||
return self.reactor.NOW
|
|
||||||
self.reset_print_time()
|
|
||||||
return self.motor_off_time
|
|
||||||
def stats(self, eventtime):
|
|
||||||
buffer_time = 0.
|
|
||||||
if self.print_time:
|
|
||||||
buffer_time = self.printer.mcu.get_print_buffer_time(
|
|
||||||
eventtime, self.print_time)
|
|
||||||
return "print_time=%.3f buffer_time=%.3f print_time_stall=%d" % (
|
|
||||||
self.print_time, buffer_time, self.print_time_stall)
|
|
||||||
# Movement commands
|
|
||||||
def get_position(self):
|
def get_position(self):
|
||||||
return [self.pos[i] * self.steppers[i].step_dist
|
return [s.mcu_stepper.get_commanded_position() for s in self.steppers]
|
||||||
for i in StepList]
|
def set_position(self, newpos, homing_axes):
|
||||||
def set_position(self, newpos):
|
for i in StepList:
|
||||||
self.pos = [int(newpos[i]*self.steppers[i].inv_step_dist + 0.5)
|
s = self.steppers[i]
|
||||||
for i in StepList]
|
s.set_position(newpos[i])
|
||||||
def move(self, newpos, speed, sloppy=False):
|
if i in homing_axes:
|
||||||
# Round to closest step position
|
self.limits[i] = (s.position_min, s.position_max)
|
||||||
newpos = [int(newpos[i]*self.steppers[i].inv_step_dist + 0.5)
|
def _home_axis(self, homing_state, axis, stepper):
|
||||||
for i in StepList]
|
s = stepper
|
||||||
relsteps = [newpos[i] - self.pos[i] for i in StepList]
|
# Determine moves
|
||||||
self.pos = newpos
|
if s.homing_positive_dir:
|
||||||
if relsteps == [0]*len(newpos):
|
pos = s.position_endstop - 1.5*(
|
||||||
# no move
|
s.position_endstop - s.position_min)
|
||||||
return
|
rpos = s.position_endstop - s.homing_retract_dist
|
||||||
#logging.debug("; dist %s @ %d\n" % (
|
r2pos = rpos - s.homing_retract_dist
|
||||||
# [newpos[i]*self.steppers[i].step_dist for i in StepList], speed))
|
else:
|
||||||
# Create move and queue it
|
pos = s.position_endstop + 1.5*(
|
||||||
move = Move(self, relsteps, speed)
|
s.position_max - s.position_endstop)
|
||||||
move.calc_junction(self.move_queue.prev_move())
|
rpos = s.position_endstop + s.homing_retract_dist
|
||||||
self.move_queue.add_move(move)
|
r2pos = rpos + s.homing_retract_dist
|
||||||
def home(self, axis):
|
# Initial homing
|
||||||
|
homing_speed = s.homing_speed
|
||||||
|
if axis == 2:
|
||||||
|
homing_speed = min(homing_speed, self.max_z_velocity)
|
||||||
|
homepos = [None, None, None, None]
|
||||||
|
homepos[axis] = s.position_endstop
|
||||||
|
coord = [None, None, None, None]
|
||||||
|
coord[axis] = pos
|
||||||
|
homing_state.home(coord, homepos, s.get_endstops(), homing_speed)
|
||||||
|
# Retract
|
||||||
|
coord[axis] = rpos
|
||||||
|
homing_state.retract(coord, homing_speed)
|
||||||
|
# Home again
|
||||||
|
coord[axis] = r2pos
|
||||||
|
homing_state.home(coord, homepos, s.get_endstops(),
|
||||||
|
homing_speed/2.0, second_home=True)
|
||||||
|
# Set final homed position
|
||||||
|
coord[axis] = s.position_endstop + s.get_homed_offset()
|
||||||
|
homing_state.set_homed_position(coord)
|
||||||
|
def home(self, homing_state):
|
||||||
# Each axis is homed independently and in order
|
# Each axis is homed independently and in order
|
||||||
homing_state = homing.Homing(self, self.steppers)
|
for axis in homing_state.get_axes():
|
||||||
for a in axis:
|
if axis == self.dual_carriage_axis:
|
||||||
homing_state.plan_home(a)
|
dc1, dc2 = self.dual_carriage_steppers
|
||||||
return homing_state
|
altc = self.steppers[axis] == dc2
|
||||||
def dwell(self, delay):
|
self._activate_carriage(0)
|
||||||
self.get_last_move_time()
|
self._home_axis(homing_state, axis, dc1)
|
||||||
self.update_move_time(delay)
|
self._activate_carriage(1)
|
||||||
def motor_off(self):
|
self._home_axis(homing_state, axis, dc2)
|
||||||
self.dwell(STALL_TIME)
|
self._activate_carriage(altc)
|
||||||
last_move_time = self.get_last_move_time()
|
else:
|
||||||
|
self._home_axis(homing_state, axis, self.steppers[axis])
|
||||||
|
def motor_off(self, print_time):
|
||||||
|
self.limits = [(1.0, -1.0)] * 3
|
||||||
for stepper in self.steppers:
|
for stepper in self.steppers:
|
||||||
stepper.motor_enable(last_move_time, 0)
|
stepper.motor_enable(print_time, 0)
|
||||||
self.dwell(STALL_TIME)
|
for stepper in self.dual_carriage_steppers:
|
||||||
logging.debug('; Max time of %f' % (last_move_time,))
|
stepper.motor_enable(print_time, 0)
|
||||||
|
self.need_motor_enable = True
|
||||||
|
def _check_motor_enable(self, print_time, move):
|
||||||
|
need_motor_enable = False
|
||||||
|
for i in StepList:
|
||||||
|
if move.axes_d[i]:
|
||||||
|
self.steppers[i].motor_enable(print_time, 1)
|
||||||
|
need_motor_enable |= self.steppers[i].need_motor_enable
|
||||||
|
self.need_motor_enable = need_motor_enable
|
||||||
|
def _check_endstops(self, move):
|
||||||
|
end_pos = move.end_pos
|
||||||
|
for i in StepList:
|
||||||
|
if (move.axes_d[i]
|
||||||
|
and (end_pos[i] < self.limits[i][0]
|
||||||
|
or end_pos[i] > self.limits[i][1])):
|
||||||
|
if self.limits[i][0] > self.limits[i][1]:
|
||||||
|
raise homing.EndstopMoveError(
|
||||||
|
end_pos, "Must home axis first")
|
||||||
|
raise homing.EndstopMoveError(end_pos)
|
||||||
|
def check_move(self, move):
|
||||||
|
limits = self.limits
|
||||||
|
xpos, ypos = move.end_pos[:2]
|
||||||
|
if (xpos < limits[0][0] or xpos > limits[0][1]
|
||||||
|
or ypos < limits[1][0] or ypos > limits[1][1]):
|
||||||
|
self._check_endstops(move)
|
||||||
|
if not move.axes_d[2]:
|
||||||
|
# Normal XY move - use defaults
|
||||||
|
return
|
||||||
|
# Move with Z - update velocity and accel for slower Z axis
|
||||||
|
self._check_endstops(move)
|
||||||
|
z_ratio = move.move_d / abs(move.axes_d[2])
|
||||||
|
move.limit_speed(
|
||||||
|
self.max_z_velocity * z_ratio, self.max_z_accel * z_ratio)
|
||||||
|
def move(self, print_time, move):
|
||||||
|
if self.need_motor_enable:
|
||||||
|
self._check_motor_enable(print_time, move)
|
||||||
|
for i in StepList:
|
||||||
|
axis_d = move.axes_d[i]
|
||||||
|
if not axis_d:
|
||||||
|
continue
|
||||||
|
step_const = self.steppers[i].step_const
|
||||||
|
move_time = print_time
|
||||||
|
start_pos = move.start_pos[i]
|
||||||
|
axis_r = abs(axis_d) / move.move_d
|
||||||
|
accel = move.accel * axis_r
|
||||||
|
cruise_v = move.cruise_v * axis_r
|
||||||
|
|
||||||
|
# Acceleration steps
|
||||||
|
if move.accel_r:
|
||||||
|
accel_d = move.accel_r * axis_d
|
||||||
|
step_const(move_time, start_pos, accel_d,
|
||||||
|
move.start_v * axis_r, accel)
|
||||||
|
start_pos += accel_d
|
||||||
|
move_time += move.accel_t
|
||||||
|
# Cruising steps
|
||||||
|
if move.cruise_r:
|
||||||
|
cruise_d = move.cruise_r * axis_d
|
||||||
|
step_const(move_time, start_pos, cruise_d, cruise_v, 0.)
|
||||||
|
start_pos += cruise_d
|
||||||
|
move_time += move.cruise_t
|
||||||
|
# Deceleration steps
|
||||||
|
if move.decel_r:
|
||||||
|
decel_d = move.decel_r * axis_d
|
||||||
|
step_const(move_time, start_pos, decel_d, cruise_v, -accel)
|
||||||
|
# Dual carriage support
|
||||||
|
def _activate_carriage(self, carriage):
|
||||||
|
toolhead = self.printer.lookup_object('toolhead')
|
||||||
|
toolhead.get_last_move_time()
|
||||||
|
dc_stepper = self.dual_carriage_steppers[carriage]
|
||||||
|
dc_axis = self.dual_carriage_axis
|
||||||
|
self.steppers[dc_axis] = dc_stepper
|
||||||
|
extruder_pos = toolhead.get_position()[3]
|
||||||
|
toolhead.set_position(self.get_position() + [extruder_pos])
|
||||||
|
if self.limits[dc_axis][0] <= self.limits[dc_axis][1]:
|
||||||
|
self.limits[dc_axis] = (
|
||||||
|
dc_stepper.position_min, dc_stepper.position_max)
|
||||||
|
self.need_motor_enable = True
|
||||||
|
cmd_SET_DUAL_CARRIAGE_help = "Set which carriage is active"
|
||||||
|
def cmd_SET_DUAL_CARRIAGE(self, params):
|
||||||
|
gcode = self.printer.lookup_object('gcode')
|
||||||
|
carriage = gcode.get_int('CARRIAGE', params)
|
||||||
|
if carriage not in (0, 1):
|
||||||
|
raise gcode.error("Invalid carriage")
|
||||||
|
self._activate_carriage(carriage)
|
||||||
|
gcode.reset_last_position()
|
||||||
|
|||||||
@@ -1,34 +1,44 @@
|
|||||||
# Wrapper around C helper code
|
# Wrapper around C helper code
|
||||||
#
|
#
|
||||||
# Copyright (C) 2016 Kevin O'Connor <kevin@koconnor.net>
|
# Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||||
#
|
#
|
||||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
import os, logging
|
import os, logging
|
||||||
import cffi
|
import cffi
|
||||||
|
|
||||||
COMPILE_CMD = "gcc -Wall -g -O -shared -fPIC -o %s %s"
|
|
||||||
SOURCE_FILES = ['stepcompress.c', 'serialqueue.c']
|
######################################################################
|
||||||
|
# c_helper.so compiling
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
COMPILE_CMD = "gcc -Wall -g -O2 -shared -fPIC -o %s %s"
|
||||||
|
SOURCE_FILES = ['stepcompress.c', 'serialqueue.c', 'pyhelper.c']
|
||||||
DEST_LIB = "c_helper.so"
|
DEST_LIB = "c_helper.so"
|
||||||
OTHER_FILES = ['list.h', 'serialqueue.h']
|
OTHER_FILES = ['list.h', 'serialqueue.h', 'pyhelper.h']
|
||||||
|
|
||||||
defs_stepcompress = """
|
defs_stepcompress = """
|
||||||
struct stepcompress *stepcompress_alloc(uint32_t max_error
|
struct stepcompress *stepcompress_alloc(uint32_t max_error
|
||||||
, uint32_t queue_step_msgid, uint32_t oid);
|
, uint32_t queue_step_msgid, uint32_t set_next_step_dir_msgid
|
||||||
void stepcompress_push(struct stepcompress *sc, double step_clock);
|
, uint32_t invert_sdir, uint32_t oid);
|
||||||
double stepcompress_push_factor(struct stepcompress *sc
|
void stepcompress_free(struct stepcompress *sc);
|
||||||
, double steps, double step_offset
|
int stepcompress_reset(struct stepcompress *sc, uint64_t last_step_clock);
|
||||||
, double clock_offset, double factor);
|
int stepcompress_set_homing(struct stepcompress *sc, uint64_t homing_clock);
|
||||||
double stepcompress_push_sqrt(struct stepcompress *sc
|
int stepcompress_queue_msg(struct stepcompress *sc, uint32_t *data, int len);
|
||||||
, double steps, double step_offset
|
|
||||||
, double clock_offset, double sqrt_offset, double factor);
|
int32_t stepcompress_push(struct stepcompress *sc, double step_clock
|
||||||
void stepcompress_reset(struct stepcompress *sc, uint64_t last_step_clock);
|
, int32_t sdir);
|
||||||
void stepcompress_queue_msg(struct stepcompress *sc
|
int32_t stepcompress_push_const(struct stepcompress *sc, double clock_offset
|
||||||
, uint32_t *data, int len);
|
, double step_offset, double steps, double start_sv, double accel);
|
||||||
uint32_t stepcompress_get_errors(struct stepcompress *sc);
|
int32_t stepcompress_push_delta(struct stepcompress *sc
|
||||||
|
, double clock_offset, double move_sd, double start_sv, double accel
|
||||||
|
, double height, double startxy_sd, double arm_d, double movez_r);
|
||||||
|
|
||||||
struct steppersync *steppersync_alloc(struct serialqueue *sq
|
struct steppersync *steppersync_alloc(struct serialqueue *sq
|
||||||
, struct stepcompress **sc_list, int sc_num, int move_num);
|
, struct stepcompress **sc_list, int sc_num, int move_num);
|
||||||
void steppersync_flush(struct steppersync *ss, uint64_t move_clock);
|
void steppersync_free(struct steppersync *ss);
|
||||||
|
void steppersync_set_time(struct steppersync *ss
|
||||||
|
, double time_offset, double mcu_freq);
|
||||||
|
int steppersync_flush(struct steppersync *ss, uint64_t move_clock);
|
||||||
"""
|
"""
|
||||||
|
|
||||||
defs_serialqueue = """
|
defs_serialqueue = """
|
||||||
@@ -39,24 +49,30 @@ defs_serialqueue = """
|
|||||||
double sent_time, receive_time;
|
double sent_time, receive_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct serialqueue *serialqueue_alloc(int serial_fd, double baud_adjust
|
struct serialqueue *serialqueue_alloc(int serial_fd, int write_only);
|
||||||
, int write_only);
|
|
||||||
void serialqueue_exit(struct serialqueue *sq);
|
void serialqueue_exit(struct serialqueue *sq);
|
||||||
|
void serialqueue_free(struct serialqueue *sq);
|
||||||
struct command_queue *serialqueue_alloc_commandqueue(void);
|
struct command_queue *serialqueue_alloc_commandqueue(void);
|
||||||
|
void serialqueue_free_commandqueue(struct command_queue *cq);
|
||||||
void serialqueue_send(struct serialqueue *sq, struct command_queue *cq
|
void serialqueue_send(struct serialqueue *sq, struct command_queue *cq
|
||||||
, uint8_t *msg, int len, uint64_t min_clock, uint64_t req_clock);
|
, uint8_t *msg, int len, uint64_t min_clock, uint64_t req_clock);
|
||||||
void serialqueue_encode_and_send(struct serialqueue *sq
|
void serialqueue_encode_and_send(struct serialqueue *sq
|
||||||
, struct command_queue *cq, uint32_t *data, int len
|
, struct command_queue *cq, uint32_t *data, int len
|
||||||
, uint64_t min_clock, uint64_t req_clock);
|
, uint64_t min_clock, uint64_t req_clock);
|
||||||
void serialqueue_pull(struct serialqueue *sq, struct pull_queue_message *pqm);
|
void serialqueue_pull(struct serialqueue *sq, struct pull_queue_message *pqm);
|
||||||
void serialqueue_set_clock_est(struct serialqueue *sq, double est_clock
|
void serialqueue_set_baud_adjust(struct serialqueue *sq, double baud_adjust);
|
||||||
, double last_ack_time, uint64_t last_ack_clock);
|
void serialqueue_set_clock_est(struct serialqueue *sq, double est_freq
|
||||||
void serialqueue_flush_ready(struct serialqueue *sq);
|
, double last_clock_time, uint64_t last_clock);
|
||||||
void serialqueue_get_stats(struct serialqueue *sq, char *buf, int len);
|
void serialqueue_get_stats(struct serialqueue *sq, char *buf, int len);
|
||||||
int serialqueue_extract_old(struct serialqueue *sq, int sentq
|
int serialqueue_extract_old(struct serialqueue *sq, int sentq
|
||||||
, struct pull_queue_message *q, int max);
|
, struct pull_queue_message *q, int max);
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
defs_pyhelper = """
|
||||||
|
void set_python_logging_callback(void (*func)(const char *));
|
||||||
|
double get_monotonic(void);
|
||||||
|
"""
|
||||||
|
|
||||||
# Return the list of file modification times
|
# Return the list of file modification times
|
||||||
def get_mtimes(srcdir, filelist):
|
def get_mtimes(srcdir, filelist):
|
||||||
out = []
|
out = []
|
||||||
@@ -70,26 +86,52 @@ def get_mtimes(srcdir, filelist):
|
|||||||
return out
|
return out
|
||||||
|
|
||||||
# Check if the code needs to be compiled
|
# Check if the code needs to be compiled
|
||||||
def check_build_code(srcdir):
|
def check_build_code(srcdir, target, sources, cmd, other_files=[]):
|
||||||
src_times = get_mtimes(srcdir, SOURCE_FILES + OTHER_FILES)
|
src_times = get_mtimes(srcdir, sources + other_files)
|
||||||
obj_times = get_mtimes(srcdir, [DEST_LIB])
|
obj_times = get_mtimes(srcdir, [target])
|
||||||
if not obj_times or max(src_times) > min(obj_times):
|
if not obj_times or max(src_times) > min(obj_times):
|
||||||
logging.info("Building C code module")
|
logging.info("Building C code module %s", target)
|
||||||
srcfiles = [os.path.join(srcdir, fname) for fname in SOURCE_FILES]
|
srcfiles = [os.path.join(srcdir, fname) for fname in sources]
|
||||||
destlib = os.path.join(srcdir, DEST_LIB)
|
destlib = os.path.join(srcdir, target)
|
||||||
os.system(COMPILE_CMD % (destlib, ' '.join(srcfiles)))
|
os.system(cmd % (destlib, ' '.join(srcfiles)))
|
||||||
|
|
||||||
FFI_main = None
|
FFI_main = None
|
||||||
FFI_lib = None
|
FFI_lib = None
|
||||||
|
pyhelper_logging_callback = None
|
||||||
|
|
||||||
# Return the Foreign Function Interface api to the caller
|
# Return the Foreign Function Interface api to the caller
|
||||||
def get_ffi():
|
def get_ffi():
|
||||||
global FFI_main, FFI_lib
|
global FFI_main, FFI_lib, pyhelper_logging_callback
|
||||||
if FFI_lib is None:
|
if FFI_lib is None:
|
||||||
srcdir = os.path.dirname(os.path.realpath(__file__))
|
srcdir = os.path.dirname(os.path.realpath(__file__))
|
||||||
check_build_code(srcdir)
|
check_build_code(srcdir, DEST_LIB, SOURCE_FILES, COMPILE_CMD
|
||||||
|
, OTHER_FILES)
|
||||||
FFI_main = cffi.FFI()
|
FFI_main = cffi.FFI()
|
||||||
FFI_main.cdef(defs_stepcompress)
|
FFI_main.cdef(defs_stepcompress)
|
||||||
FFI_main.cdef(defs_serialqueue)
|
FFI_main.cdef(defs_serialqueue)
|
||||||
|
FFI_main.cdef(defs_pyhelper)
|
||||||
FFI_lib = FFI_main.dlopen(os.path.join(srcdir, DEST_LIB))
|
FFI_lib = FFI_main.dlopen(os.path.join(srcdir, DEST_LIB))
|
||||||
|
# Setup error logging
|
||||||
|
def logging_callback(msg):
|
||||||
|
logging.error(FFI_main.string(msg))
|
||||||
|
pyhelper_logging_callback = FFI_main.callback(
|
||||||
|
"void(const char *)", logging_callback)
|
||||||
|
FFI_lib.set_python_logging_callback(pyhelper_logging_callback)
|
||||||
return FFI_main, FFI_lib
|
return FFI_main, FFI_lib
|
||||||
|
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# hub-ctrl hub power controller
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
HC_COMPILE_CMD = "gcc -Wall -g -O2 -o %s %s -lusb"
|
||||||
|
HC_SOURCE_FILES = ['hub-ctrl.c']
|
||||||
|
HC_SOURCE_DIR = '../lib/hub-ctrl'
|
||||||
|
HC_TARGET = "hub-ctrl"
|
||||||
|
HC_CMD = "sudo %s/hub-ctrl -h 0 -P 2 -p %d"
|
||||||
|
|
||||||
|
def run_hub_ctrl(enable_power):
|
||||||
|
srcdir = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
hubdir = os.path.join(srcdir, HC_SOURCE_DIR)
|
||||||
|
check_build_code(hubdir, HC_TARGET, HC_SOURCE_FILES, HC_COMPILE_CMD)
|
||||||
|
os.system(HC_CMD % (hubdir, enable_power))
|
||||||
|
|||||||
219
klippy/clocksync.py
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
# Micro-controller clock synchronization
|
||||||
|
#
|
||||||
|
# Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
#
|
||||||
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
import logging, threading, math
|
||||||
|
|
||||||
|
COMM_TIMEOUT = 3.5
|
||||||
|
RTT_AGE = .000010 / (60. * 60.)
|
||||||
|
DECAY = 1. / 30.
|
||||||
|
TRANSMIT_EXTRA = .001
|
||||||
|
|
||||||
|
class ClockSync:
|
||||||
|
def __init__(self, reactor):
|
||||||
|
self.reactor = reactor
|
||||||
|
self.serial = None
|
||||||
|
self.status_timer = self.reactor.register_timer(self._status_event)
|
||||||
|
self.status_cmd = None
|
||||||
|
self.mcu_freq = 1.
|
||||||
|
self.last_clock = 0
|
||||||
|
self.clock_est = (0., 0., 0.)
|
||||||
|
# Minimum round-trip-time tracking
|
||||||
|
self.min_half_rtt = 999999999.9
|
||||||
|
self.min_rtt_time = 0.
|
||||||
|
# Linear regression of mcu clock and system sent_time
|
||||||
|
self.time_avg = self.time_variance = 0.
|
||||||
|
self.clock_avg = self.clock_covariance = 0.
|
||||||
|
self.prediction_variance = 0.
|
||||||
|
self.last_prediction_time = 0.
|
||||||
|
def connect(self, serial):
|
||||||
|
self.serial = serial
|
||||||
|
self.mcu_freq = serial.msgparser.get_constant_float('CLOCK_FREQ')
|
||||||
|
# Load initial clock and frequency
|
||||||
|
get_uptime_cmd = serial.lookup_command('get_uptime')
|
||||||
|
params = get_uptime_cmd.send_with_response(response='uptime')
|
||||||
|
self.last_clock = (params['high'] << 32) | params['clock']
|
||||||
|
self.clock_avg = self.last_clock
|
||||||
|
self.time_avg = params['#sent_time']
|
||||||
|
self.clock_est = (self.time_avg, self.clock_avg, self.mcu_freq)
|
||||||
|
self.prediction_variance = (.001 * self.mcu_freq)**2
|
||||||
|
# Enable periodic get_status timer
|
||||||
|
self.status_cmd = serial.lookup_command('get_status')
|
||||||
|
for i in range(8):
|
||||||
|
params = self.status_cmd.send_with_response(response='status')
|
||||||
|
self._handle_status(params)
|
||||||
|
self.reactor.pause(0.100)
|
||||||
|
serial.register_callback(self._handle_status, 'status')
|
||||||
|
self.reactor.update_timer(self.status_timer, self.reactor.NOW)
|
||||||
|
def connect_file(self, serial, pace=False):
|
||||||
|
self.serial = serial
|
||||||
|
self.mcu_freq = serial.msgparser.get_constant_float('CLOCK_FREQ')
|
||||||
|
self.clock_est = (0., 0., self.mcu_freq)
|
||||||
|
freq = 1000000000000.
|
||||||
|
if pace:
|
||||||
|
freq = self.mcu_freq
|
||||||
|
serial.set_clock_est(freq, self.reactor.monotonic(), 0)
|
||||||
|
# MCU clock querying (status callback invoked from background thread)
|
||||||
|
def _status_event(self, eventtime):
|
||||||
|
self.status_cmd.send()
|
||||||
|
return eventtime + 1.0
|
||||||
|
def _handle_status(self, params):
|
||||||
|
# Extend clock to 64bit
|
||||||
|
last_clock = self.last_clock
|
||||||
|
clock = (last_clock & ~0xffffffff) | params['clock']
|
||||||
|
if clock < last_clock:
|
||||||
|
clock += 0x100000000
|
||||||
|
self.last_clock = clock
|
||||||
|
# Check if this is the best round-trip-time seen so far
|
||||||
|
sent_time = params['#sent_time']
|
||||||
|
if not sent_time:
|
||||||
|
return
|
||||||
|
receive_time = params['#receive_time']
|
||||||
|
half_rtt = .5 * (receive_time - sent_time)
|
||||||
|
aged_rtt = (sent_time - self.min_rtt_time) * RTT_AGE
|
||||||
|
if half_rtt < self.min_half_rtt + aged_rtt:
|
||||||
|
self.min_half_rtt = half_rtt
|
||||||
|
self.min_rtt_time = sent_time
|
||||||
|
logging.debug("new minimum rtt %.3f: hrtt=%.6f freq=%d",
|
||||||
|
sent_time, half_rtt, self.clock_est[2])
|
||||||
|
# Filter out samples that are extreme outliers
|
||||||
|
exp_clock = ((sent_time - self.time_avg) * self.clock_est[2]
|
||||||
|
+ self.clock_avg)
|
||||||
|
clock_diff2 = (clock - exp_clock)**2
|
||||||
|
if (clock_diff2 > 25. * self.prediction_variance
|
||||||
|
and clock_diff2 > (.000500 * self.mcu_freq)**2):
|
||||||
|
if clock > exp_clock and sent_time < self.last_prediction_time + 10.:
|
||||||
|
logging.debug("Ignoring clock sample %.3f:"
|
||||||
|
" freq=%d diff=%d stddev=%.3f",
|
||||||
|
sent_time, self.clock_est[2], clock - exp_clock,
|
||||||
|
math.sqrt(self.prediction_variance))
|
||||||
|
return
|
||||||
|
logging.info("Resetting prediction variance %.3f:"
|
||||||
|
" freq=%d diff=%d stddev=%.3f",
|
||||||
|
sent_time, self.clock_est[2], clock - exp_clock,
|
||||||
|
math.sqrt(self.prediction_variance))
|
||||||
|
self.prediction_variance = (.001 * self.mcu_freq)**2
|
||||||
|
else:
|
||||||
|
self.last_prediction_time = sent_time
|
||||||
|
self.prediction_variance = (
|
||||||
|
(1. - DECAY) * (self.prediction_variance + clock_diff2 * DECAY))
|
||||||
|
# Add clock and sent_time to linear regression
|
||||||
|
diff_sent_time = sent_time - self.time_avg
|
||||||
|
self.time_avg += DECAY * diff_sent_time
|
||||||
|
self.time_variance = (1. - DECAY) * (
|
||||||
|
self.time_variance + diff_sent_time**2 * DECAY)
|
||||||
|
diff_clock = clock - self.clock_avg
|
||||||
|
self.clock_avg += DECAY * diff_clock
|
||||||
|
self.clock_covariance = (1. - DECAY) * (
|
||||||
|
self.clock_covariance + diff_sent_time * diff_clock * DECAY)
|
||||||
|
# Update prediction from linear regression
|
||||||
|
new_freq = self.clock_covariance / self.time_variance
|
||||||
|
pred_stddev = math.sqrt(self.prediction_variance)
|
||||||
|
self.serial.set_clock_est(new_freq, self.time_avg + TRANSMIT_EXTRA,
|
||||||
|
int(self.clock_avg - 3. * pred_stddev))
|
||||||
|
self.clock_est = (self.time_avg + self.min_half_rtt,
|
||||||
|
self.clock_avg, new_freq)
|
||||||
|
#logging.debug("regr %.3f: freq=%.3f d=%d(%.3f)",
|
||||||
|
# sent_time, new_freq, clock - exp_clock, pred_stddev)
|
||||||
|
# clock frequency conversions
|
||||||
|
def print_time_to_clock(self, print_time):
|
||||||
|
return int(print_time * self.mcu_freq)
|
||||||
|
def clock_to_print_time(self, clock):
|
||||||
|
return clock / self.mcu_freq
|
||||||
|
def get_adjusted_freq(self):
|
||||||
|
return self.mcu_freq
|
||||||
|
# system time conversions
|
||||||
|
def get_clock(self, eventtime):
|
||||||
|
sample_time, clock, freq = self.clock_est
|
||||||
|
return int(clock + (eventtime - sample_time) * freq)
|
||||||
|
def estimated_print_time(self, eventtime):
|
||||||
|
return self.clock_to_print_time(self.get_clock(eventtime))
|
||||||
|
# misc commands
|
||||||
|
def clock32_to_clock64(self, clock32):
|
||||||
|
last_clock = self.last_clock
|
||||||
|
clock_diff = (last_clock - clock32) & 0xffffffff
|
||||||
|
if clock_diff & 0x80000000:
|
||||||
|
return last_clock + 0x100000000 - clock_diff
|
||||||
|
return last_clock - clock_diff
|
||||||
|
def is_active(self, eventtime):
|
||||||
|
print_time = self.estimated_print_time(eventtime)
|
||||||
|
last_clock_print_time = self.clock_to_print_time(self.last_clock)
|
||||||
|
return print_time < last_clock_print_time + COMM_TIMEOUT
|
||||||
|
def dump_debug(self):
|
||||||
|
sample_time, clock, freq = self.clock_est
|
||||||
|
return ("clocksync state: mcu_freq=%d last_clock=%d"
|
||||||
|
" clock_est=(%.3f %d %.3f) min_half_rtt=%.6f min_rtt_time=%.3f"
|
||||||
|
" time_avg=%.3f(%.3f) clock_avg=%.3f(%.3f)"
|
||||||
|
" pred_variance=%.3f" % (
|
||||||
|
self.mcu_freq, self.last_clock, sample_time, clock, freq,
|
||||||
|
self.min_half_rtt, self.min_rtt_time,
|
||||||
|
self.time_avg, self.time_variance,
|
||||||
|
self.clock_avg, self.clock_covariance,
|
||||||
|
self.prediction_variance))
|
||||||
|
def stats(self, eventtime):
|
||||||
|
sample_time, clock, freq = self.clock_est
|
||||||
|
return "freq=%d" % (freq,)
|
||||||
|
def calibrate_clock(self, print_time, eventtime):
|
||||||
|
return (0., self.mcu_freq)
|
||||||
|
|
||||||
|
# Clock syncing code for secondary MCUs (whose clocks are sync'ed to a
|
||||||
|
# primary MCU)
|
||||||
|
class SecondarySync(ClockSync):
|
||||||
|
def __init__(self, reactor, main_sync):
|
||||||
|
ClockSync.__init__(self, reactor)
|
||||||
|
self.main_sync = main_sync
|
||||||
|
self.clock_adj = (0., 1.)
|
||||||
|
self.last_sync_time = 0.
|
||||||
|
def connect(self, serial):
|
||||||
|
ClockSync.connect(self, serial)
|
||||||
|
self.clock_adj = (0., self.mcu_freq)
|
||||||
|
curtime = self.reactor.monotonic()
|
||||||
|
main_print_time = self.main_sync.estimated_print_time(curtime)
|
||||||
|
local_print_time = self.estimated_print_time(curtime)
|
||||||
|
self.clock_adj = (main_print_time - local_print_time, self.mcu_freq)
|
||||||
|
self.calibrate_clock(0., curtime)
|
||||||
|
def connect_file(self, serial, pace=False):
|
||||||
|
ClockSync.connect_file(self, serial, pace)
|
||||||
|
self.clock_adj = (0., self.mcu_freq)
|
||||||
|
# clock frequency conversions
|
||||||
|
def print_time_to_clock(self, print_time):
|
||||||
|
adjusted_offset, adjusted_freq = self.clock_adj
|
||||||
|
return int((print_time - adjusted_offset) * adjusted_freq)
|
||||||
|
def clock_to_print_time(self, clock):
|
||||||
|
adjusted_offset, adjusted_freq = self.clock_adj
|
||||||
|
return clock / adjusted_freq + adjusted_offset
|
||||||
|
def get_adjusted_freq(self):
|
||||||
|
adjusted_offset, adjusted_freq = self.clock_adj
|
||||||
|
return adjusted_freq
|
||||||
|
# misc commands
|
||||||
|
def dump_debug(self):
|
||||||
|
adjusted_offset, adjusted_freq = self.clock_adj
|
||||||
|
return "%s clock_adj=(%.3f %.3f)" % (
|
||||||
|
ClockSync.dump_debug(self), adjusted_offset, adjusted_freq)
|
||||||
|
def stats(self, eventtime):
|
||||||
|
adjusted_offset, adjusted_freq = self.clock_adj
|
||||||
|
return "%s adj=%d" % (ClockSync.stats(self, eventtime), adjusted_freq)
|
||||||
|
def calibrate_clock(self, print_time, eventtime):
|
||||||
|
# Calculate: est_print_time = main_sync.estimatated_print_time()
|
||||||
|
ser_time, ser_clock, ser_freq = self.main_sync.clock_est
|
||||||
|
main_mcu_freq = self.main_sync.mcu_freq
|
||||||
|
est_main_clock = (eventtime - ser_time) * ser_freq + ser_clock
|
||||||
|
est_print_time = est_main_clock / main_mcu_freq
|
||||||
|
# Determine sync1_print_time and sync2_print_time
|
||||||
|
sync1_print_time = max(print_time, est_print_time)
|
||||||
|
sync2_print_time = max(sync1_print_time + 4., self.last_sync_time,
|
||||||
|
print_time + 2.5 * (print_time - est_print_time))
|
||||||
|
# Calc sync2_sys_time (inverse of main_sync.estimatated_print_time)
|
||||||
|
sync2_main_clock = sync2_print_time * main_mcu_freq
|
||||||
|
sync2_sys_time = ser_time + (sync2_main_clock - ser_clock) / ser_freq
|
||||||
|
# Adjust freq so estimated print_time will match at sync2_print_time
|
||||||
|
sync1_clock = self.print_time_to_clock(sync1_print_time)
|
||||||
|
sync2_clock = self.get_clock(sync2_sys_time)
|
||||||
|
adjusted_freq = ((sync2_clock - sync1_clock)
|
||||||
|
/ (sync2_print_time - sync1_print_time))
|
||||||
|
adjusted_offset = sync1_print_time - sync1_clock / adjusted_freq
|
||||||
|
# Apply new values
|
||||||
|
self.clock_adj = (adjusted_offset, adjusted_freq)
|
||||||
|
self.last_sync_time = sync2_print_time
|
||||||
|
return self.clock_adj
|
||||||
@@ -1,12 +1,31 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python2
|
||||||
# Script to implement a test console with firmware over serial port
|
# Script to implement a test console with firmware over serial port
|
||||||
#
|
#
|
||||||
# Copyright (C) 2016 Kevin O'Connor <kevin@koconnor.net>
|
# Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||||
#
|
#
|
||||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
import sys, optparse, os, re, logging
|
import sys, optparse, os, re, logging
|
||||||
|
import reactor, serialhdl, pins, util, msgproto, clocksync
|
||||||
|
|
||||||
import reactor, serialhdl, pins, util, msgproto
|
help_txt = """
|
||||||
|
This is a debugging console for the Klipper micro-controller.
|
||||||
|
In addition to mcu commands, the following artificial commands are
|
||||||
|
available:
|
||||||
|
PINS : Load pin name aliases (eg, "PINS arduino")
|
||||||
|
DELAY : Send a command at a clock time (eg, "DELAY 9999 get_uptime")
|
||||||
|
FLOOD : Send a command many times (eg, "FLOOD 22 .01 get_uptime")
|
||||||
|
SUPPRESS : Suppress a response message (eg, "SUPPRESS stats")
|
||||||
|
SET : Create a local variable (eg, "SET myvar 123.4")
|
||||||
|
STATS : Report serial statistics
|
||||||
|
LIST : List available mcu commands, local commands, and local variables
|
||||||
|
HELP : Show this text
|
||||||
|
All commands also support evaluation by enclosing an expression in { }.
|
||||||
|
For example, "reset_step_clock oid=4 clock={clock + freq}". In addition
|
||||||
|
to user defined variables (via the SET command) the following builtin
|
||||||
|
variables may be used in expressions:
|
||||||
|
clock : The current mcu clock time (as estimated by the host)
|
||||||
|
freq : The mcu clock frequency
|
||||||
|
"""
|
||||||
|
|
||||||
re_eval = re.compile(r'\{(?P<eval>[^}]*)\}')
|
re_eval = re.compile(r'\{(?P<eval>[^}]*)\}')
|
||||||
|
|
||||||
@@ -14,56 +33,137 @@ class KeyboardReader:
|
|||||||
def __init__(self, ser, reactor):
|
def __init__(self, ser, reactor):
|
||||||
self.ser = ser
|
self.ser = ser
|
||||||
self.reactor = reactor
|
self.reactor = reactor
|
||||||
|
self.clocksync = clocksync.ClockSync(self.reactor)
|
||||||
self.fd = sys.stdin.fileno()
|
self.fd = sys.stdin.fileno()
|
||||||
util.set_nonblock(self.fd)
|
util.set_nonblock(self.fd)
|
||||||
|
self.mcu_freq = 0
|
||||||
self.pins = None
|
self.pins = None
|
||||||
self.data = ""
|
self.data = ""
|
||||||
self.reactor.register_fd(self.fd, self.process_kbd)
|
reactor.register_fd(self.fd, self.process_kbd)
|
||||||
self.local_commands = { "PINS": self.set_pin_map }
|
self.connect_timer = reactor.register_timer(self.connect, reactor.NOW)
|
||||||
|
self.local_commands = {
|
||||||
|
"PINS": self.command_PINS, "SET": self.command_SET,
|
||||||
|
"DELAY": self.command_DELAY, "FLOOD": self.command_FLOOD,
|
||||||
|
"SUPPRESS": self.command_SUPPRESS, "STATS": self.command_STATS,
|
||||||
|
"LIST": self.command_LIST, "HELP": self.command_HELP,
|
||||||
|
}
|
||||||
self.eval_globals = {}
|
self.eval_globals = {}
|
||||||
|
def connect(self, eventtime):
|
||||||
|
self.output(help_txt)
|
||||||
|
self.output("="*20 + " attempting to connect " + "="*20)
|
||||||
|
self.ser.connect()
|
||||||
|
self.clocksync.connect(self.ser)
|
||||||
|
self.ser.handle_default = self.handle_default
|
||||||
|
self.mcu_freq = self.ser.msgparser.get_constant_float('CLOCK_FREQ')
|
||||||
|
mcu_type = self.ser.msgparser.get_constant('MCU')
|
||||||
|
self.pins = pins.PinResolver(mcu_type, validate_aliases=False)
|
||||||
|
self.reactor.unregister_timer(self.connect_timer)
|
||||||
|
self.output("="*20 + " connected " + "="*20)
|
||||||
|
return self.reactor.NEVER
|
||||||
|
def output(self, msg):
|
||||||
|
sys.stdout.write("%s\n" % (msg,))
|
||||||
|
sys.stdout.flush()
|
||||||
|
def handle_default(self, params):
|
||||||
|
self.output(self.ser.msgparser.format_params(params))
|
||||||
|
def handle_suppress(self, params):
|
||||||
|
pass
|
||||||
def update_evals(self, eventtime):
|
def update_evals(self, eventtime):
|
||||||
f = self.ser.msgparser.config.get('CLOCK_FREQ', 1)
|
self.eval_globals['freq'] = self.mcu_freq
|
||||||
c = (eventtime - self.ser.last_ack_time) * f + self.ser.last_ack_clock
|
self.eval_globals['clock'] = self.clocksync.get_clock(eventtime)
|
||||||
self.eval_globals['freq'] = f
|
def command_PINS(self, parts):
|
||||||
self.eval_globals['clock'] = int(c)
|
self.pins.update_aliases(parts[1])
|
||||||
def set_pin_map(self, parts):
|
def command_SET(self, parts):
|
||||||
mcu = self.ser.msgparser.config['MCU']
|
val = parts[2]
|
||||||
self.pins = pins.map_pins(parts[1], mcu)
|
try:
|
||||||
def lookup_pin(self, value):
|
val = float(val)
|
||||||
if self.pins is None:
|
except ValueError:
|
||||||
self.pins = pins.mcu_to_pins(self.ser.msgparser.config['MCU'])
|
pass
|
||||||
return self.pins[value]
|
self.eval_globals[parts[1]] = val
|
||||||
|
def command_DELAY(self, parts):
|
||||||
|
try:
|
||||||
|
val = int(parts[1])
|
||||||
|
except ValueError as e:
|
||||||
|
self.output("Error: %s" % (str(e),))
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
self.ser.send(' '.join(parts[2:]), minclock=val)
|
||||||
|
except msgproto.error as e:
|
||||||
|
self.output("Error: %s" % (str(e),))
|
||||||
|
return
|
||||||
|
def command_FLOOD(self, parts):
|
||||||
|
try:
|
||||||
|
count = int(parts[1])
|
||||||
|
delay = float(parts[2])
|
||||||
|
except ValueError as e:
|
||||||
|
self.output("Error: %s" % (str(e),))
|
||||||
|
return
|
||||||
|
msg = ' '.join(parts[3:])
|
||||||
|
delay_clock = int(delay * self.mcu_freq)
|
||||||
|
msg_clock = int(self.clocksync.get_clock(self.reactor.monotonic())
|
||||||
|
+ self.mcu_freq * .200)
|
||||||
|
try:
|
||||||
|
for i in range(count):
|
||||||
|
next_clock = msg_clock + delay_clock
|
||||||
|
self.ser.send(msg, minclock=msg_clock, reqclock=next_clock)
|
||||||
|
msg_clock = next_clock
|
||||||
|
except msgproto.error as e:
|
||||||
|
self.output("Error: %s" % (str(e),))
|
||||||
|
return
|
||||||
|
def command_SUPPRESS(self, parts):
|
||||||
|
oid = None
|
||||||
|
try:
|
||||||
|
name = parts[1]
|
||||||
|
if len(parts) > 2:
|
||||||
|
oid = int(parts[2])
|
||||||
|
except ValueError as e:
|
||||||
|
self.output("Error: %s" % (str(e),))
|
||||||
|
return
|
||||||
|
self.ser.register_callback(self.handle_suppress, name, oid)
|
||||||
|
def command_STATS(self, parts):
|
||||||
|
curtime = self.reactor.monotonic()
|
||||||
|
self.output(' '.join([self.ser.stats(curtime),
|
||||||
|
self.clocksync.stats(curtime)]))
|
||||||
|
def command_LIST(self, parts):
|
||||||
|
self.update_evals(self.reactor.monotonic())
|
||||||
|
mp = self.ser.msgparser
|
||||||
|
out = "Available mcu commands:"
|
||||||
|
out += "\n ".join([""] + sorted([
|
||||||
|
mp.messages_by_id[i].msgformat for i in mp.command_ids]))
|
||||||
|
out += "\nAvailable artificial commands:"
|
||||||
|
out += "\n ".join([""] + [n for n in sorted(self.local_commands)])
|
||||||
|
out += "\nAvailable local variables:"
|
||||||
|
out += "\n ".join([""] + ["%s: %s" % (k, v)
|
||||||
|
for k, v in sorted(self.eval_globals.items())])
|
||||||
|
self.output(out)
|
||||||
|
def command_HELP(self, parts):
|
||||||
|
self.output(help_txt)
|
||||||
def translate(self, line, eventtime):
|
def translate(self, line, eventtime):
|
||||||
evalparts = re_eval.split(line)
|
evalparts = re_eval.split(line)
|
||||||
if len(evalparts) > 1:
|
if len(evalparts) > 1:
|
||||||
self.update_evals(eventtime)
|
self.update_evals(eventtime)
|
||||||
try:
|
try:
|
||||||
for i in range(1, len(evalparts), 2):
|
for i in range(1, len(evalparts), 2):
|
||||||
evalparts[i] = str(eval(evalparts[i], self.eval_globals))
|
e = eval(evalparts[i], dict(self.eval_globals))
|
||||||
|
if type(e) == type(0.):
|
||||||
|
e = int(e)
|
||||||
|
evalparts[i] = str(e)
|
||||||
except:
|
except:
|
||||||
print "Unable to evaluate: ", line
|
self.output("Unable to evaluate: %s" % (line,))
|
||||||
return None
|
return None
|
||||||
line = ''.join(evalparts)
|
line = ''.join(evalparts)
|
||||||
print "Eval:", line
|
self.output("Eval: %s" % (line,))
|
||||||
if self.pins is None and self.ser.msgparser.config:
|
|
||||||
self.pins = pins.mcu_to_pins(self.ser.msgparser.config['MCU'])
|
|
||||||
if self.pins is not None:
|
if self.pins is not None:
|
||||||
try:
|
try:
|
||||||
line = pins.update_command(line, self.pins).strip()
|
line = self.pins.update_command(line).strip()
|
||||||
except:
|
except:
|
||||||
print "Unable to map pin: ", line
|
self.output("Unable to map pin: %s" % (line,))
|
||||||
return None
|
return None
|
||||||
if line:
|
if line:
|
||||||
parts = line.split()
|
parts = line.split()
|
||||||
if parts[0] in self.local_commands:
|
if parts[0] in self.local_commands:
|
||||||
self.local_commands[parts[0]](parts)
|
self.local_commands[parts[0]](parts)
|
||||||
return None
|
return None
|
||||||
try:
|
return line
|
||||||
msg = self.ser.msgparser.create_command(line)
|
|
||||||
except msgproto.error, e:
|
|
||||||
print "Error:", e
|
|
||||||
return None
|
|
||||||
return msg
|
|
||||||
def process_kbd(self, eventtime):
|
def process_kbd(self, eventtime):
|
||||||
self.data += os.read(self.fd, 4096)
|
self.data += os.read(self.fd, 4096)
|
||||||
|
|
||||||
@@ -78,7 +178,11 @@ class KeyboardReader:
|
|||||||
msg = self.translate(line.strip(), eventtime)
|
msg = self.translate(line.strip(), eventtime)
|
||||||
if msg is None:
|
if msg is None:
|
||||||
continue
|
continue
|
||||||
|
try:
|
||||||
self.ser.send(msg)
|
self.ser.send(msg)
|
||||||
|
except msgproto.error as e:
|
||||||
|
self.output("Error: %s" % (str(e),))
|
||||||
|
return None
|
||||||
self.data = kbdlines[-1]
|
self.data = kbdlines[-1]
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@@ -91,7 +195,6 @@ def main():
|
|||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
r = reactor.Reactor()
|
r = reactor.Reactor()
|
||||||
ser = serialhdl.SerialReader(r, serialport, baud)
|
ser = serialhdl.SerialReader(r, serialport, baud)
|
||||||
ser.connect()
|
|
||||||
kbd = KeyboardReader(ser, r)
|
kbd = KeyboardReader(ser, r)
|
||||||
try:
|
try:
|
||||||
r.run()
|
r.run()
|
||||||
|
|||||||
161
klippy/corexy.py
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
# Code for handling the kinematics of corexy robots
|
||||||
|
#
|
||||||
|
# Copyright (C) 2017 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
#
|
||||||
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
import logging, math
|
||||||
|
import stepper, homing
|
||||||
|
|
||||||
|
StepList = (0, 1, 2)
|
||||||
|
|
||||||
|
class CoreXYKinematics:
|
||||||
|
def __init__(self, toolhead, printer, config):
|
||||||
|
self.steppers = [
|
||||||
|
stepper.PrinterHomingStepper(
|
||||||
|
printer, config.getsection('stepper_x')),
|
||||||
|
stepper.PrinterHomingStepper(
|
||||||
|
printer, config.getsection('stepper_y')),
|
||||||
|
stepper.LookupMultiHomingStepper(
|
||||||
|
printer, config.getsection('stepper_z'))]
|
||||||
|
self.steppers[0].mcu_endstop.add_stepper(self.steppers[1].mcu_stepper)
|
||||||
|
self.steppers[1].mcu_endstop.add_stepper(self.steppers[0].mcu_stepper)
|
||||||
|
max_velocity, max_accel = toolhead.get_max_velocity()
|
||||||
|
self.max_z_velocity = config.getfloat(
|
||||||
|
'max_z_velocity', max_velocity, above=0., maxval=max_velocity)
|
||||||
|
self.max_z_accel = config.getfloat(
|
||||||
|
'max_z_accel', max_accel, above=0., maxval=max_accel)
|
||||||
|
self.need_motor_enable = True
|
||||||
|
self.limits = [(1.0, -1.0)] * 3
|
||||||
|
# Setup stepper max halt velocity
|
||||||
|
max_halt_velocity = toolhead.get_max_axis_halt()
|
||||||
|
max_xy_halt_velocity = max_halt_velocity * math.sqrt(2.)
|
||||||
|
self.steppers[0].set_max_jerk(max_xy_halt_velocity, max_accel)
|
||||||
|
self.steppers[1].set_max_jerk(max_xy_halt_velocity, max_accel)
|
||||||
|
self.steppers[2].set_max_jerk(
|
||||||
|
min(max_halt_velocity, self.max_z_velocity), self.max_z_accel)
|
||||||
|
def get_steppers(self, flags=""):
|
||||||
|
if flags == "Z":
|
||||||
|
return [self.steppers[2]]
|
||||||
|
return list(self.steppers)
|
||||||
|
def get_position(self):
|
||||||
|
pos = [s.mcu_stepper.get_commanded_position() for s in self.steppers]
|
||||||
|
return [0.5 * (pos[0] + pos[1]), 0.5 * (pos[0] - pos[1]), pos[2]]
|
||||||
|
def set_position(self, newpos, homing_axes):
|
||||||
|
pos = (newpos[0] + newpos[1], newpos[0] - newpos[1], newpos[2])
|
||||||
|
for i in StepList:
|
||||||
|
s = self.steppers[i]
|
||||||
|
s.set_position(pos[i])
|
||||||
|
if i in homing_axes:
|
||||||
|
self.limits[i] = (s.position_min, s.position_max)
|
||||||
|
def home(self, homing_state):
|
||||||
|
# Each axis is homed independently and in order
|
||||||
|
for axis in homing_state.get_axes():
|
||||||
|
s = self.steppers[axis]
|
||||||
|
# Determine moves
|
||||||
|
if s.homing_positive_dir:
|
||||||
|
pos = s.position_endstop - 1.5*(
|
||||||
|
s.position_endstop - s.position_min)
|
||||||
|
rpos = s.position_endstop - s.homing_retract_dist
|
||||||
|
r2pos = rpos - s.homing_retract_dist
|
||||||
|
else:
|
||||||
|
pos = s.position_endstop + 1.5*(
|
||||||
|
s.position_max - s.position_endstop)
|
||||||
|
rpos = s.position_endstop + s.homing_retract_dist
|
||||||
|
r2pos = rpos + s.homing_retract_dist
|
||||||
|
# Initial homing
|
||||||
|
homing_speed = s.homing_speed
|
||||||
|
if axis == 2:
|
||||||
|
homing_speed = min(homing_speed, self.max_z_velocity)
|
||||||
|
homepos = [None, None, None, None]
|
||||||
|
homepos[axis] = s.position_endstop
|
||||||
|
coord = [None, None, None, None]
|
||||||
|
coord[axis] = pos
|
||||||
|
homing_state.home(coord, homepos, s.get_endstops(), homing_speed)
|
||||||
|
# Retract
|
||||||
|
coord[axis] = rpos
|
||||||
|
homing_state.retract(coord, homing_speed)
|
||||||
|
# Home again
|
||||||
|
coord[axis] = r2pos
|
||||||
|
homing_state.home(coord, homepos, s.get_endstops(),
|
||||||
|
homing_speed/2.0, second_home=True)
|
||||||
|
if axis == 2:
|
||||||
|
# Support endstop phase detection on Z axis
|
||||||
|
coord[axis] = s.position_endstop + s.get_homed_offset()
|
||||||
|
homing_state.set_homed_position(coord)
|
||||||
|
def motor_off(self, print_time):
|
||||||
|
self.limits = [(1.0, -1.0)] * 3
|
||||||
|
for stepper in self.steppers:
|
||||||
|
stepper.motor_enable(print_time, 0)
|
||||||
|
self.need_motor_enable = True
|
||||||
|
def _check_motor_enable(self, print_time, move):
|
||||||
|
if move.axes_d[0] or move.axes_d[1]:
|
||||||
|
self.steppers[0].motor_enable(print_time, 1)
|
||||||
|
self.steppers[1].motor_enable(print_time, 1)
|
||||||
|
if move.axes_d[2]:
|
||||||
|
self.steppers[2].motor_enable(print_time, 1)
|
||||||
|
need_motor_enable = False
|
||||||
|
for i in StepList:
|
||||||
|
need_motor_enable |= self.steppers[i].need_motor_enable
|
||||||
|
self.need_motor_enable = need_motor_enable
|
||||||
|
def _check_endstops(self, move):
|
||||||
|
end_pos = move.end_pos
|
||||||
|
for i in StepList:
|
||||||
|
if (move.axes_d[i]
|
||||||
|
and (end_pos[i] < self.limits[i][0]
|
||||||
|
or end_pos[i] > self.limits[i][1])):
|
||||||
|
if self.limits[i][0] > self.limits[i][1]:
|
||||||
|
raise homing.EndstopMoveError(
|
||||||
|
end_pos, "Must home axis first")
|
||||||
|
raise homing.EndstopMoveError(end_pos)
|
||||||
|
def check_move(self, move):
|
||||||
|
limits = self.limits
|
||||||
|
xpos, ypos = move.end_pos[:2]
|
||||||
|
if (xpos < limits[0][0] or xpos > limits[0][1]
|
||||||
|
or ypos < limits[1][0] or ypos > limits[1][1]):
|
||||||
|
self._check_endstops(move)
|
||||||
|
if not move.axes_d[2]:
|
||||||
|
# Normal XY move - use defaults
|
||||||
|
return
|
||||||
|
# Move with Z - update velocity and accel for slower Z axis
|
||||||
|
self._check_endstops(move)
|
||||||
|
z_ratio = move.move_d / abs(move.axes_d[2])
|
||||||
|
move.limit_speed(
|
||||||
|
self.max_z_velocity * z_ratio, self.max_z_accel * z_ratio)
|
||||||
|
def move(self, print_time, move):
|
||||||
|
if self.need_motor_enable:
|
||||||
|
self._check_motor_enable(print_time, move)
|
||||||
|
sxp = move.start_pos[0]
|
||||||
|
syp = move.start_pos[1]
|
||||||
|
move_start_pos = (sxp + syp, sxp - syp, move.start_pos[2])
|
||||||
|
exp = move.end_pos[0]
|
||||||
|
eyp = move.end_pos[1]
|
||||||
|
axes_d = ((exp + eyp) - move_start_pos[0],
|
||||||
|
(exp - eyp) - move_start_pos[1], move.axes_d[2])
|
||||||
|
for i in StepList:
|
||||||
|
axis_d = axes_d[i]
|
||||||
|
if not axis_d:
|
||||||
|
continue
|
||||||
|
step_const = self.steppers[i].step_const
|
||||||
|
move_time = print_time
|
||||||
|
start_pos = move_start_pos[i]
|
||||||
|
axis_r = abs(axis_d) / move.move_d
|
||||||
|
accel = move.accel * axis_r
|
||||||
|
cruise_v = move.cruise_v * axis_r
|
||||||
|
|
||||||
|
# Acceleration steps
|
||||||
|
if move.accel_r:
|
||||||
|
accel_d = move.accel_r * axis_d
|
||||||
|
step_const(move_time, start_pos, accel_d,
|
||||||
|
move.start_v * axis_r, accel)
|
||||||
|
start_pos += accel_d
|
||||||
|
move_time += move.accel_t
|
||||||
|
# Cruising steps
|
||||||
|
if move.cruise_r:
|
||||||
|
cruise_d = move.cruise_r * axis_d
|
||||||
|
step_const(move_time, start_pos, cruise_d, cruise_v, 0.)
|
||||||
|
start_pos += cruise_d
|
||||||
|
move_time += move.cruise_t
|
||||||
|
# Deceleration steps
|
||||||
|
if move.decel_r:
|
||||||
|
decel_d = move.decel_r * axis_d
|
||||||
|
step_const(move_time, start_pos, decel_d, cruise_v, -accel)
|
||||||
285
klippy/delta.py
Normal file
@@ -0,0 +1,285 @@
|
|||||||
|
# Code for handling the kinematics of linear delta robots
|
||||||
|
#
|
||||||
|
# Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
#
|
||||||
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
import math, logging
|
||||||
|
import stepper, homing
|
||||||
|
|
||||||
|
StepList = (0, 1, 2)
|
||||||
|
|
||||||
|
# Slow moves once the ratio of tower to XY movement exceeds SLOW_RATIO
|
||||||
|
SLOW_RATIO = 3.
|
||||||
|
|
||||||
|
class DeltaKinematics:
|
||||||
|
def __init__(self, toolhead, printer, config):
|
||||||
|
stepper_configs = [config.getsection('stepper_' + n)
|
||||||
|
for n in ['a', 'b', 'c']]
|
||||||
|
stepper_a = stepper.PrinterHomingStepper(printer, stepper_configs[0])
|
||||||
|
stepper_b = stepper.PrinterHomingStepper(
|
||||||
|
printer, stepper_configs[1],
|
||||||
|
default_position=stepper_a.position_endstop)
|
||||||
|
stepper_c = stepper.PrinterHomingStepper(
|
||||||
|
printer, stepper_configs[2],
|
||||||
|
default_position=stepper_a.position_endstop)
|
||||||
|
self.steppers = [stepper_a, stepper_b, stepper_c]
|
||||||
|
self.need_motor_enable = self.need_home = True
|
||||||
|
self.radius = radius = config.getfloat('delta_radius', above=0.)
|
||||||
|
arm_length_a = stepper_configs[0].getfloat('arm_length', above=radius)
|
||||||
|
self.arm_lengths = arm_lengths = [
|
||||||
|
sconfig.getfloat('arm_length', arm_length_a, above=radius)
|
||||||
|
for sconfig in stepper_configs]
|
||||||
|
self.arm2 = [arm**2 for arm in arm_lengths]
|
||||||
|
self.endstops = [s.position_endstop + math.sqrt(arm2 - radius**2)
|
||||||
|
for s, arm2 in zip(self.steppers, self.arm2)]
|
||||||
|
self.limit_xy2 = -1.
|
||||||
|
self.max_z = min([s.position_endstop for s in self.steppers])
|
||||||
|
self.min_z = config.getfloat('minimum_z_position', 0, maxval=self.max_z)
|
||||||
|
self.limit_z = min([ep - arm
|
||||||
|
for ep, arm in zip(self.endstops, arm_lengths)])
|
||||||
|
logging.info(
|
||||||
|
"Delta max build height %.2fmm (radius tapered above %.2fmm)" % (
|
||||||
|
self.max_z, self.limit_z))
|
||||||
|
# Setup stepper max halt velocity
|
||||||
|
self.max_velocity, self.max_accel = toolhead.get_max_velocity()
|
||||||
|
self.max_z_velocity = config.getfloat(
|
||||||
|
'max_z_velocity', self.max_velocity,
|
||||||
|
above=0., maxval=self.max_velocity)
|
||||||
|
max_halt_velocity = toolhead.get_max_axis_halt()
|
||||||
|
for s in self.steppers:
|
||||||
|
s.set_max_jerk(max_halt_velocity, self.max_accel)
|
||||||
|
# Determine tower locations in cartesian space
|
||||||
|
self.angles = [sconfig.getfloat('angle', angle)
|
||||||
|
for sconfig, angle in zip(stepper_configs,
|
||||||
|
[210., 330., 90.])]
|
||||||
|
self.towers = [(math.cos(math.radians(angle)) * radius,
|
||||||
|
math.sin(math.radians(angle)) * radius)
|
||||||
|
for angle in self.angles]
|
||||||
|
# Find the point where an XY move could result in excessive
|
||||||
|
# tower movement
|
||||||
|
half_min_step_dist = min([s.step_dist for s in self.steppers]) * .5
|
||||||
|
min_arm_length = min(arm_lengths)
|
||||||
|
def ratio_to_dist(ratio):
|
||||||
|
return (ratio * math.sqrt(min_arm_length**2 / (ratio**2 + 1.)
|
||||||
|
- half_min_step_dist**2)
|
||||||
|
+ half_min_step_dist)
|
||||||
|
self.slow_xy2 = (ratio_to_dist(SLOW_RATIO) - radius)**2
|
||||||
|
self.very_slow_xy2 = (ratio_to_dist(2. * SLOW_RATIO) - radius)**2
|
||||||
|
self.max_xy2 = min(radius, min_arm_length - radius,
|
||||||
|
ratio_to_dist(4. * SLOW_RATIO) - radius)**2
|
||||||
|
logging.info(
|
||||||
|
"Delta max build radius %.2fmm (moves slowed past %.2fmm and %.2fmm)"
|
||||||
|
% (math.sqrt(self.max_xy2), math.sqrt(self.slow_xy2),
|
||||||
|
math.sqrt(self.very_slow_xy2)))
|
||||||
|
self.set_position([0., 0., 0.], ())
|
||||||
|
def get_steppers(self, flags=""):
|
||||||
|
return list(self.steppers)
|
||||||
|
def _cartesian_to_actuator(self, coord):
|
||||||
|
return [math.sqrt(self.arm2[i] - (self.towers[i][0] - coord[0])**2
|
||||||
|
- (self.towers[i][1] - coord[1])**2) + coord[2]
|
||||||
|
for i in StepList]
|
||||||
|
def _actuator_to_cartesian(self, pos):
|
||||||
|
return actuator_to_cartesian(self.towers, self.arm2, pos)
|
||||||
|
def get_position(self):
|
||||||
|
spos = [s.mcu_stepper.get_commanded_position() for s in self.steppers]
|
||||||
|
return self._actuator_to_cartesian(spos)
|
||||||
|
def set_position(self, newpos, homing_axes):
|
||||||
|
pos = self._cartesian_to_actuator(newpos)
|
||||||
|
for i in StepList:
|
||||||
|
self.steppers[i].set_position(pos[i])
|
||||||
|
self.limit_xy2 = -1.
|
||||||
|
if tuple(homing_axes) == StepList:
|
||||||
|
self.need_home = False
|
||||||
|
def home(self, homing_state):
|
||||||
|
# All axes are homed simultaneously
|
||||||
|
homing_state.set_axes([0, 1, 2])
|
||||||
|
endstops = [es for s in self.steppers for es in s.get_endstops()]
|
||||||
|
s = self.steppers[0] # Assume homing speed same for all steppers
|
||||||
|
# Initial homing
|
||||||
|
homing_speed = min(s.homing_speed, self.max_z_velocity)
|
||||||
|
homepos = [0., 0., self.max_z, None]
|
||||||
|
coord = list(homepos)
|
||||||
|
coord[2] = -1.5 * math.sqrt(max(self.arm2)-self.max_xy2)
|
||||||
|
homing_state.home(coord, homepos, endstops, homing_speed)
|
||||||
|
# Retract
|
||||||
|
coord[2] = homepos[2] - s.homing_retract_dist
|
||||||
|
homing_state.retract(coord, homing_speed)
|
||||||
|
# Home again
|
||||||
|
coord[2] -= s.homing_retract_dist
|
||||||
|
homing_state.home(coord, homepos, endstops,
|
||||||
|
homing_speed/2.0, second_home=True)
|
||||||
|
# Set final homed position
|
||||||
|
spos = [ep + s.get_homed_offset()
|
||||||
|
for ep, s in zip(self.endstops, self.steppers)]
|
||||||
|
homing_state.set_homed_position(self._actuator_to_cartesian(spos))
|
||||||
|
def motor_off(self, print_time):
|
||||||
|
self.limit_xy2 = -1.
|
||||||
|
for stepper in self.steppers:
|
||||||
|
stepper.motor_enable(print_time, 0)
|
||||||
|
self.need_motor_enable = self.need_home = True
|
||||||
|
def _check_motor_enable(self, print_time):
|
||||||
|
for i in StepList:
|
||||||
|
self.steppers[i].motor_enable(print_time, 1)
|
||||||
|
self.need_motor_enable = False
|
||||||
|
def check_move(self, move):
|
||||||
|
end_pos = move.end_pos
|
||||||
|
xy2 = end_pos[0]**2 + end_pos[1]**2
|
||||||
|
if xy2 <= self.limit_xy2 and not move.axes_d[2]:
|
||||||
|
# Normal XY move
|
||||||
|
return
|
||||||
|
if self.need_home:
|
||||||
|
raise homing.EndstopMoveError(end_pos, "Must home first")
|
||||||
|
limit_xy2 = self.max_xy2
|
||||||
|
if end_pos[2] > self.limit_z:
|
||||||
|
limit_xy2 = min(limit_xy2, (self.max_z - end_pos[2])**2)
|
||||||
|
if xy2 > limit_xy2 or end_pos[2] < self.min_z or end_pos[2] > self.max_z:
|
||||||
|
raise homing.EndstopMoveError(end_pos)
|
||||||
|
if move.axes_d[2]:
|
||||||
|
move.limit_speed(self.max_z_velocity, move.accel)
|
||||||
|
limit_xy2 = -1.
|
||||||
|
# Limit the speed/accel of this move if is is at the extreme
|
||||||
|
# end of the build envelope
|
||||||
|
extreme_xy2 = max(xy2, move.start_pos[0]**2 + move.start_pos[1]**2)
|
||||||
|
if extreme_xy2 > self.slow_xy2:
|
||||||
|
r = 0.5
|
||||||
|
if extreme_xy2 > self.very_slow_xy2:
|
||||||
|
r = 0.25
|
||||||
|
max_velocity = self.max_velocity
|
||||||
|
if move.axes_d[2]:
|
||||||
|
max_velocity = self.max_z_velocity
|
||||||
|
move.limit_speed(max_velocity * r, self.max_accel * r)
|
||||||
|
limit_xy2 = -1.
|
||||||
|
self.limit_xy2 = min(limit_xy2, self.slow_xy2)
|
||||||
|
def move(self, print_time, move):
|
||||||
|
if self.need_motor_enable:
|
||||||
|
self._check_motor_enable(print_time)
|
||||||
|
axes_d = move.axes_d
|
||||||
|
move_d = move.move_d
|
||||||
|
movexy_r = 1.
|
||||||
|
movez_r = 0.
|
||||||
|
inv_movexy_d = 1. / move_d
|
||||||
|
if not axes_d[0] and not axes_d[1]:
|
||||||
|
# Z only move
|
||||||
|
movez_r = axes_d[2] * inv_movexy_d
|
||||||
|
movexy_r = inv_movexy_d = 0.
|
||||||
|
elif axes_d[2]:
|
||||||
|
# XY+Z move
|
||||||
|
movexy_d = math.sqrt(axes_d[0]**2 + axes_d[1]**2)
|
||||||
|
movexy_r = movexy_d * inv_movexy_d
|
||||||
|
movez_r = axes_d[2] * inv_movexy_d
|
||||||
|
inv_movexy_d = 1. / movexy_d
|
||||||
|
|
||||||
|
origx, origy, origz = move.start_pos[:3]
|
||||||
|
|
||||||
|
accel = move.accel
|
||||||
|
cruise_v = move.cruise_v
|
||||||
|
accel_d = move.accel_r * move_d
|
||||||
|
cruise_d = move.cruise_r * move_d
|
||||||
|
decel_d = move.decel_r * move_d
|
||||||
|
|
||||||
|
for i in StepList:
|
||||||
|
# Calculate a virtual tower along the line of movement at
|
||||||
|
# the point closest to this stepper's tower.
|
||||||
|
towerx_d = self.towers[i][0] - origx
|
||||||
|
towery_d = self.towers[i][1] - origy
|
||||||
|
vt_startxy_d = (towerx_d*axes_d[0] + towery_d*axes_d[1])*inv_movexy_d
|
||||||
|
tangentxy_d2 = towerx_d**2 + towery_d**2 - vt_startxy_d**2
|
||||||
|
vt_arm_d = math.sqrt(self.arm2[i] - tangentxy_d2)
|
||||||
|
vt_startz = origz
|
||||||
|
|
||||||
|
# Generate steps
|
||||||
|
step_delta = self.steppers[i].step_delta
|
||||||
|
move_time = print_time
|
||||||
|
if accel_d:
|
||||||
|
step_delta(move_time, accel_d, move.start_v, accel,
|
||||||
|
vt_startz, vt_startxy_d, vt_arm_d, movez_r)
|
||||||
|
vt_startz += accel_d * movez_r
|
||||||
|
vt_startxy_d -= accel_d * movexy_r
|
||||||
|
move_time += move.accel_t
|
||||||
|
if cruise_d:
|
||||||
|
step_delta(move_time, cruise_d, cruise_v, 0.,
|
||||||
|
vt_startz, vt_startxy_d, vt_arm_d, movez_r)
|
||||||
|
vt_startz += cruise_d * movez_r
|
||||||
|
vt_startxy_d -= cruise_d * movexy_r
|
||||||
|
move_time += move.cruise_t
|
||||||
|
if decel_d:
|
||||||
|
step_delta(move_time, decel_d, cruise_v, -accel,
|
||||||
|
vt_startz, vt_startxy_d, vt_arm_d, movez_r)
|
||||||
|
# Helper functions for DELTA_CALIBRATE script
|
||||||
|
def get_stable_position(self):
|
||||||
|
return [int((ep - s.mcu_stepper.get_commanded_position())
|
||||||
|
/ s.mcu_stepper.get_step_dist() + .5)
|
||||||
|
* s.mcu_stepper.get_step_dist()
|
||||||
|
for ep, s in zip(self.endstops, self.steppers)]
|
||||||
|
def get_calibrate_params(self):
|
||||||
|
return {
|
||||||
|
'endstop_a': self.steppers[0].position_endstop,
|
||||||
|
'endstop_b': self.steppers[1].position_endstop,
|
||||||
|
'endstop_c': self.steppers[2].position_endstop,
|
||||||
|
'angle_a': self.angles[0], 'angle_b': self.angles[1],
|
||||||
|
'angle_c': self.angles[2], 'radius': self.radius,
|
||||||
|
'arm_a': self.arm_lengths[0], 'arm_b': self.arm_lengths[1],
|
||||||
|
'arm_c': self.arm_lengths[2] }
|
||||||
|
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Matrix helper functions for 3x1 matrices
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
def matrix_cross(m1, m2):
|
||||||
|
return [m1[1] * m2[2] - m1[2] * m2[1],
|
||||||
|
m1[2] * m2[0] - m1[0] * m2[2],
|
||||||
|
m1[0] * m2[1] - m1[1] * m2[0]]
|
||||||
|
|
||||||
|
def matrix_dot(m1, m2):
|
||||||
|
return m1[0] * m2[0] + m1[1] * m2[1] + m1[2] * m2[2]
|
||||||
|
|
||||||
|
def matrix_magsq(m1):
|
||||||
|
return m1[0]**2 + m1[1]**2 + m1[2]**2
|
||||||
|
|
||||||
|
def matrix_add(m1, m2):
|
||||||
|
return [m1[0] + m2[0], m1[1] + m2[1], m1[2] + m2[2]]
|
||||||
|
|
||||||
|
def matrix_sub(m1, m2):
|
||||||
|
return [m1[0] - m2[0], m1[1] - m2[1], m1[2] - m2[2]]
|
||||||
|
|
||||||
|
def matrix_mul(m1, s):
|
||||||
|
return [m1[0]*s, m1[1]*s, m1[2]*s]
|
||||||
|
|
||||||
|
def actuator_to_cartesian(towers, arm2, pos):
|
||||||
|
# Find nozzle position using trilateration (see wikipedia)
|
||||||
|
carriage1 = list(towers[0]) + [pos[0]]
|
||||||
|
carriage2 = list(towers[1]) + [pos[1]]
|
||||||
|
carriage3 = list(towers[2]) + [pos[2]]
|
||||||
|
|
||||||
|
s21 = matrix_sub(carriage2, carriage1)
|
||||||
|
s31 = matrix_sub(carriage3, carriage1)
|
||||||
|
|
||||||
|
d = math.sqrt(matrix_magsq(s21))
|
||||||
|
ex = matrix_mul(s21, 1. / d)
|
||||||
|
i = matrix_dot(ex, s31)
|
||||||
|
vect_ey = matrix_sub(s31, matrix_mul(ex, i))
|
||||||
|
ey = matrix_mul(vect_ey, 1. / math.sqrt(matrix_magsq(vect_ey)))
|
||||||
|
ez = matrix_cross(ex, ey)
|
||||||
|
j = matrix_dot(ey, s31)
|
||||||
|
|
||||||
|
x = (arm2[0] - arm2[1] + d**2) / (2. * d)
|
||||||
|
y = (arm2[0] - arm2[2] - x**2 + (x-i)**2 + j**2) / (2. * j)
|
||||||
|
z = -math.sqrt(arm2[0] - x**2 - y**2)
|
||||||
|
|
||||||
|
ex_x = matrix_mul(ex, x)
|
||||||
|
ey_y = matrix_mul(ey, y)
|
||||||
|
ez_z = matrix_mul(ez, z)
|
||||||
|
return matrix_add(carriage1, matrix_add(ex_x, matrix_add(ey_y, ez_z)))
|
||||||
|
|
||||||
|
def get_position_from_stable(spos, params):
|
||||||
|
angles = [params['angle_a'], params['angle_b'], params['angle_c']]
|
||||||
|
radius = params['radius']
|
||||||
|
radius2 = radius**2
|
||||||
|
towers = [(math.cos(angle) * radius, math.sin(angle) * radius)
|
||||||
|
for angle in map(math.radians, angles)]
|
||||||
|
arm2 = [a**2 for a in [params['arm_a'], params['arm_b'], params['arm_c']]]
|
||||||
|
endstops = [params['endstop_a'], params['endstop_b'], params['endstop_c']]
|
||||||
|
pos = [es + math.sqrt(a2 - radius2) - p
|
||||||
|
for es, a2, p in zip(endstops, arm2, spos)]
|
||||||
|
return actuator_to_cartesian(towers, arm2, pos)
|
||||||
5
klippy/extras/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Package definition for the extras directory
|
||||||
|
#
|
||||||
|
# Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
#
|
||||||
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
32
klippy/extras/ad5206.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# AD5206 digipot code
|
||||||
|
#
|
||||||
|
# Copyright (C) 2017,2018 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
#
|
||||||
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
import pins
|
||||||
|
|
||||||
|
class ad5206:
|
||||||
|
def __init__(self, config):
|
||||||
|
printer = config.get_printer()
|
||||||
|
enable_pin_params = pins.get_printer_pins(printer).lookup_pin(
|
||||||
|
'digital_out', config.get('enable_pin'))
|
||||||
|
if enable_pin_params['invert']:
|
||||||
|
raise pins.error("ad5206 can not invert pin")
|
||||||
|
self.mcu = enable_pin_params['chip']
|
||||||
|
self.pin = enable_pin_params['pin']
|
||||||
|
self.mcu.add_config_object(self)
|
||||||
|
scale = config.getfloat('scale', 1., above=0.)
|
||||||
|
self.channels = [None] * 6
|
||||||
|
for i in range(len(self.channels)):
|
||||||
|
val = config.getfloat('channel_%d' % (i+1,), None,
|
||||||
|
minval=0., maxval=scale)
|
||||||
|
if val is not None:
|
||||||
|
self.channels[i] = int(val * 256. / scale + .5)
|
||||||
|
def build_config(self):
|
||||||
|
for i, val in enumerate(self.channels):
|
||||||
|
if val is not None:
|
||||||
|
self.mcu.add_config_cmd(
|
||||||
|
"send_spi_message pin=%s msg=%02x%02x" % (self.pin, i, val))
|
||||||
|
|
||||||
|
def load_config_prefix(config):
|
||||||
|
return ad5206(config)
|
||||||
113
klippy/extras/bed_tilt.py
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
# Bed tilt compensation
|
||||||
|
#
|
||||||
|
# Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
#
|
||||||
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
import logging
|
||||||
|
import probe, mathutil
|
||||||
|
|
||||||
|
class BedTilt:
|
||||||
|
def __init__(self, config):
|
||||||
|
self.printer = config.get_printer()
|
||||||
|
self.x_adjust = config.getfloat('x_adjust', 0.)
|
||||||
|
self.y_adjust = config.getfloat('y_adjust', 0.)
|
||||||
|
if config.get('points', None) is not None:
|
||||||
|
BedTiltCalibrate(config, self)
|
||||||
|
self.toolhead = None
|
||||||
|
gcode = self.printer.lookup_object('gcode')
|
||||||
|
gcode.set_move_transform(self)
|
||||||
|
def printer_state(self, state):
|
||||||
|
if state == 'connect':
|
||||||
|
self.toolhead = self.printer.lookup_object('toolhead')
|
||||||
|
def get_position(self):
|
||||||
|
x, y, z, e = self.toolhead.get_position()
|
||||||
|
return [x, y, z - x*self.x_adjust - y*self.y_adjust, e]
|
||||||
|
def move(self, newpos, speed):
|
||||||
|
x, y, z, e = newpos
|
||||||
|
self.toolhead.move([x, y, z + x*self.x_adjust + y*self.y_adjust, e],
|
||||||
|
speed)
|
||||||
|
|
||||||
|
# Helper script to calibrate the bed tilt
|
||||||
|
class BedTiltCalibrate:
|
||||||
|
def __init__(self, config, bedtilt):
|
||||||
|
self.bedtilt = bedtilt
|
||||||
|
self.printer = config.get_printer()
|
||||||
|
points = config.get('points').split('\n')
|
||||||
|
try:
|
||||||
|
points = [line.split(',', 1) for line in points if line.strip()]
|
||||||
|
self.points = [(float(p[0].strip()), float(p[1].strip()))
|
||||||
|
for p in points]
|
||||||
|
except:
|
||||||
|
raise config.error("Unable to parse bed tilt points")
|
||||||
|
if len(self.points) < 3:
|
||||||
|
raise config.error("Need at least 3 points for bed_tilt_calibrate")
|
||||||
|
self.speed = config.getfloat('speed', 50., above=0.)
|
||||||
|
self.horizontal_move_z = config.getfloat('horizontal_move_z', 5.)
|
||||||
|
self.z_position_endstop = None
|
||||||
|
if config.has_section('stepper_z'):
|
||||||
|
zconfig = config.getsection('stepper_z')
|
||||||
|
self.z_position_endstop = zconfig.getfloat('position_endstop', None)
|
||||||
|
self.manual_probe = config.getboolean('manual_probe', None)
|
||||||
|
if self.manual_probe is None:
|
||||||
|
self.manual_probe = not config.has_section('probe')
|
||||||
|
self.gcode = self.printer.lookup_object('gcode')
|
||||||
|
self.gcode.register_command(
|
||||||
|
'BED_TILT_CALIBRATE', self.cmd_BED_TILT_CALIBRATE,
|
||||||
|
desc=self.cmd_BED_TILT_CALIBRATE_help)
|
||||||
|
cmd_BED_TILT_CALIBRATE_help = "Bed tilt calibration script"
|
||||||
|
def cmd_BED_TILT_CALIBRATE(self, params):
|
||||||
|
self.gcode.run_script("G28")
|
||||||
|
probe.ProbePointsHelper(
|
||||||
|
self.printer, self.points, self.horizontal_move_z,
|
||||||
|
self.speed, self.manual_probe, self)
|
||||||
|
def get_position(self):
|
||||||
|
kin = self.printer.lookup_object('toolhead').get_kinematics()
|
||||||
|
return kin.get_position()
|
||||||
|
def finalize(self, z_offset, positions):
|
||||||
|
logging.info("Calculating bed_tilt with: %s", positions)
|
||||||
|
params = { 'x_adjust': self.bedtilt.x_adjust,
|
||||||
|
'y_adjust': self.bedtilt.y_adjust,
|
||||||
|
'z_adjust': z_offset }
|
||||||
|
logging.info("Initial bed_tilt parameters: %s", params)
|
||||||
|
def adjusted_height(pos, params):
|
||||||
|
x, y, z = pos
|
||||||
|
return (z - x*params['x_adjust'] - y*params['y_adjust']
|
||||||
|
- params['z_adjust'])
|
||||||
|
def errorfunc(params):
|
||||||
|
total_error = 0.
|
||||||
|
for pos in positions:
|
||||||
|
total_error += adjusted_height(pos, params)**2
|
||||||
|
return total_error
|
||||||
|
new_params = mathutil.coordinate_descent(
|
||||||
|
params.keys(), params, errorfunc)
|
||||||
|
logging.info("Calculated bed_tilt parameters: %s", new_params)
|
||||||
|
for pos in positions:
|
||||||
|
logging.info("orig: %s new: %s", adjusted_height(pos, params),
|
||||||
|
adjusted_height(pos, new_params))
|
||||||
|
z_diff = new_params['z_adjust'] - z_offset
|
||||||
|
if self.z_position_endstop is not None:
|
||||||
|
# Cartesian style robot
|
||||||
|
z_extra = ""
|
||||||
|
probe = self.printer.lookup_object('probe', None)
|
||||||
|
if probe is not None:
|
||||||
|
last_home_position = probe.last_home_position()
|
||||||
|
if last_home_position is not None:
|
||||||
|
# Using z_virtual_endstop
|
||||||
|
home_x, home_y = last_home_position[:2]
|
||||||
|
z_diff -= home_x * new_params['x_adjust']
|
||||||
|
z_diff -= home_y * new_params['y_adjust']
|
||||||
|
z_extra = " (when Z homing at %.3f,%.3f)" % (home_x, home_y)
|
||||||
|
z_adjust = "stepper_z position_endstop: %.6f%s\n" % (
|
||||||
|
self.z_position_endstop - z_diff, z_extra)
|
||||||
|
else:
|
||||||
|
# Delta (or other) style robot
|
||||||
|
z_adjust = "Add %.6f to endstop position\n" % (-z_diff,)
|
||||||
|
msg = "%sx_adjust: %.6f y_adjust: %.6f" % (
|
||||||
|
z_adjust, new_params['x_adjust'], new_params['y_adjust'])
|
||||||
|
logging.info("bed_tilt_calibrate: %s", msg)
|
||||||
|
self.gcode.respond_info(
|
||||||
|
"%s\nTo use these parameters, update the printer config file with\n"
|
||||||
|
"the above and then issue a RESTART command" % (msg,))
|
||||||
|
|
||||||
|
def load_config(config):
|
||||||
|
return BedTilt(config)
|
||||||
73
klippy/extras/delta_calibrate.py
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# Delta calibration support
|
||||||
|
#
|
||||||
|
# Copyright (C) 2017-2018 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
#
|
||||||
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
import math, logging
|
||||||
|
import probe, delta, mathutil
|
||||||
|
|
||||||
|
class DeltaCalibrate:
|
||||||
|
def __init__(self, config):
|
||||||
|
self.printer = config.get_printer()
|
||||||
|
if config.getsection('printer').get('kinematics') != 'delta':
|
||||||
|
raise config.error("Delta calibrate is only for delta printers")
|
||||||
|
self.radius = config.getfloat('radius', above=0.)
|
||||||
|
self.speed = config.getfloat('speed', 50., above=0.)
|
||||||
|
self.horizontal_move_z = config.getfloat('horizontal_move_z', 5.)
|
||||||
|
self.manual_probe = config.getboolean('manual_probe', None)
|
||||||
|
if self.manual_probe is None:
|
||||||
|
self.manual_probe = not config.has_section('probe')
|
||||||
|
self.gcode = self.printer.lookup_object('gcode')
|
||||||
|
self.gcode.register_command(
|
||||||
|
'DELTA_CALIBRATE', self.cmd_DELTA_CALIBRATE,
|
||||||
|
desc=self.cmd_DELTA_CALIBRATE_help)
|
||||||
|
cmd_DELTA_CALIBRATE_help = "Delta calibration script"
|
||||||
|
def cmd_DELTA_CALIBRATE(self, params):
|
||||||
|
# Setup probe points
|
||||||
|
points = [(0., 0.)]
|
||||||
|
scatter = [.95, .90, .85, .70, .75, .80]
|
||||||
|
for i in range(6):
|
||||||
|
r = math.radians(90. + 60. * i)
|
||||||
|
dist = self.radius * scatter[i]
|
||||||
|
points.append((math.cos(r) * dist, math.sin(r) * dist))
|
||||||
|
# Probe them
|
||||||
|
self.gcode.run_script("G28")
|
||||||
|
probe.ProbePointsHelper(self.printer, points, self.horizontal_move_z,
|
||||||
|
self.speed, self.manual_probe, self)
|
||||||
|
def get_position(self):
|
||||||
|
kin = self.printer.lookup_object('toolhead').get_kinematics()
|
||||||
|
return kin.get_stable_position()
|
||||||
|
def finalize(self, z_offset, positions):
|
||||||
|
kin = self.printer.lookup_object('toolhead').get_kinematics()
|
||||||
|
logging.info("Calculating delta_calibrate with: %s", positions)
|
||||||
|
params = kin.get_calibrate_params()
|
||||||
|
logging.info("Initial delta_calibrate parameters: %s", params)
|
||||||
|
adj_params = ('endstop_a', 'endstop_b', 'endstop_c', 'radius',
|
||||||
|
'angle_a', 'angle_b')
|
||||||
|
def delta_errorfunc(params):
|
||||||
|
total_error = 0.
|
||||||
|
for spos in positions:
|
||||||
|
x, y, z = delta.get_position_from_stable(spos, params)
|
||||||
|
total_error += (z - z_offset)**2
|
||||||
|
return total_error
|
||||||
|
new_params = mathutil.coordinate_descent(
|
||||||
|
adj_params, params, delta_errorfunc)
|
||||||
|
logging.info("Calculated delta_calibrate parameters: %s", new_params)
|
||||||
|
for spos in positions:
|
||||||
|
logging.info("orig: %s new: %s",
|
||||||
|
delta.get_position_from_stable(spos, params),
|
||||||
|
delta.get_position_from_stable(spos, new_params))
|
||||||
|
self.gcode.respond_info(
|
||||||
|
"stepper_a: position_endstop: %.6f angle: %.6f\n"
|
||||||
|
"stepper_b: position_endstop: %.6f angle: %.6f\n"
|
||||||
|
"stepper_c: position_endstop: %.6f angle: %.6f\n"
|
||||||
|
"radius: %.6f\n"
|
||||||
|
"To use these parameters, update the printer config file with\n"
|
||||||
|
"the above and then issue a RESTART command" % (
|
||||||
|
new_params['endstop_a'], new_params['angle_a'],
|
||||||
|
new_params['endstop_b'], new_params['angle_b'],
|
||||||
|
new_params['endstop_c'], new_params['angle_c'],
|
||||||
|
new_params['radius']))
|
||||||
|
|
||||||
|
def load_config(config):
|
||||||
|
return DeltaCalibrate(config)
|
||||||
602
klippy/extras/display.py
Normal file
@@ -0,0 +1,602 @@
|
|||||||
|
# Basic LCD display support
|
||||||
|
#
|
||||||
|
# Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
# Copyright (C) 2018 Aleph Objects, Inc <marcio@alephobjects.com>
|
||||||
|
#
|
||||||
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
import logging
|
||||||
|
|
||||||
|
BACKGROUND_PRIORITY_CLOCK = 0x7fffffff00000000
|
||||||
|
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# HD44780 (20x4 text) lcd chip
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
HD44780_DELAY = .000037
|
||||||
|
|
||||||
|
class HD44780:
|
||||||
|
char_right_arrow = '\x7e'
|
||||||
|
char_thermometer = '\x00'
|
||||||
|
char_heater_bed = '\x01'
|
||||||
|
char_speed_factor = '\x02'
|
||||||
|
char_clock = '\x03'
|
||||||
|
char_degrees = '\x04'
|
||||||
|
def __init__(self, config):
|
||||||
|
self.printer = config.get_printer()
|
||||||
|
# pin config
|
||||||
|
ppins = self.printer.lookup_object('pins')
|
||||||
|
pins = [ppins.lookup_pin('digital_out', config.get(name + '_pin'))
|
||||||
|
for name in ['rs', 'e', 'd4', 'd5', 'd6', 'd7']]
|
||||||
|
mcu = None
|
||||||
|
for pin_params in pins:
|
||||||
|
if mcu is not None and pin_params['chip'] != mcu:
|
||||||
|
raise ppins.error("hd44780 all pins must be on same mcu")
|
||||||
|
mcu = pin_params['chip']
|
||||||
|
if pin_params['invert']:
|
||||||
|
raise ppins.error("hd44780 can not invert pin")
|
||||||
|
self.pins = [pin_params['pin'] for pin_params in pins]
|
||||||
|
self.mcu = mcu
|
||||||
|
self.oid = self.mcu.create_oid()
|
||||||
|
self.mcu.add_config_object(self)
|
||||||
|
self.send_data_cmd = self.send_cmds_cmd = None
|
||||||
|
# framebuffers
|
||||||
|
self.text_framebuffer = (bytearray(' '*80), bytearray('~'*80), 0x80)
|
||||||
|
self.glyph_framebuffer = (bytearray(64), bytearray('~'*64), 0x40)
|
||||||
|
self.framebuffers = [self.text_framebuffer, self.glyph_framebuffer]
|
||||||
|
def build_config(self):
|
||||||
|
self.mcu.add_config_cmd(
|
||||||
|
"config_hd44780 oid=%d rs_pin=%s e_pin=%s"
|
||||||
|
" d4_pin=%s d5_pin=%s d6_pin=%s d7_pin=%s delay_ticks=%d" % (
|
||||||
|
self.oid, self.pins[0], self.pins[1],
|
||||||
|
self.pins[2], self.pins[3], self.pins[4], self.pins[5],
|
||||||
|
self.mcu.seconds_to_clock(HD44780_DELAY)))
|
||||||
|
cmd_queue = self.mcu.alloc_command_queue()
|
||||||
|
self.send_cmds_cmd = self.mcu.lookup_command(
|
||||||
|
"hd44780_send_cmds oid=%c cmds=%*s", cq=cmd_queue)
|
||||||
|
self.send_data_cmd = self.mcu.lookup_command(
|
||||||
|
"hd44780_send_data oid=%c data=%*s", cq=cmd_queue)
|
||||||
|
def send(self, cmds, is_data=False):
|
||||||
|
cmd_type = self.send_cmds_cmd
|
||||||
|
if is_data:
|
||||||
|
cmd_type = self.send_data_cmd
|
||||||
|
cmd_type.send([self.oid, cmds], reqclock=BACKGROUND_PRIORITY_CLOCK)
|
||||||
|
#logging.debug("hd44780 %d %s", is_data, repr(cmds))
|
||||||
|
def flush(self):
|
||||||
|
# Find all differences in the framebuffers and send them to the chip
|
||||||
|
for new_data, old_data, fb_id in self.framebuffers:
|
||||||
|
if new_data == old_data:
|
||||||
|
continue
|
||||||
|
# Find the position of all changed bytes in this framebuffer
|
||||||
|
diffs = [[i, 1] for i, (nd, od) in enumerate(zip(new_data, old_data))
|
||||||
|
if nd != od]
|
||||||
|
# Batch together changes that are close to each other
|
||||||
|
for i in range(len(diffs)-2, -1, -1):
|
||||||
|
pos, count = diffs[i]
|
||||||
|
nextpos, nextcount = diffs[i+1]
|
||||||
|
if pos + 4 >= nextpos and nextcount < 16:
|
||||||
|
diffs[i][1] = nextcount + (nextpos - pos)
|
||||||
|
del diffs[i+1]
|
||||||
|
# Transmit changes
|
||||||
|
for pos, count in diffs:
|
||||||
|
chip_pos = pos
|
||||||
|
if fb_id == 0x80 and pos >= 40:
|
||||||
|
chip_pos += 0x40 - 40
|
||||||
|
self.send([fb_id + chip_pos])
|
||||||
|
self.send(new_data[pos:pos+count], is_data=True)
|
||||||
|
old_data[:] = new_data
|
||||||
|
def init(self):
|
||||||
|
curtime = self.printer.get_reactor().monotonic()
|
||||||
|
print_time = self.mcu.estimated_print_time(curtime)
|
||||||
|
# Program 4bit / 2-line mode and then issue 0x02 "Home" command
|
||||||
|
init = [[0x33], [0x33], [0x33, 0x22, 0x28, 0x02]]
|
||||||
|
# Reset (set positive direction ; enable display and hide cursor)
|
||||||
|
init.append([0x06, 0x0c])
|
||||||
|
for i, cmds in enumerate(init):
|
||||||
|
minclock = self.mcu.print_time_to_clock(print_time + i * .100)
|
||||||
|
self.send_cmds_cmd.send([self.oid, cmds], minclock=minclock)
|
||||||
|
# Add custom fonts
|
||||||
|
self.glyph_framebuffer[0][:len(HD44780_chars)] = HD44780_chars
|
||||||
|
for i in range(len(self.glyph_framebuffer[0])):
|
||||||
|
self.glyph_framebuffer[1][i] = self.glyph_framebuffer[0][i] ^ 1
|
||||||
|
self.flush()
|
||||||
|
def write_text(self, x, y, data):
|
||||||
|
if x + len(data) > 20:
|
||||||
|
data = data[:20 - min(x, 20)]
|
||||||
|
pos = [0, 40, 20, 60][y] + x
|
||||||
|
self.text_framebuffer[0][pos:pos+len(data)] = data
|
||||||
|
def clear(self):
|
||||||
|
self.text_framebuffer[0][:] = ' '*80
|
||||||
|
|
||||||
|
HD44780_chars = [
|
||||||
|
# Thermometer
|
||||||
|
0b00100,
|
||||||
|
0b01010,
|
||||||
|
0b01010,
|
||||||
|
0b01010,
|
||||||
|
0b01010,
|
||||||
|
0b10001,
|
||||||
|
0b10001,
|
||||||
|
0b01110,
|
||||||
|
# Heated bed
|
||||||
|
0b00000,
|
||||||
|
0b11111,
|
||||||
|
0b10101,
|
||||||
|
0b10001,
|
||||||
|
0b10101,
|
||||||
|
0b11111,
|
||||||
|
0b00000,
|
||||||
|
0b00000,
|
||||||
|
# Speed factor
|
||||||
|
0b11100,
|
||||||
|
0b10000,
|
||||||
|
0b11000,
|
||||||
|
0b10111,
|
||||||
|
0b00101,
|
||||||
|
0b00110,
|
||||||
|
0b00101,
|
||||||
|
0b00000,
|
||||||
|
# Clock
|
||||||
|
0b00000,
|
||||||
|
0b01110,
|
||||||
|
0b10011,
|
||||||
|
0b10101,
|
||||||
|
0b10001,
|
||||||
|
0b01110,
|
||||||
|
0b00000,
|
||||||
|
0b00000,
|
||||||
|
# Degrees
|
||||||
|
0b01100,
|
||||||
|
0b10010,
|
||||||
|
0b10010,
|
||||||
|
0b01100,
|
||||||
|
0b00000,
|
||||||
|
0b00000,
|
||||||
|
0b00000,
|
||||||
|
0b00000,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# ST7920 (128x64 graphics) lcd chip
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
ST7920_DELAY = .000020 # Spec says 72us, but faster is possible in practice
|
||||||
|
|
||||||
|
class ST7920:
|
||||||
|
char_right_arrow = '\x1a'
|
||||||
|
def __init__(self, config):
|
||||||
|
printer = config.get_printer()
|
||||||
|
# pin config
|
||||||
|
ppins = printer.lookup_object('pins')
|
||||||
|
pins = [ppins.lookup_pin('digital_out', config.get(name + '_pin'))
|
||||||
|
for name in ['cs', 'sclk', 'sid']]
|
||||||
|
mcu = None
|
||||||
|
for pin_params in pins:
|
||||||
|
if mcu is not None and pin_params['chip'] != mcu:
|
||||||
|
raise ppins.error("st7920 all pins must be on same mcu")
|
||||||
|
mcu = pin_params['chip']
|
||||||
|
if pin_params['invert']:
|
||||||
|
raise ppins.error("st7920 can not invert pin")
|
||||||
|
self.pins = [pin_params['pin'] for pin_params in pins]
|
||||||
|
self.mcu = mcu
|
||||||
|
self.oid = self.mcu.create_oid()
|
||||||
|
self.mcu.add_config_object(self)
|
||||||
|
self.send_data_cmd = self.send_cmds_cmd = None
|
||||||
|
self.is_extended = False
|
||||||
|
# framebuffers
|
||||||
|
self.text_framebuffer = (bytearray(' '*64), bytearray('~'*64), 0x80)
|
||||||
|
self.glyph_framebuffer = (bytearray(128), bytearray('~'*128), 0x40)
|
||||||
|
self.graphics_framebuffers = [(bytearray(32), bytearray('~'*32), i)
|
||||||
|
for i in range(32)]
|
||||||
|
self.framebuffers = ([self.text_framebuffer, self.glyph_framebuffer]
|
||||||
|
+ self.graphics_framebuffers)
|
||||||
|
def build_config(self):
|
||||||
|
self.mcu.add_config_cmd(
|
||||||
|
"config_st7920 oid=%u cs_pin=%s sclk_pin=%s sid_pin=%s"
|
||||||
|
" delay_ticks=%d" % (
|
||||||
|
self.oid, self.pins[0], self.pins[1], self.pins[2],
|
||||||
|
self.mcu.seconds_to_clock(ST7920_DELAY)))
|
||||||
|
cmd_queue = self.mcu.alloc_command_queue()
|
||||||
|
self.send_cmds_cmd = self.mcu.lookup_command(
|
||||||
|
"st7920_send_cmds oid=%c cmds=%*s", cq=cmd_queue)
|
||||||
|
self.send_data_cmd = self.mcu.lookup_command(
|
||||||
|
"st7920_send_data oid=%c data=%*s", cq=cmd_queue)
|
||||||
|
def send(self, cmds, is_data=False, is_extended=False):
|
||||||
|
cmd_type = self.send_cmds_cmd
|
||||||
|
if is_data:
|
||||||
|
cmd_type = self.send_data_cmd
|
||||||
|
elif self.is_extended != is_extended:
|
||||||
|
add_cmd = 0x22
|
||||||
|
if is_extended:
|
||||||
|
add_cmd = 0x26
|
||||||
|
cmds = [add_cmd] + cmds
|
||||||
|
self.is_extended = is_extended
|
||||||
|
cmd_type.send([self.oid, cmds], reqclock=BACKGROUND_PRIORITY_CLOCK)
|
||||||
|
#logging.debug("st7920 %d %s", is_data, repr(cmds))
|
||||||
|
def flush(self):
|
||||||
|
# Find all differences in the framebuffers and send them to the chip
|
||||||
|
for new_data, old_data, fb_id in self.framebuffers:
|
||||||
|
if new_data == old_data:
|
||||||
|
continue
|
||||||
|
# Find the position of all changed bytes in this framebuffer
|
||||||
|
diffs = [[i, 1] for i, (nd, od) in enumerate(zip(new_data, old_data))
|
||||||
|
if nd != od]
|
||||||
|
# Batch together changes that are close to each other
|
||||||
|
for i in range(len(diffs)-2, -1, -1):
|
||||||
|
pos, count = diffs[i]
|
||||||
|
nextpos, nextcount = diffs[i+1]
|
||||||
|
if pos + 5 >= nextpos and nextcount < 16:
|
||||||
|
diffs[i][1] = nextcount + (nextpos - pos)
|
||||||
|
del diffs[i+1]
|
||||||
|
# Transmit changes
|
||||||
|
for pos, count in diffs:
|
||||||
|
count += pos & 0x01
|
||||||
|
count += count & 0x01
|
||||||
|
pos = pos & ~0x01
|
||||||
|
chip_pos = pos >> 1
|
||||||
|
if fb_id < 0x40:
|
||||||
|
# Graphics framebuffer update
|
||||||
|
self.send([0x80 + fb_id, 0x80 + chip_pos], is_extended=True)
|
||||||
|
else:
|
||||||
|
self.send([fb_id + chip_pos])
|
||||||
|
self.send(new_data[pos:pos+count], is_data=True)
|
||||||
|
old_data[:] = new_data
|
||||||
|
def init(self):
|
||||||
|
cmds = [0x24, # Enter extended mode
|
||||||
|
0x40, # Clear vertical scroll address
|
||||||
|
0x02, # Enable CGRAM access
|
||||||
|
0x26, # Enable graphics
|
||||||
|
0x22, # Leave extended mode
|
||||||
|
0x02, # Home the display
|
||||||
|
0x06, # Set positive update direction
|
||||||
|
0x0c] # Enable display and hide cursor
|
||||||
|
self.send(cmds)
|
||||||
|
self.flush()
|
||||||
|
def load_glyph(self, glyph_id, data):
|
||||||
|
if len(data) > 32:
|
||||||
|
data = data[:32]
|
||||||
|
pos = min(glyph_id * 32, 96)
|
||||||
|
self.glyph_framebuffer[0][pos:pos+len(data)] = data
|
||||||
|
def write_text(self, x, y, data):
|
||||||
|
if x + len(data) > 16:
|
||||||
|
data = data[:16 - min(x, 16)]
|
||||||
|
pos = [0, 32, 16, 48][y] + x
|
||||||
|
self.text_framebuffer[0][pos:pos+len(data)] = data
|
||||||
|
def write_graphics(self, x, y, row, data):
|
||||||
|
if x + len(data) > 16:
|
||||||
|
data = data[:16 - min(x, 16)]
|
||||||
|
gfx_fb = y * 16 + row
|
||||||
|
if gfx_fb >= 32:
|
||||||
|
gfx_fb -= 32
|
||||||
|
x += 16
|
||||||
|
self.graphics_framebuffers[gfx_fb][0][x:x+len(data)] = data
|
||||||
|
def clear(self):
|
||||||
|
self.text_framebuffer[0][:] = ' '*64
|
||||||
|
zeros = bytearray(32)
|
||||||
|
for new_data, old_data, fb_id in self.graphics_framebuffers:
|
||||||
|
new_data[:] = zeros
|
||||||
|
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Icons
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
nozzle_icon = [
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000111111110000,
|
||||||
|
0b0001111111111000,
|
||||||
|
0b0001111111111000,
|
||||||
|
0b0001111111111000,
|
||||||
|
0b0000111111110000,
|
||||||
|
0b0000111111110000,
|
||||||
|
0b0001111111111000,
|
||||||
|
0b0001111111111000,
|
||||||
|
0b0001111111111000,
|
||||||
|
0b0000011111100000,
|
||||||
|
0b0000001111000000,
|
||||||
|
0b0000000110000000,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000
|
||||||
|
]
|
||||||
|
|
||||||
|
bed_icon = [
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0111111111111110,
|
||||||
|
0b0111111111111110,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000
|
||||||
|
]
|
||||||
|
|
||||||
|
heat1_icon = [
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0010001000100000,
|
||||||
|
0b0001000100010000,
|
||||||
|
0b0000100010001000,
|
||||||
|
0b0000100010001000,
|
||||||
|
0b0001000100010000,
|
||||||
|
0b0010001000100000,
|
||||||
|
0b0010001000100000,
|
||||||
|
0b0001000100010000,
|
||||||
|
0b0000100010001000,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000
|
||||||
|
]
|
||||||
|
|
||||||
|
heat2_icon = [
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000100010001000,
|
||||||
|
0b0000100010001000,
|
||||||
|
0b0001000100010000,
|
||||||
|
0b0010001000100000,
|
||||||
|
0b0010001000100000,
|
||||||
|
0b0001000100010000,
|
||||||
|
0b0000100010001000,
|
||||||
|
0b0000100010001000,
|
||||||
|
0b0001000100010000,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000
|
||||||
|
]
|
||||||
|
|
||||||
|
fan1_icon = [
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0111111111111110,
|
||||||
|
0b0111000000001110,
|
||||||
|
0b0110001111000110,
|
||||||
|
0b0100001111000010,
|
||||||
|
0b0100000110000010,
|
||||||
|
0b0101100000011010,
|
||||||
|
0b0101110110111010,
|
||||||
|
0b0101100000011010,
|
||||||
|
0b0100000110000010,
|
||||||
|
0b0100001111000010,
|
||||||
|
0b0110001111000110,
|
||||||
|
0b0111000000001110,
|
||||||
|
0b0111111111111110,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000
|
||||||
|
]
|
||||||
|
|
||||||
|
fan2_icon = [
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0111111111111110,
|
||||||
|
0b0111000000001110,
|
||||||
|
0b0110010000100110,
|
||||||
|
0b0100111001110010,
|
||||||
|
0b0101111001111010,
|
||||||
|
0b0100110000110010,
|
||||||
|
0b0100000110000010,
|
||||||
|
0b0100110000110010,
|
||||||
|
0b0101111001111010,
|
||||||
|
0b0100111001110010,
|
||||||
|
0b0110010000100110,
|
||||||
|
0b0111000000001110,
|
||||||
|
0b0111111111111110,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000
|
||||||
|
]
|
||||||
|
|
||||||
|
feedrate_icon = [
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0111111000000000,
|
||||||
|
0b0100000000000000,
|
||||||
|
0b0100000000000000,
|
||||||
|
0b0100000000000000,
|
||||||
|
0b0111111011111000,
|
||||||
|
0b0100000010000100,
|
||||||
|
0b0100000010000100,
|
||||||
|
0b0100000010000100,
|
||||||
|
0b0100000011111000,
|
||||||
|
0b0000000010001000,
|
||||||
|
0b0000000010000100,
|
||||||
|
0b0000000010000100,
|
||||||
|
0b0000000010000010,
|
||||||
|
0b0000000000000000,
|
||||||
|
0b0000000000000000
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# LCD screen updates
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
LCD_chips = { 'st7920': ST7920, 'hd44780': HD44780 }
|
||||||
|
|
||||||
|
class PrinterLCD:
|
||||||
|
def __init__(self, config):
|
||||||
|
self.printer = config.get_printer()
|
||||||
|
self.reactor = self.printer.get_reactor()
|
||||||
|
self.lcd_chip = config.getchoice('lcd_type', LCD_chips)(config)
|
||||||
|
self.lcd_type = config.get('lcd_type')
|
||||||
|
# printer objects
|
||||||
|
self.gcode = self.toolhead = self.sdcard = None
|
||||||
|
self.fan = self.extruder0 = self.extruder1 = self.heater_bed = None
|
||||||
|
# screen updating
|
||||||
|
self.screen_update_timer = self.reactor.register_timer(
|
||||||
|
self.screen_update_event)
|
||||||
|
# Initialization
|
||||||
|
FAN1_GLYPH, FAN2_GLYPH, BED1_GLYPH, BED2_GLYPH = 0, 1, 2, 3
|
||||||
|
def printer_state(self, state):
|
||||||
|
if state == 'ready':
|
||||||
|
self.lcd_chip.init()
|
||||||
|
# Load printer objects
|
||||||
|
self.gcode = self.printer.lookup_object('gcode')
|
||||||
|
self.toolhead = self.printer.lookup_object('toolhead')
|
||||||
|
self.sdcard = self.printer.lookup_object('virtual_sdcard', None)
|
||||||
|
self.fan = self.printer.lookup_object('fan', None)
|
||||||
|
self.extruder0 = self.printer.lookup_object('extruder0', None)
|
||||||
|
self.extruder1 = self.printer.lookup_object('extruder1', None)
|
||||||
|
self.heater_bed = self.printer.lookup_object('heater_bed', None)
|
||||||
|
# Load glyphs
|
||||||
|
self.load_glyph(self.BED1_GLYPH, heat1_icon)
|
||||||
|
self.load_glyph(self.BED2_GLYPH, heat2_icon)
|
||||||
|
self.load_glyph(self.FAN1_GLYPH, fan1_icon)
|
||||||
|
self.load_glyph(self.FAN2_GLYPH, fan2_icon)
|
||||||
|
# Start screen update timer
|
||||||
|
self.reactor.update_timer(self.screen_update_timer, self.reactor.NOW)
|
||||||
|
# ST7920 Glyphs
|
||||||
|
def load_glyph(self, glyph_id, data):
|
||||||
|
if self.lcd_type != 'st7920':
|
||||||
|
return
|
||||||
|
glyph = [0x00] * (len(data) * 2)
|
||||||
|
for i, bits in enumerate(data):
|
||||||
|
glyph[i*2] = (bits >> 8) & 0xff
|
||||||
|
glyph[i*2 + 1] = bits & 0xff
|
||||||
|
return self.lcd_chip.load_glyph(glyph_id, glyph)
|
||||||
|
def animate_glyphs(self, eventtime, x, y, glyph_id, do_animate):
|
||||||
|
frame = do_animate and int(eventtime) & 1
|
||||||
|
self.lcd_chip.write_text(x, y, (0, (glyph_id + frame)*2))
|
||||||
|
# Graphics drawing
|
||||||
|
def draw_icon(self, x, y, data):
|
||||||
|
for i, bits in enumerate(data):
|
||||||
|
self.lcd_chip.write_graphics(
|
||||||
|
x, y, i, [(bits >> 8) & 0xff, bits & 0xff])
|
||||||
|
def draw_progress_bar(self, x, y, width, value):
|
||||||
|
value = int(value * 100.)
|
||||||
|
data = [0x00] * width
|
||||||
|
char_pcnt = int(100/width)
|
||||||
|
for i in range(width):
|
||||||
|
if (i+1)*char_pcnt <= value:
|
||||||
|
# Draw completely filled bytes
|
||||||
|
data[i] |= 0xFF
|
||||||
|
elif (i*char_pcnt) < value:
|
||||||
|
# Draw partially filled bytes
|
||||||
|
data[i] |= (-1 << 8-((value % char_pcnt)*8/char_pcnt)) & 0xff
|
||||||
|
data[0] |= 0x80
|
||||||
|
data[-1] |= 0x01
|
||||||
|
self.lcd_chip.write_graphics(x, y, 0, [0xff]*width)
|
||||||
|
for i in range(1, 15):
|
||||||
|
self.lcd_chip.write_graphics(x, y, i, data)
|
||||||
|
self.lcd_chip.write_graphics(x, y, 15, [0xff]*width)
|
||||||
|
# Screen updating
|
||||||
|
def screen_update_event(self, eventtime):
|
||||||
|
self.lcd_chip.clear()
|
||||||
|
if self.lcd_type == 'hd44780':
|
||||||
|
self.screen_update_hd44780(eventtime)
|
||||||
|
else:
|
||||||
|
self.screen_update_st7920(eventtime)
|
||||||
|
self.lcd_chip.flush()
|
||||||
|
return eventtime + .500
|
||||||
|
def screen_update_hd44780(self, eventtime):
|
||||||
|
lcd_chip = self.lcd_chip
|
||||||
|
# Heaters
|
||||||
|
if self.extruder0 is not None:
|
||||||
|
info = self.extruder0.get_heater().get_status(eventtime)
|
||||||
|
lcd_chip.write_text(0, 0, lcd_chip.char_thermometer)
|
||||||
|
self.draw_heater(1, 0, info)
|
||||||
|
if self.extruder1 is not None:
|
||||||
|
info = self.extruder1.get_heater().get_status(eventtime)
|
||||||
|
lcd_chip.write_text(0, 1, lcd_chip.char_thermometer)
|
||||||
|
self.draw_heater(1, 1, info)
|
||||||
|
if self.heater_bed is not None:
|
||||||
|
info = self.heater_bed.get_status(eventtime)
|
||||||
|
lcd_chip.write_text(10, 0, lcd_chip.char_heater_bed)
|
||||||
|
self.draw_heater(11, 0, info)
|
||||||
|
# Fan speed
|
||||||
|
if self.fan is not None:
|
||||||
|
info = self.fan.get_status(eventtime)
|
||||||
|
lcd_chip.write_text(10, 1, "Fan")
|
||||||
|
self.draw_percent(14, 1, 4, info['speed'])
|
||||||
|
# G-Code speed factor
|
||||||
|
gcode_info = self.gcode.get_status(eventtime)
|
||||||
|
lcd_chip.write_text(0, 2, lcd_chip.char_speed_factor)
|
||||||
|
self.draw_percent(1, 2, 4, gcode_info['speed_factor'])
|
||||||
|
# SD card print progress
|
||||||
|
if self.sdcard is not None:
|
||||||
|
info = self.sdcard.get_status(eventtime)
|
||||||
|
lcd_chip.write_text(7, 2, "SD")
|
||||||
|
self.draw_percent(9, 2, 4, info['progress'])
|
||||||
|
# Printing time and status
|
||||||
|
toolhead_info = self.toolhead.get_status(eventtime)
|
||||||
|
lcd_chip.write_text(14, 2, lcd_chip.char_clock)
|
||||||
|
self.draw_time(15, 2, toolhead_info['printing_time'])
|
||||||
|
self.draw_status(0, 3, gcode_info, toolhead_info)
|
||||||
|
def screen_update_st7920(self, eventtime):
|
||||||
|
# Heaters
|
||||||
|
if self.extruder0 is not None:
|
||||||
|
info = self.extruder0.get_heater().get_status(eventtime)
|
||||||
|
self.draw_icon(0, 0, nozzle_icon)
|
||||||
|
self.draw_heater(2, 0, info)
|
||||||
|
extruder_count = 1
|
||||||
|
if self.extruder1 is not None:
|
||||||
|
info = self.extruder1.get_heater().get_status(eventtime)
|
||||||
|
self.draw_icon(0, 1, nozzle_icon)
|
||||||
|
self.draw_heater(2, 1, info)
|
||||||
|
extruder_count = 2
|
||||||
|
if self.heater_bed is not None:
|
||||||
|
info = self.heater_bed.get_status(eventtime)
|
||||||
|
self.draw_icon(0, extruder_count, bed_icon)
|
||||||
|
if info['target']:
|
||||||
|
self.animate_glyphs(eventtime, 0, extruder_count,
|
||||||
|
self.BED1_GLYPH, True)
|
||||||
|
self.draw_heater(2, extruder_count, info)
|
||||||
|
# Fan speed
|
||||||
|
if self.fan is not None:
|
||||||
|
info = self.fan.get_status(eventtime)
|
||||||
|
self.animate_glyphs(eventtime, 10, 0, self.FAN1_GLYPH,
|
||||||
|
info['speed'] != 0.)
|
||||||
|
self.draw_percent(12, 0, 4, info['speed'])
|
||||||
|
# SD card print progress
|
||||||
|
if self.sdcard is not None:
|
||||||
|
info = self.sdcard.get_status(eventtime)
|
||||||
|
if extruder_count == 1:
|
||||||
|
x, y, width = 0, 2, 10
|
||||||
|
else:
|
||||||
|
x, y, width = 10, 1, 6
|
||||||
|
self.draw_percent(x, y, width, info['progress'])
|
||||||
|
self.draw_progress_bar(x, y, width, info['progress'])
|
||||||
|
# G-Code speed factor
|
||||||
|
gcode_info = self.gcode.get_status(eventtime)
|
||||||
|
if extruder_count == 1:
|
||||||
|
self.draw_icon(10, 1, feedrate_icon)
|
||||||
|
self.draw_percent(12, 1, 4, gcode_info['speed_factor'])
|
||||||
|
# Printing time and status
|
||||||
|
toolhead_info = self.toolhead.get_status(eventtime)
|
||||||
|
self.draw_time(10, 2, toolhead_info['printing_time'])
|
||||||
|
self.draw_status(0, 3, gcode_info, toolhead_info)
|
||||||
|
# Screen update helpers
|
||||||
|
def draw_heater(self, x, y, info):
|
||||||
|
temperature, target = info['temperature'], info['target']
|
||||||
|
if target and abs(temperature - target) > 2.:
|
||||||
|
s = "%3.0f%s%.0f" % (
|
||||||
|
temperature, self.lcd_chip.char_right_arrow, target)
|
||||||
|
else:
|
||||||
|
s = "%3.0f" % (temperature,)
|
||||||
|
if self.lcd_type == 'hd44780':
|
||||||
|
s += self.lcd_chip.char_degrees
|
||||||
|
self.lcd_chip.write_text(x, y, s)
|
||||||
|
def draw_percent(self, x, y, width, value):
|
||||||
|
self.lcd_chip.write_text(x, y, ("%d%%" % (value * 100.,)).center(width))
|
||||||
|
def draw_time(self, x, y, seconds):
|
||||||
|
seconds = int(seconds)
|
||||||
|
self.lcd_chip.write_text(x, y, "%02d:%02d" % (
|
||||||
|
seconds // (60 * 60), (seconds // 60) % 60))
|
||||||
|
def draw_status(self, x, y, gcode_info, toolhead_info):
|
||||||
|
status = toolhead_info['status']
|
||||||
|
if status == 'Printing' or gcode_info['busy']:
|
||||||
|
pos = self.toolhead.get_position()
|
||||||
|
status = "X%-4.0fY%-4.0fZ%-5.2f" % (pos[0], pos[1], pos[2])
|
||||||
|
self.lcd_chip.write_text(x, y, status)
|
||||||
|
|
||||||
|
def load_config(config):
|
||||||
|
return PrinterLCD(config)
|
||||||
39
klippy/extras/fan.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# Printer cooling fan
|
||||||
|
#
|
||||||
|
# Copyright (C) 2016-2018 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
#
|
||||||
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
import pins
|
||||||
|
|
||||||
|
FAN_MIN_TIME = 0.100
|
||||||
|
|
||||||
|
class PrinterFan:
|
||||||
|
def __init__(self, config):
|
||||||
|
self.last_fan_value = 0.
|
||||||
|
self.last_fan_time = 0.
|
||||||
|
self.max_power = config.getfloat('max_power', 1., above=0., maxval=1.)
|
||||||
|
self.kick_start_time = config.getfloat('kick_start_time', 0.1, minval=0.)
|
||||||
|
printer = config.get_printer()
|
||||||
|
self.mcu_fan = pins.setup_pin(printer, 'pwm', config.get('pin'))
|
||||||
|
self.mcu_fan.setup_max_duration(0.)
|
||||||
|
cycle_time = config.getfloat('cycle_time', 0.010, above=0.)
|
||||||
|
hardware_pwm = config.getboolean('hardware_pwm', False)
|
||||||
|
self.mcu_fan.setup_cycle_time(cycle_time, hardware_pwm)
|
||||||
|
def set_speed(self, print_time, value):
|
||||||
|
value = max(0., min(self.max_power, value))
|
||||||
|
if value == self.last_fan_value:
|
||||||
|
return
|
||||||
|
print_time = max(self.last_fan_time + FAN_MIN_TIME, print_time)
|
||||||
|
if (value and value < self.max_power
|
||||||
|
and not self.last_fan_value and self.kick_start_time):
|
||||||
|
# Run fan at full speed for specified kick_start_time
|
||||||
|
self.mcu_fan.set_pwm(print_time, self.max_power)
|
||||||
|
print_time += self.kick_start_time
|
||||||
|
self.mcu_fan.set_pwm(print_time, value)
|
||||||
|
self.last_fan_time = print_time
|
||||||
|
self.last_fan_value = value
|
||||||
|
def get_status(self, eventtime):
|
||||||
|
return {'speed': self.last_fan_value}
|
||||||
|
|
||||||
|
def load_config(config):
|
||||||
|
return PrinterFan(config)
|
||||||
37
klippy/extras/heater_fan.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# Support fans that are enabled when a heater is on
|
||||||
|
#
|
||||||
|
# Copyright (C) 2016-2018 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
#
|
||||||
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
import fan, extruder
|
||||||
|
|
||||||
|
PIN_MIN_TIME = 0.100
|
||||||
|
|
||||||
|
class PrinterHeaterFan:
|
||||||
|
def __init__(self, config):
|
||||||
|
self.printer = config.get_printer()
|
||||||
|
self.heater_name = config.get("heater", "extruder0")
|
||||||
|
self.heater_temp = config.getfloat("heater_temp", 50.0)
|
||||||
|
self.fan = fan.PrinterFan(config)
|
||||||
|
self.mcu = self.fan.mcu_fan.get_mcu()
|
||||||
|
max_power = self.fan.max_power
|
||||||
|
self.fan_speed = config.getfloat(
|
||||||
|
"fan_speed", max_power, minval=0., maxval=max_power)
|
||||||
|
self.fan.mcu_fan.setup_start_value(0., max_power)
|
||||||
|
def printer_state(self, state):
|
||||||
|
if state == 'ready':
|
||||||
|
self.heater = extruder.get_printer_heater(
|
||||||
|
self.printer, self.heater_name)
|
||||||
|
reactor = self.printer.get_reactor()
|
||||||
|
reactor.register_timer(self.callback, reactor.NOW)
|
||||||
|
def callback(self, eventtime):
|
||||||
|
current_temp, target_temp = self.heater.get_temp(eventtime)
|
||||||
|
power = 0.
|
||||||
|
if target_temp or current_temp > self.heater_temp:
|
||||||
|
power = self.fan_speed
|
||||||
|
print_time = self.mcu.estimated_print_time(eventtime) + PIN_MIN_TIME
|
||||||
|
self.fan.set_speed(print_time, power)
|
||||||
|
return eventtime + 1.
|
||||||
|
|
||||||
|
def load_config_prefix(config):
|
||||||
|
return PrinterHeaterFan(config)
|
||||||
39
klippy/extras/homing_override.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# Run user defined actions in place of a normal G28 homing command
|
||||||
|
#
|
||||||
|
# Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
#
|
||||||
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
|
||||||
|
class HomingOverride:
|
||||||
|
def __init__(self, config):
|
||||||
|
self.printer = config.get_printer()
|
||||||
|
self.start_pos = [config.getfloat('set_position_' + a, None)
|
||||||
|
for a in 'xyz']
|
||||||
|
self.script = config.get('gcode')
|
||||||
|
self.in_script = False
|
||||||
|
self.gcode = self.printer.lookup_object('gcode')
|
||||||
|
self.gcode.register_command("G28", self.cmd_G28)
|
||||||
|
def cmd_G28(self, params):
|
||||||
|
if self.in_script:
|
||||||
|
# Was called recursively - invoke the real G28 command
|
||||||
|
self.gcode.cmd_G28(params)
|
||||||
|
return
|
||||||
|
# Calculate forced position (if configured)
|
||||||
|
toolhead = self.printer.lookup_object('toolhead')
|
||||||
|
pos = toolhead.get_position()
|
||||||
|
homing_axes = []
|
||||||
|
for axis, loc in enumerate(self.start_pos):
|
||||||
|
if loc is not None:
|
||||||
|
pos[axis] = loc
|
||||||
|
homing_axes.append(axis)
|
||||||
|
toolhead.set_position(pos, homing_axes=homing_axes)
|
||||||
|
self.gcode.reset_last_position()
|
||||||
|
# Perform homing
|
||||||
|
try:
|
||||||
|
self.in_script = True
|
||||||
|
self.gcode.run_script(self.script)
|
||||||
|
finally:
|
||||||
|
self.in_script = False
|
||||||
|
|
||||||
|
def load_config(config):
|
||||||
|
return HomingOverride(config)
|
||||||
54
klippy/extras/multi_pin.py
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# Virtual pin that propagates its changes to multiple output pins
|
||||||
|
#
|
||||||
|
# Copyright (C) 2017,2018 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
#
|
||||||
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
import pins
|
||||||
|
|
||||||
|
class PrinterMultiPin:
|
||||||
|
def __init__(self, config):
|
||||||
|
self.printer = config.get_printer()
|
||||||
|
try:
|
||||||
|
pins.get_printer_pins(self.printer).register_chip('multi_pin', self)
|
||||||
|
except pins.error:
|
||||||
|
pass
|
||||||
|
self.pin_type = None
|
||||||
|
self.pin_list = [pin.strip() for pin in config.get('pins').split(',')]
|
||||||
|
self.mcu_pins = []
|
||||||
|
def setup_pin(self, pin_params):
|
||||||
|
pin_name = pin_params['pin']
|
||||||
|
pin = self.printer.lookup_object('multi_pin ' + pin_name, None)
|
||||||
|
if pin is not self:
|
||||||
|
if pin is None:
|
||||||
|
raise pins.error("multi_pin %s not configured" % (pin_name,))
|
||||||
|
return pin.setup_pin(pin_params)
|
||||||
|
if self.pin_type is not None:
|
||||||
|
raise pins.error("Can't setup multi_pin %s twice" % (pin_name,))
|
||||||
|
self.pin_type = pin_params['type']
|
||||||
|
invert = ""
|
||||||
|
if pin_params['invert']:
|
||||||
|
invert = "!"
|
||||||
|
self.mcu_pins = [
|
||||||
|
pins.setup_pin(self.printer, self.pin_type, invert + pin_desc)
|
||||||
|
for pin_desc in self.pin_list]
|
||||||
|
return self
|
||||||
|
def get_mcu(self):
|
||||||
|
return self.mcu_pins[0].get_mcu()
|
||||||
|
def setup_max_duration(self, max_duration):
|
||||||
|
for mcu_pin in self.mcu_pins:
|
||||||
|
mcu_pin.setup_max_duration(max_duration)
|
||||||
|
def setup_start_value(self, start_value, shutdown_value):
|
||||||
|
for mcu_pin in self.mcu_pins:
|
||||||
|
mcu_pin.setup_start_value(start_value, shutdown_value)
|
||||||
|
def setup_cycle_time(self, cycle_time, hardware_pwm=False):
|
||||||
|
for mcu_pin in self.mcu_pins:
|
||||||
|
mcu_pin.setup_cycle_time(cycle_time, hardware_pwm)
|
||||||
|
def set_digital(self, print_time, value):
|
||||||
|
for mcu_pin in self.mcu_pins:
|
||||||
|
mcu_pin.set_digital(print_time, value)
|
||||||
|
def set_pwm(self, print_time, value):
|
||||||
|
for mcu_pin in self.mcu_pins:
|
||||||
|
mcu_pin.set_pwm(print_time, value)
|
||||||
|
|
||||||
|
def load_config_prefix(config):
|
||||||
|
return PrinterMultiPin(config)
|
||||||
69
klippy/extras/output_pin.py
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
# Code to configure miscellaneous chips
|
||||||
|
#
|
||||||
|
# Copyright (C) 2017,2018 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
#
|
||||||
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
|
||||||
|
PIN_MIN_TIME = 0.100
|
||||||
|
|
||||||
|
class PrinterOutputPin:
|
||||||
|
def __init__(self, config):
|
||||||
|
self.printer = config.get_printer()
|
||||||
|
ppins = self.printer.lookup_object('pins')
|
||||||
|
self.is_pwm = config.getboolean('pwm', False)
|
||||||
|
if self.is_pwm:
|
||||||
|
self.mcu_pin = ppins.setup_pin('pwm', config.get('pin'))
|
||||||
|
cycle_time = config.getfloat('cycle_time', 0.100, above=0.)
|
||||||
|
hardware_pwm = config.getboolean('hardware_pwm', False)
|
||||||
|
self.mcu_pin.setup_cycle_time(cycle_time, hardware_pwm)
|
||||||
|
self.scale = config.getfloat('scale', 1., above=0.)
|
||||||
|
else:
|
||||||
|
self.mcu_pin = ppins.setup_pin('digital_out', config.get('pin'))
|
||||||
|
self.scale = 1.
|
||||||
|
self.mcu_pin.setup_max_duration(0.)
|
||||||
|
self.last_value_time = 0.
|
||||||
|
static_value = config.getfloat('static_value', None,
|
||||||
|
minval=0., maxval=self.scale)
|
||||||
|
if static_value is not None:
|
||||||
|
self.is_static = True
|
||||||
|
self.last_value = static_value / self.scale
|
||||||
|
self.mcu_pin.setup_start_value(
|
||||||
|
self.last_value, self.last_value, True)
|
||||||
|
else:
|
||||||
|
self.is_static = False
|
||||||
|
self.last_value = config.getfloat(
|
||||||
|
'value', 0., minval=0., maxval=self.scale) / self.scale
|
||||||
|
shutdown_value = config.getfloat(
|
||||||
|
'shutdown_value', 0., minval=0., maxval=self.scale) / self.scale
|
||||||
|
self.mcu_pin.setup_start_value(self.last_value, shutdown_value)
|
||||||
|
self.gcode = self.printer.lookup_object('gcode')
|
||||||
|
self.gcode.register_command("SET_PIN", self.cmd_SET_PIN,
|
||||||
|
desc=self.cmd_SET_PIN_help)
|
||||||
|
cmd_SET_PIN_help = "Set the value of an output pin"
|
||||||
|
def cmd_SET_PIN(self, params):
|
||||||
|
pin_name = self.gcode.get_str('PIN', params)
|
||||||
|
pin = self.printer.lookup_object('output_pin ' + pin_name, None)
|
||||||
|
if pin is not self:
|
||||||
|
if pin is None:
|
||||||
|
raise self.gcode.error("Pin not configured")
|
||||||
|
return pin.cmd_SET_PIN(params)
|
||||||
|
if self.is_static:
|
||||||
|
raise self.gcode.error("Static pin can not be changed at run-time")
|
||||||
|
value = self.gcode.get_float('VALUE', params) / self.scale
|
||||||
|
if value == self.last_value:
|
||||||
|
return
|
||||||
|
print_time = self.printer.lookup_object('toolhead').get_last_move_time()
|
||||||
|
print_time = max(print_time, self.last_value_time + PIN_MIN_TIME)
|
||||||
|
if self.is_pwm:
|
||||||
|
if value < 0. or value > 1.:
|
||||||
|
raise self.gcode.error("Invalid pin value")
|
||||||
|
self.mcu_pin.set_pwm(print_time, value)
|
||||||
|
else:
|
||||||
|
if value not in [0., 1.]:
|
||||||
|
raise self.gcode.error("Invalid pin value")
|
||||||
|
self.mcu_pin.set_digital(print_time, value)
|
||||||
|
self.last_value = value
|
||||||
|
self.last_value_time = print_time
|
||||||
|
|
||||||
|
def load_config_prefix(config):
|
||||||
|
return PrinterOutputPin(config)
|
||||||
127
klippy/extras/pid_calibrate.py
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
# Calibration of heater PID settings
|
||||||
|
#
|
||||||
|
# Copyright (C) 2016-2018 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
#
|
||||||
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
import math, logging
|
||||||
|
import extruder, heater
|
||||||
|
|
||||||
|
class PIDCalibrate:
|
||||||
|
def __init__(self, config):
|
||||||
|
self.printer = config.get_printer()
|
||||||
|
self.gcode = self.printer.lookup_object('gcode')
|
||||||
|
self.gcode.register_command(
|
||||||
|
'PID_CALIBRATE', self.cmd_PID_CALIBRATE,
|
||||||
|
desc=self.cmd_PID_CALIBRATE_help)
|
||||||
|
cmd_PID_CALIBRATE_help = "Run PID calibration test"
|
||||||
|
def cmd_PID_CALIBRATE(self, params):
|
||||||
|
heater_name = self.gcode.get_str('HEATER', params)
|
||||||
|
target = self.gcode.get_float('TARGET', params)
|
||||||
|
write_file = self.gcode.get_int('WRITE_FILE', params, 0)
|
||||||
|
try:
|
||||||
|
heater = extruder.get_printer_heater(self.printer, heater_name)
|
||||||
|
except self.printer.config_error as e:
|
||||||
|
raise self.gcode.error(str(e))
|
||||||
|
print_time = self.printer.lookup_object('toolhead').get_last_move_time()
|
||||||
|
calibrate = ControlAutoTune(heater)
|
||||||
|
old_control = heater.set_control(calibrate)
|
||||||
|
try:
|
||||||
|
heater.set_temp(print_time, target)
|
||||||
|
except heater.error as e:
|
||||||
|
raise self.gcode.error(str(e))
|
||||||
|
self.gcode.bg_temp(heater)
|
||||||
|
heater.set_control(old_control)
|
||||||
|
if write_file:
|
||||||
|
calibrate.write_file('/tmp/heattest.txt')
|
||||||
|
Kp, Ki, Kd = calibrate.calc_final_pid()
|
||||||
|
logging.info("Autotune: final: Kp=%f Ki=%f Kd=%f", Kp, Ki, Kd)
|
||||||
|
self.gcode.respond_info(
|
||||||
|
"PID parameters: pid_Kp=%.3f pid_Ki=%.3f pid_Kd=%.3f\n"
|
||||||
|
"To use these parameters, update the printer config file with\n"
|
||||||
|
"the above and then issue a RESTART command" % (Kp, Ki, Kd))
|
||||||
|
|
||||||
|
TUNE_PID_DELTA = 5.0
|
||||||
|
|
||||||
|
class ControlAutoTune:
|
||||||
|
def __init__(self, heater):
|
||||||
|
self.heater = heater
|
||||||
|
# Heating control
|
||||||
|
self.heating = False
|
||||||
|
self.peak = 0.
|
||||||
|
self.peak_time = 0.
|
||||||
|
# Peak recording
|
||||||
|
self.peaks = []
|
||||||
|
# Sample recording
|
||||||
|
self.last_pwm = 0.
|
||||||
|
self.pwm_samples = []
|
||||||
|
self.temp_samples = []
|
||||||
|
# Heater control
|
||||||
|
def set_pwm(self, read_time, value):
|
||||||
|
if value != self.last_pwm:
|
||||||
|
self.pwm_samples.append((read_time + heater.PWM_DELAY, value))
|
||||||
|
self.last_pwm = value
|
||||||
|
self.heater.set_pwm(read_time, value)
|
||||||
|
def adc_callback(self, read_time, temp):
|
||||||
|
self.temp_samples.append((read_time, temp))
|
||||||
|
if self.heating and temp >= self.heater.target_temp:
|
||||||
|
self.heating = False
|
||||||
|
self.check_peaks()
|
||||||
|
elif (not self.heating
|
||||||
|
and temp <= self.heater.target_temp - TUNE_PID_DELTA):
|
||||||
|
self.heating = True
|
||||||
|
self.check_peaks()
|
||||||
|
if self.heating:
|
||||||
|
self.set_pwm(read_time, self.heater.max_power)
|
||||||
|
if temp < self.peak:
|
||||||
|
self.peak = temp
|
||||||
|
self.peak_time = read_time
|
||||||
|
else:
|
||||||
|
self.set_pwm(read_time, 0.)
|
||||||
|
if temp > self.peak:
|
||||||
|
self.peak = temp
|
||||||
|
self.peak_time = read_time
|
||||||
|
def check_busy(self, eventtime):
|
||||||
|
if self.heating or len(self.peaks) < 12:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
# Analysis
|
||||||
|
def check_peaks(self):
|
||||||
|
self.peaks.append((self.peak, self.peak_time))
|
||||||
|
if self.heating:
|
||||||
|
self.peak = 9999999.
|
||||||
|
else:
|
||||||
|
self.peak = -9999999.
|
||||||
|
if len(self.peaks) < 4:
|
||||||
|
return
|
||||||
|
self.calc_pid(len(self.peaks)-1)
|
||||||
|
def calc_pid(self, pos):
|
||||||
|
temp_diff = self.peaks[pos][0] - self.peaks[pos-1][0]
|
||||||
|
time_diff = self.peaks[pos][1] - self.peaks[pos-2][1]
|
||||||
|
max_power = self.heater.max_power
|
||||||
|
Ku = 4. * (2. * max_power) / (abs(temp_diff) * math.pi)
|
||||||
|
Tu = time_diff
|
||||||
|
|
||||||
|
Ti = 0.5 * Tu
|
||||||
|
Td = 0.125 * Tu
|
||||||
|
Kp = 0.6 * Ku * heater.PID_PARAM_BASE
|
||||||
|
Ki = Kp / Ti
|
||||||
|
Kd = Kp * Td
|
||||||
|
logging.info("Autotune: raw=%f/%f Ku=%f Tu=%f Kp=%f Ki=%f Kd=%f",
|
||||||
|
temp_diff, max_power, Ku, Tu, Kp, Ki, Kd)
|
||||||
|
return Kp, Ki, Kd
|
||||||
|
def calc_final_pid(self):
|
||||||
|
cycle_times = [(self.peaks[pos][1] - self.peaks[pos-2][1], pos)
|
||||||
|
for pos in range(4, len(self.peaks))]
|
||||||
|
midpoint_pos = sorted(cycle_times)[len(cycle_times)/2][1]
|
||||||
|
return self.calc_pid(midpoint_pos)
|
||||||
|
# Offline analysis helper
|
||||||
|
def write_file(self, filename):
|
||||||
|
pwm = ["pwm: %.3f %.3f" % (time, value)
|
||||||
|
for time, value in self.pwm_samples]
|
||||||
|
out = ["%.3f %.3f" % (time, temp) for time, temp in self.temp_samples]
|
||||||
|
f = open(filename, "wb")
|
||||||
|
f.write('\n'.join(pwm + out))
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
def load_config(config):
|
||||||
|
return PIDCalibrate(config)
|
||||||
189
klippy/extras/probe.py
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
# Z-Probe support
|
||||||
|
#
|
||||||
|
# Copyright (C) 2017-2018 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
#
|
||||||
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
import pins, homing
|
||||||
|
|
||||||
|
HINT_TIMEOUT = """
|
||||||
|
Make sure to home the printer before probing. If the probe
|
||||||
|
did not move far enough to trigger, then consider reducing
|
||||||
|
the Z axis minimum position so the probe can travel further
|
||||||
|
(the Z minimum position can be negative).
|
||||||
|
"""
|
||||||
|
|
||||||
|
class PrinterProbe:
|
||||||
|
def __init__(self, config):
|
||||||
|
self.printer = config.get_printer()
|
||||||
|
self.speed = config.getfloat('speed', 5.0)
|
||||||
|
self.z_offset = config.getfloat('z_offset')
|
||||||
|
# Infer Z position to move to during a probe
|
||||||
|
if config.has_section('stepper_z'):
|
||||||
|
zconfig = config.getsection('stepper_z')
|
||||||
|
self.z_position = zconfig.getfloat('position_min', 0.)
|
||||||
|
else:
|
||||||
|
pconfig = config.getsection('printer')
|
||||||
|
self.z_position = pconfig.getfloat('minimum_z_position', 0.)
|
||||||
|
# Create an "endstop" object to handle the probe pin
|
||||||
|
ppins = self.printer.lookup_object('pins')
|
||||||
|
pin_params = ppins.lookup_pin('endstop', config.get('pin'))
|
||||||
|
mcu = pin_params['chip']
|
||||||
|
mcu.add_config_object(self)
|
||||||
|
self.mcu_probe = mcu.setup_pin(pin_params)
|
||||||
|
if (config.get('activate_gcode', None) is not None or
|
||||||
|
config.get('deactivate_gcode', None) is not None):
|
||||||
|
self.mcu_probe = ProbeEndstopWrapper(config, self.mcu_probe)
|
||||||
|
# Create z_virtual_endstop pin
|
||||||
|
ppins.register_chip('probe', self)
|
||||||
|
self.z_virtual_endstop = None
|
||||||
|
# Register PROBE/QUERY_PROBE commands
|
||||||
|
self.gcode = self.printer.lookup_object('gcode')
|
||||||
|
self.gcode.register_command(
|
||||||
|
'PROBE', self.cmd_PROBE, desc=self.cmd_PROBE_help)
|
||||||
|
self.gcode.register_command(
|
||||||
|
'QUERY_PROBE', self.cmd_QUERY_PROBE, desc=self.cmd_QUERY_PROBE_help)
|
||||||
|
def build_config(self):
|
||||||
|
toolhead = self.printer.lookup_object('toolhead')
|
||||||
|
z_steppers = toolhead.get_kinematics().get_steppers("Z")
|
||||||
|
for s in z_steppers:
|
||||||
|
for mcu_endstop, name in s.get_endstops():
|
||||||
|
for mcu_stepper in mcu_endstop.get_steppers():
|
||||||
|
self.mcu_probe.add_stepper(mcu_stepper)
|
||||||
|
def setup_pin(self, pin_params):
|
||||||
|
if (pin_params['pin'] != 'z_virtual_endstop'
|
||||||
|
or pin_params['type'] != 'endstop'):
|
||||||
|
raise pins.error("Probe virtual endstop only useful as endstop pin")
|
||||||
|
if pin_params['invert'] or pin_params['pullup']:
|
||||||
|
raise pins.error("Can not pullup/invert probe virtual endstop")
|
||||||
|
self.z_virtual_endstop = ProbeVirtualEndstop(
|
||||||
|
self.printer, self.mcu_probe)
|
||||||
|
return self.z_virtual_endstop
|
||||||
|
def last_home_position(self):
|
||||||
|
if self.z_virtual_endstop is None:
|
||||||
|
return None
|
||||||
|
return self.z_virtual_endstop.position
|
||||||
|
cmd_PROBE_help = "Probe Z-height at current XY position"
|
||||||
|
def cmd_PROBE(self, params):
|
||||||
|
toolhead = self.printer.lookup_object('toolhead')
|
||||||
|
homing_state = homing.Homing(toolhead)
|
||||||
|
pos = toolhead.get_position()
|
||||||
|
pos[2] = self.z_position
|
||||||
|
try:
|
||||||
|
homing_state.homing_move(
|
||||||
|
pos, [(self.mcu_probe, "probe")], self.speed, probe_pos=True)
|
||||||
|
except homing.EndstopError as e:
|
||||||
|
reason = str(e)
|
||||||
|
if "Timeout during endstop homing" in reason:
|
||||||
|
reason += HINT_TIMEOUT
|
||||||
|
raise self.gcode.error(reason)
|
||||||
|
self.gcode.reset_last_position()
|
||||||
|
cmd_QUERY_PROBE_help = "Return the status of the z-probe"
|
||||||
|
def cmd_QUERY_PROBE(self, params):
|
||||||
|
toolhead = self.printer.lookup_object('toolhead')
|
||||||
|
print_time = toolhead.get_last_move_time()
|
||||||
|
self.mcu_probe.query_endstop(print_time)
|
||||||
|
res = self.mcu_probe.query_endstop_wait()
|
||||||
|
self.gcode.respond_info(
|
||||||
|
"probe: %s" % (["open", "TRIGGERED"][not not res],))
|
||||||
|
|
||||||
|
# Endstop wrapper that enables running g-code scripts on setup
|
||||||
|
class ProbeEndstopWrapper:
|
||||||
|
def __init__(self, config, mcu_endstop):
|
||||||
|
self.mcu_endstop = mcu_endstop
|
||||||
|
self.gcode = config.get_printer().lookup_object('gcode')
|
||||||
|
self.activate_gcode = config.get('activate_gcode', "")
|
||||||
|
self.deactivate_gcode = config.get('deactivate_gcode', "")
|
||||||
|
# Wrappers
|
||||||
|
self.get_mcu = self.mcu_endstop.get_mcu
|
||||||
|
self.add_stepper = self.mcu_endstop.add_stepper
|
||||||
|
self.get_steppers = self.mcu_endstop.get_steppers
|
||||||
|
self.home_start = self.mcu_endstop.home_start
|
||||||
|
self.home_wait = self.mcu_endstop.home_wait
|
||||||
|
self.query_endstop = self.mcu_endstop.query_endstop
|
||||||
|
self.query_endstop_wait = self.mcu_endstop.query_endstop_wait
|
||||||
|
self.TimeoutError = self.mcu_endstop.TimeoutError
|
||||||
|
def home_prepare(self):
|
||||||
|
self.gcode.run_script(self.activate_gcode)
|
||||||
|
self.mcu_endstop.home_prepare()
|
||||||
|
def home_finalize(self):
|
||||||
|
self.gcode.run_script(self.deactivate_gcode)
|
||||||
|
self.mcu_endstop.home_finalize()
|
||||||
|
|
||||||
|
# Wrapper that records the last XY position of a virtual endstop probe
|
||||||
|
class ProbeVirtualEndstop:
|
||||||
|
def __init__(self, printer, mcu_endstop):
|
||||||
|
self.printer = printer
|
||||||
|
self.mcu_endstop = mcu_endstop
|
||||||
|
self.position = None
|
||||||
|
# Wrappers
|
||||||
|
self.get_mcu = self.mcu_endstop.get_mcu
|
||||||
|
self.add_stepper = self.mcu_endstop.add_stepper
|
||||||
|
self.get_steppers = self.mcu_endstop.get_steppers
|
||||||
|
self.home_start = self.mcu_endstop.home_start
|
||||||
|
self.home_wait = self.mcu_endstop.home_wait
|
||||||
|
self.query_endstop = self.mcu_endstop.query_endstop
|
||||||
|
self.query_endstop_wait = self.mcu_endstop.query_endstop_wait
|
||||||
|
self.home_prepare = self.mcu_endstop.home_prepare
|
||||||
|
self.TimeoutError = self.mcu_endstop.TimeoutError
|
||||||
|
def home_finalize(self):
|
||||||
|
self.position = self.printer.lookup_object('toolhead').get_position()
|
||||||
|
self.mcu_endstop.home_finalize()
|
||||||
|
|
||||||
|
# Helper code that can probe a series of points and report the
|
||||||
|
# position at each point.
|
||||||
|
class ProbePointsHelper:
|
||||||
|
def __init__(self, printer, probe_points, horizontal_move_z, speed,
|
||||||
|
manual_probe, callback):
|
||||||
|
self.printer = printer
|
||||||
|
self.probe_points = probe_points
|
||||||
|
self.horizontal_move_z = horizontal_move_z
|
||||||
|
self.speed = speed
|
||||||
|
self.manual_probe = manual_probe
|
||||||
|
self.callback = callback
|
||||||
|
self.toolhead = self.printer.lookup_object('toolhead')
|
||||||
|
self.results = []
|
||||||
|
self.busy = True
|
||||||
|
self.gcode = self.printer.lookup_object('gcode')
|
||||||
|
self.gcode.register_command(
|
||||||
|
'NEXT', self.cmd_NEXT, desc=self.cmd_NEXT_help)
|
||||||
|
# Begin probing
|
||||||
|
self.move_next()
|
||||||
|
if not manual_probe:
|
||||||
|
while self.busy:
|
||||||
|
self.gcode.run_script("PROBE")
|
||||||
|
self.cmd_NEXT({})
|
||||||
|
def move_next(self):
|
||||||
|
x, y = self.probe_points[len(self.results)]
|
||||||
|
curpos = self.toolhead.get_position()
|
||||||
|
curpos[0] = x
|
||||||
|
curpos[1] = y
|
||||||
|
curpos[2] = self.horizontal_move_z
|
||||||
|
self.toolhead.move(curpos, self.speed)
|
||||||
|
self.gcode.reset_last_position()
|
||||||
|
cmd_NEXT_help = "Move to the next XY position to probe"
|
||||||
|
def cmd_NEXT(self, params):
|
||||||
|
# Record current position
|
||||||
|
self.toolhead.wait_moves()
|
||||||
|
self.results.append(self.callback.get_position())
|
||||||
|
# Move to next position
|
||||||
|
curpos = self.toolhead.get_position()
|
||||||
|
curpos[2] = self.horizontal_move_z
|
||||||
|
self.toolhead.move(curpos, self.speed)
|
||||||
|
if len(self.results) == len(self.probe_points):
|
||||||
|
self.toolhead.get_last_move_time()
|
||||||
|
self.finalize(True)
|
||||||
|
return
|
||||||
|
self.move_next()
|
||||||
|
def finalize(self, success):
|
||||||
|
self.busy = False
|
||||||
|
self.gcode.reset_last_position()
|
||||||
|
self.gcode.register_command('NEXT', None)
|
||||||
|
if success:
|
||||||
|
z_offset = 0.
|
||||||
|
if not self.manual_probe:
|
||||||
|
probe = self.printer.lookup_object('probe')
|
||||||
|
z_offset = probe.z_offset
|
||||||
|
self.callback.finalize(z_offset, self.results)
|
||||||
|
|
||||||
|
def load_config(config):
|
||||||
|
return PrinterProbe(config)
|
||||||
229
klippy/extras/replicape.py
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
# Code to configure miscellaneous chips
|
||||||
|
#
|
||||||
|
# Copyright (C) 2017,2018 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
#
|
||||||
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
import logging
|
||||||
|
import pins, mcu
|
||||||
|
|
||||||
|
REPLICAPE_MAX_CURRENT = 3.84
|
||||||
|
REPLICAPE_SHIFT_REGISTER_BUS = 1
|
||||||
|
REPLICAPE_SHIFT_REGISTER_DEVICE = 1
|
||||||
|
REPLICAPE_PCA9685_BUS = 2
|
||||||
|
REPLICAPE_PCA9685_ADDRESS = 0x70
|
||||||
|
REPLICAPE_PCA9685_CYCLE_TIME = .001
|
||||||
|
PIN_MIN_TIME = 0.100
|
||||||
|
|
||||||
|
class pca9685_pwm:
|
||||||
|
def __init__(self, replicape, channel, pin_params):
|
||||||
|
self._replicape = replicape
|
||||||
|
self._channel = channel
|
||||||
|
if pin_params['type'] not in ['digital_out', 'pwm']:
|
||||||
|
raise pins.error("Pin type not supported on replicape")
|
||||||
|
self._mcu = replicape.host_mcu
|
||||||
|
self._mcu.add_config_object(self)
|
||||||
|
self._bus = REPLICAPE_PCA9685_BUS
|
||||||
|
self._address = REPLICAPE_PCA9685_ADDRESS
|
||||||
|
self._cycle_time = REPLICAPE_PCA9685_CYCLE_TIME
|
||||||
|
self._max_duration = 2.
|
||||||
|
self._oid = None
|
||||||
|
self._invert = pin_params['invert']
|
||||||
|
self._start_value = self._shutdown_value = float(self._invert)
|
||||||
|
self._is_static = False
|
||||||
|
self._last_clock = 0
|
||||||
|
self._pwm_max = 0.
|
||||||
|
self._set_cmd = None
|
||||||
|
def get_mcu(self):
|
||||||
|
return self._mcu
|
||||||
|
def setup_max_duration(self, max_duration):
|
||||||
|
self._max_duration = max_duration
|
||||||
|
def setup_cycle_time(self, cycle_time, hardware_pwm=False):
|
||||||
|
if hardware_pwm:
|
||||||
|
raise pins.error("pca9685 does not support hardware_pwm parameter")
|
||||||
|
if cycle_time != self._cycle_time:
|
||||||
|
logging.info("Ignoring pca9685 cycle time of %.6f (using %.6f)",
|
||||||
|
cycle_time, self._cycle_time)
|
||||||
|
def setup_start_value(self, start_value, shutdown_value, is_static=False):
|
||||||
|
if is_static and start_value != shutdown_value:
|
||||||
|
raise pins.error("Static pin can not have shutdown value")
|
||||||
|
if self._invert:
|
||||||
|
start_value = 1. - start_value
|
||||||
|
shutdown_value = 1. - shutdown_value
|
||||||
|
self._start_value = max(0., min(1., start_value))
|
||||||
|
self._shutdown_value = max(0., min(1., shutdown_value))
|
||||||
|
self._is_static = is_static
|
||||||
|
self._replicape.note_pwm_start_value(
|
||||||
|
self._channel, self._start_value, self._shutdown_value)
|
||||||
|
def build_config(self):
|
||||||
|
self._pwm_max = self._mcu.get_constant_float("PCA9685_MAX")
|
||||||
|
cycle_ticks = self._mcu.seconds_to_clock(self._cycle_time)
|
||||||
|
if self._is_static:
|
||||||
|
self._mcu.add_config_cmd(
|
||||||
|
"set_pca9685_out bus=%d addr=%d channel=%d"
|
||||||
|
" cycle_ticks=%d value=%d" % (
|
||||||
|
self._bus, self._address, self._channel,
|
||||||
|
cycle_ticks, self._start_value * self._pwm_max))
|
||||||
|
return
|
||||||
|
self._oid = self._mcu.create_oid()
|
||||||
|
self._mcu.add_config_cmd(
|
||||||
|
"config_pca9685 oid=%d bus=%d addr=%d channel=%d cycle_ticks=%d"
|
||||||
|
" value=%d default_value=%d max_duration=%d" % (
|
||||||
|
self._oid, self._bus, self._address, self._channel, cycle_ticks,
|
||||||
|
self._start_value * self._pwm_max,
|
||||||
|
self._shutdown_value * self._pwm_max,
|
||||||
|
self._mcu.seconds_to_clock(self._max_duration)))
|
||||||
|
cmd_queue = self._mcu.alloc_command_queue()
|
||||||
|
self._set_cmd = self._mcu.lookup_command(
|
||||||
|
"schedule_pca9685_out oid=%c clock=%u value=%hu", cq=cmd_queue)
|
||||||
|
def set_pwm(self, print_time, value):
|
||||||
|
clock = self._mcu.print_time_to_clock(print_time)
|
||||||
|
if self._invert:
|
||||||
|
value = 1. - value
|
||||||
|
value = int(max(0., min(1., value)) * self._pwm_max + 0.5)
|
||||||
|
self._replicape.note_pwm_enable(print_time, self._channel, value)
|
||||||
|
self._set_cmd.send([self._oid, clock, value],
|
||||||
|
minclock=self._last_clock, reqclock=clock)
|
||||||
|
self._last_clock = clock
|
||||||
|
def set_digital(self, print_time, value):
|
||||||
|
if value:
|
||||||
|
self.set_pwm(print_time, 1.)
|
||||||
|
else:
|
||||||
|
self.set_pwm(print_time, 0.)
|
||||||
|
|
||||||
|
class ReplicapeDACEnable:
|
||||||
|
def __init__(self, replicape, channel, pin_params):
|
||||||
|
if pin_params['type'] != 'digital_out':
|
||||||
|
raise pins.error("Replicape virtual enable pin must be digital_out")
|
||||||
|
if pin_params['invert']:
|
||||||
|
raise pins.error("Replicape virtual enable pin can not be inverted")
|
||||||
|
self.mcu = replicape.host_mcu
|
||||||
|
self.value = replicape.stepper_dacs[channel]
|
||||||
|
self.pwm = pca9685_pwm(replicape, channel, pin_params)
|
||||||
|
def get_mcu(self):
|
||||||
|
return self.mcu
|
||||||
|
def setup_max_duration(self, max_duration):
|
||||||
|
self.pwm.setup_max_duration(max_duration)
|
||||||
|
def set_digital(self, print_time, value):
|
||||||
|
if value:
|
||||||
|
self.pwm.set_pwm(print_time, self.value)
|
||||||
|
else:
|
||||||
|
self.pwm.set_pwm(print_time, 0.)
|
||||||
|
|
||||||
|
ReplicapeStepConfig = {
|
||||||
|
'disable': None,
|
||||||
|
'1': (1<<7)|(1<<5), '2': (1<<7)|(1<<5)|(1<<6), 'spread2': (1<<5),
|
||||||
|
'4': (1<<7)|(1<<5)|(1<<4), '16': (1<<7)|(1<<5)|(1<<6)|(1<<4),
|
||||||
|
'spread4': (1<<5)|(1<<4), 'spread16': (1<<7), 'stealth4': (1<<7)|(1<<6),
|
||||||
|
'stealth16': 0
|
||||||
|
}
|
||||||
|
|
||||||
|
class Replicape:
|
||||||
|
def __init__(self, config):
|
||||||
|
printer = config.get_printer()
|
||||||
|
pins.get_printer_pins(printer).register_chip('replicape', self)
|
||||||
|
revisions = {'B3': 'B3'}
|
||||||
|
config.getchoice('revision', revisions)
|
||||||
|
self.host_mcu = mcu.get_printer_mcu(printer, config.get('host_mcu'))
|
||||||
|
# Setup enable pin
|
||||||
|
self.mcu_pwm_enable = pins.setup_pin(
|
||||||
|
printer, 'digital_out', config.get('enable_pin', '!P9_41'))
|
||||||
|
self.mcu_pwm_enable.setup_max_duration(0.)
|
||||||
|
self.mcu_pwm_start_value = self.mcu_pwm_shutdown_value = False
|
||||||
|
# Setup power pins
|
||||||
|
self.pins = {
|
||||||
|
"power_e": (pca9685_pwm, 5), "power_h": (pca9685_pwm, 3),
|
||||||
|
"power_hotbed": (pca9685_pwm, 4),
|
||||||
|
"power_fan0": (pca9685_pwm, 7), "power_fan1": (pca9685_pwm, 8),
|
||||||
|
"power_fan2": (pca9685_pwm, 9), "power_fan3": (pca9685_pwm, 10) }
|
||||||
|
# Setup stepper config
|
||||||
|
self.send_spi_cmd = None
|
||||||
|
self.last_stepper_time = 0.
|
||||||
|
self.stepper_dacs = {}
|
||||||
|
shift_registers = [1, 0, 0, 1, 1]
|
||||||
|
for port, name in enumerate('xyzeh'):
|
||||||
|
prefix = 'stepper_%s_' % (name,)
|
||||||
|
sc = config.getchoice(
|
||||||
|
prefix + 'microstep_mode', ReplicapeStepConfig, 'disable')
|
||||||
|
if sc is None:
|
||||||
|
continue
|
||||||
|
sc |= shift_registers[port]
|
||||||
|
if config.getboolean(prefix + 'chopper_off_time_high', False):
|
||||||
|
sc |= 1<<3
|
||||||
|
if config.getboolean(prefix + 'chopper_hysteresis_high', False):
|
||||||
|
sc |= 1<<2
|
||||||
|
if config.getboolean(prefix + 'chopper_blank_time_high', True):
|
||||||
|
sc |= 1<<1
|
||||||
|
shift_registers[port] = sc
|
||||||
|
channel = port + 11
|
||||||
|
cur = config.getfloat(
|
||||||
|
prefix + 'current', above=0., maxval=REPLICAPE_MAX_CURRENT)
|
||||||
|
self.stepper_dacs[channel] = cur / REPLICAPE_MAX_CURRENT
|
||||||
|
self.pins[prefix + 'enable'] = (ReplicapeDACEnable, channel)
|
||||||
|
self.enabled_channels = {ch: False for cl, ch in self.pins.values()}
|
||||||
|
if config.getboolean('servo0_enable', False):
|
||||||
|
shift_registers[1] |= 1
|
||||||
|
if config.getboolean('servo1_enable', False):
|
||||||
|
shift_registers[2] |= 1
|
||||||
|
self.sr_disabled = tuple(reversed(shift_registers))
|
||||||
|
if [i for i in [0, 1, 2] if 11+i in self.stepper_dacs]:
|
||||||
|
# Enable xyz steppers
|
||||||
|
shift_registers[0] &= ~1
|
||||||
|
if [i for i in [3, 4] if 11+i in self.stepper_dacs]:
|
||||||
|
# Enable eh steppers
|
||||||
|
shift_registers[3] &= ~1
|
||||||
|
if (config.getboolean('standstill_power_down', False)
|
||||||
|
and self.stepper_dacs):
|
||||||
|
shift_registers[4] &= ~1
|
||||||
|
self.sr_enabled = tuple(reversed(shift_registers))
|
||||||
|
self.host_mcu.add_config_object(self)
|
||||||
|
self.host_mcu.add_config_cmd("send_spi bus=%d dev=%d msg=%s" % (
|
||||||
|
REPLICAPE_SHIFT_REGISTER_BUS, REPLICAPE_SHIFT_REGISTER_DEVICE,
|
||||||
|
"".join(["%02x" % (x,) for x in self.sr_disabled])))
|
||||||
|
def build_config(self):
|
||||||
|
cmd_queue = self.host_mcu.alloc_command_queue()
|
||||||
|
self.send_spi_cmd = self.host_mcu.lookup_command(
|
||||||
|
"send_spi bus=%u dev=%u msg=%*s", cq=cmd_queue)
|
||||||
|
def note_pwm_start_value(self, channel, start_value, shutdown_value):
|
||||||
|
self.mcu_pwm_start_value |= not not start_value
|
||||||
|
self.mcu_pwm_shutdown_value |= not not shutdown_value
|
||||||
|
self.mcu_pwm_enable.setup_start_value(
|
||||||
|
self.mcu_pwm_start_value, self.mcu_pwm_shutdown_value)
|
||||||
|
self.enabled_channels[channel] = not not start_value
|
||||||
|
def note_pwm_enable(self, print_time, channel, value):
|
||||||
|
is_enable = not not value
|
||||||
|
if self.enabled_channels[channel] == is_enable:
|
||||||
|
# Nothing to do
|
||||||
|
return
|
||||||
|
self.enabled_channels[channel] = is_enable
|
||||||
|
# Check if need to set the pca9685 enable pin
|
||||||
|
on_channels = [1 for c, e in self.enabled_channels.items() if e]
|
||||||
|
if not on_channels:
|
||||||
|
self.mcu_pwm_enable.set_digital(print_time, 0)
|
||||||
|
elif is_enable and len(on_channels) == 1:
|
||||||
|
self.mcu_pwm_enable.set_digital(print_time, 1)
|
||||||
|
# Check if need to set the stepper enable lines
|
||||||
|
if channel not in self.stepper_dacs:
|
||||||
|
return
|
||||||
|
on_dacs = [1 for c in self.stepper_dacs.keys()
|
||||||
|
if self.enabled_channels[c]]
|
||||||
|
if not on_dacs:
|
||||||
|
sr = self.sr_disabled
|
||||||
|
elif is_enable and len(on_dacs) == 1:
|
||||||
|
sr = self.sr_enabled
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
print_time = max(print_time, self.last_stepper_time + PIN_MIN_TIME)
|
||||||
|
clock = self.host_mcu.print_time_to_clock(print_time)
|
||||||
|
# XXX - the send_spi message should be scheduled
|
||||||
|
self.send_spi_cmd.send([REPLICAPE_SHIFT_REGISTER_BUS,
|
||||||
|
REPLICAPE_SHIFT_REGISTER_DEVICE, sr],
|
||||||
|
minclock=clock, reqclock=clock)
|
||||||
|
def setup_pin(self, pin_params):
|
||||||
|
pin = pin_params['pin']
|
||||||
|
if pin not in self.pins:
|
||||||
|
raise pins.error("Unknown replicape pin %s" % (pin,))
|
||||||
|
pclass, channel = self.pins[pin]
|
||||||
|
return pclass(self, channel, pin_params)
|
||||||
|
|
||||||
|
def load_config(config):
|
||||||
|
return Replicape(config)
|
||||||