Brushless Motor Basic Programming Question - Electronics Forums

Author Topic: Brushless Motor Basic Programming Question  (Read 13613 times)

mamette

  • Trusted Member
  • *
  • Posts: 14
  • Karma: +0/-0
  • I have a soldering iron and I'm not afraid to use it!
    • View Profile
Brushless Motor Basic Programming Question
« on: June 09, 2013, 08:47:18 AM »
Hi everyone..

I have try code for rotating my brushless motor from here:
http://elabz.com/bldc-motor-with-arduino-circuit-and-software/

Because i just want to rotating my brushless motor, i modify the code to be like this:
Code: [Select]
/*
Driving a DVD drive spindle three-phase motor
 
This code was used for the stroboscope project
 
This example code is in the public domain. Based on several Arduino code samples
 
http://elabz.com/
 
 */
 
// constants won't change. They're used here to
// set pin numbers:
const int motorPin1 =3;
const int motorPin2 =6;
const int motorPin3 =5;
const int motorDelay=0; // together with pot controls the RPM
const int potState=0;       // controls the RPM speed

// Variables will change:
boolean direct = true; // direction true=forward, false=backward


/*
int pwmSin[] = {127,110,94,78,64,50,37,26,17,10,4,1,0,1,4,10,17,26,37,50,64,78,94,110,127,144,160,176,191,204,217,228,237,244,250,253,254,253,250,244,237,228,217,204,191,176,160,144,127
}; // array of PWM duty values for 8-bit timer - sine function
*/
 
int pwmSin[]={511,444,379,315,256,200,150,106,68,39,17,4,0,4,17,39,68,106,150,200,256,315,379,444,511,578,643,707,767,822,872,916,954,983,1005,1018,1022,1018,1005,983,954,916,872,822,767,707,643,578,511
}; // array of PWM duty values for 10-bit timer - sine function
 
int increment;
int currentStepA=0;
int currentStepB=16;
int currentStepC=32;

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long motorDelayActual = 0;  // the actual delay, based on pot value and motor delay set above
long lastMotorDelayTime = 0;


 
void setup() {
 
  pinMode(motorPin1, OUTPUT);
  pinMode(motorPin2, OUTPUT);
  pinMode(motorPin3, OUTPUT);
 
  TCCR1B = TCCR1B & 0b11111000 | 0x01; // set PWM frequency @ 31250 Hz for Pins 9 and 10
  TCCR2B = TCCR2B & 0b11111000 | 0x01; // set PWM frequency @ 31250 Hz for Pins 11 and 3 (3 not used)

  //ICR1 = 255 ; // 8 bit resolution
  ICR1 = 1023 ; // 10 bit resolution




}
 
void loop() {

motorDelayActual =   potState * motorDelay / 100;
move();
   
}
 
 
 
void move() {
if((millis() - lastMotorDelayTime) >  motorDelayActual)
{ // delay time passed, move one step
 
  if (direct==true)
  {
    increment = 1;
  }
    else
    {
     increment = -1; 
    }
  currentStepA = currentStepA + increment;
  if(currentStepA > 47) currentStepA = 0;
  if(currentStepA<0) currentStepA =47;
   
  currentStepB = currentStepB + increment;
  if(currentStepB > 47) currentStepB = 0;
  if(currentStepB<0) currentStepB =47;
   
    currentStepC = currentStepC + increment;
  if(currentStepC > 47) currentStepC = 0;
  if(currentStepC<0) currentStepC =47;
 
lastMotorDelayTime = millis();
}
   
analogWrite(motorPin1, pwmSin[currentStepA]);
analogWrite(motorPin2, pwmSin[currentStepB]);
analogWrite(motorPin3, pwmSin[currentStepC]);
   
}

And it's works..

But, there is something that i not understand. I use ATMega 328p and use pins 3,6 and 5 as PWM output. And i set the PWM register is like this:
Code: [Select]
TCCR1B = TCCR1B & 0b11111000 | 0x01; // set PWM frequency @ 31250 Hz for Pins 9 and 10
  TCCR2B = TCCR2B & 0b11111000 | 0x01; // set PWM frequency @ 31250 Hz for Pins 11 and 3 (3 not used)

  //ICR1 = 255 ; // 8 bit resolution
  ICR1 = 1023 ; // 10 bit resolution

