Poor results with stepper motor

Hi All,

I’ve got a stepper motor I’m trying to use with simpleFOC library, setup:
-Motor: 200 PPR stepper motor
-Controller: Arduino Uno (ATMega328P)
-Driver: 4x BTS7960 (40A 25V Integrated Half-bridge driver+MOSFET)
+I have successfully used the Arduino “stepper” library to drive this exact configuration with classical stepper motor commutation and it works great.

I can get the motor spinning with simpleFOC in openloop angle/velocity, but the motion is rough, there’s a once per revolution thump, and (in angle mode) when the motor stops it sometimes (depending on the angle I stop at) makes a periodic thumping/clicking noise. I am using openloop modes for now because I figured I should get it working first with that.

My app is listed below.


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

// BLDC motor & driver instance
StepperMotor motor = StepperMotor(64, 3);
StepperDriver4PWM driver = StepperDriver4PWM(5, 6, 9, 10);

// instantiate the commander
Commander command = Commander(Serial);
void doTarget(char* cmd) {
command.scalar(&motor.target, cmd);
}
void doLimit(char* cmd) {
command.scalar(&motor.voltage_limit, cmd);
}
void doVelocity(char* cmd) {
command.scalar(&motor.velocity_limit, cmd);
}

void setup() {
// set enable lines high
pinMode(1, OUTPUT); pinMode(2, OUTPUT); pinMode(3, OUTPUT); pinMode(4, OUTPUT);
digitalWrite(1, 1); digitalWrite(2, 1); digitalWrite(3, 1); digitalWrite(4, 1);

driver.voltage_power_supply = 5;
driver.voltage_limit = 5;
driver.init();
// link the motor and the driver
motor.linkDriver(&driver);

motor.voltage_limit = 4; // [V]
// limit/set the velocity of the transition in between
// target angles
motor.velocity_limit = 2 * 3.141592; // [rad/s] cca 50rpm
// open loop control config
motor.controller = MotionControlType::angle_openloop;

// init motor hardware
motor.init();

// add target command T
command.add(‘T’, doTarget, “target velocity”);
command.add(‘L’, doLimit, “voltage limit”);
command.add(‘V’, doVelocity, “movement velocity”);

motor.useMonitoring(Serial); // strange compiler error without this
motor.target = 2 * 3.141592;
Serial.begin(115200);
Serial.println(“Motor ready!”);
Serial.println(“Set target position [rad]”);

_delay(1000);
}

void loop() {

// open loop velocity movement
// using motor.voltage_limit and motor.velocity_limit
// to turn the motor “backwards”, just set a negative target_velocity
//motor.move(target_velocity);
motor.move();

// function intended to be used with serial plotter to monitor motor variables
// significantly slowing the execution down!!!
motor.monitor();

// user communication
command.run();
}

Are you only supplying 5V to this? I think it needs 5.5v or 6v minimum.

Could you be slamming the motor with too much current? Perhaps try:

driver.voltage_limit = 1.0f;
motor.voltage_limit = driver.voltage_limit / 2 ;  // motor is usually set to half driver voltage

In openloop, it is often best to set the voltage_limit needs to be as small as possible without the stepper missing steps as it is quite easy to overcook the motor.

Whilst some have got good results out of steppers and simplefoc it requires ‘everything’ to have decent specs. This is because steppers typically have more than 5x the PP count. Your ATMega328P is slow and not good at floating point maths. You might get ok results in openloop, but I think it’ll struggle in closed loop.

Similarly when you spec out your encoder/magnetic sensor it needs to be high precision. For every physical rotation you have 64 electrical rotations and it is the electrical rotations that are important for FOC. Compare that to a BLDC with 7PP you’ve already lost 3 or 4 bits of precision off the sensor.

I suspect esp32 or stm32 chips will give you better results in the long run. Or you could try the newer uno r4 (although support for this renesas chip is fairly new in simplefoc so might be buggy).

Monitor will definitely slow down your execution, serial communication is expensive in all cases. Maybe set monitor downsampling to something like 100 or so if you don’t have any other way to get data out.

I’ve gotten excellent performance out of steppers with SFOC, but as Owen said., everything has to be spot on.

You said that your motor has 200 steps. Why not 50 poles then?
StepperMotor motor = StepperMotor(64, 3);

The motor does have 200 steps, I have absolutely verified this using classical stepper motor commutation(which I have alot of experience) I used the exact wiring, exact driver(BTS7960), and controller (Uno). In this classical stepper mode(with Arduino stepper lib), it works exactly as a stepper motor should, and rotates (very robustly) exactly once when I send it 200 steps.

In SimpleFOC is where things are really confusing. I used 64 because this is what made the motor spin once per second at a speed of 6.28 rad/s in open loop velocity mode. I tried today and the number was 60. I tried using 50, motor spins way slower than 1 rotation per second. At ANY speed I try there’s “knocking” when the motor moves and when it stops in angle mode

I was supplying about 6.5 volts to the BTS
I’ve tried different voltages and the motor performance is just as horrible: Wrong speed, almost no torque, knocking. What could I be doing wrong here???

driver.voltage_limit = 1.0f;
motor.voltage_limit = driver.voltage_limit / 2 ;

This motor needs ~5v to run. I tried what you said and the motor does nothing but faintly vibrate

If it’s a 200 step motor, I promise it’s got 50 pole pairs. If it doesn’t work at 50, you’ve got another problem.

The motor.voltage_limit setting is bidirectional, so setting that to 2.5v means that it’s +2.5 and -2.5, for a peak to peak of 5v.