Inversor trifasico controlado por SPWM

Hola, Buenas Noches

Me presento soy estudiante de Ingenieria mecátronica y me encuentro realizando un proyecto que consiste en el control de velocidad de un motor trifasico, pero mi principal proposito del foro es hablar del control de inversor trifasico. He visto en otros foros que se ha tocado el tema, pero nunca se ha podido llegar a un código final que le permita a otros usuarios aprender y utlizarlo, es por eso que decidi crear este nuevo foro.
Aprovecho y enlazo foro el cual vi que llego a estar muy avanzado, pero se paro por completo:

http://forum.arduino.cc/index.php?topic=323650.0

Para lograr el control de velocidad del motor fue necesario crear un variador de frecuencia, el cual contiene una parte de rectitifación, filtrado (Resistencia y capacitor) y una parte de inversión.
Lo primero que me enfoque en la parte de electronica, fue separar la parte de potencia con la parte de control por medio de los OPTOS 4N35 y luego utilice el driver IR2110 que me permite controlar dos MOSFETS a la vez. Debido a que controlare 6 MOSFET utilice tres de estos controladores.

Mi principal problema radica en la activación de los MOSFET, me base en el foro anteriormente nombrado para tener una idea principal de como activarlo, obviamente teniendo en cuenta que la frecuencia de mi pais es de 60 Hz. Pero al momento de realizar la simulación en proteus, tengo muchas zonas en donde esta totalmente muerta, no se si por crear tan exacta la activación de los mofets me genere un desfase, y haga que todo el código se mueva. (Tambien entiendo que le estoy pidiendo mucho a proteus, pero quiero estar un poco mejor asesorado antes de realizar pruebas)

Adjunto código en el siguiente post...

Les agradeceria demasiado si me pueden ayudar con un par de consejos con este código, ya que mi fuerte es la electronica y llevo ya varios meses aprendiendo de la programación, pero aun tengo algunos vacios.

Adjunto esquema potencia y control.
Gracias, Saludos

Adjunto código modificado a 60 Hz:

const byte dutycycle_520 [520] = {128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157,
                                  157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 
                                  187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 215, 
                                  216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
                                  246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, 240, 239, 238, 237, 236, 
                                  235, 234, 233, 232, 231, 230, 229, 228, 227, 226, 226, 225, 224, 223, 222, 221, 220, 219, 218, 217, 216, 215, 214, 213, 212, 211, 210, 209, 208, 207, 
                                  206, 205, 204, 203, 202, 201, 200, 199, 198, 197, 196, 195, 194, 193, 192, 191, 190, 189, 188, 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 
                                  176, 175, 174, 173, 172, 171, 170, 169, 168, 168, 167, 166, 165, 164, 163, 162, 161, 160, 159, 158, 157, 156, 155, 154, 153, 152, 151, 150, 149, 148, 
                                  147, 146, 145, 144, 143, 142, 141, 140, 139, 138, 137, 136, 135, 134, 133, 132, 131, 130, 129, 128, 128, 127, 126, 125, 124, 123, 122, 121, 120, 119,
                                  118, 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 99, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87,
                                  86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49,
                                  48, 47, 46, 45, 44, 43, 42, 41, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12,
                                  11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,  11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 30, 
                                  31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 
                                  69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
                                  105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128};

           
int puntero_sin0   = 130;    // 157 Usada para moverse por los valores de la tabla. Su máximo será 520. Representa la señal senoidal sin desfase. Apunta a DC = 255.
int puntero_sin120 = 453;    // 547 Usada para moverse por los valores de la tabla. Su máximo será 520. Representa la señal senoidal con desfase = 120. Apunta a DC = 64.
int puntero_sin240 = 324;    // 391 Usada para moverse por los valores de la tabla. Su máximo será 520. Representa la señal senoidal con desfase = 240. Apunta a DC = 64.

  /* Ahora se llevará acabo la configuración de los timers de la placa arduino, ya que se requiere la modificación de estos
     para la correcta generación de las señales PWM. Los registros de control serán modificados mediante hexadecimal. */

void setup() {

  // Configuramos los pines de PWM como salidas

  pinMode (3, OUTPUT);  // Conectado a transistor Q6. Par transistores para senoidal con fase 240 
  pinMode (5, OUTPUT);  // Conectado a transistor Q2. Par transistores para senoidal con fase 0
  pinMode (6, OUTPUT);  // Conectado a transistor Q1. Par transistores para senoidal con fase 0
  pinMode (9, OUTPUT);  // Conectado a transistor Q3. Par transistores para senoidal con fase 120
  pinMode (10, OUTPUT); // Conectado a transistor Q4. Par transistores para senoidal con fase 120
  pinMode (11, OUTPUT); // Conectado a transistor Q5. Par transistores para senoidal con fase 240
  
  // Configuramos los timers mediante los registros de control.
  
  TCCR0A = 0xA1; // Habilitamos las dos salidas en modo Phase-correct - 8 bits. Pre-escaler = 1. Salidas no invertidas.
  TCCR0B = 0xC1; 
  TCCR1A = 0xA1; // Habilitamos las dos salidas en modo Phase-correct - 8 bits. Pre-escaler = 1. Salidas no invertidas.
  TCCR1B = 0xC1;
  TCCR2A = 0xA1; // Habilitamos las dos salidas en modo Phase-correct - 8 bits. Pre-escaler = 1. Salidas no invertidas.
  TCCR2B = 0xC1; 
}

void loop() {

  // Programa principal, se usarán directamente los registros de comparación porque es más rápido que usar las funciones propias de arduino.
  
  OCR0A = dutycycle_520 [puntero_sin0];    // Registro de comparación para pin A del timer 0. Genera la PWM para Q1.

  /* Este es un retardo de 4.875 us utilizado para crear un tiempo muerto entre pares de transistores y evitar cortocircuitos en los mismos.
     Demostración: (1+1+(1+2)*25+1)/16000000 = 4.875 us*/

  asm volatile ( 
        "clr r16 \n"       // 1 ciclo de reloj.
        "ldi r16, 0x14 \n" // 1 ciclo de reloj. 26 vueltas cargadas.
        "1: dec r16 \n"    // 1 ciclo de reloj
        "brne 1b  \n"      // 2 ciclos de reloj para retornar y 1 para salir 
      ); 
      
   OCR0B = dutycycle_520 [puntero_sin0];    // Registro de comparación para pin B del timer 0. Genera la PWM para Q2.
   OCR1A = dutycycle_520 [puntero_sin120];  // Registro de comparación para pin A del timer 1. Genera la PWM para Q3.
  
  // Retardo 4.875 us.
  
   asm volatile ( 
      "clr r16 \n"       // 1 ciclo de reloj.
      "ldi r16, 0x14 \n" // 1 ciclo de reloj. 26 vueltas cargadas.
      "1: dec r16 \n"    // 1 ciclo de reloj
      "brne 1b  \n"      // 2 ciclos de reloj para retornar y 1 para salir 
    ); 
    
   OCR1B = dutycycle_520 [puntero_sin120];  // Pin B del timer 1. Genera la PWM para Q4
   OCR2A = dutycycle_520 [puntero_sin240];  // Pin A del timer 2. Genera la PWM para Q5
   
   // Retardo 4.875 us.
    
   asm volatile ( 
      "clr r16 \n"       // 1 ciclo de reloj
      "ldi r16, 0x14 \n" // 1 ciclo de reloj. 26 vueltas cargadas.
      "1: dec r16 \n"    // 1 ciclo de reloj
      "brne 1b  \n"      // 2 ciclos de reloj para retornar y 1 para salir 
    ); 
    
    OCR2B = dutycycle_520 [puntero_sin240];  // Registro de comparación para pin B del timer 2. Genera la PWM para Q6
  
  /////-------------------Falta el retardo de 32 us---------------------------------------/////

  // Ahora establecemos las condiciones para moverse por la tabla de valores y volver al comienzo una vez completado un período de señal.  
  
    if ( puntero_sin0++ < 520 )   { puntero_sin0++; }   else { puntero_sin0 = 0; }   // Si no se ha llegado al final de la tabla, avanza. Si se ha llegado, vuelve a 0.
    if ( puntero_sin120++ < 520 ) { puntero_sin120++; } else { puntero_sin120 = 0; } // Si no se ha llegado al final de la tabla, avanza. Si se ha llegado, vuelve a 0.
    if ( puntero_sin240++ < 520 ) { puntero_sin240++; } else { puntero_sin240 = 0; } // Si no se ha llegado al final de la tabla, avanza. Si se ha llegado, vuelve a 0.     

}

