Hi everyone, recently found SimpleFOC while researching PID motor control libraries for a project.
I have a setup consisting of a Pi Pico, a L298N driver board, a NEMA17 stepper, and an AMT103 encoder. I’ve managed to get everything configured and running, and I’ve also set up live control with SimpleFOCStudio.
The problem is when I run the motor in angle (closed-loop) mode. I set my increments to 6.28 rads in SimpleFOCStudio and I have been testing single and double rotations. If I keep incrementing in the same direction, the motor’s response is snappy and smooth for the first three or so rotations, but after that each successive rotation gets a little slower, a little noisier, and draws more current. This can get so bad after about ten rotations in one direction that the motor is basically at a standstill and drawing 1-2A from my 12V Power Supply.
BUT if I switch directions, it very quickly becomes snappy and smooth again, with power consumption as it should be. However if I continue in this direction the motor starts struggling after a few rotations again.
This has me baffled. I first thought that maybe the encoder is misconfigured and just slightly off, but I have manually confirmed that the encoder is accurate (I tested this by doing exactly 10, 20, 30 rotations by hand and double checking the reported angle). It’s almost as if there’s some kind of rotational slack present somewhere that isn’t being accounted for?
I’m aware of the limitations of the L298N due to its slow switching characteristics, but I have been running these tests at slow speeds and within those first few rotations in either direction the performance is great. The only other thing possibly harming me is I’m not using the index channel on my encoder but if my reported angles are accurate I don’t see why that should be a problem.
I’m at a loss what to do now. Any insight as to what’s happening would be greatly appreciated.
Below is my code and a picture of my setup. (Pi Pico running Arduino Framework through PlatformIO)
#include <Arduino.h>
#include <SimpleFOC.h>
// Stepper motor & driver instance
StepperMotor motor = StepperMotor(50, 1.5); // Pole pairs, Phase resistance
StepperDriver4PWM driver = StepperDriver4PWM(p20, p19, p18, p17, p21, p16); // A+, A-, B+, B-, enA, enB
// Encoder instance & callbacks
Encoder encoder = Encoder(p14, p15, 2048); // A, B, Set PPR (see DIP switches inside encoder)
void doA(){encoder.handleA();}
void doB(){encoder.handleB();}
// instantiate the commander
Commander command = Commander(Serial);
void doMotor(char* cmd) {command.motor(&motor, cmd); }
void setup() {
// encoder config
encoder.init();
encoder.enableInterrupts(doA, doB);
// link the motor to the encoder
motor.linkSensor(&encoder);
// driver config
driver.pwm_frequency = 32000;
// power supply voltage [V]
driver.voltage_power_supply = 12;
driver.init();
// link the motor and the driver
motor.linkDriver(&driver);
// limiting motor current (provided resistance)
motor.current_limit = 1.7; // [Amps]
motor.voltage_sensor_align = 5; // aligning voltage
motor.foc_modulation = FOCModulationType::SpaceVectorPWM; // choose FOC modulation (optional)
motor.LPF_velocity.Tf = 0.01; // velocity low pass filtering time constant
motor.velocity_limit = 50;
// controller configuration based on the control type
motor.PID_velocity.P = 0.2;
motor.PID_velocity.I = 20;
motor.PID_velocity.D = 0;
// open loop control config
motor.controller = MotionControlType::angle;
// init motor hardware
motor.init();
motor.initFOC();
// add target command T
command.add('M', doMotor, "Full Motor Config");
Serial.begin(115200);
Serial.println("Motor ready!");
_delay(1000);
}
void loop() {
motor.loopFOC(); // FOC algorithm
motor.move(); // Motor control loop
command.run(); // User communication
}