Raspberry Pi & Arduino. Un nuevo ecosistema?


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

     

     

     

    28 Responses to “Raspberry Pi & Arduino. Un nuevo ecosistema?”

    1. Javi Says:

      Cojonudo!!! Que interesante….

      Estoy deseando que llegue la mía….

      Javi

    2. German Says:

      No dejo de sorprenderme con tu blog Droky.

    3. Raspberry Pi & Arduino. Un nuevo ecosistema? | ARDUTEKA Says:

      [...] través  de este artículo podemos ver como  comunicar a Raspberry Pi con nuestro Arduino y el código necesario para [...]

    4. Peich Says:

      Veo que tenia el mismo concepto de arduino y raspberry… Pronto veremos muchos robotines más inteligentes que los actuales :)

    5. Farnell España Says:

      Muchas gracias por tu agradecimiento :) Seguiremos de cerca tus posts ;)

    6. Jorge Crespo Says:

      Hola.

      Muy interesante el artículo, ya han pasado tres semanas desde que lo pagué, así que debería llegar pronto….

      Estoy pensando en un servidor web en raspberry que por un lado mande imágenes de la cámara instalada en un robot y por otro te permita mover tanto el robot como la cámara por internet. A ver si me llega y puedo hacer pruebas.

      Enhorabuena por el blog

    7. Jorge Crespo Says:

      Por cierto, llevo desde que he escrito el otro mensaje pensándolo: Como montar un servidor el en el que crear eventos, como pulsar una tecla o un botón, y que se envíe un comando por puerto de serie.

      ¿Alguna idea o proyecto?

    8. Arduteka Raspberry Pi & Arduino. Un nuevo ecosistema? Says:

      [...] través  de este artículo podemos ver como  comunicar a Raspberry Pi con nuestro Arduino y el código necesario para [...]

    9. droky Says:

      Hola Jorge,
      Pues lo tienes muy fácil:
      node.js + serialport para node
      Siempre puedes usar los Get/Post de html, pero son muy lentos y la otra opción son usar winsockets.
      Yo me decantaría por node.js y su facilidad de uso desde cualquier plataforma e integración en web con javascript.
      Salu2

    10. Jorge Crespo Says:

      No había pensado el get/post, de ese modo sería muy sencillo; sólo habría una página con un poco de PHP.

      Y respecto de node, no lo conocía, pero parece la opción ideal. Más rápido, sencillo y completo, y simplemente con javascript… Muy interesante.

      Encima, all meter “node.js” en Google ya aparecen directamente ejemplos con Arduino. Es el candidato ideal.

      Muchas gracias, y si consigo que funcione te pondré un comentario por aquí, por si te interesa.

    11. LocoMJ Says:

      Increible post con información rica rica :)
      A ver si me llega el rasp y empiezo a cacharrear a tope, aunque tengo bastante carencias en cuanto a programación una vez me sacan de C o php :(

    12. maglev45 Says:

      English, please?

    13. Raspberry Pi en Tiempo Real « La Pizarra de Litox Says:

      [...] BricoGeek me llega este fantástica prueba de comparación de Raspberry Pi con Arduino y la combinación definitiva que puede resultar de su unión. Realmente la respuesta de los pines [...]

    14. Anónimo Says:

      [...] [...]

    15. Jose Says:

      Te queria preguntar si me puedes decir el modelo de servo que has utilizado.

      ¿Se puede dirigir el servo directamente con raspeberry pi?¿O tengo que usar arduino y raspberry?

      Soy novato en esto de arduino.

      Gracias

      Jose

    16. Controlling Servos Using the Pi | novitiate.co.uk Says:

      [...] http://www.radikaldesig.com/2012/05/18/raspberry-pi-arduino-un-nuevo-ecosistema/  (Sorry but it is in spanish) [...]

    17. sims 3 Says:

      We’re a bunch of volunteers and opening a brand new scheme in our community. Your website provided us with valuable information to work on. You’ve done a formidable job and our entire group
      can be thankful to you.

    18. droky Says:

      Hi sims 3,
      Thank so much for your words!

    19. jj Says:

      Hi droky,

      if it’s not too much of a hassle, would you mind publishing a basic wiring diagram for how to control a motor directly from the R-PI GPIOs, maybe also noting the specs of the the motors used in your test? Thanks!

    20. iso9660 Says:

      En mi opinión estás dando una idea equivocada de lo que se puede hacer y lo que no con este artículo. Creo que si utilizaras pthreads para crear un hilo de control del PWN y sincronizar el programa iría bien sin necesidad de usar una arduino.

    21. droky Says:

      Puede que esa sea tu percepción, pero deberías de considerar que las distribuciones actuales para la RaspberryPi no están optimizadas para multithreading, ni procesamiento paralelo eficiente. Sí sería posible usar Posix Threads y coordinar todos los hilos con el sistema, pero te animo a que programes un sistema que controle por ejemplo 10 señales PWM a 500Hz con 8 bits de resolucion, un par de sensores analógicos y un par de I/O digitales. Daría para un artículo interesantísimo y lograrías la piedra rosetta en la actualidad RaspberryPi. Sí es posible, pero es necesario un skill de programación elevado cuando puedes delegar este trabajo. Lo ideal sería disponer de un RTOS para la RaspberryPi que todavía no está pulido (el mundillo CNC está deseando un RTOS que funcione bien para darle la carga de trabajo a la RaspberryPi y olvidarse del PC), o usar un lenguaje más trillado y estable (a nivel de eficiencia en el control del hardware) para implementar el multithreading como el ADA y hacer un control de procesos más efectivo. Efectivamente se puede hacer, pero quizás sea como matar moscas a cañonazos. En procesos industriales y sistemas embebidos, siempre se ha delegado el manejo de los sistemas adyacentes de control y potencia a dispositivos externos al dispositivo controlador. Si te encuentras un diseño industrial que no funcione así, te puedo asegurar que será un problema.
      Salu2

    22. Iso9660 Says:

      Estoy de acuerdo con que es mucho más complejo programar en un sistema como Linux que con un micro, y que cada cosa es para lo que es, pero a lo que voy es a que este artículo está hecho desde el punto de vista de un programador de micros, no de aplicaciones para sistemas. Lo de la dificultad es como todo. Seguro que a mi me cuesta horrores sacarle todo el potencial a un arduino, pero con una raspberry te aseguro que se pueden hacer virguerías, incluso sin multihilo y simplemente utilizando redes de petri. Por último creo que lo que eres capaz de hacer es una pasada, pero estoy convencido de que el control se puene hacer mucho más rápido sin acoplar un arduino.

    23. droky Says:

      Me parece interesantísimo lo que indicas. Ciertamente tienes razón con el enfoque, que es la base del blog, por tanto, te invito a colaborar en un nuevo artículo. Tu olvídate de la electrónica si es el problema, de eso me encargo yo. Se me ocurre algo si estas dispuesto, que mostraría las verdaderas capacidades de la Raspberry. Nada excesivamente complejo, pero orientado a lo que indicas. Si estás interesado, contáctame por email y vemos que podemos hacer.
      Salu2

    24. iso9660 Says:

      Hola droky, me parece bien tu propuesta. Puedo colaborar en un proyecto simple, pero encuentro tu email. Si quieres podemos contactar enviando mensajes por la cuenta pública goonies@mailinator.com

    25. droky Says:

      Puedes contactarme en d.r.o.k.y.@r.a.d.i.k.a.l.d.e.s.i.g.com
      Sin los puntos ;)
      Y te planteo lo que se me ha ocurrido

    26. Isaac Says:

      Muy interesante el artículo.

      Estoy de acuerdo en que es mejor dejar la parte de actuadores (motores, relés) a Arduino y usar la Raspberry para proceso de datos.

      Una aplicación simple pero a la vez muy interesante en la que estoy trabajando és la de hacer object tracking usando las librerias OpenCV en la Raspberry Pi y comunicando a arduino la posicion (Pan & Tilt) a la que queremos que nos enfoque la camara.

      En cuanto tenga los primeros resultados los comparto :)

    27. droky Says:

      Estoy deseando ver esos resultados. Si necesitas donde publicarlo, aquí tienes un hueco. Salu2

    28. » Raspberry Pi en Tiempo Real La Pizarra de Litox Says:

      [...] BricoGeek me llega este fantástica prueba de comparación de Raspberry Pi con Arduino y la combinación definitiva que puede resultar de su unión. Realmente la respuesta de los pines [...]

    Leave a Reply


    Copy Protected by Tech Tips's CopyProtect Popup Images .