TCCR1B is PWM register for pins 9 and 10 (OC1A and OC1B), then TCCR2B is PWM register for pins 11 and 3 (OC2A and OC2B). But, i use pins 3, 6 and 5. It is ok for TCCR1B because it is for pin 3, but how about TCCR2B? TCCR2B is for pin 9 and 10, not for pins 6 and 5. But the code is works well..

Then, i change the PWM register to be like this:
Code: [Select]
  TCCR2B = TCCR2B & 0b11111000 | 0x01; // set PWM frequency @ 31250 Hz for Pins 11 and 3 (3 not used)
  TCCR0B = TCCR0B & 0b11111000 | 0x01; // set PWM frequency @ 31250 Hz for Pins 5 and 6

I change TCCR1B with TCCR0B because TCCR0B is for pins 6 and 5 (OC0A and OC0B). But, the code is not works when i change it. This is confusing, when i use the right register, the code not works. But when i use wrong register, the code works well..

Does anybody know why this happen?

Thank You..
« Last Edit: June 09, 2013, 08:49:11 AM by mamette »

Electronics Forums

Brushless Motor Basic Programming Question
« on: June 09, 2013, 08:47:18 AM »

ElectroNick

  • The forum moderator
  • Administrator
  • Full Member
  • *****
  • Posts: 154
  • Karma: +3/-0
  • The soldering iron is ON!
    • View Profile
    • Electronics Blog
Re: Brushless Motor Basic Programming Question
« Reply #1 on: June 09, 2013, 11:59:58 AM »
It probably works because by setting up the wrong register you are essentially leaving the right register in its default settings (i.e. timer prescaled to 64 - slow PWM, 8 bit resolution instead of 10).  The fast PWM does not seem to work with your motor. Motors too slow, load too high? I'm not sure why it happens at this point but see what may be causing the motor to respond. Could be that using 10 bit sine wave with 8 bit PWM resolution output means that the commutation of the windings only works 1/4th of the time (because 3/4th of the PWM values from that sine wave table are too high and get ignored)?

mamette

  • Trusted Member
  • *
  • Posts: 14
  • Karma: +0/-0
  • I have a soldering iron and I'm not afraid to use it!
    • View Profile
Re: Brushless Motor Basic Programming Question
« Reply #2 on: June 12, 2013, 11:11:23 AM »
Quote
The fast PWM does not seem to work with your motor. Motors too slow, load too high?

No, the motor is no load..

Now i try to just use one of TCCR2B or TCCR1B and use 8 bit PWM resolution. When i use TCCR2B or TCCR1B, it's works well, but if i use TCCR0B, the brushless motor is not rotating.

The code is become like this: ( i prefer to just use TCCR2B)

Code: [Select]
// constants won't change. They're used here to
// set pin numbers:
const int motorPin1 =3;
const int motorPin2 =6;
const int motorPin3 =5;

// Variables will change:
boolean direct = true; // direction true=forward, false=backward

int pwmSin[] = {127,110,94,78,64,50,37,26,17,10,4,1,0,1,4,10,17,26,37,50,64,78,94,110,127,144,160,176,191,204,217,228,237,244,250,253,254,253,250,244,237,228,217,204,191,176,160,144,127
}; // array of PWM duty values for 8-bit timer - sine function

 
//int pwmSin[]={511,444,379,315,256,200,150,106,68,39,17,4,0,4,17,39,68,106,150,200,256,315,379,444,511,578,643,707,767,822,872,916,954,983,1005,1018,1022,1018,1005,983,954,916,872,822,767,707,643,578,511
//}; // array of PWM duty values for 10-bit timer - sine function
 
int increment;
int currentStepA=0;
int currentStepB=16;
int currentStepC=32;

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
//long motorDelayActual = 0;  // the actual delay, based on pot value and motor delay set above
long lastMotorDelayTime = 0;

