I’m currently working on a project that needs very cheap contactless angular position sensing, and I ended up trying to develop a custom solution. SimpleFOC provided a convenient platform for prototyping the concept, so I thought it would be nice to write a sensor driver for this technique to let other people use it easily.
You can have a look at a rough draft for the documentation here if you want a detailed explanation, but this is the TLDR:
Two analog linear hall sensors placed very specifically around the outer edge of a bldc motor can pick up a non-symmetrical waveform from the motor’s own magnets, that the microcontroller can sample and use to find relative shaft angle
~20 cents per sensor in single quantity, no cost for magnets
Off-axis from the motor’s axle
Specific sensor location for each motor part number (note: not each individual motor though)
Requires fast and frequent analog sampling
Requires a computationally expensive trig function
Many factors can degrade performance of the sensor
Here are some pictures of the setup:
Note the two sot23-3 packages on the perfboard suspended right above the motor, these are the two hall sensors
The sensor can only tell absolute angle within one electrical revolution, due to the way it uses the motor’s own magnets. This is not good enough for absolute shaft angle, so at best it acts exactly the same way as e.g. an incremental optical encoder does when interacting with SimpleFOC, which means a calibration routine upon every power-on.
I definitely don’t have as much experience with brushless motors as some of the people here, so anyone who knows more can feel free to chime in. But the impression I get is that a vast majority of the brushless motors that have integrated sensing use digital hall sensors, which give you something like six counts per electrical revolution. This is great for trapezoidal commutation, as the hall signal can be used to define both the timing and the step number of the next step in the commutation sequence, even at very low speeds, but it’s practically useless for FOC commutation. Using linear analog hall sensors like above gives much finer angular resolution, which is much better suited for FOC.
Awesome work, I think you have here one of the cheapest solutions that are good enough for position control. I think a lot of people here will find this work valuable and we’ll find it implemented in some projects soon.
Awesome! This may actually be less trouble in terms of sensor placement than digital hall sensors, since you don’t have to worry about the angular position of the sensors relative to the stator. Plus two sensors is two thirds the work soldering tiny wires and capacitors EDIT: Even better, it looks like 49e hall sensors don’t even need filtering capacitors.
And you could switch to 8-bit ADC when the motor gets above a certain speed so you can use higher ADC clock rate to reduce the reading time. Lower precision values, but higher accuracy since less time delay means the values you have are closer to the actual rotor position.
What sort of range are you getting on the voltage throughout the cycle?
I’m getting very little range with the sensor placements shown in the pdf. Only about four counts out of 1024 with the sensor placed 3mm below the lip of a 35mm diameter 12N14P motor. If I hold it directly against the outside of the rotor and slide it around, I get about ten counts of range (0x20c to 0x216). Measuring with multimeter on the sensor pin I get 2.571-2.6v (working out the math by hand, that should be 0x20e to 0x214 on the ADC).
I also tried a 28mm motor which doesn’t have a ring on the base so I can get the sensor right against the underside of the lip, and it gives similar poor results. However if I push the sensor just a little farther inside the motor then I get much greater range, about 0x1dc-0x248 (108 counts). But I wonder if the output would still be sinusoidal in there, and if the field from the nearby stator coils would interfere too much.
Do you think my motors are just too well made and don’t leak enough flux to use this kind of sensor? Or do they come in different sensitivity ranges and I got the wrong kind? Any other ideas I could try?
Based on the picture in my initial post, it looks like I was getting somewhere in the vicinity of 0.7V amplitude, and my hall sensors came from aliexpress if it makes any difference.
Could you please post some pictures of your setup, or provide links to the motors you are using? Otherwise, the best feedback I can offer is that it is very likely that the back-iron on your motors is too thick to let any magnetic field through as you suspect. It is fairly easy to tell if a motor will work by checking whether something metal will stick to the rotor shell with any substantial force, and about half of my motors won’t even attract a paperclip.
I have also looked at the second sensor orientation with the oscilloscope, with the halls under the motor lip, and the waveform looked pretty decent to me. I think the magnetic field from the magnets dominates the magnetic field generated by the stator coils, but this is just anecdotal for now. The challenge with this sensor placement is the sharper curvature of the magnetic field in the area under the lip makes it much harder to achieve optimal positioning and signal amplitude.
And yes, it looks like just not enough leakage flux on most motors to use this technique. The only one I have that feels at all magnetic on the outside is Racerstar BR4114. I’ll try the inside positioning and see what sort of signal quality I get, but it will have to wait until next time I’m machining a custom stator mount. I’ll include pockets for three digital hall sensors, plus a fourth pocket that’s positioned relative to one of the others for a second linear hall so I can test that first.
Thanks for the update, I actually also have the 2208 T-motor, and testing it with the linear halls shows basically zero output just as you have seen. All of the motors you are using have the unfortunate feature of a flux redirection plate on the bottom that blocks direct access to the magnets.
Alrighty, got my stator mount done, and this technique is looking more viable now. In the first photo with the sensors properly in the pockets, I get a total range of 96 counts out of 1024 on the ADC. That might work but still seems a little low, so I tried hot gluing a sensor up on top of the 1mm high pocket wall. That puts it very close to contacting the rotor, but gets 280 counts. Next time I think I’ll split the difference and raise the pockets up 0.5mm or a bit more (I made several mistakes in the machining of this one so it’s sort of a throwaway anyway).
Now there is the issue of how to actually read them. The DYS SN40A ESC that I’m currently using only has one unused ADC pin, so I’d have to irreversibly modify it to get both sensors readable. I also have a B-G431B-ESC1, but they don’t have easily accessible ADC pins either. There are two itsy bitsy solder pads, one labeled TP3 that connects to pin 18 (PB1/ADC1_IN12), and the other unlabeled but visibly connected to pin 10 (PA2/ADC1_IN3), but I’m not sure if I can hit them without taking out any other little SMD components.
Hopefully Valentine will come through with the Lepton board, with easily accessible ADC pins and even higher current capacity I may just work with the digital hall sensors for now.