Go Down

Topic: AS5600 magnetic sensor deadband (Read 353 times) previous topic - next topic

AleBKK

Hello people, I've been working on building an actuator using an AS5600 on the control and servo sides to measure the position using the analog output from the sensor; the basic idea is that the control wheel is turned, the AS5600 there measures the angle, an Arduino does its PIDy thing and turns a motor until the angle in the servo matches the control position.
So far so good except for the fact that there is a deadband, or as the datasheet puts it "...if the range is 360 degrees, to avoid discontinuity points exactly at the limit of the range, a 10-LSB hysteresis is applied. This hysteresis suppresses toggling the OUT pin when the magnet is close to zero or 360 degrees.".
The consequence of that is that it's not possible to have control over the full 360 degrees of range, over that hysteresis gap turning the control doesn't move the actuator which ends up jumping from one side of the gap to the other.

The datasheet includes information about a CONF register that can be reprogrammed via I2C, I have no experience changing registers using I2C so before I go down that rabbit hole I thought I better ask in case anyone knows if that hysteresis setting affects the analog output hysteresis or if it only affects the ANGLE register values, from the datasheet it's not clear what the case is.

The TL;DR version is, is it possible to reduce or eliminate the deadband in the AS5600 sensor so that it can produce a continuous angle input over the full rotation?

Thanks a bunch.

As an added question, I did retrieve data using I2C from the sensor, from both the RAW ANGLE and the ANGLE, however both are extremely noisy, unusable really, is that normal?

MarkT

The datasheet is the definitive guide, often they take several rereadings to intuit the design intention of the chip's interface.  AS do lots of other rotary magnetic encoder chips, I've used the AS5040 without issues its got an incremental encoder output, PWM output and a synchronous serial absolute output...  Only 10 bit but you're deluding yourself about getting greater accuracy than that from a hall sensor.  If you want high accuracy and linear behaviour an optical encoder is the right choice.
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

AleBKK

The datasheet is the definitive guide, often they take several rereadings to intuit the design intention of the chip's interface.  AS do lots of other rotary magnetic encoder chips, I've used the AS5040 without issues its got an incremental encoder output, PWM output and a synchronous serial absolute output...  Only 10 bit but you're deluding yourself about getting greater accuracy than that from a hall sensor.  If you want high accuracy and linear behaviour an optical encoder is the right choice.
I'm not looking for high accuracy, the problem is there is a discontinuity in the motion of the actuator caused by, I think, the hysteresis setting in the PWM. My question was if it is possible to reduce or eliminate this problem by changing the settings in the configuration register.
Besides, because of size constrains an optical encoder is a not really an option.

I made a screenshot of the serial plotter showing the problem as the control dial is turned, as you can see there's a flat response at the top when the hysteresis kicks in, what I'd like to is to eliminate that flat response or reduce it as much as possible.



Here's the code I'm using at the moment, running on an Arduino Nano:

Code: [Select]
#include <Wire.h>
#include <SparkFun_TB6612.h>

int motorCtrlMap;

double ctrlPos, actPos, motorCtrl;
double kp = 2, ki = 0, kd = 0;
unsigned long currentTime, previousTime;
double elapsedTime;
double error;
double lastError;
double cumError, rateError;
int outCons;
#define AIN1 11
#define AIN2 12
#define PWMA 10
#define STBY 13
const int offsetA = 1;
Motor motor1 = Motor(AIN1, AIN2, PWMA, offsetA, STBY);

void setup()
{
  ctrlPos = analogRead(A0);
  pinMode(STBY, OUTPUT);
  pinMode(PWMA, OUTPUT);
  pinMode(AIN1, OUTPUT);
  pinMode(AIN2, OUTPUT);
  Wire.begin();
  Serial.begin(9600);
}

void loop() {

  ctrlPos = analogRead(A0);
  actPos = analogRead(A1);
  motorCtrl = computePID(actPos);
  motorCtrlMap = map(motorCtrl, 0, 1023, 255, -255);
  Serial.print(1023);
  Serial.print(" ");
  Serial.print(0);
  Serial.print(" ");
  Serial.print(ctrlPos);
  Serial.print("  ");
  Serial.print(actPos);
  Serial.print("  ");
  Serial.println(motorCtrl);
  if ((motorCtrl <= -10) || (motorCtrl >= 10)) {
    motor1.drive(motorCtrl);
  }
  else {
    motor1.drive(0);
  }

}

double computePID(double inp) {
  currentTime = millis();                //get current time
  elapsedTime = (double)(currentTime - previousTime);        //compute time elapsed from previous computation

  error = ctrlPos - inp;                                // determine error
  if (error > 512) error -= 1023;
  if (error < -512) error += 1023;
  cumError += (error * (elapsedTime / 1000));            // compute integral
  rateError = (error - lastError) / elapsedTime; // compute derivative

  //double out = kp * error + (ki * cumError);          //PID output
  double out = kp * error + (ki * cumError) + (kd * rateError);          //PID output
  outCons = constrain(out, -250, 250);

  lastError = error;                                //remember current error
  previousTime = currentTime;                        //remember current time

  return outCons;                                        //have function return the PID output
}

AleBKK

I uploaded to Thingiverse the parts for 3D printing the thing I'm working on, in case someone may be interested:

https://www.thingiverse.com/thing:4030416

Go Up