Programando un Arduino remotamente con el módulo ESP8266

IMG_20141108_002938

Una de mis viejas aspiraciones cuando construyo robots es poder programarlos sin tener que recogerlos, enchufarles un cable usb o un programador ICSP y volverlos a dejar en su sitio.

En este artículo explicaré cómo con un Arduino UNO y un módulo ESP8266 (llamado WI07C) se puede programar un sketch de Arduino en la placa sin tener que estar cerca de esta, todo mediante wifi y sockets tcp/ip.

Descripción general

Como se puede ver en el vídeo tenemos un Arduino UNO conectado a un display HD44780 y a un módulo wifi ESP8266. Arduino envía cadenas hello world al servidor sockettest que está escuchando por el puerto 49000. Se modifica el código Arduino en el IDE poniendo hello folks, se compila y el fichero .hex generado (se puede ver donde está activandolo en Archivo/Preferencias/compilación) se copia a la carpeta del programa en python. Cuando Arduino recibe un comando reboot se conecta al servidor python por el puerto 50000 entrando en modo de datos, acto seguido se reinicia y empieza la programación remota de Arduino. El proceso se reliza dos veces en el vídeo.

Lo que se aprovecha es el método que tiene Arduino para programarse, ya que usando el puerto serie después de un reset se puede programar un Arduino si se sigue el protocolo STK500 implementado en el bootloader.

Esquema de conexiones

esquema

El Arduino y el display HD44780 se alimentan a 5 voltios, el módulo ESP8266 se alimenta a 3,3 voltios. Como el pin rx del módulo wifi sólo puede funcionar a 3,3V se usa un diodo zener de 3,3 voltios junto con una resistencia de 100 Ω.

En las placas Arduino, el pin de reset del microcontrolador está conectado a una resistencia y esta a su vez está conectada a VCC, con lo que para el microcontrolador el pin está a nivel alto. Cuando se pulsa el botón de reset lo que se hace es derivar la corriente hacia masa (ya que el bóton está conectado a esta) y el microcontrolador, al estar a nivel bajo el pin de reset, realiza un reseteo. Cuando el microcontrolador arranca, todos los pines están configurados como entradas (alta impedancia) y por eso no le afecta que el pin de reset esté conectado directamente al pin 12. Si se configura el pin 12 como salida y luego se conecta a masa (nivel bajo o LOW) se provoca el mismo efecto que si se pulsase el botón de reset, además, al existir la resistencia anteriormente mencionada, no hay que preocuparse de que se produzca un cortocircuito al unir VCC con masa (GND).

Sketch de Arduino

Lo que hace el skecth de Arduino es:

  • Inicializa el puerto serie a 115200 bps.
  • Elimina los caracteres que hubiera en el buffer de entrada del puerto serie.
  • Inicializa el módulo wifi en modo estación, lo resetea, se conecta al punto de acceso normal, configura las conexiones como simples en modo normal y se conecta al servidor normal por el puerto 49000. Si hubiese algún fallo en algún punto pararía la ejecución y lo indicaría en el display.
  • Envia una cadena de texto y un número consecutivo tanto al servidor como al display. Si hubiese algún fallo en algún punto pararía la ejecución y lo indicaría en el display.
  • Si entre el envío de las cadenas de texto se recibe una cadena reboot entonces resetea el módulo, se conecta al punto de acceso bootloader, configura las conexiones como simples en modo normal y se conecta al servidor de programación por el puerto 50000. Acto seguido envía una cadena hello y espera a recibir una cadena welcome, si ha sido así, entonces envía el nombre del fichero .hex con el que quiere ser programado el Arduino y espera a recibir una cadena ok, momento en el cual configura el pin 12 como salida y lo pone a nivel bajo, conectándolo a masa y provocando un reset en el Arduino. Si hubiese algún fallo en algún punto pararía la ejecución y lo indicaría en el display.

Aquí cabe destacar cómo funciona el sistema de reseteo: Justo después del reseteo, el pin de TX de Arduino está a nivel bajo durante un tiempo, lo que provoca que el módulo wifi vea eso como un byte 0, que enviará a través de la conexión TCP/IP. El servidor de programación aprovechará esta circunstancia para saber cuando ha empezado el reseteo e iniciar el protocolo STK500. El bootloader de Arduino entra en acción después del reseteo y espera a recibir ordenes del protocolo STK500, si las recibe actúa en consecuencia, si no, ejecuta el programa principal.

