AS5048 skip calibration

Hello!

My English is not very good, I hope you can understand it.

I am trying to make the motor skip calibration and keep current angle.

Sometimes is work,
Sometimes the motor keeps going in the same direction.
Sometimes the motor does not rotate(electric current:0.4~0.5A).
Sometimes the motor CCW and CW speeds are different.

driver: L6234
position sensors: AS5048A
microcontroller: ESP32

simplefoc v 2.0.1

My Code


#include <SimpleFOC.h>
#include <SPI.h>



#define   BLDC1_MOSI2 23
#define   BLDC1_MISO2 19
#define   BLDC1_SCLK2 18
#define   BLDC1_CS2   5

#define   BLDC1_INH_A 25
#define   BLDC1_INH_B 26
#define   BLDC1_INH_C 27
#define   BLDC1_EN_GATE 33

// SPI Magnetic sensor instance (AS5047U example)
// MISO PB14
// MOSI PB15
// SCK PB13
MagneticSensorSPI sensor = MagneticSensorSPI(BLDC1_CS2, 14, 0x3FFF);

//SPIClass SPI_2(BLDC1_MOSI2, BLDC1_MISO2, BLDC1_SCLK2);
SPIClass * SPI_2 = NULL;

// BLDC motor instance
BLDCMotor motor_1 = BLDCMotor(14);
// driver instance
BLDCDriver3PWM driver_1 = BLDCDriver3PWM(BLDC1_INH_A, BLDC1_INH_B, BLDC1_INH_C, BLDC1_EN_GATE);

void initMotor1 () {

  //SCLK = 18, MISO = 19, MOSI = 23, SS = 5
  SPI_2 = new SPIClass(VSPI);
  
  // initialise magnetic sensor hardware
  sensor.init(SPI_2);
  Serial.println("initMotor1-1");
  // link the motor to the sensor
  motor_1.linkSensor(&sensor);

  
  // driver config
  // power supply voltage [V]
  driver_1.voltage_power_supply = 12 ;
  driver_1.init();
  // link driver
  motor_1.linkDriver(&driver_1);
  
  // choose FOC modulation (optional)
  motor_1.foc_modulation = FOCModulationType::SpaceVectorPWM;

  // set motion control loop to be used
  motor_1.controller = ControlType::angle;

  // contoller configuration 
  // default parameters in defaults.h

  // velocity PI controller parameters
  motor_1.PID_velocity.P = 1;
  motor_1.PID_velocity.I = 110;
  motor_1.PID_velocity.D = 0;
  motor_1.PID_velocity.output_ramp = 1000;
  // maximal voltage to be set to the motor
  motor_1.voltage_limit = 6;
  
  // velocity low pass filtering time constant
  // the lower the less filtered
  motor_1.LPF_velocity.Tf = 0.01;

  // angle P controller 
  motor_1.P_angle.P = 20;
  // maximal velocity of the position control
  motor_1.velocity_limit = 40;

  
  // comment out if not needed
  motor_1.useMonitoring(Serial);

  delay(1000);
  // initialize motor
  motor_1.init();
  // align sensor and start FOC
  motor_1.initFOC(sensor.getAngle());
//  motor_1.target = 0;
//  motor_1.shaftAngle();
 
}

void setup() {

  // use monitoring with serial 
  Serial.begin(115200);

  _delay(1000);
  initMotor1();
  _delay(1000);

  
  Serial.println("Full control example: ");
  Serial.println("Run user commands to configure and the motor (find the full command list in docs.simplefoc.com) \n ");
  Serial.println("Initial motion control loop is voltage loop.");
  Serial.println("Initial target voltage 2V.");
  
  _delay(1000);
}

void loop() {
  motor_1.loopFOC();
  
  motor_1.move();
  motor_1.command(serialReceiveUserCommand());
  
}


// utility function enabling serial communication the user
String serialReceiveUserCommand() {
  
  // a string to hold incoming data
  static String received_chars;
  
  String command = "";

  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the string buffer:
    received_chars += inChar;

    // end of user input
    if (inChar == '\n') {
      
      // execute the user command
      command = received_chars;

      // reset the command buffer 
      received_chars = "";
    }
  }
  return command;
}

Hey @Aaron,

Have you tried to run the example for finding zero offset?
There you should find the motor/sensor zero offset and the natural direction. After that you can just provide those values to the initFOC(offset, direction).
Since Arduino doesn’t have permanent memory, we cannot remember that value in between calls.
But if you run the example and copy the values to you code you should be set. :smiley:

Hi @Antun_Skuric
Thank you for your reply .

I changed my code

motor_1.initFOC(3.6501, Direction::CW);

3.6501 is Run example 《find_zero_offset_and_direction》 output value.
And
I don’t know how to keep the current angle when the motor is powered on(ControlType::angle).

Hey @Aaron,

Sorry for the delay, perfect, well done!

If you wish for the motor to start holding the position it is initially in you just need to change the initial target value.

After initFOC just add the line:

motor.target = motor.shaft_angle; // or sensor.getAngle();

Of it you are using something like motor.move(target_angle); make sure to initialise the target_angle to the initial sensor position. Something like:

