control of three phases induction motor with arduino

Hi
for the realization of a speed controller for three-phase induction motor, I realize an inverter (6 IGBT) (the attached picture)
So I have to control this inverter.
I did a search in our forum I found this:
http://forum.arduino.cc/index.php?topic=121727.0
I tried this code on arduino uno (Atmega328p). but i didn't obtein a good results:
one of the three phase is not correct. i think that the problem is the dead time. in addition to that i don't find a solution to varying the frequency.
does any one help me.
thanks in advance.

/*
*
* DDS Sine Generator mit ATMEGS 328
* Timer2 generates the  31250 KHz Clock Interrupt
* Use Timer2 Interrupt to change duty cycle for the output PWM signals
* D. Tolken
* 120 degress out of phase signals for 3 phase BLDC motor controller
* CPUT, South Africa


a Huge thumbs up and thanks must be given to Martin Nawrath for the developement of the original code to generate a sine wave using PWM and a LPF.
Link:
                                         http://interface.khm.de/index.php/lab/experiments/arduino-dds-sinewave-generator/
*/

#include "avr/pgmspace.h" //Store data in flash (program) memory instead of SRAM

// Look Up table of a single sine period divied up into 256 values. Refer to PWM to sine.xls on how the values was calculated
PROGMEM  prog_uchar sine256[]  = {
  127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240,
  242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,
  221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,
  76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,
  33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124

};
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) //define a bit to have the properties of a clear bit operator
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))//define a bit to have the properties of a set bit operator

int PWM1= 11;// PWM1 output, phase 1
int PWM2 = 3; //![WM2 ouput, phase 2
int PWM3 = 10; //PWM3 output, phase 3
int offset_1 = 85; //offset 1 is 120 degrees out of phase with previous phase, Refer to PWM to sine.xls
int offset_2 = 170; //offset 2 is 120 degrees out of phase with offset 1. Refer to PWM to sine.xls
int program_exec_time = 6; //monitor how quickly the interrupt trigger
int ISR_exec_time = 7; //monitor how long the interrupt takes

double dfreq;
const double refclk=31376.6;      // measured output frequency

// variables used inside interrupt service declared as voilatile
volatile byte current_count;              // Keep track of where the current count is in sine 256 array
volatile byte ms4_delay;             //variable used to generate a 4ms delay
volatile byte c4ms;              // after every 4ms this variable is incremented, its used to create a delay of 1 second
volatile unsigned long phase_accumulator;   // pahse accumulator
volatile unsigned long tword_m;  // dds tuning word m, refer to DDS_calculator (from Martin Nawrath) for explination.

void setup()
{
  pinMode(PWM1, OUTPUT);      //sets the digital pin as output
  pinMode(PWM2, OUTPUT);      //sets the digital pin as output
  pinMode(PWM3, OUTPUT);      //sets the digital pin as output
  pinMode(program_exec_time, OUTPUT);      //sets the digital pin as output
  pinMode(9, OUTPUT);         //sets the digital pin as output
  sbi(PORTD,program_exec_time); //Sets the pin
  Setup_timer1();
  Setup_timer2();
  
  //Disable Timer 1 interrupt to avoid any timing delays
  cbi (TIMSK0,TOIE0);              //disable Timer0 !!! delay() is now not available
  sbi (TIMSK2,TOIE2);              //enable Timer2 Interrupt

  dfreq=1000.0;                    //initial output frequency = 1000.o Hz
  tword_m=pow(2,32)*dfreq/refclk;  //calulate DDS new tuning word 

}
void loop()
{
  while(1) 
  {
      sbi(PORTD,program_exec_time); //Sets the pin 
      if (c4ms > 250) // c4ms = 4ms, thus 4ms *250 = 1 second delay
       {                 
        c4ms=0;                          //Reset c4ms
        dfreq=analogRead(0);             //Read voltage on analog 1 to see desired output frequency, 0V = 0Hz, 5V = 1.023kHz
        cbi (TIMSK2,TOIE2);              //Disable Timer2 Interrupt
        tword_m=pow(2,32)*dfreq/refclk;  //Calulate DDS new tuning word
        sbi (TIMSK2,TOIE2);              //Enable Timer2 Interrupt 
      }
  }
}