Servidor de programación

Lo que hace el servidor de programación es:

  • Crea un socket que escuche por el puerto 50000
  • Cuando un cliente de conecta espera a la cadena hello, si la recibe reponde con una cadena welcome.
  • Espera a que el cliente le envíe un nombre de fichero .hex. Trata de abrir el fichero en el mismo directorio y lo lee interpretando todas las líneas para guardar los datos del programa en memoria. Si todo va bien envía una cadena ok.
  • Espera a recibir el byte 0, y cuando lo recibe empieza el protocolo STK500 para comunicarse con el bootloader de Arduino y programarlo. Básicamente lo que hace es entrar en modo de programación, indicarle a que páginas quiere acceder y enviar los datos de cada página, así hasta que ha enviado todos los datos del programa, después sale del modo de programación cerrando la conexión

Aquí cabe destacar que cuando se cierra la conexión TCP/IP con el cliente (ya sea por un error o porque el proceso de programación ya ha terminado), el módulo ESP8266 sale del modo de datos automáticamente y no es necesario que el nuevo sketch tenga que enviarle la cadena de escape +++ para poder entrar otra vez en modo de comandos.

Conclusiones

Espero que esto os sirva para que en vuestros proyectos podais programar remotamente vuestros Arduinos a través de una red local o Internet.

Habría que tener en cuenta que el proceso de actualización puede quedarse a medias si la conexión a la red wifi es lenta y provocaría que el programa no se ejecutara correctamente. Así que que una mejora sería acoplar un chip aparte que reprogramase el Arduino por ICSP con un programa preestablecido en caso de que detectase que la programación no fue finalizada correctamente.

Comentar que la versión de firmware del módulo ESP8266 que he usado es la 0019000902 y el Arduino es un UNO. Ambos funcionan a 115200 bps, pero si quisierais utilizar otras velocidades (en otros Arduinos el bootloader configura el puerto serie a 19200 o 57600 bps) habría que cargar un firmware que lo permitiese, como por ejemplo la versión 0.922 de electrodragon y su comando AT+CIOBAUD.

