Blog

Coche RC con NodeMCU (ESP8266)

Introducción

Materiales utilizados

  • Coche RC
  • NodeMCU V1(ESP8266)
  • Puente H (L293D)
  • ProtoBoard y jumpers

Introducción

LA idea es convertir un coche RC para que sea manejado por un ESP8266, creo que es el primer coche controlado por websocket, al menos no he visto otro en lo que buscaba información para este proyecto.

El coche lo compre el mas barato que encontré y al desarmarlo tenia dos motores DC 5V uno para el impulso y otro para la dirección, mas adelante les explicare el problema que tuve para el control de la dirección.
Tuve mucho interés en el manejo de los websockets que son los sustitutos del GET y POST en HTTP y los mas idoneos para este tipo de comunicación el cual estan siempre conectados cliente/servidor
El coche se conectara a mi red WIFII y estará funcionando como server, a la espera de que se conecten los clientes, que podrán ser un movil, tablet, PC, por medio de un browser a través de HTML.

El HTML consistirá en 5 botones básicos arriba, abajo, izquierda, derecha, parada, a los que le doy algo de estilo con CSS, demostrando así el enorme potencial de estos modulos ESP8266.

Primera Demo

Pasos:

1-paso: Abrir el coche y quitar la parte de radiofrecuencia el mando tampoco nos serviría, lo pueden guardar para otro proyecto tanto el mando como el transmisor
2-paso: conectar los motores al puente H

Para mas información de que es un puente H:

http://panamahitek.com/el-puente-h-invirtiendo-el-sentido-de-giro-de-un-motor-con-arduino/

3-paso asignar pines del ESP8266 y conectar

const byte AcelMotor_pin = 14;  // Pin D5, to H-Brige "enable 1"
const byte Adelante_pin = 12;   // Pin D6, to H-Brige "input 1"
const byte Atras_pin = 13;      // Pin D7, to H-Brige "input 2"

const byte Derecha_pin = 4;     // Pin D2, to H-Brige "input 1"
const byte Izquierda_pin = 5;   // Pin D1, to H-Brige "input 2"
Asignacion de pin

 


 

 

Empezamos con la adaptación!

 

El codigo

Lo primero es instanciar al websocket y preparar el modulo como server

ESP8266WiFiMulti WiFiMulti;
ESP8266WebServer server(80);
WebSocketsServer webSocket = WebSocketsServer(81);

Iniciamos la coneccion a mi red WIFI  e iniciamos el servidor.

 WiFiMulti.addAP(ssid, password);
 while(WiFiMulti.run() != WL_CONNECTED) {
    Serial.print(".");
    delay(100);
   
  }

  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  if (mdns.begin("espWebSock", WiFi.localIP())) {
    Serial.println("MDNS responder started");
    mdns.addService("http", "tcp", 80);
    mdns.addService("ws", "tcp", 81);
  }
  else {
    Serial.println("MDNS.begin failed");
  }
  Serial.print("Connect to http://espWebSock.local or http://");
  Serial.println(WiFi.localIP());

  server.on("/", handleRoot);
  server.onNotFound(handleNotFound);

  server.begin();

  webSocket.begin();
  webSocket.onEvent(webSocketEvent);
}

Una ves conectado a la red wifi y haya  dado una IP al servidor, empezamos a configurar lo el front end para ser visualizado por el cliente.

<body onload="javascript:start();">
<div id="div1">
<h1 id="text">RC CONTROL</h1>
<input id="textField1" type="text" value="" align="right" size="13"/><br>
<input id="display"    type="text" value="" align="right" size="13"/><br>
</div>

<div id="div2"><b>POWER</b></div>
<div id="div3">
<div id="ledstatus"><b>Estado</b></div>
<button id="ledon"    type="button" onclick="buttonclick(this);">>></button> 
<button id="ledoff"   type="button" onclick="buttonclick(this);">FRENO</button>
<button id="reversa"  type="button" onclick="buttonclick(this);">>></button>
<button id="izquierda"type="button" onclick="buttonclick(this);"><<</button>
<button id="derecha"  type="button" onclick="buttonclick(this);">>></button>
<button id="O"        type="button" onclick="buttonclick(this);">ON</button>
<input id="p"      type="range" min="0" max="255" step="5";>
</div>
</body>
</html>

