Hello all! I have recently build a BLDC motor controller which works great. I have tested and implemented it with hall sensors and am able to get good performance with some velocity code. I am now trying to write the position code equivalent so that I will be able to implement “holds” where the bldc motor will stop moving and hold it’s position. This is because I plan to use it to build a robotic arm in which position holds will be needed. Is there any way to implement a position hold with the hall sensor velocity code? Setting velocity to 0 doesnt seem to work well as it jitters like crazy. I understand the position control code has support for this but it doesnt seem to work - it calibrates and moves to the hall sensors find but when it hits the main loop it stutters a ton not really moving. Any thoughts to the problem? Any help is appreciated!
This is the working hall sensor velocity code which I’ve tested to work:
#include <SimpleFOC.h>
// Define the BLDC motor pins
#define BLDC_PWM_UH_GPIO 12
#define BLDC_PWM_UL_GPIO 11
#define BLDC_PWM_VH_GPIO 10
#define BLDC_PWM_VL_GPIO 9
#define BLDC_PWM_WH_GPIO 8
#define BLDC_PWM_WL_GPIO 18
#define DRV0_CSN_PIN 48
#define DRV1_SCK_PIN 47
#define HALLU_PIN 6
#define HALLV_PIN 7
#define HALLW_PIN 15
#define ENABLE_PIN 38
#define POLE_PAIRS 2 // Number of permanent magnets in motor divided by 2
// Create BLDCMotor and BLDCDriver6PWM objects
BLDCMotor motor = BLDCMotor(POLE_PAIRS); // number of pole pairs
BLDCDriver6PWM driver = BLDCDriver6PWM(BLDC_PWM_UH_GPIO, BLDC_PWM_UL_GPIO, BLDC_PWM_VH_GPIO, BLDC_PWM_VL_GPIO, BLDC_PWM_WH_GPIO, BLDC_PWM_WL_GPIO);
// hall sensor instance
HallSensor sensor = HallSensor(HALLU_PIN, HALLV_PIN, HALLW_PIN, POLE_PAIRS);
// Interrupt routine intialisation
// channel A and B callbacks
void doA(){sensor.handleA();}
void doB(){sensor.handleB();}
void doC(){sensor.handleC();}
// velocity set point variable
float target_velocity = -80;
unsigned long previousMillis = 0; // will store last time LED was updated
// instantiate the commander
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&target_velocity, cmd); }
void setup() {
pinMode(ENABLE_PIN, OUTPUT);
pinMode(DRV0_CSN_PIN, OUTPUT);
pinMode(DRV1_SCK_PIN, OUTPUT);
digitalWrite(DRV1_SCK_PIN, LOW);
digitalWrite(DRV0_CSN_PIN, HIGH);
digitalWrite(ENABLE_PIN, LOW);
delay(250);
digitalWrite(ENABLE_PIN, HIGH);
// use monitoring with serial
Serial.begin(115200);
// enable more verbose output for debugging
// comment out if not needed
//SimpleFOCDebug::enable(&Serial);
// initialize sensor sensor hardware
sensor.init();
sensor.enableInterrupts(doA, doB, doC);
// link the motor to the sensor
motor.linkSensor(&sensor);
// driver config
// power supply voltage [V]
driver.voltage_power_supply = 24;
driver.init();
// link the motor and the driver
motor.linkDriver(&driver);
// aligning voltage [V]
motor.voltage_sensor_align = 3;
// 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.2f;
motor.PID_velocity.I = 2;
motor.PID_velocity.D = 0;
// default voltage_power_supply
motor.voltage_limit = 2;
// jerk control using voltage voltage ramp
// default value is 300 volts per sec ~ 0.3V per millisecond
motor.PID_velocity.output_ramp = 1000;
// velocity low pass filtering time constant
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', doTarget, "target voltage");
Serial.println(F("Motor ready."));
Serial.println(F("Set the target velocity using serial terminal:"));
_delay(1000);
previousMillis = millis();
}
void loop() {
/*unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= 2100)
{
previousMillis = currentMillis;
target_velocity *= -1;
}*/
// main FOC algorithm function
// the faster you run this function the better
// Arduino UNO loop ~1kHz
// Bluepill loop ~10kHz
motor.loopFOC();
// 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);
// function intended to be used with serial plotter to monitor motor variables
// significantly slowing the execution down!!!!
// motor.monitor();
// user communication
command.run();
}
This is the position control code that I am trying to get working but has problems in the main loop. It just stutters and wont move to the position after calibrating the hall sensors:
#include <SimpleFOC.h>
// Define the BLDC motor pins
#define BLDC_PWM_UH_GPIO 12
#define BLDC_PWM_UL_GPIO 11
#define BLDC_PWM_VH_GPIO 10
#define BLDC_PWM_VL_GPIO 9
#define BLDC_PWM_WH_GPIO 8
#define BLDC_PWM_WL_GPIO 18
#define DRV0_CSN_PIN 48
#define DRV1_SCK_PIN 47
#define HALLU_PIN 6
#define HALLV_PIN 7
#define HALLW_PIN 15
#define ENABLE_PIN 38
#define POLE_PAIRS 2 // Number of permanent magnets in motor divided by 2
// BLDC motor & driver instance
BLDCMotor motor = BLDCMotor(POLE_PAIRS);
BLDCDriver6PWM driver = BLDCDriver6PWM(BLDC_PWM_UH_GPIO, BLDC_PWM_UL_GPIO, BLDC_PWM_VH_GPIO, BLDC_PWM_VL_GPIO, BLDC_PWM_WH_GPIO, BLDC_PWM_WL_GPIO);
// hall sensor instance
HallSensor sensor = HallSensor(HALLU_PIN, HALLV_PIN, HALLW_PIN, POLE_PAIRS);
// Interrupt routine intialisation
// channel A and B callbacks
void doA(){sensor.handleA();}
void doB(){sensor.handleB();}
void doC(){sensor.handleC();}
// angle set point variable
float target_angle = 2;
// instantiate the commander
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&target_angle, cmd); }
void setup() {
pinMode(ENABLE_PIN, OUTPUT);
pinMode(DRV0_CSN_PIN, OUTPUT);
pinMode(DRV1_SCK_PIN, OUTPUT);
digitalWrite(DRV1_SCK_PIN, LOW);
digitalWrite(DRV0_CSN_PIN, HIGH);
digitalWrite(ENABLE_PIN, LOW);
delay(250);
digitalWrite(ENABLE_PIN, HIGH);
// initialize sensor hardware
sensor.init();
sensor.enableInterrupts(doA, doB, doC);
// link the motor to the sensor
motor.linkSensor(&sensor);
// driver config
// power supply voltage [V]
driver.voltage_power_supply = 24;
driver.init();
// link the motor and the driver
motor.linkDriver(&driver);
// aligning voltage [V]
motor.voltage_sensor_align = 3;
// index search velocity [rad/s]
motor.velocity_index_search = 3;
// set motion control loop to be used
motor.controller = MotionControlType::angle;
// contoller configuration
// default parameters in defaults.h
// velocity PI controller parameters
motor.PID_velocity.P = 0.2f;
motor.PID_velocity.I = 2;
motor.PID_velocity.D = 0;
// default voltage_power_supply
motor.voltage_limit = 2;
// jerk control using voltage voltage ramp
// default value is 300 volts per sec ~ 0.3V per millisecond
motor.PID_velocity.output_ramp = 1000;
// velocity low pass filtering time constant
motor.LPF_velocity.Tf = 0.01f;
// angle P controller
motor.P_angle.P = 100;
// maximal velocity of the position control
motor.velocity_limit = 100;
// use monitoring with serial
Serial.begin(115200);
// 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', doTarget, "target angle");
Serial.println(F("Motor ready."));
//Serial.println(F("Set the target angle 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();
// 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_angle);
// function intended to be used with serial plotter to monitor motor variables
// significantly slowing the execution down!!!!
// motor.monitor();
// user communication
command.run();
}
Thank you for your time!