Hi All,
I am pretty new to BLDC motors. I have the aforementioned setup and the motor (https://ca.robotshop.com/products/ipower-gm2804-gimbal-motor-w-as5048a-encoder) should be able to spin ~2000rpm unloaded. I slowly step my velocity control up (with very conservative PI gains and slew) but cannot seem to get much higher than 1000rpm before the motor spontaneously changes direction and stops responding to velocity commands. Has anyone experienced this? This persists in open loop voltage control. I have checked and SPI speed and Arduino loop time should not be the cause.
This is the current Arduino sketch:
/**
*
- Velocity motion control example
- Steps:
-
- Configure the motor and magnetic sensor
-
- Run the code
-
- Set the target velocity (in radians per second) from serial terminal
- By using the serial terminal set the velocity value you want to motor to obtain
*/
#include <SimpleFOC.h>
// magnetic sensor instance - SPI
MagneticSensorSPI sensor = MagneticSensorSPI(9, 14, 0x3FFF);
// MagneticSensorSPI sensor = MagneticSensorSPI(AS5048_SPI, 10);
// magnetic sensor instance - MagneticSensorI2C
//MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);
// MagneticSensorAnalog sensor = MagneticSensorAnalog(A1, 14, 1020);
// BLDC motor & driver instance
BLDCMotor motor = BLDCMotor(7);
BLDCDriver3PWM driver = BLDCDriver3PWM(6, 10, 5, 8);
// Stepper motor & driver instance
//StepperMotor motor = StepperMotor(50);
//StepperDriver4PWM driver = StepperDriver4PWM(9, 5, 10, 6, 8);
// velocity set point variable
float target_velocity = 0;
// loopFOC frequency meter
unsigned long _lf_last_ms = 0;
uint32_t _lf_count = 0;
float _lf_hz = 0.0f;
// instantiate the commander
Commander command = Commander(Serial);
// Set target velocity using RPM input
void doTargetRpm(char* cmd) {
float rpm = atof(cmd);
target_velocity = rpm * (2.0f * PI) / 60.0f; // store as rad/s
Serial.print(F("Target set (RPM): "));
Serial.println(rpm);
}
// Toggle between closed-loop velocity and open-loop velocity
void doToggleOpenLoop(char* cmd) {
(void)cmd;
if (motor.controller == MotionControlType::velocity_openloop) {
motor.controller = MotionControlType::velocity;
Serial.println(F(“Mode: closed-loop velocity”));
} else {
motor.controller = MotionControlType::velocity_openloop;
Serial.println(F(“Mode: open-loop velocity”));
}
}
// On-demand status print
void doPrintStatus(char* cmd) {
(void)cmd;
float rpm_meas = motor.shaft_velocity * 60.0f / (2.0f * PI);
float rpm_target = target_velocity * 60.0f / (2.0f * PI);
Serial.print(F("Target(RPM): “));
Serial.print(rpm_target);
Serial.print(F(” | RPM: “));
Serial.print(rpm_meas);
Serial.print(F(” | dir: “));
Serial.print(motor.sensor_direction == Direction::CW ? F(“CW”) : F(“CCW”));
Serial.print(F(” | mode: "));
Serial.println(motor.controller == MotionControlType::velocity_openloop ? F(“open-loop”) : F(“closed-loop”));
}
// Print PWM frequency
void doPrintPwmFreq(char* cmd) {
(void)cmd;
Serial.print(F("PWM frequency (Hz): "));
Serial.println(driver.pwm_frequency);
}
// Print loopFOC frequency
void doPrintLoopHz(char* cmd) {
(void)cmd;
Serial.print(F("loopFOC rate (Hz): "));
Serial.println(_lf_hz, 1);
}
void setup() {
// use monitoring with serial
Serial.begin(115200);
// enable more verbose output for debugging
// comment out if not needed
// SimpleFOCDebug::enable(&Serial); // disable to improve loop rate
// initialise magnetic sensor hardware
sensor.clock_speed = 8000000; // 8 MHz (AMS supports up to ~10 MHz)
sensor.init();
// link the motor to the sensor
motor.linkSensor(&sensor);
// driver config
// power supply voltage [V]
driver.voltage_power_supply = 10;
driver.voltage_limit = 10;
driver.pwm_frequency = 50000;
driver.init();
// link the motor and the driver
motor.linkDriver(&driver);
// set motion control loop to be used
motor.controller = MotionControlType::velocity;
// contoller configuration
// default parameters in defaults.h
// velocity PI controller parameters
motor.PID_velocity.P = 0.1f;
motor.PID_velocity.I = 0.05;
motor.PID_velocity.D = 0;
// default voltage_power_supply
motor.voltage_limit = 10.0f;
// jerk control using voltage voltage ramp
// default value is 300 volts per sec ~ 0.3V per millisecond
motor.PID_velocity.output_ramp = 100;
motor.voltage_sensor_align = 2;
// velocity low pass filtering
// default 5ms - try different values to see what is the best.
// the lower the less filtered
motor.LPF_velocity.Tf = 0.01f;
// comment out if not needed
motor.useMonitoring(Serial);
// initialize motor
motor.init();
// align sensor and start FOC
motor.initFOC();
// add target command T
command.add(‘T’, doTargetRpm, “target velocity (RPM)”);
// add print command P (on-demand status)
command.add(‘P’, doPrintStatus, “print status”);
// add print PWM frequency command F
command.add(‘F’, doPrintPwmFreq, “print PWM frequency (Hz)”);
// add loop rate print command L
command.add(‘L’, doPrintLoopHz, “print loopFOC rate (Hz)”);
// toggle open-loop / closed-loop velocity control
command.add(‘O’, doToggleOpenLoop, “toggle open/closed loop velocity”);
Serial.println(F(“Motor ready.”));
Serial.println(F(“Set the target velocity using serial terminal:”));
_delay(1000);
}
void loop() {
// main FOC algorithm function
// the faster you run this function the better
// Arduino UNO loop ~1kHz
// Bluepill loop ~10kHz
motor.loopFOC();
// loopFOC rate counter
_lf_count++;
unsigned long _now = millis();
unsigned long _dt = _now - _lf_last_ms;
if (_dt >= 1000UL) {
_lf_hz = (float)_lf_count * 1000.0f / (float)_dt;
_lf_count = 0;
_lf_last_ms = _now;
}
// Motion control function
// velocity, position or voltage (defined in motor.controller)
// this function can be run at much lower frequency than loopFOC() function
// You can also use motor.move() and set the motor.target in the code
motor.move(target_velocity);
// Status printing moved to on-demand command ‘P’
// function intended to be used with serial plotter to monitor motor variables
// significantly slowing the execution down!!!
// motor.monitor();
// user communication
command.run();
}
And here is the output showing the flip and loss of control:
Target set (RPM): 500.00
Target(RPM): 500.00 | RPM: 405.70 | dir: CW | mode: closed-loop
Target(RPM): 500.00 | RPM: 470.62 | dir: CW | mode: closed-loop
Target(RPM): 500.00 | RPM: 486.32 | dir: CW | mode: closed-loop
Target set (RPM): 700.00
Target(RPM): 700.00 | RPM: 664.12 | dir: CW | mode: closed-loop
Target(RPM): 700.00 | RPM: 687.45 | dir: CW | mode: closed-loop
Target set (RPM): 900.00
Target(RPM): 900.00 | RPM: 865.12 | dir: CW | mode: closed-loop
Target(RPM): 900.00 | RPM: 873.54 | dir: CW | mode: closed-loop
Target(RPM): 900.00 | RPM: 897.31 | dir: CW | mode: closed-loop
Target set (RPM): 1000.00
Target(RPM): 1000.00 | RPM: 985.16 | dir: CW | mode: closed-loop
Target(RPM): 1000.00 | RPM: 998.06 | dir: CW | mode: closed-loop
Target set (RPM): 1100.00
Target(RPM): 1100.00 | RPM: -1255.24 | dir: CW | mode: closed-loop
Target(RPM): 1100.00 | RPM: -1263.39 | dir: CW | mode: closed-loop
Any help is much appreciated, thanks!
Lyndon