float target_angle = motor.shaft_angle; // or sensor.getAngle();

Hi @Antun_Skuric
Thank you for your reply .

After initFOC add the line:

motor.target = sensor.getAngle();

But the motor will shake one time after initialization.

All Code

/**
 * 
 * STM32 Bluepill position motion control example with magnetic sensor
 * 
 * The same example can be ran with any STM32 board - just make sure that put right pin numbers.
 * 
 */
#include <SimpleFOC.h>
#include <SPI.h>



#define   BLDC1_MOSI2 23
#define   BLDC1_MISO2 19
#define   BLDC1_SCLK2 18
#define   BLDC1_CS2   5


#define   BLDC2_M_PWM 4 
#define   BLDC2_M_OC 16
#define   BLDC2_OC_ADJ 17

#define   BLDC1_INH_A 25
#define   BLDC1_INH_B 26
#define   BLDC1_INH_C 27
#define   BLDC1_EN_GATE 33

// SPI Magnetic sensor instance (AS5047U example)
// MISO PB14
// MOSI PB15
// SCK PB13
MagneticSensorSPI sensor = MagneticSensorSPI(BLDC1_CS2, 14, 0x3FFF);

//SPIClass SPI_2(BLDC1_MOSI2, BLDC1_MISO2, BLDC1_SCLK2);
SPIClass * SPI_2 = NULL;

// BLDC motor instance
BLDCMotor motor_1 = BLDCMotor(14);
// driver instance
BLDCDriver3PWM driver_1 = BLDCDriver3PWM(BLDC1_INH_A, BLDC1_INH_B, BLDC1_INH_C, BLDC1_EN_GATE);

void initMotor1 () {

  // DRV8302 specific code
  // M_OC  - enable overcurrent protection
  pinMode(BLDC2_M_OC, OUTPUT);
  digitalWrite(BLDC2_M_OC, LOW);
  // M_PWM  - enable 3pwm mode
  pinMode(BLDC2_M_PWM, OUTPUT);
  digitalWrite(BLDC2_M_PWM, HIGH);
  // OD_ADJ - set the maximum overcurrent limit possible
  // Better option would be to use voltage divisor to set exact value
  pinMode(BLDC2_OC_ADJ, OUTPUT);
  digitalWrite(BLDC2_OC_ADJ, HIGH);
  
  //SCLK = 18, MISO = 19, MOSI = 23, SS = 5
  SPI_2 = new SPIClass(VSPI);
  
  // initialise magnetic sensor hardware
  sensor.init(SPI_2);
  Serial.println("initMotor1-1");
  // link the motor to the sensor
  motor_1.linkSensor(&sensor);

  
  // driver config
  // power supply voltage [V]
  driver_1.voltage_power_supply = 24 ;
  driver_1.init();
  // link driver
  motor_1.linkDriver(&driver_1);
  
  // choose FOC modulation (optional)
  motor_1.foc_modulation = FOCModulationType::SpaceVectorPWM;

  // set motion control loop to be used
  motor_1.controller = ControlType::angle;

  // contoller configuration 
  // default parameters in defaults.h

  // velocity PI controller parameters
  motor_1.PID_velocity.P = 0.05;
  motor_1.PID_velocity.I = 30;
  motor_1.PID_velocity.D = 0;
  // maximal voltage to be set to the motor
  motor_1.voltage_limit = 6;
  
  // velocity low pass filtering time constant
  // the lower the less filtered
  motor_1.LPF_velocity.Tf = 0.01;

  // angle P controller 
  motor_1.P_angle.P = 20;
  // maximal velocity of the position control
  motor_1.velocity_limit = 40;

  
  // comment out if not needed
  motor_1.useMonitoring(Serial);
  
  delay(1000);
  // initialize motor
  motor_1.init();
  // align sensor and start FOC
//  delay(100);
//  motor_1.initFOC();
//  motor_1.target = sensor.getAngle();
  motor_1.initFOC(3.6501, Direction::CW);
  delay(100);
//  sensor.initRelativeZero();
  motor_1.target = motor_1.shaft_angle;

//  motor_1.shaftAngle();
 
}

void setup() {

  // use monitoring with serial 
  Serial.begin(115200);

  _delay(1000);
  initMotor1();
  _delay(1000);

  
  Serial.println("Full control example: ");
  Serial.println("Run user commands to configure and the motor (find the full command list in docs.simplefoc.com) \n ");
  Serial.println("Initial motion control loop is voltage loop.");
  Serial.println("Initial target voltage 2V.");
  
  _delay(1000);
}

void loop() {
  motor_1.loopFOC();
  
  motor_1.move();
  motor_1.command(serialReceiveUserCommand());
  
}


// utility function enabling serial communication the user
String serialReceiveUserCommand() {
  
  // a string to hold incoming data
  static String received_chars;
  
  String command = "";

  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the string buffer:
    received_chars += inChar;

    // end of user input
    if (inChar == '\n') {
      
      // execute the user command
      command = received_chars;

      // reset the command buffer 
      received_chars = "";
    }
  }
  return command;
}