Como podrán observar el código HTML es muy básico y al cargar la pagina pues se ejecuta el java script que es quien se encarga la lógica de programación. el código CSS pues no viene al tema, al final del proyecto pondré el código completo y podrán descargarlo.

Ahora el código de enlace como lo llamo entre la interacción del cliente con el coche RC

La idea es que al cargar la pagina la funcion start() se ejecuta y crea el socket con el cliente y el coche RC queda a la espera de instrucciones por medio de eventos, en el vídeo explicare mejor esta parte y podrán ver los mensajes cliente/servidor

function start() {
  websock = new WebSocket('ws://' + window.location.hostname + ':81/');
  websock.onopen =   function(evt){console.log('RC ready to drive'); };
  websock.onclose =  function(evt){console.log('RC connection close'); };
  websock.onerror =  function(evt){console.log(evt); };
  websock.onmessage =function(evt){console.log(evt);
    
  
    var e = document.getElementById('ledstatus');
    output = document.getElementById("display");
    output_text = document.getElementById("textField1");
     
       
      if (evt.data === 'ledon') {
      e.style.color = 'red';
      output_text.style.color ='red';
      var state= "Acelerando.."
      output_text.value=state;
             
    }
    else if (evt.data === 'ledoff') {
      e.style.color = 'black';
      //canvas.fillText(state,10,50);
      output_text.style.color ='black';
      var state= "Freno"
      output_text.value=state;
    }
      else if (evt.data === 'reversa') {
      e.style.color = 'black';
      output_text.style.color ='black';
      var state= "Reversa"
      output_text.value=state;
      }
      else if (evt.data === 'izquierda') {
      e.style.color = 'black';
      output_text.style.color ='black';
      var state= "Izquierda"
      output_text.value=state;        
    }
    else if (evt.data === 'derecha') {
      e.style.color = 'black';
      output_text.style.color ='black';
      var state= "Derecha"
      output_text.value=state;        
    }
    else if (evt.data > "100") {
      e.style.color = 'black';
      output.style.color ='black';
      var state= "Velocidad ";
      output.value=(state + evt.data);        
    }
    else {
      console.log('unknown event');
      document.getElementById("text").value = "";
    }
   
  };
}
function buttonclick(e) {
  websock.send(e.id);
 }

Una ves podemos interpretar las instrucciones del cliente pues hacemos andar el coche RC.

Esta parte es muy arduino.

Como había comentado antes el coche queda a la espera de instrucciones por medio de eventos pues el código para interactuar con el coche esta aquí.

Lo que inicia el evento es un mensaje tipo texto, que es el que indica la instrucción “Izquierda” pues el pone a 0 el pin D6 y a HIGH el pin 7 lo que hace que el motor de dirección gire a la izquierda, y así con las demás instrucciones.