void initBLDC() {

  pinMode(motorPin1, OUTPUT);
  pinMode(motorPin2, OUTPUT);
  pinMode(motorPin3, OUTPUT);
 
  //TCCR1B = TCCR1B & 0b11111000 | 0x01; // set PWM frequency @ 31250 Hz for Pins 9 and 10
  TCCR2B = TCCR2B & 0b11111000 | 0x01; // set PWM frequency @ 31250 Hz for Pins 11 and 3 (3 not used)
  //TCCR0B = TCCR0B & 0b11111000 | 0x01; // set PWM frequency @ 31250 Hz for Pins 5 and 6
 
 
  ICR1 = 255 ; // 8 bit resolution
  //ICR1 = 1023 ; // 10 bit resolution
 
}

 
void setup() {
 
  initBLDC();
 
}


void loop() {

BLDCmove();
   
}
 
 
 
void BLDCmove() {
if((millis() - lastMotorDelayTime) > 0)
{ // delay time passed, move one step
 
  if (direct==true)
  {
    increment = 1;
   
  currentStepA = currentStepA + increment;
  if(currentStepA > 47) currentStepA = 0;
  if(currentStepA<0) currentStepA =47;
   
  currentStepB = currentStepB + increment;
  if(currentStepB > 47) currentStepB = 0;
  if(currentStepB<0) currentStepB =47;
   
    currentStepC = currentStepC + increment;
  if(currentStepC > 47) currentStepC = 0;
  if(currentStepC<0) currentStepC =47;
 
  }
   
   
  if (direct==false)
  {
    increment = -1;
   
  currentStepA = currentStepA + increment;
  if(currentStepA > 47) currentStepA = 0;
  if(currentStepA<0) currentStepA =47;
   
  currentStepB = currentStepB + increment;
  if(currentStepB > 47) currentStepB = 0;
  if(currentStepB<0) currentStepB =47;
   
    currentStepC = currentStepC + increment;
  if(currentStepC > 47) currentStepC = 0;
  if(currentStepC<0) currentStepC =47;
  }
 
lastMotorDelayTime = millis();

}
   
analogWrite(motorPin1, pwmSin[currentStepA]);
analogWrite(motorPin2, pwmSin[currentStepB]);
analogWrite(motorPin3, pwmSin[currentStepC]);
   
}

Then, i combine the code above with my IMU sketch, The code is here:
https://github.com/mamette/Brushless/blob/master/brushless_IMU.ino

The result is my brushless motor rotating much slower. Is IMU processing affected my brushless motor speed?
« Last Edit: June 12, 2013, 11:13:52 AM by mamette »

ElectroNick

  • The forum moderator
  • Administrator
  • Full Member
  • *****
  • Posts: 154
  • Karma: +3/-0
  • The soldering iron is ON!
    • View Profile
    • Electronics Blog
Re: Brushless Motor Basic Programming Question
« Reply #3 on: June 12, 2013, 12:24:04 PM »
I think the problem is with the way the code in your sketch is structured. I did not read it all very carefully, but I see a lot of delay(20);  lines in there, no doubt to accommodate the accelerometer communication. During the delay nothing is happening in an Arduino. Arduino can only process one thread at the time, and if you told it to wait, it will halt everything, including processing of the motor commutation sequences. That will either stop or slow down the motor.

20 milliseconds is a HUGE delay as far as BLDC motor is concerned. Let's say you wanted it to rotate at 600RPM - not too fast but not too relaxed either. That means that you only have 100 milliseconds (600RPM/60 = 10 rotations per second = 100ms per rotation) in which you have to process 36 commutation changes for a 12 pole/9 cog BLDC motor. That means that your commutation change routine only has  100/36 = 2.77ms to process the change if nothing else was running in the Arduino. So, during each of your many delay(20);  you are missing at least 7 commutation steps.

I think you should take a look at your code and see how you can make those 20 milliseconds  more productive. Say, instead of doing a delay(20), see if you can send it into a subroutine that for the next 20 milliseconds will be rotating the motor.

