I’ve been restoring an old Technics turntable. Within about five minutes of pulling it apart, I discovered that the original driver chip (now unobtainium) had burnt out. I thought, “How hard could it be?” and decided to throw together an Arduino-based replacement for the old board. That was six months ago. :')
Initial open-loop tests left me feeling super optimistic, but the problems really began when I transitioned to closed-loop control. At first, I tried to reuse the motor’s original position-sensing mechanism, but variable-reluctance sensing turned out to be essentially black magic. In theory it’s doable, but it really needs analog sense circuitry and signal amplification—none of which I could be bothered with. So I opted for Hall-effect sensors instead, since they’re readily available and supported by SimpleFOC…or so I thought.
My local electronic hobby store only sells Linear Hall sensors, which I did not realise until after I had installed them, arranged in a 120° array, which—so far as I can tell—isn’t officially supported. Fortunately, implementing that was easier than getting VR sensors to work. The code actually works now, I just need to tie it into an Arduino script, so I figured it’s as good a time as any to post a little progress report. Mostly to motivate me to finish the thing.
Better yet, use the LinearHall class to get a high resolution angle.
Normally it uses two sensors spaced 90°, but 120° can be done using a custom ReadLinearHalls function like this:
void ReadLinearHalls(int hallA, int hallB, int *a, int *b) {
*a = analogRead(hallA);
*b = analogRead(hallB);
*b = *a * _1_SQRT3 + *b * _2_SQRT3;
}
That’s based on the logic of CurrentSense::getABCurrents:
It essentially converts two 120° spaced vector components into 90° spaced, which is then converted to an angle with atan2 by the LinearHall class like usual.
Ideally you would want to read all 3 sensors and use them like in the last case of getABCurrents, or change which two you read to exclude the one that’s closest to its sine wave peak, where accuracy suffers since the change in reading per change in angle is small. It should give better precision than two sensors spaced 90 degrees.
It would be a bit hacky, but you could pack two pin numbers into one of the variables when initializing the LinearHall class, and then unpack them like this:
void ReadLinearHalls(int hallA, int hallBC, int *a_out, int *b_out) {
int a = analogRead(hallA);
int b = analogRead(hallBC & 0xff);
int c = analogRead(hallBC >> 8);
int mid = (a + b + c) / 3;
a -= mid;
b -= mid;
*a_out = a;
*b_out = _1_SQRT3 * a + _2_SQRT3 * b;
}
That’s the idea behind using the clarke transform. The output of which is two sine waves 90 degrees opposed, ideal for atan2. If I just add that function immediately before any atan2 it should just work™
e.g:
Also I had to go through and add a whole bunch of pinC logic where relevant but that was trivial.
Granted it won’t be as fast, but for my use case it’s probably not going to be noticeable. It certainly works and is a lot more elegant than my disaster spaghetti code.