void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length)
{
  
  Serial.printf("webSocketEvent(%d, %d, ...)\r\n", num, type);
  switch(type) {
    case WStype_DISCONNECTED:
      Serial.printf("[%u] Disconnected!\r\n", num);
      break;
    case WStype_CONNECTED:
      {
        IPAddress ip = webSocket.remoteIP(num);
        Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\r\n", num, ip[0], ip[1], ip[2], ip[3], payload);
      
      } 
      break;
    case WStype_TEXT:
    {
      Serial.printf("[%u] get Text: %s\r\n", num, payload);

      String text = String((char *) &payload[0]);
      if(text=="ledon"){
        analogWrite(AcelMotor_pin, acel);  //Pin 5
        acel=acel+10;
        Serial.print("Velocidad ");
        Serial.println(acel);
        analogWrite (Adelante_pin, 1023);   // Pin D6
        analogWrite (Atras_pin,0);          //Pin D7
        String temp =String(acel); // convierte to string
        webSocket.sendTXT(num,temp);
                      
            }
      if(text=="ledoff"){
        Serial.println("break");  
        analogWrite (Adelante_pin, 0);     // Pin D6
        analogWrite (Atras_pin,0);         //Pin D7
            //webSocket.sendTXT(num, "break", 5);
           // analogWrite(LEDPIN, 0);
            acel=500;
            }
       if(text=="reversa"){
        Serial.println("reversa");
        analogWrite(AcelMotor_pin, acel);
        acel=acel+10;
        Serial.println(acel);
        analogWrite (Adelante_pin,0);     // Pin D6
        analogWrite (Atras_pin,1023);     //Pin D7
        webSocket.sendTXT(num, "reversa", length);
            }  
       if(text=="izquierda"){
        flag = true;
        analogWrite(Izquierda_pin, 0); //Pin 2
        analogWrite(Derecha_pin, 1023);      //Pin 1
        Serial.println("izquierda");
           webSocket.sendTXT(num, "girar a la izquierda", 20);
            } 
       if(text=="derecha"){
        flag = true;
        analogWrite(Izquierda_pin, 1023);    //Pin 2
        analogWrite(Derecha_pin, 0);   //Pin 1
        Serial.println("izquierda");
        
          webSocket.sendTXT(num, "girar a la derecha", 18);
            }                         
    

Conclusiones

Estoy muy satisfecho con los resultados la verdad que aprendí mucho, este proyecto es fácil de hacer y económico en comparación con lo que se puede aprender ya que toca electrónica, microprocesadores, html, css, javascript etc….

El problema que tuve que la dirección es que estoy trabajando con un motor dc con escobillas por lo que al inyectar alimentación este gira bruscamente hacia un lado impidiendo una conducción fina, como mejora sustituiré el motor de dirección por un servo motor que es mas adecuado para la dirección en un coche RC

El código no esta depurado por lo que tiene algunas librerías de mas y algunas variable tienen nombre sin sentido, cuando finalice el proyecto del todo ya les dejare un código mas limpio.

Cualquier duda o comentario estoy a su orden.

 

Conectando ESP8266 con Arduino nano “I2C” 2da parte

Introducción:

En este proyecto utilizaremos:
1- 1 NODEMCU (ESP12E).
2- 1 Arduino Nano
3- 2 DS18B20
4- breadboard
5- Cables de conexion

Introducción

En este ocasión presento como es la transferencia de datos mediante el protocolo I2C, entre un ESP8266 como maestro y un Arduino Nano como esclavo pero transfiriendo los datos de dos sensores de temperatura DS18B20, este es un sensor que contiene una dirección única que permite identificarlo individualmente, lo que lo hace propicio para el uso del protocolo OnWire que permite enviar y recibir datos utilizando un solo cable.

Click aquí para ver la primera parte

Para Saber sobre el sensor DS1820 click aqui

El código

Presentare la codificación del esclavo ya que la del maestro(ESP8266) es básicamente  la misma que en la primera parte.

En este vídeo explico su funcionamiento:

1- Añadimos las librerías relacionadas con el sensor
OneWire y DallarTemperture

2- Definimos el pin 2 del arduino nano
#One_WIRE_BUS

3- Instanciamos y asociamos el pin 2 del arduino al protocolo OneWire y la librería DallasTemperarute
OneWire oneWire(ONE_WIRE_BUS)
DallasTemperature sensors(&oneWire)

#include <Wire.h>
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into pin 2 on the Arduino
#define ONE_WIRE_BUS 2
// Setup a oneWire instance to communicate with any OneWire devices 
// (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
 
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

4- Definimos la direccion del esclavo y asignamos los nombres a las variables

const byte MY_ADDRESS = 42;
int Temp1,Temp2;
// various commands we might get

enum {
    CMD_ID = 1,
    CMD_READ_Temp1  = 2,
    CMD_READ_Temp2 = 3
    };

5- iniciamos los sensores

 sensors.begin();

6- Creamos uns subrutina que lee las medidas del los sensores.

void sendSensorTemp ()
  {
  // call sensors.requestTemperatures() to issue a global temperature
  // request to all devices on the bus
  Serial.print(" Requesting temperatures...");
  sensors.requestTemperatures(); // Send the command to get temperatures
  Serial.println("DONE");
  
  Temp1 = sensors.getTempCByIndex(0);
  Temp2 = sensors.getTempCByIndex(1);
  delay(500);
  
  }  // end of sendSensor

8- llamamos la subrutina infinitamente en el loop

void loop() 
  {
   sendSensorTemp ();
  }  // end of loop

A continucion los codigos completos tanto del master como el esclavo

/Master
/*These examples illustrate how a master can request data from a slave).
First, the master, which asks the slave for information:
*/
#include <Wire.h>

const int SLAVE_ADDRESS = 42;
int Temp1,Temp2;
// various commands we might send
enum {
    CMD_ID = 1,
    CMD_READ_Temp1  = 2,
    CMD_READ_Temp2 = 3
    };

void sendCommand (const byte cmd, const int responseSize)
  {
  Wire.beginTransmission (SLAVE_ADDRESS);
  Wire.write (cmd);
  //Wire.endTransmission ();
  if (Wire.endTransmission () == 0)
  {
  Serial.println("Data Sent OK");  
  }
  else{
    Serial.println("Error Sending Data");
    }
  Wire.requestFrom (SLAVE_ADDRESS, responseSize);  
  }  // end of sendCommand
  
void setup ()
  {
  Wire.begin (0,2);   
  Serial.begin (115200);  // start serial for output
  
  sendCommand (CMD_ID, 1);
  
  if (Wire.available ())
    {
    Serial.println("");  
    Serial.print ("Slave is ID: ");
    Serial.println (Wire.read (), DEC);
    }
  else
    Serial.println ("No response to ID request");
  
  }  // end of setup

void loop()
  {
  
  
  sendCommand (CMD_READ_Temp1, 1);
  Temp1 = Wire.read ();
  Serial.print ("Value of Temp1: ");
  Serial.println (Temp1);

  sendCommand (CMD_READ_Temp2, 1);
  Temp2= Wire.read ();
  Serial.print ("Value of Temp2: ");
  Serial.println (Temp2);

  delay (500);   
  }  // end of loop
Master
// Slave
/*It has to be able to reply to any request without even knowing the address of the device 
 making the request.
It does this by setting up an interrupt handler (by calling Wire.onRequest).
This gets called any time a master wants a response.
We also need the Wire.onReceive handler, to get the initial "command" - that is,
we need to know what data is wanted.
The example above assumes a single-byte command, which we save in the variable "command".
Then when the requestEvent handler is called, we check what the most-recent command was,
and send an appropriate response.
Warning - because of the way the Wire library is written, the requestEvent handler can 
only (successfully) do a single send. The reason is that each attempt to send a reply resets
the internal buffer back to the start. Thus in your requestEvent, if you need to send multiple bytes,
you should assemble them into a temporary buffer, and then send that buffer using a single Wire.write. 
For example:
*/
#include <Wire.h>
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into pin 2 on the Arduino
#define ONE_WIRE_BUS 2
// Setup a oneWire instance to communicate with any OneWire devices 
// (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
 
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

const byte MY_ADDRESS = 42;
int Temp1,Temp2;
// various commands we might get

enum {
    CMD_ID = 1,
    CMD_READ_Temp1  = 2,
    CMD_READ_Temp2 = 3
    };

char command;

void setup() 
  {
  command = 0;
  
  Serial.begin(115200);
  Serial.println("Dallas Temperature IC Control Library Demo");

  // Start up the library
  sensors.begin();
  Wire.begin (MY_ADDRESS);
  Wire.onReceive (receiveEvent);  // interrupt handler for incoming messages
  Wire.onRequest (requestEvent);  // interrupt handler for when data is wanted

  }  // end of setup

void sendSensorTemp ()
  {
  // call sensors.requestTemperatures() to issue a global temperature
  // request to all devices on the bus
  Serial.print(" Requesting temperatures...");
  sensors.requestTemperatures(); // Send the command to get temperatures
  Serial.println("DONE");
  
  Temp1 = sensors.getTempCByIndex(0);
  Temp2 = sensors.getTempCByIndex(1);
  delay(500);
  
  }  // end of sendSensor

void loop() 
  {
   sendSensorTemp ();
  }  // end of loop

void receiveEvent (int howMany)
  {
  command = Wire.read ();  // remember command for when we get request
  } // end of receiveEvent


void requestEvent ()
  {
  switch (command)
     {
     
    case CMD_ID:      Wire.write (0x55); break;   // send our ID 
    case CMD_READ_Temp1: Wire.write(Temp1); break;  // send Temp1 value
    case CMD_READ_Temp2: Wire.write(Temp2); break;   // send Temp2 value
    
     }  // end of switch
  
  }  // end of requestEvent
ESCLAVO

Conectando NodeMCU(ESP12) con Arduino nano “I2C”

Introducción:

En este proyecto utilizaremos:
1- 1 NODEMCU (ESP12E).
2- 1 Arduino Nano
3- 5 LEDs
4- breadboard
5- Cables de conexion

Para configurar el Ide de arduino lee esto: Instructable to setup the Arduino IDE to program ESP 8266!
Programming ESP8266 using Arduino IDE : http://bit.ly/2hdARij
Getting started with ESP8266 : http://bit.ly/2hdARij
ESp8266 with Arduino: http://bit.ly/2hdARij
ESP8266 with Raspberry Pi : http://bit.ly/2hdARij
ESP8266 Arduino Core : http://bit.ly/2hdARij
Schematic : http://bit.ly/2hdARij
ESP8266 : http://bit.ly/2hdARij

Que es el I2C?

Un circuito interintegrado (I²C, del inglés Inter-Integrated Circuit) es un bus serie de datos desarrollado en 1982 por Philips Semiconductors (hoy NXP Semiconductors). Se utiliza principalmente internamente para la comunicación entre diferentes partes de un circuito, por ejemplo, entre un controlador y circuitos periféricos integrados.

Mas información:
Wikipedia

http://www.gammon.com.au/i2c

El I²C está diseñado como un bus maestro-esclavo. La transferencia de datos es siempre inicializada por un maestro; el esclavo reacciona. Es posible tener varios maestros mediante un modo multimaestro, en el que se pueden comunicar dos maestros entre si, de modo que uno de ellos trabaja como esclavo. El arbitraje (control de acceso en el bus) se rige por las especificaciones, de este modo los maestros pueden ir turnándose.

Protocolo I2C

Como Funciona ?

Inicio de Comunicación “Maestro Esclavo”

La imagen abajo muestra mediante un analizador lógico el carater “S”(0x53), siendo enviado desde el Maestro al esclavo con dirección 42

Analisis logico I2C

From the above graphic note the following points of interest:

  • La transmisión empieza con “Condición Especial”, etiquetada como “START”. Cuando el SDA “Serial Data” es puesto bajo mientras el SCL (serial clock) se mantiene en alto.
  • Los 7-bit de direccion son transmitidos al esclavo el bit  mas significativo primero primero. En este caso es el 42(0X2A o ob0101010). El analizador logico reporta la direccion 0x54, pero realmente 0x2A(42) movido hacia la izquierda un bit, enotoces es que la escritura “write” bit (0) es pocicionado en el ultimo bit significativo.
  • Entonces la lectura/escritura es transmitida. 0 es scritura ( de maestro a esclav0) y 1 esclavo/maestro.
  • El maestro espera por el esclavo para poner  linea SDA en estado bajo con un  ACK (acknowledge) indicando que la direccsion del esclavo existe y esta preparada para recibir datos. si el sclvo esta conectado y no tiene la misma direccion requerida por el maestro, entonces ignarara la linea SDA dejando la lina en estado alto. Esto se indicar con un NAK (negative acknowledgement).
  • Entonces el byte de datos(0x53 en este caso) es transmitido el mayor bit significativo primero.
  • Otra vez despues de los 8 bits de datos el maestro revisa que el sclavo acknowledges poniendo la linea SDA en estado bajo.
  • Mas datos son trasmitidos pero no se muestran en esta grafica.
  • La transmision termina con un “Conficion de paro” (etiquetado  Stop) soltando la linea SDA para ponerla en alto mientras la linea SCL tambien se mantiene en alto.

Primeras pruebas:

Enviar una cadena de datos

Objetivo:

Enviar una secuencia de números del 3 al 7 para configurar los pines digitales del Arduino nano del 3 al 7 y cambiar el estado del led, conectados a cada pin.

Arduino Uno Configuración de pin:

Analog port 4 (A4) = SDA (serial data)
Analog port 5 (A5) = SCL (serial clock)

NodeMCU V1 pint out:
Master

gpio 0 (D3) = SDA (serial data)
gpio 1 (D4) = SCL (serial clock)

 

Serial.begin(9600);
  //pin D3: sda,pin:D4 scl. join the I2C bus as  master
  Wire.begin(0, 2);
  Serial.println("I2C Master READY!");
Master

Este paso es importante ya que he probado con otros pines y no funcionan de momento con estos pines me ha funcionado perfectamente.

En este video explico de manera mas amplia la configuracion para transmitir datos por I2C entre el NodeMCU y el arduino nano.

En siguientes post y videos seguire haciendo mas pruebas como el de utizar una libreria para poder enviar cualquier tipo de datos, el  ejemplo sera con un sensor de temparatura.

#include <Wire.h>

const byte ARDUINO_SLAVE_ADDRESS = 42;

void setup ()
{
  Serial.begin(9600);
  //pin D3: sda,pin:D4 scl. join the I2C bus as master
  Wire.begin(0, 2);
  Serial.println("I2C Master READY!");

  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
}  // end of setup

void loop ()
{
  for (byte x = 3; x <= 7; x++)
  {
    Wire.beginTransmission (ARDUINO_SLAVE_ADDRESS);
    Wire.write (x);

    if (Wire.endTransmission () == 0) {
      digitalWrite (LED_BUILTIN, HIGH);
      Serial.println(String("Data Sent:") + byte(x) + String(" OK"));

    } // end of IF loop
    else {
      digitalWrite (LED_BUILTIN, LOW);
      Serial.println(String("Data Sent:") + byte(x) + String(" NOT OK"));
    }// end of ELSE loop
    delay (200);
  }  // end of for loop
  delay(5000);
}  // end of loop
NODEMCU Master
#include <Wire.h>

const byte MY_ADDRESS = 42;

void setup ()
{
  Serial.begin(115200);
  Wire.begin (MY_ADDRESS);
  for (byte i = 2; i <= 7; i++)
    pinMode (i, OUTPUT);
  // set up receive handler
  Wire.onReceive (receiveEvent);
}  // end of setup

void loop()
{
  // nothing in main loop
}

// called by interrupt service routine when incoming data arrives
void receiveEvent (int howMany)
{
  for (int i = 0; i < howMany; i++)
  { 
    Serial.print(String("valor del howMany:") + byte(howMany));
    byte c = Wire.read ();

    // toggle requested LED

    if (digitalRead (c) == LOW) {
      Serial.println(String("Receiving Data:") + byte(c));
      Serial.println(String("Pin:")+byte(c) + String("Is now ON ..."));
      digitalWrite (c, HIGH);
    } // end of IF loop
    else {
      digitalWrite (c, LOW);
      Serial.println(String("Pin:")+byte(c) + String("Is now OFF ..."));
    } // end of else loop
  }  // end of for loop
}  // end of receiveEvent
Arduino NANO sclavo

Configurando el ESP-12

Ya tengo todo preparado para empezar a trastear con el ESP-12, aquí os pongo la configuracion que he decidido hacer porque creo es la mas segura para empezar a familiarizarme con este increíble modulo.

Si no sabéis nada sobre el modulo ESP-12 podéis saber mas  aqui:

Para bajar y utilizar el ESPplorer pinchar aqui:

Lista de Materiales

  • ESP8266 module
  • USB to Serial converter
  • 3.3V 1A Power Supply(EN mi caso uso una bateria de movil (3.7V)
  • Capacitor (4.7uf)(No es neceario si usas baterias)
  • LED
  • Resistors: 10 kohm (3), 200 ohm(1)
  • Zener Diode (3.3V)
  • Breadboard
  • Jumper wires

Conexiones y pines

Configuracion ESP-12

Continuar leyendo “Configurando el ESP-12”

ESP8266 Primeros pasos

Tengo ya unos cuantos años trabajando con el Arduino ,La verdad estaba muy satisfecho con su rendimiento y asignación de entradas y salidas, lo suficiente para mi proyecto, que es lo que siempre habia soñado, poder controlar mi acuario.

Continuar leyendo “ESP8266 Primeros pasos”