mamette

  • Trusted Member
  • *
  • Posts: 14
  • Karma: +0/-0
  • I have a soldering iron and I'm not afraid to use it!
    • View Profile
Re: Brushless Motor Basic Programming Question
« Reply #4 on: June 12, 2013, 10:39:26 PM »
I think the problem is with the way the code in your sketch is structured. I did not read it all very carefully, but I see a lot of delay(20);  lines in there, no doubt to accommodate the accelerometer communication. During the delay nothing is happening in an Arduino. Arduino can only process one thread at the time, and if you told it to wait, it will halt everything, including processing of the motor commutation sequences. That will either stop or slow down the motor.

20 milliseconds is a HUGE delay as far as BLDC motor is concerned. Let's say you wanted it to rotate at 600RPM - not too fast but not too relaxed either. That means that you only have 100 milliseconds (600RPM/60 = 10 rotations per second = 100ms per rotation) in which you have to process 36 commutation changes for a 12 pole/9 cog BLDC motor. That means that your commutation change routine only has  100/36 = 2.77ms to process the change if nothing else was running in the Arduino. So, during each of your many delay(20);  you are missing at least 7 commutation steps.

I think you should take a look at your code and see how you can make those 20 milliseconds  more productive. Say, instead of doing a delay(20), see if you can send it into a subroutine that for the next 20 milliseconds will be rotating the motor.

But all of the delay(20); is in the void setup() {..} section, there is no delay in the main loop..

Or i must use interrupts for the motor?

« Last Edit: June 12, 2013, 10:40:57 PM by mamette »

ElectroNick

  • The forum moderator
  • Administrator
  • Full Member
  • *****
  • Posts: 154
  • Karma: +3/-0
  • The soldering iron is ON!
    • View Profile
    • Electronics Blog
Re: Brushless Motor Basic Programming Question
« Reply #5 on: June 13, 2013, 12:09:16 AM »
But all of the delay(20); is in the void setup() {..} section, there is no delay in the main loop..
You are right, I did not read it too carefully all the way through. at the same time though, you have these lines in the main loop:

Code: [Select]
  timer = millis() - timer; //how long did the loop take?
  timer = (timeStep * 1000) - timer; //how much time to add to the loop to make it last time step msec
  delay(timer);

How long does that delay take? It's in milliseconds, anyway - almost guaranteed to be too long for any serious RPMs. You may want to switch to microseconds in anything that involves BLDCs.

mamette

  • Trusted Member
  • *
  • Posts: 14
  • Karma: +0/-0
  • I have a soldering iron and I'm not afraid to use it!
    • View Profile
Re: Brushless Motor Basic Programming Question
« Reply #6 on: June 13, 2013, 09:15:20 AM »
I change the delay to microseconds, but the motor is not rotating.

How about use Interrupt? I have try using interrupts, but looks like my code is wrong, so the motor is not rotating, it's seems just hold the position..

This is my code using interrupts:

Code: [Select]
// constants won't change. They're used here to
// set pin numbers:
const int motorPin1 =3;
const int motorPin2 =6;
const int motorPin3 =5;

// Variables will change:
boolean direct = true; // direction true=forward, false=backward

int pwmSin[] = {127,110,94,78,64,50,37,26,17,10,4,1,0,1,4,10,17,26,37,50,64,78,94,110,127,144,160,176,191,204,217,228,237,244,250,253,254,253,250,244,237,228,217,204,191,176,160,144,127
}; // array of PWM duty values for 8-bit timer - sine function

 
//int pwmSin[]={511,444,379,315,256,200,150,106,68,39,17,4,0,4,17,39,68,106,150,200,256,315,379,444,511,578,643,707,767,822,872,916,954,983,1005,1018,1022,1018,1005,983,954,916,872,822,767,707,643,578,511
//}; // array of PWM duty values for 10-bit timer - sine function
 
int increment;
int currentStepA=0;
int currentStepB=16;
int currentStepC=32;

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
//long motorDelayActual = 0;  // the actual delay, based on pot value and motor delay set above
long lastMotorDelayTime = 0;

