domingo, 20 de abril de 2014

Interesantes Interruptores

Los interruptores son la manera más fácil de comunicarnos con Arduino. Podemos conectar un pulsador a cada una de las entradas digitales y asignar una acción a cada uno de ellos. La entrada digital lee HIGH/5V en un estado del interruptor y LOW/0V en el otro y podemos pedir a Arduino que realice una acción dependiendo del estado del interruptor.

Un interruptor en un circuito eléctrico controla un solo dispositivo, mientras que con Arduino podemos asociar al interruptor una secuencia de eventos tan complicada como queramos. Ejemplo: en el video de abajo el pulsador se usa para llevar voltaje a las vías mientras está activado, pero para esto no nos haría falta una Arduino y podríamos haber conectado el interruptor al transistor; en la segunda parte, cuando se activa el interruptor, Arduino lanza una secuencia de acciones: luz verde, espera un segundo, aceleración progresiva, velocidad constante, luz roja y frenada progresiva.



Encontrareis los esquemáticos y códigos para los ejemplos al final de la entrada

Cómo

En un montaje eléctrico colocábamos el interruptor en mitad del cable de alimentación y si estaba abierto, no circulaba corriente. En electrónica de señal tenemos dos puntos de dificultad extra:

  1. Arduino lee el voltaje a la salida del interruptor para saber si está activado, pero no nos interesa que pase intensidad que daría un consumo innecesario. Ya se encargarán los transistores de hacer pasar la intensidad hacia las vías u otros dispositivos.
  2. Una entrada digital debe ver siempre un valor de 5V o 0V, no podemos dejarla al aire porque tomará un valor cualquiera.

Así que no nos vale el primer montaje que se nos ocurre:

Así no: interruptor mal conectado y además el esquemático dibujado 
en la espalda de un sobre da sensación de poca profesionalidad

Porque
  1. esto llevaría a la entrada digital tanta intensidad como suministre la fuente de 5V y la puede quemar
  2.  cuando el interruptor está abierto, la entrada no está forzada a 0V ni a 5V, y puede tomar cualquier valor.

Todo esto se soluciona añadiendo una resistencia de pull-down de 10k que forzará un 0 en la entrada mientras el interruptor esté abierto y que limitará la corriente cuando esté cerrado:

Así sí: Esquemático en una vieja factura de una
tienda de electrónica, este tío es un pro

En una configuración pull-down con el interruptor abierto, la entrada recibe 0V a través de la resistencia. Como no circula corriente no hay pérdida de voltaje y ambos lados de la resistencia ven 0V/LOW. Cuando el interruptor se cierra, circula sólo una corriente de 0.5 mA y tenemos la entrada a 5V/HIGH.

Muy bien: Esquemáticos en bloc de notas de
hotel de lujo. MegaPro

Las entradas digitales de Arduino tienen una resistencia interna de pull-up que nos puede simplificar el conexionado (ejemplo aquí) y podemos prescindir de la resistencia, pero en nuestro programa habrá que tener en cuenta:

1.Se debe declarar el uso de internal pull-up en el setup para el pin que usamos de entrada

      void setup(){
          pinMode(pinStart, INPUT_PULLUP);
      }
      
2. Con un pull-up, la lógica del interruptor se invierte: cuando está abierto da HIGH y cuando está cerrado da LOW


Lectura de un Interruptor

Deberemos declarar en setup todos los interruptores que usemos como entradas. Luego, en loop podemos tomar varias estrategias:

Caso 1: Un único interruptor lanza una función

      void loop(){
        
        while(digitalRead(pinEntrada)==0){
          delay(10);
        }
        ...
        
En este caso, Arduino arrancará y se quedará a la espera de que activemos el interruptor antes de seguir ejecutando el resto del contenido de loop. Al terminar, se vuelve al inicio y a la espera del interruptor.


Caso 2: Más de un interruptor

    void loop(){
      
      if (digitalRead(interruptor1)==HIGH){
       accion1();
      }else if (digitalRead(interruptor2)==HIGH){   
        accion2();
      }
      delay(10);  
    }

En este otro caso, loop sólo está vigilando cuál de los botones es presionado. Las acciones que se ejecutan para cada botón estarían definidas aparte en las subfuciones "accion1()" y "accion2()".

En los ejemplos anteriores tenemos dos limitaciones en nuestro programa:
-          mientras esperamos a leer el interruptor, Arduino no puede hacer nada más: todo lo que se está moviendo se sigue moviendo, todo lo parado sigue parado
-          cuando estamos realizando una secuencia de acciones, no se presta atención al interruptor. Esto puede ser peligroso si nuestro interruptor es por ejemplo un botón de parada de emergencia, al que tenemos que prestar atención sobre todo lo demás.

Para solventar estos dos problemas, los procesadores de Arduino pueden programarse para recibir interrupciones por algunas de sus entradas. Cuando se activa una interrupción se dejará de lado todo lo que se esté haciendo y se ejecutará la acción asignada a la interrupción. Más detalles aquí.


 Multitud de Interruptores

La maqueta necesitará más de un botón de control. Vale la pena construirse una placa con un pulsador para cada una de las acciones que queramos realizar. El montaje que os propongo es un ejemplo con tres pulsadores, pero se puede replicar el montaje hasta ocupar las 13 entradas digitales.


 A medida que la maqueta progresa, podemos ir  modificando las acciones de cada botón, dándoles funciones cada vez más complejas o bien asignarles funciones temporalmente para hacer pruebas.




Conexionado pull-down


Cada interruptor se conecta a 5V a tierra con una resistencia de 10k. Los pines se declaran como INPUT en setup.





Requiere la mitad de elementos, pero debemos tener presente hacer el setup de los pines como INPUT_PULLUP.


Código y Esquemáticos



   Ejemplo 1: Transistor y Pulsador (configuración pull-down)


/* TRANSISTOR INTERRUPTOR   

El tren se moverá mientras se acciona el pulsador

Aceleraciones progresivas con la función voltProgresivo  

CONEXIONES: 
  - Base del Transistor a pin Arduino 11
  - Colector del transistor a una via
  - Emisor del transistor a tierra GND
  - La otra via al positivo de la fuente de alimentación
  - Arduino conectada a la fuente de alimentación
    mediante Vin y GND, ojo a la polaridad
  
Carles F. Abril 2014  

*/
  

int base=11;  // pin para conectar la base del transistor
int interruptor=2;
int pasoVolt=10;  // paso del voltaje para aceleración progresiva
int maxVolt=120; //voltaje máximo = maxVolt *VoltajeFuente/255
int minVolt=40; //voltaje mínimo para que ruede la máquina
                //principio de la aceleración

void setup(){
    pinMode(interruptor,INPUT);
    pinMode(base, OUTPUT);//definimos el pin hacia el transistor como salida
    pinMode(13,OUTPUT);
    analogWrite(base,0);
    digitalWrite(13,LOW);
}

void loop(){
  
  if (digitalRead(interruptor)==HIGH){
    analogWrite(base,80);
    digitalWrite(13,HIGH);
    
  }else{
    analogWrite(base,0);
    digitalWrite(13,LOW);
  }
  delay(10);
  >
}



   Ejemplo 2: Secuencia de Órdenes (configuración con pull-up interno)


/* SECUENCIA DE ORDENES   

Cuando se pulsa el botón, el semáforo pasa a verde, el tren
acelera progresivamente, se mueve a velocidad constante durante
dos segundos, cambia el semáforo a rojo y frena progresivamente.

Aceleraciones progresivas con la función voltProgresivo  

CONEXIONES: 
  - Interruptor a GND por un lado y al pin 7 por otro
  - Led rojo con resistencia de 470 ohm en seria al pin 6 por un lado 
    y a GND por el otro
  - Led verde con resistencia de 470 ohm en seria al pin 5 por un lado 
    y a GND por el otro
  - Base del Transistor a pin Arduino 11
  - Colector del transistor a una via
  - Emisor del transistor a tierra GND
  - La otra via al positivo de la fuente de alimentación
  - Arduino conectada a la fuente de alimentación mediante Vin y GND, 
  ojo a la polaridad
  
Carles F., Abril 2014  


*/
  
int pinStart=7; // pin del interruptor
int ledRojo=6;  // pin para el led rojo
int ledVerde=5; // pin para el led verde

int base=11;  // pin para conectar la base del transistor
int pasoVolt=10;  // paso del voltaje para aceleración progresiva
int maxVolt=120; //voltaje máximo = maxVolt *VoltajeFuente/255
int minVolt=60; //voltaje mínimo para que ruede la máquina
                //principio de la aceleración

void setup(){
    pinMode(pinStart, INPUT_PULLUP);
    pinMode(ledRojo, OUTPUT);
    pinMode(ledVerde, OUTPUT);
    pinMode(base, OUTPUT);
    
    digitalWrite(ledVerde,LOW); //inicializa las salidas
    digitalWrite(ledRojo,HIGH);
    analogWrite(base,0);
        
}

void loop(){
  
  while(digitalRead(pinStart)==1){
    delay(10);
  }  // mientras no pulsamos el botón, 
     // damos vueltas dentro del while
  
  digitalWrite(ledVerde,HIGH); //luz verde
  digitalWrite(ledRojo,LOW);
  delay(1000);
  voltProgresivo(minVolt, maxVolt, base, 300, pasoVolt); //acelera
  delay(2000); //mantiene velocidad durante 2 segundos
  
  digitalWrite(ledVerde,LOW);  //luz roja
  digitalWrite(ledRojo,HIGH);  
  delay(600);
  voltProgresivo(maxVolt, minVolt, base, 300, pasoVolt); //frena
  analogWrite(base,0); //desactivamos el transistor
  delay(100);  //volvemos a esperar al botón  
               
}

void voltProgresivo(int startV, int endV, int digiHigh, int timeSpacing, int VSpacing){
  
  /* modifica el PWM progresivamente, en pasos de VSpacing
  (recomendado 10) cada timeSpacing (milisegundos).digiHigh is el puerto de salida
  de Arduino (4, 5, 6, 9, 10 u 11). 
  
  endV-startV debe ser divisible por VSpacing

  */
  
  /* ejemplo acelerando  voltProgresivo(80, 160, 7, 200, 10);
     example frendando  voltProgresivo(160, 80, 7, 200, 10);*/
  
  int steps = (endV - startV)/VSpacing;
  int direcc;
  
  if (steps > 0) {
    direcc = -1;
  }else{
    direcc=1;
  }
  
  for (int i=1; i < abs(steps+1); i++){  
    int salida=startV-VSpacing *i*direcc;
    if (salida > 200){
      salida = 200;
    } else if (salida < 0){
      salida=0;
    }
    
    analogWrite(digiHigh, salida);
    delay (timeSpacing);
  }
}

  
  
  




domingo, 2 de febrero de 2014

Tremenda Diatriba sobre Trenes y Transistores

El camino hacia una maqueta autónoma es largo. Hoy el primer paso: Un tren se mueve por el circuito siguiendo un programa almacenado en una Arduino que regula el voltaje del circuito mediante un transistor:


 
Los esquemáticos




y otra vista gracias a Fritzing

He usado el icono del motor para representar las vias y el tren


 
El Código


/* TRANSISTOR DEMO   

El tren se moverá durante siete segundos y parará durante cinco

Aceleraciones progresivas con la función voltProgresivo  

CONEXIONES: 
  - Base del Transistor a pin Arduino 11
  - Colector del transistor a una via
  - Emisor del transistor a tierra GND
  - La otra via al positivo de la fuente de alimentación
  - Arduino conectada a la fuente de alimentación mediante Vin y GND, 
  ojo a la polaridad
  
  */
  
int base=11;  // pin para conectar la base del transistor
int pasoVolt=10;  // paso del voltaje para aceleración progresiva
int maxVolt=120; //voltaje máximo = maxVolt *VoltajeFuente/255
int minVolt=60; //voltaje mínimo para que ruede la máquina
                //principio de la aceleración

void setup(){
    pinMode(base, OUTPUT);//definimos el pin hacia el transistor como salida
}

void loop(){
  voltProgresivo(minVolt, maxVolt, base, 200, pasoVolt); //aceleracion
  delay(5000); //se mantiene el voltaje máximo durante 5 segundos
  voltProgresivo(maxVolt, minVolt, base, 200, pasoVolt); //frenada
  analogWrite(base,0); //desactivamos el pin
  delay(3000);  //3 segundos de pausa
}

void voltProgresivo(int startV, int endV, int digiHigh, int timeSpacing, int VSpacing){
  
  /* modifica el PWM progresivamente, en pasos de VSpacing
  (recomendado 10) cada timeSpacing (milisegundos).digiHigh es 
   el puerto de salida de Arduino (3, 5, 6, 9, 10 u 11). 
  
  endV-startV debe ser divisible por VSpacing

  */
  
  /* ejemplo acelerando  voltProgresivo(80, 160, 7, 200, 10);
     example frendando  voltProgresivo(160, 80, 7, 200, 10);*/
  
  int steps = (endV - startV)/VSpacing;
  int direcc;
  
  if (steps > 0) {
    direcc = -1;
  }else{
    direcc=1;
  }
  
  for (int i=1; i < abs(steps+1); i++){  
    int salida=startV-VSpacing *i*direcc;
    if (salida > 200){
      salida = 200;
    } else if (salida < 0){
      salida=0;
    }
    
    analogWrite(digiHigh, salida);
    delay (timeSpacing);
  }
}

 
Qué hay detrás de todo esto

Dado que ya hay magníficos tutoriales sobre cómo programar Arduino, voy a centrarme más en su integración en la maqueta. De todos modos, no os dé reparo pedir detalles en los comentarios si queréis que entre más a fondo en algún tema. Dejadme que os cuente por encima cómo funcionan las salidas de Arduino.

Arduino tiene trece puertos digitales (i.e. trece sitios dónde enchufar cosas) que pueden funcionar como entradas o salidas: podemos conectar un interruptor como entrada, o un led como salida por ejemplo. Tienen solo dos posibles estados: HIGH (5 voltios) y LOW (0 voltios). Esto es un poco limitado, si vamos a conectar ahí nuestro tren, parecería que solo podemos poner dos valores de voltaje: corriendo a 5V o parado a 0V. ¿Qué hay de las aceleraciones progresivas? ¿No podemos mover un tren lentamente para simular maniobra? Pues sí, con el sucio truco del PWM.

 
PWM

Pulse Width Modulation (PWM) consiste en encender y apagar una salida muy rápido de manera que en promedio, el valor de voltaje medio esté entre el valor máximo de 5V y el mínimo de 0V. ¿En qué valor exactamente? Pues va a depender de si estamos más tiempo con el interruptor abajo o arriba. Si de cada cinco milisegundos, estamos mitad y mitad encendidos, tendremos un voltaje de 2,5V. Si estamos 4 milisegundos encendidos y 1 apagados, el valor de voltaje medio será de 4V.

Tres ejemplos de diferentes valores de PWM




De los trece puertos digitales, los que llevan el gusanito al lado pueden dar PWM: 3, 5, 6, 9, 10 y 11.

Usad la expresión

    analogWrite(puerto, valor);

para poner un voltaje en un cierto puerto. El valor se da en 255avos de 5V (204 son 4V, 178 son 3,5V…)
Comparad analogWrite (que puede dar un rango de valores de salida) con digitalWrite que solo dará 0 o 5V.

Si alguien se ha lanzado ya a conectar una salida digital a las vias y ha intentado hacer correr una locomotora se habrá llevado un chasco: no se mueve. Esto es porque Arduino apenas puede dar potencia en sus salidas. Es un buen cerebro, pero no tiene músculo. Arduino apenas tiene potencia para encender un led. Puede dar cinco voltios, pero muy pocos amperios. Es como si intentamos arrancar un automóvil con una pila de petaca: da 12V igual que la bateria del coche pero apenas tiene intensidad.

Vamos a necesitar a alguien que pueda tomar las señales del cerebro Arduino (lista pero sin fuerza) por un lado y la potencia de una fuente de alimentación (fuerte pero tonta) por otro y regular el voltaje hacia las vías: nuestro amigo el transistor.

 
Los Transistores

Podemos comparar el transistor a un grifo: tiene una cañería de entrada, una salida de agua y una llave para dejar pasar el agua o no. Con Arduino manejaremos la llave y regularemos el flujo, no de agua sino de corriente eléctrica.

Un transistor tipo NPN: la llave se denomina base, B, el lado conectado a la fuente es el colector C y el lado de salida del flujo es el Emisor E.

El símil del grifo no acaba de ser exacto porque el transistor funciona más bien como uno de esos pulsadores de fuente pública que ó están apagados ó están soltando un chorro de agua que te deja empapado, sin término medio. Pero esto ya nos va bien porque lo manejaremos con PWM y a base de pasar muy rápido de cerrado a totalmente abierto podremos tener estados de flujo intermedios.

Pero ojo, a todo esto sólo podemos mover el tren en una dirección. El transistor no puede funcionar a la inversa, sería como intentar meter agua en la cañería a través del grifo. Si queremos mover el tren hacia adelante y hacia atrás nos hará falta un puente H. Escribiré sobre el puente H mañana la semana que viene… como pronto o así.

 
Cómo seleccionar un transistor

La hoja de especificación de un transistor es un tremendo galimatías de datos y gráficos. Para aplicaciones caseras como las nuestras basta fijarnos en cuatro cosas:

Voltaje de saturación Vsat: El voltaje en la puerta que hará que pase a conducir corriente. Si queremos manejar el transistor con Arduino tiene que estar entre 2,5 y 4V, de manera que con uno de nuestras salidas HIGH estemos comodamente en la zona de conducción. Los componentes TTL siempre tienen esta característica.
Vsat < 4V
Vsat > 2,5V

Voltaje entre Emisor y Colector Vceo: Debe ser mayor que el voltaje de nuestra fuente de alimentación (que debería rondar los 15V)
Vceo > 15V

Voltaje Colector Emisor en saturación, Vce(sat): la caida de voltaje entre E y C cuando el transistor está conduciendo. A efectos prácticos, el voltaje disponible para el tren es el de la fuente de alimentación menos Vce(sat)

Potencia disipable Ptot: El transistor se calentará por el hecho de tener intensidad circulando por él. Dependiendo de la construcción de cada uno, podrá evacuar más o menos calor y podrá llevar más o menos intensidad sin quemarse. Al escoger un transistor nos hace falta saber cuanta intensidad consume nuestro tren y multiplicarlo por Vce(sat). El resultado debe ser menor que la potencia disipable.

Ptot < Vce(sat) * I

En mi caso me he encontrado de todo: desde los chasis motorizados de Tomix que apenas consumen 0.1 A cuando están acelerando hasta las antiguas máquinas de Ibertren que se tragan 0.6 A. Para un transistor con Vce(sat) de 2V, el chasis de Tomix disipará 0.2W y la vieja Ibertrén 1.2W.

Finalmente, hay que escoger la resistencia entre la base y la salida de Arduino. Sin ésta, la salida estaría conectada directamente a  tierra y la corriente circularía sin ningún control. Tomaremos la mayor resistencia que con los 5V del HIGH garantiza la corriente nedesaria para saturación Isat:

Rb< 5V / Isat

Otro apunte sobre instalación: se debe conectar un diodo en paralelo al transistor para no forzar corriente  de E a C cuando dejamos de alimentar el motor y éste gira por su inercia actuando como dinamo.


 

Unos pocos ejemplos

Existen dos grandes familias de transistores, los BJT y los MOSFET. Hoy me centro en los primeros e intentaré dedicar una entrada más adelante a los MOSFET, que son más caros pero con unas prestaciones muy interesantes.
De los transistores BJT, os recomiendo la variedad NPN que me resulta más fácil de conectar. Estarán abiertos con HIGH y cerrados con LOW, fácil.



TIP 12x, TIP 11x, TIP10x: Son NPN si x es un número par. Aunque voluminosos, pueden conducir muchísima corriente y además llevan el diodo incorporado en el interior: menos elementos a montar. Yo los uso para pruebas, es imposible quemarlos. Su resistencia de base adecuada es de 330 Ohm.

2N2222: Más modesto en disipación pero más barato y muy fácil de encontrar. Conectadla a la salida de Arduino con 47 Ohm.

ULN2803: Un integrado con ocho transistores en un solo empaquetado. Muy práctico si hay que controlar diversos circuitos, te ahorras cableado y espacio en la placa. En este la resistencia de base es especialmente indicada porque tiene un límite a la intensidad entre base y emisor. Cualquier resistencia de base de entre 470 Ohm y 1 kOhm funcionará.



 
¿Qué es ese zumbido en el video?

Los más observadores habrán escuchado un zumbido al arrancar la locomotora. La frecuencia del PWM de Arduino ( la velocidad con que abrimos y cerramos el interruptor) es de 400 Herz, una frecuencia audible que hace resonar el motor cuando está arrancando. En un tren eléctrico queda hasta realista, pero para locomotoras diesel o de vapor hace feo. En este enlace podeis ver cómo incrementar la frecuencia para disminuir este efecto.
La otra opción es un filtro (condensador y resistencia) a la entrada de las vias... igual le dedico otra entrada al respecto. 

lunes, 20 de enero de 2014

A Modo de Introducción

Qué

Este blog es un intento de documentar los pasos que he seguido para hacer trenes autónomos escala N y su gestor a nivel de la maqueta mediante el microcontrolador Arduino.


Una placa Arduino Uno, Arduino Mini y la 252 de RENFE para dar una idea de escala. 
Ya se ve a venir que la integración de la electrónica en los vagones será un parto.

No creo que nadie tenga la ilusión de seguir mis pasos, pero creo que algunas de las soluciones que he ido encontrando a lo largo del camino pueden ser puntualmente útiles bien a modelistas, bien a usuarios de Arduino con otras aplicaciones en mente


Por qué

Desde pequeño, desde que en mi circuito de Ibertren puse a correr una segunda locomotora, me fastidiaba que el control fuese común para los dos trenes: si giraba más el potenciómetro, ambos trenes corrían más y no los podía operar independientemente. Esto era tan poco realista que dolía solo de pensarlo: en la central de RENFE en Madrid no hay un señor con un volante gigante que hace que todos los trenes corran más,  cada tren corre a discreción del maquinista que lleva a bordo.
Las posibilidades  de gestionar los trenes por separado en un sistema analógico son limitadas: tramos de via aislados controlados por relés... la dificultad se dispara a poco que crezca el circuito. Nos conviene un robot maquinista en cada locomotora. Y ese robot tiene que poder recibir órdenes de un gestor central del circuito.


Eh, un momento ¡Si eso ya existe!

Efectivamente, pero yo no lo sabía. La mayoría de marcas tienen ya sus propios sistemas e incluso hay una iniciativa estilo háztelo-tu-mismo llamada OpenDCC http://www.opendcc.org/index_e.html con esquemas electrónicos y programas de control públicos.


El puente que une las tomas de corriente al motor se puede sustituir por un decoder digital

Los nuevos diseños de locomotoras o bien ya son digitales o son “digital ready”, esto es, con un enchufe dónde se puede conectar el decoder (el intérprete) del sistema digital

Pero todo esto lo averigüé más tarde. Retomé la idea de mi tren autómata cuando apareció Arduino, una plataforma con un microcontrolador excepcionalmente fácil de programar... y barata.
OpenDCC me parecía interesante a nivel hobby, pero francamente, cuando empecé con todo esto no sabía suficiente electrónica para entender los esquemas. Mi ambición se limitaba al tren autómata, uno que actúa siguiendo su programa y no necesita recibir órdenes, así que un DCC me venía grande. A mi me bastaría con el controlador Arduino y un driver de voltaje a bordo del tren... o eso creía.


Cómo

Iré publicando las soluciones que he encontrado para  controlar cada elemento de la maqueta con Arduino  y los criterios de diseño que he seguido. Al final, debería haber:

-         Reguladores de voltaje para motores
-         El tren autómata: controlador y driver
-         Mandar órdenes al tren a través de la vía
-         Accionamiento de un desvío
-         Miniaturización de la electrónica: el controlador AtTiny y los chasis motorizados de Tomix
-         Cómo conocer la posición de los trenes
-         Cambio de sentido en el circuito
Ese es el orden en el que lo he ido desarrollando, pero si alguien está interesado en un tema en concreto no tiene más que pedirlo en los comentarios y le daré prioridad.


Atentos, spoiler del final de la temporada

El cuento acaba, y acaba bien.
Aquí teneis un video del estado actual de la maqueta, diversos trenes recibiendo órdenes independientes, cambio de sentido de giro, vias auxiliares...


Como veis, lo que he ganado en realismo en cuanto a la independencia de los trenes lo he perdido en el aspecto estético: los componentes electrónicos se me salen por los costados. Quizá en breve, si consigo mas confianza en los circuitos, me atreva a dar el salto a componentes más pequeños para soldadura en superficie (SMD) y a pedir unas pocas placas a un Fab.


Comentarios, consejos, preguntas y críticas no solo son bienvenidos, son lo que me motivará a seguir escribiendo.