Stepper FOC control loud, rough, uneven

I’ve recently started to use the SimpleFOClibrary but I’m running into some issues when trying to control a Nema 17 with a AS5600 and L298N off of a Nucleo-64. I’m primarily following the example stepper drive code from the examples, but when the motor is turning it sounds just like a bad stepper driver with rough steps and uneven velocity over each rotation. Additionally, it has significant cogging when backdriven. I’m suspecting that there is a lot of performance I’m leaving on the table as a result of my code. The physical wiring of the project is the same as the stepper example except for the AS5600, which I have separately verified to be working. The serial monitor output indicates that the motor gets successfully initiated and returns a magnetic angle and the “Ready” message. Does it look like I’m missing anything in my code that could be causing me these problems? Thank you for the assistance, I’m really excited to have this working!

#include <SimpleFOC.h>

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

// instance of AS5600 sensor
MagneticSensorI2C encoder = MagneticSensorI2C(AS5600_I2C);


// commander interface
Commander command = Commander(Serial);
void onMotor(char* cmd){ command.motor(&motor, cmd); }

void setup() {

  // set voltage for initial config
  motor.voltage_sensor_align = 5;
  motor.torque_controller = TorqueControlType::foc_current;

  // initialize encoder sensor hardware
  encoder.init();
  //encoder.enableInterrupts(doA, doB); 
  // link the motor to the sensor
  motor.linkSensor(&encoder);

  // choose FOC modulation
  motor.foc_modulation = FOCModulationType::SpaceVectorPWM;

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

  // set control loop type to be used
  motor.controller = MotionControlType::torque;
  motor.torque_controller = TorqueControlType::foc_current;
  
  // controller configuration based on the control type 
  motor.PID_velocity.P = 0.2;
  motor.PID_velocity.I = 20;
  motor.PID_velocity.D = 0;
  // default voltage_power_supply
  motor.voltage_limit = 12;

  // velocity low pass filtering time constant
  motor.LPF_velocity.Tf = 0.01;

  // angle loop controller
  motor.P_angle.P = 20;
  // angle loop velocity limit
  motor.velocity_limit = 50;

  // use monitoring with serial for motor init
  // monitoring port
  Serial.begin(115200);
  // comment out if not needed
  motor.useMonitoring(Serial);

  // initialise motor
  motor.init();
  // align encoder and start FOC
  motor.initFOC();

  // set the initial target value
  motor.target = 1;

  // define the motor id
  command.add('M', onMotor, "motor");

  // Run user commands to configure and the motor (find the full command list in docs.simplefoc.com)
  Serial.println(F("Motor commands sketch | Initial motion control > torque/voltage : target 2V."));
  
  _delay(1000);
}


void loop() {
  // iterative setting FOC phase voltage
  motor.loopFOC();

  // iterative function setting the outter loop target
  // velocity, position or voltage
  // if tatget not set in parameter uses motor.target variable
  motor.move();

  // user communication
  command.run();
}
1 Like

Screenshot of SimpleFOCStudio for more info:

Hi, and welcome @kernelsploit !

You’re in foc_current mode, but haven’t set up any current sensing… try switching to velocity, position, or torque-voltage modes. These should work better.

In terms of the PID, usually the D value has to stay at 0 or very very low, eg. 0.001.

The method I usually follow is:
Try setting everything to 0, and increase P until you reach a point where it begins to oscillate, then take it back just a little to stop the oscillations. Probably you won’t be at your target point yet. Then slowly increase I until the motor tracks the target value well. If there are still oscillations, you can try increasing D very slightly.

1 Like