void initBLDC() {

  pinMode(motorPin1, OUTPUT);
  pinMode(motorPin2, OUTPUT);
  pinMode(motorPin3, OUTPUT);
  
  //TCCR1B = TCCR1B & 0b11111000 | 0x01; // set PWM frequency @ 31250 Hz for Pins 9 and 10
  TCCR2B = TCCR2B & 0b11111000 | 0x01; // set PWM frequency @ 31250 Hz for Pins 11 and 3 (3 not used)
  //TCCR0B = TCCR0B & 0b11111000 | 0x01; // set PWM frequency @ 31250 Hz for Pins 5 and 6
  
  ICR1 = 255 ; // 8 bit resolution
  //ICR1 = 1023 ; // 10 bit resolution
  TIMSK2 |= _BV(TOIE1);
  sei();

  // Enable Timer1 Interrupt for Motor Control
  OCR0A = 0;
  OCR0B = 0;
  OCR1A = 0;
  OCR1B = 0;  
  OCR2A = 0;  
  OCR2B = 0;  
}


ISR(TIMER2_OVF_vect) {  
 if((millis() - lastMotorDelayTime) > 0)
{ // delay time passed, move one step
 
  if (direct==true)
  {
    increment = 1;
    
  currentStepA = currentStepA + increment;
  if(currentStepA > 47) currentStepA = 0;
  if(currentStepA<0) currentStepA =47;
  
  currentStepB = currentStepB + increment;
  if(currentStepB > 47) currentStepB = 0;
  if(currentStepB<0) currentStepB =47;
  
    currentStepC = currentStepC + increment;
  if(currentStepC > 47) currentStepC = 0;
  if(currentStepC<0) currentStepC =47;
  
  }
  
  
  if (direct==false)
  {
    increment = -1;
    
  currentStepA = currentStepA + increment;
  if(currentStepA > 47) currentStepA = 0;
  if(currentStepA<0) currentStepA =47;
  
  currentStepB = currentStepB + increment;
  if(currentStepB > 47) currentStepB = 0;
  if(currentStepB<0) currentStepB =47;
  
    currentStepC = currentStepC + increment;
  if(currentStepC > 47) currentStepC = 0;
  if(currentStepC<0) currentStepC =47;
  }
  
lastMotorDelayTime = millis();

}
  
analogWrite(motorPin1, pwmSin[currentStepA]);
analogWrite(motorPin2, pwmSin[currentStepB]);
analogWrite(motorPin3, pwmSin[currentStepC]);
  
};  

void setup() {
 
  initBLDC();
  
}


void loop() {

  //IMU Code Here
    
}
 

mamette

  • Trusted Member
  • *
  • Posts: 14
  • Karma: +0/-0
  • I have a soldering iron and I'm not afraid to use it!
    • View Profile
Re: Brushless Motor Basic Programming Question
« Reply #7 on: June 17, 2013, 10:55:25 AM »
I GOT IT!!! it must use Interrupts, and all things will works well..

Code: [Select]
// constants won't change. They're used here to
// set pin numbers:
const int motorPin1 =3;
const int motorPin2 =6;
const int motorPin3 =5;

// Variables will change:
boolean direct = true; // direction true=forward, false=backward

int pwmSin[] = {127,110,94,78,64,50,37,26,17,10,4,1,0,1,4,10,17,26,37,50,64,78,94,110,127,144,160,176,191,204,217,228,237,244,250,253,254,253,250,244,237,228,217,204,191,176,160,144,127
}; // array of PWM duty values for 8-bit timer - sine function

 
//int pwmSin[]={511,444,379,315,256,200,150,106,68,39,17,4,0,4,17,39,68,106,150,200,256,315,379,444,511,578,643,707,767,822,872,916,954,983,1005,1018,1022,1018,1005,983,954,916,872,822,767,707,643,578,511
//}; // array of PWM duty values for 10-bit timer - sine function
 