//Timer 1 setup
//Set prscaler to 1, PWM mode to phase correct PWM,  16000000/510 = 31372.55 Hz clock
void Setup_timer1(void)
{
  // Timer1 Clock Prescaler to : 1
  sbi (TCCR1B, CS10);
  cbi (TCCR1B, CS11);
  cbi (TCCR1B, CS12);
  
  // Timer1 PWM Mode set to Phase Correct PWM
  cbi (TCCR1A, COM1A0);
  sbi (TCCR1A, COM1A1);
  cbi (TCCR1A, COM1B0); 
  sbi (TCCR1A, COM1B1);

  // Mode 1 / Phase Correct PWM
  sbi (TCCR1A, WGM10); 
  cbi (TCCR1A, WGM11);
  cbi (TCCR1B, WGM12);
  cbi (TCCR1B, WGM13);
}

//Timer 1 setup
//Set prscaler to 1, PWM mode to phase correct PWM,  16000000/510 = 31372.55 Hz clock
void Setup_timer2() 
{
  // Timer2 Clock Prescaler to : 1
  sbi (TCCR2B, CS20);
  cbi (TCCR2B, CS21);
  cbi (TCCR2B, CS22);

  // Timer2 PWM Mode set to Phase Correct PWM
  cbi (TCCR2A, COM2A0);  // clear Compare Match
  sbi (TCCR2A, COM2A1);
  cbi (TCCR2A, COM2B0); 
  sbi (TCCR2A, COM2B1);
  
  // Mode 1  / Phase Correct PWM
  sbi (TCCR2A, WGM20);  
  cbi (TCCR2A, WGM21);
  cbi (TCCR2B, WGM22);
}


//Timer2 Interrupt Service at 31372,550 KHz = 32uSec
//This is the timebase REFCLOCK for the DDS generator
//FOUT = (M (REFCLK)) / (2 exp 32)
//Runtime : 8 microseconds
ISR(TIMER2_OVF_vect)
{
  cbi(PORTD,program_exec_time); //Clear the pin
  sbi(PORTD,ISR_exec_time);          // Sets the pin

  phase_accumulator=phase_accumulator+tword_m; //Adds tuning M word to previoud phase accumulator. refer to DDS_calculator (from Martin Nawrath) for explination.
  current_count=phase_accumulator >> 24;     // use upper 8 bits of phase_accumulator as frequency information                      
  
  OCR2A=pgm_read_byte_near(sine256 + current_count); // read value fron ROM sine table and send to PWM
  OCR2B=pgm_read_byte_near(sine256 + (uint8_t)(current_count + offset_1)); // read value fron ROM sine table and send to PWM, 120 Degree out of phase of PWM1
  
  OCR1A = pgm_read_byte_near(sine256 + (uint8_t)(current_count + offset_2));// read value fron ROM sine table and send to PWM, 120 Degree out of phase of PWM2
  OCR1B = pgm_read_byte_near(sine256 + (uint8_t)(current_count + offset_2));// read value fron ROM sine table and send to PWM, 120 Degree out of phase of PWM2
  
  //increment variable ms4_delay every 4mS/125 =  milliseconds 32uS
  if(ms4_delay++ == 125) 
  {  
    c4ms++;
    ms4_delay=0; //reset count
   }   

cbi(PORTD,ISR_exec_time);            //Clear the pin
}
//http://forum.arduino.cc/index.php?topic=121727.0

I would go for drivers with integrated dead time. That would feel a lot safer when using these voltages. As far as i can see you are using the PWM output so you have no provision for deadtime in neither hardware or software. Also your post says induction motor but the comment in the code says bldc. These are NOT the same (but very similar)

