This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm whether you accept or reject these cookies being set.

A cookie will be stored in your browser regardless of choice to prevent you being asked this question again. You will be able to change your cookie settings at any time using the link in the footer.

  • 0 voto(s) - 0 Media
  • 1
  • 2
  • 3
  • 4
  • 5
problemas salida PWM arduino UNO
#1
Hola, 
estoy intentando controlar varios motores y servos con arduino y una app que hecho con appinventor2.
su funcionamiento es sencillo, con seis sliders regulo cuatro motores y dos servos.
La app manda una cadena de datos al arduino. Esto parece que funciona, con el monitor serial veo que llegan los datos bien.
el problema es que si por ejemplo solo muevo un slider de un motor se mueven los tres. 
He mirado con un miniosciloscopio y veo que el pin pwm que tengo configurado con el slider tiene un valor pwm correcto, pero observo las otras salidas y tambien tienen señal pwm y sus sliders estan a 0.
Alguien sabe que puede pasar?
adjunto el sketch de arduino a ver si alguién tiene idea de que puede pasar o tiene una idea mejor para que esto no suceda.

La señal que que envia desde la app es un valor de 133 (en la app lo tengo de 0 a 255), la señal en el pin 3 a nivel alto es de unos 1060 microsegundos, aproximadamente a nivel bajo esta los mismos microsegundos, si vario el slider de la app esta señal tambien varia correctamente.

El problema esta en el pin 5 y 6 tengo una señal a nivel alto de 248 microsegundos, cuando tendría que estar a 0,


gracias.

// simulación roboping con sliders v1_1

#include <SoftwareSerial.h>  // libreria para poder utilzar otros pins de comunicación
#include <Servo.h>
SoftwareSerial BT(12, 13); // RX, TX para hacer pruebas utilizo los en los pines 0 y 1
int motor1 = 3;    //pin motor inferior
int motor2 = 5;    //pin motor superior izquierda
int motor3 = 6;    //pin motor superior derecha
//int motor_elevador =11;    //pin motor elevador
//SoftwareSerial BT(7,8); // RX, TX
//int motor1 =3;    //pin motor inferior
//int motor2 =5;    //pin motor superior izquierda
//int motor3 =6;    //pin motor superior derecha
//int motor_elevador =11;    //pin motor elevador

//int servo_h_pin =3;
//int servo_v_pin =5;
int servo_h_pin = 9;
int servo_v_pin = 10;
//int servo_pisto_pin =7;

Servo servo_h;      // crea el objeto servo horizontal
Servo servo_v;      // crea el objeto servo vertical
//Servo servo_pisto;
//int pos_horizontal = 0; //posición inicial del servo horizontal
//int pos_vertical = 0; //posición inicial del servo vertical

void setup()
{
  BT.begin(9600);  // velocidad del puerto del módulo bluetooth
  Serial.begin(9600);

  pinMode (motor1, OUTPUT); // declaramos el los motores como salidas
  pinMode (motor2, OUTPUT); // declaramos el los motores como salidas
  pinMode (motor3, OUTPUT); // declaramos el los motores como salidas
  //pinMode (motor_elevador,OUTPUT); // declaramos el los motores como salidas

  servo_h.attach (servo_h_pin); // vincula el servo horizontal al pin 9
  servo_v.attach (servo_v_pin); // vincula el servo vertical al pin 10
  //servo_pisto.attach (servo__pisto_pin);// vincula el servo que controla el piston con el pin 11

  servo_h.write (90);
  servo_v.write (90);
  //servo_pisto.write (15);

}

