As you can see the LUT is much, much smoother as the linear interpolation the plot is applying (I checked, the code is also using linear interpolation) is not being stairstepped by un-interpolated super-resolution.
There needs to be some work done here to improve this, it is quite likely that for many motors this lack of interpolation actively degrades performance.
Unfortunately even the smooth LUT with proper high resolution was not sufficient to allow my extreme encoder side offset to function. I’m frankly not sure why, it may just be entirely outside of the operational bounds of the sensor. For now I’ll explore different options as I’m running out of time for my project. I hope this knowledge here helps someone fix the code.
Can you use that concept at all, if your sensor is side mounted? After all, at first glance, the geometry is very different. I did not fully think this through though, just a thought.
Hmm, I think that is indeed a bug left over from before the lut size was optional. I think n_ticks should be calculated as n_lut/_NPP rather than 5*_NPP.
But yeah, pointing the sensor at the side of a magnet probably won’t work. Can you explain the mechanical constraints? Most of my designs don’t have access to the end of the shaft at all, so my favorite solution is two 49E linear halls sensing the rotor magnets (can’t do high-precision angle control, but good enough to spin a BLDC). But if you’re able to mount a magnet on the end of the shaft, I don’t see why you can’t also get the encoder over the end of the shaft. Unless it’s a non-ferrous shaft with a magnet embedded in it rather than stuck on the end, in which case you could use two linear halls spaced 90 degrees.
I have a few of these cheap aliexpress 2204 motors, which come with a diametric ring magnet on the end. I was trying to make a PCB which sits in a ring around the base of the motor, soldered onto the exposed pins. That way I could have kept the through-hole available while keeping a very low vertical profile. I am very constrained in vertical space for my usecase. For now I have settled for pressing a 3mm diametric magnet into the end of the hollow shaft and putting a sensor over that. Fills the hole, but gives me the low profile I need. Unfortunately a simple hall sensor won’t work, this is a gimbal motor, it almost never moves fast, but it needs to be very precise.
Linear halls will be good then. I can mail you a few if you’d like. I have a bunch and they can go in a regular envelope so the cost is negligible. You’ll have to experimentally figure out the appropriate distance for them to get a good signal without saturating. For improved accuracy, use this calibration class I wrote a few weeks ago (and just now cleaned up enough to post on github):
I can’t currently spare the time to mess with that, but it’s definitely an idea for the future. You sure shipping is acceptable? I may post at unreasonable times, but I do still reside in germany.
I assume linear halls measure strength of the magnetic field in one location, so with two offset 90° you can tell exact position of the magnet?
Looks like it would be $1.70, so no problem. And yes, they give a roughly sinusoidal output as the shaft rotates, so you can convert them to an angle with atan2, or use that calibration class which steps the motor in open loop and records the sensor values at each position so it doesn’t actually matter if it’s sinusoidal or not (and since it avoids using readings near the peak of the wave, it can tolerate a little bit of saturation before the flattening of the peak reaches outside the exclusion zone).
Huh this is a bit issue! I’ve tried but wasn’t really able to reproduce this. I did not try with a stepper yet though.
What sensor were you using?
Also if you have some time you can try the new version, maybe it resolves this issue. There was a fmod call in the previous solution that could be at the origin of the issue.
I commented on the implementation on github. TL/DR: I don’t think doing the extrapolation is a good idea, we should instead allow some leeway in the lut size to fit the pole pair count.
I have also observed similar behavior to as described, though as discussed my case was rather extreme. With it I occasionally got it to behave for a bit of the segment, and less so in others. This may be due to the calibration just running out of precision in the extremes of the spectrum, especially with the low resolution of 5 ticks per pole pair that was hardcoded until you fixed it just now.
Did you see the PM I sent? There should be a green envelope icon up at the top right of the screen over your user icon.
That seems to have fixed it. Everywhere holds strongly now. However there is a bug in the constructor: the calculation of lut_resolution is reciprocal of how it’s done in calibrate(), so it doesn’t work when reloading the saved table.
It still has a bit more velocity variation throughout the revolution than my integer calibration, but it’s not bad. Probably just due to the fact that I average the readings from two laps in each direction rather than just one, or perhaps smoother motion from not pausing at each step position (I wish I’d noticed the settle_time_ms argument and tried setting it to 0). These motors are super sensitive to angle offset. The sensor I’m using is AS5048A, and it really slows down at one point in the revolution without calibration.
P.S. You can save several cycles for the cost of 2 bytes here: float lut_entry_higher = decodeOffsetU16(calibrationLut[ lut_index >= n_lut-1 ? 0 : (lut_index + 1)]);
If you add an extra entry to the table and copy the first entry to it, you can do calibrationLut[lut_index + 1] without checking.
Also, I’d suggest making voltage_calibration an argument to the calibrate function rather than a member variable, since it’s a waste of RAM during normal use. And have it default to NOT_SET (or do away with it entirely) and use motor.voltage_sensor_align instead, since that will generally be the same anyway.