Sistema de partículas en matriz LED con acelerómetro

agosto 22nd, 2012

 

Hace unas semanas compré en DealExtreme un reloj con matriz de leds y al ver que era hackeable, me decidí a hacer algunas modificaciones sobre la placa para convertirla en un gadget curioso y divertido.

Lo primero era quitar ese triste Atmega8 que traía con un cuarzo de 32.768 Khz que no me servía para nada.

Sustituí el Atmega8 por un Atmega328AU con un Bootloader de Arduino UNO, aprovechando que la placa dispone de conector ISP y que el mapa de pines son equivalentes.

Añadí un cristal de cuarzo nuevo de 16MHz y dos condensadores de desacoplo de 33pF para el cristal.

Posteriormente, aprovechando que la placa implementa la posibilidad de un V-Bus para USB, le puse las resistencias correspondientes de 100 ohms y la de Pull-Up de 1k5. He decidido obviar los diodos zener de 3v6, porque tengo un par de V-Bus montados en esta configuración y funcionan perfectamente.

Como quería hacer algo divertido con la placa, le añadí a modo de disipador del HT1632C una pequeña placa de evaluación con un acelerómetro triaxial analógico de STMicroelectronics, el LIS344ALH

 

 

Con lo que la PCB ya tomó otra forma y quedó tal que así:

 

 

 

En ella podemos ver que he tenido que añadir un conversor LDO a 3.3v para la alimentación de la placa del acelerómetro y que he pegado con una gota de cianoacrilato.

Tambien he tenido que retirar una resistencia de Pull-Up a A2 que venía por si se quería añadir un sensor de temperatura a la placa original.

Asimismo, he retirado un condensador de desacoplo en el pin AREF del Atmega328 y que he conectado a 3.3v del LDO para usar como tensión de referencia en el conversor A/D del chip.

Esta es la parte del uC:

Y esta la del acelerómetro:


 

Lo primero que probé fueron las librerías para HT1632C de Adafruit que necesitaron de unas pequeñas modificaciones para que funcionaran en este modelo de placa y el resultado fue este:

 

Pero eso era muy triste… :(
Algunos ya conocéis mi pasión por los sensores, especialmente acelerómetros y giroscopios, así que decidí en una aburrida tarde de lunes que podía programar un sistema de partículas al estilo de la bolita que rebotaba en otra matriz de leds que publiqué hace ya un par de años…
Y este fue el resultado. Mucho más divertido desde luego:

Aquí podeis ver en procesing, una simulación 3D del posicionado de la placa con filtrado del acelerómetro ( a la izquierda) y tal y como se lee sin filtro alguno ( a la derecha ):

Os dejo los fuentes en GitHub por si quereis trastear con ellos.


DESCARGAS

 

Salu2

Raspberry Pi & Arduino. Un nuevo ecosistema?

mayo 18th, 2012


Afortunadamente (para mí) he sido uno de los que han recibido la Raspberry Pi en los primeros envíos de Farnell, creo que en la segunda tanda.

Como es de bien nacidos ser agradecido, quiero hacer lo propio con l@s chic@s de @FarnellES en twitter que me han tenido al tanto siempre de como iba la distribución de las Raspberry Pi ;) .

Bueno, pues a lo que iba, esto hoy va a ser más un artículo de opinión personal con mi experiencia (muy poca todavía) con la placa y su entorno.

Lo que me ha llevado a escribir esta entrada, es un post de Liz (Raspberry Pi Foundation), en el que mostraba su tristeza por la actitud (quizás demasiado apasionada si esa puede ser la descripción) de alguna gente de la comunidad de Arduino que se mostraba a la defensiva dando a entender que la Raspberry venía a ocupar el nicho que actualmente posee Arduino en el mundo geek.

Personalmente, pienso como ella y no creo que eso llegue a pasar, pues son dos cosas completamente diferentes y que a mi entender se complementan o pueden hacerlo muy bien.

