Control de motor BLDC desde 0 (Posicion)

Buenas, tenia mucho que no entraba al foro siquiera, posteare esto aquí por si a alguien mas le puede servir:
Desde hace tiempo tengo en mente varios proyectos con motores BLDC, como ya sabrán son motores trifásicos que son controlados por un puente H triple, los controles ESC o variadores como comúnmente los conocemos algunos hobbystas son muy útiles para casos sencillos en los que se requiere solamente velocidad burda en lazo abierto, sin embargo en algunos casos mas especiales se requiere control de posición del motor, como por ejemplo en el caso de los gimball o estabilizadores de cámaras en estos casos los ESC's convencionales nos son totalmente inútiles (se puede modificar el firmware, pero no es la idea).
Existen varias opciones comerciales que ofrecen mayor control sobre la posición del rotor como lo son O-drive y V-esc, pero son caros y con la escasez de semiconductores se puso aun peor la situación.

Por el momento mi proyecto consiste en un simple puente H que puede ser controlado por un arduino común, en las semanas siguientes iré actualizando el proyecto pero por ahora lo subo aquí, por si hay alguna sugerencia o error que estoy cometiendo me lo hagan saber.
Este proyecto lo inicie porque soy aficionado a la astronomía y quiero una montura direct drive, obviamente son exageradamente caras así que decidí hacer una con motores de hoverboard.
En mi caso usare un STM32 para aprovechar la mayor resolución del pwm, ya que esto dará como resultado una mayor resolución a la hora de hacer tracking del cielo. La tarjeta final tendrá capacidad para controlar 2 motores, es decir 2 puentes H así como entradas analógicas y digitales para varios periféricos.
Mi fuerte es la electrónica, así que no se asusten con mi código :smile:

#include <math.h>
int Output1 = PA8;
int Output2 = PA9;
int Output3 = PA10;
int analogVal;
const int analogInput = PA0;
HardwareTimer timer(1);
//int potVal = 0;
double A = 0;
long IT;
double B; //= 0.00400001;
int amp;// = 11000;
//int Freq_IN = A0;
int var1 = 0;
int var2 = 0;
int var3 = 0;
int var4 = 0;
int var5 = 0;
int var6 = 0;
int cont = 0;
int ampval;
double Phase1 = 2 * PI / 3;
double Phase2 = 4 * PI / 3;
double Phase3 = 2 * PI;
boolean toggle1 = true;
boolean toggle = false; // true = Enabling Serial Plotter Output
void setup()
{
  timer.setPrescaleFactor(1);
  //timer.setOverflow(255);
  Serial.begin(9600);
  pinMode(Output1, PWM);
  pinMode(Output2, PWM);
  pinMode(Output3, PWM);
  //pinMode(Freq_IN, INPUT);
  //delay(5000);
}
void loop()
{
  // analogVal = (analogRead(analogInput) - 2000);
  analogVal = analogRead(analogInput) ;
  Serial.println(ampval);
  B = map(analogVal, 0, 4095, 500000, -500000 );
  ampval = analogVal - 2042;
  if (ampval < 0) {
    ampval = ampval * (-1);
  }
  B = B / 100000000;
  amp = map(ampval, 0, 2095, 8000, 14000 );
  if (ampval < 30) {
    B = 0;
  }
  A += B;
  cont = cont + 1 ;
  IT ++;
  pwmWrite(Output1, var1);
  pwmWrite(Output2, var2);
  pwmWrite(Output3, var3);
  if (toggle == true)
  {
    Serial.print(var1);
    Serial.print("\t");
    Serial.print(var2);
    Serial.print("\t");
    Serial.println(var3);
    Serial.println("\t");


  }
  var4 = amp * sin(A + Phase1);
  var1 = var4 + 32768;
  var5 = amp * sin(A + Phase2);
  var2 = var5 + 32768;
  var6 = amp * sin(A + Phase3);
  var3 = var6 + 32768;

  if (A >= 2 * PI)
  {

    // if(toggle1 == true){
    //Serial.println(IT);
    // }
    A = 0;
    //cont = 0;
  }

}

Aqui un Video de como va el proyecto.
PD no pude subir imagenes, me marca error o algo estoy haciendo mal

Desde ya que muchos te vamos a apoyar con lo que sea.
Puedes documentar tu puente H trifásico?
Yo comienzo viendo algunos errores que no se si son deliberados o no
amp toma valores entre 8000 y 14000, ok.

amp = map(ampval, 0, 2095, 8000, 14000 );

pero acá el problema

 var1 = var4 + 32768;

var1 definido como int -32767 a 32768 la suma de var4 a 32768 genera un overflow .
Debes definir var1 a var3 como long.

Programa modificado con las observaciones.

#include <Arduino.h>
#include <math.h>
int Output1 = PA8;
int Output2 = PA9;
int Output3 = PA10;
int analogVal;
const int analogInput = PA0;

HardwareTimer timer(1);
//int potVal = 0;
double A = 0;
long IT;
double B; //= 0.00400001;
int amp;// = 11000;
//int Freq_IN = A0;
long var1 = 0;
long var2 = 0;
long var3 = 0;
long var4 = 0;
long var5 = 0;
long var6 = 0;
int cont = 0;
int ampval;
double Phase1 = 2 * PI / 3;
double Phase2 = 4 * PI / 3;
double Phase3 = 2 * PI;
boolean toggle1 = true;
boolean toggle = false; // true = Enabling Serial Plotter Output

void setup() {
  timer.setPrescaleFactor(1);
  //timer.setOverflow(255);
  Serial.begin(9600);
  pinMode(Output1, PWM);
  pinMode(Output2, PWM);
  pinMode(Output3, PWM);
  //pinMode(Freq_IN, INPUT);
  //delay(5000);
}
void loop() {
  // analogVal = (analogRead(analogInput) - 2000);
  analogVal = analogRead(analogInput) ;
  Serial.println(ampval);
  B = map (analogVal, 0, 4095, 500000, -500000 );
  ampval = analogVal - 2042;
  if (ampval < 0) {
      ampval = ampval * (-1);
  }
  B = B / 100000000UL;
  amp = map(ampval, 0, 2095, 8000, 14000 );
  if (ampval < 30) 
      B = 0;
  A += B;
  cont++;
  IT ++;
  
  if (toggle)  {
      Serial.print(var1);
      Serial.print("\t");
      Serial.print(var2);
      Serial.print("\t");
      Serial.println(var3);
      Serial.println("\t");
  }
  var4 = amp * sin(A + Phase1);
  var1 = var4 + 32768;

  var5 = amp * sin(A + Phase2);
  var2 = var5 + 32768;

  var6 = amp * sin(A + Phase3);
  var3 = var6 + 32768;
  
  pwmWrite(Output1, var1);
  pwmWrite(Output2, var2);
  pwmWrite(Output3, var3);
  
  if (A >= 2 * PI)   {
     A = 0;
  }
}

Tienes razón esa es la teoría que yo entiendo para un Arduino normal, sin embargo estoy usando el int del stm32 que tengo entendido tiene como valores máximos:

-2,147,483,648 to 2,147,483,647

Esto según la literatura de ARM. Por el momento no me ha dado problemas, pero supongo que si alguien usa un Arduino si debería hacer modificaciones al código.
Por lo del puente H si lo pienso publicar aqui, sin embargo necesito hacer modificaciones al circuito general, debo agregar un medidor de corriente para cada motor y entradas/salidas del integrado para conectar periféricos y otras cosas.

Algo que me agradaría que me recomendaran es como subir esquemáticos, archivos, o pcb's que como ya mencione publico poco y no sabría como hacerlo

Volví a intentar subir imágenes del circuito y esquemático pero no me deja, dice que un error ocurrió al subir el archivo

Yo uso EasyEDa para hacer esquemáticos. Hay muchos tutoriales en Youtube sobre como usarlo. Aprende a usar los esquemáticos y luego te permitirá tmb usar el PCB y si quieres encargar placas porque tiene librerias y stock en algunas casas Chinas (si mal recuerdo) para encargar las placas desarrolladas.

Tienes razón respecto de los enteros, asi que mi sugerencia no es correcta.

Tal vez me explique mal, estoy intentando subir las imágenes aquí al foro, pero no puedo, me marca error al intentar subir jpg's o png's ya intente quitando el exif con gimp pero aun así nada.
El diseño del esquemático y pcb lo estoy realizando en Altium 17, como lo mencione sigo trabajando en el, pero me gustaría ir subiendo las versiones previas a la final para ir recibiendo retroalimentación al respecto antes de mandar a fabricar con JLCPCB la versión final

Sorry, there was an error uploading that file. Please try again.

¿No será un problema de dimensiones o de peso?
¿Has probado reducirlas a ver que ocurre?

Saludos

Intente reducir el tamaño del archivo hasta 40kb pero aun así no pude subirlo, podrías indicarme donde puedo ver los limites de tamaño y resolución de imágenes.
Otra cosa que debo hacer es comentar el código, a veces yo mismo no entiendo que hace cada parte del el

Subelo a google drive (por dar un ejemplo), coloca el link y luego yo lo agrego debidamente donde me indiques.

Veamos, aquí están las imágenes de la primera versión

al igual que un pequeño video, ojo esta versión esta optimizada para fabricación por transferencia de tóner, tiene espacios grandes entre pistas y casi pude ponerla toda en una cara, solo falto un puente, que me pareció mas sencillo hacerlo con jumpers (el cable rojo), los diodos de protección de la parte superior que si están en la tarjeta faltan en el esquemático y PCB.

Aun tengo que limpiar los picos de voltaje que ocurren al hacer la conmutación, ya que usando voltajes mas altos dichos picos matan los MOSFET's y en duty cycles altos generan ringing, por ahora el voltaje usado es 13.8v a unos pocos amperes, menos de 6.


Los MOSFET's son de 60v 20A pero mientras tenga los parámetros requeridos por los motores, son intercambiables mientras sean D-PAK normal, el gate driver es el IR2103, los diodos para el bootstraping son simples diodos schottky rápidos de 1A 80v.

Bueno pues siguiendo con el proyecto, dejo el código actualizado y comentado para dos canales/motores.
Aun espero una pieza para poder armar la montura, pero creo que esta semana ya podre mostrarla armada y funcional, por el momento seguiré trabajando con el software en Python para el rastreo de objetos, también falta la comunicación serial entre ambos pero ya va caminando la cosa.

#include <math.h>
const int OA1 = PA8;
const int OA2 = PA9;
const int OA3 = PA10;
const int OB1 = PB6;
const int OB2 = PB7;
const int OB3 = PB8;
int analogVal;
int analogVal2;
const int analogInput = PA0;
const int analogInput2 = PA1;
HardwareTimer timer(1);
double A = 0;
double B;
double A2 = 0;
double B2;
int amp;
int amp2;
int ampval;
int ampval2;
int var1 = 0;
int var2 = 0;
int var3 = 0;
int var4 = 0;
int var5 = 0;
int var6 = 0;
int bar1 = 0;
int bar2 = 0;
int bar3 = 0;
int bar4 = 0;
int bar5 = 0;
int bar6 = 0;
int cont = 0;
double Phase1 = 2 * PI / 3;
double Phase2 = 4 * PI / 3;                                // Estas son las fases, o especificamente la relacion que existe entre ellas expresada en numeros
double Phase3 = 2 * PI;
boolean toggle = false;                                    // true = activa la escritura hacia el Serial Plotter
int ctV;
int ctH;
void setup()
{
  timer.setPrescaleFactor(1);
  Serial.begin(9600);
  pinMode(OA1, PWM);                                        //poniendo los pines en modo PWM
  pinMode(OA2, PWM);
  pinMode(OA3, PWM);
  pinMode(OB1, PWM);
  pinMode(OB2, PWM);
  pinMode(OB3, PWM);
  ctV = analogRead(analogInput);                            //Obteniendo valores centrales para hacer calibracion inical
  ctH = analogRead(analogInput2);
}


void loop()
{
  analogVal = analogRead(analogInput) ;                     //leyendo palanca vertical
  B = map(analogVal, 0, 4095, 5000000, -5000000 );          //mapeando palanca vertical, se obtiene el valor del paso que el motor realizara (forma rudimentaria de controlar la velocidad)
  ampval = analogVal - ctV;                                 //restando valor de calibracion al valor de la medicion, se obtienen valores que van de -2048 a 2048
  if (ampval < 0) {                                         //si el valor es menor que 0 se conviertenlos valores negativos a positivos,
    ampval = ampval * (-1);                                 //para obtener la magnitud del movimiento == velocidad + potencia, se multiplicca por -1
  }


  amp = map(ampval, 0, 2048, 8000, 14000 );                 //mapeando la magnitud de movimiento de la palanca hacia el valor de la amplitud de pwm
  B = B / 1000000000;                                       //se convierte el paso en un valor muy pequeño, ya que el algoritmo trabaja con valores de 0 a 2*pi
  if (ampval < 30) {                                        //aqui se establece una zona muerta, es decir si el valor del cambio de la palanca es muy pequeño se ignora
    B = 0;                                                  //esto se hace porque los potenciometros de las palancas tienen jitter, es decir el valor varia lo suficiente
  }                                                         //para que el sistema lo detecte y se produce movimiento no deseado se puede variar el numero (30) por default
  A += B;                                                   //se agrega el paso al valor de A, A almacena la posicion actual




  analogVal2 = analogRead(analogInput2);                    //Aqui se hace lo mismo que se hizo en la region anterior, solo que para el segundo canal/motor
  B2 = map(analogVal2, 0, 4095, 5000000, -5000000 );        //
  ampval2 = analogVal2 - ctH;                               //
  if (ampval2 < 0) {                                        //
    ampval2 = ampval2 * (-1);                               //
  }                                                         //
  B2 = B2 / 1000000000;                                     //
  amp2 = map(ampval2, 0, 2048, 8000, 14000 );               //
  if (ampval2 < 30) {                                       //
    B2 = 0;                                                 //
  }                                                         //
  A2 += B2;                                                 //Aqui terminan los algoritmos del segundo canal



  if (B == 0 && B2 == 0)                                    //si el valor de B y B2 es 0 es porque la palanca no se esta moviendo respecto a la calibracion
  { //que se realizo al inicio del programa
    Serial.println("Esperando comando");                    //Esperando que la palanca se mueva
    delay(100);                                             // delay gratuito, puedes descansar aqui
  }




  if (toggle == true)                                       //esta funcion solo imprime los valores de las ondas senoidales
  {                                                         //se activa con el toggle de arriba
    Serial.print(0);
    Serial.print("\t");
    Serial.print(100000);                                   //se imprimen constantes 0 y 100,000 para evitar el autorango del serial ploter del idea
    Serial.print("\t");
    Serial.print(var1);
    Serial.print("\t");
    Serial.print(var2);
    Serial.print("\t");
    Serial.print(var3);
    Serial.print("\t");
    Serial.print(bar1);
    Serial.print("\t");
    Serial.print(bar2);
    Serial.print("\t");
    Serial.print(bar3);
    Serial.println("\t");

  }

  //MOTOR #1
  var4 = amp * sin(A + Phase1);                              //Aqui se calculan los valores de cada una de las fases de cada motor
  var1 = var4 + 32768;                                       //se suma 32768/2 para que el valor del pwm se mantenga positivo osea se pone media potencia
  var5 = amp * sin(A + Phase2);                              //y varia hacia arriba y hacia abajo con los parametros dados para el ancho de pulso
  var2 = var5 + 32768;                                       //
  var6 = amp * sin(A + Phase3);
  var3 = var6 + 32768;
  //MOTOR #2                                                    
  bar4 = amp2 * sin(A2 + Phase1);                           //si se quieren observar las fases mejor en el serial ploter agregar un ofset mayor que 65,535
  bar1 = bar4 + 32768;                                      //yo use 80,000 y me funciono bien, sin embargo hay que tener cuidado de regresar el ofset a el valor 
  bar5 = amp2 * sin(A2 + Phase2);                           //dentro del rango del pwm para evitar un overflow
  bar2 = bar5 + 32768;
  bar6 = amp2 * sin(A2 + Phase3);
  bar3 = bar6 + 32768; //32768;

  pwmWrite(OA1, var1);                                        //aqui se mandan los valores de cada fase en forma de pwm, es decir son las conexiones de
  pwmWrite(OA2, var2);                                        //cada fase del motor se conectan aqui
  pwmWrite(OA3, var3);
  pwmWrite(OB1, bar1);
  pwmWrite(OB2, bar2);
  pwmWrite(OB3, bar3);

  if (A >= 2 * PI)                                            //aqui se mantenen los valores de la posicion de cada motor en el rango adecuado 2*PI para ambos motores
  {
    A = 0;
  }

  if (A2 >= 2 * PI)
  {
    A2 = 0;
  }
}

Después de recibir la primera versión de la tarjeta desde china me puse a trabajar en un script sencillo en Python para mandar datos vía USB, el firmware de control en la tarjeta es básicamente el mismo pero leyendo los comandos por serial.
Aun faltan mas detalles, por ejemplo implementar control por PID ya que he notado que en ciertas ocasiones el sistema comienza a oscilar.

PD sigo sin poder subir archivos aquí, aun no se porque.
Controladora
PCB
Video

No puedes subir cualquier tamaño de archivo.
Los videos se suben a Youtube y se coloca el link, muy simple.
El PCB lo guardas en algun formato de imagen tipo jpg, png etc que no tenga mas de 2MB creo.



Yo simplemente bajé tus archivos y luego los arrastré hasta áca y ya se ven.

La placa PCB luce muy bien.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.