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
control servo sin libreria "servo.h"
#1
hola, estoy haciendo un pequeño proyecto en los que necesito controlar 4 motores de CC (solo en una dirección), y tres servos. 
lo que tengo hasta ahora es el control de 2 servos y los 4 motores, mediante 4 potenciómetros controlo los servos y un joystick controlo los 2 servos.

ahora quiero controlar otro servo y no tengo más salidas pwm (arduino Uno),
he visto el siguiente programa para controlar un servo sin la libreria "servo.h"

Código:
int servoPin = 9;  //Conectamos el servo al pin digital 9
int lapausa = 20;  // Declaramos una variable de tipo INTEGER para regular el movimiento del servo (tiempo original 20)

void setup()
{
  
  
 pinMode(servoPin, OUTPUT);     // Declaramos el pin digital 9 como salida
 digitalWrite(servoPin, LOW);   // Ponemos el pin digital 9 en LOW
}

void loop() {
for(int i = 0; i < 180; i++) // Iniciamos un bucle de 0 a 180 grados
{
  moverServo(servoPin, i);   // Movemos un poco el servomotor 
  delay(lapausa);            // Hacemos un delay definido por la variable "lapausa"

}

// Funcion para simplificar la regla de tres (modificada para un servomotor Tower PRO SG90)
void moverServo(int pin, int angulo)    // Recogemos las variables PIN y ANGULO en cada llamada 
{
   float pausa;                         // Declaramos la variable float para recoger los resultados de la regla de tres
   pausa = angulo*2000.0/180.0 + 700;   // Calculamos el ancho del pulso aplicando la regla de tres
   digitalWrite(pin, HIGH);             // Ponemos el pin en HIGH 
   delayMicroseconds(pausa);            // Esperamos con el pin en HIGH durante el resultado de la regla de tres
   digitalWrite(pin, LOW);              // Y ponemos de nuevo el pin en LOW
   delayMicroseconds(25000-pausa);      // Completamos el ciclo de y empezamos uno nuevo para crear asi el tren de pulsos
}


este sketch hace lo siguiente, el servo va de la posición 0º a 180º y vuelve otra vez a la posición inicial más lentamente. Lo que me interesa es que vaya tan rápido como sea posible a un extremo y el retorno a la posición inicial poderlo regular mediante un potenciometro (seria el mismo que el que alimenta un motor, (tienen que variar los dos a la vez la velocidad).

otro problema es que seguramente luego también intente hacer un control de los motores y servos mediante bluetooth y si tengo la librería "servo.h" no se si habrá algún problema con las dos librerías.

perdón por todo este rollo.
  Responder
#2
Creo que no habrá problema entre librerías ya que he visto varios programas utilizando varias librerías a la vez. Además lo que tengo entendido es que la librería hace eso que has puesto: genera pulsos de entre 20 y 2 creo que le dicen al servo el ángulo al que hay que ir ( mira esta vídeo: https://www.youtube.com/watch?v=llNoXMyzjYw ). Para que vaya más rápido posible a una posición, pienso que bastaría con poner directamente la instrucción de que se mueva a el ángulo [quitar el for y poner solo moverServo(servoPin, "angulo que quieras") ]
Un saludo y suerte!
  Responder
#3
Un servo controlado "a pelo" ha de realizarse utilizando un timer para una precisión decente además de para evitar pausas (delays bloqueantes) en el programa.
Te explico... un servo funciona del siguiente modo:
- Cada 20ms ha de enviarsele la posición a la que quieres que vaya y el ira a su maxina velocidad hasta alli.
- La posición del servo se indica mediante un pulso de entre 1000uS (1ms) y 2000uS (2ms) de ancho, es decir, poniendo a 1 el pin ese tiempo.
- Cada servo es un mundo y en determinados servos ese valor cambia, tambien suelen aceptar valores de refresco mas bajos que 20ms (Si envias de forma mas continua la señal menos traqueteo percibes en el servo si lo fuerzas con la mano, si no envias la señal de posición continuanente, el servo se desactiva y deja de intentar ir a la posición)

Por desgracia no puedes utilizar la funcion millis () para nada salvo para establecer el tiempo de refresco de los servos, y si no lo haces a través de un timer tendrás al microcontrolador parado unos milisegundos cada 20ms, si esto no te importa demasiado un código básico seria así:


Código:
#define pinServo1 12 //El que quieras
#define pinServo2 13 //El que quieras

long int millisAnterior = 0;
int gradosServo1 = 0;
int gradosServo2 = 0;

void setup() {
  pinMode(pinServo1, OUTPUT);
  pinMode(pinServo2, OUTPUT);
}

//Devuelve la cantidad de uS a temporizar segun los grados que le pidas (Rango 0 a 180 grados) (Hay dos funciones hechas, usa la que prefieras)
int posicionServo_0_180(int grados){
  return map(grados, 0, 180, 1000, 2000); //1000 y 2000 es el minimo y maximo de tiempo (1000 es 0 grados, 2000 es 180 grados, cambialo si es necesario)
}

//Devuelve la cantidad de uS a temporizar segun los grados que le pidas (Rango -90 a 90 grados)
int posicionServo_menos90_mas90(int grados){
  return map(grados, -90, 90, 1000, 2000);
}

void loop() {
  //Cada 20ms mandas un pulso de entre 1ms y 2ms
  if (millis() > millisAnterior + 20){
    millisAnterior = millis(); //Importante no olvidarse de actualizar esta variable
    //Codigo de todos los servos extra
    digitalWrite (pinServo1, HIGH);
    delayMicroseconds (posicionServo_0_180(gradosServo1));
    digitalWrite (pinServo1, LOW);

    //Servo 2.. lo mismo...
    digitalWrite (pinServo2, HIGH);
    delayMicroseconds (posicionServo_0_180(gradosServo2));
    digitalWrite (pinServo2, LOW);

    //Asi hasta los que quieras tu, máximo 9 servos (9 servos.. 2ms cada uno en el peor de los casos... 18ms, tu pobre arduino no podria ejecutar casi nada mas al usar delays bloqueantes como estos)
  }

}


Para actualizar la posición del servo simplemente tendrias que darle el valor deseado a las variables gradosServoX y automaticamente el servo iria a su máxima velocidad hacia ahi.

Esto lo puedes utilizar si tienes uno o dos servos a más... pero dado que este código que te he hecho es básico y no utiliza timers si no delays bloqueantes, te quitará un 10% de tiempo del procesador por cada servo que controles asi... yo esto nunca lo he hecho con arduino, si no con pics de Microchip, y he llegado a controlar hasta 6 servos asi para hacer un brazo robotico programado al 100% por mi, pero en mi caso lo realizaba utilizando timers.

Por otro lado, no tengo muy claro si te funcionará del todo bien, pues las funciones como digitalWrite, son funciones que acceden al puerto especifico que tu le digas y tardan un tiempo (Unos uS cada vez que los utilizas), lo ideal era gestionar eso accediendo al puerto de arduino directamente... pero supongo que no te afectará demasiado.


Este código en principio lo podrías utilizar con cualquier Pin de tu arduino, lo de la salida Pwm del arduino no lo tengo muy claro, pero supongo que tiene determinados pines concretos por la salida de los comparadores que debe tener internamente, aun así, casi todo es emulable por software... así que deberías poder hacer a traves de codigo el proceso necesario para controlar esos dos servos a mas sin problema.
  Responder
#4
Depende del servo, el ciclo de trabajo y el pulso puede variar. Los analógicos normalmente funcionan como te ha comentado Shellmer, pero los más modernos funcionan a frecuencias de 125Hz e incluso 250Hz (aunque suelen ser retrocompatibles). El ancho de pulso puede variar entre los 800 y los 2200 microsegundos.
  Responder
#5
(04-12-2016, 03:02 PM)WeSo escribió: Depende del servo, el ciclo de trabajo y el pulso puede variar. Los analógicos normalmente funcionan como te ha comentado Shellmer, pero los más modernos funcionan a frecuencias de 125Hz e incluso 250Hz (aunque suelen ser retrocompatibles). El ancho de pulso puede variar entre los 800 y los 2200 microsegundos.

Asi es, los que yo controlaba con un PIC16F876A admitían valores desde 800 hasta 2100uS mas o menos, y como dije en el anterior post, llegaban a admitir intervalos de refresco más bajos que 20mS (Que son 50Hz), por lo que asumo que es lo que tu has dicho, que al ser más nuevos probablemente fueran de 125 herzios.


Homer32, no utilices el código que has pasado para el control de los servos, es una chapuza como una catedral, y por lo que veo va a utilizar el 100% del tiempo del procesador para gestionar un unico servo.
Conforme a la velocidad del servo, si mandas al servo ir directamente a la posición que quieras, irá a su máxima velocidad. En ese código se ve que el chico que lo hizo quería que fuese más lento y iba cambiando el angulo progresivamente.
  Responder
#6
Gracias por vuestra ayuda,
Shellmer no entiendo bien como lo tengo que hacer.
En el void loop
moverServo (servoPin,180); aquí el servo hiria directamente a la posición de 180
Delay ( ); aquí que delay tendría que poner para dar tiempo que el servo se posicione a 180? Mi intención era que el valor de este delay estuviera relacionado con un potenciómetro.
moverServo (servoPin,0);
Delay (x);
Esto podría funcionar?


Enviado desde mi Edison 3 mediante Tapatalk
  Responder
#7
Según lo que tengo yo entendido un delay es simplemente una pausa, va a ser tiempo en el que el arduino no va a hacer nada, se queda parado. Cuando quieres controlar el tiempo de un led por ej viene bien pero ya para cuando quieres leer los datos de un sensor es horroroso. No sé si esto es así de verdad, a ver lo que te aconsejan los más experimentados.
PD: Si lo que quieres es hacer que el servo se mueva a x angulo en y tiempo se me ocurre que dividas el angulo entre el tiempo en el que se va a recorrer (para ver lo que tarda más o menos en recorrer un grado) y hacer que el servo se mueva de un grado en un grado con un delay (una pausa) de lo que has calculado antes. Repito esto es algo que se ma acaba de ocurrir ahora mismo, seguramente sea una chapuza Indeciso , pero esto es planificar , probar, fallar, volver a planificar.....
Suerte!
  Responder
#8
Shellmer he probado tu codigo y no hace nada.
podrias explicar un poco más el código y como actualizar la función milis?
  Responder
#9
(06-12-2016, 02:26 PM)homer32 escribió: Shellmer he probado tu codigo y no hace nada.
podrias explicar un poco más el código y como actualizar la función milis?

Claro que no hace nada, pues está enviando al servo constantemente a la posición de las variables gradosServo1 y gradosServo2 (Que es 0 grados, prueba a moverlos a mano cuando este encendido todo, a ver si te hacen fuerza) 
Para que eso funcione debes setearle un valor comprendido entre 0 y 180 a esas variables, con eso debería de ir el servo a la posición que le indicases y mantener su posición constantemente.

Prueba a añadir al final del loop un gradosServo1 = 90; Además cambia el numero del pin arriba al de tus servos.
No he probado el código porque no tengo un arduino a mano (Salvo el de la impresora 3D...), pero en un principio debería funcionarte minimamente.


La función millis() te da el numero de milisegundos transcurridos desde que has encendido el arduino, tu no debes actualizarla, solo leerla, es útil para hacer delays sin la función delay(), evitando que el micro se quede tonto sin hacer nada en las esperas.
  Responder
#10
Gracias Shelmer por tu ayuda y paciencia....
efectivamente el servo se mueve a la posición que le indico en el inicio del programa donde le doy el valor inicial a las variables int gradosServo1 = 0;
luego también e probado lo de añadir una nueva posición al final del loop un gradosServo1 = 90; y efectivamente va hasta la posición de 90 y se mantiene, esta trabajando porque haciendo fuerza con la mano no se mueve.
luego lo que me interesaba es que una vez vaya a la posición de 180º y luego retorne a 0º, espere un tiempo que lo determinara un potenciometro conectado a una entrada digital, esto es lo que quiero que haga.
en el void setup has puesto:
int posicionServo_0_180(int grados) {
return map(grados, 0, 180, 1000, 2000); //1000 y 2000 es el minimo y maximo de tiempo (1000 es 0 grados, 2000 es 180 grados, cambialo si es necesario)

yo tendria que variar la variable grados, pero esto no tendria que estar en el void loop?
entiendo que esto último hace esto, crea la variable int posicionServo_0_180 y su valor sera la variable grados,
luego hacemos un mapeo de la variable grados, depende del valor de grados nos dara un valor entre 1000 y 2000

esta función que hace exactamente?
delayMicroseconds (posicionServo_0_180 (gradosServo1)); temporiza en microsegundos, la variable posicionServo_0_180 y esta otra parte (gradosServo1)) que hace? esto seria la posición a la cual se tendria que desplazar el servo?, pero como al iniciar la variable tenemos un valor 0? no entiendo exactamente este trozo.

Shelmer , gracias por tu paciencia.


como puedes ver no tengo mucha idea de programar, hasta ahora para hacer un temporizador solo habia utilizado la función delay y cuatro funciones basicas, tambien hace tiempo habia programado algun pic con el programa flowcode que utiliza diagramas de bloques y es bastante intuitivo.
  Responder
#11
(07-12-2016, 09:47 AM)homer32 escribió: Gracias Shelmer por tu ayuda y paciencia....
efectivamente el servo se mueve a la posición que le indico en el inicio del programa donde le doy el valor inicial a las variables  int gradosServo1 = 0;
luego también e probado lo de añadir una nueva posición al final del loop un gradosServo1 = 90;  y efectivamente va hasta la posición de 90 y se mantiene, esta trabajando porque haciendo fuerza con la mano no se mueve.
luego lo que me interesaba es que una vez vaya a la posición de 180º y luego retorne a 0º, espere un tiempo que lo determinara un potenciometro conectado a una entrada digital, esto es lo que quiero que haga.
en el void setup has puesto:
int posicionServo_0_180(int grados) {
 return map(grados, 0, 180, 1000, 2000); //1000 y 2000 es el minimo y maximo de tiempo (1000 es 0 grados, 2000 es 180 grados, cambialo si es necesario)

yo tendria que variar la variable grados, pero esto no tendria que estar en el void loop?
entiendo que esto último hace esto, crea la variable int posicionServo_0_180 y su valor sera la variable grados,
luego hacemos un mapeo de la variable grados, depende del valor de grados nos dara un valor entre  1000 y 2000

esta función que hace exactamente?
delayMicroseconds (posicionServo_0_180 (gradosServo1));  temporiza  en microsegundos, la variable posicionServo_0_180 y esta otra parte (gradosServo1)) que hace? esto seria la posición a la cual se tendria que desplazar el servo?, pero como al iniciar la variable tenemos un valor 0? no entiendo exactamente este trozo.

Shelmer , gracias por tu paciencia.


como puedes ver no tengo mucha idea de programar, hasta ahora para hacer un temporizador solo habia utilizado la función delay y cuatro funciones basicas, tambien hace tiempo habia programado algun pic con el programa flowcode que utiliza diagramas de bloques y es bastante intuitivo.

Cuando tu declaras algo asi:

Código:
int nombreDeLaFuncion(){
 return valorADevolver;
}


Lo que esto hace es devolver ese valor a la sección de código desde donde lo llamas... deberías verte un poco la estructura de programación de arduino y lo que son las funciones que retornan void(nada), int(un numero entero), float(un numero decimal), double(un decimal tambien) y boolean(un booleano, true o false)

Para que lo entiendas te lo desgloso como si lo programase linea por linea sin juntar nada:
Esta es la función que te puse: 
Código:
delayMicroseconds (posicionServo_0_180 (gradosServo1));

Esta es la función desglosada:

Código:
int grados = 90;
int microsegundosDelServo = posicionServo_0_180(grados);   ==>> Esto es lo mismo que int microsegundosDelServo = posicionServo_0_180(90); 
delayMicroseconds(milisegundosDelServo);

La variable esta inicializada arriba del todo a 0, por tanto, nada más encender el arduino, el servo se irá a la posición de 0 grados.
  Responder
#12
gracias por la expicación, algo más claro me queda.
ya te dije que programar no se mucho estoy empezando.
  Responder


Posibles temas similares…
Tema Autor Respuestas Vistas Último mensaje
  Arduino nano y servo de rotación continua Bear 2 299 04-03-2022, 08:07 PM
Último mensaje: Bear
  Funcionamiento incorrecto servo Bear 1 490 28-05-2021, 06:48 PM
Último mensaje: Bear
  Control calefacción central arduino (colaboradores) jgarridc 0 1,011 27-11-2018, 08:33 PM
Último mensaje: jgarridc
  CONSULTA Re: Arduino Mega, 1 servo ,1 nema, 3 motor DC carlos hop 8 2,650 26-09-2018, 01:30 PM
Último mensaje: Shellmer
  APORTE Control de Persiana por bluetooth kuadri 0 1,467 16-06-2018, 11:33 PM
Último mensaje: kuadri