46 pensamientos en “Programando un Arduino remotamente con el módulo ESP8266

  1. Javier

    Enhorabuena por el articulo, todo un éxito salir en Hackaday.

    El componente del ESP-01 para Fritzing, ¿lo has hecho tu? ¿o esta disponible en algún sitio?.

    Responder
      1. manoloceltas

        Muy buena la aportación. Estuve buscando por la red y aqui es donde esta mejor analizado en módulo(y en castellano. Estoy esperando los que he pedido para conectar con arduinos.

        Responder
  2. carlo

    Great idea man!
    I would like to point out that the zener diode is indispensable to make it work, not only because of level translation, but also because no zero byte is sent after reset without it..
    I’ve rewritten your script in c++ under Qt, with a GUI that let choose the hex file to upload, directly searching in favourite paths..
    My devices have a simple web interface with a server running on port 80, so I send the /upgrade command followed by the IP address and port of the progamming server. The device than reboots and connects to the server to be programmed.. Unfortunetely I’m experiensing some troubles during programming, which usually stops after 8-9 pages. So if I upload the blink sketch everything works because it’s about 5 pages, but for bigger sketch it fails, probably due to sync problems, because I receive no ack.
    If you are interested we can work on togheter..

    Responder
    1. carlo

      Trying to figure out the cause of my problem, I found that it depends on the responsivity of the router. In my network the delay is too high, whereas in my office it works pretty well with every kind of sketch… Again, nice job! I learned many things with your script, thank you..

      Responder
      1. admin Autor

        That is my problem too. I have a VPS where the python script is running and due to net delays, sometimes the arduino bootloader runs the main program while it is not loaded at all. I’m working in an alternative circuit to store the downloaded sketch in a 24AA1025 eeprom memory and then program the arduino with ICSP from a PIC12F1822.

        Responder
        1. carlo

          Your alternative solution seems similar to Moteino boards. I was minding to modify the esp8266 firmware instead to limit the need of new hardware. The sketch upload procedure may be driven by it: we can use it to parse the upload command and internally switch to programming mode. We can also use the GPIO2 pin to reset arduino and implement a little buffer to avoid delay problems.. Next week I wil try to read v0922 firmware to figure out if it’s feasible..

          Responder
          1. admin Autor

            Well, it is a bit different because the boot loader is the original from arduino. The Arduino sketch should program the eeprom by I2c with the new sketch and then the pic reads the eeprom and program the AVR by isp.

            Let me know your advances about the modified esp8266 firmware to program the Arduino. It seems interesting.

    2. Francesco

      Hello can you help me? My code is blocking on AT+CIPSTART
      can you send me you application to upload. Hex?
      Thanks

      Responder
  3. Pingback: Módulo WIFI ESP8266 - El blog de Marcos

  4. Newton Isaak

    Hello, very interesting article!
    Could you write english version, cause did not understand details.
    Thank you.

    Responder
  5. eduardo mendez

    hola , alguien sabe si es posible controlar el arduino uno remotamente con el módulo ESP8266 conectado por wifi a intternet para activar un contacto seco ?

    Responder
    1. willar

      Hola Eduardo si es posible controlar tu arduino por el modulo esp solo tienes que colocar el modulo al arduino como aparecen en internet rx/ tx tx/rx y listo envias tu cadena es cual programa el chip de arduino para que la reciba y utilizar los comandos AT+CIMUX = 1 & Chr$(13) luego AT+CIPSERVER=1,80 & Chr$(13) y AT+CIPSEND=0,30 & Chr$(13) donde el el 30 es un ejemplo de 30 caracteres que estas enviando.

      Responder
  6. ikin

    Muchas gracias por compartir esta información, es muy útil. Lo he probado con un UNO y funciona de maravilla, mientras que con un Pro Mini no hay modo. ¿Qué puede ser?

    Responder
    1. admin Autor

      Me imagino que por la velocidad del puerto serie a la que funciona el bootloader, en el arduino UNO es de 115200, en el mini pro es de 57600, por lo que para que funcione sólo deberías cambiar en el sketch de arduino la velocidad del puerto serie a 57600 y configurarla también a esa velocidad en el módulo esp8266.

      Responder
      1. ikin

        Gracias por tan pronta respuesta. Lo he probado a 115200 y 57600 con el mismo resultado 🙁

        El mensaje que veo desde el equipo donde corre el programa python es este:

        Connection to Arduino bootloader: failed

        Es decir, parece que va bien la secuencia hello-wellcome-programa-ok-reincio y entra en la función “program_process”, pero ahí dentro es donde falla.

        Responder
  7. ikin

    Ole ole, solucionado 🙂 Funciona efectivamente a 57600. El problema, era además de ese que el pin RST del Arduino no estaba bien soldado y cuando lo ponía a GND desde la salida 12 en realidad no se estaba produciendo el reinicio. Tras muchas pruebas, me di cuenta que era ese el problema….quitar vieja soldadura, soldadura nueva, y ya funciona 🙂

    Muchísimas gracias 🙂

    Responder
    1. Francesco

      Can you help me ?
      my circuit not function…
      i have problem with bootloader…
      i can upload new code…
      can you explain me the circuit and the correct code please?
      thanks

      Responder
  8. Pingback: Programming an Arduino via WiFi with the ESP8266 -Use Arduino for Projects

  9. THULASI RAM

    Hi your blog is really good..
    help me out..
    I am using arduino uno for this one
    AT version:0.23.0.0(Apr 24 2015 21:11:01)
    SDK version:1.0.1
    my cmd terminal says

    Listen to connections
    192.168.1.xx connected
    Traceback (most recent call last):
    File “arduino_remote_program_wifi.py”,line 247. in
    main()
    File “arduino_remote_program_wifi.py”,line 231. in main
    if wait_for(cli,”hello”,5000)[0]:
    File “arduino_remote_program_wifi.py”,line 231. in wait_for
    received +=cli.recv(1)
    socket.error:[Errno 10054] An existing connection was forcibly closed by the remote host

    help me out..

    Responder
  10. Alexander

    Hi, i’m trying to use this solution, all steps are working correct except for entering bootloader. TX is expected to be low for a while, but it dont, so python server do not recieve \x00 and do not start updating firmware. How can i solve this?

    Please, help, your article is very helpful, just one more step.

    Responder
      1. hardika

        i have same problem, python server do not recieve \x00 .
        i try sending 0 byte if (send_command(“\x00”, 2000, “ok”, “error”)) . but still not working
        please give me a hit..

        Responder
      2. Francesco

        Hello i try to send a byte 0, but the program remain looped in
        listen to connection
        192.168.1.185 connected
        listen to connection
        192.168.1.185 connected
        listen to connection
        192.168.1.185 connected

        where is the problem ?
        Can you answer me please?
        THANKS

        Responder
  11. Victor

    Un post genial, me gustaria preguntarte una duda,
    ¿Este sistema de programación es compatible con el arduino Mega 2560?
    He leido por la web el arduino mega dispone de un bootloder que usa el protocolo STK500v2 y no el STK500(v1)

    Responder
    1. admin Autor

      Pues sinceramente no me he mirado la versión 2 del protocolo. La diferencia estriba en el acceso a bloques de memoria por encima de los 128K. Siempre puedes probar ya que si algo falla se puede reflashear el microcontrolador con su firmware original.

      Responder
      1. +91-9033533754

        Really interesting tutorial, and i really appreciate your work!
        Here I’m trying to up date my arduino uno firmware same manner as you described here, but instead of ESP 8266 I’m using RN171 WiFly module from roving network along with arduino.
        every thing is working grate, but the problem is after sending “Reboot” command from my server, arduino get reset and connect the python server having different port, but at the last moments I’m getting message from python script as “connect to arduino boot-loader failed!”
        then after I’d try with different baudrate like 9600, 19200 but nothing happen and getting same result!!!!
        any suggestions
        Regards
        Mahendra sondagar

        Responder
  12. Grant Pinkert

    Hey, I don’t know if you’re still paying attention to this, but I was just wondering if you could give me some advice? For some reason when the arduino is sending out the “hello guys” string, my server is not picking it up. I have checked and I am sure they are on the same IP and port. Also, how are you inputting where the hex file is saved? Are you sending that to your python server? Those are my two questions, thanks so much for doing this!

    Responder
    1. admin Autor

      The first question: If you follow the code as is, I guess you first received the “Hello world” successfully, however when you switch to the new firmware you didnt receive the “Hello guys”, do you?. I think the firmware was not programmed correclty. Did the script python returns a “Program memory address: success” and “Leaving programming mode: success”?

      The second question: The arduino sketch send the .hex file it wants to be programmed (Arduino_remote_example.cpp.hex); that file, after compiling in arduino ide, is stored in the same directory than python script is located.

      Responder
      1. Grant Pinkert

        OK, so I got the rest of that stuff to work. However, once the arduino connects with the Python script, nothing happens. Any idea what could be causing the server to not start sending the new info, or the arduino not entering the bootloader? This is a picture of the issue: https://drive.google.com/file/d/0B1f4r8iM9x2QdlA2eS1XRUl4VkU/view?usp=sharing

        This is after I have told it to reboot and after it connected to the python server. Thanks for the help!

        Responder
      2. Grant

        I know I already asked you for help, but I figured out wwhat the problem was. Unfortunately, I have a few other questions.

        1- Do I send the zero byte before the reset, or after the reset?
        2- What does pin 13 have to do with anything? I can’t see what it is being used for on the code or the schematic.
        3- when I pull pin 12 low, that triggers the reset, correct?

        Thanks so much!

        Responder
  13. scg

    Hey, so I am having a problem with entering the bootloader. Once I reset the board, it does not stay in the bootloader, and just keeps going in the loop without updating the board. I tried sending a zero byte, but that didn’t work either, I still kept timing out. Any suggestions for how to enter the bootloader?

    I was doing this for the zero byte:

    String zero = “\x00”;
    Serial.println(“AT+CIPSEND=1”);
    Serial.print(zero);
    pinMode ( 12 , OUTPUT ) ;
    digitalWrite ( 12 , LOW ) ;
    for ( ; ; ) ;

    Like I said, it does not enter the bootloader, and it does not echo anything back after the reset, it just keeps going with the original code. Thanks for the help!

    Responder
  14. Iker

    Una preguntilla, porque en el codigo de arduino pones a nivel alto y bajo el pin 13? No veo que este conectado a ningun sitio ni que sirva para nada. Tambien veo que lo has declarado como OUTPUT.
    Gracias.

    Responder
    1. admin Autor

      Como el pin 13 está asociado al led que incorpora Arduino, lo utilizo para saber que está encendido y esperando ordenes y cuando lo apago es porque ha habido algún fallo.

      Responder

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *