Issues switching from open to closed loop control

Hi all,

I’ve gotten to the point where I’ve set up my B-G431B-ESC1 board with this 14 pole motor and an AS5600, and it all seems to work well enough in open loop velocity control mode. The motor spins fairly well, and the encoder readout is correct at 6.28 radians per motor revolution. However, if I set MotionControlType::torque (or any of the other closed loop control types), I can’t obtain a useful response from the motor other than initFOC’s alignment routine. find_pole_pairs_number.ino correctly estimates the pole count of my motor like so:

Estimated PP : 7
PP = Electrical angle / Encoder angle 
2160.00/309.02 = 6.99

And yet afterwards, the motor fails to respond in any way other than vibrate erratically or heat up. Moreover, setting phase_resistance to its correct value (specified to be 0.6 ohm, which I’ve confirmed to be close enough with a multimeter) results in no motion at all, even during initFOC, so I have to either leave it unset or set it to a much higher value than it actually is–to around 3-6 ohm–to get it to move at all. Are there any troubleshooting steps that come to mind? Thanks in advance for any help, and here’s my current code:

#include <Arduino.h>
#include <SimpleFOC.h>

BLDCMotor motor = BLDCMotor(7);
BLDCDriver6PWM driver = BLDCDriver6PWM(PA8, PC13, PA9, PA12, PA10, PB15);
MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);

//target variable
float target_velocity = 0;

// instantiate the commander
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&target_velocity, cmd); }

void disableMotor(char* cmd) { motor.disable(); }
void enableMotor(char* cmd) { motor.enable(); }

void setup() {
  Serial.begin(115200);
  
  motor.useMonitoring(Serial);
  Wire.setClock(400000);
  Wire.begin();
  sensor.init(&Wire);
  
  driver.voltage_power_supply = 24;
  driver.init();
  // link the motor and the driver
  motor.linkDriver(&driver);
  motor.linkSensor(&sensor);
  
  // limiting motor movements
  motor.voltage_limit = 4; // have tried up to 5V
  motor.velocity_limit = 5;
  motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
  
  motor.torque_controller = TorqueControlType::voltage;
  motor.phase_resistance = 6; // have to either set this an order of magnitude higher or leave unset for things to work at all
  
  motor.voltage_sensor_align = 5;
  motor.controller = MotionControlType::torque;

  // have tried various values for these to get MotionControlType::velocity to work
  motor.PID_velocity.P = 0.5;
  motor.PID_velocity.I = 20;
  motor.PID_velocity.D = 0;

  // have tried with and without this filter
  // velocity low pass filtering time constant
  // the lower the less filtered
  //motor.LPF_velocity.Tf = 0.001;
  
  // init motor hardware
  motor.init();
  motor.initFOC();
  
  command.add('T', doTarget, "target value");
  command.add('D', disableMotor, "disable");
  command.add('E', enableMotor, "enable");
  
  Serial.print("phase resistance: ");
  Serial.println(motor.phase_resistance);
  _delay(1000);
}

unsigned long last_print = 0;
unsigned long cycle_count = 0;

void loop() {
  motor.loopFOC();
  motor.move(target_velocity);
  
  command.run();

  cycle_count++;

  unsigned long now_us = _micros();
  if ((now_us - last_print) > 500000) {
    Serial.print(cycle_count);
    cycle_count = 0;
    Serial.print(" ");
    Serial.print(sensor.getVelocity());
    Serial.print(" ");
    Serial.println(sensor.getAngle());

    last_print = now_us;
  }
}

Hi @typingkate,

Welcome to the forum!

It sounds a lot like a magnet polarisation problem! Lots of the AS5600s are delivered with the wrong magnets (axially magnetized). The readout can also be correct even with the wrong magnet. You need diametrically magnetized magnets. A easy way to check is with a compass. If the compass spins nicely when you turn the magnet, then you have the correct one!

If you have the correct magnet, then another thing to check, is to ground the direction port. Leaving this open can also cause problems in closed loop mode!

1 Like

I think you can set the phase resistance in constructor of bldc motor (2nd arg?). If you set the phase resistance then I suspect simplefoc expects you to set motor.current_limit (perhaps instead of voltage limit). I think internally by setting phase resistance, simplefoc derives voltage using v = i * r.
Not something I’ve played with so stand to be corrected.
Many, many people have been caught out with wrong magnets.

This is way overdue, but I wanted to share my success rather than leave the topic on a cliffhanger! I now have angle control. The one change I can think of is that I’ve switched to using an AS5047P, interfaced to the board using A/B/I. I suspect that the AS5600 either didn’t have enough resolution, output stability (especially during erratic motion), or that there was an issue with the I2C bus (sometimes it would hang requiring a power cycle of the encoder). I’m still using the same magnet, so I don’t think it’s the magnet polarization. I still haven’t checked it with a compass, but I found and ordered them looking for diametrically magnetized magnets, making sure that the description explicitly stated the fact. I have some more magnets coming in that I ordered from a separate supplier (once again making sure they are diametrically magnetized), so I will at least have another opportunity to see if there’s any difference, but regardless, it finally works! Anyway, here’s some video (the Uno is only there to configure the encoder over SPI):

video 1
video 2

Thanks to both of you (alongside all the others, especially SimpleFOCStudio was very helpful) for your help and for making all of this work freely available.

2 Likes