void loop()
{
  // cuando haya datos disponibles
  while (BT.available () > 0 )
  {
    delay(5);
    int valor_servo_h = BT.parseInt();  //leemos el primer valor entero (servo horizontal) y lo almacenamos en la variable
    int valor_servo_v = BT.parseInt();  //leemos el segundo valor entero (servo vertical) y lo almacenamos en la variable
    int valor_motor3 = BT.parseInt();   //leemos el tercer valor entero (motor superior derecha) y lo almacenamos en la variable
    int valor_motor2 = BT.parseInt();   //leemos el cuarto valor entero (motor superior izquierda) y lo almacenamos en la variable
    int valor_motor1 = BT.parseInt();   //leemos el quinto valor entero (motor inferior) y lo almacenamos en la variable
    //int valor_m_elevador = BT.parseInt();  //leemos el último valor entero (motor elevador) y lo almacenamos en la variable
    // int valor_servo_pisto = BT.parseInt(); //leemos el último valor entero (motor elevador) y lo almacenamos en la variable

    // cuando lea el carácter fin de línea ('\n') quiere de decir que ha finalizado el envío de los 6 valores
    if (BT.read() == '\n')
    {
      //enviamos los valores recibidos de los sliders a los pines de los motores y servos
      servo_h.write (valor_servo_h);
      servo_v.write (valor_servo_v);
      //servo_pisto.write (valor_servo_pisto);
      analogWrite (motor3, valor_motor3);
      analogWrite (motor2, valor_motor2);
      analogWrite (motor1, valor_motor1);
      //analogWrite (motor_elevador,valor_m_elevador);

      Serial.println(valor_servo_h);
      Serial.println(valor_servo_v);
      Serial.println(valor_motor3);
      Serial.println(valor_motor2);
      Serial.println(valor_motor1);
      //BT.println(motor_elevador,valor_m_elevador);

      delay (100);
    }
  }
}
  Responder
#2
El println de los 3 motores te devuelve valores iguales o diferentes?
  Responder
#3
No son valores diferentes, corresponden con los valores que recibe de la app


Enviado desde mi PRA-LX1 mediante Tapatalk
  Responder
#4
¿Cuál es el programa de App Inventor?
  Responder
#5
Tu problema es que estas usando los pines 5 y 6... esos pines son controlados por el timer0, este timer es el encargado de contar los ms que transcurren desde el encendido que recibes cuando utilizas la función millis(), por ello la gestión del pwm no es perfecta. La solución seria que utilizases otros pines, como por ejemplo el 9, 10 o 11 para controlar los motores.

Cita:The PWM outputs generated on pins 5 and 6 will have higher-than-expected duty cycles. This is because of interactions with the millis() and delay() functions, which share the same internal timer used to generate those PWM outputs. This will be noticed mostly on low duty-cycle settings (e.g. 0 - 10) and may result in a value of 0 not fully turning off the output on pins 5 and 6.
Link:
https://www.arduino.cc/reference/en/lang...alogwrite/


Ahora viene el problema... por lo que veo estas utilizando 3 motores DC y dos servos, pues bien, para controlar la velocidad de los motores DC si o si necesitas una salida PWM, sin embargo, para los servo estas utilizando la librería de servo.h. Esta librería permite la gestión de más de 12 servos a la vez pero tiene una pega... utiliza el timer1 para gestionar estos motores, y este timer comparte sus funciones con el PWM de los pines 9 y 10.

En resumen... necesitas 3 salidas PWM para los motores. Tienes disponibles los pines 3,5,6,9,10,11 en el arduino uno. Los pines 5 y 6 no los puedes usar correctamente debido a la interferencia del millis(), y en los pines 9 y 10 te es anulada la función de pwm por la libreria servo.h. En resumen... te quedas con 2 pines PWM para usar, insuficientes.

Por ultimo necesitas 2 salidas normales para los servo... estos pines no son problema ya que la liberia servo.h precisamente se encarga con el timer1 de gestionar cualquier pin (incluso pines sin pwm) para que le envíen la señal que necesitan para saber su posición a los servo (que no es un pwm, si no realmente una señal en alto de entre 0.9 y 2.1ms de duración cada 20ms para que el servo sepa su posición)



Siento decirte que utilizando un arduino uno no vas a poder hacer funcionar esto de una manera convencional, te recomiendo que consigas un arduino mega y lo hagas con el. Teniendo en cuenta que su precio es prácticamente el mismo creo que es tu mejor opción.

