Hi all,
As a personal challenge, I've been trying to build a brushless gimbal without using any off-the-shelf control boards. That means that I've had to design my own ESC, which is proving to be quite a challenge.
On the hardware side, I've created 3 mosfet half-bridges, one for each coil of the BLDC motor. Scoping the output at 32khz, the PWM frequency I plan to use, has revealed an acceptable square wave at the output of each bridge. On the software side, I have implemented a pwm sinusoidal drive pattern with my mega 2560, and gotten relatively smooth rotation with the motor. Problem is, my implementation isn't quite smooth enough for a gimbal, with pronounced "sticking points" every ~20 degrees leading to somewhat jerky motion.
I know it's possible to drive these specific motors at buttery smooth low speeds, as I have a commercial gimbal, the Tarot T-2d, which manages to do so, but as to how escapes me.
Here is the code I am using to drive the motor at the moment. Keep in mind that each bridge, due to a less-than-enviable design decision, requires two of the same PWM signals sent to it from different pins, due to drive current requirements. Also, I'm aware that there are more recourse-efficient and overall better ways to implement the driver, but at the moment I just want to get smooth rotation. If I figure it out, a full esc recode and redesign is in order.
#define AH 7
#define AL 8
#define BH 9
#define BL 10
#define CH 11
#define CL 12
//BLDC vars
int aPwm = 0;
int bPwm = 0;
int cPwm = 0;
void setup()
{
pinMode(AH, OUTPUT);
pinMode(AL, OUTPUT);
pinMode(BH, OUTPUT);
pinMode(BL, OUTPUT);
pinMode(CH, OUTPUT);
pinMode(CL, OUTPUT);
//Increase PWM frequency to be inaudible
TCCR2B = TCCR2B & 0b11111000 | 0x01;
TCCR1B = TCCR1B & 0b11111000 | 0x01;
TCCR4B = TCCR4B & 0b11111000 | 0x01;
}
int maxPwm = 127; //0-127
double currentT = 0; //0-1, then wrap. Point in the sin wave we're at currently.
double tInc = 0.002;//max .2 from dead stop, on computer power.
void loop()
{
currentT = currentT+tInc; //Increment current time step.
currentT = wrapDouble(currentT, 0.0, 1.0); //Wrap it 0-1.
calcPwm(); //Generate sin waves.
//Write to half-bridges
WriteInvertedPair(aPwm, AH, AL);
WriteInvertedPair(bPwm, BH, BL);
WriteInvertedPair(cPwm, CH, CL);
}
void WriteInvertedPair(int Pwm, int HighSide, int LowSide) //High and low sides are inverted in hardware. Using optos, so need to split current across 2 pins.
{
analogWrite(HighSide, Pwm);
analogWrite(LowSide, Pwm);
}
void calcPwm()
{
aPwm = (int)127+maxPwm*sin(2.0*M_PI*currentT); //0 deg
bPwm = (int)127+maxPwm*sin(2.0*M_PI*(currentT + 0.3333)); //120 deg
cPwm = (int)127+maxPwm*sin(2.0*M_PI*(currentT + 0.6666)); //240 deg
}
double wrapDouble(double num, double lowerBound, double higherBound)
{
if(num < lowerBound)
{
return higherBound;
}
else if(num > higherBound)
{
return lowerBound;
}
else
{
return num;
}
}
I've looked at as many topics related to this as I can, but none seem to provide the answer. I've also tried reverse-engineering the BruGi open-source gimbal software, to no avail. It appears that they use the same method I am. Does anyone have a way I might be able to improve my code or approach to get super smooth motion?