Hola @AdonaiVera, te he enviado un privado para que edites tu post (enlace y visualización de la imagen adjunta).

Respecto a lo que presentas y a los efectos de poder evaluarlo ahorrá trabajo para quien lo haga adjuntando el archivo Proteus teniendo en cuenta que debes subirlo como .zip (no uses otra extensión de compresor).

Creo recordar el código que has presentando o es similar a uno que vi hace un buen tiempo.
Ya te diré cuando lo mire con mas tiempo.

Les comento que hice un avance significativo, en busca de encontrar la mejor forma de activar los MOSFET; me enfoque en realizarlo por medio de Simulink en conjunto con arduino. Cree un bloque que me simulaba la señal trifasica y comparandola con la señal triangular conoceria el momento de activar el MOSFET, y gracias a la Toolbox de Arduino, creo un bloque que seria la salida en mi arduino y al estar conectados es como si trabajara online, esta salida va directamente a los MOSFET de mi sistema. Les adjunto el archivo en simulink zipeado. Recuerden que si quieren utilizarlo deben descargar la Toolbox de arduino.

De igual manera me gustaria mucho poder controlarlo 100% con código, sigo pendiente si me pueden dar un consejo respecto a eso.

Gracias
Saludos

Control_Inversor_LazoAbierto.zip (30.8 KB)

Bueno te vas por las nubes. Tu estas en una Universidad con un monton de herramientas como Simulink y Matlab. Nosotros no podemos correr eso de manera legal, asi que lo mejor que puedes hacer es compartir capturas y explicar que estas haciendo.

Listo claro que si.
Les comento un poco lo que hice, este es el esquematico en Simulink de todo el sistema:

Lo primero que realice fue la señal en trifasica, decidi dejarla de este modo para poder cambiar la frecuencia de una manera sencilla y por medio de código cree las tres fases de AC desfasas 120 grados.
Este el código, en donde tenemos tres entradas y las tres salidas.
Entradas= Frecuencia, VRMS, y tiempo.
Salidas= Tres señales senoidales desfadas 120 grados:

Y estas serian las señales desfasadas:

Luego cree un subsistema en donde agregue la entrada de la señal que acaba de crear y la compare con una señal triangular, para obtener el momento preciso en donde debe activarse el MOSFET, y para aplicarlo, utilice el siguiente código.

Entradas: Señales senoidales y señal triangular
Salidas: PWM y su respectivo inverso, invPWM.

Estas señales irian a activar mis mosfets, ademas agregue los bloques que trabajan en conjunto con Arduino para lograr por medio de mi arduino Mega, activar el sistema en tiempo real.

Esta es la llegada a los MOSFETS

Y para terminal esta seria mi señal reconstruida, como pueden ver es necesario agregar mas tiempo para que se puede crear la senoidal de mejor manera, pero decidi dejarlo asi, para que se lograra apreciar el desfase de la señal.

Y de esta manera ya tener controlado el inversor. Es una manera un poco mas practica, pero como les dije me gustaria mucho mas aprender sobre la forma de hacerlo por medio de código, si alguien conoce mas sobre eso, le agradeceria.
Saludos

Captura4.PNG

Hace poco programe un inversor trifasico para arduino te paso la liga del proyecto en Git-Hub

Gran aporte AdonaiVera :astonished:

Estoy empezando con esto y me veo a años luz de tal ingenio

Saludos,
Yurin
Reparación de electrodomesticos madrid

AdrianDroid:
Hace poco programe un inversor trifasico para arduino te paso la liga del proyecto en Git-Hub

GitHub - semakers/three-phase-signal-arduino

Wow excelente AdrianDroid, revisare para entender el código y poder adecuarlo al sistema. En simulación todo me ha funcionado de maravilla y Matlab ha soportado muy bien todo.
Pero al realizar de manera practica debido a un tiempo de muestreo tan pequeño, estoy teniendo inconvenientes.

Graciass Yurin78, Este es un tema demasiado interesante a mi parecer, pero a veces no se encuentra mucho en internet sobre esto, y he visto algunos Arduino forum pero el tema queda parado, por eso todas las personas que conozcan y que hayan trabajado con estos sitemas, estamos abiertos a tips.
Saludos