Motor move to position issue

Hi all,

I have a 14 pole-pair motor with a AS5047P encoder (ABI interface, 4096 CPR) and seem to have configured the index and able to do some position control after loose tuning, but the move_to_pos() function only works across a small range of counts, about 5900.
It may be an encoder issue, but I am not sure. Any ideas on what could be a cause of this?

I have verified that the actual number of magnet poles matches what was in the datasheet of the motor; as for the encoder, I am assuming it is on the default mode of 4096 counts.

I managed to set up the encoder with index signal, and it searches for the index at startup.
The only issue I had so far with this encoder is that I had to relax the accuracy of encoder counts during calibration (encoder.config.calib_range = 0.05), to overcome error ERROR_CPR_OUT_OF_RANGE.

Another issue, probably related, is that the velocity and current control modes do not work.

Position plots (blue=pos_estimate, orange=pos_setpoint):


I can add to this that although I didn’t directly check CPR, that this 5900 count range is roughly 1.5 turns by eyeballing, which is roughly 5900/4096, so on first observation the resolution setting seems to agree with the default value of the AS5047P.

Anyone?

In fact velocity and current control seem to start off OK, but they hit this same artificial position limit that the motor will not move away from, as if some secondary position control was in action. Can only turn a bit over half a rev each way.

Motor turns freely by hand when unpowered, and positional feedback seems fine, for multiple revs.

My issue was very similar to this one, but I tried changing over to 3.3V encoder operation with no difference:

Hi,

This one looks like a hard issue to solve remotely, so possibly why no reply, or someone maybe looking into it. My initial thoughts are the index pulse is not correct as the demanded position goes past a certain point with the motor stopping and then recovering once t comes back past the same point, as if it tries to find the index pulse past 4096 counts but stops the motor at 902 counts past either direction (4096 + (2 x 902) = 5900).

I would look at the index pulse first, its configuration or changing the Counts Per Revolution if configurable.

Could you connect the AS5047P into a separate microcontroller and set the ODrive to sensorless control so that you could test and get confidence in the encoder’s output? (Just a test).

I may be way off, although it’s hard to judge and may give you a starting point.

Hope that help,

Kind Regards,

Neil.

Thank you for the reply, interesting observations! I will try this out.

1 Like

I cobbled together some Arduino code and can detect the A/B pulses while running in sensorless mode, which looks good.

Unfortunately I haven’t yet been able to detect the index pulse using the code below.
I don’t have a scope at hand right now, so I’ll try and troubleshoot as much as I can until I can observe the index.

// https://playground.arduino.cc/Main/RotaryEncoders/

// PIN definition
#define encoderPinA 2
#define encoderPinB 3
#define encoderPinI 4

//unsigned int lastReportedPos = 0;
volatile long int encoderPos = 0;
volatile int IdxCount = 0;
volatile boolean isASet = false;
volatile boolean isBSet = false;

void setup()
{
  pinMode(encoderPinA, INPUT_PULLUP);
  pinMode(encoderPinB, INPUT_PULLUP);
  pinMode(encoderPinI, INPUT_PULLUP);

  attachInterrupt(digitalPinToInterrupt(encoderPinA), doEncoderA, CHANGE);
  attachInterrupt(digitalPinToInterrupt(encoderPinB), doEncoderB, CHANGE);
  attachInterrupt(digitalPinToInterrupt(encoderPinI), doEncoderI, RISING);
}

void loop()
{
  //if (lastReportedPos != encoderPos) {
  //  Serial.print("Index:");
  //  Serial.print(encoderPos, DEC);
  //  Serial.println();
  //  lastReportedPos = encoderPos;
  //}
  Serial.print(encoderPos, DEC);
  Serial.print(",");
  Serial.print(IdxCount, DEC);
  Serial.println();
  delay(10);
}

void doEncoderA()
{
  // Test transition
  isASet = digitalRead(encoderPinA) == HIGH;
  // and adjust counter + if A leads B
  encoderPos += (isASet != isBSet) ? +1 : -1;
}

void doEncoderB()
{
  // Test transition
  isBSet = digitalRead(encoderPinB) == HIGH;
  // and adjust counter + if B follows A
  encoderPos += (isASet == isBSet) ? +1 : -1;
}

void doEncoderI()
{
  IdxCount++;
}

My bad, just using a wrong interrupt pin on the Arduino!

Index pulse is being registered:

Just by simple observation it is looking OK.

Success!
It was indeed the index issue, and the solution is so obvious it hurts! From datasheet:

I was for some reason going with the fact that 4096 was mentioned a lot on the forums, and seemed like the default, but it was only a few counts away from 4000!

2 Likes

Yep, the default is 4000 for the 5047p, annoyingly. But the calibration check for this does error out :wink:

1 Like

Glad you got it sorted, it was just a hunch from me.