No podemos comparar la capacidad de cálculo de la Raspberry Pi con la de Arduino, como tampoco podemos hacerlo en la Raspberry Pi con la versatilidad I/O y adaptabilidad que nos ofrece Arduino. Son cosas completamente diferentes e incluso conceptualmente tambien lo son.

He querido hacer una prueba que me demostrase una de las principales diferencias entre una placa y la otra, y nada mejor que un control de dos servos, que implica la generación de dos señales PWM.

Usé un Pan-tilt con dos servos de 7grs que responden a una señal de 3,3v como pulso PWM de control para poder conectarla a los GPIO de la Rasperry Pi directamente. Los servos van alimentados con 5v desde una FA.

La primera prueba la vamos a hacer conectando las señales de los dos servos a los GPIO de la Raspberry (ojo! son conexiones directas, sin buffers intermedios ni ningún tipo de protección. Un mal uso quemaría el GPIO de la Raspberry o hasta el SoC) en este caso a las patillas 11 y 16 de P1, que se corresponden con GPIO 21 y 22 de la librería para python RPi.GPIO-0.1.0.zip de Ben Croston.

Es necesario instalarla para poder ejecutar el programa.

#       servo_GPIOs.py
#
#       Copyright 2012 Raspberry Pi User pi@raspberrypi
#
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.

import RPi.GPIO as GPIO
import time
import consola_io
#-- Servo positions
ESC = '\x1B'
servo1=90
servo2=90

# Move servos routine
# servos are attached at  GPIO22 and GPIO21
# on raspberry Pi
def mover_servo(grados,servo):
    if servo==1: GPIO_servo=22
    elif servo==2: GPIO_servo=21
    # create PWM pulse
    pos_servo=(0.0000122*grados)+0.0002
    GPIO.output(GPIO_servo, True)
    # Using time.sleep is a worst idea
    time.sleep(pos_servo)
    GPIO.output(GPIO_servo, False)
    # Another bad idea.
    time.sleep(0.0025-pos_servo)
# Asimple menu with some info
def menu():
    print """

        W - Arriba
        S - Abajo
        A - Izquierda
        D - Derecha

    ESC - Terminar
    @radikaldesig 2012 RaspberryPi
    Control de servos
    """

# set up the GPIO channels 21 & 22 as output
GPIO.setup(22, GPIO.OUT)
GPIO.setup(21, GPIO.OUT)

menu()
# main loop
while 1:
    c = consola_io.getkey()

    if c=="w" or c=="W":
        servo1=servo1+1
        if servo1>180 : servo1=180
        mover_servo(servo1,1)
    elif c=="s" or c=="S":
        servo1=servo1-1
        if servo1<0 : servo1=0
        mover_servo(servo1,1)
    elif c=="a" or c=="A":
        servo2=servo2-1
        if servo2<0 : servo2=0
        mover_servo(servo2,2)
    elif c=="d" or c=="D":
        servo2=servo2+1
        if servo2>180: servo2=180
        mover_servo(2,2)
    elif c==ESC:break

print "Goodbye"

Como se puede ver en el código, la generación del pulso PWM es “manual”, usando como generador de retardos el procedimiento sleep de la librería time de python.
Es una solución chabacana que nos va a dar problemas y va a hacer que el pulso sea irregular y que varíe o que se interrumpa, con lo que no podremos conseguir una señal estable que nos permita mover los servos en condiciones y luego veremos porqué pasa esto.
Este video muestra el movimiento de los servos y en él se aprecian los saltos producidos por las pérdidas de pulsos o la rotura de los mismos:

Si nos paramos a pensar detenidamente, no es una buena idea generar los pulsos PWM para los servos desde los GPIOs de la Raspberry:

  • Python es un lenguaje interpretado y por tanto, es lento de ejecución (aunque no lo notemos)
  • Las características propias de Linux y la forma de planificación de procesos por parte del sistema hace que perdamos tiempo en los cambios de contexto que se producen y que son inherentes al propio SO
  • Hagamos un ejemplo en C para ver como se producen retardos entre procesos por la planificación de éstos en el sistema:

    #include signal.h
    #include time.h
    main ()
    {
     int a,b;
     b=0;
     if ((a=fork())==0)
    {
     while (1)
    {
     printf("iter:%d\n",b);
     usleep(100);
     b++;
    }
    }
     usleep(100000);
     printf("Terminacion del proceso con pid= %d e iter:%d\n",a,b);
     kill(a,SIGTERM);
    }

    Tenemos que un servo se mueve aproximadamente con un pulso de entre 0,5ms y 2,5ms a una frecuencia de unos 50Hz (20ms) algo, como esto:

    Servo pulse

    Así que para una precisión de 1 grado necesitaríamos poder ajustar la longitud del pulso en intervalos de 11,1 uS.
    Con este pequeño programa de prueba, lo que vamos a hacer es crear un proceso hijo cada 100 uS durante un tiempo máx de 100mS.
    Ponemos una variable a contar los procesos hijos creados y comprobamos en varias ejecuciones que estos difieren en número en cada ocasión.
    Es muy simple, el núcleo del sistema atiende otros procesos a la vez además del nuestro, y esto hace que el nivel de prioridad del ejemplo descienda en la tabla de planificación y que nuestro pulso de 0,8ms sea realmente de 1,1ms o 0,9ms o 0,83ms provocando desviaciones de hasta 90 grados ( WoW! ), dependiendo de la carga de procesos del sistema.
    Y claro, se nos viene a la cabeza -Esto con Arduino no pasa, el uC ejecuta un solo proceso unicamente interrumpible por una IRQ y que yo tengo que habilitarle su permiso… -
    Pues sí, basta el ejemplo de cualquier dispositivo o máquina industrial, ninguna CPU o sistema embebido realiza la maniobra de un servomotor, actuador o electroválvula… de todo ello se encarga un sistema periférico, bien un inversor, un regulador de giro o un sistema controlador de servos comunicados por CAN, profibus, RS485, etc.
    Entonces, ¿porqué no complementar la capacidad de cálculo de la Raspberry Pi con las posibilidades I/O de Arduino estableciendo una comunicación a través del propio USB, que para eso disponemos de él?
    Además establecemos una barrera perfecta entre nuestros motores, servos, Triacs o lo que sea y nuestra Raspberry, que no ha sido diseñada para eso.
    Ese es el paso siguiente. Conectemos el Arduino al USB y busquemos a ver que tenemos:

    Ya tenemos localizado entre los dispositivos serie la id de nuestro Arduino. En Debian debería de crearnos un nuevo dispositivo del tipo /dev/ttyACM0.
    Podemos olvidarnos por ahora del Arduino IDE en nuestra Raspberry, ya que la máquina de java es muy pesada y tenemos la limitación de 256Mb de RAM de la placa, así que nos vamos a limitar a comunicarnos con Arduino a través de la conexión serie del USB.
    Cargamos nuestro Arduino con ServoControl.pde:

    /*
     * Servo control with Arduino
     * using an USB comunication
     */
    #No olvideis poner los angulos en el include
    #include Servo.h 
    
    // Create objects
    Servo servo1;
    Servo servo2;
    
    // Common servo setup values
    int minP = 600;   // minimum servo position, us (microseconds)
    int maxP = 2400;  // maximum servo position, us
    
    // User input for servo and position
    int inputData[3];    // raw input from serial buffer, 3 bytes
    int byteIni;        // start byte, begin reading input
    int servo;           // which servo to pulse?
    int pos;             // servo angle 0-180
    int i;               // iterator
    
    void setup()
    {
      // Attach each Servo object to a digital pin
      servo1.attach(2, minP, maxP);
      servo2.attach(3, minP, maxP);
    
      // Open the serial connection, 9600 baud
      Serial.begin(9600);
    } 
    
    void loop()
    {
      // Wait for serial input (min 3 bytes in buffer)
      if (Serial.available() > 2) {
        // Read the first byte
        byteIni = Serial.read();
        // If it's really the byteIni (255) ...
        if (byteIni == 255) {
          // ... then get the next two bytes
          for (i=0;i<2;i++) {
            inputData[i] = Serial.read();
          }
          // First byte = servo to move?
          servo = inputData[0];
          // Second byte = which position?
          pos = inputData[1];
          // Packet error checking and recovery
          if (pos == 255) { servo = 255; }
    
          // Assign new position to appropriate servo
          switch (servo) {
            case 1:
              servo1.write(pos);    // move servo1 to 'pos'
              break;
            case 2:
              servo2.write(pos);
              break;
          }
        }
      }
    }

    Conectamos las señales de control de los servos a Digital2 y Digital3 del Arduino y ya tenemos nuestro módulo periférico totalmente preciso al que vamos a enviarle las órdenes de movimiento de la forma:
    [start byte 0xFF] [servo a mover] [posicion en grados]
    Usamos la librería servo incluida en el entorno de Arduino y ahora ya podemos dejar los cálculos y el control de las posiciones para la Raspberry.
    Hagamos un ejemplo en Python:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    #
    #       servos.py
    #
    #       Copyright 2012 Raspberry Pi User pi@raspberrypi
    #
    #       This program is free software; you can redistribute it and/or modify
    #       it under the terms of the GNU General Public License as published by
    #       the Free Software Foundation; either version 2 of the License, or
    #       (at your option) any later version.
    #
    #       This program is distributed in the hope that it will be useful,
    #       but WITHOUT ANY WARRANTY; without even the implied warranty of
    #       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    #       GNU General Public License for more details.
    #
    #       You should have received a copy of the GNU General Public License
    #       along with this program; if not, write to the Free Software
    #       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
    #       MA 02110-1301, USA.
    
    import time
    import serial
    import consola_io
    import random
    
    # Assign Arduino's serial port address
    #   Windows example
    #     usbport = 'COM3'
    #   Linux example
    #     usbport = '/dev/ttyACM0'
    #   MacOSX example
    #     usbport = '/dev/tty.usbmodem621'
    usbport = '/dev/ttyACM0'
    
    # Set up serial baud rate
    ser = serial.Serial(usbport, 9600, timeout=1)
    
    # servo's position
    servo1=90
    servo2=90
    
    # move servo routine that send data to Arduino
    def mover_servo(grados,servo):
        ser.write(chr(255))    # start transmission
        ser.write(chr(servo))  # Select servo
        ser.write(chr(grados)) # degrees to move
    
    # A little menu with info
    def menu():
        print """
    
            W - Arriba
            S - Abajo
            A - Izquierda
            D - Derecha
    
        ESC - Terminar
        @radikaldesig 2012 RaspberryPi
        Control de servos
        """
    
    menu()
    while 1:
        c = consola_io.getkey()
    
        # Move UP
        if c=="w" or c=="W":
            servo1=servo1+5
            if servo1>180 : servo1=180
            mover_servo(servo1,1)
        # Move down
        elif c=="s" or c=="S":
            servo1=servo1-5
            if servo1<0 : servo1=0
            mover_servo(servo1,1)
        # Move left
        elif c=="a" or c=="A":
            servo2=servo2-5
            if servo2<0 : servo2=0
            mover_servo(servo2,2)
        # Move right
        elif c=="d" or c=="D":
            servo2=servo2+5
            if servo2>180: servo2=180
            mover_servo(servo2,2)
        # move to 20 random pos
        elif c=="v" or c=="V":
    	for i in range(20):
     	   servo1=random.randint(0,180)
    	   servo2=random.randint(0,180)
    	   mover_servo(servo1,1)
    	   mover_servo(servo2,2)
    	   time.sleep(0.5)
        elif c==ESC:break
    
    print "Goodbye"

    Necesitaremos la librería consola_io.py en el mismo directorio donde lancemos el programa y además instalar las librerías de comunicación serie de python pyserial-2.5
    Tambien debemos configurar el dispositivo creado por el Arduino para dirigir nuestra comunicación, en mi caso es usbport = ‘/dev/ttyACM0′
    Nuestro porgrama es simple, dependiendo de la pulsación de las teclas WASD, mueve los servos a intervalos de 5 grados, desde la posición de 0 grados hasta la de 180 grados, enviando 3 bytes al Arduino:
    Startbyte, Nservo, Posicion
    Le he añadido una pequeña feature al pulsar V y es que mueve los 2 servos a 20 posiciones aleatorias cada 0,5 segundos.
    Ahora si que no hay saltos y los pulsos son perfectos.
    Verdad que el Arduino y la Raspberry se complementan bien?

    Ya resumiendo, es evidente que no necesitamos una Raspberry Pi para controlar un Arduino que mueva dos servos, pero sí podemos usarla para montarla sobre una base móvil (robot, orugas,…) y poder implementar un sistema de visión artificial con OpenCV corriendo en Python usando una cámara USB, enviando la señal de la imagen por wifi, y a su vez datos de telemetría, sensores de temperatura, giroscopios, acelerómetros y dotarla de una IA que entonces sí gestione un Arduino encargado de mover los motores, el pan-tilt de la cámara, leer los sensores y manejar infinidad de dispositivos I/O que para eso Arduino tiene mucho músculo y rodaje.

    Aún podemos pensar que esto no puede ser un ecosistema maravilloso???
    Os leo en el twitter…

    Droky
    @radikaldesig


    DESCARGAS

     

     

     

    Más sensores capacitivos…

    abril 23rd, 2012

    Los sensores capacitivos QT100 han pasado a la historia y ya no se fabrican.

    En su lugar se han sustituido por la nueva serie AT42QT1010, como resultado de la compra de Quantum por Atmel.

    Las características son similares a las del QT100, pero con una ligera mejoría en el rendimiento, o por lo menos es lo que yo he notado en las pruebas.

    Y una característica especialmente ventajosa es el encapsulado SOT23-6 en lugar del WSON-6 de los QT100 que los hacían más complicados de montar de forma “artesanal”.

    Me han llegado unas placas que he rediseñado de los sensores capacitivos del montaje Keypad 16 sensores antivandálicos para alejar un poco más el pad del resto del circuito, especialmente del conector miniUSB usado para enlazar con la placa controladora.

    El esquema usado es el siguiente:

    Cuando monte las placas, seguiré informando de los resultados.

    Droky

     

     

    DIY Stencils de cobre usando una laminadora

    diciembre 24th, 2011

    Continuando un poco con el post anterior y aprovechando las nuevas posibilidades de la laminadora, toca resolver uno de los problemas habituales a la hora de hacer PCBs SMD, la necesidad de disponer de un stencil para aplicar la pasta de soldadura.
    Esto es lo que necesitamos además de la laminadora:

    A continuación imprimimos en mirror y en negativo la capa Cream para el stencil de nuestro circuito.
    Lo hacemos sobre un trozo de hoja para transferencia. Podeis ver otra vez que mi toner está en las últimas :(

    Ahora recortamos un trozo de lámina de cobre que cubra la PCB y un centímetro más aprox. para recoger la pasta de estaño sobrante en la aplicación:

    Pasamos por la laminadora la hoja de cobre con el papel transfer 2-3 veces para que se fije bien:

    Una vez pasado por el agua, retiramos el papel y tenemos ya el toner sobre la lámina:

    Lo siguiente es sellar el toner para evitar porosidades que se coman la lámina de cobre por donde no corresponde.
    Para ello usamos el Green TRF Foil que tambien aplicamos con la laminadora:

    Pelamos y protegemos los bordes con cinta adhesiva. Tambien podemos corregir defectos con un rotulador permanente:

    Es muy importante cubrir la parte trasera, para que el atacado no destruya toda la lámina:

    Lo atacamos con nuestro método habitual, percloruro férrico o H2O2 y ácido muriático ( el mío ):

    Limpiamos con acetona los restos del Green TRF foil y del toner:

    Y ya tenemos nuestro stencil listo para usar!!!:

    A ver si alguno os animáis y me mostráis vuestros resultados.

    Droky,
    Ya sabéis, por twitter en @radikaldesig

    Laminadora para transferencia de toner (modificación)

    diciembre 23rd, 2011

    Hola de nuevo.
    Esta vez voy a explicaros como modificar una laminadora o plastificadora (que puede conseguirse facilmente en España por poco precio) para poder transferir tóner a las PCBs bien para hacer placas de circuitos, o para serigrafiarlas.
    En un próximo artículo explicaré como hacer stencils de lámina de cobre, para lo que también necesitaremos la laminadora.
    Mucha gente usa el método de la plancha como alternativa a la insoladora. Unas veces los resultados son muy buenos, pero otras no y es en mayor parte porque no se produce una transferencia adecuada del tóner a la PCB por una aplicación de calor deficiente.
    La laminadora nos permite aplicar de forma uniforme calor a la PCB por medio de sus rodillos flexibles que hacen que la tranferencia sea completa en toda la placa. Pero nos encontramos con un problema y es que la temperatura para la fijación del tóner es más elevada que para plastificar documentos, por lo tanto necesitamos modificar nuestra laminadora.
    Este artículo está basado en su homónimo de http://ultrakeet.com.au/index.php?id=article&name=superFuserV2 sólo lo he aplicado a una Fellowes FPLA4 que compré hace unos 3 años con idea de hacer esto pero que tenía arrinconada en casa.
    Lo siguiente es desmontar la laminadora y observamos en su interior los rodillos, el motor que los hace girar con su reductora, un par de termostatos y un fusible térmico:

    En esta imagen se ve más claro:

    • El capuchón blanco superior es el termostato que hace encender el led verde de “OK”
    • El tubo de goma blanco esconde un fusible térmico de 142ºC
    • El termostato inferior (110ºC) es el que controla los calefactores

    En una tienda local de componentes electrónicos me compré:

    El termostato del led no lo he sustituído, simplemente dejo calentar unos 5 minutos más desde que se enciende el led verde y ya está.
    En esta imagen se ve donde se sustituye el fusible térmico antiguo (142ºC) por el nuevo (240ºC):

    Y este es el nuevo termostato de 165ºC:

    Una vez modificado, he hecho una prueba en un trozo de placa muy viejo que tenía por casa.
    Primero imprimir en modo espejo la PCB sobre un papel satinado o de revista que permita que el toner no se fije demasiado a él.
    Hacerlo a la máxima oscuridad posible de la impresora.
    Como podeis ver, mi tóner no está en muy buenas condiciones…

    La placa la he repasado con un poco de lana de acero y luego la he limpiado con acetona. Una vez seca la meto en la laminadora.
    Como es baquelita de 1,6mm le doy 4 pasadas por la laminadora ( hasta que esté tan caliente que ya no la pueda agarrar)

    Luego la introduzco en agua fría y dejo que ablande el papel para ir deshaciéndolo con los dedos y finalmente con ayuda de un cepillo de dientes.
    El toner queda bien fijado en el cobre:

    Atacar por el método preferido, Percloruro férrico ó H2O2 y ácido muriático. A gusto del consumidor.
    El resultado con el H2O2 es éste:

    Teniendo en cuenta que el toner es de competencia y está un poco en las últimas, el resultado es bastante bueno sobre un papel de catálogo.
    He hecho la prueba con una PCB ruteada a 6mils y con vías de 8mils. Los defectos son producidos por el tóner y un poco la absorción del papel del catálogo.
    Está muy bien para una prueba rápida. Creo que la insoladora va a quedar para las cosas “buenas”

    En resumen, al modificar la temperatura de la laminadora conseguimos que el tóner se fije mejor sin estropear la plancha de la ropa XD y al mismo tiempo, no se dañará por una elevada temperatura gracias a la limitación del termostato y a la protección del fusible térmico.

    La siguiente prueba será haciendo un stencil para aplicación de pasta de estaño usando lámina de cobre de 0,15mm
    Droky,
    @radikaldesig

     


    Copy Protected by Tech Tips's CopyProtect Popup Images .