Experimenting with magnetic absolute encoders

Motivation

I needed to measure the accelerator pedal position on a electrical vehicle I was building. At first I used a regular potentiometer which worked just fine but it quickly became clear that a potentiometer would not survive for long where it was located. I was looking for a more solid state method of sensing the position. I needed to translate a rotary motion into a digital position signal in a way that was resistant to water and dirt.

Measuring the direction of a magnetic field

I wanted to try using a magnetometer to sense the direction of the magnetic field from a small magnet. For this first experiment I used a TLV493 3-axis magnetometer. This device has 3 individual axes which can be read using I2C.  For sensing rotation in one plane I only used two axes:

By placing the magnet right on top of the sensor the magnetic field can be read from two directions:

To resolve the rotation of the magnet the ATAN2 function can be used to covert these two magnitudes back to an angle value.  This method will only tell you what direction the magnet is pointing but not how many times it has spun around. After passing 360 degrees the direction will abruptly jump back to 0 degrees and vice versa.

I made a demo application that illustrates this.

 

Apart from the direction of the magnetic field the strength can also be deducted from the two signals. This is used in the application above to determine if the magnet is in place or removed.

For the demo I used Arduino and the TLV493D-A1B6 library by Infineon to read the sensor. The meat of the code is essentially:

    Tlv493dMagnetic3DSensor.updateData();
    float x = Tlv493dMagnetic3DSensor.getX();
    float y = Tlv493dMagnetic3DSensor.getY();
    float w = atan2(x, y);

The result in ‘w’ is the angle in radians. The examples supplied with the library demonstrates all that is needed to get the device connected and working.

This is a solved problem

It turns out that there are many devices that directly performs this measurement and convert it into rotation. A quick internet search led me to the MT6701 from MagnTek. This device internally performs the above calculation and lets the user read out the rotation directly with high precision.

I bought a bunch of small boards on eBay containing this chip:

The board conveniently comes with a small radially polarized magnet that makes mounting much easier.

The only Arduino Library for the MT6701 I could find was for ESP32 microcontroller and depended on some FreeRTOS features. I took the liberty of snipping the business end of the code:

#include <Wire.h>
int readCount() {
  uint8_t data[2];
  Wire.beginTransmission(0x06);
  Wire.write(0x03);                   // Starting register ANGLE_H
  Wire.endTransmission(false);        // End transmission, but keep the I2C bus active
  Wire.requestFrom(0x06, 2);  // Request two bytes
  unsigned long startTime = millis();
  if (Wire.available() < 2) {
    return -1;
  }
  int angle_h = Wire.read();
  int angle_l = Wire.read();
  return (angle_h << 6) | angle_l;  // returns value from 0 to 16383
}
void setup() {
  Serial.begin(115200);
  Wire.begin();
  Wire.setClock(400000);
}
void loop() {
  Serial.println(readCount());
  delay(100);
}

The above code just read out the magnet angle as a 14-bit(0-16283) number.

The chip has other features that are _NOT_ reflected in the above code such as pushbutton functionality and analog/PWM output.

Keeping the dirt out

Since I needed to 3D print some sort of holder for the sensor and magnet combo I decided to try and print them as a one piece captive print. With this method two objects are printed simultaneously with one inside the other effectively allowing one to move inside the other while still being held in place unable to escape:

The magnet is placed in cavity of a rotating body- and the sensor on the bottom of a stationary body.  The sensor and magnet are thus separated by a dust and waterproof shell:

I printed several prototypes to see how much clearance was needed to break the two parts apart after printing. On my printer 0.3mm. seem to be a good distance.

I could have completely imbedded the magnet inside the printed part by stopping the print and inserting the magnet. Since this was only a test I opted to just have a long channel that the magnet was pressed into so I could re use it later. The sensor board is held in place with a couple of small screws:

It should be pretty straight forward to adapt the above design for all sorts of rotational sensing that need to exist in a rough environment.

Conclusion

This experiment started out to explore if you could use some sort of solid state technique to measure rotation of a EV throttle pedal. This totally works and seem pretty useful specially by using a dedicated chip to simplify the calculations. I was however really surprised by the accuracy of the method. I expected to get a ‘good enough for a foot pedal’ reading but accuracy and repeatability of this system is much better than I anticipated.

I have often used quadrature encoders for things like servo systems or for precise angle measurements thinking that was the only game in town. Now I know that there are other methods and that they comes with the benefit of being absolute and semi- solid state.

 

Leave a Reply