thanks for your contribution.
yes i have no provision for deadtime in neither hardware or software. i would like to provide this dead in the code (software) but i don't know how. if there is a hardware solution why not. for the comment in the code which says bldc. i mentioned that I have found this code in the forum and it should function normally in this case.
so how can i provide this dead time?

nilton61:
I would go for drivers with integrated dead time. That would feel a lot safer when using these voltages. As far as i can see you are using the PWM output so you have no provision for deadtime in neither hardware or software. Also your post says induction motor but the comment in the code says bldc. These are NOT the same (but very similar)

The circuit shows an IR2130 which has integrated deadtime (they call it "cross-conduction
prevention") There are graphs of deadtime v. temperature and v. voltage in the datasheet
for that driver.

[ Also you might want to look at the code I posted in Reply #24 here: PWM for 3-phase Inverter - Motors, Mechanics, Power and CNC - Arduino Forum - it shows setting up 2 timers in synchrony on the Uno to
generate 3-phase PWM - proof of concept code though, not polished. Note that for
an induction motor you have to control phase and amplitude and measure or estimate
rotor position/speed to have any decent control over torque. ]

Are you sure you don't want to get a commercial variable frequency drive like the Altivar 08 "used" for about 100$ on eBay. It already has a 0 to 5v analog input compatible with the arduino PWM outputs and all the adjustable variables for control ( like soft start ) that you may need.
When you get into the higher energy applications there is a much higher risk of things going wrong and someone getting injured. Interfacing with a certified piece of equipment designed to do the job may be a lot cheaper in the long run.

MarkT:
The circuit shows an IR2130 which has integrated deadtime (they call it "cross-conduction
prevention") There are graphs of deadtime v. temperature and v. voltage in the datasheet
for that driver.

[ Also you might want to look at the code I posted in Reply #24 here: PWM for 3-phase Inverter - Motors, Mechanics, Power and CNC - Arduino Forum - it shows setting up 2 timers in synchrony on the Uno to
generate 3-phase PWM - proof of concept code though, not polished. Note that for
an induction motor you have to control phase and amplitude and measure or estimate
rotor position/speed to have any decent control over torque. ]

thanks Mr Mark_T
I tried with this code (dry run) .For low voltage (40V) it worked correctly. but when I put 311V, the IR2130 was destroyed and I had a power outage. how I can rectify that. thank you in advance.

Going from testing at 40V to 300V in one step is asking for exploding devices. You need
to take care with these lethal voltages and monitor the waveforms and currents as you
test at higher voltages and powers. A Variac to control the supply voltage is the traditional
way to do this.

Once you're at mains power levels any mistake will cause the circuit to destroy itself
taking away any evidence of what happened - you need to work up gradually and monitor all the
relevant things - current levels, power levels, device temperatures, waveform anomalies...

Be safe, remember these voltages kill and exploding IGBTs and chips can blind you with
shrapnel so wear eye protection when debugging high power circuitry.

I would recommend a variav AND a isolation transformer

so I have to use a Variac.Ok I understand but for deadtime what i can do? i don't know if there is a circuit for varying the deadtime and see the result. And for the current pretection I added a fuse at the DC input of 5A. is that enough?

No, you need to sense current on microsecond timescales and shutdown if it gets too
high - IGBTs at 300V are usually guaranteed to survive shoot-through currents for a
couple of microseconds only.

This means fast comparators directly triggering shutdown mode as part of the protection
circuitry... However that appears to be there in your circuit in the form of the ITRIP input
to the inverter module. What current level is it set for?

Are you really using slow opto-couplers? You need high speed logic opto-couplers
to control gate switching, something with a response time more like 100ns than 5us,
or you'll have little control over programmed deadtime.

hi , i worked for this project and i succeed to varying the frequency and have the best solution for the dead time and my project work now .
th mark-T for your help.

Hi,
Did you manage to get it working?
I have a similar project, with an AC induction motor with a supply of 50V, and I am trying to find a solution to control the speed with the arduino.

Thanks

Hello adelo14, can you explain what you changed in your code for have successful ??
Can you share with us your work?

Thanks