Antes de nada, gracias por leerme.
Estoy intentado controlar el condensador variable de una delta loop movido con motor paso a paso y controlado con Arduino UNO. Hasta ahora he conseguido mover el motor con pulsadores para controlar los giros y la velocidad pero lo que me interesa y no consigo es hacer que el motor gire a posiciones fijas.
Me explico, la antena está diseñada para las bandas de 30 a 80m por lo tanto, lo interesante sería girar el potenciómetro, con la ayuda de un dial calibrado, en las posiciones para cada banda, de modo que si giro el pot y lo sitúo en la posición de 40m el condensador variable gire para sintonizar esa banda y con los pulsadores (izquierda y derecha) hacer el ajuste fino.
El giro del condensador variable puede ser de 180º o 360º (no tiene tope) aunque la sintonía puede hacerse entre 0º y 180º. El dial podría ser algo así.
He investigado en Internet y no encuentro un código que me pueda servir de base para este proyecto, por eso agradecería cualquier ayuda para conseguir mover el motor paso a paso de una posición a otra.
El motor es unipolar 28BYJ-48 y el driver ULN2003. El acoplamiento entre el eje del motor y del condensador variable lo hago con HLTNC flexible.
73.
Un cordial saludo.
EA7AHG
Paco Andrés
Buen día, Paco.
Yo hice este sistema del amigo Jose Bascon, EA7HVO, y va de maravilla. El sistema es para poder controlar tres antenas con motor paso a paso y memorizar las posiciones fijas con sus megaciclos correspondientes en el menú muy fácil de manejar y yo uso sólo uno de los tres. El artículo es muy muy completo y fácil de realizar.... lo hice yo, que no se nada apenas de arduino y menos de programación. Espero que te sirva, que seguro que si, como a mi y lo puedas hacer como yo. Los componentes son económicos y tienes también el archivo para imprimir la caja de control.
Aquí te dejo el link de la página:
https://www.instructables.com/Controller-for-3-Magnetic-Loop-Antennas-With-Endst/
También te comento que la unión/acople del eje del motor con el condensador variable ha de ser de material no conductor, plástico o algo así para que no produzca un pequeño ruido si lo unes metálicamente eje con eje. Eso me iba a volver un poco loco hasta que hice esto y perfecto. Es una maravilla como queda y funciona. Controlas los pasos de inicio y paro en cualquier banda, memorizandolo en el menú fácil de usar. Espero que te sirva como a mi. Un abrazo y 73 de Juan, EA7JTT.
(No necesitas poner interruptores de final de carrera ni nada de eso, sólo deja un margen de pasos de al principio y al final, y ya está. Yo uso un condensador de vacio y tienes mucho margen para lo de la cantidad de vueltas sin problemas.)
Gracias Juan José por tu rápida y atenta respuesta.
Voya echar un vistazo a lapágina que me indicas, creo que es lo que necesito. De hecho, yo también tengo una pantalla LCD para ver el sentido de giro y la velocidad del motor.
La pieza que une el eje del rotor del CV y del motor es flexible y de materialaislante. Además, había pensado hacer un choque de RF junto al motor y otro a la entrada de la caja del mando con el cable que manda los impulsos a las bobinas del motor paso a paso, aunque la alimentación la pretendo hacer con una batería sin conexión a la red. No sé si en tu caso todo esto es necesario.
Si tengo algún problema me pongo en contacto contigo ya que estamos cerca.
Gracias de nuevo.
Un cordial saludo.
EA7AHG
Paco Andrés
Bueno, tienes varios métodos o sistemas para preseleccionar la posición final de un motor. No he trabajado nunca con un rotor paso a paso pero si he programado un sistema que selecciona una dirección de antena con la precisión de un grado. La preselección se puede realizar con un encoder y la forma correcta de actuar sobre el mCU de un UNO es utilizar las interrupciones que están en los pines digitales 2 y 3.
Cualquier movimiento en el encoder detiene el flujo del programa y permite seleccionar una dirección de giro, luego de seleccionar el punto donde quieres que se detenga el motor que gira el condensador, en mi caso, pulsando el pulsador del mismo encoder pasa de la posición de lectura al inicio del giro hasta que está en la posición seleccionada.
Lo métodos se definen en el setup() con una función nativa;
attachInterrupt (digitalPinToInterrupt (interrupt0Pin), do_encoder_cw, CHANGE); //CHANGE indica que se ejecuta cada vez que que hay un cambio
attachInterrupt (digitalPinToInterrupt (interrupt1Pin), do_encoder_ccw, CHANGE); //de valor en el encoder pero se puede programar cuando pasa de
// LOW, FALLING, RISING
https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/
digitalPinToInterrupt (); //, selecciona el número de interrupción que en este caso es el pin digital 2 (giro a derecha o CW)
do_encoder_cw (); // es una función que se ejecuta secuencialmente cada vez que el encoder se mueve un paso a la derecha.
do_encoder_ccw (); // es una función simétrica que se ejecuta cada vez que el encoder se mueve a la izquierda (CCW=
void do_encoder_cw () {
if (rotating) delay (1);
if (digitalRead (interrupt0Pin) != setCW) {
setCW = !setCW;
if (setCW && !setCCW) encoderPosition -= 1;
if (encoderPosition == 0) encoderPosition = maxDegrees;
rotating = false;
}
}
El código lo tengo en revisión y es el repo está un poco revuelto, pero se puede leer con buena voluntad y funciona bién.
https://github.com/argulab/digital-console-for-G450C/blob/main/rotatorG450C_1.2/rotatorG450C_1.2.ino
Las funciones están en las líneas 91 y 101
En realidad estoy trabajando en una nueva consola con pantalla gráfica para que represente la esfera de giro de la antena.
En cualquier caso, en mi experiencia, si se trata de preseleccionar una dirección, bien sea de giro de un rotor de antena o, como en tu caso, de un condensador variable de ajuste, si se emplea un encoder es importante ajustarse al sistema de interrupciones del mCU que utilices. Si se conecta el encoder a otro pines digitales, puede funcionar, pero producirá saltos y lecturas erróneas. Esto en lo que pasa con los encoder del código de K3NG que es bastante deficiente (por experiencia), con el manejo de las interrupciones, el codificador funciona como un Stradivarius.
La cultura del esfuerzo se cultiva desde la motivación, no mediante el castigo como algunos quisieran.
http://www.enioea2hw.wordpress.com
73, Enio
Paco EA7AHG:
Es fantástico ver cómo en este foro se comparten los conocimientos para la educación y el entretenimiento de todos. Espero ver tu código resultante, para seguir el espíritu de compartir con todos.
jon, ea2sn
Jon, EA2SN / AE2SN
... el que lee mucho y anda mucho vee mucho y sabe mucho. (Don Quijote, libro segundo, capítulo XXV)
Examinador Voluntario para la FCC (EE. UU.) con ARRL-VEC 4BDXCC como EE2A con una vertical y 5-100 W
Gracias Enio y Jon por interesaros por el tema.
Como dice Jon es muy importante el aportar para crecer en cuanto al conocimiento y el saber. Yo tengo que confesaros que me estoy iniciando en esto de la programación para Arduino, por ello, no me atrevo a publicar ningún archivo ino sobre todo cuando veo algo como lo publicado por EA7HVO
https://www.instructables.com/Controller-for-3-Magnetic-Loop-Antennas-With-Endst/
Por ello, estoy estudiando toda la información aportada por EA7HVO y dejo de momento el proyecto con 4 pulsadores y potenciómetro, de hecho ya he pedido los materiales necesarios (motor paso a paso 17HS08-1004S, CNC-Shield-Expansion-Board-A4988, controlador de Motor paso a paso A4988 DRV8825, mini interruptor de fin de carrera) excepto la pantalla LCD y Arduino UNO que ya los tengo.
73
Un cordial saludo.
EA7AHG
Paco Andrés
A mí también me gusta que se comparta el conocimiento.
Si quieres buenas respuestas haz buenas preguntas
73 de Angel, EA2ET.
Bueno Paco Andrés. Si te estás iniciando en la programación para Arduino, la experiencia que te puedo transmitir es que antes de iniciar un proyecto tomes algunas decisiones que te facilitarán el desarrollo. Todas decisiones se encuadran en el desarrollo ágil de software.
https://es.wikipedia.org/wiki/Desarrollo_%C3%A1gil_de_software
Es un enfoque profesional que te facilita la vida aunque utilices la programación como hobby. El objetivo del desarrollo ágil es escribir un código que resulte legible, exento de débitos técnicos y auto documentado.
Una de las primeras cuestiones que debes entender es el fundamento del lenguaje. Es frecuente encontrar en en Internet muchos programas escritos por aficionados que probablemente funcionan aunque su comprensión se complica, incluso para el mismo autor. Para que esto no ocurra es importante crear reglas.
La primera son los nombres de las funciones y las variables. Cada una debe estar autodefinida. Ejemplos:
do_button_ccw_pushed (), un método que se ejecuta cuando de pulsa determinado botón.
on_realay_ccw_high (), método que se ejecuta cuando determinado relé está activo.
Es importante conocer los tipo de variables y su longitud, por eso es mejor utilizar las definiciones de C++, por ejemplo:
uint8_t, es un entero sin signo (sólo positivo) de un byte
uint16_t es un entero sin signo de dos bytes, lo mismo que "unsigned int"
uint32_t es un número entero de cuatro bytes
En C++ es importante definir los métodos antes de que sean invocados por otro, por ejemplo, aunque en Arduino funciona, es mejor que las funciones:
void setup () {}
loop () {}
sean las últimas en este orden y sigas siempre una metodología igual, tanto en el orden de declaraciones, el formato de los nombres de los métodos (funciones) o de las variables. Simplemente porque cuando el código crece, llega un momento en el que el mismo autor se pierde y esto crea bugs y débitos técnicos.
Evita en lo posible instrucciones de decisión anidadas, esto complica el código y reduce al mínimo el código del loop ().
He revisado el código que ha propuesto EA7JTT y por un lado mi admiración por el enorme trabajo realizado. El código se compila y, probablemente funcionará. Sin embargo, me cuesta un esfuerzo enorme entenderlo. Creo que se pueden escribir las mismas instrucciones con mayor claridad. Nunca se trata de copiar un código, eso no genera conocimiento, hay que entenderlo y hay que modifciarlo para mejorar.
La cultura del esfuerzo se cultiva desde la motivación, no mediante el castigo como algunos quisieran.
http://www.enioea2hw.wordpress.com
73, Enio
Por ejemplo, C++ es un lenguaje híbrido de programación estructurada orientado a objetos. Permite la programación de clases y la separación del código en diferentes archivos.
Una de las primeras modificaciones que haría el código citado es crear una clase display (o pantalla). Como muestra, la dirección que incluyo remite a mi repo en GitHub en la que he creado una clase Display, para toda gestión de una pantalla TFT de 2,8'' que utilizo en el decodificador CI-V para el selector automático de antenas y el reloj digital dual.
Esta clase se contiene en dos archivos.
Cabecera display.h y los métodos display.cpp
https://github.com/argulab/CI_V-control-with-Arduino/blob/master/decoder_11/display.cpp
https://github.com/argulab/CI_V-control-with-Arduino/blob/master/decoder_11/display.h
Esta es una de las clases del programa que en conjunto tiene unas 2500 líneas, pero el loop () solo se dedica a revisar eventos.
void loop () { | |
bool frequencyRead; | |
rigstate rigStatus = rig.read_power_state(); | |
if (PreviousRigState != rigStatus) | |
on_radio_state_change (rigStatus); | |
if (rigStatus == ON) { | |
if (btn.button_pressed (ANTENNA_MODE_BUTTON_PIN)) { | |
AntennaMode = AntennaMode == AUTOMATIC ? MANUAL : AUTOMATIC; | |
dsp.display_antenna_mode (AntennaMode); | |
} | |
if (elapsed_radio_read_millis ()) | |
rig.request_frequency (); | |
if (Serial1.available ()) | |
frequencyRead = rig.read_frequency (); | |
#ifdef DEBUG_FRAME | |
rig.debug_frame (); | |
#endif //DEBUG_FRAME | |
if (frequencyRead) | |
on_read_frequency (); | |
if (AntennaMode == MANUAL && btn.button_pressed(UP_BUTTON_PIN)) | |
on_up_button_pressed(); | |
} | |
if (btn.button_pressed (DATETIME_MODE_BUTTON_PIN)) | |
DatetimeMode = DatetimeMode == NORMAL ? SETTING : NORMAL; | |
if (DatetimeMode == SETTING) { | |
wtc.set_datetime_service (); | |
wtc.init_watch (); | |
DatetimeMode = NORMAL; | |
} | |
if (DatetimeMode == NORMAL && elapsed_datatime_read_millis ()) | |
wtc.service_datetime (); | |
} |
Observa poor ejemplo la expresión ternaria:
DatetimeMode = DatetimeMode == NORMAL ? SETTING : NORMAL;
sustituye a un código complejo:
if (DatettimeMode == NORMAL) {
DatetimeMode = SETTING;
else {
DatetimeMode = NORMAL;
{
{
Una serie de instrucciones que siguen a una condición, se sacan fuera del loop a una función externa (programación estrcuturada)
por ejemplo:
if (frequencyRead)
on_read_frequency ()
en lugar de:
If (frequencyRead) {
uint32_t frequency = rig.decode_frequency (); | |
#ifdef DEBUG_FREQUENCY_READ | |
Serial.print ("Freccuencia = "); | |
Serial.println (frequency); | |
#endif//DEBUG_FREQUENCY_READ | |
if (frequency <= 181000 || frequency >= 5200000) | |
return; | |
service_frequency (frequency); | |
bands activeBand = rig.decode_band (frequency); | |
#ifdef DEBUG_ACTIVE_BAND | |
Serial.print ("Banda Activa = "); | |
Serial.println (rig.band_to_name (activeBand)); | |
#endif //DEBUG_ACTIVE_BAND | |
service_band (activeBand); | |
if (AntennaMode == AUTOMATIC) | |
on_automatic_mode (activeBand); |
}
Una condición excluyente te evita un bucle, ejemplo:
if (frequency <= 181000 || frequency >= 5200000) |
return; |
en lugar de incluir un primer nivel de condidión:
if (frequency >= 181000 && frequency <= 5200000) {
// more code
}
Analiza la función, queremos evitar el proceso de cualquier lectura de frecuencia fuera de los límites, esto puede ocurrir por el "ruido" generado en el sensor), la primera función aborta el proceso al inicio y devuelve el control al loop (), la segunda opción ejecuta el proceso si la condición es cierta. Ambas funciones hacen lo mismo, pero el código es más claro y mejor estructurado porque ya de inicio eliminamos huna anidación.
La imagen es de la pantalla del display,
La primera línea es la fecha,
La segunda línea es la hora UTC
La tercera más grande es la hora local y el reloj del shack
La cuarta línea indica la banda y la frecuencia con precisión de 10 Hz,
la quinta línea indica la antena activa.
El recuadro de la izquierda indica si el selector de antena es manual o automático
El recuadro de la derecha indica si el ATU remoto está activado o no.
La cultura del esfuerzo se cultiva desde la motivación, no mediante el castigo como algunos quisieran.
http://www.enioea2hw.wordpress.com
73, Enio
Gracias Enio.
Se ve que estás bastante puesto en programación. Leyéndote estoy aprendiendo bastante y rápido.
A partir de ahora voy a intentar simplificar expresiones y emplear más las llamadas a eventos dentro del bloque loop().
Como tú indicas, no sólo me limito a copiar el código sino que además lo estoy desmenuzando y viendo el porqué de las distintas expresiones, eventos y bloques del código.
Gracias una vez más. 73
Un cordial saludo.
EA7AHG
Paco Andrés
Saludos.
Como indqué en mi última aportación, he encontrado un trabajo muy interesante en https://circuits4you.com/2016/05/13/rotary-encoder-arduino-ky-040/ . En él se describe como controlar un motor paso a paso con un Encoder rotativo.
Sigo investigando la manera de completar el proyecto con una pantalla LCD con I2C y menú para guardar/recuperar memorias con posiciones del motor paso apaso correspondientes a frecuencias.
73
Un cordial saludo.
EA7AHG
Paco Andrés
QDURE - https://qsl.ure.es
Imprime y confirma tus QSL en tan solo tres click.
Nunca fue tan fácil y cómodo
el confirmar tus contactos.
TIENDA ONLINE URE
Publicaciones, mapas, polos, camisetas, gorras, tazas, forros polares y mucho más...
WEBCLUSTER EA4URE
Conoce el nuevo WebCluster de URE, ahora con nuevos filtros e información y compatible con GDURE