Over the last few months I’ve been experimenting with hall effect angle sensors attached to the back of stepper motors. This is a follow up to some of the work I did on the Mechaduino ( Mechaduino experiment ). However, in the mechaduino code the goal was to be able to react to changing sensor readings with low-latency (eg, for closed-loop support). In contrast, the goal of my recent work with angle sensors is to gather large amounts of data for off-line analysis. A similar type of development approach that the adxl345 accelerometer code uses. (And, indeed, some interesting results were found comparing the data and timing between the angle sensors and accelerometer.)
The main reason I have not proposed merging this into the main Klipper repository is that I’m uncertain about the current angle calibration code. These angle sensors are surprisingly accurate, but they do need calibration to get to that accuracy (likely because the magnet glued to the back of the stepper shaft is never 100% centered). The current calibration code seems to work okay, but it does require numpy to be installed.
any luck with pushing this (or at least part of it) to master?
I’m concerned about closed-loop support because with 1.5mm nozzle and 1.1mm layer height there are often problems with missing steps because of nozzle hitting obstacles from previous layers.
Small bubbles becomes huge monster godzilla bubbles with such nozzle and even infill can pop up causing obstacles for nozzle when getting cold.
Also I’m very against using BTT/MKS driver shields:
they have built in driver (I don’t like what I can’t replace)
it’s a lot of useless parts there, we need only sensor and magnet, klipper can handle everything else
they often create “salmon skin” artefacts on side surfaces
So I’d be super glad (and guess many other users) if klipper would have native support for a1333, as5047d, and tle5012b (maybe even cheap as5600?) sensors.
I can order bunch of those sensors and help with testing and some coding if needed.
I finally ordered a bunch of sensors and magnets, couple that you mentioned and couple new.
Guess it won’t be a problem for me to add calibration routine for them (AS5600, MT6701),
but adding closed loop support might be challenging, because I never looked deeply into your architecture.
Good thing is it looks like >50% already implemented there (calibration and logging).
Do you know anyone making closed loop errors fixing watch process or are you going to implement it?
P.s.: still thinking those MKS/BTT servo boards are huge overkill because klipper can do the same and even better (because it can be editted and modified easily).
Unfortunately, my experience led me to believe that implementing a traditional “closed loop” driver would be high effort and have a high risk of failure. My rough conclusion is that minor overshoot on typical stepper motors is common and correcting it with a closed loop feedback system will likely lead to “salmon skin” effects. That is, I fear correcting motor position is likely to result in worse quality.
That said, I think it may be possible to use the sensors to characterize a stepper motor driver and use that to calibrate the motion system to send slightly modified commands - so as to improve positional accuracy in a predictive way. (A kind of “feed forward” system.) Alas, this is likely very complex.
I’m not currently working on this and don’t have any short or medium term plans to work on it. I don’t know of anyone else currently working on it.
I’m thinking about rough compensation in case motor missed steps - if it hit something, in my case layers gets switched up to 10mm by X\Y, so need to try get back to something that could be called valid position and continue.
It’s not correcting motor position all the time, it’s “watch for some specified delta in what we see on motor shaft and what it should be and if it happens - get it back until that delta is eliminated”.
So watchdog process looks for errors printing in usual way, if error occurs - it’s emergency situation, stop printing and eliminate discrepancy in supposed position and current drive shaft position.
When done - continue normal printing.
As I see klipper has enough quality of prints when mechanics are OK and these sensors should be used only to fix specified discrepancy delta. Because when obstacle occurs, it’s not couple missed steps there, motor misses a lot of steps and looses torque untill it rebounds back. Usually it happens on start of movement with huge acceleration and low speed. With constant low speed and no acceleration same place can be crossed OK.
You are very welcome to share your thoughts, because someone of us will be doing this code I guess, if not you - then me
Well, for what it’s worth, I fear that may be a “lot of development effort to enable a low quality result”. If the steppers lose steps (which always occurs in multiples of 4 full steps) then almost certainly the print quality will suffer dramatically. I’d personally prefer to work on “development that facilitates excellent quality results”.
That said, I understand that some machines and processes require compromises. If that’s something you want to work on, then go for it!
It took a while, but I got a bunch of sensors working (in arduino for now).
Ordered TLE5012 and AS5047D as bare MCU’s, because PCB’s with them were unreasonably expensive, so made PCB’s myself.
What was surprising is that MT6701 is way more precise than any of TLE5012 and AS5047D,
it doesn’t even tremble in 0.01 degree, really smooth (14bits), while TLE5012 trembles around 0.02 deg from time to time on turned off motor.
AS5047D had worst documentation, and it trembles a lot, though I did everything I could find about it’s PCB:
it works nearly as bad as AS5600, which is dirt cheap, but only I2C\PWM.
so got a bunch of questions here:)
which sensors\boards did you use? any pictures or PCB schemes?
what about tremble/accuracy on still motor? 0.02 deg for all or less, or …?
looks like you use only SPI/SSI, without I2C, is it because it’s too slow for this? (I could make MT6701 to work in SSI, need to add code for it to klipper, so asking a lot here)
can I send you my code for review to add MT6701 support? Or create pull request? It cost like 5-6 times less than TLE5012 and AS5047D on their PCB’s, nearly as low as 3$, it can add more attention to these sensors. Though it doesn’t have any ready to use libs or code examples, but it works really smooth.
I didn’t observe any issues with precision or reliability with the tle5012b - the least significant bit can fluctuate a little, but I’ve seen that on all the sensors I’ve tested.
I’m not familiar with the MT6701. I don’t see an issue with adding support for it if someone wants to do that work.
sorry, but I won’t have time to add this into klipper till summer or even autumn(
just sharing my code for MT6701 (for arduino, SPI mode), might help someone,
because it took quite time to find it’s small datasheet and make something from it (because it’s a mess with errors).
code
const int CLOCK_PIN = 13;
const int DATA_PIN = 12;
const int CS_PIN = 10;
const int BIT_COUNT = 24;
void setup() {
//setup our pins
pinMode(DATA_PIN, INPUT);
pinMode(CLOCK_PIN, OUTPUT);
pinMode(CS_PIN, OUTPUT);
//give some default values
digitalWrite(CS_PIN, LOW);
digitalWrite(CLOCK_PIN, HIGH);
Serial.begin(115200);
}
void loop() {
unsigned long reading = readPosition();
if (reading != 0) {
Serial.print("Reading: ");
Serial.println(reading);
}
delay(500);
}
//read the current angular position
unsigned long readPosition() {
// Read the same position data twice to check for errors
unsigned long sample1 = shiftIn(DATA_PIN, CLOCK_PIN, BIT_COUNT);
delayMicroseconds(25); // Clock mus be high for 20 microseconds before a new sample can be taken
unsigned long sample2 = shiftIn(DATA_PIN, CLOCK_PIN, BIT_COUNT);
if (sample1 != sample2)
return 0;
return sample1;
}
//read in a byte of data from the digital input of the board.
unsigned long shiftIn(const int data_pin, const int clock_pin, const int bit_count) {
unsigned long data = 0;
digitalWrite(CS_PIN, LOW);
delayMicroseconds(1);
for (int i=0; i<bit_count; i++) {
data <<= 1;
digitalWrite(clock_pin,LOW);
delayMicroseconds(1);
digitalWrite(clock_pin,HIGH);
delayMicroseconds(1);
data |= digitalRead(data_pin);
}
digitalWrite(CS_PIN, HIGH);
return data;
}
I think MT6701 is not worth it, it is easier to get it working with I2C.
So, no new protocols, no new commands.
However, because of the current ready-to-use infrastructure and some historical limitations (we do not have high-speed i2c sensors), I think this way is also too much work.
SSI should be enough.
MT6816 - is the stupidest one, can just return 14-bit angle data. It can replace MT6701. (I’m not sure it’s worth it, low resolution, and no calibration).
Better latency ~ 1us.
MT6826S - nice, 15-bit encoder with calibration capabilities, in some ways like TLE5012B. Lattecy ~ 10us.
There is also an interesting MT6835 which costs comparable to TLE5012B but has a 21-bit resolution (Sic!). It is like MT6826.
My current plan is to:
Test accuracy data They are more accurate than my motors.
Check if there are enough resolution to tune TMC5160. enough
Maybe play around with a closed loop as an error detection mechanism. All those sensors have latency and they can’t be used for real-time correction, but if there is a constant lag detected, like 4-8 full steps - why not? Maybe just macro to home XY again (Pause and home usually help with such a thing).
It should be fun to: decrease current, move the toolhead by hand, and see how it is returned back
UPD:
Check CRC/Parity is important.
This is the before and after for MT6826S:
About MT6701,
On the other hand, SSI can be used as SPI - do not connect MOSI, and guess the right mode.
Cause now I’m more or less familiar with angle code and MT* family.
I can try to implement pulling of data, if someone has one and is willing to test it.
(you can DM me, here or on Klipper Discord)