AS5600 "jamming"

Hi everyone.
I am using AS5600 with some cheap drone motors and Nucleo-F411RE. But the output of magnetic sensors seems odd.
When using the sensor alone(magnetic_sensor_i2c_example) the angle is regular, 6.28 per round.
But in the close loop control mode the sensor will jammed in fer seconds after motor.init() everytime. More detailed is the angle is freezed at a value like this:


Sometimes it needs unplug the power of AS5600 to reset the output.
Any idea?

Hi @hbozyq,

A few things to check:

  • Check your magnet polarisation. Often the magnets delivered with the AS5600 are wrong.
  • Check that you connected the DIR port of the AS5600. Leaving this connector open can result in malfunctions in the I2C communication.
  • Check if you maybe need to add pull up resistors.

Otherwise can you confirm to us that open loop mode is working correcty?

The magnet is diametrically magnetised.
DIR is pulled up.
I2C is pulled up with 3.3k to 5v.

Oke that is great, then we can exclude these things!

Can you tell us a bit more about your hardware setup (which driver are you using?) and code?

  • Does open loop control work?
  • Do you also have this jamming issue without serial connection?
  • Do you also have this issue after you removed the power from the system?

Open loop control works.

  • Do you also have this jamming issue without serial connection?
    Yep.
  • Do you also have this issue after you removed the power from the system?
    Yep.

Hardware: My custom shield(link) + NUCLEO-F411RE
Both work great with hall sensor.

Code:

#include <SimpleFOC.h>

InlineCurrentSense current_sense = InlineCurrentSense(0.01, 20.0, PA0, PA4);

MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);

BLDCMotor motor = BLDCMotor(7);
BLDCDriver3PWM driver = BLDCDriver3PWM(PB4,PA7,PB10);


void setup() {
  current_sense.init();
  motor.linkCurrentSense(&current_sense);

  Wire.setClock(400000);
  sensor.init();
  motor.linkSensor(&sensor);

  driver.voltage_power_supply = 12;
  driver.init();
  motor.linkDriver(&driver);


  motor.controller = MotionControlType::torque;
  motor.torque_controller = TorqueControlType::foc_current;

  motor.PID_current_q.P = 30;
  motor.PID_current_q.I= 800;
  motor.PID_current_d.P= 10;
  motor.PID_current_d.I = 200;
  motor.LPF_current_q.Tf = 0.02; 
  motor.LPF_current_d.Tf = 0.02; 

  motor.PID_velocity.P = 0.1;
  motor.PID_velocity.I = 1;
  motor.PID_velocity.D = 0.000;
  motor.LPF_velocity.Tf = 0.05;

  motor.current_limit = 1.2;
  
  motor.voltage_limit = 1.5;

  Serial.begin(115200);
  motor.useMonitoring(Serial);
  motor.monitor_variables = 0b1111111;
  motor.monitor_downsample = 100;
  
  motor.init();

  motor.initFOC();

  _delay(1000);
}


void loop() {
  motor.loopFOC();
  
  motor.move(0.1);

  motor.monitor();

}

Even openloop the jamming hapened.

code:
//Open loop motor control example
#include <SimpleFOC.h>

MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);

// BLDC motor & driver instance
BLDCMotor motor = BLDCMotor(7);
BLDCDriver3PWM driver = BLDCDriver3PWM(PB4,PA7,PB10);

// Stepper motor & driver instance
//StepperMotor motor = StepperMotor(50);
//StepperDriver4PWM driver = StepperDriver4PWM(9, 5, 10, 6,  8);


//target variable
float target_velocity = 0;

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

void setup() {

  // driver config
  // power supply voltage [V]
  driver.voltage_power_supply = 12;
  driver.init();
  // link the motor and the driver
  motor.linkDriver(&driver);

  // limiting motor movements
  motor.voltage_limit = 1;   // [V]
  motor.velocity_limit = 5; // [rad/s] cca 50rpm
 
  // open loop control config
  motor.controller = MotionControlType::velocity_openloop;

  // init motor hardware
  motor.init();

  // add target command T
  command.add('T', doTarget, "target velocity");

  Wire.setClock(400000);
  sensor.init();

  Serial.begin(115200);
  Serial.println("Motor ready!");
  Serial.println("Set target velocity [rad/s]");
  _delay(1000);
}

void loop() {

  // open loop velocity movement
  // using motor.voltage_limit and motor.velocity_limit
  motor.move(target_velocity);
  Serial.print(sensor.getAngle());
  Serial.print("\t");
  Serial.println(sensor.getVelocity());
  // user communication
  command.run();
}

Basically is openloop velocity plus sensor test example.
At the very beginning the angle is normal but soon freezed.

Can you try playing with i2c clock speeds?

Wire.setClock(100000); // or 400000 or 1000000;

I find it best to call the above immediately after sensor.init();

It feels like a noise or pullup problem on sda or scl. 3.3K pullups seem sensible - you might want to go a bit lower if choosing 1M clock speed. Can you shorten these wires or move them away from other wires (including each other).

I fix the problem after replaced the cable. Thanks for all your help!
Now I wonder how to change i2c pins.
eg:PB7 to PB9.
I have tried like this, but it doesnt work.

  Wire.setClock(400000);
  Wire.setSDA(PB9);
  Wire.setSCL(PB8);
  sensor.init(&Wire);
1 Like

Good to hear you’ve got it working. With stm32, typically each i2c bus has a choice of two pin maps. You need to check what alternate pins can be used using datasheet or device config tool that comes with stm cube ide.

Im also experiencing a problem like this on my Nucleo-F411RE with the MPU6050. It sometimes just stops the main loop. I have heard that Wire.h is causing that problem if the SCL pin is disconnected for a brief moment. Do you think that there might be a disconnect because of interference in the wires? If so would a shielded wire help? Im also using the SimpleFOCShields pullup resistors for I2C.

I regularly shove an additional 1 or 2k pullup resistor between sda and v3.3 (or 5v). You can usually find somewhere to shove it in without soldering e.g. into the back of the 2.54mm connector near the i2c device. Sda seems to cause me more issues but I’ve occasionally done sda and scl. I’ve also done this with hall sensors.

Faster i2c (400k and 1M) typically require lower (more powerful) pullups.

Finally found it. setClock() should be called AFTER sensor.init().
so the code should like:

Wire.setSDA(PB9);
Wire.setSCL(PB8);
sensor.init(&Wire);
Wire.setClock(400000);

Just taking notes for someone who have the same problem.

3 Likes

I’ve found this to be different on different MCUs. For STM32 after is good, but ESP32 wants it before, IIRC.