Por ultimo... si te obcecas en querer hacerlo si o si con un arduino uno, siempre puedes intentar utilizar el timer2 para gestionar los servos y no utilizar la libreria de servo.h y así liberar el timer1 y los pines 9 y 10, el timer2 es el encargado de gestionar la función tone() que probablemente no utilices. Creo que hay librerias que utilizan el timer2 para gestionar algunos servo (como esta: https://github.com/nabontra/ServoTimer2), pero como nunca lo he probado no te puedo asegurar que funcione, y personalmente... no se cual será tu nivel en programación, pero si no es muy alto yo no me metería en estos fregados.
Aun así, si lo intentas, buena suerte, así es como se aprende, además, no tienes nada que perder!


EDIT: Se me ha ocurrido una idea que podría o no funcionar, como tienes problemas con los pines 5 y 6 en el sentido de que nunca se desactivan del todo, podrías intentar hacer que si el valor es 0, entonces usar un digitalwrite 0, quizá así se te desconecte la salida y se te quede en modo digital sin pwm... no se si funcionará, aun así, te recomiendo que tires de un arduino mega ya que por lo que vi en tu código, tienes mas motores que 3 y las salidas pwm se te van a quedar justas o ser insuficientes.
  Responder
#6
Gracias por responder tengo algún Arduino mega probaré con este.
Miraré el tema de los timers para el mega i que no me afecte

Enviado desde mi PRA-LX1 mediante Tapatalk
  Responder
#7
https://www.luisllamas.es/salidas-analog...n-arduino/

Ahi tienes los timers de uno y mega asi como que timers utilizan la funcion servo, spi y tone.
  Responder
#8
Umm... viendo el link que ha pasado Nullz lo cierto es que estoy viendo que si usases el timer2 anularias el pwm de los pines 3 y 11, asi que estarias igual que usando la libreria servo normal y anulando los 9 y 10.

La mejor opcion en tu caso va a ser usar el mega, echale un ojo al blog de luisllamas, esta muy bien redactado y explica muy bien muchisimas cosas. Por desgracia yo empece aprendiendo a programar microcontroladores de microchip... si no este tipo de info me habria venido muy bien...
Por ultimo, recuerda que en la propia web de arduino se explican todas las funciones que este tiene disponible y si te ocurren cosas raras siempre puedes buscar la documentación.
Habitualmente ya avisan de detalles como estos de perder pines en ella, y como has visto en el link que yo te puse hasta avisan del problema en el pwm de los pines 5 y 6.
  Responder
#9
Gracias miraré los links.
La página de Luis Llamas la consulto algunas veces la verdad es que está muy bien.
El tema de programar es por hooby y la verdad me queda mucho por aprender.
Hace muchos años hice electrónica pero nunca programe ningún micro.
Ya que estamos puestos ahora una pregunta de electrónica.
He hecho una SHIELD para controlar estos motores. Consta de unos transistores bd139 para controlar los motores van a 12V.
Para la alimentación de los servos utilizo dos DC-DC buck convertes para reducir la tensión hasta 5.5V.
El problema es que el servo no se mueve y los convertes se calientan muchísimo.
Los negativos de los convertes y los de Arduino están unidos.
Los servos son mg 946 si no recuerdo mal.
La señal del servo varía cuando variamos el slider que controla el servo
Perdón por el rollo.


Enviado desde mi PRA-LX1 mediante Tapatalk
  Responder
#10
Pues la verdad, mi fuerte es la programación y lo que se de electronica es lo aprendido de andar por casa cacharreando... vamos, autodidacta total.

Lo primero de todo es indicarte que si un servo no recibe su señal cada 20ms (mas o menos), el servo se queda muerto, es decir, aunque lo tengas alimentado no se va a mover y deberias poder forzar su posición y girarlo libremente sin que te corrija la posición. Si puedes girarlo sin que se te resista deberias comprobar si la señal le esta llegando correctamente.

Como dices que se te calientan, no me tendria mucho sentido que lo hiciesen si no esta el motor manteniendo su posición, y juraria que una vez llegan a su posicion el motor se apaga hasta que tu lo fuerzas y detecta que se esta alejando de la posicion que tu le indicas. En este caso el consumo deberia bajar y no se te deberia calentar ni el servo ni el buck.

Debes tener especial cuidado con el valor de posicion que le envias al servo ya que cada servo es un mundo y algunos admiten valores de entre 0.9ms y 2.1ms de señal en alto mientras que en otros este rango es menor, y muchas veces si les envias un valor incorrecto los servos se estan esforzando en llegar a una zona que no pueden llegar debido al tope mecanico que tienen.

En resumen... yo probaria a darle una señal o un angulo intermedio para probar si se bloquean o se mueven al menos. Si la señal la reciben y no se mueven ya si que deberias comprobar la fuente de alimentacion o los buck converter.
  Responder
#11
buenos dias,
finalmente tal y como habeis comentado he utilizado un arduino mega, las salidas de los motores funcionan ok y las de los 2 servos tambien.
Ahora tengo el siguiente problema quiero controlar otro servo más, este ha de hacer lo siguiente, ha de ir a una posición, esperar un tiempo y volver a la posiciión inicial una vez transcurrido este tiempo. (visto así seria la primera practica de encender un led y apagarlo con un delay  Sisi1 Sisi1 Sisi1).
El tiempo que esta en una posición u otra lo controlo mediante la variable "valor_servo_pisto" esta variable se la doy a través de la app y puede ir de 0 a 1023. Por el monitor serial veo que recibe bien los datos.
El problema que pasa es que no varia la velocidad del servo o del led, siempre es la misma, y esta es la que le he dado al iniciar la variable.
a ver si teneis alguna idea.
Otra consulta más primero prové a configurar el Serial1, para recibir datos, y no funcionaba, por casualidad probé con el Serial2 y funciona perfectamente. Sabeis que puede ser? que tenga el Serial1 roto?

os adjunto el sketch.


// simulación roboping con sliders v1_1

//#include <SoftwareSerial.h>  // libreria para poder utilzar otros pins de comunicación
#include <Servo.h>



int led =  13;      
int estadoLed = LOW;             
int valor_servo_pisto =350;

//SoftwareSerial BT(12, 13); // RX, TX para hacer pruebas utilizo los en los pines 0 y 1

int motor1 = 3;    //pin motor inferior
int motor2 = 5;    //pin motor superior izquierda
int motor3 = 6;    //pin motor superior derecha
int motor4 = 7;         //pin motor mezclador, motor que evita que las bolas se atasquen 

int servo_h_pin = 9;
int servo_v_pin = 10;
int servo_pisto_pin =11;


Servo servo_h;          // crea el objeto servo horizontal
Servo servo_v;          // crea el objeto servo vertical
Servo servo_pisto;          // crea el objeto servo pisto, es el que empuja la bola hacia arriba
//int pos_horizontal = 0;   //posición inicial del servo horizontal
//int pos_vertical = 0;     //posición inicial del servo vertical
//int pos_pisto =15;

void setup()
{
  Serial.begin(9600);                   // velocidad del puerto del monitor serie
  Serial2.begin(9600);  // velocidad del puerto del módulo bluetooth
 

  pinMode (motor1, OUTPUT);         // declaramos el los motores como salidas
  pinMode (motor2, OUTPUT);         // declaramos el los motores como salidas
  pinMode (motor3, OUTPUT);         // declaramos el los motores como salidas
  pinMode (motor4, OUTPUT);         // declaramos el los motores como salidas
  pinMode (led,OUTPUT);                 // declaramos el pin 13 como salida

  servo_h.attach (servo_h_pin); // vincula el servo horizontal al pin 9
  servo_v.attach (servo_v_pin); // vincula el servo vertical al pin 10
  servo_pisto.attach (servo_pisto_pin);// vincula el servo que controla el piston con el pin 11

  servo_h.write (90);
  servo_v.write (90);
  servo_pisto.write (15);
  delay (500);

}

void loop()
{

   servo_pisto.write(15);
   estadoLed = LOW;
   digitalWrite (led, estadoLed);
   delay (valor_servo_pisto);
   servo_pisto.write(160);
   estadoLed = HIGH;
   digitalWrite (led, estadoLed);
   delay (valor_servo_pisto);
   
 /*valor_servo_pisto = intervalo;  

 

 //intervalo = map( intervalo, 0,255,0,1023);
   //  if (intervalo <= 300)   // si el valor del potenciometro es inferior o igual a 300, intervalo valdra 300, para dar tiempo al servo que vaya a la posiciones inicial y final
   {
      intervalo = 300 ;
   }

   
   
  /*tiempo = millis();
  
      if(tiempo - tiempoAnterior > intervalo)  // pasará por aqui cada 1000 contajes
      {
        tiempoAnterior = tiempo;   
        
    
        if (estadoLed == LOW)  // es una forma de que el estado siempre cambie en función de su estado anterior
        {
          estadoLed = HIGH;
        }
         
        else
         {
          estadoLed = LOW;
         }
        digitalWrite(led, estadoLed);
        if (estadoLed == HIGH)
        {
           servo_pisto.write(15);  //Nueva posición del servo posicio trasera servo
        }
      
        else
        {
        servo_pisto.write(160);  //Nueva posición del servo posicio davantera servo
        }
      }
    delayMicroseconds (80000); 
    */
      
  // cuando haya datos disponibles
  while (Serial2.available () > 0 )
  {
    delay(5);
    int valor_servo_h = Serial2.parseInt();          //leemos el primer valor entero (servo horizontal) y lo almacenamos en la variable
    int valor_servo_v = Serial2.parseInt();          //leemos el segundo valor entero (servo vertical) y lo almacenamos en la variable
    int valor_motor3 = Serial2.parseInt();           //leemos el tercer valor entero (motor superior derecha) y lo almacenamos en la variable
    int valor_motor2 = Serial2.parseInt();           //leemos el cuarto valor entero (motor superior izquierda) y lo almacenamos en la variable
    int valor_motor1 = Serial2.parseInt();           //leemos el quinto valor entero (motor inferior) y lo almacenamos en la variable
    // int valor_m_elevador = Serial1.parseInt();    //leemos el último valor entero (motor elevador) y lo almacenamos en la variable
    int valor_servo_pisto = Serial2.parseInt();      //leemos el último valor entero (motor elevador) y lo almacenamos en la variable
    
     
    
    // cuando lea el carácter fin de línea ('\n') quiere de decir que ha finalizado el envío de los 6 valores
    if (Serial2.read() == '\n')
    {
     
      
      //enviamos los valores recibidos de los sliders a los pines de los motores y servos
      servo_h.write (valor_servo_h);
      servo_v.write (valor_servo_v);
      // servo_pisto.write (valor_servo_pisto);
      analogWrite (motor3, valor_motor3);
      analogWrite (motor2, valor_motor2);
      analogWrite (motor1, valor_motor1);
      analogWrite (motor4, valor_servo_pisto);
      
      
      
       Serial.print("valor servo horizontal:  ");
      Serial.println(valor_servo_h);
       Serial.print("valor servo vertical:  ");
      Serial.println(valor_servo_v);
       Serial.print("valor motor superior derecha:  ");
      Serial.println(valor_motor3);
      Serial.print("valor motor superior izquierda:  ");
      Serial.println(valor_motor2);
      Serial.print("valor motor inferior:  ");
      Serial.println(valor_motor1);
      //Serial.print("valor intervalo:  ");
      //Serial.println(intervalo);
      //Serial.println(servo_pisto);
      Serial.print("valor servo piston:  ");
      Serial.println(valor_servo_pisto);
       
    }   
     
  }      
}
  Responder
#12
Bueno un problema era que he declarado variables locales, cuando se reciben datos por el bluetooth. Ahora he declarado estas mismas variables como globales, al principio del scketch y ya funciona ok.
  Responder


Posibles temas similares…
Tema Autor Respuestas Vistas Último mensaje
  DUDA arduino uno + GPS + SD + SDS011 JRRAmirez 1 0 23-07-2023, 04:57 PM
Último mensaje: asesorplaza1
  exit status 1 Error compilando para la tarjeta Arduino/Genuino Uno fcojavier 26 59,300 18-03-2022, 11:26 PM
Último mensaje: asesorplaza1
  problemas arduino nano generico Lejisan 2 699 12-07-2021, 01:25 PM
Último mensaje: asesorplaza1
  problemas con arduino mega vs UGC jcvb 0 617 08-12-2020, 11:07 PM
Último mensaje: jcvb
  Placa MEGA(china) la reconoce como UNO Jaimelito 1 888 18-11-2020, 10:15 PM
Último mensaje: asesorplaza1