int increment;
int currentStepA=0;
int currentStepB=16;
int currentStepC=32;

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
//long motorDelayActual = 0;  // the actual delay, based on pot value and motor delay set above
long lastMotorDelayTime = 0;

void initBLDC() {

  pinMode(motorPin1, OUTPUT);
  pinMode(motorPin2, OUTPUT);
  pinMode(motorPin3, OUTPUT);
 
  //TCCR1B = TCCR1B & 0b11111000 | 0x01; // set PWM frequency @ 31250 Hz for Pins 9 and 10
  //TCCR2B = TCCR2B & 0b11111000 | 0x01; // set PWM frequency @ 31250 Hz for Pins 11 and 3
  TCCR2B = _BV(CS21);
  //TCCR0B = TCCR0B & 0b11111000 | 0x01; // set PWM frequency @ 31250 Hz for Pins 5 and 6
 

  ICR1 = 255 ; // 8 bit resolution
  //ICR1 = 1023 ; // 10 bit resolution
  TIMSK2 |= _BV(TOIE1);
  //sei();
  //Timer2 Settings: Timer Prescaler /64,
  //TCCR2B |= ((1<<CS22) | (0<<CS21) | (0<<CS20)); 
  //Use normal mode
  //TCCR2B |= (0<<WGM21) | (0<<WGM20);
  // Use internal clock - external clock not used in Arduino
  //ASSR |= (0<<AS2);                     //http://forum.arduino.cc/index.php/topic,37875.0.html
  sei();
 
    // Enable Timer1 Interrupt for Motor Control
  //OCR2A = 0;  //11  APIN
  //OCR2B = 0;  //D3
  //OCR1A = 0;  //D9  CPIN
  //OCR1B = 0;  //D10 BPIN
  //OCR0A = 0;  //D6
  //OCR0B = 0;  //D5
}


ISR(TIMER2_OVF_vect) {   
  BLDCmove();   
}; 


void setup() {
  initBLDC(); 
}


void loop() {

  //IMU Code Here
   
}
 
void BLDCmove() {
  if((millis() - lastMotorDelayTime) > 0)
  { // delay time passed, move one step
 
    BLDCCommut();
 
    lastMotorDelayTime = millis();

  }
 
  motorMove(); 
}

void BLDCCommut() {
 
  if (direct==true)
  {
    increment = 1;
   
  currentStepA = currentStepA + increment;
  if(currentStepA > 47) currentStepA = 0;
  if(currentStepA<0) currentStepA =47;
   
  currentStepB = currentStepB + increment;
  if(currentStepB > 47) currentStepB = 0;
  if(currentStepB<0) currentStepB =47;
   
    currentStepC = currentStepC + increment;
  if(currentStepC > 47) currentStepC = 0;
  if(currentStepC<0) currentStepC =47;
 
  }
   
   
  if (direct==false)
  {
    increment = -1;
   
  currentStepA = currentStepA + increment;
  if(currentStepA > 47) currentStepA = 0;
  if(currentStepA<0) currentStepA =47;
   
  currentStepB = currentStepB + increment;
  if(currentStepB > 47) currentStepB = 0;
  if(currentStepB<0) currentStepB =47;
   
    currentStepC = currentStepC + increment;
  if(currentStepC > 47) currentStepC = 0;
  if(currentStepC<0) currentStepC =47;
  }
 
}

void motorMove() {
 
  analogWrite(motorPin1, pwmSin[currentStepA]);
  analogWrite(motorPin2, pwmSin[currentStepB]);
  analogWrite(motorPin3, pwmSin[currentStepC]);

}

 

Related Topics

  Subject / Started by Replies Last post
0 Replies
14818 Views
Last post December 08, 2011, 03:57:06 PM
by ElectroNick
22 Replies
36189 Views
Last post June 06, 2013, 11:39:44 PM
by sa898
1 Replies
15481 Views
Last post February 11, 2013, 12:15:21 PM
by ElectroNick
14 Replies
22720 Views
Last post June 07, 2013, 11:49:31 AM
by mamette
0 Replies
12099 Views
Last post April 05, 2015, 07:30:53 PM
by earslan